Past and Future Turtles: The Evolution of the Logo Programming Language (Part 1)

When I was a young child, one of my best friends was a turtle.

Not a real turtle, although that would have been fun, but a virtual one. My turtle lived inside of an Apple II, an early 8-bit computer, at my elementary school.

When I first met her, my turtle, she didn’t do much. She just sat there. It didn’t take long for me to realize that in order to get her to do something, I would need to prompt her. To do this, there was a literal prompt on the screen, beckoning me to type something.

?

And so I typed FORWARD, thinking that this should, obviously, move the turtle forward.

NOT ENOUGH INPUTS TO FORWARD

Undeterred, I revised my input to FORWARD 10, just picking an arbitrary number. Although I was only six years old, I deduced that FORWARD needed a quantity, quantities were numbers and well, ten was a good start.

And hooray, the turtle moved! I was in love with my turtle from that moment on. I learned that she could also move BACK, and turn LEFT and RIGHT. I didn’t know what degrees were when I first met my turtle, but by the time I finished our first session together, I did!

Seymour Papert in 1971

That afternoon in 1981, I had learned some of a programming language called Logo. The father of Logo was a mathematician and philosopher named Seymour Papert. Interested in learning how to improve mathematics education in young children, in the early 1960s, he had studied under Jean Piaget, a Swiss psychologist who championed a philosophy of learning known as constructivism.

When children are given new information, for example, that a full turn is made up of 360 degrees, they are likely to only accept that information if they already have the underlying understanding required, such as that a turn can be divided in half, quarters and so on, down to 360ths. Or even the concept of a number as high as 360 can exist in the first place.

Otherwise, they are likely to either misinterpret the new information to fit their current understanding (“I only understand numbers as high as 100, and so they must mean 100”) or will simply ignore it, with a silent internal ‘syntax error’.

This can improve if a) the teacher explains numbers up to 360, b) the teacher explains division and then finally c) the teacher explains that when you spin around, you are making a circle (hold out your arm! The point of your finger draws a circle when you spin) and if you spin around halfway, you’re moving 180 degrees and so on.

This may still not be enough. If the child fails to understand a, b and / or c, they still won’t understand it.

However, if the child is able to actively explore these concepts in an environment that has some measure of feedback, the likelihood of their gaining understanding improves. For example, if the teacher suggests they turn randomly, and the teacher tells them how far they have turned each time they do it, they will soon learn that if they turn halfway, they have turned 180 degrees. They will learn that a full turn is 360 degrees. They will understand that the next number after 100 is 101, and hence the next number after 200 is 201. And so on.

This is what Papert learned under Piaget. But obviously, while desirable it’s not practical for each child to have an adult giving them feedback on everything they do until they understand it. The world just doesn’t (and probably will never have) a 1:1 student to teacher ratio. This was a problem Piaget and Papert simply couldn’t surmount.

But in the early 1960s, a new technology was emerging, one that Papert realized could remove his roadblock – the computer.

Computers did not tire, they did not lose patience. Although at that time large and small in number, it was not hard for Papert to see the future, a future where schools were full of terminals connected to computers, one for each child, with which the students could explore ‘mathland’, a simple environment where mathematical concepts could be demonstrated through trial and error. The more input students provided, and the more output they absorbed, the sooner they would grasp concepts. Computers seemed a perfect fit for the task of educating children using constructivist principles.

In 1961, Papert had met an American, Marvin Minsky, at a conference in England. They presented papers that were surprisingly similar, and connected as a result. So, powered by his idea of using computers to teach children, in 1964, Papert went to the US, and joined Minskey’s Artificial Intelligence Group, a team of researchers at the Massachusetts Institute of Technology (MIT).

Papert was impressed with the technology-centric culture at MIT, and attitude that everyone had the potential to learn anything they wanted to, a position Papert shared. The students under Minsky and Papert had free rein to work on whatever they wanted, encouraging experimentation and the practical testing of even the most wild theories. Papert saw how his students, when encouraged, would learn great amounts of knowledge on their own, and collaborate with others to get past roadblocks they encountered in their pursuits. At MIT these students were known as ‘hackers’.

One of these hackers, Daniel Bobrow, graduated and got a job at a research and development (R&D) firm called Bolt, Beranek and Newman. In the mid-1960s they had started exploring computer technologies, and their potential. Bobrow became head of their new Artificial Intelligence group. There, he met Wally Feurzeig, who was leading BBN’s education group. The space race had encouraged the US government to find ways of improving math education in schools, and BBN was hoping to find a solution. They had already developed ‘time-sharing’ technology which allowed a mainframe computer to be used by many people at the same time, they just needed software to run on it that children could use to learn.

Bobrow brought in Papert and introduced him to Feurzeig, and the three discussed the idea of developing a computing language for children, Papert’s Mathland. Around that time, BBN had a visitor who demonstrated a new programming language called BASIC. Rather than using memory addresses, BASIC used line numbers to track execution, and named variables that transparently linked to memory addresses. These abstractions made it much easier for non-computer scientists to create computer programs.

BBN’s researchers created a version of BASIC they called Telcomp, which Feurzeig modified to include strings, and called Stringcomp. BBN trialed Stringcomp (using teletypes, typewriters connected to a remote computer) in eight elementary and junior high-school classrooms in 1966. That year, Minsky’s assistant at MIT, Cynthia Solomon, joined Feurzeig’s team at MIT.

Seymour Papert at Muzzey Junior High School in 1966

