# Archives November 2020

#### Quick Play: Warped Logo Spirals

One of the best things about turtleSpaces is its capacity for discovery through play.

Today I was playing with spirals:

I started off by creating a simple spiral using the RARC primitive and a simple REPEAT loop. This loop uses REPCOUNT (the current repeat loop iteration) to define the radius of the arc, resulting in an ever-growing spiral.

I clicked and dragged on the window to rotate the camera around the spiral. But let’s make the spiral itself three-dimensional:

I’ve ‘warped’ the spiral by placing three rarcs inside of the repeat loop, along with a ROLLLEFT (rl) and a ROLLRIGHT (rr). With the twisting and turning, the turtle ends up roughly halfway around a somewhat distorted circle, which you can see if you type:

```cs rarc 90 20 rr 90 rarc 90 20 rl 90 rarc 90 20

cs repeat 2 [rarc 90 20 rr 90 rarc 90 20 rl 90 rarc 90 20]```

If we orbit the camera (by clicking and dragging) around our spiral, we can see just how warped it is!

What else can we do with it?

Whoa! What happened there? I added a dn (down) 10 to the end of the loop. Let’s take a look from another vantage point:

That’s pretty distorted. Let’s try a smaller value, say 2:

Okay, pretty neat. How about if at the end of each loop we also roll left (rl) a little?

Another angle:

Let’s play around with the values of down (dn) and rollleft (rl) a bit:

What if we do a right turn (rt) instead of a roll right (rr)?

And what if we add the roll back in?

Let’s play around with the values a bit:

All right, that’s enough from me! But you can play around with the different values and see what happens. That’s all part of the fun of turtleSpaces!

#### Make it Rain!

```TO rain

reset

penup hideturtle
fullscreen
make "count 0

forever [

inc "count
setposition {-300 + random 600 300 -300 + random 600}
make "size 0.25 + ((1 + random 20) / 20)

begintag "teardrop
setfillcolor pick [2 3 6 7 14]

up 90
cutsphere 10 * :size 20 20 1 13
lower 4.5 * :size
cone 8.9 * :size 18 * :size 20
down 90
;raindrop

endtag

newmodel :count "teardrop
clean

hatch [
setmodel :count
showturtle
make "speed (5 + random 10) / 10
while ypos > -300 [
back :speed rollright 0.25
]
]

wait 5 + random 25
]

END
```

#### Control turtleSpaces from other applications with its API

You can communicate with turtleSpaces over a socket (telnet) connection to port 1967.

First you need to issue the API command inside of turtleSpaces to enable API connections, or use the -enable-api flag when starting up.

Then connect to turtleSpaces from an external application or terminal. You can issue instructions to affect turtles and the environment just like you would do inside the turtleSpaces application.

The API connection executes as its own worker. You can also redirect input and output to the API instance by using setread “api and setwrite “api – but these must be issued by the API worker itself to redirect to that worker (if you use another API connection, reading and writing will be redirected to that API instance, for example).

Using the API, you can use turtleSpaces as a visualiser for another application, and have it act as a light organ, or create charts and graphs.

#### ‘Snake’ written in turtleSpaces Logo

```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:

;take the output from the readchar primitive and place it
;into the input container. keyp indicates if there is a character
;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
```