News

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!

Example: My Gosh, It’s Full of Stars!

Open in turtleSpaces IDE
Run starscape to create a galaxy of randomly-shaped and colored stars.

TO star :radius :points :size :filled
  ;takes number number number boolean (true or false)
  ;eg star 10 9 40 false
  ;or star 20 5 50 true
  
  pu dropanchor tether
  ;pull up the turtle pen, drop the 'anchor' to set the 'anchor point' to the current position, and do not change it if the turtle's rotation changes (tether)
  ;the anchor point is the point the orbit primitives orbit around
  
  if :filled [polyspot :radius :points * 2
    if oddp :points [rt 360 / :points / 4]]
  ;if creating a filled star, create a polygon to fill in the center
  ;if the star has an odd number of points, we need to turn a little
  
  pullout :radius
  ;pull out from the anchor point, which is currently the turtle's position
  
  repeat :points [
    ;repeat once for each point:
    
    pu make "position position
    ;set the :position container to the current turtle position
    
    orbitleft 360 / :points / 2
    ;orbit around the anchor point (in this case the center) to the left
    ;a fraction of 360 degrees divided by the number of points divided by 2
    
    pullout :size
    ;pull the turtle out from the center of the star (anchor point)
    
    setvectors direction :position
    ;point the turtle toward the previous position
    
    if not :filled [pd line distance position :position]
    ;if not making a filled star, create a line in front of the turtle of
    ;the length required for its end to be the previous turtle position.
    
    if :filled [frag]
    ;if creating a filled star, create a 'fragment' based on the last three
    ;turtle positions
    
    pu make "position position
    ;set the :position container to the current position
    
    pullin :size
    ;pull the turtle in toward the center of the star (anchor point)
    
    orbitleft 360 / :points / 2
    ;orbit to the left again a similar amound to the last orbitleft
    
    setvectors direction :position
    ;point toward the previous position
    
    if not :filled [pd line distance position :position]
    ;create a line if not a filled star similarly to the previous line
    
    if :filled [frag]
    ;create a fragment if a filled star similarly to the previous frag
    
  ]
END

TO starscape
  reset ht snappy:setposition [0 0 0] snappy:dropanchor repeat 200 [pu home randvec fd 1000 + random 1000 up 90 snappy:setvectors direction myrtle:position randfc randpc randps randfs star 10 + random 100 3 + random 20 10 + random 90 randbool]
END

Example: It’s Turtles All The Way Down!

In turtleSpaces, you can ‘stamp’ the current model, leaving a copy of it in the current position. This can be useful in some circumstances, to create artworks made out of more sophisticated models. In the case of this example, we’re going to use the default ‘myrtle’ turtle model to create a descending spiral of turtles.

If you change the colors in the default palette using the definecolor primitive, then those colors are also used to render the turtle model, and by extension the stamp. And so, if we ‘cycle’ the colors, shifting their RGB values from one palette slot to the next, we can create a rotating series of differently-colored turtles.

Note: For reasons, colors 0 (black) and 15 (white) cannot be redefined. But there are 1-14 and 16-63 to play with, which is plenty!

For aesthetic reasons, we want a certain turtle to have the default colors, so we need to add an offset to some of the calculations to make that happen. Finally, we need to position Snappy (the camera or view turtle) in a certain position to get the view we want. Because this involved a fair amount of manual fiddling, I’ve just inserted the position and vectors into the listing to reproduce Snappy’s position and orientation.

Finally, to make the spiral we’re going to use the orbit commands, which rotate the turtle around an ‘anchor point’. The tether primitive allows us to turn the turtle away from the anchor point, which would normally move the anchor point but does not if tether is called. We descend a little each time we move, creating a downward spiral.