After Papert visited these classrooms and saw the interaction between children and Stringcomp, he became convinced that BASIC was not the answer, and that a new language would need to be written, one more suited to learning.

Importantly, the new language would need to more adequately demonstrate how the computer came to its conclusions. Papert felt that due to computers’ requirements for literal instruction, children would be able to see how the computer ‘thought’ and realize that was how they themselves also thought, helping them break down problems into smaller elements the way a computer would when it solved them. Thus, the new language would serve a dual purpose, both teaching mathematics, and how mathematics are solved.

BASIC was too monolithic in its command-based structure, and those ‘smaller parts’ could not be shown to its users, happening behind the scenes and out of sight.

And so, the new language would both need to be able to accomplish what one could accomplish in BASIC, while doing so using smaller steps that could be inspected by novice programmers. But to avoid needless and redundant repetition of code, these steps would need to be able to be reused. Because of the philosophy behind it, Wally Feurzeig christened the new language ‘Logo’, derived from Logos, the greek word for ‘thought’.

Minsky, Papert and Solomon had a number of discussions about how Logo would work. Solomon had learned some of the Lisp programming language (a language where all code and data are written in the form of expressions and lists, the name Lisp short for LISt Processing) while Minsky’s assistant, and she appreciated its power for manipulating English language strings, which she recognized could be used as a method by which students could observe the effects of computer code on recognizable data, or data that they created themselves.

It also probably didn’t hurt that Lisp had been invented by the same BBN employee (and MIT alumnus) that had developed its time-sharing system. And so, it was decided that the new language would be a variant of Lisp.

However, Lisp had some drawbacks in terms of its use with younger coders. It had an extreme reliance on structure, using an intricate array of parentheses which often led to errors that were hard to resolve (leading to nicknames Lost in Stupid Brackets and Lots of Irritating Superfluous Parentheses). Its interpreter was also bulky, and not interactive, like BASIC.

In designing Logo, Papert, Minsky and Solomon took the expression, list and string elements of Lisp, removing much of the need for brackets by making assumptions about syntax parsing and inputs, and later allowing for the ‘stacking’ of what they called ‘primitives’ (functions which may or may not resolve to a value) on a single line, such that you could type:

PRINT SUM 4 4

and the computer would output 8, or:

TYPE 1 TYPE 2 TYPE 3

and the computer would output 123.

Lists allowed for the string manipulation Solomon had been hoping for:

(PRINT PICK [RED GREEN BLUE] PICK [DOG CAT BOAT])

BLUE BOAT

RED DOG

GREEN CAT

etc.

Logo was a lot more BASIC-like in its syntax and usage, while allowing for many features BASIC did not, such as the ability to create ‘procedures’, lists of primitives that could be named, and executed just like any other primitive, such as:

TO BOX

   REPEAT 4 [
      FORWARD 10
      RIGHT 90
   ] 

END

which could be executed simply by typing:

BOX

but even better:

TO POLY :SIDES :SIZE

   REPEAT :SIDES [
      FORWARD :SIZE
      RIGHT 360 / :SIDES
   ]

END

the colon indicating a variable or container for storing a value.

POLY 4 10

would re-create our box, but the user could provide any desired values, like SUM. This satisfied Papert’s need to have both the ability to demonstrate computer problem-solving in smaller chunks, while also allowing for the reuse of code. Students could create the BOX or POLY procedures themselves, then use them in other procedures. A picture would form in their minds of the hierarchy of execution, and they would understand better how the computer, and they themselves, thought.

Except that we are getting ahead of ourselves with BOX and POLY, because in the beginning Logo did not have a turtle! When Logo was initially trialled in a seventh-grade classroom (in 1968 at Muzzey Junior High School in Lexington, Massachusetts), students were using the same teletypes the Stringcomp trial had used, and they used Logo to manipulate lists and strings rather than a turtle. Which worked quite well to engage students who were strong in English, but failed to engage those who were not.

Cynthia Solomon (left) and Seymour Papert (right) at Muzzey Junior High in 1966

Also, on the teletype math was still just numbers, regardless of the more elegant way Logo could break down mathematical equations. Kids who didn’t ‘get’ numbers still didn’t get numbers! Papert craved some sort of graphical representation, but the technology at the time strongly precluded that. And so, towards the end of the trial, he had the idea of creating a physical robot, one that could move about on the floor, and draw out graphical representations of mathematic output.

Papert and Solomon left BBN and headed back to MIT, where they formed the Logo Group. In England, two robots had been developed that could wander about a space, their inventor dubbing them ‘tortoises’. The Logo Group developed their own robots, calling them turtles. Having access to expensive display hardware, they also developed a virtual turtle, one that lived on the computer screen.

They added primitives to Logo to control the turtle: FORWARD, BACK LEFT, RIGHT. And they discovered that Papert had been right – children took to the turtle, the turtle allowing Logo users to have a perspective inside the computer, that of the turtle, rather than depending on an understanding of abstract concepts of code paths or numbers. The procedural structure of Logo meant the turtle could be ‘taught’: taught how to draw a square, taught how to draw a polygon, creating them inside of its environment, interacting it and shaping it like a child scrawling on the wall of their bedroom.

The turtle allowed for an empathetic bond to form between it and the child, giving the child a dual sense of accomplishment when the turtle succeeded at what the child told it to do – both because the child correctly instructed the turtle, and the turtle successfully carried out those instructions, the result of the latter the evidence of the former. The child could also ‘think like the turtle’ when developing procedures and debugging, moving about the room as the turtle would, figuring out roughly what they needed the turtle to do, and then refining their program as needed.

