Welcome to EcmaTurtle. There is no real manual yet, but I wrote this quick introduction for you.
Except for this first section, the contents of the manual can be accessed from within the program via the context help. When you place the cursor over a known command in the source code editor, the related section is shown.
EcmaTurtle is an educational tool and a toy. Its main focus is centered around turtle graphics. Commands similar to those found in the Logo Programming Language are provided, but JavaScript is used as the programming language instead. Because JavaScript is very flexible, you can use most programming paradigms in your programs.
Although I tried to include a set of useful example programs, EcmaTurtle was not made for autodidact study. It is a tool for teachers, that will guide their students through the learning process.
If you are on your own, I recommend you take a look at the Learning Area of the MDN web site. You can also get help from real people on the IRC Network. You will probably want to join ##javascript on Freenode.
Hopefully, the UI of EcmaTurtle is self-explanatory, but a few aspects may not be as intuitive:
Tracesection and can be replayed.
If you run into problems, be it my software not working right or you having questions, feel free to contact me.
The following sections are used in the program as context specific help.
The links will only work on this very page, if JavaScript is enabled in your browser:
Set the cursor on a command in the source code above to get help on it.
JavaScript functions provided by EcmaTurtle:
The scope of an object (or variable, function) is the region in the program, where it is "visible"and this can be accessed. The top level is the "global scope", where your program and its functions live in. Code within curly braces gets its own new scope. While objects outside the local scope can be accessed from the inside, code outside of the scope cannot access local objects.
var myGlobalVariable = 1; function func( myArgument ) { var myLocalVariable = myArgument; myGlobalVariable = myLocalVariable; } console.log(myGlobalVariable); // Output: "1" func(2); console.log(myGlobalVariable); // Output: "2" console.log(myLocalVariable); // Uncaught ReferenceError: myLocalVariable is not defined console.log(myArgument); // Uncaught ReferenceError: myArgument is not defined
It is possible to re-use a name, that already exists outside of the current scope. This makes access to the outside object impossible. It is also quesionable, if this is a good idea:
function x() { const y = 1; console.log(y); function z() { const y = 2; console.log(y); } z(); } x(); // Output: "1", "2"
Variables declared with var are put into memory during the compile phase, before the program is started. Therfore, those variables are available, before they seemingly have been declared, as if they were automagically moved to the top of the scope. This can be prevented by never using the outdated var instruction, but instead using let (which was added to JavaScript at a later time), thus preventing nasty surprises:
function func() { console.log(my_var); console.log(my_let); var my_var = "This will be logged to the console."; let my_let = "Will trigger a Reference Error."; }
JavaScript is a very powerful language. Unfortunately, it has some really strange quirks, that can easily trip unexpirienced programmers, sometimes even experts are scratching their heads. It also allows you to do things, that are not always smart to do. Simpler code is safer in general, and easier to understand, when you come back to it a long time later.
Therefore, I recommend, you stick to certain coding styles and refrain from writing clever constructs. Here are a few hints, that will make your code easier to debug and will prevent certain mistakes from happenening in the first place:
if (something == true) do_another_thing();To prevent forgetting to add the braces, when you add code to the true branch later, format it either like so:
if (something == true) do_another_thing();Preferrably be strict and use curly braces:
if (something == true) { do_another_thing(); }
i = i + 1; // Increase i by oneit should be something like:
i = i + 1; // Select next entry
are inactive parts of a source code, helping the reader to understand, what's going on.
/* This is a multi-line comment */ const y = 1; // The rest of this line is a comment. /* This type of comment, can wrap around // this type of comment */
are lists of values, which can be accessed by their index.
const myArray = [ 1, 2, "three", {"four": 4} ]; for( let i=0 ; i<myArray.length ; ++i ) { console.log( myArray[i] ); } // Output: // 1 // 2 // three // {four: 4}
can either group a set commands (scope) or be a list of key/value pairs (objects).
The if statement will always execute the next command, if the condition evaluates to true:
if (condition == true) doSomething();
In order to have it execute several commands, one can combine them into a "block", that behaves like it was one single command:
if (condition == true) { doSomething(); doAnotherThing(); }
const myObject = { "key1": "value1", "key2": "value2", }; console.log( myObject.key1 ); // Output: value1 console.log( myObject["key2"] ); // Output: value2 myObject["key3"] = "value3"; console.log(myObject.key3); // Output: value3 const key_name = "key4"; myObject[key_name] = "value4"; console.log(myObject.key4); // Output: value4
The variable myObject contains a reference to the data within the object and will usually not change throughout the lifetime of the variable. Therefore it should be declared const. The contents (properties) of an object are always variable.
Used for functions and their arguments or in mathematical expressions.
function myFunc( someArgument ) { console.log(someArgument); } myFunc("Text"); // Output: Text
const someValue = (1 + 2) / 3;
Comparison operators return Boolean values (true/false).
if (var1 == var2) { do_something(); } const true_or_not = (1 < 2); // Result: true
true also represents the value (+1), while false equals to zero:
const add_offset = true; const offset = 3; const value = 10 + (add_offset * offset); // Result: 13
Operators combine one, two or three values. Most of the time you will see arithmetical operators (const x = a + b;) or assignments (const x = 1;).
Like in mathematics, operators have different priorities, called "operator precedence". See the MDN link below for a list of all operators and their order of precedence.
const x = 1 + 2 * 3; // Result: 7 const x = (1 + 2) * 3; // Result: 9 const remainder = 7 % 3; // Modulo, remainder of division. Result: 1 const is_equal = (a == b); // Boolean operator (equality). Result: true/false
moves the turtle forward. If the turtle is "down", this will draw a line.
FD(10);
moves the turtle backwards. If the turtle is "down", this will draw a line.
BK(10);
turns the turtle to the left.
LT(90)
turns the turtle to the right.
RT(90)
lifts the turtle, so it will not draw a line, when moving.
UP()
Lowers the turtle, so it will draw a line, while moving.
DN()
Sets the pen to the home position (0|0) and the direction 0° (to the right).
DN()
Pushes position, direction, color, line width and pen up/down status to the stack.
PUSH()
Retreives position, direction, color, line width and pen up/down status from the stack.
POP()
Shows the pen.
SHOW()
Hides the pen
HIDE()
sets the line width. At 100% zoom, a unit is SCALE_FACTOR pixels on the screen.
WIDTH(1)
sets the drawing color. CSS color codes and names are allowed.
COLOR("red") COLOR("#f00") COLOR("#ff0000") COLOR("rgb(255,0,0)") COLOR("rgba(100%,0,0, 0.5)") COLOR("hsl(0,1,0.5)") COLOR("hsla(0,100%,50%, 0.5)")
sets the background color. CSS color codes and names are allowed
BACKGROUND("red") BACKGROUND("#f00") BACKGROUND("#ff0000") BACKGROUND("rgb(255,0,0)") BACKGROUND("rgba(100%,0,0, 0.5)") BACKGROUND("hsl(0,1,0.5)") BACKGROUND("hsla(0,100%,50%, 0.5)")
Repeats a block of commands a given number of times.
REPEAT 12 BEGIN do_this_12_times(); END
Starts a block of repeated commands.
REPEAT 12 BEGIN do_this_12_times(); END
Ends a block of repeated commands.
REPEAT 12 BEGIN do_this_12_times(); END
upadets the screen and pauses program execution.
SLEEP(1000)
shows, what has been drawn so far. Useful, when speed is set to "No animation".
UPDATE()
Clears the drawing, sets options.
RESET() RESET(NO_GRID) RESET(NO_GRID | NO_TURTLE) RESET(NO_GRID | NO_TURTLE | FULL_SPEED) RESET(NO_GRID | NO_TURTLE | NO_ANIMATION | NO_TRACE | NO_LOG)
RESET will enable all options, unless one or more flags prohibiting the option(s) are set.
Set execution speed as a delay between every command.
SPEED(33) SPEED(NO_ANIMATION) // No automatic update of the screen while running. // See RESET() and UPDATE()
toggles the grid on or off. The grid will never be saved when downloading the image.
GRID() // Turns the grid on GRID(ON) GRID(1) GRID(true) GRID(OFF) // Turns the grid off GRID(0) GRID(false)
returns a random value from 0..1 or min..max
let random_float = RND() // Returns values from 0 to 0.999... let random_integer = (2, 9) // Returns values from 2 to 9
returns the sinus of a value.
let y = SIN(45)
While JavaScript Math functions take angles in radians, Turtle functions use degrees:
const x = COS(45); const y = Math.sin(45 / 180 * Math.PI);
returns the cosinus of a value.
let x = COS(45)
While JavaScript Math functions take angles in radians, Turtle functions use degrees:
const x = COS(45); const y = Math.sin(45 / 180 * Math.PI);
returns the tangens of a value.
let y = TAN(45);
While JavaScript Math functions take angles in radians, Turtle functions use degrees:
const x = COS(45); const y = Math.sin(45 / 180 * Math.PI);
returns the cotangens of a value.
let x = COT(90);
While JavaScript Math functions take angles in radians, Turtle functions use degrees:
const x = COS(45); const y = Math.sin(45 / 180 * Math.PI);
returns the square root of a value.
let r = SQRT(4); // r will be 2
- the mathematical constant π.
let radians = degrees / 180 * PI; let degrees = radians * 180 / π; // The unicode charcter is allowed, too.
- the mathematical constant τ = 2π.
let radians = degrees / 360 * TAU; let degrees = radians * 360 / τ; // The unicode charcter is allowed, too.
defines a constant and assigns a value to it.
const my_string = "String"; const my_array = ["with", 1, 3, "mixed", "content"]; const my_object = { name:"My PC", type:"Notebook", GB_ram:8 };
It is a good idea to define all variables as const, if you don't intend to change their contents later. This prevents you from accidentially assigning values to it.
defines a variable for the current function. Initial values can also be set:
var π; var my_string = "String"; var my_array = ["with", 1, 3, "mixed", "content", my_string]; var my_object = { name:"My PC", type:"Notebook", GB_ram:8 };
defines a variable for the current scope.
Initial values can also be set:
let my_string = "String"; let my_array = ["with", 1, 3, "mixed", "content"]; let my_object = { name:"My PC", type:"Notebook", GB_ram:8 }; for( let i=0 ; i<MAX ; ++i ) { console.log(i); }
executes a command, if a given condition evaluates to true.
if (myVariable == 1) { console.log("Yay. It is 1."); } else { console.log("Nay. It isn't 1."); }
Executes the commands in the else branch, if the given condition evaluates to false.
if (myVariable == 1) { console.log("Yay. It is 1."); } else { console.log("Nay. It isn't 1."); }
will execute a block of commands, if the given variable equals to the case:
switch (command) { case "do_something": do_something(); break; case "do_another_thing": do_another_thing(); break; default: do_a_default_action(); }
In fact, a switch statement is similar to a combination of if and goto; The first case with a label equal to the switch variable will be jumped to, like in the following example:
if (command == "do_something") goto DO_SOMETHING; if (command == "do_another_thing") goto DO_ANOTHER_THING; goto DEFAULT; DO_SOMETHING: do_something(); goto SWITCH_END; // break; will jump to the end of a switch DO_ANOTHER_THING: do_another_thing(); goto SWITCH_END; // break; will jump to the end of a switch DEFAULT: do_a_default_action(); SWITCH_END: // Done.
Therefore, if the break; instruction is omitted, the next case block will be executed, too. This is called "fall through" and might be intended. It is a good idea, to place a comment explaining, that the fall through is intended and not a case of a forgotten break;
switch (command) { case "do_a": // Doing nothing here means, that do_a is effectively the same as do_b. // fall through case "do_b": do_something_only_if_a_or_b(); // fall through case "do_c": do_in_all_three_cases(); break; // Make sure, no other case blocks after this are executed. }
part of a switch statement, that is executed, when the switch variable is equal to the case label:
switch (command) { case "do_something": do_something(); break; case "do_another_thing": do_another_thing(); break; default: do_a_default_action(); }
part of a switch statement, that is executed, when no case applied:
switch (command) { case "do_something": do_something(); break; case "do_another_thing": do_another_thing(); break; default: do_a_default_action(); }
exits the current loop or switch and jumps to the next command after the loop/switch.
switch (command) { case "do_something": do_something(); break; // Do NOT execute the commands in the next case section case "do_another_thing": do_another_thing(); break; // Do NOT execute the commands in the default section default: do_a_default_action(); } jump_here_when_break_is_called();
let text = ""; for( let i=1 ; i<=10 ; ++i ) { if (i == 5) { break; // Exit the for loop alltogether } text = text + i; } console.log(text); // Expected output: "1234"
terminates execution of the statements in the current iteration of the current or labeled loop, and continues execution of the loop with the next iteration.
var text = ""; for( let i=0 ; i<10 ; ++i ) { if (i == 3) { continue; // Skip the rest of this iteration } text = text + i; } console.log(text); // Expected output: "012456789"
repeats a block of commands as long as a given condition evaluates to true.
for( initialization ; condition ; command list );
for( var i=0, text="" ; text.length<4 ; ++i, text+=i ); console.log(text); // Expected output: "1234"
Note, that commands in each section are separated by commas, not semicolons.
The above example is a bit unwieldy. Furthermore, the instruction or block after the for can also be executed in each iteration. The block will be executed before the instructions in the "command list" section.
It is common to use the sections in the for statement for counting the numbers of iterations and put the actual work in the block after the for:
let text = ""; for( let i=1 ; i<=4 ; ++i ) { text += i; } console.log(text); // Expected output: "1234"
for is pretty flexible. You can create an endless loop like so:
for(;;) { repeat_me_endlessly(); }
which is equal to:
while (true) { repeat_me_endlessly(); }
executes a block of commands as long as the condition evaluates to true
let we_are_running = true; while (we_are_running) { we_are_running = decide_if_we_keep_running(); }
One can use while to do the same as a for loop:
let counter = 1; let text = ""; while (counter <= 4) { text = text + counter; counter = counter + 1; } console.log(text); // Expected output: "1234"
Take care not to create unterminated (endless) loops in EcmaTurtle. It is not designed for this and may crash.
introduces a new "sub-program", which can be called from elsewhere.
function do_something() { console.log("Hello, world!"); } do_something(); console.log("Test"); do_something(); // Prints three lines: "Hello World!", "Test", "Hello, World!"
As in mathematics, functions can return values to the caller:
function add_numbers( n1, n2 ) { return n1 + n2; } const sum = add_numbers(1, 2); console.log(sum); // Expected output: 3
terminates the execution of a function and may return a value.
function compare( value1, value2 ) { if (value1 < value2) { return -1; } if (value1 > value2) { return +1; } return 0; }
If no return statement is used, the return value is undefined:
function do_something() { // Calculate things } const value = do_something(); console.log( typeof value ); // Expected output: "undefined"
short description
Example code
- Boolean flag. Equal to ON and +1
if (true) always_do_this(); GRID(true) GRID(ON) GRID(1)
- Boolean flag, equal to OFF and 0
if (false) never_do_this(); GRID(false) GRID(OFF) GRID(0)
short description
Example code
short description
Example code
short description
Example code