TO turtlesallthewaydown

  reset
  
  snappy:setposition [-0.0567188571145 -41.2097873969 -9.14256453631]
  snappy:setvectors [
    [0.0177688320245 0.192937058466 -0.981050233209]
    [-0.00350577343795 0.981211134942 0.192905205264]
    [0.999835975629 1.16396598173E-05 0.0181113694522]
  ]
  ;position Snappy where we want him to reproduce the image
  
  make "defaultcols colors
  ;make a copy of the default color palette
  
  penup dropanchor
  pullout 50 tether
  ;we want 'orbit' in a circle
  
  left 90 orbitright 39
  ;because we tethered, we can point away
  ;then orbit around the anchor point
  
  repeat 800 [
    setfillshade -5 + repcount / 20
    ;set the shade of the fill color, the color used
    ;to create the voxels that make up the turtle, amongst others
    
    make "offset remainder repcount + 11 14
    ;why +11? So we get the default turtle colors in the right place!
    
    repeat 14 [
      definecolor repcount item 2 + remainder (:offset + repcount) 14 :defaultcols
      ;shuffle the color palette. We need to start at item 2 because 1 is black
      ;(item is 1-based, whereas definecolor is 0-based -- 0 being black)
      
    ]
    
    stamp "myrtle
    ;make a copy of myrtle in the current position
    
    orbitleft 22.95 lower 1
  ]

END

If you replace stamp “myrtle with stamp “astronaut, and before it add a setmodelscale 0.5, like this:

setmodelscale 0.5 stamp "astronaut

you get:

If you change the “astronaut in stamp “astronaut to stamp pick [astronaut spaceship plane] like so:

setmodelscale 0.5 stamp pick [astronaut spaceship plane]

you’ll get:

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

New WebAssembly Build of turtleSpaces Logo Now Available

To make turtleSpaces more accessible to our users, we’ve created a WebAssembly build of turtleSpaces and paired it with a new Javascript front-end UI that renders turtleSpaces output natively in the browser, and has a code editor with syntax highlighting.

It comes with a number of built-in examples, and a fairly complete set of features: loading from the local machine, saving to the local machine, exporting STL, exporting PNG (high-resolution), and sharing using the turtleSpaces model viewer (which unlike STL is in full color).

Obviously execution in the web interface is slower than if you download the native turtleSpaces binary for your operating system, but our webLogo still provides most of the functionality of turtleSpaces while making it available for other platforms such as Chromebooks, Raspberry Pi 4 and so forth (anything that can run a Chromium-based browser).

And, because it is 3D, and has dozens of shape primitives, our webLogo still offers far more creative opportunities than other Logos.

Check out the webLogo here!

turtleSpaces Model Web Viewer

On our journey to porting turtleSpaces to the Web (yes, that’s coming!), we’ve added a primitive, SHAREVECTORS “description (or |description|) that allows users to share their creations to the web. SHAREVECTORS will return a link to the turtleSpaces website where you can view a static model, as it was in turtleSpaces when you executed the SHAREVECTORS command.

Note that the camera in the web viewer is currently fixed to the Y axis and is oriented upward, and so you need to ensure your models are oriented that way (they should look correct if you issue a CAM:CS to return the camera turtle to its home position).

You can also embed the viewer (and your creation) into your own web page if you use the following bit of code:

<iframe src="https://turtlespaces.org:9876/embed?pict=YourSceneHere" frameBorder="0" width="720" height="512" scrolling="no">

replacing YourSceneHere with the ID of your scene (the bit in the share URL after pict= and before the ” that follows it) which looks something like 8970c41a0c9a35553e6a2613f8b0516c67381e9a556beb647de84c09

Note: Due to limitations with WebGL, pen width is not currently supported.

You can click and drag to rotate the model, or use the scroll wheel to zoom in and out.

Here’s a few embedded examples:

Logo Fireworks

This Logo program uses hatchlings to create simple 2D fireworks. The turtle’s model is changed into an icosphere to simulate a launching firework, and then more hatchlings are used to create the starburst. The trails are merged back into the main turtle ‘track’ and the hatchlings are terminated, leaving the rendered drawing on-screen at the conclusion of the program.

Read through the code (and pay particular attention to the ;comments) to see how the program works. It is made up of two procedures: fireworks, and burst.