An early Logo video display

While Logo’s string and list facilities are impressive, it is fair to say the turtle made Logo. Both the physical and virtual turtles were used by fifth graders at the Bridge School in Lexington in a trial during 1970 and 1971. But both robots and video terminals were expensive in the 1970s, and schools hadn’t widely adopted computer terminals; as such, there was no widespread use of Logo in the 1970s.

However, the emergence of the home computer market in the late 1970s provided an opportunity for Logo to reach a wider segment of the population. In 1980, Minskey, Papert, Solomon and two Canadians founded Logo Computer Systems Inc. (LCSI) and  in 1981 they published a version of Logo for the Apple II computer, which I booted up and met Seymour, Cynthia and Marvin’s turtle for the first time.

They would have been very happy I learned about degrees (and other things) from their turtle!

But where did Logo go from there? Carry on to Past and Future Turtles: Logo’s Adventures in Academia (Part 2)

And don’t forget to try our weblogo… or read the Hacker News discussion!

One-A-Day: Qtips

Today’s example is short but sweet. It creates a design made out of a bunch of qtip-like ‘sticks’ with balls on the ends.

It is a design made out of ‘almost squares’ (four sides each at an 85 degree angle to each other). The turtle then turns right 5 degrees, and slides left 20 before continuing to the next almost-square.

Each side of the almost-square is coloured based on its iteration in the almost-square loop, and the fill colour of the balls is set to match. Also, each iteration is raised an amount relative to its iteration, creating a pleasing 3D effect.

Click here to open the project in the viewer or open it in the webLogo IDE

TO qtips
  hideturtle
  clearscreen
  repeat 24 [
    repeat 4 [
      penup 
      setz repcount * 3 
      ;raise up the turtle based on the loop count
      pendown 
      setpencolor 10 + repcount
      ;set the pen color based on the loop count
      setfillcolor pencolor 
      ;for the spheres
      icosphere 2 
      rope 100 
      ;a rope is a cylinder-based line
      icosphere 2 
      right 85
    ] 
    right 5 
    penup
    slideleft 20 
    pendown
  ]
END

One-a-Day: FRAG

The FRAG primitive creates a filled shape out of the current turtle position and her last two positions. For example:

FD 100 RT 90 FD 100 FRAG

will create a triangle.

While turtleSpaces has a variety of shape primitives, sometimes you need to create an arbitrary shape, and FRAG aids you in this.

Take this example, which draws a star:

TO star
  repeat 4 [
    forward 100
    right 170
    forward 86
    frag
    left 70
    forward 86
    right 170
    forward 100
    frag
    right 180
  ]

We can change the number of sides the star has by changing the number of repeats and fiddling with the values a bit:

TO star2
  repeat 5 [
    fd 100 rt 170
    fd 86 frag
    lt 88 fd 86
    rt 170 fd 100
    frag rt 180
  ]
END

First, let’s change our star procedures so they can take a :size parameter, like so:

TO star1 :size
  repeat 4 [
    fd 100 * :size
    rt 170
    fd 86 * :size
    frag
    lt 70
    fd 86 * :size
    rt 170
    fd 100 * :size
    frag
    rt 180
  ]
END

In this case, :size is a ratio, that is, 0.5 will make a star half the size, and 2 will make a star twice the size of the default.

You can change the color of the star using the SETFILLCOLOR primitive, or set a random fill color with RANDFC.

The following procedures create a sky full of stars:

TO star1 :size
  repeat 4 [
    fd 100 * :size
    rt 170
    fd 86 * :size
    frag
    lt 70
    fd 86 * :size
    rt 170
    fd 100 * :size
    frag
    rt 180
  ]
END

TO star2 :size
  repeat 5 [fd 100 * :size rt 170 fd 86 * :size frag lt 88 fd 86 * :size rt 170 fd 100 * :size frag rt 180]
END

TO star3 :size
  repeat 6 [fd 100 * :size rt 170 fd 86 * :size frag lt 100 fd 86 * :size rt 170 fd 100 * :size frag rt 180]
END

TO star4 :size
  repeat 7 [fd 100 * :size rt 170 fd 86 * :size frag lt 108.625 fd 86 * :size rt 170 fd 100 * :size frag rt 180]
END

TO star5 :size
  repeat 8 [fd 100 * :size rt 170 fd 86 * :size frag lt 115 fd 86 * :size rt 170 fd 100 * :size frag rt 180]
END

TO stars
  reset cam:setposition [0 0 0]
  cam:fixate [0 0 0]
  cam:setviewpoint [0 0 0]
  cam:newworker [forever [up 0.1 lt 0.1 rr 0.1 wait 1]]
  repeat 200 [
    pu home randori fd 400 + random 1000 up 90
    lt random 60 pd randpc randfc randfs randps
    make "size (10 + random 90) / 100
    run {pick [star1 star2 star3 star4 star5] :size}
  ]
  
END

Type STARS and press Enter to see the stars!

FRAG’s sister, SHARD creates a three-dimensional FRAG with depth beneath it. This depth is supplied as a parameter, in turtle-units, eg. SHARD 5. Try replacing FRAG with SHARD 5 in one of your star procedures and see what happens! (You’ll need to drag the camera around to see the sides of the star)

Examples: Turtle Art

