Download code

Jump to: navigation, search

Back to Turtle_graphics_(JavaScript)

Download for Windows: single file, zip

Download for UNIX: single file, zip, tar.gz, tar.bz2

terrapin.htm

  1 <html><head>
  2 <title>a buggy concatenative turtle</title>
  3 <!-- 20070131 [DL] swap renamed flip.  improve tokenization -->
  4 <!-- 20060822 [DL] lame kludge for Opera 9.01 -->
  5 <!-- 20060820 [DL] written -->
  6 <script type="text/javascript"><!--
  7 function codevec(l)
  8 {
  9   var v = l.slice(0)
 10   v.sarg = function() { return checkarg(this.shift()) }
 11   v.varg = function() { return [].concat(this.sarg()) }
 12   v.call = function(l) {
 13 		for(var w = codevec(l); w.length; this.unshift(w.pop())); }
 14   return v
 15 }
 16 
 17 var plan = {}	// source tokens for user-defined words
 18 var user = {}	// functions for user-defined words
 19 var dict = {	// functions for system-defined words
 20 'pen':		function(ctx,v) { ctx.penState = !ctx.penState },
 21 'mirror':	function(ctx,v) { ctx.scale(1,-1) },
 22 'reverse':	function(ctx,v) { ctx.scale(-1,1) },
 23 'turn':		function(ctx,v) { ctx.rotate(v.sarg()*3.1415926/180) },
 24 'forward':	function(ctx,v) { ctx.translate(v.sarg(),0); ctx.displace() },
 25 'scale':	function(ctx,v) { 
 26 			var sc = v.sarg()
 27 			ctx.lineWidth /= sc
 28 			ctx.scale(sc,sc)
 29 				},
 30 'repeat':	function(ctx,v) { 
 31 			var n  = v.sarg()
 32 			var rv = v.varg()
 33 			if(n < 0)	{ n = -n; rv = invert(rv) }
 34 			while(n--)	{ interp(ctx, rv) }
 35 			/////////////////////
 36 			// if(n == 0)	return
 37 			// v.call(rv.concat(['repeat',n-1,rv]))
 38 			/////////////////////
 39 				},
 40 'poly':		function(ctx, v) {
 41 			var n  = v.sarg()
 42 			var a  = 360/(n<0?-n:n)
 43 			v.call(['repeat',n,v.varg().concat(['turn',a])]) },
 44 'def':		function(ctx,v) {
 45 			var name = v.shift()
 46 			plan[name] = v.varg()
 47 			user[name] = function(ctx,v) { v.call(plan[name]) }
 48 				},
 49 'inverse':	function(ctx,v)	{ v.call(invert(v.varg())) },
 50 'identity':	function(ctx,v) { v.call(       v.varg() ) },
 51 'under':	function(ctx,v) {
 52 			var av = v.varg()
 53 			var uv = v.varg()
 54 			v.call(av.concat(uv.concat(invert(av))))
 55 				},
 56 'within':	function(ctx,v)	{
 57 			var av = v.varg()
 58 			var wv = v.varg()
 59 			v.call(av.concat(wv.concat(av)))
 60 				},
 61 'flip':		function(ctx,v) {
 62 			var fn = v.sarg()
 63 			var bv = v.varg()
 64 			var av = v.varg()
 65 			v.call([fn,av,bv])
 66 				},
 67 '':		ignore
 68 }
 69 function invert(ov)
 70 {
 71   var ov = codevec(ov)
 72   var nv = []
 73   while(ov.length)  {
 74     var e = ov.sarg()
 75     switch(e)  {
 76     case 'pen':
 77     case 'mirror':
 78     case 'reverse':
 79       nv.unshift(e)
 80       break
 81     case 'turn':
 82     case 'forward':
 83       nv = [e,-ov.sarg()].concat(nv)
 84       break
 85     case 'scale':
 86       nv = [e,1/ov.sarg()].concat(nv)
 87       break
 88     case 'repeat':
 89     case 'poly':
 90       var c  = ov.sarg()
 91       var ev = ov.varg()
 92       nv = [e,-c,ev].concat(nv)
 93       break
 94     case 'inverse':
 95       nv = ['identity',ov.varg()].concat(nv)
 96       break
 97     case 'identity':
 98       nv = ['inverse',ov.varg()].concat(nv)
 99       break
100     case 'under':
101       var av = ov.varg()
102       var uv = ov.varg()
103       nv = [e,av,invert(uv)].concat(nv)
104       break
105     case 'within':
106       var av = ov.varg()
107       var wv = ov.varg()
108       nv = [e,invert(av),invert(wv)].concat(nv)
109       break
110     case 'flip':
111       var fn = ov.sarg()
112       var bv = ov.varg()
113       var av = ov.varg()
114       e = [fn,av,bv]
115       // fall through
116     default:
117       return invert(e.concat(ov)).concat(nv)
118     }
119   }
120   return nv
121 }
122 
123 function checkarg(e) { return (plan[e] || e) }
124 function checkop(e)  { return (dict[e] || user[e] || ignore) }
125 
126 function ignore(ctx, v) { }
127 function donext(ctx, v) { checkop(v.shift())(ctx,v) }
128 function interp(ctx, v) { for(v = codevec(v); v.length; donext(ctx,v)); }
129 function tokens(s) { return s.replace(/([\[\]])/g," $1 ").split(/\s+/) }
130 function tree(v)
131 {
132   var t = []
133   v.nxt = function() { return this.length ? this.shift() : ']' }
134   for(var e = v.nxt(); e != ']'; e = v.nxt()) { t.push(e == '[' ? tree(v) : e) }
135   return(t)
136 }
137 function turtle(t,c)
138 {
139   /////////////////////////
140   if(document.getElementById("kludge").checked)	{
141     dict['forward'] = function(ctx,v)	{
142 	var x = v.sarg()
143 	if(ctx.penState)	{
144 		ctx.beginPath()
145 		ctx.moveTo(0,0)
146 		ctx.lineTo(x,0)
147 		ctx.stroke()
148 	}
149 	ctx.translate(x,0)
150     }
151   } else {
152     dict['forward'] = function(ctx,v) {
153 	ctx.translate(v.sarg(),0); ctx.displace() }
154   }
155   /////////////////////////
156 
157   var txt = document.getElementById(t)
158   var cvs = document.getElementById(c)
159   var src = txt.value
160   var ctx = cvs.getContext("2d")
161 
162   ctx.save()
163   ctx.clearRect(0,0,cvs.width,cvs.height)
164   ctx.translate(cvs.width/2,cvs.height/2)
165   ctx.beginPath()	// start track display
166   ctx.moveTo(0,0)
167 
168   ctx.penState = 1
169   ctx.displace = function() { this.penState ? ctx.lineTo(0,0)
170 					    : ctx.moveTo(0,0) }
171   plan = {}
172   user = {}
173   interp(ctx, tree(tokens(src)))
174 
175   ctx.stroke()		// show the track
176   ctx.beginPath()	// start turtle display
177   ctx.moveTo(0,-5)
178   ctx.lineTo(20,0)
179   ctx.lineTo(0, 5)
180   ctx.closePath()
181   ctx.fill()		// show the turtle
182   ctx.restore()
183 }
184 
185 function init() { document.getElementById("kludge").checked = !!window.opera }
186 
187 //--></script>
188 <style type="text/css">
189 body	 { font-family: arial; font-size: 10pt;
190 	   background-color: #CCC; color: #000; }
191 h1	 { font-size: 14pt; }
192 canvas   { background-color: #EEE; }
193 textarea { background-color: #EEE; }
194 .doc	 { float: right; border: 1px solid #000; background-color: #FEC; }
195 </style></head><body onLoad="init();turtle('txt','cvs')">
196 <h1>a buggy concatenative turtle <i>(mobilis terrapin)</i></h1>
197 <canvas height=256 width=256 id="cvs" onClick="turtle('txt','cvs')"></canvas>
198 <button onClick="turtle('txt','cvs')">&lt;&lt; draw </button>
199 <textarea cols=60 rows=20 id="txt" onPaste="turtle('txt','cvs')">
200 def jog [ forward 30 under [ turn 45 ] [ forward 10 ] ]
201 def joggle [ under jog reverse reverse ]
202 poly 16 [ poly 4 joggle ]
203 </textarea>
204 <p>Requires javascript and &lt;canvas&gt; support <small> (Safari,Opera,Firefox?)</small>.  Userproofing not included.</p>
205 <p>My Opera can't hack matrix changes while drawing &mdash; if you don't see any output, enable
206 <label for="kludge"> the
207 <input id="kludge" type="checkbox" onClick="turtle('txt','cvs')"/>
208 bletcherous kludge</label></p> 
209 <hr>
210 <div class="doc">
211 <table>
212 <tr><td>pen             </td><td> toggle pen up/down</td></tr>
213 <tr><td>mirror		</td><td> toggle left/right</td></tr>
214 <tr><td>reverse		</td><td> toggle forward/back</td></tr>
215 <tr><td>turn X		</td><td> rotate X degrees</td></tr>
216 <tr><td>forward X	</td><td> translate X units</td></tr>
217 <tr><td>scale X		</td><td> multiply unit size</td></tr>
218 <tr><td></td></tr>
219 <tr><td>repeat N [ ]	</td><td> repeat a plan N times</td></tr>
220 <tr><td>poly N [ ]	</td><td> repeat with implicit turning</td></tr>
221 <tr><td>within [ ] [ ]	</td><td> sandwich a plan<br>(within a b == a b a)</td></tr>
222 <tr><td></td></tr>
223 <tr><td>inverse [ ]	</td><td> produce the opposite of a plan <br>(inverse a == a<sup>-1</sup>)</td></tr>
224 <tr><td>under [ ] [ ]	</td><td> make a do/undo sandwich<br>(under a b == a b a<sup>-1</sup>)</td></tr>
225 <tr><td></td></tr>
226 <tr><td>flip NAME	</td><td> switch argument order<br>(flip f b a == f a b)</td></tr>
227 <tr><td>def NAME [ ]	</td><td> define a subplan<br>(sorry, no arguments)</td></tr>
228 </table>
229 </div>
230 repeat 4 [ forward 100 turn 90 ]<br>
231 <hr>
232 poly 6 [ poly 36 [ reverse pen forward 20 ] ]<br>
233 <hr>
234 def spot [ poly 6 [ forward 10 ] ]<br>
235 def arm [ under [ forward 70 turn -60 ] ]<br>
236 poly 12 [ arm spot ]<br> 
237 <hr>
238 def coil [ repeat 300 [ turn 5 forward 5 scale .99 ] ]<br>
239 def branch [ flip under [ ] ]<br>
240 poly 2 [ branch coil ]<br>
241 <hr>
242 def jog [ forward 30 under [ turn 45 ] [ forward 10 ] ]<br>
243 def joggle [ under jog reverse reverse ]<br>
244 poly 6 [ poly 5 joggle ]<br>
245 <hr>
246 def t [ turn 90 ]<br>
247 def f [ forward 60 ]<br>
248 def h [ forward 30 ]<br>
249 def x [ under [ under t f ] h ]<br>
250 <br>
251 def u [ under t f h ]<br>
252 def q [ under [ repeat 2 u ] ]<br>
253 def w [ under [ repeat 1 u ] ]<br>
254 def e [ under [ repeat 0 u ] ]<br>
255 <br>
256 poly 4 [ q [<br>
257 poly 4 [ w [<br>
258 poly 4 [ e [ <br>
259 x inverse x<br>
260 ] ] ] ] ] ]<br>
261 </body> </html>


hijacker
hijacker
hijacker
hijacker