Pencilcode
Pencilcode
A Programming Primer
David Bau
Visit http://pencilcode.net/ to run your programs.
Primer:
100 Little Projects
1. Lines
2. Points
3. Loops
4. Nesting
5. Functions
6. Parameters
7. Time
8. Output
9. Input
10. Numbers
11. Computation
12. Objects
13. Arrays
14. Recursion
15. Randomness
16. Sets
17. Text
18. Motion
19. Concurrency
20. Styles
21. Selectors
22. Events
23. Slicing
24. Sorting
25. Search
26. Intelligence
Contents
Part 2
Appendix:
One Project in Detail
1. Running Pencil Code
2. Keeping a Secret
3. Computers are Fine Calculators
4. Strings and Numbers
5. Creating Graphics
6. Making our First Program
7. Hurry Up and Wait
8. Using "for" to Repeat
9. Using "if" to Choose
10. Input with "read"
11. Using "while" to Repeat
12. Improving our Game
13. Making it Look Like Hangman
14. Picking a Random Secret
15. Loading a List from the Internet
16. The Whole Hangman Program
17. Making it Yours
Next Steps
Reference
Primer
Square
pen blue
fd 100
rt 90
fd 100
rt 90
fd 100
rt 90
fd 100
rt 90
Triangle
pen black
fd 80; rt 120
fd 80; rt 120
fd 80; rt 120
House
speed 5
pen orange
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
Turtle
pen green
rt 360, 10
lt 45, 30
rt 360, 8
lt 90, 50
rt 360, 8
lt 90, 30
rt 360, 8
lt 90, 50
rt 360, 8
lt 45, 30
2. Points
Dot Row
rt 90; dot lightgray
fd 30; dot gray
fd 30; dot()
fd 30
Message
message = 'Hello You.' message
see 'message' Hello You.
see message
Lighthouse
pen crimson
fd 60; label 'GO'
rt 30
fd 40; rt 120; dot gold, 30 GO
fd 40; rt 30
fd 60; rt 90
fd 40; rt 90
Smiley
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
lt 120, 35
ht()
Bullseye
x = 18 90
see x * 5
dot black, x * 5
dot white, x * 4
dot black, x * 3
dot white, x * 2
3. Loops
Rectangle
pen green
for d in [50, 100, 50, 100]
fd d
rt 90
Rainbow
for c in [
red
orange
yellow
green
blue
violet
]
pen c
rt 360, 50
fd 10
Range
see [1..5] [1, 2, 3, 4, 5]
see [1...5] [1, 2, 3, 4]
Square Loop
pen blue
for [1..4]
fd 100
rt 90
Gold Star
pen gold, 3
for [1..5]
fd 100
rt 2 * 360 / 5
Descending Loop
pen purple
for x in [50..1] by -1
rt 30, x
4. Nesting
Violet
pen blueviolet
for [1..5]
rt 72
for [1..3]
fd 50
rt 120
Combinations
for outside in [skyblue, violet, pink]
for inside in [palegreen, orange, red]
dot outside, 21
dot inside, 7
fd 25
rt 36
Decorated Nest
pen turquoise
for [1..10]
dot blue
for [1..4]
fd 50
rt 90
lt 36
bk 50
Catalog
speed 100
rt 90
for color in [red, gold, green, blue]
jump 40, -160
for sides in [3..6]
pen path
for [1..sides]
fd 100 / sides
lt 360 / sides
fill color
fd 40
5. Functions
Scoot Function
pen purple
scoot = (x) -> fd 10 * x
rt 90
scoot 7
Spike Function
spike = (x) ->
fd x
label x
60
bk x
10
20
pen crimson
30
50
for n in [1..6] 40
spike n * 10
rt 60
Square Function
square = (size) ->
for [1..4]
fd size
rt 90
pen red
square 80
jump 15, 15
pen firebrick
square 50
Tee Function
tee = ->
fd 50
rt 90
bk 25
fd 50
pen green
tee()
pen gold
tee()
pen black
tee()
6. Parameters
Polygon
polygon = (c, s, n) ->
pen c
for [1..n]
fd s
rt 360 / n
pen null
Rule
rule = (sizes) ->
for x in sizes
fd x
bk x
rt 90; fd 10; lt 90
pen black
rule [50, 10, 20, 10, 50, 10, 20, 10, 50]
Starburst
starburst = (x, shape) ->
for z in [1..x]
shape()
rt 360 / x
stick = -> fd 30; bk 30
pen deeppink
starburst 3, stick
jump 0, -60
starburst 20, stick
jump 0, -90
starburst 10, -> fd 30; dot blue; bk 30
jump 0, -100
starburst 5, ->
fd 30
starburst 7, ->
fd 10
bk 10
bk 30
7. Time
Pause
speed 100
pen red
for x in [1..20]
fd 80
rt 100
if x is 10
pause 2
Second Hand
speed Infinity
advance = ->
pen lightgray
bk 100
rt 5
pen red
fd 100
tick advance
Countdown
seconds = 5 5
tick ->
4
if seconds is 0
write "Time's up!" 3
tick null 2
else 1
write seconds
Time's up!
seconds = seconds - 1
Click Draw
speed Infinity
pen green
tick ->
moveto lastclick
Move Draw
speed Infinity
pen orange
Imagery
url = "http://upload.wikimedia.org/wikipedia" +
"/commons/6/61/Baby_Gopher_Tortoise.jpg"
write """<center><img src="#{url}" width=100>
</center>"""
Bold Statement
n = write "<h1>Notice</h1>"
write """
<p>This long paragraph has
<b>bold</b>, <i>italic</i>,
Notice
and <u>underlined</u> text.
Horizontal rule below.</p> This long paragraph has bold,
"""
italic, and underlined text.
write "<hr>"
write """ Horizontal rule below.
<p><a href="//pencilcode.net/">
Link</a> with an <a>.
</p> Link with an <a>.
"""
n.css
background: pink
Graffiti
n = write "<h1>Notice</h1>"
write """
<p>This long paragraph has
<b>bold</b>, <i>italic</i>,
N
</p>"""
This long paragraph has bold,
ic
n.css
background: pink
e
Polygon to Order
await read "Color?", defer color Color? green
await read "Sides?", defer sides
Sides? 8
pen color
for [1..sides]
fd 30
rt 360 / sides
Guess My Number
secret = random [1..100]
turns = 5
write "Guess my number."
while turns > 0 Guess my number.
await readnum defer pick ⇒ 50
if pick is secret Too small!
write "You got it!"
4 left.
break
if 1 <= pick < secret ⇒ 75
write "Too small! " Too big!
turns = turns - 1 3 left.
else if secret < pick <= 100
⇒ 64
write "Too big! "
turns = turns - 1 Too big!
if turns > 1 2 left.
write "#{turns} left." ⇒ 55
else if turns is 1
write "Last guess!"
Too small!
else Last guess!
write "Game over." ⇒ 59
write "It was #{secret}." You got it!
break
Polygon Revisited
read "Color?", (color) -> Color? red
read "Sides?", (sides) ->
Sides? 8
pen color
for [1..sides]
fd 30
rt 360 / sides
10. Numbers
Parsing
write '5' + '3' 53
write Number('5') + Number('3')
8
Ways to Count
counter = 0 1a
write ++counter + 'a'
write (counter += 1) + 'b'
2b
write (counter = counter + 1) + 'c' 3c
Circle Measurements
area = (radius) -> radius 1
Math.PI * radius * radius
a 3.141592653589793
circumference = (radius) -> c 6.283185307179586
2 * Math.PI * radius radius 5
a 78.53981633974483
for r in [1, 5, 10]
write 'radius ' + r
c 31.41592653589793
write 'a ' + area r radius 10
write 'c ' + circumference r a 314.1592653589793
c 62.83185307179586
Hypotenuse
hypotenuse = (a, b) -> 5
Math.sqrt(a * a + b * b)
13
write hypotenuse 3, 4 14.142135623730951
write hypotenuse 5, 12 14
write hypotenuse 10, 10
write Math.floor(hypotenuse(10, 10))
Euclid's Method
gcf = (a, b) -> gcf(120,80)=40
if a > b
gcf(120,81)=3
return gcf b, a
remainder = b % a gcf(120,82)=2
if remainder is 0 gcf(120,83)=1
return a gcf(120,84)=12
gcf remainder, a
gcf(120,85)=5
for x in [80..88] gcf(120,86)=2
write "gcf(120,#{x})=" + gcf(120,87)=3
gcf(120, x) gcf(120,88)=8
11. Computation
Power
power = (x, p) -> 2
answer = 1
4
answer *= x for i in [0...p]
return answer 8
for n in [1..5] 16
write power(2, n) 32
Built-in Power
write Math.pow(2, 5) 32
write Math.pow(2, 0.5)
1.4142135623730951
Factorial
factorial = (x) -> 1
if x < 1 then 1
2
else x * factorial(x - 1)
for x in [1..4] 6
write factorial x 24
Fibonacci
fib = (n) -> 2
if n <= 2
3
1
else 5
fib(n - 1) + fib(n - 2) 8
for x in [3..8] 13
write fib x
21
Complex
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, 1, n/20), s
12. Objects
Page Coordinates
startpos =
pageX: 80
pageY: 10
moveto startpos
pen coral
moveto
pageX: 30
pageY: 50
moveto {pageX: 160, pageY: 50}
Figure
figure = [
{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 line in figure
pen line.c
slide line.x, line.y
Scoring
points =
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) -> bison: 7
total = 0 armadillo: 12
for letter in word
total += points[letter]
giraffe: 14
write "#{word}: #{total}" zebra: 16
score x for x in ['bison', 'armadillo', 'giraffe', 'zebra']
Methods
memo =
sum: 0
Total 495 / 11
count: 0
add: (x) -> @sum += x; @count += 1 Average 45
stats: ->
write "Total #{this.sum} / #{this.count}"
write "Average #{this.sum / this.count}"
memo.add(n) for n in [40..50]
memo.stats()
13. Arrays
Story
story = [ Exclamation? Yowzer
'Exclamation?'
adverb? slowly
'! he said '
'adverb?' noun?
' as he jumped into his convertible '
'noun?'
' and drove off with his '
'adjective?'
' wife.'
]
for i in [0...story.length] by 2
prompt = story[i]
await read prompt, defer answer
story[i] = answer
write story.join ''
Primes
primes = [] 2
candidate = 2
3
while primes.length < 10
composite = false 5
for p in primes 7
if candidate % p is 0 11
composite = true
13
break
if not composite 17
primes.push candidate 19
write candidate 23
candidate = candidate + 1
29
Fractal Fern
speed 1000
fern = (x) ->
if x > 1
fd x
rt 95
fern x * .4
lt 190
fern x * .4
rt 100
fern x * .8
lt 5
bk x
pen green
fern 50
Koch Snowflake
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 [1..3]
flake 150
rt 120
fill 'azure strokeStyle navy'
15. Randomness
Two Dice
onedice = -> 6
random [1..6]
9
twodice = ->
onedice() + onedice() 11
for [1..5] 8
write twodice() 10
Random Walk
for [1..20]
fd 10
rt random(181) - 90
dot gray, 5
Cubism
for [1..14]
pen random [red,black,blue]
fd random 70
rt 90
Confetti
for [1..300]
moveto random position
dot random color
Decimal Random
for [1..2] 0.3955826204144705
write Math.random()
0.46279336348825273
Five Flips
c = [0, 0, 0, 0, 0, 0]
for [1..500]
heads = 0
for [1..5] 0:21
heads += random 2 1:73
c[heads] += 1 2:160
for h of c
3:145
b = write h + ":" + c[h]
b.css 4:85
background: skyblue 5:16
width: c[h]
16. Sets
Scatter
turtle.remove()
s = hatch 15, orange
s.pen gold
s.plan ->
this.rt random 360
this.fd Math.abs(20 * random normal)
Turtle Race
fd 200; pen red; slide 200, 0
finished = 0
racers = hatch 7
racers.plan (j) ->
@wear random color
@speed 5 + random normal
@slide j * 25 + 25, 0
while not @touches red
@fd random 5
await @done defer()
@label ++finished
Rescue Class
turtle.remove()
speed 100
randpos = ->
[50 * random(normal), 50 * random(normal)]
hatch(20, green).scale(0.75).plan ->
this.moveto randpos()
this.addClass 'kid' 1
hatch(3, red).plan (num) -> 1
2
hero = this 2
2
count = 0
hero.moveto randpos() 0
hero.pen red 0
while true 0
0
await hero.done defer()
kid = $('.kid').nearest(hero).eq(0)
if kid.length is 0
write "hero ##{num} got #{count}"
return
else if hero.touches(kid)
count += 1
kid.label num
kid.remove()
else
hero.turnto(kid).fd(5)
17. Text
text = """If you can look into the seeds of time
And say which grain will grow and which will not,
Speak, then, to me."""
Substr
see text.indexOf 'which' 47
see text.substr 47, 7 which g
Unicode
see 'charCode', text.charCodeAt(0) charCode 73
see 'string', String.fromCharCode(73) string I
for x in [88, 188, 9988] 88 X
see x, String.fromCharCode(x) 188 ¼
9988 ✄
Match
see text.match /w....g.../ ["will grow"]
see text.match /[a-z][a-z]/ ["yo"]
see text.match /\s[a-z][a-z]\s/ [" of "]
see text.match /\b[a-z][a-z]\b/ ["of"]
see text.match /\b[a-z][a-z]\b/gi ["If", "of", "to", "me"]
see text.match /\b[gn][a-z]*\b/g ["grain", "grow", "not"]
see text.match /z/ null
Split
lines = text.split /\n/ Speak, then, to me.
see lines[2] ["If", "you", "can"]
words = text.split /\s+/
see words[0..2]
Groups
pattern = /\b([a-z]+) of ([a-z]+)\b/ group 0: seeds of time
matched = pattern.exec text group 1: seeds
for g in [0..2] group 2: time
see "group #{g}: #{matched[g]}"
Replace
r = text.replace /[A-Z][a-z]*/g, If you can look into the
"<mark>$&</mark>"
seeds of time
r = r.replace /\n/g,
"<br>" And say WHICH grain
r = r.replace /\bw[a-z]*\b/g, WILL grow and WHICH
(x) -> x.toUpperCase() WILL not,
write r
Speak, then, to me.
18. Motion
Bounce
speed Infinity
pen purple
vy = 10
tick 20, ->
slide 1, vy
if inside(window)
vy -= 1
else
vy = Math.abs(vy) * 0.9
Tag
speed Infinity
write "Catch blue!"
Catch blue!
b = hatch blue
bk 100
tick 10, ->
turnto lastmousemove
fd 5
b.turnto 45 + direction b
b.fd 6
if b.touches(turtle)
write "You win!"
tick off
else if not b.touches(window)
write "Blue got away!"
tick off
Orbit
speed Infinity; pen orange
G = 100
v = [0, 1]
sun = hatch(gold)
sun.slide G, 0
tick 100, ->
sun.moveto lastclick
s = sun.getxy()
p = getxy()
d = distance(sun)
d3 = d * d * d
if d3 > 0 then for i in [0..1]
v[i] += G * (s[i] - p[i]) / d3
slide v[0], v[1]
19. Concurrency
Race Condition
b = hatch blue
r = hatch red
b.lt 90; b.pen blue
b.play 'g'
b.rt 170, 50
b.dot 50, blue
r.rt 90; r.pen red
r.play 'd'
r.lt 170, 50
r.dot 50, red
Line Follower
dot orange, 220
dot white, 180
jump 100, 0
pen skyblue
while true
fd 3 + random 3
await done defer()
if touches orange
lt 5
else
rt 5
Shared Memory
shared = { d: 0 } ⇒ 30
do ->
⇒ -20
while true
await read defer shared.d ⇒
do ->
pen red
while true
fd 10
await done defer()
rt shared.d
Message Passing
button 'send color', -> send color
send 'go', random color
do ->
for x in [1..25]
await recv 'go', defer c
pen c
fd 50
rt 88, 10
20. Styles
Thick Lines
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
Border
text = write 'Outlined.' Outlined.
text.css { border: '2px solid red' }
turtle.css { border: '3px dotted blue' }
Font
h = write 'Fancy!'
h.css
font: '55px Helvetica'
fontStyle: 'italic'
Fancy!
Text Decoration
write 'Before'
d = write 'Decorated'
write 'After'
d.css
display: 'inline-block'
cursor: 'pointer' Before
padding: '10px'
Deco
margin: '-5px' rate
opacity: '0.7'
d
After
color: 'white'
fontSize: '110%'
letterSpacing: '5px'
textDecoration: 'underline'
boxShadow: '1px 1px black'
background: 'mediumaquamarine'
transform: 'rotate(10deg)translateX(20px)'
21. Selectors
Tags
write """<style>
h2 { color: red; }
h3 { background: bisque; } Stylesheet
</style>
"""
write "<h2>Stylesheet</h2>"
Tag Styles
write "<h3>Tag Styles</h3>"
write "<h3>style specific tags</h3>" style specific tags
Classes
write """
<style> Class a
.a { text-decoration: underline; }
.b { font-style: italic; }
</style> Class b
"""
write "<p class='a'>Class a</p>" Classes apply to any tag.
write "<h3 class='b'>Class b</h3>"
write "<p class='b'>Classes apply to any tag.</p>"
Composites
write """
1 2 3 4 5 6 7 8 9 10 11
<style>
i { border: 1px solid black; margin: 2px; 12 13 14 15 16 17 18 19
display:inline-table }
i:nth-of-type(1) { background: gold } 20 21 22 23 24
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>"
jQuery
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 } avocado
$('mark').animate {
padding: '5px' }
$('mark:nth-of-type(2n)').animate {
opacity: 0.3 }
22. Events
Shift Click
$(document).click (event) ->
see event
if event.shiftKey
pen blue
else
pen null
moveto event
Arrow Keys
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
Magic Hat
speed Infinity
turtle.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()
23. Slicing
Choices
choices = (menu, sofar = []) -> small vanilla cone
if menu.length is 0 small vanilla cup
write sofar.join ' ' small chocolate cone
else for item in menu[0] small chocolate cup
choices menu[1...], medium vanilla cone
sofar.concat item medium vanilla cup
medium chocolate cone
choices [ medium chocolate cup
['small', 'medium', 'large'] large vanilla cone
['vanilla', 'chocolate'] large vanilla cup
['cone', 'cup'] large chocolate cone
] large chocolate cup
Shuffle
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] J♦/3♠/7♣/9♥/6♠
choice = random(i + 1)
3♥/10♦/7♥/7♦/8♥
[d[i], d[choice]] = [d[choice], d[i]]
deal = (d, n) -> d.splice(-n) A♦/Q♥/2♣/8♠/K♦
shuffle deck
for [1..3]
write deal(deck, 5).join('/')
Caesar Cipher
key = 13
a2z = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
rot = a2z[key...].concat a2z[...key]
box = write '<input>'
out = write ''
attack at dawn
box.keyup ->
result = for c in box.val() NGGNPX NG QNJA
char = c.toUpperCase()
if char in a2z
rot[a2z.indexOf char]
else
char
out.text result.join ''
24. Sorting
Quick Sort
list = (random 10 for [1..8]) 3,4,4,5,6,7,7,8
list.sort()
write list
array = []
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'}
]
makemaze 0, 0
speed 5
wander 4, 4, 0
26. Intelligence
Tic Tac Toe
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
O
respond = ->
response = bestmove(-1).move
if response? X
board[response] = -1;
grid.cell().eq(response).text 'O'
colorwinner()
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}
Appendix
Hangman
One Project in Detail
In this section, we use Pencil Code to make a game of hangman from
scratch.
It takes a couple hours to learn enough programming to make a game of
hangman.
We will learn about:
Memory and naming
Computer arithmetic
Using functions
Simple graphics
How to make a program
Input and output
Loops and choices
Delays and synchronization
Connecting to the internet
At the end we will have a game we can play.
1. Running Pencil Code
Go to pencilcode.net.
Click on "Let's Play!"
The screen should look like this:
The left side of the screen is where you type in your program, and the right
is where programs run. The lower right corner is a test panel where you
type code and run it right away.
While exploring the projects in this book, you can also use the test panel in
the lower right corner to ask for help with how commands work.
> secret
"crocodile"
>
> number
▶number is not defined
>
Don't worry. This is fine. You just need to teach CoffeeScript what
"number" is and try again.
> number = 43
43
> number
43
>
3. Computers are Fine Calculators
A computer is better than any calculator at doing math. Let's try.
> 2+33+66
101
In CoffeeScript, plus and minus use the usual symbols + and −. Times and
divide are done using the * and / symbol.
> n=123456789
123456789
> n*n*n
1.8816763717891548e+24
The e+24 at the end is the way that large numbers are written in
CoffeeScript. It means 1.8816763717891548 × 1024. CoffeeScript
calculates numbers with 15 digits of precision.
There are several ways to change a number. For example, += changes a
variable by adding to it.
> n += 1
123456790
> n
123456790
>
* times x < 24 is x less than 24? Number(digits) makes a number from a string
/ divide x > 24 is x more than 24? n += 1 change n by adding one
If we try to convert a string to a number in a way that does not make sense,
we get NaN, which stands for "Not a Number".
5. Creating Graphics
In Pencil Code, we can create graphics by using the turtle. There are five
basic turtle functions:
code meaning
pen red chooses the pen color red
fd 100 moves forward by 100 pixels
rt 90 turns right by 90 degrees
lt 120 turns left by 120 degrees
bk 50 slides back by 50 pixels
In the test panel, enter two commands to draw a line:
The reference at the end of this book lists many other colors that can be
used. To stop drawing, use "pen null" to select no pen.
Try turning the turtle and drawing another line. Notice that rt turns the
turtle in place, and we need to move the turtle with fd to draw a corner.
...
> rt 90
> fd 100
>
If we give a second number to rt, the turtle will move while turning and
form an arc. Try making a circle:
...
> rt 360, 30
>
pen blue
fd 150
rt 90
fd 50
rt 90
fd 20
A website will be created with your account name. If I choose the account
name "newbie," a website is created at "newbie.pencilcode.net".
Once you have saved the program with the name "hangman," it is available
at two different addresses on pencilcode:
http://yourname.pencilcode.net/edit/hangman - this is where anyone
can see and edit your program, but you need your password to save
any changes.
http://yourname.pencilcode.net/home/hangman - here is where you
can share and run your program without showing the code.
7. Hurry Up and Wait
Write a welcome message after drawing the hangman shape:
Notice that the Pencil Code Turtle is as slow as a turtle! Unless we speed it
up with the speed function, the turtle takes its own slow time long after we
have asked it to move, and the welcome message appears before the turtle
is finished.
We can do two things to help with the slow turtle:
Change the number of moves it makes per second using "speed."
Ask the program to wait for the turtle, using "await done defer()."
Now the turtle moves faster, and the program waits until the turtle is done
before writing the welcome message.
A couple things to know:
Do not use a space between defer and the parentheses "defer()".
We can make the turtle move instantly by using "speed Infinity".
Even if you have programmed before, await/defer may be new to you.
These keywords create continuations, and they are part of Iced CoffeeScript.
To explore how they work in more detail, look up Max Krohn's Iced
CoffeeScript page online.
8. Using "for" to Repeat
We can repeat steps in a program with the "for" command.
Try adding three lines to the end of our program so that it looks like this:
write 'time to play hangman'
secret = 'crocodile'
for letter in secret
write letter
The program is saying: for every letter in the secret, write letter. So the
computer repeats "write letter" nine times, once for each letter.
If it doesn't work, check the program and make sure the line after the for is
indented; that is how CoffeeScript knows which line to repeat.
Once you have the hang of it, keep the word secret by changing the
program to write underscores instead of letters:
Notice how "append" instead of "write" puts text on the same line instead of
starting a new line each time:
Adding "write 'guess a letter'" will let the player know when to enter a
guess.
The "show += guess" line adds the guess to the string of shown letters.
Let's run it.
When we run the program, it will show us where our guessed letter
appears.
11. Using "while" to Repeat
We need to let the player take more than one turn.
"while turns > 0" repeats everything indented under it while the player still
has turns left.
if blanks is 0
write 'You win!'
break
Each time the word is printed, the "blanks" number starts at zero and
counts up the number of blanks. If it ends up at zero, it means there are no
blanks. So the player has guessed every letter and has won! In that case,
the "break" command breaks out of the "while" section early, even though
there are still turns left.
The "if guess not in secret" line checks if the guess was wrong. We only
count down the "turns" if our guess was wrong.
When we guess wrong, we also print a bunch of messages like "Nope" and
how many more turns we have. When we are wrong for the last time we
print the secret.
13. Making it Look Like Hangman
It will be more fun if we make our game look like Hangman.
All we need to do is draw parts of the poor hangman person when there is a
wrong guess. Try adding something like this to the wrong guess part:
...
write 'Nope.'
write turns + ' more turns'
if turns is 4 then lt 90; rt 540, 10; lt 90
if turns is 3 then fd 20; lt 45; bk 30; fd 30
if turns is 2 then rt 90; bk 30; fd 30; lt 45; fd 30
if turns is 1 then rt 45; fd 30
if turns is 1 then fd 30
if turns is 0
bk 30; lt 90; fd 30
await done defer()
write 'The answer is ' + secret
The semicolons (;) let you put more than one step on the same line. Notice
when putting the "if" on the same line as the commands to run, we must
use the word "then" between the test and the commands.
Try making variations on the hangman drawings for each step.
Whenever we want to pause the program to wait for the turtle to finish
drawing, we can use "await done defer()".
14. Picking a Random Secret
The only problem with the game is that it always plays the same secret
word. We should use the random function to choose a random word.
Change the line that sets the secret so that it looks like this:
...
write 'time to play hangman'
secret = random ['tiger', 'panda', 'mouse']
show = 'aeiou'
...
The square brackets [ ] and commas make a list, and the random function
picks one thing randomly from the list.
Of course, we can make the list as long as we like. Here is a longer list:
...
write 'time to play hangman'
secret = random [
'crocodile'
'elephant'
'penguin'
'pelican'
'leopard'
'hamster'
]
...
The brackets do not have to be on the same line, but we do need two!
When we list items on their own lines, the commas are optional.
15. Loading a List from the Internet
There is a longer list of animals on the internet at the address
http://pencilcode.net/data/animals.
We can load this data using a jQuery function "$.get". (Read more about
jQuery at learn.jquery.com.)
The code looks like this:
...
write 'time to play hangman'
await $.get 'http://pencilcode.net/data/animals', defer animals
secret = random animals.split '\n'
...
Tell $.get to resume the program after putting the answer in "animals."
The special string '\n' is the newline character between lines in a file.
Notice that the "\" is a backslash, not the ordinary slash.
Split the animals string into an array, with one entry per line.
speed 10
pen blue
fd 150
rt 90
fd 50
rt 90
fd 20
await done defer()
write 'time to play hangman'
await $.get 'http://pencilcode.net/data/animals', defer animals
secret = random animals.split '\n'
show = 'aeiou'
turns = 5
if blanks is 0
write 'You win!'
break
Appearance Properties
ht() hide the turtle turtle name of the main turtle
st() show the turtle getxy() [x, y] position relative to home
scale 8 do everything 8x bigger direction() direction of turtle
wear yellow wear a yellow shell hidden() if the turtle is hidden
fadeOut() fade and hide the turtle touches(obj) if the turtle touches obj
remove() totally remove the turtle inside(window) if enclosed in the window
lastmousemove where the mouse last moved
Output
write 'hi' adds HTML to the page Sets
p = write 'fast' remembers written HTML g = hatch 20 hatch 20 new turtles
p.html 'quick' changes old text g = $('img') select all <img> as a set
button 'go', adds a button with g.plan (j) -> direct the jth turtle to go
-> fd 10 an action @fd j * 10 forward by 10j pixels
read (n) -> adds a text input with
write n*n an action Other Functions
t = table 3,5 adds a 3x5 <table> see obj inspect the value of obj
t.cell(0, 0). selects the first cell of the
speed 8 set default speed
text 'aloha' table and sets its text
rt 90, 50 90 degree right arc of radius 50
tick 5, -> fd 10 go 5 times per second
Other Objects click -> fd 10 go when clicked
$(window) the visible window random [3,5,7] return 3, 5, or 7
$('p').eq(0) the first <p> element random 100 random [0..99]
$('#zed') the element with id="zed" play 'ceg' play musical notes
Colors
white gainsboro silver darkgray gray dimgray black
whitesmoke lightgray lightcoral rosybrown indianred red maroon