Logo is great for creating art! And 3D Logo makes it even better.

Many of these Logo artworks were inspired by examples created by Seymour Papert’s daughter Artemis Papert using the two-dimensional block-based TurtleArt application developed by LCSI Logo developer Brian Silverman. We’re grateful for both of their efforts in advancing Logo over the past several decades!

TO adobo
  reset setpenwidth 5 definecolor 16 [0 0 0]
  setpc 16 setbg 1 setbs 12 pu
  repeat 9 [
    repeat 10 [
      setpos {-120 + 20 * repcount -120 + 20 * repabove 1}
      setz -2 + 0.01 * random 400
      setfc pick [8 9 13]
      setfs -13 + random 10
      setheading -5 + random 11
      square 40 box 40
    ]
  ]
END

TO brush
  reset setbg 8
  setpenwidth 5 setbs 11
  
  repeat 300 [
    setpc pick [1 8 9 11]
    setps -10 + random 20
    pu
    setpos {-200 + random 400 -100 + random 200}
    rt random 360 pd
    repeat 20 + random 50 [
      make "stroke 30 + random 150
      fd :stroke rt -0.5 + 0.1 * random 10
      bk :stroke + random 2 lt -0.5 + 0.1 * random 10
    ]
    ra 0.01
  ]
END




TO bundles
  reset randbg
  repeat 40 [
    pu setpos {-200 + random 400 -100 + random 200}
    setpenwidth 4  pd
    lt random 360
    make "head heading
    repeat 2 [
      randpc
      repeat 90 [
        make "stroke 50 + random 5
        setps -10 + random 20
        fd :stroke
        bk 2 * :stroke
        fd :stroke
        rt 0.1 * random 20
        up -2 + (0.1 * random 40)]
      setheading :head
    ]
  ]
END



TO burst
  reset  pu
  make "colors {yellow orange red magenta blue}
  repeat 5 [
    setpc item repcount :colors
    setmarkerwidth repcount
    make "count repcount
    repeat 50 [
      rt random 360 mark :count * (20 + random 10)
      setpos [0 0]] lo repcount
  ]
END

TO caduceus
  reset  setpenwidth 5 pu
  repeat 4 [
    setpc item repcount [13 9 1 8]
    ra repcount * 2
    bk 120 pd
    repeat 100 [
      fd 1.4 + 0.1 * repabove 1
      rt 7.5 * sin 270 + 10 * repcount
    ]
    repeat 75 [
      fd 2.5 + 0.5 * repabove 1
      lt 0.5 * repcount
    ]
    pu home rr 180 * repcount
  ]
END

TO cards
  reset  pu
  repeat 1000 [
    setpos {-200 + random 400 -100 + random 200}
    rt random 360
    make "sizex 10 + random 20
    make "sizey 10 + random 20
    setfc 2 setfs 13
    quad :sizex + 2 :sizey + 2
    sr 1 fd 1 ra 0.01
    setfc pick [2 3 7 14]
    setfs -5 + random 10
    quad :sizex :sizey
    ra 0.01
  ]
END


TO citylights
  reset pu  setbg 2 setbs 10
  repeat 200 [
    setpos {-200 + random 400 -100 + random 200}
    rt random 360 make "size 20 + random 50
    setfc pick [1 9 13 7] lo 0.01
    until :size = 0 [
      randfs spot 0.05 * :size
      fd 5 lo 0.01 dec "size
    ]
  ]
END


TO dotcube
  cs seticosphereiterations 1 pu
  repeat 9 [
    repeat 9 [
      repeat 9 [
        setposition {-100 + 20 * repabove 2 -100 + 20 * repabove 1 -100 + 20 * repcount}
        setfc repabove 1 setfs repcount ico 2
      ]
    ]
  ]
END

TO dotspiral
  Reset setbg 13 setfc 9 cs
  repeat 1400 [
    pu fd repcount / 10
    spot repcount / 250
    rt 35
  ]
END


TO fireworks
  cs setpenwidth 5
  repeat 60 [
    pu home
    rt random 360
    randpc pd
    fd 30 + random 50
    repeat 50 [
      run pick [[pu][pd]]
      fd 2]
  ]
END

TO fish
  reset wrap
  setbounds [-180 -120 180 120]
  setbg 1 setbs 12
  pu setpos [-170 75]
  repeat 12 [
    setpenwidth 4 rt 44.5
    repeat 10 [
      sl 1
      repeat 3 [
        setpc item repcount [13 1 13]
        if repcount = 2 [ra 0.2]
        if repcount = 3 [lo 0.2]
        pd fd 50 pu bk 50 pu sr 1
      ]
      sl 2 rt 10
    ]
    setfc 1 ico 1 st
    lt 54.5 sr 13 fd 60
    lt 90
  ]
END

TO gaia
  reset setbg 2 setpenwidth 5  setpc 1
  repeat 5 [
    setpc item repcount [8 1 9 13 15]
    setorigin {0 0 2 * repcount}
    repeat 20 [
      pu home pd rt repcount * 18
      repeat 80 [
        fd 0.9 + ((repabove 2) * 0.1)
        rt 8 * sin (repcount * 8)
      ]
      lt 7.5
      repeat 5 [
        fd 20 pu bk 20 rt 15 pd
      ]
    ]
  ]
END


TO gradient
  cs pu
  repeat 30 [
    setfs -15 + repcount quad repcount 200 lo 0.01 sl 0.5
  ]
END