TO fireworks
  ;simple 2D fireworks
  
  reset
  hideturtle
  
  repeat 5 + random 10 [
    ;launch at least 5 but not more
    ;than 14 fireworks
    
    penup
    ;pull up the turtle's pen
    
    home
    ;return to [0 0 0]
    
    raise repcount
    ;raise the turtle so its lines
    ;don't overlap
    
    sety -100
    ;set the turtle's y position to
    ;-100
    
    hatch [left -60 + random 121 burst]
    ;hatch a new turtle, turn that
    ;turtle left some random value
    ;between -60 (same as right 60)
    ;and 60 degrees, then execute the
    ;burst procedure
    
    wait 30 + random 31
    ;wait between one half and one
    ;second before launching the next
  ]
  ;repeat until all fireworks launched
  
END

TO burst
  ;a single firework 'burst'
  ;originally called 'firwork' but
  ;that was a little confusing!
  
  penup hideturtle
  
  newmodel "firework [icosphere 1]
  setmodel "firework
  ;create and use a simple model
  ;made from a single icosphere
  
  randomfillcolor
  ;set a random fill color
  ;models inherit the fill color
  ;if not otherwise set inside
  ;the model
  
  showturtle
  
  repeat 100 + random 601 [
    ;travel between 200 and 700
    ;turtle steps
    
    forward 1 - 0.002 * repcount
    ;move forward 1 step minus
    ;a fraction based on the current
    ;loop iteration. This has the
    ;effect of slowing us down
    ;over time (reduce velocity)
    
    sety ypos - 0.0005 * repcount
    ;change the y position of the
    ;turtle a fraction based on the
    ;current loop iteration, simulating
    ;very simple gravity
    
    sleep 2
    ;take a little nap
    
  ]
  ;repeat until finished travelling
  
  setpencolor fillcolor
  ;set the pen color to the fill color
  
  hideturtle
  
  repeat 20 + random 21 [
    ;create between 20 and 40 fragments
    
    raise 0.01
    ;ensures seperation between
    ;overlapping lines
    
    hatch [
      pendown
      ;draw lines
      
      right random 360
      ;turn right between 0 and 359
      ;degrees
      
      make "steps 30 + random 71
      repeat :steps [
        ;travel between 30 and 100
        ;turtle steps
        
        ;setpenshade -15 + repcount / 5
        setpenshade -15 + 30 * (repcount / :steps)
        ;set the pen shade based on the
        ;loop iterations
        
        fd 1 - 0.002 * repcount
        ;move forward minus "drag"
        
        sety ypos - 0.01 * repcount
        ;apply fake gravity
        
      ]
      merge
      ;merge the hatchling's track
      ;(output) into the track of its
      ;permanent ancestor, in this case
      ;myrtle
    ]
    ;done with hatchling
  ]
  ;repeat until finished
  
END

turtleArt Thumbtack String Corkboard

This commented Logo source code creates a thumbtack, a cork board, and then draws random string art using them.

Read the ;comments to learn more about what the primitives do and what their shortcuts are.

Try some of the primitives out in turtleSpaces interactive mode (the myrtle prompt) and see what they do!

You can drag-select the source code and then paste it into the turtleSpaces editor (which you enter by typing ed and Enter or pressing control-shift-E) using control-shift-V (paste)

Then exit back to interactive mode using control-shift-O (save) and then type stringart and Enter to execute it.

Change elements of the code and see what happens!

TO tack
  ;create a thumbtack, or pushpin
  
  setfillcolor pick without 5 without 10 range [1 15]
  ;pick a number between 1 and 15 except 5 and 10
  
  cylinder 4 2 20
  ;cylinder takes width depth sides
  
  lower 2
  ;lowers the turtle eg moves beneath it
  
  cutcone 2 3 7 20
  ;cutcone takes topwidth bottomwidth depth sides
  
  lo 7
  ;lo is shortcut for lower
  
  cylinder 4 2 20
  lo 2
  setfc pick [5 10]
  ;setfc is shortcut for setfillcolor, the color
  ;used for painting shapes
  
  cylinder 1 5 8
  lo 5
  cone 1 1 8
  raise 16
  ;raises the turtle, eg moves above it
  ;all done!
  
END

