Visit http://turtlebits.net/ to run your programs.
.Copyright © 2013 David Bau.
Turtle Bits
uses the language CoffeeScript designed by Jeremy Ashkenas in 2009,
with await/defer extensions created by Maxwell Krohn in 2012,
and the jQuery-turtle plugin devleoped by the author in 2011,
built on the jQuery library invented by John Resig in 2006.
Turtlebits runs on modern HTML5 browsers.
This work is inspired by the beloved LOGO language
created by Seymour Papert and Wally Feurzeig in 1967.
Special thanks to the middle school students in Lincoln Massachusetts
and at Dorchester McCormack who vetted this material.
Bugs and ideas to https://github.com/davidbau/jquery-turtle/issues
This book is typeset in Łukasz Dziedzic's 2010 open font Lato
and Paul D. Hunt's 2012 Adobe Source Code Pro.
pen red fd 50 rt 90
pen blue fd 50; rt 90 fd 50; rt 90 fd 50; rt 90 fd 50; rt 90
pen black fd 70; rt 120 fd 70; rt 120 fd 70; rt 120
speed 5 pen green fd 30; lt 90 fd 10; rt 120 fd 80; rt 120 fd 80; rt 120 fd 10; lt 90 fd 30; rt 90 fd 60; rt 90
x = 144 pen gold fd 100; rt x fd 100; rt x fd 100; rt x fd 100; rt x fd 100; rt x
rt 90; dot lightgray fd 30; dot gray fd 30; dot() fd 30
pen crimson fd 60; label 'UP' rt 30 fd 40; rt 120; dot gold, 30 fd 40; rt 30; label 'DOWN' fd 60; rt 90 fd 40; rt 90
speed 10 dot yellow, 160 fd 20 rt 90 fd 25 dot black, 20 bk 50 dot black, 20 bk 5 rt 90 fd 40 pen black, 7 lt 30 fd 20 lt 60 fd 40 lt 60 fd 20 ht()
x = 18 see x * 5 dot black, x * 5 dot white, x * 4 dot black, x * 3 dot white, x * 2
pen green for d in [50, 100, 50, 100] fd d rt 90
for c in [red orange yellow green blue violet] pen c fd 100 bk 100 slide 10, 5
see [1..5] see [1...5]
pen blue for x in [1..4] fd 50 rt 90
speed 100 pen red for x in [1..360] fd 1 rt 1
pen purple for x in [30..1] by -1 fd x rt 30
pen blueviolet for x in [1..5] rt 72 for y in [1..3] fd 50 rt 120
for outside in [skyblue, violet, pink] for inside in [palegreen, orange, red] dot outside, 21 dot inside, 7 fd 25 rt 36
pen turquoise for y in [1..10] dot blue for x in [1..4] fd 50 rt 90 lt 36 bk 50
speed 100 rt 90 for color in [red, gold, green, blue] slide 40, -160 for sides in [3..6] pen 'path' for x in [1..sides] fd 100 / sides lt 360 / sides fill color fd 40
square = (x) -> for y in [1..4] fd x rt 90 pen red square 80
polygon = (c, s, n) -> pen c for x in [1..n] fd s rt 360 / n polygon blue, 70, 5 polygon orange, 25, 6
rule = (list) -> for x in list fd x; bk x slide 10, 0 pen black rule [50, 10, 20, 10, 50, 10, 20, 10, 50]
rotate = (x, shape) -> for z in [1..x] shape() rt 360 / x pen deeppink rotate 3, -> fd 50 pen null; bk 70 rotate 4, -> dot springgreen, 30 fd 30 bk 80; pen 'path' rotate 5, -> rotate 3, -> fd 50 fill 'violet strokeStyle blue'
speed 100 pen red for x in [1..20] fd 80 rt 100 if x is 10 delay 2000
speed Infinity advance = -> pen lightgray bk 100 rt 5 pen red fd 100 tick advance
seconds = 5 tick -> if seconds is 0 write "Time's up!" tick off else write seconds seconds = seconds - 1
speed Infinity pen green tick -> moveto lastclick
speed Infinity pen orange tick 100, -> turnto lastmousemove fd 1
cry = (who, query) -> write "Oh #{who}, #{who}!" write "#{query} #{who}?" cry "Romeo", "Wherefore art thou" cry "kitty", "What did you eat" play "fc/c/dcz"
url = "http://upload.wikimedia.org/wikipedia" + "/commons/6/61/Baby_Gopher_Tortoise.jpg" write """<center><img src="#{url}" width=100> </center>"""
n = write "<h1>Notice</h1>" write """ <p>This long paragraph has <b>bold</b>, <i>italic</i>, and <u>underlined</u> text. Horizontal rule below.</p> """ write "<hr>" write """ <p><a href="//turtlebits.net/"> Link</a> with an <a>. </p> """ n.css { background: pink }
n = write "<h1>Notice</h1>" write """ <p>This long paragraph has <b>bold</b>, <i>italic</i>, and <u>underlined</u> text. </p>""" n.css { background: pink display: 'inline-block' } n.pen purple, 10 n.bk 80 n.rt 45 n.fd 50
pen sienna button 'R', -> rt 10 button 'F', -> fd 10 button 'L', -> lt 10 button 'D', -> dot 'darkslateblue'
write "How many sides?" read (sides) -> write "Color?" read (color) -> pen color for x in [1..sides] fd 30 rt 360 / sides
secret = random [1..100] turns = 5 write "Guess my number." write "You get #{turns} guesses." dopick = (pick) -> if pick is secret write "You got it!" return if 1 <= pick < secret write "Too small! " turns = turns - 1 else if secret < pick <= 100 write "Too big! " turns = turns - 1 else write "It's a number 1 to 100." if turns > 1 write "#{turns} left." readnum dopick else if turns is 1 write "Last guess!" readnum dopick else write "Game over." write "It was #{secret}." readnum dopick
write '5' + '3' write Number('5') + Number('3')
counter = 0 write ++counter + 'a' write (counter += 1) + 'b' write (counter = counter + 1) + 'c'
area = (radius) -> Math.PI * radius * radius circumference = (radius) -> 2 * Math.PI * radius for r in [1, 5, 10] write 'radius ' + r write 'a ' + area r write 'c ' + circumference r
hypotenuse = (a, b) -> Math.sqrt(a * a + b * b) write hypotenuse 3, 4 write hypotenuse 5, 12 write hypotenuse 10, 10 write Math.floor(hypotenuse(10, 10))
gcf = (a, b) -> if a > b return gcf b, a remainder = b % a if remainder is 0 return a gcf remainder, a for x in [80..88] write "gcf(120,#{x})=" + gcf(120, x)
power = (x, p) -> answer = 1 answer *= x for i in [0...p] return answer for n in [1..5] write power(2, n)
write Math.pow(2, 5) write Math.pow(2, 0.5)
factorial = (x) -> if x < 1 then 1 else x * factorial(x - 1) for x in [1..4] write factorial x
fib = (n) -> if n <= 2 1 else fib(n - 1) + fib(n - 2) for x in [3..8] write fib x
mandelbrot = (n, c, z) -> if n is 0 or z.r*z.r + z.i*z.i > 4 return n else return mandelbrot n - 1, c, { r: c.r + z.r*z.r - z.i*z.i i: c.i + 2*z.r*z.i } speed 100 ht() scale 150 s = 0.05 for x in [-2..1] by s for y in [-1.5..1.5] by s n = mandelbrot 20, {r:x,i:y}, {r:x,i:y} moveto x, y dot "hsl(100,100%,#{5*n}%)", s
moveto {pageX: 80, pageY: 50}; pen coral moveto {pageX: 80, pageY: 10} moveto {pageX: 30, pageY: 50} moveto {pageX: 160, pageY: 50}
plan = [ {c: dimgray, x: 75, y: 12} {c: gray, x: 0, y: 78} {c: dimgray, x: -75, y: 5} {c: gray, x: -35, y: -18} {c: plum, x: 0, y: -62} {c: gray, x: 35, y: -15} {c: black, x: 0, y: 95} ] for record in plan pen record.c slide record.x, record.y
values = { a: 1, e: 1, i: 1, l: 1, n: 1, o: 1, r: 1, s: 1, t: 1, u: 1 d: 2, g: 2, b: 3, c: 3, m: 3, p: 3 f: 4, h: 4, v: 4, w: 4, y: 4 k: 5, j: 8, x: 8, q: 10, z: 10 } score = (word) -> total = 0 for letter in word total += values[letter] write "#{word}: #{total}" score x for x in ['bison', 'armadillo', 'giraffe', 'zebra']
memo = { sum: 0 count: 0 add: (x) -> @sum += x; @count += 1 stats: -> write 'Total ' + @sum + '/' + @count write 'Average ' + @sum / @count } memo.add(n) for n in [40..50] memo.stats()
primes = [] candidate = 2 while primes.length < 10 composite = false for p in primes if candidate % p is 0 composite = true break if not composite primes.push candidate write candidate candidate = candidate + 1
stack = [] pen green speed Infinity button 'R', -> rt 30 button 'F', -> fd 10 button 'Push', -> dot crimson stack.push [getxy(), bearing()] button 'Pop', -> if not stack.length then home(); return [xy, b] = stack.pop() pen off moveto xy turnto b pen on dot pink
suits = ['\u2663', '\u2666', '\u2665', '\u2660'] deck = [] for v in [2..10].concat ['J', 'Q', 'K', 'A'] deck.push (v + s for s in suits)... shuffle = (d) -> for i in [1...d.length] choice = random(i + 1) [d[i], d[choice]] = [d[choice], d[i]] deal = (d, n) -> d.splice(-n) shuffle deck for x in [1..3] write deal(deck, 5).join('/')
spiral = (x) -> if x > 0 fd x * 10 rt 90 spiral x - 1 pen red spiral 10
speed 1000 fern = (x) -> if x > 1 fd x rt 95 pen red fern x * .4 lt 190 pen gold fern x * .4 rt 100 pen green fern x * .8 lt 5 pen null bk x pen brown fern 50
speed Infinity flake = (x) -> if x < 3 then fd x else flake x / 3 lt 60 flake x / 3 rt 120 flake x / 3 lt 60 flake x / 3 pen 'path' for s in [1..3] flake 150 rt 120 fill 'azure strokeStyle navy'
r = hatch red r.pen red r.rt 45 r.fd 60 b = hatch blue b.pen blue b.lt 83 b.fd 40
turtle.remove() crowd = hatch 20 crowd.pen goldenrod crowd.direct -> @rt random 360 @fd 20 + random 30
turtle.remove() forest = hatch 17, olive forest.direct (j) -> x = j - 8 @rt 90 @fd x * 10 @lt 90 @pen sandybrown @fd 100 - x * x
turtle.remove() group = hatch 9 group.direct (j) -> @fd 50 * Math.floor(j / 3) @rt 90 @fd 50 * (j % 3) @dot 2 * (1 + j) group.delay 1000 group.direct (j) -> @pen "hsl(#{j*36},100%,40%)" p = j + 3 for k in [1..p] @fd 100 / p @lt 360 / p
text = """If you can look into the seeds of time And say which grain will grow and which will not, Speak, then, to me."""
see text.indexOf 'which' see text.substr 47, 7
see 'charCode', text.charCodeAt(0) see 'string', String.fromCharCode(73) for x in [88, 188, 9988] see x, String.fromCharCode(x)
see text.match /w....g.../ see text.match /[a-z][a-z]/ see text.match /\s[a-z][a-z]\s/ see text.match /\b[a-z][a-z]\b/ see text.match /\b[a-z][a-z]\b/gi see text.match /\b[gn][a-z]*\b/g see text.match /z/
lines = text.split /\n/ see lines[2] words = text.split /\s+/ see words[0..2]
pattern = /\b([a-z]+) of ([a-z]+)\b/ matched = pattern.exec text for g in [0..2] see "group #{g}: #{matched[g]}"
r = text.replace /[A-Z][a-z]*/g, "<mark>$&</mark>" r = r.replace /\n/g, "<br>" r = r.replace /\bw[a-z]*\b/g, (x) -> x.toUpperCase() write r
speed Infinity pen purple vy = 10 tick 20, -> slide 1, vy if enclosedby(window) vy -= 1 else vy = Math.abs(vy) * 0.9
compare = (a, b) -> if a > b then 1 else if a < b then -1 else 0 speed Infinity pen red v = {x: 0, y: 0} tick 10, -> if not lastmousemove then return c = pagexy(); a = lastmousemove v.x += compare a.pageX, c.pageX v.y -= compare a.pageY, c.pageY slide v.x, v.y
defaultspeed Infinity write "Catch blue before red gets you." bk 100 r = hatch red b = hatch blue tick 10, -> turnto lastmousemove fd 6 r.turnto turtle r.fd 4 b.turnto bearing b b.fd 3 if b.touches(turtle) write "You win!" tick off else if r.touches(turtle) write "Red got you!" tick off else if not b.touches(document) write "Blue got away!" tick off
onedice = -> random [1..6] twodice = -> onedice() + onedice() for n in [1..5] write twodice()
for n in [1..20] fd 10 rt random(181) - 90 dot gray, 5
for n in [1..14] pen random [red,black,blue] fd random 70 rt 90
for n in [1..300] moveto random 'position' dot random 'color'
for n in [1..2] write Math.random()
c = [0, 0, 0, 0, 0, 0] for n in [1..500] heads = 0 for flips in [1..5] heads += random 2 c[heads] += 1 for h of c b = write h + ":" + c[h] b.css { background: skyblue width: c[h] }
pen blue, 10 fd 100; rt 90 pen pink, 3 fd 50; rt 90 pen 'orange ' + 'lineWidth 10 ' + 'lineCap square' fd 100; rt 90 pen black fd 50
text = write 'Outlined.' text.css { border: '2px solid red' } turtle.css { border: '3px dotted blue' }
h = write 'Fancy!' h.css { font: '55px Helvetica' fontStyle: 'italic' }
write 'Before' d = write 'Decorated' write 'After' d.css { display: 'inline-block' cursor: 'pointer' padding: '10px' margin: '-5px' opacity: '0.7' color: 'white' fontSize: '110%' letterSpacing: '5px' textDecoration: 'underline' boxShadow: '1px 1px black' background: 'mediumaquamarine' transform: 'rotate(10deg)translateX(20px)' }
write """ <style> h2 { color: red; } h3 { background: bisque; } </style> """ write "<h2>Stylesheet</h2>" write "<h3>Tag Styles</h3>" write "<p>style specific tags</p>"
write """ <style> .a { text-decoration: underline; } .b { font-style: italic; } </style> """ write "<p class='a'>Class a</p>" write "<h3 class='b'>Class b</h3>" write "<p class='b'>Classes apply to any tag.</p>"
write """ <style> i { border: 1px solid black; margin: 2px } i:nth-of-type(1) { background: gold } i:nth-of-type(2n+4) { background: skyblue } i:nth-of-type(3n+9) { background: thistle } </style> """ for x in [1..24] write "<i>#{x}</i>" write "<wbr>"
write "<p><mark>a</mark>v<mark>o</mark>" + "c<mark>a</mark>d<mark>o</mark></p>" $('p').css { fontSize: '200%' } $('mark').css { background: palegreen } $('mark').animate { padding: '5px' } $('mark:nth-of-type(2n)').animate { opacity: 0.3 }
$(document).click (event) -> see event if event.shiftKey pen blue else pen null moveto event
pen plum [L, R, U, D] = [37, 39, 38, 40] keydown (event) -> if event.which is L then lt 5 if event.which is R then rt 5 if event.which is U then fd 5 if event.which is D then bk 5
t = write "<button>Touch This</button>" t.speed Infinity t.moveto document t.mousemove (event) -> t.rt random(91) - 45 while t.touches(event) t.bk 1
defaultspeed Infinity remove() t = write '<img>' t.home() start = -> t.wear 'openicon:magic-tophat' tick off t.click (event) -> play() play = -> t.wear 'openicon:animals-rabbit' tick -> t.moveto random 'position' t.click (event) -> start() start()
colors = [ red, orange, yellow green, blue, purple] speed 20 for end in [0..colors.length] for start in [0..end] dot black, 3 fd 10 rt 4 for c in colors[start...end] dot c fd 10 rt 4
key = 13 a2z = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' rot = a2z[key...].concat a2z[...key] box = write '<input>' out = write '' box.keyup -> result = for c in box.val() char = c.toUpperCase() if char in a2z rot[a2z.indexOf char] else char out.text result.join ''
choices = (menu, sofar = []) -> if menu.length is 0 write sofar.join ' ' else for item in menu[0] choices menu[1...], sofar.concat item choices [ ['small', 'medium', 'large'] ['vanilla', 'chocolate'] ['cone', 'cup'] ]
list = (random 10 for x in [1..8]) list.sort() write list
show = (points, highlight) -> render = for k, v of points if Number(k) in highlight "<mark>#{v}</mark>" else "#{v}" write "<div>#{render.join ','}</div>" list = 'SORTME'.split '' show list, [] for i in [0 ... list.length - 1] for j in [i + 1 ... list.length] if list[i] > list[j] [list[i], list[j]] = [list[j], list[i]] show list, [i, j]
sketch = (points) -> cg() pen null for p in points moveto p pen red dot black array = [] button 'scatter', -> array = for x in [1..10] random 'position' sketch array button 'sort', -> array.sort (a, b) -> a.pageX - b.pageX sketch array
[width, height] = [9, 9] grid = table(width, height).home() sides = [ {dx: 0, dy: -1, ob: 'borderTop', ib: 'borderBottom'} {dx: 1, dy: 0, ob: 'borderRight', ib: 'borderLeft'} {dx: 0, dy: 1, ob: 'borderBottom', ib: 'borderTop'} {dx: -1, dy: 0, ob: 'borderLeft', ib: 'borderRight'} ] isopen = (x, y, side) -> return /none/.test( grid.cell(y, x).css side.ob) isbox = (x, y) -> return false unless ( 0 <= x < width and 0 <= y < height) for s in sides if isopen x, y, s return false return true makemaze = (x, y) -> loop adj = (s for s in sides when isbox x + s.dx, y + s.dy) if adj.length is 0 then return choice = random adj [nx, ny] = [x + choice.dx, y + choice.dy] grid.cell(y, x).css choice.ob, 'none' grid.cell(ny, nx).css choice.ib, 'none' makemaze nx, ny wander = (x, y, lastdir) -> moveto grid.cell y, x for d in [lastdir + 3 .. lastdir + 7] dir = d % 4 s = sides[dir] if isopen x, y, s then break turnto grid.cell y + s.dy, x + s.dx unless dir is lastdir direct -> wander x + s.dx, y + s.dy, dir makemaze 0, 0 speed 5 wander 4, 4, 0
grid = table 3, 3, {width: 48, height: 48, font: "32px Arial Black", background: "wheat"} grid.home() board = [0, 0, 0, 0, 0, 0, 0, 0, 0] grid.cell().click -> move = grid.cell().index this return unless winner() is 0 and board[move] is 0 board[move] = 1 $(this).text 'X' setTimeout respond, 500 respond = -> response = bestmove(-1).move if response? board[response] = -1; grid.cell().eq(response).text 'O' colorwinner() bestmove = (player) -> win = winner() if win != 0 then return {move: null, advantage: win} choices = {'-1': [], '0': [], '1': []} for think in [0..8] when board[think] is 0 board[think] = player outcome = bestmove(-player).advantage choices[outcome].push {move: think, advantage: outcome} board[think] = 0 for favorite in [player, 0, -player] when choices[favorite].length return random choices[favorite] return {move: null, advantage: 0} rules = [[0,1,2],[3,4,5],[6,7,8],[0,3,6],[1,4,7],[2,5,8],[0,4,8],[2,4,6]] winner = -> for row in rules if board[row[0]] and board[row[0]] is board[row[1]] is board[row[2]] return board[row[0]] return 0 colorwinner = -> for row in rules if board[row[0]] and board[row[0]] is board[row[1]] is board[row[2]] for n in row grid.cell().eq(n).css {color: red}
|
|
Colors | white | gainsboro | silver | darkgray | gray | dimgray | black |
---|---|---|---|---|---|---|
whitesmoke | lightgray | lightcoral | rosybrown | indianred | red | maroon |
snow | mistyrose | salmon | orangered | chocolate | brown | darkred |
seashell | peachpuff | tomato | darkorange | peru | firebrick | olive |
linen | bisque | darksalmon | orange | goldenrod | sienna | darkolivegreen |
oldlace | antiquewhite | coral | gold | limegreen | saddlebrown | darkgreen |
floralwhite | navajowhite | lightsalmon | darkkhaki | lime | darkgoldenrod | green |
cornsilk | blanchedalmond | sandybrown | yellow | mediumseagreen | olivedrab | forestgreen |
ivory | papayawhip | burlywood | yellowgreen | springgreen | seagreen | darkslategray |
beige | moccasin | tan | chartreuse | mediumspringgreen | lightseagreen | teal |
lightyellow | wheat | khaki | lawngreen | aqua | darkturquoise | darkcyan |
lightgoldenrodyellow | lemonchiffon | greenyellow | darkseagreen | cyan | deepskyblue | midnightblue |
honeydew | palegoldenrod | lightgreen | mediumaquamarine | cadetblue | steelblue | navy |
mintcream | palegreen | skyblue | turquoise | dodgerblue | blue | darkblue |
azure | aquamarine | lightskyblue | mediumturquoise | lightslategray | blueviolet | mediumblue |
lightcyan | paleturquoise | lightsteelblue | cornflowerblue | slategray | darkorchid | darkslateblue |
aliceblue | powderblue | thistle | mediumslateblue | royalblue | fuchsia | indigo |
ghostwhite | lightblue | plum | mediumpurple | slateblue | magenta | darkviolet |
lavender | pink | violet | orchid | mediumorchid | mediumvioletred | purple |
lavenderblush | lightpink | hotpink | palevioletred | deeppink | crimson | darkmagenta |