TO gridart
  reset
  randbg
  randfc
  pu
  
  setpos [-210 113]
  repeat 31 [
    for [i 1 57] [
      spot 3.5 * sin ((:i + repcount) * 2)
      sr 7.5
    ]
    sl 57 * 7.5
    bk 7.5
  ]
END

TO gridartico
  cs
  seticosphereiterations 1
  pu
  
  setpos [-210 113]
  repeat 31 [
    for [i 1 57] [
      ico 3.5 * sin ((:i + repcount) * 2)
      sr 7.5
    ]
    sl 57 * 7.5
    bk 7.5
  ]
END

TO gridartshade
  reset randbg randfc pu
  setpos [-210 113]
  repeat 31 [
    for [i 1 57] [
      setfs int (10 * (sin ((:i + repcount) * 2)))
      spot 3.5
      sr 7.5
    ]
    sl 57 * 7.5 bk 7.5
  ]
END

TO gridartwave :size
  cs
  seticosphereiterations 1
  pu
  
  setpos [-210 113]
  repeat 31 [
    for [i 1 57] [
      make "sin 3.5 * sin ((:i + repcount) * 2)
      ra :size * :sin
      ico :sin
      lo :size * :sin
      sr 7.5]
    sl 57 * 7.5
    bk 7.5
  ]
END

TO guessing
  Reset setspeed 5 setbg 9 setbs 3 setpenwidth 5
  repeat 8 [
    pu home ra repcount rt repcount * 45 pd
    repeat 22 [
      if repcount < 4 [
        setpc 8 setps 9 - (3 * repcount)] [
        setpc 13 setps (penshade - 1) + random 3
      ]
      repeat 360 [fd 1 - (0.015 * repabove 1) rt 1]
      pu sr 0.02 pd
    ]
  ]
END



TO heat
  cs pu
  repeat 10 [
    setfc pick [1 9 13]
    setpos {-170 + (repcount * 30) -120}
    up 90
    repeat 80 [
      cylinder 0.1 * repcount 1.6 10
      sr sin (repcount * 10)
      lo 1.5
    ]
    repeat 80 [
      cylinder 0.1 * (80 - repcount) 1.6 10
      sr sin ((80 + repcount) * 10)
      lo 1.5
    ]
    dn 90
  ]
END

TO heat2
  cs pu
  repeat 10 [
    setfc pick [1 9 13]
    setpos {-170 + (repcount * 30) -120}
    up 90
    repeat 80 [
      cylinder 0.1 * repcount 1.6 10
      sr sin (repcount * 10)
      lo 1.5
    ]
    repeat 80 [
      cylinder 0.1 * (80 - repcount) 1.6 10
      sr sin ((80 + repcount) * 10)
      lo 1.5
    ]
    dn 90 rr 180
  ]
END

TO hedgehog
  reset  setfc 1 pu ra 1 spot 20 setpc 13
  repeat 36 [
    home dropanchor tether pullout 18
    orbitleft repcount * 10 rt 225
    setmarkerwidth 0.1 * random 20
    mark 30 + random 80
  ]
END

TO funnybird :col1 :col2
  rl 90 setfc :col1 icospheroid 20 0.5
  pu rr 90 fd 5 sr 12 lt 30
  cylindroidarc 10 15 20 30 10 0.3
  fd 10 sr 15 ra 2
  setfc :col2 ico 3 lo 3.5 ico 3 ra 1.75
  bk 10 dn 90 lt 90
  domoid 10 8 20 0.3 fd 30 sl 7 rt 90
  icospheroid 8 2 fd 14
  icospheroid 8 2 bk 7 rr 30 rr 10 up 10
  cylinder 2 35 20 lo 40 rr 180 lt 90 dn 10
  domoid 7 10 10 0.5 oval 3.5 7 up 10 rt 90
  rl 180 ra 35 dn 20 rl 20
  cylinder 2 35 20 lo 40 rr 180 lt 90 up 10
  domoid 7 10 10 0.5 oval 3.5 7
END

TO hiding
  reset setpenwidth 5 pu
  sl 30 funnybird 1 9 home
  ra 20 rr 180 sl 30 up 10
  funnybird 13 8 rl 180 fd 20
  sr 20 spot 100 sl 40 up 90
  rl 90 sl 60 pd setpc 13
  pushturtle
  repeat 50 [
    popturtle
    pushturtle
    pu sr repcount * 2
    pd lt -10 + random 30
    setpc pick [8 9 13]
    setfs -10 + random 20
    raise -2 + random 6
    repeat 70 + random 30 [fd 1 rt 0.7]
  ]
  ht
END



TO icicles
  reset pu up 90
  repeat 20 [
    setpos {-210 + (20 * repcount) 115}
    make "size 20 + random 15 randfc
    repeat :size [
      cylinder 0.2 * (:size - repcount) 0.6 + (:size / 5) 20
      ra 0.5 + (:size / 5)
    ]
  ]
END

TO moon
  reset lt 120
  repeat 180 [fd 1 rt 1]
  rt 150
  repeat 180 [fd 0.774 lt 0.676]
  pu fd 30 pd
  repeat 3 [
    repeat 5 [
      fd 20 bk 40 fd 20 rt 36
    ]
    pu rt 180 sl 40 fd 40 pd
  ]
  ht
END