TO corkboard
  ;create a corkboard to push our pins into
  
  penup
  setpos [-205 -116]
  
  setfillcolor 8 setfillshade -4
  ;setfillshade takes a range of -15 to 15
  
  forward 5 lo 3 slideright 5
  voxeloid 400 222 4
  ;voxeloid takes width height depth
  ;this creates the surface of our corkboard
  
  slideleft 5 ra 3 back 5
  setfs 6
  ; setfs is shortcut for setfillshade
  
  voxeloid 10 232 10
  ;this and subsequent voxeloids
  ;create the frame
  
  right 90
  sl 10
  ;sl is shortcut for slideleft
  
  voxeloid 10 410 10
  fd 400
  ;fd is shortcut for forward
  
  left 90
  bk 10
  ;bk is shortcut for back
  
  voxeloid 10 232 10
  fd 222 lt 90 bk 10
  ;lt is shortcut for left
  
  voxeloid 10 410 10
  ;that's all folks!
  
END

TO stringart
  reset
  ;resets the workspace
  
  snappy:run pick [
    [pullout 10]
    [pullout 30 orbitdown 70]
    [orbitleft 20 orbitdown 45 rollright 10 pullout 60 rr 10 sl 25 lo 40]
    ;rr is shortcut for rollright
    [orbitright 20 orbitdown 45 rollleft 10 pullout 60 rl 10 sr 25 lo 40]
    ;rl is shortcut for rollleft
  ]
  ;pick a camera sequence and execute it as
  ;snappy, the camera turtle
  
  ;if we need snappy to do more sophisticated
  ;things, we can store procedures inside him
  
  ;logo is all about having the freedom to do
  ;things in multiple ways!
  
  setpenwidth 1 + random 5
  ;sets the 'width' of the pen, from 1 to 5
  
  randps
  randfs
  ;randps and randfs (aka randompenshade and randomfillshade)
  ;set a random shade between -12 and 12
  
  penup
  corkboard
  ;execute corkboard procedure
  
  repeat 20 + random 20  [
    ;do the following 20 + 0-19 times:
    
    randpc
    ;shortcut for randompencolor
    
    setpos {-190 + random 380 -100 + random 200}
    ;move to a random position
    
    pu
    ;pu is shortcut for penup
    
    pushturtle
    ;save the turtle state on the 'stack'
    ;you can have multiple states on the stack
    
    raise 10 + random 4 up -10 + random 20 rr -10 + random 20
    ;move into a semi-random position
    ;to give our tacks a more natural-looking
    ;placement
    
    ;moving in negative values moves the opposite
    ;direction, eg left -90 turns right 90 degrees
    
    tack
    ;execute tack procedure
    ;(create a tack)
    
    popturtle
    ;load the turtle state from the 'stack'
    ;this puts it back where and how it was when
    ;we pushed it
    
    pendown
    ;pd is shortcut for pendown
    ;this will cause us to create a line to the
    ;next random position
    
  ]
  ;repeat the above however many times
  ;specified by 20 + random 20
  
  hideturtle
  ;ta da!
  
  ;for extra credit, get some tacks, a corkboard, and some
  ;colored string and make some string art of your own!
  
  ;consider the angles the turtle would need to turn to travel
  ;along the line of string created between all the pins
  ;were the turtle to travel the string like driving
  ;down a road
  
END

 

Solar System Simulation

This Solar System simulation features the ability to add orbiting moons to the planets, a few of which are already defined. It is not entirely to scale (the planets are larger than they are in reality).

Use the scrollwheel or finger-scroll to zoom in and out, and drag the mouse to rotate around the sun!

