Skip to content
turtleSpaces turtleSpaces
  • Gallery
    • Browse Published
  • News
  • Docs
    • About Logo
    • Tour
    • Features
    • FAQ
    • Books
    • Reference
    • Tutorials
    • Examples
    • Shape Guides
    • Contemplations
    • Updates
    • Roadmap
    • Terms of Service
    • Privacy Policy
  • Discord
  • Get
  • Launch IDE
    • About
    • Open

‘Snake’ written in turtleSpaces Logo

  • Home
  • ‘Snake’ written in turtleSpaces Logo
November 9, 2020

TO snake
  
  ;setup:
  
  reset
  ;empties (erases) all containers (variables),
  ;returns the turtles to their default positions,
  ;restores their states to defaults
  
  release
  ;sets all the turtles, except for the default ones
  ;(myrtle, snappy, libby) 'free' - erasing them
  
  penup
  ;don't draw
  
  setbackgroundcolor lightblue
  
  hideturtle
  ;don't show the executing turtle (typically myrtle)
  
  stealth
  ;don't show up in output from the near primitive
  
  noaudiowait
  ;don't delay when playing sounds (the default)]
  
  print |Use keys J and K to turn snake, eat apples!|
  ;print instructions to the screen
  
  ;create the 'ground'
  setfillcolor brown
  setpos [-185 -115]
  lower 5
  quad 185 * 2 115 * 2
  
  make "score 0
  make "length 8
  ;the default snake length, in segments
  
  make "queue empty
  ;this snake implementation uses a push / pull queue
  ;to keep track of the snake's turns
  
  repeat :length [push "fd "queue]
  ;all segments start moving forward
  
  newmodel "ball [setfillcolor 12 icosphere 5]
  newmodel "head [setfillcolor 4 icosphere 6]
  newmodel "apple [setfillcolor red icosphere 4]
  ;create turtle models, where ball is a non-head segment
  
  ;create the turtles that make up the starting snake:
  repeat :length [
    nameturtle repcount
    ;create a new turtle
    ;each segment has the number of its segment as its name
    
    control repcount {"wrap "penup "back repcount "* 10 "showturtle}
    ;initialize the new turtle and move it into position
    ;{} denotes a 'softlist', a list whose contents are evaluated
    ;at execution
    
    control repcount [
      setbounds [-185 -115 185 115]
    ]
    ;sets the bounds used for wrapping. [] denotes a 'hardlist', a
    ;list whose contents are fixed and not evaluated
    
    if repcount = 1 [control 1 [setmodel "head]]
    ;if this is the first segment, give it the 'head' model
    else [control repcount [setmodel "ball]]
    ;otherwise, give it the 'ball' (segment) model
  ]
  
  ;set up the 'apple' turtle:
  nameturtle "apple
  control "apple [
    penup setmodel "apple showturtle
    
    dountil (count near position 5) = 1 [
      setpos {-180 + (10 * random 36) -100 + (10 * random 20)}
    ]
    ;set a random position until such times as the apple is not near
    ;any snake segments (turtles)
    
    ;leading parameters used in comparison operators (=, >, < etc) ;must be enclosed in {}'s if more than a single value or primitive ;because the parser evaluates right to left ] ;the main loop: forever [ norender ;don't render while we shuffle the snake forward for {"i 1 :length} [ make "move item :i :queue ;set the move variable to the :i item in the :queue switch "move case "fd [ask :i [forward 10]] case "rt [ask :i [right 90 forward 10]] case "lt [ask :i [left 90 forward 10]] ;switch / case statements execute instructions based on the ;contents of the container (variable) provided to switch ;ask creates a new worker that executes the commands using ;the specified turtle (the turtle named by :i) ;so, in this for loop we are iterating through the :queue, ;moving the turtle segments based on the item present in ;each space in the queue (fd, rt or lt) ] while workers != [] [sleep 1] ;sleep execution until the ask workers finish moving their ;turtles (the snake). This way, when we enable the render, ;we won't catch the snake mid-move. render ;enable rendering again wait 40 - :score ;wait units are 60ths of a second. The higher the score, the ;shorter the wait will be ;user control: if keyp [ ;did the user press a key? If so, do this stuff: make "input readchar ;take the output from the readchar primitive and place it ;into the input container. keyp indicates if there is a character ;already in the keyboard buffer. If readchar is called when there ;is no character in the buffer, it waits. switch "input case "j [push "lt "queue] ;if the user pressed the j key, push lt to the front of the queue case "k [push "rt "queue] ;if the user pressed the k key, push rt to the front of the queue otherwise [push "fd "queue] ;if no case has been satisfied since switch (the user pressed a key ;other than j or k), push fd to the front of the queue ] else [push "fd "queue] ;similarly, if the user hasn't pressed any key, push fd to the front ;of the queue ignore dequeue "queue ;ignore (drop) the last value off the end of the :queue ;dequeue would ordinarily return this value, ignore sends it into ;the ether ;is there something occupying the same space as the head of the snake? if (count (near 1:position 5)) > 1 [
      ;near returns the names of the turtles within the specified distance (5)
      ;count returns the count of the number of turtles returned by near
      ;if there is more than one (the head itself), we will execute the following:
      
      if memberp "apple near 1:position 5 [
        ;is it an apple?
        
        playsound "chomp
        inc "score
        ;increment the value in the score container by one
        
        (print |Yum! Score:| :score)
        ;to pass more than the default number of parameters to a primitive, wrap
        ;it in parentheses (round brackets)
        
        dountil (count near apple:position 5) = 1 [
          control "apple [setpos {-180 + (10 * random 36) -100 + (10 * random 20)}]
        ]
        ;place a new apple
        
        repeat 2 + int (:score / 10) [
          
          queue "pa "queue
          ;a pa or 'pass' will cause these new segments not to move on the next
          ;iteration, until movement commands are 'shuffled' on to their places
          ;in the queue
          
          inc "length
          ;increment the value of the length container by one
          
          nameturtle :length
          ;create a new turtle with the name contained in :length (the new length)
          
          (control :length {"hideturtle "setmodel ""ball "wrap "penup "setpos
          "query :length - 1 leftbracket "position rightbracket "setvectors
          "query :length - 1 leftbracket "vectors rightbracket})
          ;set up the new turtle and make sure it's positioned next to the
          ;previously last turtle, and is facing in the same direction
          
          control :length [setbounds [-185 -115 185 115] showturtle]
          ;set the bounds of the new turtle and show it
          
          wait 10
        ]
        ;add new segment to the snake
        
      ]
      
      ;and if it's not an apple?
      else [
        print "crash! playsound "crash finish
      ]
      ;game over, man! game over!
    ]
  ]
  
END

turtleSpaces is a graduated Logo programming language interpreter that helps you create two and three-dimensional artworks, animations and games.

It provides an easy, straightforward introduction to text-based coding.

It is based on and compatible with Logo from the Apple II, which gives it a cool retro feel, but with a vastly improved user interface and modern capabilities such as multiple threads and turtles.

Launch webLogo!

webLogo IDE

Click here to open our webLogo environment with integrated editor!

Join our Discord! (and X...)

Get help on Discord and see hundreds of examples on X!

Click here to join our Discord!
Click here to follow us on X!

Recent Updates

  • Introducing Model Context Protocol server
  • Recent turtleSpaces Updates (May 2025)
  • Introducing Spaces
  • A Logo Success Story
  • Desert Mountain Lake — An Introduction to Fill

Archives

  • Logo Coding Tutorials
  • Logo History and Contemplations
  • Logo Programming Examples
  • turtleSpaces Development Updates

Need help?

Myrtle

help@turtlespaces.org

turtleSpaces on X

Follow @turtleSpaces on X to see hundreds of examples!

Keywords

Seymour Papert · Logo coding · Logo programming · Turtle programming · Turtle Art · Logo Art · Learning to code · Coding for Kids · Coding is Fun! · Coding Art · Kids can Code · 3D Logo Programming · 3D Coding · 3D Printing · 3D Modeling · 3D Game Design · STEM Education · K-12 Education · After Scratch Before Python · Retrocoding · Retrocoders · OpenGL · GLFW

About Logo

Created in the 1960s to be a computing language understandable to children, Logo (not an acronym, but from the Greek word Logos, meaning 'speech') was initially designed as a language for manipulating… well, language, taking list processing concepts from LISP.

The turtle came later in an attempt to add geometry to Logo's proposed curriculum, first a physical turtle, then as computer displays became more common a 'virtual' one, which drew lines on the screen.

turtleSpaces is an implementation of the Apple II version, but on modern hardware, with the addition of dozens of shape primitives, tables, databases, cameras, lights, music and much more.

It runs in web browsers (WebAssembly), and has applications for Windows, macOS and Linux.

Copyright © 2020–2026 RetroCoders! | turtleSpaces is developed by April and Melody Ayres-Griffiths