TO needles
  reset
  repeat 5 [
    repeat 10 [
      pu setpos {-240 + 80 * repabove 1 126 - repcount * 23}
      pushturtle rr 90 up -15 + random 30 randfc
      cylinder 1 30 10 rr 180 cylinder 1 30 10 popturtle
    ]
  ]
END


TO nest
  reset setspeed 1
  repeat 3 [
    setpc item repcount [9 8 4]
    repeat 18 [
      pu home raise 2 * repabove 1
      rt 7 * repabove 1 rt repcount * 20
      setps -5 up 10 pd
      mark 50 + 2 * repabove 1
      repeat 4 [
        setps penshade + 2
        repeat 90 [
          pu bk 0.1 pd mark 0.2 + 0.1 * repabove 1
          rt 2 up 1
        ]
        setpenshade penshade + 1
        repeat 90 [
          pu bk 0.1 pd
          mark 0.2 + 0.1 * repabove 1
          lt 2 up 1
        ]
      ]
    ]
  ]
  setfc 7 pu home ra 17 icospheroid 10 2 ht
END



TO notnot
  reset pu sl 10 lt 40 setpc 15 setbg 1
  setmarkerwidth 10 repeat 360 [
    mark 1.1 bk 0.1 lt 1
  ]
  lt 90 mark 115 home sr 90 fd 25 rt 40
  repeat 360 [
    mark 0.8 bk 0.1 lt 1
  ]
  lt 90 mark 80
END


TO orangepeel
  reset setpenwidth 8 setbs 3
  setbg 13 setpc 9 setps 0
  repeat 5 [
    pu home
    setpos {-240 + repcount * 50 113}
    rt 100
    repeat 10 [
      sr 1.5 fd 1 pd setps -5 + repcount
      repeat 100 [
        if divisorp 10 repcount [
          setps penshade + 1
        ]
        fd 2.75 rt repcount
      ] lt 10
    ]
  ]
END

TO patio
  cs pu setpos [-87.5 85] setfc 13
  repeat 5 [
    repeat 6 [
      setfillshade -10 + random 21
      make "offset random 10
      lt 50 - :offset
      polyspot 20 4
      rt 50 - :offset
      sr 35
    ]
    sl 210 bk 35
  ]
END

TO peaks
  reset  ht pu bk 125 setbg 2
  repeat 3 [
    setfs 0 setfc 13
    fiso 100 250
    setfc 7 setfs repcount * 3
    ra 0.1
    fiso 75 200
    sl 120 lo 50 bk 30
  ]
  home bk 125 sr 120 lo 50 bk 30
  repeat 2 [
    setfc 13 setfs 0 fiso 100 250
    setfs 3 + repcount * 3
    setfc 7 ra 0.1 fiso 75 200
    sr 120 lo 50 bk 30
  ]
  setpenwidth 5 home setpos [140 80]
  setpc 13
  repeat 36 [
    pd fd 35 pu bk 35 rt 10
  ]
END


TO pinwheel
  reset twosided
  pu setbg 2
  setfc 14 setpc 7
  repeat 2 [
    setpc item repcount [7 11]
    setfc item repcount [14 13]
    pu home rt repcount * 45
    bk 10
    repeat 100 [
      fd 40 + repcount * 1.2
      lt 90 fd 10 lt 92 fd 10
      frag lt 90
    ]
  ]
END

TO postits
  reset pu
  repeat 10 [
    repeat 10 [
      setpos {-120 + 20 * repcount -120 + 20 * repabove 1}
      randfc
      setheading -5 + random 11
      square 20 ra 0.1
    ]
  ]
END


TO rainbow
  reset setpenwidth 10  pu sl 225 bk 125 lt 10 pd
  repeat 500 [
    foreach "col {red orange yellow green blue lightblue magenta} [
      setpc :col fd 0.5 * (0.1 * (10 + repcount))
    ]
    pu bk (0.5 * (7 * (0.1 * (10 + repcount))))
    sr 1 fd 0.2 * (sin (0.5 * (repcount + 100)))
    pd
  ]
END

TO redonpink
  reset setpc 1 setbg 11 setbs -5
  pu setfc 1
  repeat 1000 [
    setpos {-220 + random 440 -120 + random 240}
    ra 0.001 setfo 50 setfs -15 + random 10
    spot 5 + random 5
  ]
  setorigin [-50 -30 2]
  repeat 16 [
    setmarkerwidth 3 home dropanchor
    pullout 10 orbitleft repcount * 22.5
    rt 180
    repeat 70 [
      setmarkerwidth markerwidth - 0.02
      bk 0.1 mark 1 rt 2
    ]
    repeat 70 [
      setmarkerwidth markerwidth - 0.02
      bk 0.1 mark 2 lt 2
    ]
  ]
END


TO roses
  reset setpenwidth 5
  repeat 3 [
    pu setpos {-190 + (repcount * repcount) * 30 -90 + repcount * 50}
    pd make "size 0.05 * (repcount / 2)
    setpc item repcount [1 9 13]
    repeat 9 [
      repeat 100 [
        fd repcount *  :size rt 10
      ]
    ]
  ]
END


TO slats
  reset
  setorigin [-260 -120]
  repeat 23 [
    pu setps -7 + repcount
    home sr 20 * repcount
    setmarkerwidth 18 rt 10
    mark 250
  ]
END


TO slats2
  reset
  setorigin [-260 -120]
  repeat 23 [
    pu setps -7 + repcount
    home setpc pick [8 9 13]
    sr 20 * repcount
    setmarkerwidth 18 rt 10
    mark 250
  ]