TO solarsystem
  
  reset
  penup
  hideturtle
  
  cam:pullin 100
  ;pull in the camera turtle
  
  ;---------------------------------
  ;make a starfield in the distance:
  ;---------------------------------
  
  setfillcolor 5
  repeat 200 [
    home randomvectors
    forward 2500 + random 100
    up 90
    spot 1 + random 5
  ]
  
  ;---------------------------------
  ;define planetary parameter lists:
  ;---------------------------------
  
  make "distance [0 39 72 100 152 520 953 1918 3006 3953]
  ;the distance of the planets from the sun in 100ths of an AU
  ;The first value is the sun itself, which is at the home position
  
  make "size [100 3 7.5 7.9 4.2 88.7 74.6 32.6 30.2 1.41]
  ;the planets are in scale relative to each other but not the sun,
  ;which is much larger than the value we have given it here
  
  make "color [13 8 9 7 1 14 11 7 2 10]
  ;each planet's color (and the sun)
  
  make "tilt [0 7 3.3 0 1.85 1.31 2.49 0.77 1.77 17.14]
  ;ecliptical tilt
  
  make "speed [0 4.1 1.62 1 0.53 0.084 0.034 0.011 0.006 0.004]
  ;speed of orbit
  
  ;-------------
  ;define moons:
  ;-------------
  
  make "moon [0 0 0 1 2 0 0 0 0 0]
  ;how many moons?
  
  make "mooncolor [[][][][5][8 9][][][][][]]
  make "moondistance [[][][][3][2 3][][][][][]]
  make "moonsize [[][][][2.1][1.12 0.62][][][][][]]
  make "moontilt [[][][][0][1 2][][][][][]]
  make "moonspeed [[][][][30][40 30][][][][][]]
  ;moon parameters, similar to planets
  ;only earth and mars are populated here,
  ;add the others as you like!
  
  ;---------------------------
  ;create the sun and planets:
  ;---------------------------
  
  repeat 10 [
    home
    
    make "planet repcount
    ;store the current planet for use inside hatch
    
    newmodel repcount {"setfc item :planet :color "ico 0.1 * item :planet :size}
    ;create a new turtle model using the data from the :color and :size lists
    ;we use a 'soft list' {} to create 'hard data' for use by newmodel
    ;as the turtle model is rendered each frame
    
    hatch [
      ;create a new hatchling
      
      setmodel :planet
      ;set the turtle model
      
      penup
      dropanchor
      ;set the orbit (anchor) point to the current position
      
      pullout 0.5 * item :planet :distance
      ;pull away from the anchor the distance specified in the :distance list
      
      orbitright random 360
      ;orbit around a random amount
      
      orbitup item :planet :tilt
      ;orbit up (tilt) the amount specified in the :tilt list
      
      showturtle
      ;hatchlings are not visible by default
      
      if 0 < item :planet :moon [ ;are there any moons? foreach "moon item :planet :mooncolor [ ;for each moon, let's create it the same way we did planets: make "moonnumber loopcount make "moonmodel word :planet loopcount newmodel :moonmodel {"setfc :moon "ico 0.1 * item :moonnumber item :planet :moonsize} make "parent turtle ;define the 'parent' turtle for use by the moon hatchling hatch [ ;hatch the moon setmodel :moonmodel dropanchor right random 360 pullout item :moonnumber item :planet :moondistance orbitup item :moonnumber item :planet :moontilt showturtle forever [ fixate query :parent [position] ;keep 'fixated' (look at and set the anchor point to) ;the parent turtle's position. if orbitdistance > item :moonnumber item :planet :moondistance [
                pullin orbitdistance - (item :moonnumber item :planet :moondistance)
              ]
              ;if it's getting away from us, try and catch up!
              
              orbitright 0.1 * item :moonnumber item :planet :moonspeed
              ;orbit the planet based on the :moonspeed
              
              sleep 6.25
              ;take a little nap
            ]
          ]
        ]
      ]
      forever [
        orbitright 0.05 * item :planet :speed
        sleep 25
      ]
      ;orbit the sun (we're back to the planet now) based on the value
      ;from the :speed list. Then take a little nap (wait 1)
      
    ]
  ]
  hideturtle
  ;hide Myrtle, although she would be sitting in the sun
  
END

One-a-Day: Space Tube Ride using TUBE and TUBEARC

Myrtle creates a 3D space tube ride for her to fly through…

Sometimes Myrtle needs to take a break and have a little fun! One of the things she can do is make a space tube and fly through it, using the TUBE and TUBEARC primitives:

TUBE makes a straight tube, and takes the parameters <radius> <depth> and <sides>. So, tube 20 10 10 makes a tube with a radius of 20 turtle units, a depth of 10 turtle units and 10 sides.

