Pico Logo
August 14, 2026 · View on GitHub
Installation
From the Releases page, download the UF2 file for your device and the logo.img file. On your SD Card, copy the logo.img file into the root folder and insert it into the PicoCalc.
Flash the PicoCalc with the latest release and reboot your PicoCalc:
- Make sure your PicoCalc is off.
- Push and hold the BOOTSEL button, accessible through the back of the PicoCalc, while connecting your PicoCalc with a USB cable to a computer. Use the USB port of the Pico, closest to the bottom of the device.
- Release the BOOTSEL button once your Pico appears as a mass storage device called
RPI-RP2. - Drag and drop the Pico Logo UF2 file onto the
RPI-RP2volume. Your Pico will reboot. - Disconnect the USB cable and turn on the PicoCalc. You are now running Pico Logo.
You should see:
Copyright 2025-2026 Blair Leduc
Welcome to Pico Logo.
?_
The question mark, ? is the prompt. When the prompt is on the screen, you can type something. The flashing underscore, _ is the cursor. It appears when Logo wants you to type something and shows where the next character you type will appear.
Restore the default filesystem
At the prompt, enter:
.restore "/sd/logo.img
This will format and restore the factory filesystem contents. You can now remove the logo.img file from the SD Card.
References
This reference manual contains content that is collected from:
- Apple Logo Reference Manual
- Apple Logo II Reference Manual
- Atari Logo Reference Manual
- Berkeley Logo
===
Contents
{{TOC}}
===
Introduction
Logo Programs
A Logo program is a collection of procedures.
For example, a program to draw a house consists of these procedures: house, box, tri, right, forward, and repeat. Of these, the last three are primitives. The first three are user-defined procedures, built out of Logo primitives.
to house
box
forward 50
right 30
tri 50
end
to box
repeat 4 [forward 50 right 90]
end
to tri :size
repeat 3 [forward :size right 120]
end
We are assuming that you have had some experience with Logo and have built up an intuitive model of what Logo is about. Here we give a more formal model. This model is just another way to think about Logo. It is not meant to replace your current way of thinking, but rather to enhance it.
Formal Logo
The actual Logo system is very complicated. It will help if we consider a formal description of Logo, and then Logo as it really is. We begin our formal description by restricting ourselves to a part of Logo, which we'll call formal Logo; we then relax the restrictions in order to describe the language you actually use, which we'll call relaxed Logo.
Every instruction in formal Logo works without change in relaxed Logo. Conversely, anything that can be done in Logo can be done in formal Logo, but you will immediately recognize situations where formal Logo forces idioms that no one would actually use. For example, if you are experienced in Logo you will notice that numbers look peculiar in formal Logo: they are quoted. Since numbers are words, you can quote them in relaxed Logo as well. But we do so very rarely; in relaxed Logo, numbers are self-quoting.
Procedures and inputs: We assume that you know what procedures are, at least on an intuitive level. Here we develop some more precise ways to talk about them.
In formal Logo, every procedure requires a definite number of inputs. These inputs are always one of two kinds: they may be words or they may be lists. They may be given directly, as in forward "100, or indirectly through the mediation of another procedure, as in forward sum "60 “40. Both of these examples have the same effect. If an input is given directly as a word, it must be preceded by a quote mark, as in print "forward. If it is given directly as a list, it is surrounded by square brackets, as in print [How are you?].
Words and lists: A word is made up of characters. A list is made up of elements enclosed in square brackets, with spaces between elements; an element is either a word (without quotes) or a list.
Naming things: The name of a procedure, input, or variable is a word. Logo does not care if a name is in lower or upper case. For example, the following are regarded as being the same:
forward "100
FORWARD "100
The name is remembered using the case that is used in the definition.
Property Lists: Any Logo word can have a property list associated with it. A property list consists of an even number of elements. Each pair of elements consists of a property, and its value, a word or a list.
Expressions: A procedure name followed by the required number of inputs is an expression. More generally, an expression is
- a quoted word,
- list, or
- an (unquoted) procedure name followed by as many expressions as the procedure requires.
If this seems complicated, look at an example. repeat is a procedure that requires two inputs.
This is an expression:
repeat "3 [fd "10]
The following is also an expression:
repeat sum "2 "1 [fd "10]
In this case the first input is not a quoted word, but an expression involving another procedure, sum.
The following is also an expression:
repeat sum "3 "1 sentence "fd "10
Commands and operations: There are two kinds of procedures in Logo. Those (like sum) that produce a Logo object are called operations. The others (like print) are called commands.
With these definitions we can define a Logo instruction.
A Logo instruction is a particular kind of expression. It starts with a procedure name, and that procedure must be a command. All other procedures in the expression must be operations.
Why does it matter whether an expression is an instruction or not? Consider
sum "3 "4
This is an expression, but it is not a Logo instruction.
sum will produce a number; but simply writing sum "3 "4 does not state what is to be done with the number. In fact, Logo will give an error message saying I don't know what to do with 7. Some programming languages would allow this and simply print the 7. In designing Logo we preferred to make every important act explicit; if you want something to be printed you should say so.
Relaxed Logo
Everything that can be done in Logo can be done using formal Logo. But we have allowed some other idioms, either to make the language feel more natural or to eliminate large amounts of typing.
Here we list some important relaxations of Logo. Others are mentioned in the body of the manual. See also Parsing.
Numbers: In formal Logo, all words used as direct inputs, including numbers, must be quoted. In relaxed Logo, numbers are self-quoting: the quote marks are unnecessary. For example,
sum 3 4
A number is a word made up of digits; it may also contain a minus sign, a period, and an E or N. See (Arithmetic Operations)[#arithmetic-operations].
?print 1e4
10000
?print 1n4
0.0001
Infix procedures: Formal Logo uses only prefix procedures. Thus addition is expressed by sum "3 “4. In relaxed Logo you can also use the infix form 3 + 4. Similarly with multiplication, subtraction, and division. See Arithmetic Operations.
Variable number of inputs: In formal Logo, every procedure has a fixed number of inputs. In relaxed Logo, several procedures can have variable numbers of inputs. When you use other than the expected number of inputs you must enclose the expression in parentheses:
(sum 3 4 5 6 7 8)
Dots: A familiar feature of relaxed Logo is the use of dots (:). In formal Logo, :x is written as thing "x.
Parentheses for grouping: Logo has parentheses so that you can explicitly tell Logo how to Group things. For example, consider
25 + 20 / 5
Should the addition be done first, producing 9, or should the division be done first, producing 29? Relaxed Logo follows the traditional mathematical hierarchy, in which multiplication and division are done before addition and subtraction; thus this operation first divides 20 by 5, and produces 29. To group the numbers so that addition is done first, parentheses must be used:
(25 + 20) / 5
Commands and operations: In formal Logo, a given procedure is either a command or an operation, not both. In relaxed Logo, a procedure can be sometimes a command and sometimes an operation. run and if are examples of this. See Conditionals and Control of Flow.
The command to: In formal Logo, you define a procedure with the command define; it takes two inputs, a word (the procedure name) and a list (the definition). All the usual rules about quotes and brackets apply without exception:
define "square [ [ ] [ repeat 4 [ fd 100 rt 90 ] ] ]
In relaxed Logo, you can define a procedure with edit and to. The command to is unusual in two ways. It automatically quotes its inputs, and it allows you to type in the lines of the procedure interactively:
?to square :size
>repeat 4 [fd :size rt 90]
>end
As shown, when interactively defining a procedure using the command to, the prompt changes to > until a line ending with end is encountered ending the definition of the procedure. This provides feedback that you are in the middle of defining a procedure and is the only time when this prompt is used.
A Further Note on Operations
In talking about formal Logo we have been using the word produce: a procedure produces an object (called the output of the procedure). In traditional Logo terminology we say that the procedure outputs an object.
Logo Objects
There are two types of Logo things (or objects): words and lists.
A word, such as television or 617, is made up of characters (letters, digits, punctuation). A number is a kind of word.
A list, such as [rabbits television 7 [ears feet]], is made up of Logo objects, each of which can be either a word or a list. See Words and Lists.
Variables: Some General Information
A variable is a container that holds a Logo object. The container has a name and a value. The object held in the container is called the variable's value. You create a variable in one of two ways: either by using the make or name command, or by using procedure inputs.
Logo has two kinds of variables: local variables and global variables. Variables used as procedure inputs are local to that procedure. They exist only as long as the procedure is running, and will disappear from your workspace after the procedure stops running.
Normally a variable created by make is a global variable. The local command lets you change those variables into local variables. This can be very useful if you want to avoid cluttering up your workspace with unwanted variables.
to yesno: question
local "answer
pr :question
make "answer first readlist
if equal? :answer "yes [ output true ]
output false
end
How You Might Think about Quotes
The role of quotes is best understood through the following example:
?print "heading
heading
?print heading
180
In the first case the quotation mark (") indicates that the word heading itself is the input to print.
In the second case the input is not quoted. It is therefore interpreted as a procedure, which provides the input to print.
How You Might Think about MAKE
The effect of the command
make "bird "pigeon
can be thought of as follows. A container is given a name: bird. The word pigeon is put into the container.
Once this is done the operation thing has the following effect:
thing "bird
produces pigeon.
Dots are similar to thing; for example,
:bird
produces pigeon.
We can talk about the same situation in several ways:
bird is a variable; pigeon is its value.
bird is a name of pigeon.
bird is bound to pigeon.
pigeon is the thing of bird.
You can change what it is in the container; if you type
make "bird "sparrow
then the container bird contains the word sparrow instead of the word pigeon.
How to Think about Procedures You Define and their Inputs
Procedures you define can have inputs. When you define a procedure, its title line specifies how many inputs it has and a name for each one. The inputs are put into the containers designated on the title line of the procedure definition in the order in which they occur. For example, the following procedure makes the turtle draw various polygons, depending upon what inputs are used.
to poly :step :angle
forward :step
right :angle
poly :step :angle
end
Whatever inputs you choose-for example, 50 and 90-are put into the specified containers. The first input is always put in the container step; the second input is always put in the container angle. The first input variable, step, controls the size of the figure. The second input variable, angle, controls the shape of the figure. poly 50 90 makes the turtle draw a square; poly 50 144 makes the turtle draw a pentagram; poly 50 120 makes the turtle draw a triangle.
If the input containers already have objects in them when the procedure is run, the objects are removed but are saved. They are restored when the procedure is done. In other words, the procedure borrows the container and leaves it in its original condition when done with it. This is what is meant by saying that a variable is local to the procedure within which it occurs.
For example:
?make "sound "crash
?print :sound
crash
Now we run a procedure called animal; its input variable is sound.
to animal :sound
if :sound = "meow [ pr "Cat stop ]
if :sound = "woof [ pr "Dog stop ]
pr [ I don't know ]
end
If we type animal "woof, then woof is put into the sound container for the duration of the animal procedure. Afterwards, crash is restored:
?make "sound "crash
?print :sound
crash
?animal "woof
Dog
?print :sound
crash
Another Way to Talk about Procedures
When you use a procedure, we also say that you call that procedure. Procedures you define call other procedures. For example, the poly procedure above calls other procedures (forward and right).
poly also calls itself. This is called a recursive call.
Review of Special Characters
Quotation marks, or quotes, ”, used immediately before a word, indicate that it is being used as a word, not as the name of a procedure or the value of a variable.
A colon, known as dots, :, used immediately before a word, indicates that the word is to be taken as the name of a variable and produces the value of that variable.
Brackets, [ ], are used to surround a list.
Parentheses, ( ), are necessary to group things in ways that Logo ordinarily would not, and to vary the number of inputs for certain procedures. Both of these uses are described above in this introduction.
A backslash, \, tells Logo to interpret the character that follows it literally as a character, rather than keeping some special meaning it might have. For instance, suppose you wanted to use 3[a]b as a single word. You need to type 3\[a\]b in order to avoid Logo’s usual interpretation of the brackets as the envelope around a list. You have to backslash [,(,],),+,-,*,/ and \ itself.
===
Difference from other Logo interpreters
Line continuation characters are not supported.
Words with internal spaces are created using the "\" character, not using the veritcal bar notation.
Pico Logo does not support the if predicate list1 list2 form. Use (if predicate list1 list2) or ifelse predicate list1 list2 instead.
Anonymous procedures are written as named lambda expressions - a list whose first element is a list of input names, followed by the body - rather than the ?-slot template notation ([? + 1]) used by UCB/Berkeley Logo. Where Berkeley Logo would write map [? + 1] [1 2 3], Pico Logo writes map [[x] :x + 1] [1 2 3]. See List Processing for details.
Word and name comparisons are case-insensitive throughout, including equal?: equal? "Hello "hello outputs true, and a list containing "Hello is member? of a list containing "hello. Variable and procedure names are likewise case-insensitive - make "Total 1 and :total refer to the same variable. Use before?, which compares ASCII values, when exact-case comparison is needed.
All numbers are single-precision (32-bit) IEEE floating point, matching the RP2350's hardware FPU; there is no bignum or double-precision arithmetic, so results very slightly differ in their last digit from Logos that compute in double precision. Numbers printed in exponential form use n rather than a signed exponent for negative powers of ten - 1n5 means 1 × 10-5, while 1e7 means 1 × 107 - following Apple Logo's convention rather than the 1e-5 form other Logos use (a bare minus sign inside a word is easily confused with the subtraction operator).
Pico Logo has no array data type and no array/setitem primitives for O(1) indexed access; lists are the only ordered collection. .setfirst, .setbf and .setitem do mutate a list in place, as in UCB Logo, but there is no fixed-size random-access structure to mutate into.
Tail-recursive procedures run in constant space - see Tail Call Optimization, below.
Tail Call Optimization
When the last thing a procedure does is call itself - directly, as the whole
of the last instruction line, or as the argument to output,
or inside the taken branch of if/ifelse in tail
position - Pico Logo reuses the procedure's current frame instead of pushing
a new one. This is a genuine loop under the hood, not a stack of pending
calls, so a tail-recursive procedure runs in constant space no matter how
many times it calls itself:
?to countdown :n
>if :n = 0 [stop]
>countdown :n - 1
>end
?countdown 1000000
countdown above never runs out of recursion, because each recursive call
reuses the same frame rather than adding one. This is a differentiator from
classic Logo implementations, most of which count every recursive call
(tail or not) against a fixed recursion depth and would overflow on a
million-deep call like this one.
The optimization only reuses the frame for a procedure calling itself.
Mutual recursion (a tail-calls b, which tail-calls a) and any
non-tail call still consume a level of the recursion limits given under
Supported Pico Boards (128 or 192, depending on
the board).
===
Supported Pico Boards
Pico Logo runs on three RP2350-based boards. The interpreter and its limits are identical on every board; what differs is networking - which needs a wireless radio - and storage capacity, which depends on the flash and PSRAM fitted.
Shared by every board (the RP2350 processor):
- 32768 nodes for procedure and variable storage
- 24576 characters of editor buffer
- 8192 characters in the copy buffer
- Hardware floating-point operations
Raspberry Pi Pico 2 - 4 MB flash, no radio.
- 192 levels of recursion (self tail-recursive calls don't count - see Tail Call Optimization)
- 2 MB internal filesystem
- No networking
Raspberry Pi Pico 2 W - 4 MB flash, WiFi, no PSRAM.
- 128 levels of recursion (self tail-recursive calls don't count - see Tail Call Optimization)
- 2 MB internal filesystem
- WiFi (
wifi.connect,wifi.scan, …) withnetwork.resolve,network.ntpandnetwork.ping http.getandhttp.postoverhttp://only;https://is not available, sotls?outputsfalse- HTTP responses are limited to about 2 KB (there is no PSRAM to hold a larger body)
Pimoroni Pico Plus 2 W - 16 MB flash, 8 MB PSRAM, WiFi.
- 128 levels of recursion (self tail-recursive calls don't count - see Tail Call Optimization)
- 8 MB internal filesystem
- WiFi (
wifi.connect,wifi.scan, …) withnetwork.resolve,network.ntpandnetwork.ping http.getandhttp.postover bothhttp://andhttps://, sotls?outputstrue- HTTP responses up to about 512 KB, held in PSRAM
- Words may exceed 255 characters (for example the result of
wordor an HTTP response body), held in PSRAM
===
Startup
This section describes the feature of Logo that lets you automatically load a file into your workspace when you start up Logo. You must call the file startup. There can be only one file with the name startup, although it can include commands to load other files.
The default prefix is /, the root of the device's internal storage, so the startup file is located at /startup. You can change the startup file, with editfile.
>editfile "startup
You can bury procedures and buryname variables created in your startup file (using the startup variable!) so they are not a distraction. buryall is a good approach.
For example:
?erall
?to welcome
>pr [Hello there!]
>end
?make "startup [welcome buryall]
?save "startup
You also erase procedures and variables that are only needed for startup processing (see erase and ern).
===
Using the Logo Editor
The Logo Editor is an interactive screen-oriented text editor, which provides a flexible way to define and change Logo instructions. The main command for starting up the Logo Editor is edit.
How the editor works
When you call the Editor, Logo changes the screen. The editor uses the entire screen with the header:
PICO LOGO EDITOR
centred on the top row (the top row is reverse video). The bottom line has centred in reverse video
ESC - ACCEPT BRK - CANCEL
The content you edit is on the 30 lines between the top and bottom rows. There is no prompt character, but the cursor shows where you are typing.
The text that you edit is in an area of memory called a buffer. When you enter the Editor, Logo displays the text from the edit buffer, up to 30 lines per screen.
You can move the cursor anywhere in the text using the cursor control keys described later in this section. You can also delete and insert characters using the appropriate keys.
Each key that you type makes the Editor take some action. Most typewriter characters (letters, numbers, punctuation, and Enter) are simply inserted into the buffer at the place marked on the screen by the cursor.
When you press Enter, the cursor (and any text that comes after it) moves to the next line, ready for you to continue typing.
You can have more characters on a line of text than fit across the screen. When you get to the end of the line on the screen, just continue typing without pressing Enter. The screen will scroll horizontally to show the rest of the line.
The Editor has an auxiliary line buffer called the copy buffer. You can use it to move text in a procedure or to repeat them in different places. The copy buffer can hold a limited number of characters. While this is true for the copy buffer, the length of a line is limited only by the length of the edit buffer.
Editing actions
When you are in the editor, you can use the following editing keys:
Cursor motion
←- moves the cursor one character to the left→- moves the cursor one character to the right↑- moves the cursor up to the previous line at the same column↓- moves the cursor down to the next line at the same columnHome- toggles the cursor between the first non-whitespace character and the beginning of the lineEnd- moves the cursor to the end of the lineShift↑- moves the cursor to the previous pageShift↓- moves the cursor to the next page
The cursor will not move if that position is not valid.
Inserting and deleting
Enter- creates a new line at the current cursor position and moves the cursor (and any text that comes after it) to the new line←Back- erases the character to the left of the cursorDel- erases the character at the cursor positionTab- inserts spaces until the next tab stop (tab stops are every 2 columns)CtrlF- starts incremental search (finds text)CtrlXorCtrlT- erases (or takes) the current line and stores the text in the copy buffer, including the new lineCtrlCorCtrlY- copies (or yanks) the current line and stores the text in the copy buffer, including the new lineCtrlVorCtrlP- inserts (or pastes) the text in the copy buffer at the cursor position
Block editing
Selected text is between the start anchor and the cursor and is shown in reverse video. The character at the cursor is not included in the selection. Ctrl B sets the start anchor at the cursor position. Pressing Ctrl B when the start anchor is set removes the start anchor and cancels the selection. The cursor motion keys are used to select text when the start anchor is set.
Delor←Back- erases the selected text without storing the text in the copy bufferCtrlXorCtrlT- erases (or takes) the selected text and stores the text in the copy bufferCtrlCorCtrlY- copies (or yanks) the selected text and stores the text in the copy bufferCtrlVorCtrlP- replaces (or pastes over) the selected text with the text in the copy buffer.Ctrl,- decreases the indent of the block by one tab stopCtrl.- increases the indent of the block by one tab stop
Typing any other key (except Esc or Brk) is ignored while the selection of text is active.
Incremental Search
Incremental search finds and highlights text matches in real time as you type each letter. Ctrl F starts incremental search. In this mode, typing characters will cause the editor to jump to the first match of the accumulated match text starting at the current cursor position. The match (if found) is selected (block editing). Pressing ↓ will jump to the next match of your typed phrase, and ↑ will jump to the previous match of your typed phrase, both cycling through all occurrences. Pressing ←Back removes the last letter to widen the search back out.
Matching ignores the difference between upper and lower case, so fd finds FD. When the typed phrase matches nowhere in the buffer, nothing is selected and the cursor stays at the last match found.
During incremental search, the bottom line now displays (left justified in reverse video) Search: followed by the characters in the search text. A maximum of 32 characters may be used to match text.
Pressing Esc leaves incremental search and any selected text remains selected. Pressing Brk leaves the Editor, cancelling your changes as usual.
Replacing text
Ctrl R, during an incremental search, replaces every match of the search text. The bottom line changes to Replace: and the text you type after it is what each match is replaced with, up to 32 characters. The replacement is used exactly as typed, whatever the case of the text it matched, so searching for fd and replacing with forward changes FD to forward as well.
While typing the replacement, ← and → move the cursor through it, ←Back erases the character to the left of the cursor and Del erases the character at the cursor. Tab and the other non-printable keys are ignored.
Pressing Enter replaces every match in the buffer and leaves incremental search. An empty replacement is allowed and erases every match. Nothing is replaced if the result would not fit in the Editor's buffer.
Pressing Esc cancels the replacement and returns to the incremental search, where the match found so far is still selected. Pressing Brk leaves the Editor, cancelling your changes as usual.
Viewing screens
F3 lets you see temporarily the graphics screen and its most recent contents. F1 restores the screen back to the Editor so you can pick up where you left off.
Exiting the editor
When you exit from the Editor using Esc, Logo reads each
line in the edit buffer as if you had typed it directly from top level.
If the instructions in the edit buffer define a procedure (that is, if there is a title line to ... that starts the definition), Logo behaves as though you had typed the definition of the procedure using to. If the buffer contains a procedure definition, but there is no end instruction at the end of the buffer, Logo helps out by ending the definition for you.
If there are Logo instructions on lines in the edit buffer that are part of the definition of a procedure, Logo caries them out when you exit the editor. Logo will not carry out any graphics commands or editing commands.
In the Editor, you may define more than one procedure at a
time as long as each procedure is terminated by end.
Exiting the editor using Brk, Logo does not read any lines in the edit buffer. If you were defining a procedure, the definition will be the same before you started editing.
edit (ed)
edit name
edit namelist
ed name
ed namelist
(edit)
(ed)
command
Starts the Pico Logo Editor. Starts the Logo Editor with the procedure named name (or procedures in the list namelist) and their definitions in it. This is the same output as pops.
If edit does not have an input the current contents of the buffer are used.
Example:
?to rink pr [Zamboni break] end
?edit "rink
; Opens the editor with the rink procedure
edall
edall
command
Starts the Pico Logo Editor with all procedures and variables. Procedures are formatted using to/end syntax, variables as make commands, and property lists as pprop commands. This is the same output as poall. The format ensures that when you exit the editor, all definitions can be re-executed to recreate the workspace state.
Example:
?make "snack "butter\ tart
?to pack pr [Packed:] pr :snack end
?edall
; Opens the editor with all procedures and variables
edn
edn name
edn namelist
command
Stands for edit name (name must be quoted). Starts the Logo Editor with the variable named name (or variables in the list namelist) and their values in it. This is the same output as pon. When you exit the editor the make are run, so whatever variables and values have been changed in the editor are changed in Logo.
Example:
?make "snack "ketchup\ chips
?edn "snack
; Opens the editor with: make "snack "ketchup\ chips
edns
edns
command
Stands for edit names. Starts the Logo Editor with all the names and their values in it. This is the same output as pons. When you exit the editor the make are run, so whatever variables and values have been changed in the editor are changed in Logo.
Example:
?make "snack "ketchup\ chips
?make "temp -17
?edns
; Opens the editor with all variables
to
to name input1 input2 ...
command
to tells Logo you are defining a procedure called name with the inputs (if any) as indicated. From top level, the prompt character changes from ? to > to remind you that you are defining a procedure. While you are defining a procedure, Logo does not carry out the instructions.
You need not put a quotation mark before name because TO puts one there automatically.
To complete the procedure and return Logo to top level, type the word end as the last word of the procedure. The special
word end must be the last word on its line; it is usually on a line of its own, but a short procedure may be written
entirely on one line, as in to rink pr [Zamboni break] end.
If you change your mind while defining a procedure with to,
press Brk to stop the definition.
Example:
?to square :size
>repeat 4 [fd :size rt 90]
>end
end
end
command
end is necessary, when you are using to, to tell Logo that you are done defining a procedure. It must be the last word on its line, so that end inside a list (pr [the end]) or after a quotation mark (pr "end) is an ordinary word. end also must be used to separate procedures when defining multiple procedures in the Logo Editor.
Example:
?to announce :thing
>pr se [Freshly zambonied] :thing
>end
?announce "ice
Freshly zambonied ice
===
Turtle Graphics
Pico Logo has two kinds of screens: the graphics screen and the text screen. The commands fullscreen, splitscreen, and textscreen allow you to switch between the two kinds of screens, and the F1, F2, and F3 keys do the same from the keyboard. Only those commands and keys change which screen you see: drawing while the text screen is up is not an error, and it does not switch screens. The turtle goes on drawing on the graphics screen, and your picture is waiting for you the next time you look at it.
The screen limits are 320 turtle steps high and 320 steps wide. Hence, when using Cartesian coordinates (as in setpos), you reach the edge of the screen when the y-coordinate is 160 (top) or -159 (bottom) and the x-coordinate is -159 (left edge) or 160 (right edge).
back (bk)
back distance
bk distance
command
The back command moves the turtle distance steps back. Its heading does not change. If the pen is down, Logo draws a line the specified distance.
Example:
?bk 50
clearscreen (cs)
clearscreen
cs
command
clearscreen erases the graphics screen, puts the turtle in the center of the screen, and sets the turtle's heading too (north). The center of the screen is position [0 0] and is called the home position.
Example:
?cs
forward (fd)
forward distance
fd distance
command
forward moves the turtle forward distance steps in the direction in which it is heading. If the pen is down, Logo draws a line the specified distance.
Example:
; Draw a maple-leaf stem
?fd 100
getsh
getsh shapenumber
operation
Outputs a list of 16 numbers representing the turtle shape shapenumber (an integer between 1 and 15). Note that shape number cannot be 0. Each shape consists of 8 columns by 16 rows. Each element in the list is the sum of the bit values for a row in the shape.
The first element of the list is the first row of the shape. If the whole row is filled in, the number is 255. If the row is empty, the number is 0. If only the right-most position is filled, the number is 1. If only the fifth position is filled, the number is 16.
>getsh 3
24 60 126 90 90 90 126 231 189 189 165 36 36 36 102 0
hideturtle (ht)
hideturtle
ht
command
hideturtle makes the turtle invisible. (The turtle draws faster when it is hidden.)
Example:
?ht
?repeat 4 [fd 50 rt 90]
home
home
command
The home command moves the turtle to the center of the screen and sets its heading to 0. If the pen is down, Logo draws a line to the new position. The home command is equivalent to
setpos [0 0]
setheading 0
left (lt)
left degrees
lt degrees
command
The left command turns the turtle left (counterclockwise) the specified number of degrees. The number of degrees must not be greater than approximately 3.4e38, the maximum value for a (32-bit) IEEE 754 floating point number.
Example:
; Turn to face west
?lt 90
putsh
putsh shapenumber shapespec
command
Gives shapenumber the specified shapespec as its shape. The output of getsh can be the input of putsh. shapenumber is in the range of 1 to 15. Shape 0 cannot be changed. putsh defines the slot's bitmap shape, and removes any full-colour picture captured into the slot with snapsh.
>putsh 1 [8 28 28 8 93 127 62 127 127 127 127 127 62 62 93 65]
>setsh 1
See getsh to learn about shapespec.
right (rt)
right degrees
rt degrees
command
The right command turns the turtle right (clockwise) the specified number of degrees. The number of degrees must not be greater than than approximately 3.4e38, the maximum value for a (32-bit) IEEE 754 floating point number.
Example:
; Draw an equilateral triangle
?repeat 3 [fd 80 rt 120]
setheading (seth)
setheading degrees
seth degrees
command
setheading turns the turtle so that it is heading in the direction degrees, which can be any decimal number less than than approximately 3.4e38, the maximum value for a (32-bit) IEEE 754 floating point number. Positive numbers are clockwise from north, negative numbers are counterclockwise from north. Note that right and left do relative motion, but setheading does absolute motion.
Example:
; Face west (towards British Columbia from Ontario)
?seth 270
?fd 100
setpos
setpos [xcor ycor] (setpos xcor ycor)
command
The setpos (for set position) command moves the turtle to the indicated coordinates. If the pen is down, Logo draws a line to the new position.
Example:
; Move to the top of the screen (representing north)
?pu
?setpos [0 100]
?pd
setsh
setsh shapenumber
command
Stands for set shape. Sets the shape of each turtle you are talking to. shapenumber 0 is the line-drawn turtle; slots 1 to 15 hold shapes you define - either a bitmap from putsh or a full-colour picture captured with snapsh; setsh wears whichever the slot holds. Shapes 1 through 15 are blank when Logo starts.
Whatever the slot holds, the shape is centred on the turtle's position, and setrot does not change that. Two turtles at the same position line up whichever rotation styles they wear.
Example:
?setsh 1
setx
setx xcor
command
setx moves the turtle horizontally to a point with x-coordinate xcor. The y-coordinate is unchanged. If the pen is down, Logo draws a line to the new position.
Example:
; Draw a horizontal line across the centre of the screen
?setpos [-159 0]
?pd
?setx 160
sety
sety ycor
command
sety moves the turtle vertically to a point with y-coordinate ycor. The x-coordinate is unchanged. If the pen is down, Logo draws a line to the new position.
Example:
; Draw a vertical line (like a flagpole)
?setpos [0 -100]
?pd
?sety 100
shape
shape
operation
Output the shape number of the current turtle. The normal turtle shape is 0.
Example:
?pr shape
0
showturtle (st)
showturtle
st
command
showturtle makes the turtle visible. See hideturtle.
Example:
?ht
?repeat 4 [fd 50 rt 90]
?st
heading
heading
operation
heading outputs the turtle's heading, a decimal number greater than or equal to 0 and less than 360. Logo follows the compass system where north is a heading of 0 degrees, east 90, south 180, and west 270. When you start up Logo, the turtle has a heading of 0 (straight up).
Example:
?seth 90
?pr heading
90
pos
pos
operation
pos (for position) outputs the coordinates of the current position of the turtle in the form of a list [xcor ycor]. When you start up Logo, the turtle is at [0 0], the centre of the turtle field.
Example:
?setpos [50 80]
?show pos
[50 80]
shown? (shownp)
shown?
shownp
operation
shown? outputs true if the turtle is not hidden, false otherwise.
Example:
?pr shown?
true
?ht
?pr shown?
false
towards
towards [xcor ycor]
operation
towards outputs a heading that would make the turtle face in the direction indicated by [xcor ycor].
Example:
; What heading points from home toward the west coast ferry?
?home
?pr towards [-100 0]
270
xcor
xcor
operation
xcor outputs the x-coordinate of the current position of the turtle.
Example:
?setpos [45 80]
?pr xcor
45
ycor
ycor
operation
ycor outputs the y-coordinate of the current position of the turtle.
Example:
?setpos [45 80]
?pr ycor
80
arc
arc angle radius
command
The arc command draws an arc of a circle centred on the turtle, with the given radius. The arc starts at the turtle's heading and extends clockwise through angle degrees (counterclockwise if angle is negative). The turtle itself does not move.
The arc is drawn with the current pen state and colour: with the pen up nothing is drawn, and penerase and penreverse work as they do for forward. An angle beyond 360 draws one full circle. In fence mode, an arc that would cross the edge of the screen draws up to the boundary and then reports "Turtle out of bounds".
Example:
; Draw a face: head, two eyes, and a smile
?arc 360 80
?pu setpos [-30 30] pd arc 360 8
?pu setpos [30 30] pd arc 360 8
?pu setpos [0 10] pd seth 90 arc 180 40
clean
clean
operation
The clean command erases the graphics screen but doesn't affect the turtle.
Example:
?repeat 4 [fd 60 rt 90]
?clean
dot
dot [xcor ycor]
command
The dot command puts a dot of the current pen colour at the specified coordinates, without moving the turtle. It does not draw a line, even if the pen is down.
Example:
; Mark the centre of the screen (home position)
?dot [0 0]
fence
fence
command
The fence command fences in the turtle within the edges of the screen. If you try to move the turtle beyond the edges of the screen, an error, "Turtle out of bounds" occurs and the turtle does not move. If the turtle is already out of bounds, Logo repositions it at its home position [0 0].
Example:
?fence
?fd 1000
Turtle out of bounds
fill
fill
command
The fill command fills the shape outlined by the current pen colour with the current pen colour. If the turtle is not enclosed, the background is filled with the current pen colour. Logo ignores lines of colours other than the current pen colour when determining what to fill.
Example:
; Draw and fill a square (like a red maple leaf background)
?setpc 4
?repeat 4 [fd 60 rt 90]
?fill
pendown (pd)
pendown
pd
command
The pendown command puts the turtle's pen down. When the turtle moves, it draws lines in the current pen colour. When you start up Logo, the pen is down.
Example:
?pu
?setpos [0 0]
?pd
?fd 80
penerase (pe)
penerase
pe
command
penerase puts the turtle's eraser down. When the turtle moves, it erases lines it passes over. To take away the eraser, use either pendown or penup.
Example:
; Draw then erase part of a line
?fd 80
?pe
?bk 40
?pd
penreverse (px)
penreverse
px
command
penreverse puts the reversing pen down. When the turtle moves, it tries to interchange the pen colour and background colour, drawing where there aren't lines and erasing where there are. The exact effect of this reversal is complex; what it looks like on the screen depends on the pen colour, background colour, and whether lines are horizontal or vertical. The best results are on a black background.
Example:
?px
?repeat 4 [fd 60 rt 90]
?pd
penup (pu)
penup
pu
command
The penup command lifts the pen up: when the turtle moves, it does not draw lines. The turtle cannot draw until the pen is put down again.
Example:
; Reposition turtle without drawing
?pu
?setpos [50 50]
?pd
setbg (setbackground)
setbg colournumber
setbackground colournumber
command
The setbg (for set background) command sets the background colour to the colour represented by colournumber, where colournumber is a value between 0 and 254. The backgound colour is used for the background of the full graphics screen and not for the text screen. To set the background colour for text see settextcolor.
The background colour number is 255. The default background colour number is 0.
See Colours for the default palette.
Example:
; Set a red background for the stop sign you nearly missed
?setbg 4
setpc (setpencolor)
setpc colournumber
command
The setpc (for set pencolor) command sets the color of the pen to colourumber, where colournumber is a value between 0 and 255.
See Colours for the default palette.
Example:
; Draw in red (maple leaf red)
?setpc 4
?repeat 4 [fd 60 rt 90]
setpensize
setpensize size
command
The setpensize command sets the width of the pen, in pixels, where size is a whole number of 1 or more. The value is rounded to the nearest whole number and clamped to a maximum of 32. When you start up Logo, the pen size is 1.
A pen wider than one pixel draws by stamping a filled disc at each point along the line, so lines have the same apparent width at every angle and round ends. The reversing pen (penreverse) always draws one pixel wide, regardless of the pen size.
Example:
; Draw a thick square
?setpensize 5
?repeat 4 [fd 60 rt 90]
settextcolor (settc)
settextcolor [foreground background]
settc [foreground background]
command
The settextcolor command sets the foreground and background colours for text. The input is a list of two colour numbers, where each colour number is a value between 0 and 15.
See Colours for the default palette.
Example:
; White text on red background
?settc [15 4]
?pr [Depot open at dawn]
setpalette
setpalette colournumber list
command
setpalette sets the actual colour corresponding to a given colournumber and colournumber must be an integer greater than or equal to 0. The second input is a list of three nonnegative numbers less than 256 specifying the saturation of red, green, and blue in the desired colour.
See Colours for the default palette.
Example:
; Define colour 16 as maple-leaf red
?setpalette 16 [196 30 58]
?setpc 16
palette
palette colournumber
operation
palette outputs a list of three nonnegative numbers less than 256 specifying the saturation of red, green, and blue in the colour associated with the given colour number.
Colour numbers 254 and 255 are the foreground text and background colours.
Example:
?show palette 4
[170 0 0]
restorepalette
restorepalette
command
Restores the palette's default colours. This command only restores colour numbers 0 through 127.
Example:
?setpalette 4 [255 0 0]
?restorepalette
window
window
command
The window command makes the turtle field unbounded; what you see is a portion of the turtle field as if looking through a small window around the centre of the screen. When the turtle moves beyond the visible bounds of the screen, it continues to move but can't be seen: The screen is 320 turtle steps high and 320 steps wide. The entire turtle field is 32,768 steps high and 32,768 steps wide.
Changing window to fence or wrap when the turtle is off the screen sends the turtle to its home position [0 0].
Example:
; Allow the turtle to wander off screen
?window
?fd 500
wrap
wrap
command
The wrap command makes the turtle field wrap around the edges of the screen: if the turtle moves beyond one edge of the screen, it continues from the opposite edge. The turtle never leaves the visible bounds of the screen; when it tries to, it wraps around to the other side.
Example:
; The turtle wraps around from right to left edge
?wrap
?fd 1000
background (bg)
background
bg
operation
background outputs a number representing the colour of the background and is a value between 0 and 255.
See Colours for the default palette.
Example:
?setbg 4
?pr background
4
dot? (dotp)
dot? [xcor ycor]
dotp [xcor ycor]
operation
The dot? operation outputs true if there is a dot on the screen at the indicated coordinates. If there is no dot, dot? outputs false.
Example:
?dot [0 0]
?pr dot? [0 0]
true
pen
pen
operation
pen outputs the current state of the turtle's pen. The states are pendown, penerase, penup, and penreverse. When the turtle first starts up, pen outputs pendown.
Example:
?pr pen
pendown
?pu
?pr pen
penup
pencolor (pc)
pencolor
pc
operation
pencolor outputs a number representing the current colour of the pen.
See Colours for the default palette.
Example:
?setpc 4
?pr pencolor
4
pensize
pensize
operation
pensize outputs a number representing the current width of the pen, in pixels. When the turtle first starts up, pensize outputs 1.
Example:
?setpensize 5
?pr pensize
5
textcolor (tc)
textcolor
tc
operation
textcolor outputs a list of two colour numbers representing the foreground and background colours for text. Each colour number is a value between 0 and 15.
See Colours for the default palette.
Example:
?settc [15 4]
?show textcolor
[15 4]
setmag
setmag magnification
command
Stands for set magnification. setmag 2 draws the turtle you are talking to at double size; setmag 1 returns it to normal. Magnification applies to the turtle's appearance on screen - the line-drawn turtle, bitmap shapes, and captured colour shapes alike - and to stamp. It does not change how far the turtle moves. The drawn turtle is limited to 32 by 32 pixels, so shapes larger than 16 by 16 always appear at normal size.
Example:
?tell 1 st setmag 2 ; turtle 1 appears double size
setrot
setrot style
command
Stands for set rotation style. Chooses how the turtle's shape follows its heading. The style is one of three words:
"fixed- the shape never rotates (how shapes behaved on period machines; the default)."full- the shape rotates smoothly to point along the heading."flip- the shape mirrors left or right depending on which way the turtle faces; most game characters are drawn side-on, and this makes them walk both directions with one picture.
The rotation style applies to bitmap and captured colour shapes; shape 0, the line-drawn turtle, always rotates. Shapes larger than about 22 pixels may lose their corners at diagonal headings with "full, since the drawn turtle is limited to 32 by 32 pixels.
Example:
?setsh 1 setrot "flip
?seth 90 fd 40 ; facing east: shape as drawn
?seth 270 fd 40 ; facing west: shape mirrored
snapsh
snapsh shapenumber width height
command
Stands for snap shape. snapsh captures the rectangle of the graphics screen centred on the turtle - width by height pixels, each from 8 to 32 - and stores it as a full-colour shape in slot shapenumber (1 to 15). Background pixels become transparent, so the captured image keeps its outline when worn as a shape or placed with stamp. Draw a picture with the pen you already know, pick it up with snapsh, and wear it with setsh.
A full-colour shape replaces the slot's putsh bitmap on screen until you define a new bitmap with putsh, which removes the captured image. When you are talking to several turtles, snapsh captures around the lowest-numbered one. Colour shapes are stored in a fixed memory pool; if the pool is full, Logo says it is out of space.
Example:
?repeat 4 [fd 12 rt 90] ; draw a small box
?fill
?snapsh 1 16 16 ; capture it as shape 1
?cs setsh 1 ; wear it
stamp
stamp
command
stamp copies the turtle's current shape into the picture at the turtle's position, exactly as it appears on screen. The turtle does not move, and the stamped image becomes part of the drawing - it stays when the turtle walks away, and savepic saves it. Use it for scenery, repeated decorations, or particle trails. Each turtle you are talking to stamps its own shape.
Example:
?setsh 1
?repeat 6 [stamp fd 30] ; a trail of shape 1
write
write object
command
write draws object as text on the graphics screen at the turtle's position, in the current pen colour. The text is always upright and reads left to right: it begins at the turtle's x and is centred vertically on the turtle's y, so the turtle sits at the middle of the first letter's left edge. The turtle does not move and its heading is ignored. The letters become part of the drawing: they stay when the turtle walks away, and savepic saves them. object is written the same way print writes it, so a list loses its outer brackets and numbers appear in their usual form. Each turtle you are talking to writes at its own position.
Example:
?setpc 2
?write [Score: 100] ; label the picture
?pu setxy 0 60 pd
?write count [a b c] ; writes 3
tell
tell turtlenumber
tell turtlenumberlist
command
Pico Logo has eight turtles, numbered 0 to 7. tell chooses which of them your commands talk to. After tell 3, turtle commands such as fd and rt move turtle 3; after tell [0 1 2], each command applies to turtles 0, 1, and 2 in that order. Operations such as pos and heading answer for the lowest-numbered turtle you are talking to. Duplicate numbers are ignored, and a number outside 0 to 7 causes an error.
When Logo starts, and after clearscreen, you are talking to turtle 0 only - programs written for one turtle work unchanged. Turtles 1 to 7 start hidden at the home position; use showturtle to reveal them. When turtles overlap on the screen, the lower-numbered turtle appears on top.
Because tell accepts a list, you can name a group with a variable: make "flock [1 2 3] then tell :flock.
Example:
?tell [0 1]
?setsh 0
?st
?fd 40 ; both turtles move
?tell 1
?rt 90 ; only turtle 1 turns
ask
ask turtlenumber commandlist
ask turtlenumberlist commandlist
command or operation
ask runs commandlist with your commands temporarily redirected to the named turtle or turtles, then goes back to talking to the turtles you had before - even if the list stops with an error. It is the quick way to give one turtle an instruction without changing who you are talking to. Like run, if commandlist is an operation, ask outputs whatever it outputs - handy for reading one turtle's state (ask 2 [xcor]) without changing who you are talking to.
Example:
?tell [0 1 2]
?ask 1 [fd 20] ; only turtle 1 moves
?fd 10 ; turtles 0, 1 and 2 move
?pr ask 1 [xcor] ; read turtle 1's x without retelling
20
each
each commandlist
command
each runs commandlist once for every turtle you are talking to, in ascending order, talking to just that one turtle each time. Inside the list, who is the current turtle's number, so each turtle can behave differently.
Example:
?tell [0 1 2 3]
?each [seth who * 90 fd 50] ; four turtles walk in four directions
who
who
operation
who outputs the turtle number you are talking to, or a list of numbers when you are talking to more than one turtle. Inside each, who is always the single turtle currently being addressed.
Example:
?tell [2 5]
?show who
[2 5]
?each [pr who]
2
5
touching? (touchingp)
touching? turtlenumber turtlenumber
operation
touching? outputs true when the two named turtles overlap on the screen and false otherwise. The test is exact to the pixel: it compares the turtles' rendered shapes - including any rotation and magnification - not just the squares that hold them, so two turtles report a touch only when their actual glyphs meet. Both turtles must be shown; a hidden turtle never touches anything. In wrap mode a turtle that straddles an edge is tested on both sides, so contact across the screen edge counts.
Example:
?tell [0 1]
?st
?ask 1 [setpos [10 0]]
?if touching? 0 1 [pr [crash!]]
over? (overp)
over? colour
operation
over? outputs true when any part of the turtle's shape lies over a canvas pixel drawn in palette slot colour, and false otherwise. It senses the drawing - lines, dots, fills and stamp marks - not other turtles, which are never part of the canvas. When you are talking to more than one turtle, over? answers for the lowest-numbered one; address a specific turtle with ask. Unlike touching?, over? reports for a hidden turtle too.
Example:
?setpc 12 fd 50 bk 50 ; draw a line in colour 12
?if over? 12 [pr [on the wall]]
colourunder (colorunder)
colourunder
operation
colourunder outputs the palette slot of the canvas pixel directly beneath the turtle's position. Like over? it sees only the drawing, never other turtles, and answers for the lowest-numbered turtle you are talking to. Where nothing has been drawn it outputs the background slot.
Example:
?setpc 9 fill ; flood the area under the turtle
?pr colourunder
9
distance
distance turtlenumber
operation
distance outputs the straight-line distance, in turtle steps, from the turtle you are talking to (the lowest-numbered one) to the turtle named turtlenumber. It complements towards, which gives the heading between points.
Example:
?tell [0 1]
?ask 1 [setpos [30 40]]
?pr distance 1
50
setspeed
setspeed speed
command
setspeed sets how fast each turtle you are talking to moves on its own, in turtle steps per second. Once a turtle has a speed it glides forward along its heading all by itself - drawing with its pen and obeying wrap, window and fence exactly as forward would - while your program does other things or waits at the prompt. A speed of 0 stops the turtle. Autonomous motion is paused by freeze and cleared by clearscreen.
Example:
?setspeed 30 ; glide forward 30 steps every second
?seth 90 ; head east; it keeps moving as you type
speed
speed
operation
speed outputs the autonomous speed, in turtle steps per second, of the turtle you are talking to (the lowest-numbered one). It outputs 0 when the turtle is not moving on its own.
Example:
?setspeed 45
?pr speed
45
setanim
setanim first last interval
command
setanim animates each turtle you are talking to by cycling its shape from first through last (shape numbers 0 to 15), advancing to the next frame every interval milliseconds and looping back to first after last. The frames flip on their own during a program and at the prompt, just like autonomous motion. An interval of 0 stops the animation and leaves the current shape in place. Animation is paused by freeze and cleared by clearscreen.
Example:
?setanim 1 4 100 ; walk cycle: shapes 1..4, 100 ms per frame
?setspeed 20 ; stroll across the screen, legs moving
when
when condition action
command
when arms a demon: a rule that runs action the moment condition becomes true. condition and action are both instruction lists. The condition is checked continually - while your program runs and while you type at the prompt - and its action fires once each time the condition changes from false to true (so a collision fires once on contact, not over and over while the turtles stay touching). Give the same condition an empty action list to disarm that demon; the bare form (when) prints the demons currently armed. Up to eight demons can be armed at once. Demons are paused by freeze, resumed by thaw, and all cleared by cleardemons or when a program stops with an error. clearscreen does not touch them: clearing the screen is a drawing matter, and your demons keep watching.
Example:
?when [touching? 0 1] [pr [crash!] setspeed 0]
?when [over? 12] [seth heading + 90]
?when [key?] [] ; disarm the key demon
cleardemons
cleardemons
command
cleardemons disarms every when demon at once: nothing is watching afterwards. It touches nothing else - the screen is not cleared, turtles gliding under setspeed or animating under setanim carry on, a freeze stays in force until thaw, and an HTTP server keeps listening (though with its serving demon gone, close it with http.unlisten unless you arm another handler). To disarm a single demon, give its condition an empty action list with when.
Example:
?cleardemons ; nothing is watching now
freeze
freeze
command
freeze suspends all autonomous activity at once: when demons stop firing and turtles given a setspeed or setanim hold their position and frame. Use it to pause a game. Resume everything exactly where it left off with thaw.
Example:
?freeze ; the action holds still
?thaw ; and carries on
thaw
thaw
command
thaw resumes the autonomous activity suspended by freeze: when demons are checked again and moving or animating turtles carry on from where they stopped. thaw when nothing is frozen does nothing.
Example:
?freeze
?thaw
===
Tile Maps
A tile is a small square picture - 8 by 8 or 16 by 16 pixels - that you draw once with the pen and then pick up off the screen, the way snapsh picks up a shape. A map is a grid of numbers saying which tile goes in each square of a world. Together they let you build a board far bigger than anything you would want to draw square by square: a maze, a race track, a dungeon floor.
Tiles are cheap in two ways. The bank keeps one copy of each tile no matter how often the map uses it, and the map itself costs one byte per square, so a 64 by 64 world is 4096 bytes - where the same world as a list of lists would use up most of your workspace. And because tile reads a square directly, the map is not just a picture: it is the thing your program asks "what is here?", instead of keeping a second copy of the world in a list.
Building a tile board goes like this:
newtileschooses the tile size and empties the bank.- Draw each tile with the pen and pick it up with
snaptile. newmapmakes the world, andsettilefills in the squares.stampmappaints the whole map onto the graphics screen at once.
After stampmap the board is an ordinary drawing: the turtle's pen draws over it, dot? sees it, and savepic saves it. When one square changes - a treasure is collected, a door opens - change the square with settile and repaint just that square with stamptile.
How big a bank and a map can be depends on your board. On a Pico 2 or Pico 2 W the bank holds 4096 bytes of tiles (63 tiles of 8 by 8, or 15 of 16 by 16) and a map holds 4096 squares - a 64 by 64 world. On a Pimoroni Pico Plus 2 W, which has PSRAM, the bank holds 255 tiles of either size and a map holds 262144 squares - a 512 by 512 world. Asking for more than that says you are out of space. The bank and the map survive clearscreen and an error, so clearing the screen never throws away a world you are in the middle of building.
newtiles
newtiles size
command
newtiles empties the tile bank and says how big its tiles are. size must be 8 or 16, and every tile in the bank is that many pixels square. Use 8 for fine detail such as a maze of narrow corridors, and 16 for chunky scenery such as a road with cars on it.
You can call newtiles again at any time to start over with a different size; the whole bank is emptied, and the map (if you have one) keeps its numbers but now describes squares of the new size. The number of tiles the bank holds depends on the size and on your board: with 8 by 8 tiles a Pico 2 holds 63 of them, and with 16 by 16 tiles it holds 15. A Pimoroni Pico Plus 2 W holds 255 of either.
Example:
?newtiles 8 ; a bank of 8 by 8 tiles
snaptile
snaptile tilenumber
command
Stands for snap tile. snaptile captures the square of the graphics screen centred on the turtle - as many pixels across as newtiles chose - and stores it in the bank as tile tilenumber. Tile numbers start at 1; the largest one depends on your board and the tile size.
Unlike snapsh, nothing becomes transparent: a tile is background, so every pixel is kept exactly as it is on the screen, including the background colour. Draw your tile with the pen, snap it, clear the screen, and draw the next one. When you are talking to several turtles, snaptile captures around the lowest-numbered one.
Tile 0 is not a tile you can capture. It means "nothing here" in a map, and is painted in the background colour.
Example:
?newtiles 8
?repeat 4 [fd 8 rt 90] ; a small box
?fill
?snaptile 1 ; keep it as tile 1
newmap
newmap columns rows
command
newmap makes a new world columns squares across and rows squares down, with every square set to 0 (nothing). Both numbers must be at least 1, and the number of squares - columns times rows - must fit in your board's map: 4096 squares on a Pico 2 or Pico 2 W, 262144 on a Pimoroni Pico Plus 2 W. A bigger map than that says you are out of space.
The map is a grid of squares, not of pixels. How big it is on the screen depends on the tile size: a 28 by 36 map of 8 by 8 tiles covers 224 by 288 pixels.
Example:
?newmap 28 36 ; a world of 28 x 36 squares
settile
settile column row tilenumber
command
settile puts a tile number into one square of the map. column and row start at 1, like the positions item counts, with column 1 row 1 at the top left. tilenumber is 0 to 255: 0 means "nothing here" and is painted in the background colour, and any other number names a tile in the bank. A number naming a tile you never captured is also painted as background, so you can fill a map in before you finish drawing its tiles.
Changing a square does not change the screen. Repaint it with stamptile, or repaint the whole board with stampmap.
Example:
?settile 3 4 1 ; square (3,4) shows tile 1
?stamptile 3 4 ; and show it now
tile
tile column row
operation
tile outputs the tile number in one square of the map - the number settile put there, or 0 for an empty square. column and row start at 1.
This is how a program asks the world a question. Because the answer comes straight out of the map, it is just as fast in a 512 by 512 world as in a tiny one, and it is always the same world your board was painted from - there is no second copy to keep in step.
Example:
to walkable? :col :row
op (tile :col :row) = 0 ; empty squares can be walked on
end
stampmap
stampmap
command
stampmap paints the whole map onto the graphics screen: every square of the world is drawn with the tile it names, and empty squares are painted in the background colour. It is the fast way to lay down a board - what would be hundreds of Logo commands is one command here.
What stampmap leaves behind is an ordinary drawing. The pen draws over it, dot? sees it, savepic saves it, and clearscreen wipes it (the map itself is not touched, so you can stampmap it again). If you have no map or no tiles yet, stampmap does nothing.
Example:
?stampmap ; paint the board
stamptile
stamptile column row
command
stamptile repaints one square of the map onto the graphics screen, where stampmap would have put it. It is the repair command: when a square changes during a game - a treasure taken, a wall knocked down, a door opened - change it with settile and then repaint just that square, instead of the whole board.
column and row start at 1. Anything the pen drew over that square is covered up.
Example:
?settile 3 4 0 ; the treasure is collected
?stamptile 3 4 ; wipe it off the board
===
Text and Screen Commands
Your PicoCalc has 32 lines of text on the screen, with 40 characters on each line. You can use the screen entirely for text or entirely for graphics. The PicoCalc also lets you use the top 24 lines (240 turtle units) for graphics and the bottom eight for text at the same time. When you start up Logo, the entire screen is available for text.
There are two ways to change the use of your screen:
- With regular Logo commands, which you can type at top level or insert within procedures (
fullscreen,splitscreen, andtextscreen) - With special control characters, which are read from the keyboard and obeyed almost immediately (while a procedure continues running); these cannot be placed within procedures (
F1–textscreen,F2–splitscreen, andF3–fullscreen).
You always can use the entire text screen and the entire graphics screen at the same time, but you cannot display both at the same time. When you use the fullscreen command, the text screen is still there, but you can't see it until you use textscreen or splitscreen. When you use textscreen, the graphics screen is still there, but you can't see it until you use fullscreen or splitscreen. When you use splitscreen, both screens are still there, but you can only see the top 24 lines of the graphics screen (240 turtle units) and the bottom eight lines of the text screen.
cleartext (ct)
cleartext
ct
command
cleartext clears the entire screen and puts the cursor at the upper-left corner of the text part of the screen. If you have been using the split screen, the cursor is on the eighth line from the bottom.
Example:
?pr [Snow route starts at midnight]
?ct
cursor
cursor
operation
cursor outputs a list of the column and line numbers of the cursor position. The upper-left corner of the screen is [0 0]. The upper-right is [39 0].
See setcursor.
Example:
?setcursor [10 5]
?show cursor
[10 5]
fullscreen (fs)
fullscreen
fs
command
The fullscreen command devotes the entire screen to graphics. Only the turtle field shows; any text you type will be invisible to you, although Logo will still carry out your instructions.
If Logo needs to display an error message while you are using the full graphics screen, Logo splits the screen.
Example:
?fs
?repeat 4 [fd 80 rt 90]
?ts
refresh
refresh
command
refresh presents any pending graphics drawing on the display immediately. Use it in manual refresh mode (see setrefresh) to control exactly when each frame appears - for example, once per pass around a game loop, after all the drawing for that frame is done.
refresh works in either refresh mode and does not change the mode. In automatic mode it is rarely needed, since drawing is presented as it happens.
Example:
?setrefresh "manual
?repeat 100 [fd 2 rt 3.6 refresh]
?setrefresh "auto
refreshmode
refreshmode
operation
refreshmode outputs the word auto, manual or sync, naming the current display refresh policy (see setrefresh).
Example:
?print refreshmode
auto
setcursor
setcursor [columnnumber linenumber]
command
setcursor sets the cursor to the position indicated by columnnumber and linenumber. Lines on the screen are numbered from 0 to 31. Character positions (columns) are numbered from 0 to 39.
Example:
; Position the cursor near the centre of the screen
?setcursor [20 15]
?type "Curling
setrefresh
setrefresh "auto
setrefresh "manual
setrefresh "sync
(setrefresh "sync rate)
command
setrefresh selects how graphics drawing reaches the display.
In auto mode (the default), Logo presents drawing on the display as it happens. In manual mode, drawing accumulates off-screen and nothing appears until you say refresh - useful for building a complex picture that should appear all at once, or for pacing the frames of a game or animation yourself.
sync mode is manual with an even cadence built in for games and animation. Drawing still accumulates off-screen, but each pass of your loop ends with sync instead of refresh: sync presents the frame and then waits until the next frame boundary, so the loop runs at a steady rate (frames per second) no matter how much work any one frame did. Without a rate the default is 30; supply your own with the parenthesised form, for example (setrefresh "sync 25). Pacing to a fixed boundary - rather than sleeping a fixed amount after each frame with wait - is what keeps motion smooth, the way a game locked to the television's vertical blank did.
So that a program cannot leave the screen out of date (or the prompt paced) after it stops, Logo restores auto mode when an error stops your program, when it runs throw "toplevel, or when you clear the screen with cs.
Example:
; Draw a complex scene off-screen, then show it all at once
?setrefresh "manual
?repeat 36 [repeat 8 [fd 40 rt 45] rt 10]
?refresh
?setrefresh "auto
; Run a game loop at a steady 30 frames per second
?setrefresh "sync
?until [key?] [update.world draw.world sync]
?setrefresh "auto
sync
sync
command
sync presents any pending graphics drawing on the display (exactly like refresh) and then, in sync refresh mode, waits until the next frame boundary so your loop keeps the steady rate set with setrefresh "sync. Call it once per pass around a game or animation loop, after all the drawing for that frame is done.
Because sync waits for a boundary measured from a fixed cadence - not for a fixed delay after variable work, as wait would - the loop advances at an even rate even when some frames do more work than others, so motion stays smooth. If a frame overruns its budget sync does not wait and does not try to catch up; the loop simply runs late from there.
Outside sync mode (or on a device with no clock) sync just presents the frame and returns at once, so it is a safe drop-in for refresh.
Example:
?setrefresh "sync ; 30 frames per second
?until [key?] [
? ask 0 [fd 3]
? sync
?]
?setrefresh "auto
splitscreen (ss)
splitscreen
ss
command
splitscreen devotes the top 24 lines of the screen to graphics and the bottom eight lines to text.
Example:
?ss
?repeat 4 [fd 80 rt 90]
textscreen (ts)
textscreen
ts
command
textscreen devotes the entire screen to text; the graphics screen is invisible to you until you use splitscreen or fullscreen. A turtle command given while the text screen is up still draws, but it does not bring the graphics screen back.
Example:
?fs
?repeat 4 [fd 80 rt 90]
?ts
?pr [Back to text mode]
===
Words and Lists
This section describes the primitives that work on two types of objects in Logo: words and lists. With the primitives described in this section, you can
- break words and lists into pieces
- put words and lists together
- examine words and lists
- change the case of words and lists.
butfirst (bf)
butfirst object
bf object
operation
butfirst outputs all but the first element of object. butfirst of the empty word or the empty list is an error.
Examples:
?pr butfirst "hello
ello
?show butfirst [a b c d]
[b c d]
butlast (bl)
butlast object
bl object
operation
butlast outputs all but the last element of object.
Examples:
?pr butlast "windmills
windmill
?show butlast [a b c d]
[a b c]
first
first object
operation
first outputs the first element of object. first of the empty word or the empty list is an error. Note that first of a word is a single character; first of a list can be a word or a list.
Examples:
?pr first "hello
h
?show first [a b c d]
a
replace
replace integer object value
operation
replace returns a new list with the element of object whose position within object corresponds to integer replaced with value. For example, if integer is 3, replace returns a list with the third element in the object replaced with value. Object is a word or a list. An error occurs if integer is greater than the length of object or if object is the empty word or list.
Examples:
?pr replace 2 "dig "u
dug
?show replace 4 [a b c d] "x
[a b c x]
?make "greet "hello
?pr replace 1 :greet uppercase item 1 :greet
Hello
.setfirst
.setfirst list value
command
.setfirst destructively replaces the first member of list with value, changing the list in place instead of returning a new one. List must be a non-empty list. Because lists share structure - butfirst returns the tail of a list without copying it - a cursor obtained with butfirst refers to the same cells as the original, and .setfirst through that cursor is visible in the original. This makes it possible to update one element of a long list without allocating a new list; unlike replace, which builds and returns a fresh list, .setfirst outputs nothing.
The leading dot marks .setfirst as dangerous: overwriting a cell that other structure depends on, or using it to build a circular list, corrupts those references. Prefer replace unless you specifically need in-place mutation.
Examples:
?make "l [a b c]
?.setfirst :l "x
?show :l
[x b c]
?make "flags [1 1 1 1]
?.setfirst (butfirst butfirst :flags) 0
?show :flags
[1 1 0 1]
.setbf
.setbf list value
command
.setbf destructively replaces the butfirst (the tail) of list with value, in place. List must be a non-empty list and value must be a list, since the tail of a list is itself a list. Setting the tail to the empty list truncates list to a single member. Like .setfirst, .setbf outputs nothing and mutates every list that shares the affected cell.
The leading dot marks .setbf as dangerous: pointing the tail back into the same list builds a circular list, which most list operations cannot handle.
Examples:
?make "l [a b c]
?.setbf :l [x y]
?show :l
[a x y]
?.setbf :l []
?show :l
[a]
.setitem
.setitem integer list value
command
.setitem destructively replaces the member of list at position integer (counting from 1) with value, in place - the same result as walking to that member with butfirst and applying .setfirst, but the walk is done for you. An error occurs if integer is less than 1 or greater than the length of list. Unlike replace, which returns a fresh list, .setitem outputs nothing and allocates nothing, so it can update one member of a long list cheaply.
The leading dot marks .setitem as dangerous for the same reason as the other in-place setters: it overwrites a shared cell.
Examples:
?make "l [a b c d]
?.setitem 3 :l "x
?show :l
[a b x d]
item
item integer object
operation
item outputs the element of object whose position within object corresponds to integer. For example, if integer is 3, item outputs the third element in the object. Object is a word or a list. An error occurs if integer is greater than the length of object or if object is the empty word or list.
Examples:
?pr item 4 "windmills
d
?show item 2 [a b c d]
b
last
last object
operation
last outputs the last element of object. last of the empty word or the empty list is an error.
Examples:
?pr last "Maple
e
?show last [a b c d]
d
member
member object1 object2
operation
member outputs the part of object2 in which object1 is the first element. If object1 is not an element of object2, member outputs the empty list or the empty word. This operation is useful for accessing information in a file or for sorting long lists.
Examples:
?show member "b [a b c d]
[b c d]
?pr member "x "example
xample
?show member "x [a b c d]
[]
?pr member ". 3.14159
.14159
pick
pick object
operation
pick outputs a randomly chosen element of object: an element of a list, or a character of a word. An error occurs if object is empty.
Examples:
?pr pick [butter\ tart nanaimo\ bar beavertail]
nanaimo bar
?pr pick "abcdef
d
remdup
remdup object
operation
remdup outputs a copy of object with duplicate members removed: the elements of a list, or the characters of a word. When two or more members are equal, only the last one is kept, so the survivors appear in the order of their final occurrence. As with equal?, words are compared without regard to case.
Examples:
?show remdup [a b a c b]
[a c b]
?pr remdup "mississippi
mspi
remove
remove thing object
operation
remove outputs a copy of object with every member equal to thing removed: the elements of a list, or the characters of a word. Because the members of a word are its characters, thing removes characters only when it is itself a single character. As with equal?, the comparison ignores case.
Examples:
?show remove "b [a b c b d]
[a c d]
?pr remove "l "hello\ world
heo word
reverse
reverse object
operation
reverse outputs object with its elements in the opposite order: the elements of a list, or the characters of a word. Elements that are themselves lists are not reversed internally.
Examples:
?show reverse [a b c d]
[d c b a]
?pr reverse "stressed
desserts
?show reverse [a [b c] d]
[d [b c] a]
shuffle
shuffle object
operation
shuffle outputs object with its elements rearranged in random order: the elements of a list, or the characters of a word. Every element of the input appears exactly once in the output.
Example:
?show shuffle [1 2 3 4 5]
[3 1 5 2 4]
fput
fput object list
operation
The fput (for first put) operation outputs a new list formed by putting object at the beginning of list.
Example:
?show fput "a [b c d]
[a b c d]
list
list object1 object2
(list object1 object2 object3 object4 ...)
operation
The list operation outputs a list whose elements are object1, object2, and so on.
Examples:
?show (list "d "o "g)
[d o g]
? show list "Hello "there
[Hello there]
lput
lput object list
operation
The lput (for last put) operation outputs a new list formed by putting object at the end of list.
Example:
?show lput "d [a b c]
[a b c d]
parse
parse word
operation
parse outputs a list that is obtained from parsing word. parse is useful for converting the output of readword into a list.
Example:
?show parse "a\ b\ c\ d
[a b c d]
When parse tokenizes a word that contains vertical bars (see
Vertical Bars), the bars do not appear in the result but the
characters between them are tokenized as though they were letters. So a word
read by readword that contains |a b| parses into the
single word a b.
sentence (se)
sentence object1 object2
(sentence object1 object2 object3 ...)
se object1 object2
(se object1 object2 object3 ...)
operation
sentence outputs a list made up of the contents in its inputs.
Examples:
?show (sentence "a [b c] "d)
[a b c d]
?show se "hello "world
[hello world]
word
word word1 word2
(word word1 word2 word3 ...)
operation
word outputs a word made up of its inputs.
A word normally holds up to 255 characters. On a board with PSRAM (the
Pimoroni Pico Plus 2 W) word may build a longer result;
on boards without PSRAM a result over 255 characters raises an out-of-space
error rather than being truncated.
Examples:
?pr (word "Hello, char 32 "world!)
Hello, world!
?pr word "123 "456
123456
?pr word 10 0 + 1
101
ascii
ascii character
operation
ascii outputs the American Standard Code for Information Interchange (ASCII) code for character. If the input word contains more than one character, ascii uses only its first character. Also see char.
Examples:
?pr ascii "A
65
?pr ascii "z
122
before? (beforep)
before? word1 word2
beforep word1 word2
operation
before? outputs true if word1 comes before word2. To make the comparison, Logo uses the ASCII codes of the characters in the words. Note that all uppercase letters come before all lowercase letters.
Examples:
?pr before? "Apple "Banana
true
?pr before? "apple "Banana
false
?pr before? "Cat "cat
true
char
char integer
operation
The char operation outputs the character whose ASCII code is integer. An error occurs if integer is not the ASCIl code for any character.
Examples:
?pr char 65
A
?pr char 122
z
count
count object
operation
count outputs the number of elements in object, which is a word or a list.
Examples:
?pr count "hello
5
?pr count [a b c d]
4
empty? (emptyp)
empty? object
emptyp object
operation
empty? outputs true if object is the empty word or the empty list; otherwise it outputs false.
Examples:
?pr empty? "
true
?pr empty? []
true
?pr empty? "abc
false
?pr empty? [a b c]
false
equal? (equalp)
equal? object1 object2
equalp object1 object2
operation
equal? outputs true if object1 and object2 are equal numbers, identical words, or identical lists; otherwise equal? outputs false. This operation is equivalent to the equal sign (=).
Words are compared without regard to case, just as Logo treats names: equal? "Hello "hello outputs true. Lists are compared element by element under the same rule. (To compare words by their exact character codes, use before?, which compares ASCII values.)
Examples:
?pr equal? "hello "hello
true
?pr equal? "Hello "hello
true
?pr equal? [a b c] [a b c]
true
?pr equal? 10 10
true
?pr equal? "hello "world
false
?pr equal? [a b c] [a b d]
false
?pr equal? 10 20
false
list? (listp)
list? object
listp object
operation
list? outputs true if object is a list; otherwise it outputs false.
Examples:
?pr list? [a b c]
true
?pr list? "hello
false
?pr list? 123
false
member? (memberp)
member? object1 object2
memberp object1 object2
operation
member? outputs true if object1 is an element of object2; otherwise it outputs false.
Examples:
?pr member? "b [a b c d]
true
?pr member? "b "example
false
?pr member? ". 3.14159
true
number? (numberp)
number? object
numberp object
operation
number? outputs true if object is a number; otherwise it outputs false.
Examples:
?pr number? 123
true
?pr number? "hello
false
?pr number? [a b c]
false
word? (wordp)
word? object
wordp object
operation
word? outputs true if object is a word; otherwise it outputs false. A self-quoted number is word.
Examples:
?pr word? "hello
true
?pr word? 123
true
?pr word? [a b c]
false
lowercase
lowercase word
operation
lowercase outputs word in all lowercase letters.
Examples:
?pr lowercase "HelloWorld
helloworld
?pr lowercase "AB123
ab123
uppercase
uppercase word
operation
uppercase outputs word in all uppercase letters.
Examples:
?pr uppercase "HelloWorld
HELLOWORLD
?pr uppercase "ab123
AB123
===
Variables
This section gives you some general information about how Logo uses variables and then provides descriptions of the primitives that you use with variables.
local
local name
local list
command
The local command makes its input(s) local to the procedure within which the local occurs. A local variable is accessible only to that procedure and to procedures it calls; in this regard it resembles inputs to the procedure.
Example:
?to greet
>local "snack
>make "snack "butter\ tart
>pr se [Saved for later:] :snack
>end
?greet
Saved for later: butter tart
?pr name? "snack
false
localmake
localmake name object
command
The localmake command makes name local to the procedure within which it occurs and gives it the value object, in one step. It is equivalent to local "name followed by make "name object.
Example:
?to greet
>localmake "snack "butter\ tart
>pr se [Saved for later:] :snack
>end
?greet
Saved for later: butter tart
?pr name? "snack
false
make
make name object
command
The make command puts object in name's container, that is, it gives the variable name the value object.
Example:
?make "team "house\ league
?pr :team
house league
name
name object name
command
The name command puts object in name's container, that is, it gives the variable name the value object.
name is equivalent to make with the order of the inputs reversed. Thus name "welder "job has the same effect as make "job "welder.
Example:
?name "double\ double "order
?pr :order
double double
name? (namep)
name? word
namep word
operation
name? outputs true if word has a value, that is, if :word exists; it outputs false otherwise.
Example:
?make "permit "yes
?pr name? "permit
true
?pr name? "ticket
false
thing
thing name
operation
thing outputs the thing in the container name, that is, the value of the variable name. thing "any is equivalent to :any.
Example:
?make "forecast "flurries
?pr thing "forecast
flurries
?pr :forecast
flurries
===
Arithmetic Operations
This section presents all the Logo operations that manipulate numbers. Logo has two kinds of notation for expressing arithmetic operations: prefix notation and infix notation. Prefix notation means that the name of the procedure comes before its inputs. With infix notation, the name of the procedure goes between its inputs, not before them.
This chapter contains
- a general introduction to Logo's arithmetic operations
- descriptions of the prefix-form operations
- descriptions of the infix-form operations.
abs
abs number
operation
Outputs the absolute number. If number less than zero the negative of number is returned.
Example:
; Absolute value of a wind-chill complaint
?pr abs -40
40
arctan
arctan number
(arctan x y)
operation
With one input, outputs the arctangent of number in degrees.
With two inputs, (arctan x y) outputs the arctangent of y/x in degrees, using the signs of both inputs to place the result in the full range from -180 to 180. Unlike the one-input form, it is defined when x is zero.
Examples:
?pr arctan 1
45
?pr (arctan -1 1)
135
cos
cos number
operation
Outputs the cosine of number in degrees.
Examples:
?pr cos 0
1
?pr cos 60
0.5
difference
difference number1 number2
operation
Outputs number2 subtracted from number1.
Example:
; Difference between two snow-route ticket numbers
?pr difference 705 416
289
exp
exp exponent
operation
Outputs e raised to the power of exponent.
Example:
?pr exp 1
2.71828
form
form number width decimalplaces
operation
form outputs a word representing number formatted to fit in a field of width characters with decimalplaces digits to the right of the decimal point. If decimalplaces is zero, no decimal point is included. The number is rounded to the specified number of decimal places.
If number is negative, the minus sign takes up one position in the field. If number is too large to fit in the specified width, form outputs a string using the minimum length required for number with decimalplaces.
If width is less than or equal to zero, or if decimalplaces is less than zero, an error occurs.
Examples:
; Format the total after a farmers market pierogi run
?pr word "$ form 1234.56 10 2
$ 1234.56
?pr form -17.8 6 1
-17.8
int
int number
operation
Returns the integer part of number; any decimal part is stripped off. No rounding occurs when int is used (contrast this with the round operation described later in this chapter).
Examples:
; Truncate a temperature reading
?pr int -17.8
-17
?pr int 3.9
3
intquotient
intquotient integer1 integer2
operation
intquotient outputs the result of dividing integer1 by integer2, truncated to an integer. An error occurs if integer2 is zero. If either input is a decimal number, it is truncated.
Example:
; How many full four-person curling teams from 18 players?
?pr intquotient 18 4
4
ln
ln number
operation
Outputs natural logarithm of number. An error is returned if number is less than or equal to zero.
Example:
?pr ln 1
0
?pr ln exp 1
1
log
log number
operation
Outputs the base-10 logarithm of number. An error is returned if number is less than or equal to zero.
Example:
?pr log 100
2
?pr log 1000
3
modulo
modulo integer1 integer2
operation
Outputs the remainder of dividing integer1 by integer2 using floor division, so the result takes the sign of integer2. This differs from remainder, whose result takes the sign of integer1. An error is returned if integer2 is zero.
Examples:
?pr modulo -7 3
2
?pr remainder -7 3
-1
product
product number1 number2
(product number1 number2 number3 ...)
operation
Outputs the product of its inputs. It is equivalent to the * infix-form operation. With one input, product outputs its input.
Example:
; Approximate area of a curling sheet in square metres
?pr product 5 45
225
pwr
pwr base exponent
operation
Outputs base raised to the power of exponent.
Example:
?pr pwr 2 10
1024
quotient
quotient number1 number2
operation
Outputs the result of dividing number1 by number2. It is equivalent to the / infix-form operation. Number2 must not be zero. If it is, an error occurs.
Example:
; How many 250 ml cups are in a 1 litre carton of chocolate milk?
?pr quotient 1000 250
4
random
random integer
operation
Outputs a random non-negative integer less than integer. Results come from the device's hardware random source, so every run is different; see rerandom to make them reproducible instead.
Example:
; Pick a random seat row at the community rink
?pr random 20
7
rerandom
rerandom
(rerandom integer)
command
Normally random, pick, and shuffle draw from the device's hardware random source, so their results are unpredictable. rerandom switches them to a reproducible sequence: after running rerandom, the same sequence of results follows every time. Give an integer input to select among different reproducible sequences. The effect lasts until the device is restarted.
rerandom is useful for replaying a game or a bug exactly, and for producing the same results on every device in a classroom.
Example:
?(rerandom 7)
?pr random 100
47
?pr random 100
92
?(rerandom 7)
?pr random 100
47
remainder
remainder integer1 integer2
operation
Outputs the remainder obtained when integer1 is divided by integer2. The remainder is always an integer. If integer1 and integer2 are integers, this is integer1 mod integer2. If integer1 and integer2 are not integers, they are truncated. Integer2 must not be zero. If it is, an error occurs.
Example:
; What is the remainder when dividing 17 by 5?
?pr remainder 17 5
2
round
round number
operation
Outputs number rounded off to the nearest integer. The maximum integer is 2,147,483,647.
Examples:
; Round a temperature in Celsius
?pr round -17.3
-17
?pr round -17.6
-18
sin
sin number
operation
Outputs the sine of number in degrees.
Examples:
?pr sin 30
0.5
?pr sin 90
1
sqrt
sqrt number
operation
Outputs the square root of number. The value number must not be negative or an error will occur.
Example:
; Square root of a 13 by 13 scarf pattern
?pr sqrt 169
13
sum
sum number1 number2
(sum number1 number2 number3 ...)
operation
Outputs the sum of its inputs. sum is equivalent to the + infix-form operation. With one input, sum outputs its input.
Examples:
; Coffee plus a maple dip
?pr sum 2.15 1.45
3.6
?pr (sum 1 2 3 4 5 6 7 8 9 10)
55
tan
tan number
operation
Outputs the tangent of number in degrees.
Example:
?pr tan 45
1
===
Conditionals and Control of Flow
In Logo, the boolean value of true is represented by "true and false is represented by "false.
true
true
operation
Outputs "true. In Logo, boolean truth is represented by the word true.
Example:
?pr true
true
?pr equal? true true
true
false
false
operation
Outputs "false. In Logo, boolean false is represented by the word false.
Example:
?pr false
false
?pr equal? true false
false
;
; comment
command
The semicolon (;) indicates that the rest of the line is a comment. Logo ignores everything on the line after the semicolon. You can use comments to explain what your procedures do.
Example:
to square :number
; [This procedure outputs the square of :number]
output :number * :number
end
if
if predicate list1
(if predicate list1 list2)
command or operation
If predicate is true, Logo runs list1. If predicate is false,Pico Logo runs list2 (if present). In either case, if the selected list outputs something, the if is an operation. If the list outputs nothing, the if is a command.
if as a command:
to decide
if 0 = random 2 [op "yes]
op "no
end
to decide
(if 0 = random 2 [op "yes] [op "no])
end
if as an operation:
to decide
output (if 0 = random 2 ["yes] ["no])
end
ifelse
ifelse predicate list1 list2
command or operation
ifelse is the same as if except that list2 must be present. If predicate is true, Logo runs list1; if predicate is false, Logo runs list2. In either case, if the selected list outputs something, the ifelse is an operation. If the list outputs nothing, the ifelse is a command.
Example:
to decide
ifelse 0 = random 2 [op "yes] [op "no]
end
iffalse (iff)
iffalse list
iff list
command
iffalse runs list if the result of the most recent test was false, otherwise it does nothing. Note that if test has not been run in the same procedure or a superprocedure, or from top level, iffalse does nothing.
Example:
?to check.rink :status
>test equal? :status "open
>iftrue [pr [Sharpen your skates]]
>iffalse [pr [Try again after the thaw]]
>end
?check.rink "open
Sharpen your skates
?check.rink "soft
Try again after the thaw
iftrue (ift)
iftrue list
ift list
command
iftrue runs list if the result of the most recent test was true, otherwise it does nothing. Note that if test has not been run in the same procedure or a superprocedure, or from top level, iftrue does nothing.
Example:
?test name? "team
?ift [pr :team]
test
test predicate
command
test remembers whether predicate is true or false for subsequent use by iftrue or iffalse. Each test is local to the procedure in which it occurs.
Example:
?make "score 7
?test :score > 5
?ift [pr [Good draw, skip!]]
Good draw, skip!
ignore
ignore object
command
The ignore command does nothing. It is useful when you want to call a procedure for its side effects only.
Example:
; Call random for a side effect, ignore the result
?ignore random 100
co
co
command
The co (for continue) command resumes running of a procedure after a pause or ESC, continuing from wherever the procedure paused.
Example:
?to survey
>pr [Enter rink snack:]
>pause
>pr [Thank you!]
>end
?survey
Enter rink snack:
survey? pr "fries
fries
survey? co
Thank you!
output (op)
output object
op object
command
The output command is meaningful only when it is within a procedure, not at top level. It makes object the output of your procedure and returns control to the caller. Note that although output is itself a command, the procedure containing it is an operation because it has an output. Compare with stop.
Example:
?to topping :snack
>if equal? :snack "fries [output "gravy]
>if equal? :snack "pierogi [output "sour\ cream]
>if equal? :snack "toast [output "peameal]
>output "Unknown
>end
?pr topping "fries
gravy
?pr topping "pierogi
sour cream
pause
pause
command or operation
The pause command is meaningful only when it is within a procedure, not at top level. It suspends running of the procedure and tells you that you are pausing; you can then type instructions interactively. To indicate that you are in a pause and not a t top level, the prompt character changes to the name of the procedure you were in, followed by a question mark. During a pause, BRK does not work; the only way to return to top level during a pause is to run throw toplevel.
The procedure may be resumed by typing co.
Example:
?to inspect
>pr [Pausing for inspection...]
>pause
>pr [Resumed!]
>end
?inspect
Pausing for inspection...
inspect? pr "debugging
debugging
inspect? co
Resumed!
stop
stop
command
The stop command stops the procedure that is running and returns control to the caller. This command is meaningful only when it is within a procedure-not at top level. Note that a procedure containing stop is a command. Compare stop with output.
Example:
?to check.temp :celsius
>if :celsius > 0 [pr [Above freezing - no parka needed] stop]
>pr [Below freezing - wear your toque!]
>end
?check.temp 5
Above freezing - no parka needed
?check.temp -20
Below freezing - wear your toque!
wait
wait integer
command
wait tells Logo to wait for integer milliseconds.
Example:
; Pause for 1 second between messages
?pr [Kettle on...]
?wait 1000
?pr [Tea is steeped!]
catch
catch name list
command
catch runs list. If a throw name command is called while list is run, control returns to the first statement after the catch. The name is used to match up a throw with a catch. For instance, catch "chair [whatever] catches a throw "chair but not a throw "table.
There is one special case. catch "error catches an error that would otherwise print an error message and return to top level. If an error is caught, the message that Logo would normally print isn't printed. See the explanation of error in this section to find out how to tell what the error was.
Example:
?to safe.divide :a :b
>catch "error [output :a / :b]
>pr se [Error:] item 2 error
>output 0
>end
?pr safe.divide 10 2
5
?pr safe.divide 10 0
Error: Division by zero
0
error
error
operation
error outputs a four-element list containing information about the most recent error that has not had a message printed or output by error. If there was no such error, error outputs the empty list. The elements in the list are
- a unique number identifying the error
- a message explaining the error
- the name of the primitive causing the error, if any
- the name of the procedure within which the error occurred (the empty list, if top level).
Logo runs throw "error [whenever] an error occurs during the execution of a procedure. Control passes to top level unless a catch "error has been run. When an error is caught in this way, no error message is printed, and you can design your own.
Refer to Error Messages for a complete list of error messages and their meanings.
Example:
?catch "error [make "x 1/0]
?show error
[6 [Division by zero] quotient []]
go
go word
command
The go command transfers control to the instruction following label word in the same procedure.
Example:
?to count.loonies
>make "n 0
>label "loop
>make "n :n + 1
>pr :n
>if :n < 5 [go "loop]
>end
?count.loonies
1
2
3
4
5
label
label word
command
The label command itself does nothing. However, a go word passes control to the instruction following it. Note that word must always be a literal word (that is, it must be preceded by a quotation mark).
Example:
?to countdown
>make "n 10
>label "start
>pr :n
>make "n :n - 1
>if :n > 0 [go "start]
>pr [Zamboni doors closed]
>end
for
for forcontrol instructionlist
command
The first input must be a list containing three or four members: (1) a word, which will be used as the name of a local variable; (2) a word or list that will be evaluated as by RUN to determine a number, the starting value of the variable; (3) a word or list that will be evaluated to determine a number, the limit value of the variable; (4) an optional word or list that will be evaluated to determine the step size. If the fourth member is missing, the step size will be 1 or -1 depending on whether the limit value is greater than or less than the starting value, respectively.
The second input is an instructionlist. The effect of for is to run that instructionlist repeatedly, assigning a new value to the control variable (the one named by the first member of the forcontrol list) each time. First the starting value is assigned to the control variable. Then the value is compared to the limit value. for is complete when the sign of (current - limit) is the same as the sign of the step size. (If no explicit step size is provided, the instructionlist is always run at least once. An explicit step size can lead to a zero-trip for, e.g., for [i 1 0 1] ...). Otherwise, the instructionlist is run, then the step is added to the current value of the control variable and for returns to the comparison step.
? for [i 2 7 1.5] [print :i]
2
3.5
5
6.5
?
do.while
do.while list predicatelist
command
do.while runs list repeatedly as long as predicatelist is true. An error occurs if predicatelist is not true or false. A do.while loop can be exited early by a throw or stop command. list is always run at least once.
Example:
; Count ferry boarding calls
?make "call 1
?do.while [pr se [Call:] :call make "call :call + 1] [:call <= 3]
Call: 1
Call: 2
Call: 3
while
while predicatelist list
command
while tests predicatelist and, if it is true, runs list. It then repeats this process until predicatelist is false. An error occurs if predicatelist is not true or false. A while loop can be exited early by a throw or stop command. list may not be run at all if predicatelist is initially false.
Example:
; Count days below freezing
?make "temp -17
?make "days 0
?while [:temp < 0] [make "days :days + 1 make "temp :temp + 3]
?pr :days
6
do.until
do.until list predicatelist
command
do.until runs list repeatedly until predicatelist is true. An error occurs if predicatelist is not true or false. A do.until loop can be exited early by a throw or stop command. list is always run at least once.
Example:
; Print ticks until the kettle boils
?make "ticks 0
?do.until [make "ticks :ticks + 1 pr :ticks] [:ticks = 5]
1
2
3
4
5
until
until predicatelist list
command
until tests predicatelist and, if it is false, runs list. It then repeats this process until predicatelist is true. An error occurs if predicatelist is not true or false. An until loop can be exited early by a throw or stop command. list may not be run at all if predicatelist is initially true.
Example:
; Count loonies to ten
?make "score 0
?until [:score = 10] [make "score :score + 1]
?pr :score
10
forever
forever list
command
forever runs list repeatedly until interrupted by Brk, F4 or F9. A forever loop can also be exited by a throw or stop command.
Example:
; Flash a warning until Brk is pressed
?to blink.warning
>forever [pr [Check ice conditions!] wait 1000]
>end
repeat
repeat integer list
command
repeat runs list integer times. An error occurs if integer is negative can can be interrupted by Brk, F4 or F9. A repeat loop can be exited early by a throw or stop command.
Example:
; Draw a square
?repeat 4 [fd 50 rt 90]
repcount
repcount
operation
recount outputs the repetition count of the innermost current repeat or forever, starting from 1. If no repeat or forever is active, outputs –1.
Example:
; Number three butter tart batches
?repeat 3 [pr se [Batch] repcount]
Batch 1
Batch 2
Batch 3
run
run list
command or operation
The run command runs list as if typed in directly. If list is an operation, then run outputs whatever list outputs.
Example:
?run [pr [Mind the slush]]
Mind the slush
?make "action [pr "sorry]
?run :action
sorry
runresult
runresult list
operation
runresult runs list as if typed in directly, like run, but reports whether it produced a value rather than passing the value along. If list outputs a value, runresult outputs a one-member list containing that value; if list runs a command that outputs nothing, runresult outputs the empty list. It is most useful for running a list whose contents you do not control, where you cannot know in advance whether it will output.
Example:
?show runresult [sum 2 3]
[5]
?show runresult [pr "done]
done
[]
throw
throw name
command
The throw command is meaningful only within the range of the catch command. An error occurs if no corresponding catch name is found. throw toplevel returns control to top level. Contrast with stop.
See catch.
Example:
?to find.snack :list :target
>catch "found [
> foreach :list [[p]
> if equal? :p :target [pr se [Found:] :p throw "found]
> ]
> pr [Snack not found]
>]
>end
?find.snack [chips squares nanaimo] "nanaimo
Found: nanaimo
toplevel
toplevel
operation
Outputs "toplevel. throw toplevel to return control to the top level.
Example:
?to emergency.exit
>pr [Returning to top level!]
>throw toplevel
>end
step
step name
step list
command
The step command takes the procedure indicated by name or list as input and lets you run them line by line. step pauses at each line of execution and continues only when you press any key on the keyboard.
Example:
?to greet
>pr [Hello]
>pr [from the rink]
>end
?step "greet
?greet
; Execution pauses after each line, press any key to continue
trace
trace name
trace list
command
The trace command takes the procedures indicated by name or list as input and causes them to print tracing information when executed. It does not interrupt the execution of the procedure, but allows you to see the depth of the procedure stack during execution. trace is useful in understanding recursive procedures or complex programs with many subprocedures.
Example:
?to greet :name
>pr se [Hello] :name
>end
?trace "greet
?greet "Riley
==> greet [Riley]
Hello Riley
<== greet
unstep
unstep name
unstep list
command
unstep restores the procedure(s) indicated by name or list back to their original states. After you step through a procedure (with step), you must use unstep so that it will execute normally again.
Example:
?step "greet
; ... step through greet ...
?unstep "greet
; greet now runs at normal speed again
untrace
untrace name
untrace list
command
untrace stops the tracing of procedure name and causes it to execute normally again.
Example:
?trace "greet
?greet "Casey
==> greet [Casey]
Hello Casey
<== greet
?untrace "greet
?greet "Casey
Hello Casey
===
List Processing
The primitives in this section let you process lists. Each primitive takes either name of the procedure, a lambda expression or procedure text to apply to each element of the list.
For example, if you wanted to concatenate corresponding elements of two lists, you could use the following map command with a named procedure:
?show (map "word [a b c] [d e f])
[ad be cf]
A lambda expression is an anonymous procedure. It is written as a list whose first element is a list of input names (with no colons) and whose remaining elements are the expression for the output. For example, the lambda expression that adds 1 to its input would be written as follows:
[[x] :x + 1]
We could use this lambda expression with map to add 1 to each element of a list:
?show map [[x] :x + 1] [1 2 3]
[2 3 4]
An anonymous procedure is a list whose first element is a list of input names (with no colons) and whose remaining elements are the body of the procedure. This is the list text that is used with define and output bytext. For example, the anonymous procedure that adds two numbers would be written as follows:
[[x y] [output :x + :y ]]
To add the corresponding elements of two lists, we could use this anonymous procedure with map:
?show map [[x y] [ output :x + :y ]] [1 2 3] [4 5 6]
[5 7 9]
The anonymous procedure, while not recommended for complex procedures, can be used, when multiple lines are needed:
[[x y] [(print [x+y=] :x + :y)] [output :x + :y]]
For a more complex example, to calculate the distance between two points in any number of dimensions, we can use map and apply together with lambda expressions:
? show sqrt apply "sum map [[x] pwr :x 2] (map [[a b] :a - :b] [1 2 3] [4 5 6])
5.19615
apply
apply procedure inputlist
command or operation
Runs procedure, providing its inputs with the members of inputlist. The number of members in inputlist must be an acceptable number of inputs for procedure. apply outputs what procedure outputs, if anything.
Examples:
?show apply [[a b c] :a + :b + :c] [1 2 3]
6
?show apply "sum [1 2 3 4]
10
foreach
foreach data procedure
(foreach data1 data2 ... procedure)
command
Evaluates procedure repeatedly, once for each member of the data list. If more than one data list are given, each of them must be the same length. (The data inputs can be words, in which case procedure is evaluated once for each character.)
Each data list provides one input to procedure at each evaluation. Thus, if there are two data lists, procedure must have two inputs; if there are three data lists, procedure must have three inputs; and so on.
Examples:
?foreach [1 2 3] [[i] print :i]
1
2
3
?
?(foreach [1 2 3] [4 5 6] [[a b] print :a + :b])
5
7
9
?
map
map procedure data
(map procedure data1 data2 ...)
operation
map evaluates procedure once for each member of the data list and outputs a object of the results. If more than one data object are given, each of them must be the same length. (The data inputs can be words, in which case procedure is evaluated once for each character.) The output object will be a word if the first data input is a word; otherwise, the output will be a list.
Each data list provides one input to procedure at each evaluation. Thus, if there are two data lists, procedure must have two inputs; if there are three data lists, procedure must have three inputs; and so on.
Examples:
?show map [[x] :x * :x] [1 2 3 4]
[1 4 9 16]
?show (map "sum [1 2 3] [4 5 6])
[5 7 9]
?show map [[x] ascii :x] "hello"
104101108108111
?
map.se
map.se procedure data (map.se procedure data1 data2 ...)
operation
Outputs a list formed by evaluating the procedure repeatedly and concatenating the results using sentence. That is, the members of the output are the members of the results of the evaluations. The output list might, therefore, be of a different length from that of the data input(s). (If the result of an evaluation is the empty list, it contributes nothing to the final output.) The data inputs may be words or lists.
Each data list provides one input to procedure at each evaluation. Thus, if there are two data lists, procedure must have two inputs; if there are three data lists, procedure must have three inputs; and so on.
Example:
; Expand rink-counter shorthand to full orders
?to expand :abbrev
>if equal? :abbrev "DD [output [double double]]
>if equal? :abbrev "KD [output [macaroni dinner]]
>output (list :abbrev)
>end
?show map.se "expand [DD KD PB]
[double double macaroni dinner PB]
filter
filter procedure data
operation
filter evaluates procedure once for each member of the data list and outputs a list of those members for which procedure outputs true. Procedure must have one input. The output object will be a word if data is a word; otherwise, the output will be a list.
Procedure must output either true or false for each member of data.
Examples:
?show filter [[x] :x > 2] [1 2 3 4 5]
[3 4 5]
?show filter [[x] 105 < ascii :x] "hello
llo
?
find
find procedure data
operation
find evaluates procedure once for each member of the data list and outputs the first member for which procedure outputs true. Procedure must have one input.
Procedure must output either true or false for each member of data.
Example:
?show find [[x] 0 = remainder :x 2] [1 3 4 5 6]
4
?
reduce
reduce procedure data
operation
reduce evaluates procedure repeatedly to combine the members of data into a single output. Procedure must have two inputs.
If data has only one member, that member is output. If data is empty, an error occurs. Otherwise, the last two members of data are provided as inputs to procedure, and the output of procedure is then combined with the previous member of data by calling procedure again. This process continues until all members of data have been combined.
Examples:
?show reduce [[a b] :a + :b] [1 2 3 4]
10
?
?show reduce [[x y] word :x :y] [a b c d e]
abcde
?
?show reduce [[x y] [(pr "; :x ", :y)] [op :x + :y]] [1 2 3]
; 2 , 3
; 1 , 5
6
?
crossmap
crossmap procedure listlist
(crossmap procedure data1 data2 ...)
operation
crossmap evaluates procedure for every combination of members from the input lists and outputs a list of the results. If more than one data list are given, each of them can be of different lengths. (The data inputs can be words, in which case procedure is evaluated once for each character.)
Each data list provides one input to procedure at each evaluation. Thus, if there are two data lists, procedure must have two inputs; if there are three data lists, procedure must have three inputs; and so on.
As a special case, if only one data list input is given, that listlist is taken as a list of data lists, and each of its members contributes values to an input of procedure.
Examples:
? show crossmap [[x y] :x + :y] [[1 2] [10 20 30]]
[11 21 31 12 22 32]
?
?show (crossmap "word [a b c] [1 2 3 4])
[a1 a2 a3 a4 b1 b2 b3 b4 c1 c2 c3 c4]
?
===
Special Control Characters
Break
Brk
Pressing Brk immediately stops whatever is running, returning Logo to top level, unless in a pause mode.
F4
F4
Pressing F4 interrupts whatever is running. Typing any character resumes normal execution. This special character is particularly useful in giving yourself time to read when Logo is displaying more than one screenful of information.
F9
F9
Pressing F9 interrupts whatever is running, causing a pause. F9 is equivalent in effect to pause, but different in its use: you press F9 at the keyboard during the running of a procedure, while pause is part of the definition of a procedure.
===
Modifying Procedures Under Program Control
copydef
copydef name newname
command
copydef copies the definition of name, making it the definition of newname as well.
Example:
?to kettle pr [Tea is ready] end
?copydef "kettle "thermos
?thermos
Tea is ready
define
define name list
command
define makes list the definition of the procedure name. The first element of list is a list of the inputs to name, with no colon (:) before the names.
If name has no inputs, this must be the empty list. Each subsequent element is a list consisting of one line of the procedure definition. (This list does not contain end, because end is not part of the procedure definition.)
The second input to define has the same form as the output from text. define can redefine an existing procedure.
Example:
?define "notice [[item] [pr se [Found by the rink door:] :item]]
?notice "mitts
Found by the rink door: mitts
defined? (definedp)
defined? word
definedp word
operation
defined? outputs true if word is the name of a user-defined procedure, false otherwise.
Example:
?to maple pr [Leaf!] end
?pr defined? "maple
true
?pr defined? "oak
false
primitive? (primitivep)
primitive? name
primitivep name
operation
primitive? outputs true if name is the name of a primitive, false otherwise.
Example:
?pr primitive? "print
true
?pr primitive? "greet
false
text
text name
operation
The text primitive outputs the definition of name as a list of lists, suitable for input to define.
Example:
?to notice :item
>pr se [Found by the rink door:] :item
>end
?show text "notice
[[item] [pr se [Found by the rink door:] :item]]
primitives
primitives
operation
primitives outputs a list of the names of all primitives, in alphabetical order. This list includes the names of all operations and commands described in this reference, as well as some additional primitives that are not described here but are available for use in your programs. The list does not include the names of user-defined procedures.
Example:
?pr member? "print primitives
true
?pr member? "greet primitives
false
help
help name
(help)
command
help outputs a brief description of the primitive name: the type of primitive (command or operation), the inputs it takes, and a quick reminder of its purpose and use.
If name is not the name of a primitive, help searches instead: it lists the primitives whose names contain name, or failing that, the primitives whose descriptions mention it. An error occurs only when nothing matches.
With no inputs, (help) lists every primitive, grouped by the chapters of this manual.
Example:
?help "rand
No help for rand. Related:
random rerandom
?
===
Logical Operations
and
and predicate1 predicate2
(and predicate1 predicate2 predicate3 ...)
operation
Outputs true if all of its inputs are true. All inputs are evaluated.
Example:
?pr and true true
true
?make "sidewalk "icy
?make "salted true
?pr and equal? :sidewalk "icy :salted
true
?pr and true false
false
not
not predicate
operation
Outputs true if predicate is false.
Outputs false if predicate is true.
Example:
?pr not true
false
?pr not false
true
?make "snowing false
?if not :snowing [pr [Patio season declared]]
Patio season declared
or
or predicate1 predicate2
(or predicate1 predicate2 predicate3 ...)
operation
Outputs true if any of its inputs are true. All inputs are evaluated.
Example:
?pr or false false
false
?pr or false true
true
?make "snack "butter\ tart
?if or equal? :snack "butter\ tart equal? :snack "nanaimo\ bar [pr [Dessert table approved]]
Dessert table approved
===
Bitwise Operations
bitand
bitand num1 num2
(bitand num1 num2 num3 ...)
operation
Outputs the bitwise AND of its inputs, which must be integers.
Example:
?pr bitand 12 10
8
?pr bitand 255 15
15
bitor
bitor num1 num2
(bitor num1 num2 num3 ...)
operation
Outputs the bitwise OR of its inputs, which must be integers.
Example:
?pr bitor 12 10
14
?pr bitor 4 3
7
bitxor
bitxor num1 num2
(bitxor num1 num2 num3 ...)
operation
Outputs the bitwise exclusive OR of its inputs, which must be integers.
Example:
?pr bitxor 12 10
6
?pr bitxor 255 170
85
bitnot
bitnot num
operation
Outputs the bitwise NOT of its input, which must be an integer.
Example:
?pr bitnot 0
-1
?pr bitnot 12
-13
ashift
ashift num1 num2
operation
Outputs num1 arithmetic-shifted to the left by num2 bits. If num2 is negative, the shift is to the right with sign extension. The inputs must be integers.
Example:
?pr ashift 1 4
16
?pr ashift 16 -2
4
?pr ashift -8 -1
-4
lshift
lshift num1 num2
operation
Outputs num1 logical-shifted to the left by num2 bits. If num2 is negative, the shift is to the right with zero fill. The inputs must be integers.
Example:
?pr lshift 1 4
16
?pr lshift 16 -2
4
?pr lshift -8 -1
2147483644
===
The Outside World
key? (keyp)
key? keyp
operation
key? outputs true if there is at least one character waiting to be read-that is, one that has been typed on the keyboard and not yet picked up by readchar or readlist. key? outputs false if there are no such characters.
Example:
?to wait.for.key
>pr [Press any key to continue...]
>until [key?] []
>ignore rc
>end
pollkeys
pollkeys
command
pollkeys refreshes what keydown? and keyhit? report, and discards any characters waiting for readchar.
readchar hands you a stream of characters at the keyboard's typing speed: nothing for a third of a second after a key goes down, then ten repeats a second, queued up in the order they were typed. That is what you want at a prompt and the wrong thing inside a game. A frame loop reading one character a frame takes them out slower than the keyboard puts them in, so the backlog grows and the game acts on a key the player has already let go of; and reading one character at a time means two keys can never be held at once.
pollkeys reads the keyboard's state instead of its history: which keys are down, right now. Call it once at the top of each frame. keydown? and keyhit? afterwards cost nothing, so you can ask about as many keys as your game has controls.
Because a game that polls key state never reads the characters those same keypresses produce, pollkeys throws them away. Call pollkeys once before your loop starts as well, so a keypress left over from a menu is not delivered to the first frame.
Example:
?to play
>pollkeys ; ignore whatever started the game
>until [:over] [frame]
>end
keydown? (keydownp)
keydown? code
keydownp code
operation
keydown? outputs true if the key with ASCII code code was held down at the last pollkeys, and false if it was not. It answers for as many frames as the player keeps the key down, which is what a control like steering or thrust wants.
The codes are the ones ascii outputs for ordinary characters — 32 for the space bar, 112 for p — and for the keys that are not characters: 180 left arrow, 183 right arrow, 181 up arrow, 182 down arrow, 13 enter, 8 backspace, 177 escape. Shift, control and alt do not change the code: keydown? 112 is true whether or not shift is down.
Example:
?to steer
>if keydown? 180 [left :turn.rate]
>if keydown? 183 [right :turn.rate]
>if keydown? 181 [thrust]
>end
keyhit? (keyhitp)
keyhit? code
keyhitp code
operation
keyhit? outputs true if the key with ASCII code code was pressed between the last two pollkeys, and false if it was not.
Where keydown? reports that a key is down, keyhit? reports that it went down: once per press, however long the player holds it. Use it for a control that should act once — firing a shot, pausing, choosing a menu item — and keydown? for one that should act continuously.
keyhit? also catches a tap that is over so quickly the key is no longer down by the time pollkeys runs, which keydown? cannot see at all.
Example:
?to poll.input
>pollkeys
>if keyhit? 112 [toggle.pause stop] ; once per press of P
>if :paused [stop]
>if keydown? 181 [thrust] ; every frame it is held
>if keyhit? 32 [fire] ; one shot per press of space
>end
readchar (rc)
readchar
rc
operation
readchar outputs the first character typed at the keyboard or read from the current file or network connection. If you are reading from the keyboard and no character is waiting to be read, readchar waits until you type something.
readchar does not output a character if you are reading from a file and the end-of-file position is reached. In this case, readchar outputs an empty list. Note that readchar from the keyboard does not echo what you type on the screen.
If reading from a network connection and the read times out before a character is available, readchar outputs an empty list. readchar will also output an empty list if the network connection is closed before a character is available.
If you are reading from the keyboard, you can set the high bit of the character being read by holding down either Alt key a you type the character. Setting the high bit adds 128 to the character.
Example:
?to get.answer
>pr [Press Y for Yes or N for No:]
>make "key rc
>if equal? :key "Y [pr [Oui!] stop]
>pr [Non!]
>end
readchars (rcs)
readchars integer
rcs integer
operation
The readchars operation outputs the first integer number of characters typed at the keyboard or read from the current file or network connection. If you are reading from the keyboard and no characters are waiting to be read, readchars waits for you to type something.
If you are reading from a file and the end-of-file position reached before integer characters are read, readchars outputs the characters read up to that point. If the end-of-file was reached before readchars was called, readchars outputs an empty list.
If reading from a network connection and the read times out before the requested number of characters are available, readchars outputs the characters read up to that point. If the network connection was closed before readchars was called, readchars outputs an empty list.
Note that readchars from the keyboard does not echo what you type on the screen.
Remember that a carriage return is read as a character.
If you are reading from the keyboard, you can set the high bit of the character being read by holding down either Alt key as you type the character. Setting the high bit adds 128 to character.
Example:
?to read.postal
>pr [Enter first 3 chars of postal code:]
>make "prefix rcs 3
>pr se [Prefix:] :prefix
>end
readlist (rl)
readlist
rl
operation
The readlist operation reads a line of information from the current file or network connection and outputs the information in the form of a list. Normally, the source is the keyboard, where you type in information followed by a carriage return. This information is echoed on the screen. The command setread allows you to read from other files or network connections.
If you are reading from a file where the end-of-file position has already been reached, readlist outputs the empty word.
If you are reading from a network connection and the read times out before a line is available, readlist outputs the characters read up to that point. If the network connection was closed before readlist was called, readlist outputs an empty list.
Example:
?to ask.order
>pr [Enter rink snack order:]
>make "input rl
>pr se [You entered:] :input
>end
?ask.order
Enter rink snack order:
fries gravy
You entered: fries gravy
readword (rw)
readword
rw
operation
readword reads a line of information from the current file or network connection and outputs it as a word. Normally, the source is the keyboard and readword waits for you to type and press Enter. What you type is echoed on the screen. If you press Enter before typing a word, readword outputs an empty word.
If you use readword from a file, readword reads characters until it reaches a carriage return, and outputs those characters as a word. The next character to be read is the one after the carriage return. When the end-of-file position is reached, readword outputs an empty list.
If you are reading from a network connection and the read times out before a line is available, readword outputs the characters read up to that point. If the network connection was closed before readword was called, readword outputs an empty list.
Because readword returns the line verbatim, any vertical bars (see
Vertical Bars) are preserved in the resulting word. This
differs from readlist and parse, which tokenize
the line and so consume the bars while keeping the characters between them.
See readlist, readchar, readchars, and setread.
Example:
?to ask.toque
>pr [Enter toque colour:]
>make "shade rw
>pr se [Toque:] :shade
>end
?ask.toque
Enter toque colour:
red
Toque: red
print (pr)
print object
(print object1 object2 ...)
pr object
(pr object1 object2 ...)
command
The print command prints its inputs followed by a carriage return on the screen, unless the destination has been changed by setwrite. The outermost brackets of lists are not printed. A space is printed between the inputs if there is more than one.
Example:
?pr [Snow route starts at midnight]
Snow route starts at midnight
?pr "sorry
sorry
?(pr "loonie "toonie "hydro)
loonie toonie hydro
show
show object
command
The show command prints object followed by a carriage return on the screen, unless the destination has been changed by setwrite. If object is a list, Logo leaves brackets around it. A space is printed between the inputs if there is more than one.
Example:
?show [loonie toonie hydro]
[loonie toonie hydro]
?show "sorry
sorry
type
type object
(type object1 object2 ...)
command
The type command prints its inputs without a carriage return on the screen, unless the destination has been changed by setwrite. The outermost brackets of lists are not printed. Spaces are not printed between the inputs.
Example:
?type "Rink
?type ":
?type "closed
Rink: closed
standout
standout object
operation
outputs object in standout mode. In standout mode, text is displayed in reverse video. If the display does not support reverse video, the text is displayed normally. The outermost brackets of lists are not printed.
Example:
?pr standout "Caution
Caution
?pr standout [Slush at door]
Slush at door
toot
toot duration frequency
(toot duration leftfrequency rightfrequency)
command
Generates a tone via audio output. Duration is measured in units of 1/1000th of a second (A whole note is 2000 units; a eighth note is 250 units). A frequency is specified in Hertz (cycles per second) and can range from 131 (C3) to 1976 (B6). 440Hz is the tuning frequency A.
If one frequency is provided the same tone is produced on both left and right channels.
toot does not block. If a second toot is requested, Logo will wait until the previous toot completes.
toot is the simplest way to make a sound. For volume, envelopes, waveforms, noise, and background music, see sound, setenv, setwave, and play.
The actual frequency range is 100Hz to 2000Hz. If the input is outside this range, no tone is produced and but
tootbehaves as if a rest is requested. By convention, a rest is produced using a frequency of 0Hz.
Example:
; Play A440 for 500ms (like a school gym scoreboard buzzer)
?toot 500 440
; Play two notes: a rising interval
?toot 250 440
?toot 250 523
; Play different tones on left and right channels
?(toot 1000 440 523)
sound
sound voice frequency duration
(sound voice frequency duration volume)
command
Plays a note immediately on voice and returns at once (it does not wait). frequency is in Hertz and duration in milliseconds. volume is 0 to 15; when omitted, the voice's current volume is used (15 until you set one).
There are eight voices, numbered by ear: 0, 1, and 2 are tone voices and 3 is a noise voice on the left channel; 4, 5, and 6 are tone voices and 7 is noise on the right. voice may be a single number or a list of voice numbers, in which case the note plays on each of them (like tell).
The note is shaped by the voice's envelope (setenv) and waveform (setwave). Calling sound on a voice that is playing queued music (see play) flushes that voice's queue - the effect wins.
The frequency range is 20Hz to 10000Hz. A frequency outside this range (including 0) is a rest: the voice is gated off through its release.
Example:
; A 440Hz note for half a second on voice 0
?sound 0 440 500
; A short, loud noise burst - a stereo explosion on both noise voices
?(sound [3 7] 6000 80 15)
setenv
setenv voice [attack decay sustain release]
command
Sets the ADSR envelope of voice. attack, decay, and release are times in milliseconds; sustain is a level from 0 to 15. The envelope shapes every note the voice plays afterwards: the note rises to full volume over attack, falls to the sustain level over decay, holds there while it sounds, then fades over release.
voice may be a single number or a list of voice numbers. The default envelope is [5 0 15 30], which is click-free but otherwise flat, like toot.
Example:
; A percussive pluck: instant attack, quick fall to silence
?setenv 1 [0 60 0 40]
?sound 1 1800 90
env
env voice
operation
outputs the ADSR envelope of voice as the list [attack decay sustain release], as set by setenv. voice must be a single voice number.
Example:
?show env 0
[5 0 15 30]
setwave
setwave voice waveform
(setwave voice "pulse duty)
command
Sets the waveform of voice. For a tone voice (0, 1, 2, 4, 5, 6) waveform is square, pulse, triangle, or sawtooth. For a noise voice (3, 7) it is white or periodic. Using a tone waveform on a noise voice, or a noise waveform on a tone voice, is an error.
With pulse you may give a duty cycle from 1 to 99 (percent); it defaults to 50. voice may be a single number or a list of voice numbers.
Example:
?setwave 0 "triangle
?(setwave 1 "pulse 25)
?setwave 3 "periodic
wave
wave voice
operation
outputs the waveform word of voice, as set by setwave. voice must be a single voice number.
Example:
?show wave 0
square
play
play [notes]
(play voice [notes])
command
Plays a sequence of notes on voice (voice 0 when omitted) in the background: the notes are added to the voice's queue and Logo continues at once. Calling play again on the same voice appends to what is already queued, so a tune can be built up a phrase at a time. voice may be a single number or a list of voice numbers.
Each note is a word:
- A note is [length] letter [accidental] [octave] [dot]. The letter is
atog. An accidental is#orsfor a sharp orbfor a flat. The octave is a digit from 1 to 8. A leading length number sets the note length (4 = quarter note, 8 = eighth, and so on); a trailing.dots it. Sogis a plain G,8gan eighth-note G,c#5a C sharp in octave 5, and8g#5.a dotted eighth-note G sharp in octave 5. - A rest is [length]
r[dot], for example2rfor a half rest. - Control words change the defaults from that point on:
tn sets the tempo in quarter-notes per minute (40 to 300),on the octave (1 to 8),ln the default length (1 to 32), andvn the volume (0 to 15).
If the voice's queue is full, play waits for room (you can interrupt it with the break key), so long tunes stream rather than failing.
Example:
; Frere Jacques, phrase by phrase, as background music
to f1 play [c d e c] end
to f2 play [e f 2g] end
?f1 f1 f2 f2
; A drum pattern on the left noise voice
?(play 3 [l8 c c 4c])
playing? (playingp)
playing?
(playing? voice)
playingp
(playingp voice)
operation
outputs true if any voice is currently sounding or still has notes queued, and false if all voices are silent. With a voice argument it asks about that one voice. This pairs well with when to chain music together: when [not playing?] [next.verse].
Example:
?play [c d e c]
?show playing?
true
stopsound
stopsound
command
Silences every voice (through its release) and clears all queued notes. It does not change the envelopes or waveforms set with setenv and setwave, so the timbre you chose survives.
Example:
?play [c d e f g a b c6]
?stopsound
===
Managing your Workspace
nodes
nodes
operation
nodes outputs the number of free nodes. This gives you an idea of how much space you have in your workspace for procedures, variables, properties, and the running of procedures. nodes is most useful if run immediately after recycle.
Words and lists share the interpreter's memory. recycle reclaims storage for words and lists that are no longer reachable, so a program that creates temporary words can recover that space explicitly. Live words still use a 32 KB atom table, so a workspace that keeps too many distinct words can still run out of space.
Example:
?recycle
?pr nodes
14253
atoms
atoms
operation
atoms outputs the number of free bytes in the word table. Words and lists share the interpreter's memory, but they do not share the same shelf: nodes counts the free nodes that lists and procedure bodies are built from, while atoms counts the room left for the characters of distinct words. A program can be rich in one and out of the other, so a program that runs out of space with plenty of nodes free is a program to point atoms at.
Every distinct word costs its characters once, however many places refer to it — and a number stored in a list is a word, so a program storing continuously changing numbers mints a new word for each one. That is the usual reason this figure falls during a loop that looks like it allocates nothing. recycle gives back the room used by words nothing refers to any more.
Example:
?make "l (list 0)
?recycle
?pr atoms
19536
?repeat 100 [make "n random 100000 .setitem 1 :l :n]
?pr atoms
18664
?recycle
?pr atoms
19528
recycle
recycle
command
The recycle command frees up as much unreachable list, word, and blob storage as possible, performing what is called a garbage collection. Logo does not collect garbage on its own: if you run out of space, the current instruction stops with an out of space error, and you must run recycle (typically at a convenient point in your program, such as the top of a main loop) to reclaim unused storage.
Example:
; Free memory before starting the main loop
?recycle
?pr nodes
14253
po
po name
po list
command
The po (for print out) command prints the definition(s) of the named procedure(s).
Example:
?to notice :item
>pr se [Found in lost and found:] :item
>end
?po "notice
to notice :item
pr se [Found in lost and found:] :item
end
poall
poall
command
The poall (for print out all) command prints the definition of every procedure and the value of every variable in the workspace.
Example:
?make "snack "ketchup\ chips
?to hello pr [Hi] end
?poall
make "snack "ketchup\ chips
to hello
pr [Hi]
end
pon
pon name
pon list
command
pon (for print out name) prints the name and value of the named variable(s).
Example:
?make "snowbank "tall
?pon "snowbank
make "snowbank "tall
pons
pons
command
pons (for print out names) prints the name and value of every variable in the workspace.
Example:
?make "snack "ketchup\ chips
?make "temp -17
?pons
make "snack "ketchup\ chips
make "temp -17
pops
pops
command
pops (for print out procedures) prints the definition of every procedure in the workspace.
See bury for exceptions.
Example:
?to weather pr [Chance of flurries] end
?pops
to weather
pr [Chance of flurries]
end
pot
pot name
pot list
command
The pot (for print out title) command prints the title line of the named procedure(s) in the workspace.
Example:
?to label :item :shelf
>pr (se [Put] :item [on] :shelf)
>end
?pot "label
to label :item :shelf
pots
pots
command
pots (for print out titles) prints the title line of every procedure in the workspace.
See bury for exceptions.
Example:
?to maple end
?to leaf end
?pots
to maple
to leaf
erall
erall
command
erall erases all procedures, variables, and properties from the workspace.
See bury for exceptions.
Example:
?make "route "snow
?to hello pr [Hi] end
?erall
?pr name? "route
false
erase (er)
erase name
erase list
er name
er list
command
The erase command erases the named procedure(s) from the workspace.
Example:
?to hello pr [Hello] end
?defined? "hello
true
?erase "hello
?defined? "hello
false
ern
ern name
ern list
command
The ern (for erase name) command erases the named variable(s) from the workspace.
Example:
?make "toque "red
?pr name? "toque
true
?ern "toque
?pr name? "toque
false
erns
erns
command
erns (for erase names) erases all variables from the workspace.
See bury for exceptions.
Example:
?make "snack "ketchup\ chips
?make "temp -17
?erns
?pr name? "snack
false
erps
erps
command
The erps (for erase procedures) command erases all procedures from the workspace.
See bury for exceptions.
Example:
?to pancake pr [Needs syrup] end
?erps
?defined? "pancake
false
bury
bury name
bury list
command
The bury command buries the procedure(s) in its input. Certain commands (erall, erps, poall, pops, pots, and save) act on everything in the workspace except procedures and names that are buried.
Example:
?to startup pr [Welcome to Pico Logo!] end
?bury "startup
?pots
; startup is not listed
buryall
buryall
command
The buryall command buries all the procedures and variable names in the workspace.
Once buryall is run, there are no procedure titles or names visible.
Example:
?to greet pr [Fresh coffee] end
?make "snack "butter\ tart
?buryall
?pots
; nothing listed
buryname
buryname name
buryname list
command
buryname buries the variable name(s) in its input.
Example:
?make "population 38000000
?buryname "population
?pons
; population is not listed
unbury
unbury name
unbury list
command
The unbury command unburies the named procedure(s).
Example:
?bury "startup
?unbury "startup
?pots
to startup
unburyall
unburyall
command
unburyall unburies all procedures and variable names that are currently buried in the workspace.
Once unburyall is run, the procedures and variable names are visible.
Example:
?buryall
?unburyall
?pots
; all procedures visible again
unburyname
unburyname name
unburyname list
command
unburyname unburies the variable name(s) in its input.
Example:
?buryname "ticket
?unburyname "ticket
?pons
make "ticket "snow\ route
===
File Management
Pico Logo presents a single directory tree with two filesystems mounted in it:
/- the root is the device's internal flash storage. It is always present and is where files are saved by default (the default prefix is/). Yourstartupfile lives here as/startup./sd- the FAT32 SD card, mounted under/sd. It appears in a listing of/only while a card is inserted, and is re-read automatically when a card is removed and another inserted. Asking about/sdwith no card present reportsThere is no SD card.
Paths may be absolute (beginning with /) or relative to the current prefix (see setprefix). rename moves a file between the two filesystems by copying it and deleting the original, while copyfile leaves the original in place. Both work on files only; moving or copying a directory across filesystems is not supported and reports File is the wrong type. Both are binary-safe, so images and other binary files are copied without corruption.
Use free to see how much space remains on a filesystem. The whole internal filesystem can be saved to and reloaded from an SD-card file with backup and .restore.
files
files
(files ext)
operation
Outputs a list of file names in the currect directory. If ext is present, the file names are limited to those with the ext extension. If ext is "*" then all files are output.
Example:
?pr files
[startup rink readme.txt]
?pr (files "txt")
[readme.txt]
directories
directories
operation
Outputs a list of directory names in the current directory.
Example:
?pr directories
[Logo sketches snacks]
createdir
createdir pathname
command
createdir creates the subdirectory indicated by pathname. The last file name in pathname is the subdirectory to be created, and preceding names indicate where it should be placed.
Example:
?createdir "sketches
?pr directories
[sketches]
setprefix (sp)
setprefix pathname
sp pathname
command
Sets a prefix that will be used as the implicit beginning of filenames in open, load, and save commands. The input to setprefix must be a word, unless it is the empty list, to indicate that there should be no prefix. sp is an abbreviation for setprefix.
The pathname can include parent directory references ("..") to navigate up the directory tree. For example, if the current prefix is /sketches/apple/, then setprefix ".." will change the prefix to /sketches/, and setprefix "..\/banana" will change it to /sketches/banana/.
Examples:
?setprefix "/sketches
?pr prefix
/sketches/
?setprefix "apple
?pr prefix
/sketches/apple/
?setprefix "..
?pr prefix
/sketches/
?setprefix "..\/banana
?pr prefix
/sketches/banana/
prefix
prefix
operation
Outputs the current file prefix, or [] if there is no prefix.
Example:
?setprefix "/sketches
?pr prefix
/sketches/
?setprefix []
?pr prefix
[]
editfile
editfile pathname
command
editfile loads the file indicated by pathname into the edit buffer and saves the edited contents under the same filename. The old contents will be lost.
You can use editfile on any file, whether it exists or not. If it does not exist, the editor buffer is erased and Logo creates the file when you save the contents of the edit buffer.
The edit buffer is limited based on Supported Pico Boards. If the file you try to edit contains more than this, Logo displays an error message and does not let you edit the file.
If you exit the editor with Brk, the file remains unchanged.
When exiting the editor, the contents of the buffer are not run.
Example:
?editfile "storm_notes
; Opens the editor with storm_notes contents
; After saving and exiting, the file is updated
erasefile (erf)
erasefile pathname
erf pathname
command
Stands for erase file. Erases any type of file. The input must be the name of a file in the current directory or a full pathname.
Example:
?pr file? "old_data
true
?erasefile "old_data
?pr file? "old_data
false
erasedir
erasedir pathname
command
Stands for erase directory. Erases a directory. The directory must be empty or this command will result in an error.
Example:
?createdir "temp
?erasedir "temp
?pr dir? "temp
false
cat
cat
(cat pathname)
command
Prints the names of the files and directories in the current directory, sorted alphabetically and packed into as many columns as fit across the screen (like a terse ls). Directories have the slash "/" character appended to their name. If pathname is present, it specifies the directory to be listed.
For a detailed one-per-line listing that includes file sizes, use catalog.
cat prints to the screen but not to the current writer.
Example:
?cat
kite rink startup
maze sketches/
catalog
catalog
(catalog pathname)
command
Prints a detailed list of the files and directories in the current directory, one per line, sorted alphabetically (like ls -l). Each line begins with the file's size in bytes, right-aligned; directories have a blank size column and the slash "/" character appended to their name. If pathname is present, it specifies the directory to be listed.
For a compact multi-column listing, use cat.
catalog prints to the screen but not to the current writer.
Example:
?catalog
418 rink
212 startup
sketches/
free
free
(free pathname)
operation
Outputs a two-element list [free_blocks block_size] describing the filesystem that holds the current directory, or - if pathname is given - the filesystem that holds pathname. free_blocks is the number of free allocation blocks; block_size is the size of one block in bytes. A block is the filesystem's own allocation unit (a flash block on the internal / filesystem, a cluster on the /sd card), so block sizes differ between volumes - multiply the two to get free bytes and compare across volumes.
Reports There is no SD card if asked about /sd when no card is present.
Example:
?pr free
1018 4096
?show (free "/sd)
[1962500 8192]
?pr product first free last free
4169728
file? (filep)
file? pathname
filep pathname
operation
Outputs true if the file exists, otherwise false.
Example:
?pr file? "startup
true
?pr file? "missing
false
dir? (dirp)
dir? pathname
dirp pathname
operation
Outputs true if the directory exists, otherwise false.
Example:
?pr dir? "sketches
true
?pr dir? "snacks
false
rename
rename pathname1 pathname2
operation
Renames the file or directory from pathname1 to pathname2. A file or directory can be moved if the paths are different. A file may be moved between the internal storage and the /sd card (it is copied, then the original is deleted); moving a directory across the two filesystems is not supported and reports File is the wrong type.
Example:
?rename "draft "pancake_final
?pr file? "pancake_final
true
copyfile
copyfile pathname1 pathname2
command
Copies the file pathname1 to pathname2, leaving the original in place. If pathname2 already exists it is replaced. The copy is binary-safe, so images and other binary files are copied without corruption, and it may cross between the internal storage and the /sd card (for example copyfile "/sd/turtle.bmp "/turtle.bmp). pathname1 must be a file; copying a directory, or copying onto an existing directory, reports File is the wrong type. Copying a file onto itself has no effect.
Example:
?copyfile "/sd/logo.bmp "/logo.bmp
?pr file? "/logo.bmp
true
backup
backup pathname
command
Writes a complete image of the internal filesystem (/) to pathname, which must be on the SD card (for example backup "/sd/2026-06-30.bak). Only the blocks that actually hold data are written, so the backup file stays small. The image survives re-flashing the firmware, so a backup made before an update can be restored afterwards with .restore.
The backup file must live on the SD card, not on the internal filesystem it is imaging; otherwise Logo reports Backup file must be on the SD card.
Example:
?backup "/sd/2026-06-30.bak
?pr file? "/sd/2026-06-30.bak
true
.restore
.restore pathname
command
Dangerous. Erases the entire internal filesystem (/) and replaces it with the image stored in pathname (which must be on the SD card). Every file currently in internal storage is lost. The leading period marks .restore as a dangerous operation, following Logo convention - there is no undo. All open files are closed before the restore begins.
The image may come from a device with a smaller internal filesystem than this one; the restored filesystem is grown to fill the available space. An image from a larger filesystem cannot be restored onto a smaller one and reports Backup file is not valid for this device. The image is fully checked before any storage is erased, so a corrupt or incompatible backup leaves the existing filesystem untouched.
Example:
?.restore "/sd/2026-06-30.bak
pofile
pofile pathname
command
pofile (for print out file) prints out the contents of the file indicated by pathname. Logo prints the contents to the screen. An error occurs if you try to use pofile on a file that is already open.
pofile prints to the screen but not to the current writer.
Example:
?pofile "winter
to greet
pr [Mitts are in the hall]
end
===
Managing Various Files
load
load pathname
command
The load command loads the contents of the file indicated by pathname into the workspace, as if you typed it directly from top level. An error occurs if the file does not exist.
After Logo loads the contents of a file, it looks for a variable called startup. If one exists, Logo executes its contents.
Demons armed with when while a file loads do not run until the whole file has been read. A demon's action can therefore call a procedure the file defines further down, or load another file. A startup runs after that, with demons live as they are at top level.
Example:
?load "winter
; Loads all procedures and variables from winter
save
save pathname
command
The save command creates a file and saves in it all unburied procedures and variables and all properties in the workspace. An error occurs if the file you name already exists. In this case, you should first either erase the existing file using erasefile or rename it using rename.
Example:
?to greet pr [Fresh coffee] end
?save "winter
; Saves all procedures and variables to winter
savel
savel name pathname
savel namelist pathname
command
The savel command saves the procedures named in name or namelist, and all the unburied variables and properties in the workspace to pathname. An error occurs if any of the procedures named in name or namelist do not exist in the workspace, or if the file you name already exists. In this case, you should first either erase the existing file using erasefile or rename it using rename. This command is useful for saving a portion of your workspace onto a SD Card. Compare it with save.
Example:
?to greet pr [Hello] end
?to farewell pr [Goodbye] end
?savel [greet farewell] "greetings
; Saves only greet and farewell procedures
loadpic
loadpic pathname
command
The loadpic command loads the picture named by pathname onto the graphics screen. Logo will only load 8-bit indexed color BMP onto the graphics screen. The palette will be changed to match that in the BMP file.
Example:
; Load a grey jay image onto the graphics screen
?loadpic "greyjay.bmp
savepic
savepic pathname
command
savepic saves the graphics screen into the file indicated by pathname. You can retrieve the screen later using loadpic. The image is saved as a 8-bit indexed color BMP (.bmp) file.
Example:
; Draw something then save the screen
?repeat 4 [fd 50 rt 90]
?savepic "rink.bmp
dribble
dribble file
command
dribble starts the process of sending a copy of the characters displayed on the text screen to file. dribble records interactions between the PicoCalc and the person at the keyboard. dribble automatically opens file. nodribble stops the process of dribbling. You cannot use setread or setwrite with a dribble file while still dribbling. However, once a dribble file on disk has been closed with nodribble, you can treat it like any other file. You can then open it, read from it, or write to it. Note that only one dribble file can be open at one time.
Example:
?dribble "session.txt
?pr [Hello from the rink!]
Hello from the rink!
?nodribble
; session.txt now contains the interaction
nodribble
nodribble
command
nodribble turns off the dribble feature so a copy of the characters from the screen will no longer be sent to the file or device named previously by the dribble command.
Example:
?dribble "log.txt
?pr [Logging session...]
?nodribble
===
Input and Output to Files, Network Connections and Devices
These commands and operations allow you to open files and network connections, read from and write to them, and close them when you are finished.
A network connection is specified as a word in this format: host:port. For example, to open a connection to the host myserver.com on port 8080, you would use the word "myserver.com:8080. The host can be a domain name or an IP address in dotted decimal format (for example, "192.168.1.100:8080). The port must be a number between 1 and 65535. If this pattern is not matched, Logo assumes you are referring to a file.
The screen and keyboard are devices and are special. You cannot open or close them. To select the keyboard as the current reader, use the setread command with the empty list as input. To select the screen as the current writer, use the setwrite command with the empty list as input.
allopen
allopen
operation
allopen outputs a list of all files and network connections currently open. The open command opens a file or a network connection.
Example:
?open "notes
?open "log.txt
?show allopen
[notes log.txt]
close
close target
command
The close command closes the named file or network connection that is currently open. See open to open a file or network connection. An error occurs if you try to use close with a file or network connection that is not open. An error also occurs if you try to use close with a file or network connection that is opened by the dribble command.
Example:
?open "log.txt
?setwrite "log.txt
?pr [Session started after snow clearing]
?setwrite []
?close "log.txt
closeall
closeall
command
The closeall command closes all files and network connections that are currently open. Dribble files are not closed with closeall. Use the open and close commands to open and close one file at a time. If you try to use closeall when no files or network connections are open, it is ignored.
See nodribble for closing dribble files.
Example:
?open "data.txt
?open "log.txt
?closeall
?show allopen
[]
filelen
filelen file
operation
filelen outputs the length in bytes of the contents of the file indicated by file. The file must be open to use this primitive. An error occurs if the file is not open.
This procedure returns an error if the file is a network connection.
Example:
?open "notes
?pr filelen "notes
1024
?close "notes
open
open target
command
The open command opens target so it can send or receive characters. You must open a file or network connection before you can access it. You can open a maximum of eight files or network connections at once.
If the file named by target does not exist, then open creates the file.
If target is a host:port, open establishes a TCP connection to the specified host:port. An error occurs if the connection cannot be established.
Once a file or network connection is open, you use setread and setwrite to set the read and write for the file or network connection. Then you can use the standard reading and writing commands access the file or to communicate over the network.
When you finish using Logo, you must close all files and network connections that are open, see the close, closeall and goodbye commands.
Example:
?open "log.txt
?setwrite "log.txt
?pr [Logging from the basement workbench]
?setwrite []
?close "log.txt
reader
reader
operation
reader outputs the current file or network connection that is open for reading. You can change the current read file with the setread primitive. reader returns the name of the file, the network connection or the empty list if the current reader is the keyboard.
Example:
?pr reader
[]
?open "recipes.txt
?setread "recipes.txt
?pr reader
recipes.txt
readpos
readpos
operation
readpos (for read position) outputs the position in the current reader. An error occurs if the current reader is a network connection or the keyboard. To set the position in the read file, see the setreadpos command.
Example:
?open "notes
?setread "notes
?pr readpos
0
?ignore readword
?pr readpos
12
setread
setread target
command
setread sets the current reader to target. After you give this command, readlist, readword, readchar, and readchars read information from this file or network connection.
Before you use setread, you must open the file or network connection with the open command. An error occurs if the file or network connection is not open.
To set the current reader back to the keyboard, give setread the empty list as input.
Example:
?open "recipes.txt
?setread "recipes.txt
?pr readword
buttertarts
?setread []
; back to reading from keyboard
setreadpos
setreadpos integer
command
setreadpos sets the read position in the current reader. The integer should be a number between 0 and the current length of the file. An error occurs if it is not in this range. An error also occurs if the current reader is a network connection or the keyboard.
See readpos for more information about the setreadpos command.
Example:
?open "notes
?setread "notes
?setreadpos 0
?pr readpos
0
setwrite
setwrite target
command
setwrite sets the current writer to the file, network connection or the screen you name. The primitives print, type, and show all print to the current writer. You cannot use setwrite unless the file or network connection has previously been opened.
Before you use setwrite, you must open the file or network connection with the open command. An error occurs if the file or network connection is not open.
To restore the screen as the current writer, use the setwrite command with the empty list as input.
The commands
po,poall,pon,pons,pops,pot,pots, andpofileall print to the screen but not to the current writer.
Example:
?open "log.txt
?setwrite "log.txt
?pr [Logged from the rink]
?setwrite []
?close "log.txt
setwritepos
setwritepos integer
command
setwritepos sets the write position in the current file. This command is useful when modifying information in a file. You must set the write position to a number that is between 0 and the end-of-file position. If you try to set it somewhere out of this range, an error occurs. An error also occurs if you try to set the write position when the current writer is the screen or a network connection.
To check the current position, use the writepos command.
Example:
?open "log.txt
?setwrite "log.txt
?pr [line one]
?pr writepos
9
?setwritepos 0
?pr writepos
0
writepos
writepos
operation
writepos (for write position) outputs where in the current write file the the next character will be written. An error occurs if the current writer is the screen or a network connection.
Example:
?open "log.txt
?setwrite "log.txt
?pr [Hydro]
?pr writepos
6
writer
writer
operation
writer outputs the current file, network connection, or the empty list if the current writer is the screen. Compare this with the allopen operation.
Example:
?pr writer
[]
?open "log.txt
?setwrite "log.txt
?pr writer
log.txt
?setwrite []
.timeout
.timeout
operation
timeout outputs the current timeout value in milliseconds for network operations. A timeout value of 0 indicates that there is no timeout.
Example:
?pr .timeout
0
?.settimeout 5000
?pr .timeout
5000
.settimeout
.settimeout integer
command
The settimeout command sets the timeout value for network operations to integer milliseconds. A timeout value of 0 indicates that there is no timeout. If a network operation does not complete within the specified time, it fails with an error.
Example:
; Set 5 second timeout for network operations
?.settimeout 5000
?pr .timeout
5000
===
Time Management
ticks
ticks
operation
ticks outputs the number of milliseconds since the device started, as a plain number. It's a monotonic clock - it never jumps backward and isn't affected by settime/setdate - so it's the right tool for timing an interval: read it before and after, and subtract. It wraps around after about 49.7 days of continuous uptime.
Logo numbers are single-precision floating point, which represents integers exactly only up to 16,777,216. After about 4.66 hours of uptime,
tickscan no longer distinguish every individual millisecond - fine for timing anything from a game frame to a long wait, but not for measuring uptime itself to the millisecond after that long.
Example:
?make "start ticks
?repeat 100000 [pr "tick]
...
?pr (ticks - :start)
842
; that repeat took 842 milliseconds
date
date
operation
date outputs the current date as a list in the form [year month day], where year is the full year (e.g., 2026), month is a number from 1 to 12, and day is a number from 1 to 31.
Example:
?show date
[2026 7 1]
; July 1, after the fireworks are swept up
?make "d date
?pr se [Year:] item 1 :d
Year: 2026
time
time
operation
time outputs the current time as a list in the form [hour minute second], where hour is a number from 0 to 23, minute is a number from 0 to 59, and second is a number from 0 to 59.
Example:
?show time
[14 30 0]
; 2:30 PM Eastern Time
?make "t time
?pr se [Hour:] item 1 :t
Hour: 14
setdate
setdate [year month day]
command
The setdate command sets the current date to the specified year, month, and day. An error occurs if the date is not valid.
Example:
; Set date to a long-weekend morning
?setdate [2026 7 1]
?show date
[2026 7 1]
settime
settime [hour minute second]
command
The settime command sets the current time to the specified hour, minute, and second. An error occurs if the time is not valid.
Example:
; Set time to noon
?settime [12 0 0]
?show time
[12 0 0]
===
WiFi Management
These procedures allow you to manage the WiFi connection of the device.
wifi? (wifip)
wifi?
operation
wifi? outputs true if the WiFi is connected, otherwise it outputs false.
Example:
?pr wifi?
false
?wifi.connect "TimHortonsWiFi "double-double
?pr wifi?
true
tls? (tlsp)
tls?
operation
tls? outputs true if this board can open https:// connections, otherwise it outputs false. TLS needs PSRAM to hold the handshake buffers, so a board with WiFi but no PSRAM (such as the Pico 2 W) can still use http.get on http:// URLs while tls? outputs false. Unlike wifi?, this reports a fixed hardware capability rather than the live connection state.
Example:
?pr tls?
true
?if tls? [pr http.get "https://example.com/] [pr [no https on this board]]
wifi.mac
wifi.mac
operation
wifi.mac outputs the MAC address of the device as a word of six hexadecimal numbers separated by colons, each between 0 and FF. The MAC address is a unique identifier for the device on a network.
Example
?wifi.mac
00:00:5E:12:34:56
wifi.connect
wifi.connect ssid password
command
The wifi.connect command connects to the WiFi network with the given ssid and password. If the connection is successful, wifi? will output true. If the connection fails, an error message is displayed.
wifi.connect waits for the network to answer, which can take several seconds — and up to thirty if the network is out of range. Use wifi.start instead when you would rather carry on working while the connection is made.
Example:
?wifi.connect "TimHortonsWiFi "double-double
?pr wifi?
true
?pr wifi.ssid
TimHortonsWiFi
wifi.start
wifi.start ssid password
command
The wifi.start command begins connecting to the WiFi network with the given ssid and password, but does not wait for the result. Unlike wifi.connect, it finishes at once, so the rest of your program — or your startup file — keeps running while the network connects in the background.
Use wifi? or wifi.status to find out how the connection is getting on. A when demon is the tidiest way to wait for it, because it lets you do something the moment the network is ready:
?wifi.start "TimHortonsWiFi "double-double
?when [wifi?] [network.ntp -4 pr [clock set]]
The demon fires once, as soon as the device has an address on the network. Until then wifi? outputs false, and the rest of your program runs normally.
wifi.start keeps trying until it succeeds, so it copes with a network that needs several attempts or is not yet switched on. It stops only for a refused password, or when you call wifi.disconnect. wifi.status says how it is getting on; an error is displayed only when the attempt cannot be started at all, such as on a board with no radio.
wifi.status
wifi.status
operation
wifi.status outputs a word describing the state of the WiFi connection:
| Output | Meaning |
|---|---|
off | Not connected, and nothing is being attempted |
connecting | Looking for the network and joining it |
noaddress | Joined the network; waiting for it to assign an address |
connected | Connected, with an address on the network |
notfound | The network was not found |
badpassword | The network refused the password |
failed | Joining the network failed for some other reason |
The first four are the stages of a connection in progress; the last three say where it went wrong.
Joining a network is often unreliable: an attempt may fail outright, be missed by a scan, or join and then never get around to assigning an address. On some networks it simply takes several tries. So wifi.start keeps trying — whenever a connection stops making progress for a few seconds, it quietly begins another attempt, and it goes on doing so until it connects. This means a device left switched on will join the network whenever it becomes reachable, even if that is some time later.
Two things stop it: wifi.disconnect, and a refused password, since that will not come right however many times it is tried.
So failed, notfound and noaddress are ordinary sights along the way and do not mean Pico Logo has given up — each one is simply the attempt that just ended. Only badpassword is final. If you want to report a problem without repeating yourself every few seconds, count the attempts rather than printing on each one:
make "tries 0
when [equal? wifi.status "failed] ~
[make "tries :tries + 1
if :tries = 5 [pr [Still cannot join the network]]]
Example:
?wifi.start "TimHortonsWiFi "double-double
?pr wifi.status
connecting
?pr wifi.status
noaddress
?pr wifi.status
connected
To watch the whole sequence — useful when a connection is not coming up, and the fastest way to see which stage it stalls at:
make "last "off
wifi.start "TimHortonsWiFi "double-double
when [not equal? wifi.status :last] [make "last wifi.status pr :last]
wifi.status outputs connected in exactly the cases where wifi? outputs true. It is most useful after wifi.start, where it tells you whether an attempt is still going or has given up — something wifi? alone cannot say.
Example:
?wifi.start "TimHortonsWiFi "double-double
?pr wifi.status
connecting
?pr wifi.status
connected
wifi.ip
wifi.ip
operation
wifi.ip outputs the current IP address assigned to the device by the WiFi network. If the device is not connected to a WiFi network, wifi.ip outputs the empty list.
Example:
?wifi.connect "TimHortonsWiFi "double-double
?pr wifi.ip
192.168.1.42
wifi.ssid
wifi.ssid
operation
wifi.ssid outputs the SSID of the WiFi network to which the device is currently connected. If the device is not connected to a WiFi network, wifi.ssid outputs the empty list.
Example:
?pr wifi.ssid
TimHortonsWiFi
wifi.disconnect
wifi.disconnect
command
The wifi.disconnect command disconnects the device from the current WiFi network. After executing this command, wifi? will output false.
Example:
?pr wifi?
true
?wifi.disconnect
?pr wifi?
false
wifi.scan
wifi.scan
operation
wifi.scan outputs a list of available WiFi networks. Each network is represented as a sublist containing the SSID and signal strength.
Example:
?show wifi.scan
[[TimHortonsWiFi -65] [HarveysWiFi -72] [HomeNetwork -48]]
wifi.sethostname
wifi.sethostname name
command
The wifi.sethostname command sets the device's network name to name. Once WiFi is connected, other machines on the same network can reach the device by this name with .local added — for example http://picologo.local — instead of its numeric IP address. The same name is given to the router as the device's DHCP hostname.
name must be a word of letters, digits, and hyphens (a hyphen may not be the first or last character), up to 32 characters long, and must not contain a dot: the .local part is added automatically. The default name is picologo, and it returns to picologo each time the device restarts, so put a wifi.sethostname line in your startup file to keep a custom name. If WiFi is already connected, the new name takes effect immediately.
Example:
?wifi.sethostname "picocalc
?wifi.connect "TimHortonsWiFi "double-double
?pr wifi.hostname
picocalc
Now http://picocalc.local reaches the device from a phone or laptop on the same network.
wifi.hostname
wifi.hostname
operation
wifi.hostname outputs the device's current network name (the name set by wifi.sethostname, without the .local suffix). The default is picologo.
Example:
?pr wifi.hostname
picologo
?wifi.sethostname "myturtle
?pr wifi.hostname
myturtle
===
Network Operations
network.ping
network.ping ipaddress
operation
The network.ping operation sends a ping request to the specified ipaddress. It outputs the number of milliseconds it took for the response if a response is received, otherwise it outputs -1. The ipaddress should be in standard dotted-decimal notation (e.g., "192.168.1.1").
Example:
?pr network.ping "8.8.8.8
14
?pr network.ping "192.168.1.1
2
network.resolve
network.resolve hostname
operation
The network.resolve operation takes a hostname (e.g., "www.example.com") and outputs its corresponding IP address in dotted-decimal notation. If the hostname cannot be resolved, it outputs the empty list.
Example:
?pr network.resolve "canada.ca
192.197.168.105
network.ntp
network.ntp
(network.ntp timezone)
(network.ntp timezone serveraddress)
operation
The network.ntp operation synchronizes the device's internal clock with a Network Time Protocol (NTP) server. It outputs true if the synchronization is successful, otherwise it outputs false. Ensure that the device is connected to a WiFi network before using this command.
If the synchronization succeeds, the device's date and time are updated to match the NTP server. If timezone is provided, the time is adjusted accordingly; otherwise, it defaults to UTC. timezone is specified in hours relative to UTC (e.g., -5 for EST, 1 for CET), and can include fractional hours (e.g., 5.5 for IST).
The default NTP server is "pool.ntp.org". You can specify a different server by providing its serveraddress as an argument.
Example:
; Sync time with EST timezone (UTC-5)
?pr (network.ntp -5)
true
?show time
[14 30 0]
===
HTTP Operations
These operations fetch and send data over the web. They require that the device is connected to a WiFi network (see wifi.connect); an error occurs if WiFi is not available or not connected.
A url is a word beginning with http:// or https://, for example "http://example.com/index.html, "https://example.com/index.html, or "http://example.com:8080/api. If no port is given, port 80 is used for http:// and port 443 for https://.
For an https:// url the connection is encrypted with TLS, and the server's certificate is verified: its chain must lead to one of the certificate authorities built into Pico Logo, and the certificate must match the host name in the url. If verification fails, the request fails to complete (an error you can trap with catch), exactly like a refused connection. Only a trimmed set of common certificate authorities is built in, so a host using an uncommon authority may not be trusted even though it is otherwise valid. Certificate expiry is not checked, because the device has no reliable clock at the time of the request.
Request headers are supplied as extra inputs in name/value pairs, using the parenthesised form of the operation, for example (http.get "http://example.com/ "Accept "text/plain). Each name and value is a word. Recall that a quoted word may contain - and / without a backslash (so "Content-Type and "text/plain are each a single word); a value that contains spaces cannot be written as a quoted word.
Each operation performs one complete request: it opens a connection, sends the request, reads the whole response, and closes the connection. The connection is not left open and does not appear in allopen. The read timeout is governed by .settimeout; if the server does not respond in time, the operation produces an error.
A request can fail to complete (the host cannot be resolved, the connection is refused, the request times out, or the response is larger than the device can hold). In these cases the operation produces an error, which you can trap with catch. A request that completes produces a result even when the server reports a problem: a "404 Not Found" response is not an error; the operation outputs the server's response body, and http.status outputs 404.
The response body is held as a single word. There is a fixed maximum size; a response whose body exceeds it produces an error rather than a truncated result.
After any successful request, http.status and http.header describe the most recent request. Making another request replaces this information.
http.get
http.get url
(http.get url name1 value1 name2 value2 ...)
operation
The http.get operation sends an HTTP GET request to url and outputs the response body as a word.
In the second form, the extra inputs are request headers given as name/value word pairs, for example (http.get "http://example.com/ "Accept "text/plain "User-Agent "PicoLogo). An odd number of header inputs (a name with no value) produces an error.
If the request cannot be completed, an error occurs. If the request completes, use http.status to find out whether the server reported success.
Example:
?pr http.get "http://example.com/menu.txt
Today's special is poutine.
?pr http.status
200
http.post
http.post url data
(http.post url data name1 value1 name2 value2 ...)
operation
The http.post operation sends an HTTP POST request to url with data as the request body, and outputs the response body as a word. data may be a word or a list; a list is sent as its members separated by spaces, with no outer brackets.
In the second form, the extra inputs are request headers given as name/value word pairs, in the same way as http.get.
If the request cannot be completed, an error occurs. If the request completes, use http.status to find out whether the server reported success.
Example:
?pr (http.post "http://example.com/orders [pierogi fries] "Content-Type "text/plain)
Order received.
?pr http.status
201
http.put
http.put url data
(http.put url data name1 value1 name2 value2 ...)
operation
The http.put operation sends an HTTP PUT request to url with data as the request body, and outputs the response body as a word. It behaves exactly like http.post apart from the request method: data may be a word or a list, and the parenthesised form takes request headers as name/value word pairs.
PUT is normally used to create or replace the resource at url with the supplied data.
If the request cannot be completed, an error occurs. If the request completes, use http.status to find out whether the server reported success.
Example:
?pr (http.put "http://example.com/orders/17 [pierogi fries] "Content-Type "text/plain)
Order updated.
?pr http.status
200
http.patch
http.patch url data
(http.patch url data name1 value1 name2 value2 ...)
operation
The http.patch operation sends an HTTP PATCH request to url with data as the request body, and outputs the response body as a word. It behaves exactly like http.post apart from the request method: data may be a word or a list, and the parenthesised form takes request headers as name/value word pairs.
PATCH is normally used to apply a partial update to the resource at url.
If the request cannot be completed, an error occurs. If the request completes, use http.status to find out whether the server reported success.
Example:
?pr (http.patch "http://example.com/orders/17 [fries] "Content-Type "text/plain)
Order updated.
?pr http.status
200
http.delete
http.delete url
(http.delete url name1 value1 name2 value2 ...)
operation
The http.delete operation sends an HTTP DELETE request to url and outputs the response body as a word. It sends no request body; in the parenthesised form the extra inputs are request headers given as name/value word pairs, in the same way as http.get.
DELETE is normally used to remove the resource at url.
If the request cannot be completed, an error occurs. If the request completes, use http.status to find out whether the server reported success.
Example:
?pr http.delete "http://example.com/orders/17
Order deleted.
?pr http.status
204
http.status
http.status
operation
The http.status operation outputs the numeric HTTP status code of the most recently completed request made by http.get, http.post, http.put, http.patch, or http.delete, for example 200 for success or 404 for "Not Found". If no request has been made, it outputs the empty list.
Example:
?pr http.get "http://example.com/missing.txt
Not Found
?pr http.status
404
http.header
http.header name
operation
The http.header operation outputs the value of the response header named name from the most recently completed request, as a word. The name is matched without regard to upper and lower case. If the most recent response did not include that header, or if no request has been made, it outputs the empty list.
Example:
?pr http.get "http://example.com/menu.txt
Today's special is poutine.
?pr http.header "Content-Type
text/plain
?pr http.header "X-Not-Present
[]
===
HTTP Server
These primitives let a Logo program answer HTTP requests — controlling the turtle from a phone browser, or transferring files without a cable — on the WiFi boards (the Pico 2 W and the Pico Plus 2 W).
The server handles one request at a time. http.listen starts it; each request that arrives makes http.request? output true, and a handler answers it with http.respond (see the request accessors and http.respond that follow). The usual shape is a when demon, which keeps serving while the program runs and while you type at the prompt:
wifi.connect "TimHortonsWiFi "double-double
http.listen 80
when [http.request?] [
if equal? http.path "/forward [fd 20]
if equal? http.path "/right [rt 90]
http.respond 200 sentence [heading is] heading
]
pr sentence [serving at] wifi.ip
With mDNS naming (see wifi.sethostname), the browser can reach the device at http://picologo.local instead of its IP address.
The server closes automatically when a running program stops with an error — so a serving program that errors stops serving; rerun it to restart. clearscreen does not close it: a program that redraws the screen keeps serving. Requests that are malformed, that stall halfway, whose body is too large, or that no handler answers within ten seconds are given an automatic error response and closed, so a connection is never left hanging.
http.listen
http.listen port
command
The http.listen command starts the HTTP server listening on port (a whole number from 1 to 65535). A browser reaches a server on port 80 without a port suffix in the address. It is an error to http.listen when the WiFi is not connected. Calling http.listen again on the same port does nothing, so a program that starts with it can be rerun freely; calling it on a different port moves the server to that port.
Example:
?wifi.connect "TimHortonsWiFi "double-double
?http.listen 80
?pr sentence [serving at] wifi.ip
serving at 192.168.1.42
http.unlisten
http.unlisten
command
The http.unlisten command stops the HTTP server and drops any connection in progress. It does nothing if the server is not listening. The server is also stopped automatically when a program unwinds to the prompt with an error.
Example:
?http.unlisten
http.request? (http.requestp)
http.request?
operation
http.request? outputs true when a complete request has arrived and is waiting for a response, otherwise it outputs false. It is the condition of the serving when demon, and can equally drive an ordinary polling loop:
http.listen 80
forever [if http.request? [http.respond 200 "hello]]
Example:
?pr http.request?
false
http.method
http.method
operation
http.method outputs the HTTP method of the pending request — GET, POST, PUT, and so on — as a word. It is an error to use it when no request is pending (see http.request?).
Example:
when [http.request?] [
if equal? http.method "GET [http.respond 200 "hello]
]
http.path
http.path
operation
http.path outputs the path of the pending request as a word, with any percent-escapes (such as %20 for a space) decoded and the query string removed. For a request to /turtle/forward?steps=20 it outputs /turtle/forward. It is an error to use it when no request is pending.
Example:
when [http.request?] [
if equal? http.path "/forward [fd 20]
http.respond 200 "ok
]
http.query
http.query
operation
http.query outputs the query string of the pending request — the part after the ? — as a word, or the empty word if the request had no query string. For a request to /draw?colour=red&size=3 it outputs colour=red&size=3. The parts can then be split apart in Logo. It is an error to use it when no request is pending.
Example:
?pr http.query
steps=20&turn=left
http.body
http.body
operation
http.body outputs the body of the pending request as a word, or the empty word for a request with no body (such as a GET). It is an error to use it when no request is pending. It is also an error if the body was too large to hold in memory (a large upload); use http.savebody to stream such a body straight to a file instead.
Example:
when [http.request?] [
if equal? http.method "POST [make "note http.body]
http.respond 200 "saved
]
http.reqheader
http.reqheader name
operation
http.reqheader outputs the value of the request header named name as a word, matching name without regard to upper and lower case. If the pending request has no such header it outputs the empty list. It is an error to use it when no request is pending. This is how a handler reads a shared-secret header to protect against unwanted callers.
Example:
when [http.request?] [
ifelse equal? http.reqheader "X-Key "swordfish ~
[http.respond 200 "welcome] ~
[http.respond 403 "no]
]
http.remote
http.remote
operation
http.remote outputs the IP address of the client that made the pending request, as a word, useful for logging or greeting. It is an error to use it when no request is pending.
Example:
?pr http.remote
192.168.1.87
http.respond
http.respond status body
(http.respond status body name1 value1 ...)
command
The http.respond command answers the pending request and closes the connection. status is the HTTP status code (such as 200 for success or 404 for not found), and body is a word or list sent as the response body, formatted as print would show it. The response is sent with Content-Type: text/plain; charset=utf-8 unless you override it.
In the parenthesised form, the extra inputs are name / value word pairs added as response headers — the same convention as (http.get url name value ...). Supplying a Content-Type header replaces the default, so an HTML page displays correctly in a browser. It is an error to use http.respond when no request is pending.
Example:
when [http.request?] [
http.respond 200 sentence [heading is] heading
]
Serving HTML built with http.element (see below), overriding the content type:
when [http.request?] [
(http.respond 200 http.element "h1 [Hello from Pico Logo] "Content-Type "text/html)
]
http.respondfile
http.respondfile status path
(http.respondfile status path name1 value1 ...)
command
The http.respondfile command answers the pending request with the contents of the file named path as the response body, then closes the connection. The file is sent in small pieces, so it can be any size and may contain binary data (such as a picture) — nothing is limited by the size of memory. The response is sent with Content-Type: application/octet-stream unless you override it with a Content-Type header in the parenthesised form.
If the file does not exist, http.respondfile reports an ordinary error and leaves the request pending, so a handler can catch it and answer with a 404 instead. A path containing .. is rejected. It is an error to use http.respondfile when no request is pending.
Example — a tiny file server that also serves a not-found page:
when [http.request?] [
ifelse file? http.path ~
[http.respondfile 200 http.path] ~
[http.respond 404 [not found]]
]
http.savebody
http.savebody path
command
The http.savebody command writes the body of the pending request to the file named path, streaming it straight to storage in small pieces. This is how you receive an uploaded file (for example from curl -T): the upload can be any size and may be binary, even larger than would fit in memory. The request stays pending afterwards, so the handler still finishes by answering with http.respond. A path containing .. is rejected, and it is an error to use http.savebody when no request is pending.
Example — accept uploads with PUT and serve files with GET:
when [http.request?] [
if equal? http.method "PUT [http.savebody http.path http.respond 201 "saved]
if equal? http.method "GET [http.respondfile 200 http.path]
]
Upload and download from a computer on the same network:
curl -T invaders http://picologo.local/invaders
curl -o copy.txt http://picologo.local/notes.txt
http.element
http.element tag content
(http.element tag content name1 value1 ...)
operation
http.element builds an HTML element as a word: <tag>content</tag>. content is a word or a list; a list is formatted as print would show it (its spaces come through and its outer brackets are dropped), and because the result is a word, elements nest by passing one http.element as the content of another.
In the parenthesised form the extra inputs are name / value word pairs added as attributes, so (http.element "a "forward "href "/forward) builds <a href=/forward>forward</a>. This spares you from spelling out the angle brackets with char 60 and char 62, which the Logo lexer would otherwise require. Attribute values are single words; because the lexer treats = and : as delimiters, escape them with a backslash inside a value (for example "margin\=0).
Example:
?pr http.element "h1 [Pico Logo Turtle]
<h1>Pico Logo Turtle</h1>
?pr (http.element "p (http.element "a "left "href "/left))
<p><a href=/left>left</a></p>
The inner element needs its own parentheses so its attribute pair belongs to it rather than to the outer element.
===
Property Lists
erprops
erprops
command
erprops (for erase properties) erases all properties from the workspace. To check which property lists are currently in the workspace, use pps. Use remprop to remove properties one at a time from the workspace.
Example:
?pprop "loonie "value "one
?erprops
?pr gprop "loonie "value
[]
gprop
gprop name property
operation
gprop (for get property) outputs the value of property of name. If there is no such property, gprop outputs the empty list.
Example:
?pprop "toque "season "winter
?pprop "toque "drawer "hall
?pr gprop "toque "season
winter
?pr gprop "toque "pom
[]
plist
plist name
operation
plist outputs the property list associated with name. This is a list of property names paired with their values, in the form [prop1 vall prop2 val2 ...].
Example:
?pprop "ferry "status "delayed
?pprop "ferry "dock "three
?show plist "ferry
[status delayed dock three]
pprop
pprop name property object
command
The pprop (for put property) command gives name property with value object. Note that erall erases procedures, variables, and properties. Use remprop to erase properties one at a time or erprops to erase them all at once.
Example:
?pprop "buttertart "filling "raisins
?pprop "buttertart "debate "lively
?pr gprop "buttertart "filling
raisins
?show plist "buttertart
[filling raisins debate lively]
pps
pps
command
The pps (for print properties) command prints the property lists of everything in the workspace.
Example:
?pprop "loonie "value "one
?pprop "toonie "value "two
?pps
plist "loonie [value one]
plist "toonie [value two]
remprop
remprop name property
command
The remprop (for remove property) command removes property from the property list of name.
Example:
?pprop "snowroute "starts "midnight
?pprop "snowroute "zone "blue
?remprop "snowroute "zone
?show plist "snowroute
[starts midnight]
===
JSON
A JSON document is held as text - typically the word returned by http.get. json.get reads values straight out of that text, so even a large response (which is kept in PSRAM) can be queried without copying the whole document into the workspace.
json.get
json.get document path
operation
json.get outputs the value found by following path into document. Document is a word containing JSON text. Path is a list of steps: a word selects a member of an object by key (case-sensitive, as in JSON), and a number selects an element of an array by position (1-based, like item).
A string value is output as a word with its JSON escapes resolved; a number is output as a numeric word (usable directly in arithmetic); true and false are output as the words true and false; and null is output as the empty list. A nested object or array is output as its raw JSON text, which can be passed back to json.get to read further. If any step does not match, json.get outputs the empty list. An empty path outputs the whole document.
Example:
?make "person json.get http.get "https\://example.com/me []
?show json.get :person [name]
Blair
?show json.get :person [tags 2]
c
?show json.get :person [address city]
Ottawa
?show json.get :person [missing]
[]
json.count
json.count value
operation
json.count outputs the number of elements in a JSON array, or the number of members in a JSON object, where value is a word containing that JSON text. A scalar value outputs 0, and the empty list - the result of json.get for a missing path or JSON null - also outputs 0, so json.count json.get ... can be used directly as a loop bound.
Example:
?make "person json.get http.get "https\://example.com/me []
?show json.count json.get :person [tags]
3
?for [i 1 [json.count json.get :person [tags]]] [pr json.get :person (list "tags :i)]
logo
c
rp2350
json.object
(json.object key1 value1 key2 value2 ...)
operation
json.object builds a JSON object from the given key/value pairs. Each key must be a word. A value may be a word (output as a JSON string), a number, the words true or false, the empty list (output as null), a list (output as a JSON array), or another json.object or json.array. The result is passed to json.make to produce JSON text. Give the inputs as quoted words rather than inside a list, so values containing /, - or spaces are kept intact.
See json.array and json.make.
Example:
?show json.make (json.object "name "Blair "age 42)
{"name":"Blair","age":42}
json.array
(json.array value1 value2 ...)
operation
json.array builds a JSON array from the given values, each encoded in the same way as a json.object value. The result is passed to json.make to produce JSON text. An empty array is (json.array).
See json.object and json.make.
Example:
?show json.make (json.array "logo "c "rp2350)
["logo","c","rp2350"]
json.make
json.make value
operation
json.make outputs the JSON text for value. Value is usually built with json.object and json.array, but may also be a plain Logo value: a word becomes a JSON string (a word that is a valid JSON number becomes a number, and true/false become JSON booleans), a number becomes a JSON number, a list becomes a JSON array, and the empty list becomes null. String values are escaped as required by JSON, and numbers JSON cannot represent (infinities and NaN) become null.
Example:
?show json.make (json.object "name "Blair "tags (json.array "logo "c))
{"name":"Blair","tags":["logo","c"]}
?pr (http.post "http://example.com/people json.make (json.object "name "Blair) "Content-Type "application/json)
===
Device Specific
battery
battery
operation
The battery operation returns a list where the first value is the percent remaining in the battery and the second value is true if the battery is currently charging.
Example:
?show battery
[78 false]
?pr se [Battery:] item 1 battery
Battery: 78
goodbye
goodbye
command
goodbye closes all open files and powers off the device. If the device does not support this capability, an error is displayed.
Example:
; Safely shut down the PicoCalc
?pr [Saving workspace...]
?save "session
?goodbye
.bootsel
.bootsel
command
.bootsel closes all open files and network connections and reboots the device into its USB bootloader (BOOTSEL mode), so a new firmware image can be copied onto it. The device disconnects from Logo immediately. If the device does not support this capability, an error is displayed.
Example:
; Reboot into BOOTSEL to flash new firmware
?.bootsel
===
Appendix A: Useful Tools
The procedures presented here are for your convenience when constructing your own procedures. Some of them were defined as examples for primitives and others appear here for the first time. These procedures are in the logo archive in the release. You can copy the contents of the archive into the root directory of the device's internal storage (or onto a /sd card and copy them across). A sample startup file is also included to load these tools.
Graphics Tools
These procedures are found in the file graphics_tools.
arcr and arcl
arcr radius degrees
arc1 radius degrees
command
arcr and arcl draw right and left turn arcs, respectively. Their inputs are
- the radius of the circle from which the arc is taken
- the degrees of the arc (the length of the edge)
circler and circlel
circler radius
circlel radius
command
circler and circlel draw right and left turn circles with a specified radius as input.
Math Tools
These procedures are found in the file math_tools.
divisor?
divisor? number1 number2
operation
divisor? indicates (true or false) whether number1 divides evenly into number2.
Program Logic or Debugging Tools
These procedures are found in the file program_tools.
sort
sort arg list
operation
sort takes list of words and outputs them alphabetically.
===
Appendix B: Parsing
When you type a line at Logo, it recognizes the characters as words and lists, and builds a list with is Logo’s internal representation of the line. This process is called parsing. The list is similar to the list that would be output by readlist. This section will help you understand how lines are parsed.
Words
A word is made up of characters. Here are some examples of words:
- Hello
- x
- 314
- 3.14
- 1e4
- R2D2
- Piglatin
- Pig.latin
- Pig-latin (typed as
Pig\-Latin) - Hi there (typed as
Hi\ there) - Who?
- !NOW!
- St*rs (typed as
St\*rs)
Each character is an element of the word. The word Hen3ry contains six elements:
H e n 3 r y
Words can contain any character and this includes alphanumeric characters, spaces, delimiters, tabs, and punctuation. Delimiters must be escaped by a backslash "\" character.
Delimiters and Spacing
A word is usually delimited only by spaces or tabs: That is, there is a space or tab before the word and a space or tab after the word; they set the word off from the rest of line. There are a few other delimiting characters:
[ ] ( ) + - * / = < >
You need not type a space between a word and any of these characters. For example, to find out how this line is parsed:
if 1<2[print(3+4)/5][print :x+6]
type
?to testit
>if 1<2[print(3+4)/5][print :x+6]
>end
?po "testit
to testit
if 1 < 2 [print (3 + 4) / 5] [print :x + 6]
end
And if you define a procedure to contain a line in the first form, you will see that Logo has converted it into the second.
To treat any of the characters mentioned above as a normal alphabetic character, put a backslash "\" before it. For example:
?print "fish\+chips
fish+chips
?print "butter\ tart
butter tart
Note that the quotation mark character (") and the colon (:not word delimiters.
You can also have an empty word, which is a word with elements. You type in the empty word by typing ".
Two delimiters are exceptions inside a quoted word: '/' and '-'. You can use them without a backslash and Logo treats them as normal characters. The '/' is convenient for file names and URLs, and '-' for hyphenated names such as HTTP header fields. For example:
?print "my/file/name
my/file/name
?print "Content-Type
Content-Type
Vertical Bars
Backslashing every delimiter one at a time is tedious when a word contains
several of them. As an alternative, enclose a run of characters in vertical
bars (|). Every character between the bars — including spaces, brackets,
parentheses, and the infix operators — is treated as though it were an
ordinary letter. The bars themselves are not part of the word.
?print "|New York|
New York
?print "|(a+b)|
(a+b)
?make "|my count| 10
?print :|my count|
10
?show count [|San Francisco| |New York|]
2
The bars are consumed when the word is read, so [|San Francisco| |New York|]
is a two-element list. (Printing does not restore the bars, so such a list
displays as [San Francisco New York].)
Bars may appear anywhere a word is read: bare words, quoted words ("),
variable references (:), and inside lists. Within bars, backslash still
works, and the only two characters that must be backslashed are the vertical
bar and the backslash themselves:
?print "|a\|b|
a|b
The two notations may be mixed freely; "3\[a\]b and "|3[a]b| produce the
same word.
Infix Procedures
The following characters are the names of infix procedures. You write the name between the two inputs, but Logo considers the procedures to have two inputs.
+ - * / = < >
Brackets and Parentheses
Left bracket ”[” and right bracket ”]” indicate the start and end of a list or sublist.
[Hello there, old chap]
[x y z]
[Hello]
[[House Maison] [Window Fenetre] [Dog Chien]]
[HAL [QRZ] [Belinda Moore]]
[1 [1 2] [17 2]]
The list [Hello there, old chap] contains four elements:
- Hello
- there
- old
- chap
Note that the list [1 [1 2] [17 2]] contains only three elements, not six. The second and third elements also are lists:
- 1
- [1 2]
- [17 2]
The list [], a list with no elements, is an empty list. There also exists an empty word, which is a word with no elements. You type in the empty word by typing a quotation mark followed by a space or a right bracket "]". See the equal? operation in for examples of both the empty list and the empty word.
Parentheses group things in ways Logo ordinarily would not, and vary the number of inputs for certain primitives.
If the end of a Logo line is reached (that is, the Enter key is pressed) and brackets are still open, Logo will ask for additional lines of input (prompted with "~") until the brackets are closed:
?repeat 4 [print [This [is [a [test
~]]]
This [is [a [test]]]
This [is [a [test]]]
This [is [a [test]]]
This [is [a [test]]]
If Logo finds a right bracket or parenthesis for which there was no corresponding left bracket or parenthesis, Logo returns an error:
?]print "ABC
Unexpected ']'
?print 2 + 3)
Unexpected ')'
A left bracket that is never closed is an error too. Because a semicolon comments out the rest of the line, a closing bracket written after one is not seen and the list is left open:
?show [a b
[ without ]
?show [a ; b]
[ without ]
Quotation Marks and Delimiters
Normally, you have to put a backslash () before the characters [,],(,), and \ itself. But the first character after a quotation mark (") does not need to have a backslash preceding it. For example:
?print "*
*
If a delimiter occupies any position but the first one after the quotation mark, it must have a backslash preceding it. For example:
?print "****
Not enough inputs to *
The exceptions are '/' and '-', which are always treated as normal characters in a quoted word (see Delimiters and Spacing), so "my/file/name and "Content-Type are each a single word.
The only exception to the above general rule is brackets ([ ]). If you want to put a quotation mark before a bracket, you must always include a backslash between the quotation mark and the bracket. For example:
?print "[
You don't say what to do with []
?print "\[
[
?repeat 4 [print "]
Four empty lines are produced since the "] is recognised as an emoty word followed by the closing bracket.
The Minus Sign
The way in which the minus sign "-” is parsed is also a little strange. The problem here is that one character is used to represent two different things:
- as part of a number to indicate that it is negative, as in
-3 - as a procedure of one input, called unary minus, which outputs the additive inverse of its input, as in
-XCORor-:DISTANCE - as a procedure of two inputs, which outputs the difference between its first input and its second, as in
7-3andXCOR-YCOR
The parser tries to be clever about this potential ambiguity and figure out which one was meant by the following rules:
- If the ”
-” immediately precedes a number, and follows any delimiter except right parenthesis ”)”, the number is parsed as a negative number. This allows the following behaviour:
print sum 20-20(parses as 20 minus 20)print 3*-4(parses as 3 times negative 4)print (3+4)-5(parses as 3 plus 4 minus 5)first [-3 4](outputs -3)
- If the ”
-” immediately precedes a word or left parenthesis ”(”, and follows any delimiter except right parenthesis, it is parsed as the unary minus procedure:
setpos list :x -:ysetpos list ycor -xcor
- In all other cases, ”
-” is parsed like the other infix characters-as a procedure with two inputs:
print 3-4(parses as 3 minus 4)print 3 - 4(parses exactly like the previous example)print - 3 4(procedurally the same as the previous example)
The right-parenthesis exception in rules 1 and 2 applies only when the ”)” is directly adjacent to the ”-” with no space between them. Once whitespace separates them, the space itself counts as the delimiter, so what follows the ”-” decides:
print (5+3)-2(parses as 8 minus 2 - the ”-” touches the ”)”)print (5+3) -2(parses as the two values 8 and -2 - the space before ”-” and the digit touching it make -2 a negative number)
This whitespace-sensitive reading matches established Logo convention: - glued to what follows it (but not to what precedes it) is negative or unary, while - surrounded by values on both sides is subtraction.
===
Appendix C: Useful Procedures
This Appendix contains procedures that are not primitives but are useful for various purposes. You can use these procedures as they are or modify them to suit your needs.
You can add these procedures to your startup file so they are always available when you start Logo. To do this, copy and paste the code into a file named startup and save it (save "startup) in the root directory of the device's internal storage.
Displaying Formatted Time
These procedures are for displaying the date and time in a more human-friendly format. The zeropad procedure adds a leading zero to numbers less than 10. The fdate and ftime procedures format the date and time, respectively, using zeropad to ensure that single-digit numbers are displayed with a leading zero.
to zeropad :n
if 2 > count :n [op word "0 :n]
op :n
end
to fdate
op reduce [[a b] (word :a "- :b)] map "zeropad date
end
to ftime
op reduce [[a b] (word :a ": :b)] map "zeropad time
end
WiFi Connection
This procedure connects to a WiFi network and then synchronizes the time with an NTP server. You can change the SSID, password, timezone (-5), and NTP server ("ca.pool.ntp.org) as needed.
to connect
if not wifi? [
wifi.connect "SSID "Password
]
if (network.ntp -5 "ca.pool.ntp.org) [
(pr [The time is] fdate ftime)
]
end
===
Appendix D: Error Messages
When error 35 ("I don't know how to ...") is reported at the prompt, Logo also suggests the closest primitive or procedure name if one is similar, for example Did you mean forward?.
| Number | Message |
|---|---|
| 1 | (procedure) is already defined |
| 2 | Number is too big |
| 3 | (symbol) isn't a procedure |
| 4 | (symbol) isn't a word |
| 5 | (procedure) can't be used at toplevel |
| 6 | (symbol) is a primitive |
| 7 | Can't find label (symbol) |
| 8 | Can't (symbol) from the editor |
| 9 | (symbol) is undefined |
| 10 | (procedure) didn't output to (symbol) |
| 11 | I'm having trouble with the disk |
| 12 | Disk full |
| 13 | Can't divide by zero |
| 14 | End of data |
| 15 | File already exists |
| 17 | File not found |
| 18 | File is the wrong type |
| 19 | Too few items in (list) |
| 20 | No more file buffers |
| 21 | Can't find a catch for (symbol) |
| 22 | (symbol) not found |
| 23 | Out of space |
| 24 | (procedure) can't be used in a procedure |
| 25 | (symbol) is not true or false |
| 26 | Pausing... |
| 27 | You're at toplevel |
| 28 | Stopped! |
| 29 | Not enough inputs to (procedure) |
| 30 | Too many inputs to (procedure) |
| 31 | Too much inside parenthesis |
| 32 | Too few items in (list) |
| 33 | Can only do that inside a procedure |
| 34 | Turtle out of bounds |
| 35 | I don't know how to (symbol) |
| 36 | (symbol) has no value |
| 37 | ) without ( |
| 38 | I don't know what to do with (symbol) |
| 39 | ] without [ |
| 40 | Disk is write-protected |
| 41 | (procedure) doesn't like (symbol) as input |
| 42 | (procedure) didn't output |
| 43 | I can't run (procedure) on this device |
| 44 | No file selected |
| 45 | File (file) not open |
| 46 | File (file) already open |
| 47 | File position out of range |
| 48 | Device unavailable |
| 50 | Already dribbling |
| 52 | Device (device) in use |
| 53 | File (file) too big |
| 55 | Subdirectory not found for (directory) |
| 56 | Subdirectory (directory) not empty |
| 57 | Can't open ip address and port (ip address and port) |
| 58 | I lost the network connection |
| 59 | Network connection not open |
| 60 | Network error occurred |
| 61 | Can't use (symbol) as a file or network connection |
| 62 | Invalid IP address or port (ip address and port) |
| 63 | Network connection already open |
| 64 | Can't (symbol) on a network connection |
| 65 | Network timeout occurred |
| 66 | Invalid network operation |
| 67 | Too many nested operations |
| 68 | I don't know about (procedure) |
| 69 | There is no SD card |
| 70 | Backup file must be on the SD card |
| 71 | Backup file is not valid for this device |
| 72 | [ without ] |
| !!! LOGO SYSTEM BUG !!! Should not occur. Please let me know. |
===
Appendix E: Colour Palette for Pico Logo
This is the colour palette for Pico Logo. The palette contains 256 colour numbers. The standard palette includes a range of colours across hues and includes greyscale colours.
The first 16 colour numbers are the used by the text screen. Each character on the text screen has a foreground colour and a background colour, each of which is a colour number. The colour used for the foreground and background can be changed using settextcolor. The default foreground colour number is 3 (white) and the default background colour number is 4 (dark background).
These colour numbers are assigned to the following purposes. You can change the colour stored in these colour numbers to customise the the text screen and editor's appearance:
| Colour Number | Purpose |
|---|---|
| 0 | Text foreground (0%) |
| 1 | Text foreground (33%) |
| 2 | Text foreground (66%) |
| 3 | Text foreground (100%) |
| 4 | Text background |
| 5 | Error messages |
| 6 | Strings ("word) |
| 7 | Commands |
| 8 | Procedure name (word after to) |
| 9 | Numbers |
| 10 | Comments |
| 11 | Variables (:name) |
| 12 | Keywords (to, end) |
| 13 | Bracket depth 1 |
| 14 | Bracket depth 2 |
| 15 | Bracket depth 3 |
The following 160 colour numbers are the default palette for Pico Logo, and changing these colour numbers should be avoided.
Colour numbers 176 through 247 are unallocated and can be used for your own purposes. You can change the colour stored in these colour numbers to create your own palette.
Colour numbers 248 through 253 hold the primary and secondary colours. Changing this range of colour numbers should be avoided.
Colour number 254 is used as the default pen colour. Colour number 255 contains the current background colour used on the graphics screen and is set using setbg.