END

TO snake
  CS PU RANDFC
  BK 110 UP 90
  repeat 80 [
    cylinder 0.1 * repcount 1.6 10
    sr sin (repcount * 10)
    lo 1.5
  ]
  repeat 60 [
    cylinder 0.1 * (80 - repcount) 1.6 10
    sr sin ((80 + repcount) * 10)
    lo 1.5
  ]
  DN 90 RT 60 ICOSPHEROID 5 2 SL 7 FD 3
  RANDFC ICO 1 BK 6 ICO 1 HT
END

TO snakes
  CS PU RANDFC
  repeat 10 [
    home setpos {-170 + (repcount * 30) -110}
    up 90 repeat 80 [
      cylinder 0.1 * repcount 1.6 10 sr sin (repcount * 10) lo 1.5
    ]
    repeat 60 [
      cylinder 0.1 * (80 - repcount) 1.6 10
      sr sin ((80 + repcount) * 10) lo 1.5
    ]
    DN 90 RT 60 ICOSPHEROID 5 2 SL 7 FD 3
    RANDFC ICO 1 BK 6 ICO 1
  ]
  HT
END

TO solar
  reset  repeat 5 [
    setpc item repcount [1 8 9 13 15]
    repeat 18 [
      pu home raise 2 * repabove 1
      rt repabove 1 rt repcount * 20
      setps 0 pd mark 50
      repeat 5 [
        setps penshade + 1
        repeat 90 [
          mark 0.2 + 0.1 * repabove 1 rt 2
        ]
        setpenshade penshade + 1
        repeat 90 [
          mark 0.2 + 0.1 * repabove 1 lt 2
        ]
      ]
    ]
  ]
END

TO solar2
  reset setspeed 5
  repeat 5 [
    setpc item repcount [1 8 9 13 15]
    repeat 18 [
      pu home raise 2 * repabove 1
      rt 3 * repabove 1
      rt repcount * 20
      setps 0 pd
      mark 50
      repeat 5 [
        setps penshade + 1
        repeat 90 [
          mark 0.2 + 0.1 * repabove 1 rt 2
        ]
        setpenshade penshade + 1
        repeat 90 [
          mark 0.2 + 0.1 * repabove 1 lt 2
        ]
      ]
    ]
  ]
END


TO solar3
  reset           setspeed 5
  repeat 5 [
    setpc item repcount [1 8 9 13 15]
    repeat 18 [
      pu home raise 2 * repabove 1
      rt 4 * repabove 1
      rt repcount * 20 setps 0
      pd mark 50
      repeat 5 [
        setps penshade + 1
        repeat 90 [
          mark 0.2 + 0.1 * repabove 1
          rt 2
        ]
        setpenshade penshade + 1
        repeat 90 [
          mark 0.2 + 0.1 * repabove 1 lt 2
        ]
      ]
    ]
  ]
END

TO sparks
  reset setpenwidth random 10
  randbs randbg
  repeat 5 [
    pu setposition {-200 + random 400 -100 + random 200 -100 + random 100}
    setorigin position randpc randps
    repeat 30 [
      rt random 360 pd
      while (and xpos < 300 xpos > -300 ypos < 180 ypos > -180) [fd 1 lt 0.2]
      pu home
    ]
  ]
END

TO spiralart
  reset
  snappy:pullin 100
  pu
  randbg
  sl 40
  rr 90
  bk 10
  repeat 2 [
    randfc
    repeat 2800 [
      tube 2 repcount / 400 6
      lo repcount / 500
      up 2
    ]
    pu home
    fd 10 sr 40 rl 90
  ]
  ht
END


TO spirallights
  reset  setpenwidth 5
  repeat 5 [
    make "ypos 130 - (40 * repcount)
    randpc
    repeat 10 [
      pu setpos {-220 + (40 * repcount) :ypos}
      pd
      repeat 100 [
        setps -10 + int (repcount / 5)
        fd repcount / 10 rt 30
      ]
    ]
  ]
END

TO spirallightsorange
  reset  setbg 8
  setbs 13 setpenwidth 5
  repeat 5 [
    make "ypos 130 - (40 * repcount)
    repeat 10 [
      pu setpc pick [1 8 9 13]
      setpos {-220 + (40 * repcount) :ypos}
      pd
      repeat 100 [
        setps -10 + int (repcount / 5)
        fd repcount / 10
        rt 30
      ]
    ]
  ]
END


TO spirallightsorange3d
  reset  setbg 8 setbs 13
  setpenwidth 5
  repeat 5 [
    make "ypos 130 - (40 * repcount)
    repeat 10 [
      pu setpc pick [1 8 9 13]
      setposition {-220 + (40 * repcount) :ypos 0}
      pd
      repeat 100 [
        setps -10 + int (repcount / 5)
        fd repcount / 10 rt 30 dn 2
      ]
    ]
  ]
END

TO splash
  reset setspeed 5 setpenwidth 5
  repeat 144 [
    pu home rt repcount * 2.5 dn 75 pd
    repeat 400 [
      up 5 * (sin (repcount * 4))
      setps -15 + (repcount / 12)
      fd .4
    ]
  ]
  pu home
END

TO splash2
  reset setspeed 5 setpenwidth 5
  repeat 144 [
    pu home rt repcount * 2.5 dn 75 pd
    repeat 400 [
      up 5 * (sin (repcount * 4))
      rt sin repcount
      setps -15 + (repcount / 12)
      fd .4
    ]
  ]
  pu home