TUBEARC creates a curved tube, and takes the parameters <thickness> (the radius of the tube itself) <radius> (the radius of the arc itself) <sides> <totalsegments> and <arcsegments> – the last two are the total segments that would make up a complete torus, or donut, and the number of segments we actually want to create. So values of 20 and 10 will create a half-donut: tubearc 10 20 20 20 10

There are four procedures to our space tube program: createcourse, drawcourse, followcourse and spacetube.

createcourse generates the data that represents the tube’s course. It creates a course made up of 100 segments, represented by a word made up of a series of numbers between 0 and 4, where 0 represents a straight section of tube, and 1 to 4 represent four directions of turn. We use dountil to ensure we don’t repeat the same direction of turn more than once and end up looping back on ourself. Although, createcourse is not perfect and it is still possible for the course to cross over itself – but it’s a good thing tube walls aren’t solid!

drawcourse creates the graphical representation of the contents of the :course container we generated using createcourse. We use the twosided primitive to generate reflective “normals” on both sides of the shapes we generate from that point forward, and we use randfc to set a random ‘fill color’ or shape color for each segment as we create them.

We use foreach to step through each segment listed in the :course container, creating either a tube or a tubearc where appropriate.

While tubes are created directly under Myrtle, tubearcs are created around her, and so this means we need to do a bit of calisthenics to position the tubearcs where they need to go. Follow them through one command at a time to see how they work! We wait 2 / 60ths of a second between each segment creation so we can follow it.

followcourse causes Myrtle to fly through the created course, once again iterating through the :course container using foreach. fluid causes Myrtle to move forward smoothly, and to turn through the arcs we use a repeat. sleep is another form of wait, which takes milliseconds as a parameter instead of wait‘s 60ths of a second.

setpremodel allows us to ‘prepend’ commands to the turtle’s model, allowing us to make Myrtle look like she’s turning the appropriate way as she moves through the course.

Finally, spacetube puts it all together and is the procedure we execute to create the maze and fly through it. spacetube performs a reset, turns off the text layer, tells Snappy (the camera turtle) to pull away from Myrtle 1000 turtle units, tells Snappy to ‘follow’ Myrtle (turn to face her when she disappears from his view), then executes the createcourse procedure, the drawcourse procedure, sets the view (camera) turtle to Myrtle, turns Myrtle’s ‘light’ on (so we can see properly inside the tubes), turns Snappy’s light off, sets the camera ‘view point’ of Myrtle a bit up and behind her, and then executes followcourse.

TO spacetube
  reset
  fullscreen
  snappy:pullout 1000
  snappy:follow "myrtle
  createcourse
  drawcourse
  setview "myrtle
  setlight 1
  snappy:setlight 0
  setviewpoint [0 10 -30]
  followcourse
END

TO createcourse
  make "course empty
  make "last 5
  repeat 100 [
    
    dountil :last != :segment [make "segment random 5]
    
    make "course word :course :segment
    if :segment != 0 [make "last :segment]
  ]
END

TO drawcourse
  nofluid
  cs
  pu twosided
  foreach "segment :course [
    randfc
    if :segment = 0 [tube 50 200 20 lo 200]
    else [rt :segment * 90
      dn 90 rr 90 sl 100 tubearc 50 100 20 20 5 fd 100 rr 90 lt 180 + :segment * 90]
    wait 2
  ]
  home
END

TO followcourse
  dn 90
  fluid
  foreach "segment :course [
    if :segment = 0 [fd 200]
    if :segment = 1 [setpremodel [rt 22.5] repeat 90 [fd 1.75 rt 1 sleep 1] setpremodel []]
    if :segment = 2 [setpremodel [dn 22.5] repeat 90 [fd 1.75 dn 1 sleep 1] setpremodel []]
    if :segment = 3 [setpremodel [lt 22.5] repeat 90 [fd 1.75 lt 1 sleep 1] setpremodel []]
    if :segment = 4 [setpremodel [up 22.5] repeat 90 [fd 1.75 up 1 sleep 1] setpremodel []]
  ]
END