END

TO splash3
  reset setspeed 5 setpenwidth 5
  repeat 144 [
    pu home rt repcount * 2.5 dn 75 pd
    repeat 400 [
      up 5 * (sin (repcount * 4))
      rt sin repcount
      rr sin repcount
      setps -15 + (repcount / 12)
      fd .4]
  ]
  pu home
END

TO splash4
  reset setspeed 5 setpenwidth 5 setpc 1
  repeat 144 [
    pu home rt repcount * 2.5 dn 75 pd
    repeat 400 [
      up 5 * (sin (repcount * 4))
      rt sin repcount
      rr sin repcount * 2
      setps -15 + (repcount / 12)
      fd .4]
  ]
  pu home
END

TO spotwave
  cs  pu
  repeat 32 [
    setpos {-220 205 - (repcount * 10)}
    repeat 45 [
      setfc pick [2 3 5 6 7 10 14 15]
      spot 5 sr 10
      fd -2 + sin (repcount * 10)
    ]
  ]
END


TO stickman :size
  lt 45 setmarkerwidth :size / 3
  repeat 2 [
    lt 90 mark :size * 5 spot :size
    bk :size * 5] lt 135 mark :size * 2
  lt 45 repeat 2 [
    mark :size * 5 spot :size bk :size * 5 rt 90
  ]
  lt 135 mark :size * 5
  spot :size * 2 pu bk :size * 10
END

TO stickmen
  reset pu sl 80 fd 20
  repeat 3 [
    randfc setpc fillcolor
    stickman repcount * 3
    pu sr 80 ra 20
  ]
END

TO stormy
  reset  pu setpos [-230 -120]
  repeat 8 [
    setpc item repcount [2 6 7 14 1 8 9 13]
    repeat 160 [
      pushturtle rt 45 bk random 20
      randps mark 50 + random 20
      popturtle pu
      sr 2.5 + random 5 ra 0.01
    ]
    ra 0.1 pu
    setpos {-230 -120 + repcount * 30}
  ]
END

TO swirl
  reset pu bk 20 sr 40 setpc 1
  setbg 13 setbs -10 setorigin position pd
  repeat 12 [
    repeat 30 [
      setropewidth 6.1 - (repcount / 5)
      rope 4 bk 0.2 rt 6 bk 0.2
    ]
    pu home rt repcount * 30 pd
  ]
  ht
END


TO thicket3
  reset  setbg 2 setpenwidth 5  setpc 1
  repeat 8 [
    setpc item repcount [8 1 9 4 12 13 14 15]
    repeat 20 [
      pu setposition {-200 + (repcount * 20) 0 5 + repabove 1}
      up 25 pd
      repeat 80 [
        fd 0.9 + ((repabove 2) * 0.1)
        rt 8 * sin (repcount * 8)
      ]
      lt 7.5
      repeat 5 [
        fd 20 pu bk 20 rt 15 pd
      ]
    ]
  ]
END

TO twomoons
  reset
  setorigin [-23 -23 0]
  repeat 2 [
    setpc item repcount [7 2]
    repeat 36 [
      pu home dropanchor
      pullout 10 * repabove 1
      orbitleft repcount * 10
      rt 180 pd
      if oddp repcount [fd 40 * repabove 1] [fd 20 * repabove 1]
    ]
    setorigin [30 30 -20]
  ]
END


TO vase
  reset setpenwidth 5  pu fd 50 sl 50 pd rt 135
  repeat 40 [fd 1 rt 2]
  repeat 125 [fd 1 lt 1]
  lt 5 quad 80 220 rt 180 rr 180
  quad 80 220 rr 180 rt 185
  repeat 125 [fd 1 lt 1]
  repeat 40 [fd 1 rt 2]
  pu home bk 70 lt 15 setpc 15
  repeat 6 [
    pushturtle pd fd 150 + random 20
    setfc pick [1 8 9 11] ra 0.1
    spot 5 popturtle rt 6
  ]
END


TO weave
  reset  wrap
  repeat 30000 [
    fd 1 rt
    sin repcount
    if divisorp 1000 repcount [randpc]
  ]
END

TO zig
  reset  setbg pick [1 8 9 13]
  setbs 10 setpenwidth 10
  repeat 200 [
    ra 0.1 pu
    setpos {-220 + random 440 -120 + random 240}
    rt random 360 setpc pick [1 8 9 13]
    setps -15 + random 10
    repeat 50 [
      pd fd 50 + random 3 lt random 3 bk 50 + random 3
      rt random 3 setps penshade + (-1 + random 3)
    ]
  ]
  pu setpos [-100 -50]
  setheading 300 pd setpc 1
  setps 5 ra 1
  repeat 15 [
    bk 0.2 fd 20 rt 140
    bk 0.2 fd 20 lt 132.5
  ]
END


TO zigzag
  reset setbg 8 setbs 0 setpenwidth 5
  
  repeat 360 [
    pu home pd rt repcount * 1 lt 45
    setpc pick [1 5 7 9]
    repeat 20 [
      fd repcount rt 90
      fd repcount lt 90
    ]
  ]
END

TO zigzag3d
  reset setbg 8 setbs 0 setpenwidth 5
  repeat 360 [
    pu home pd rt repcount * 1
    lt 45 up 45 setpc pick [1 5 7 9]
    repeat 20 [
      fd repcount rt 90 fd repcount lt 90
    ]
  ]
END