/* TURTLE GRAPHICS * Direct | JavaScript | Description * --------------+------------------+---------------------------- * FD n | FD(n) | Move pen n units forward * BK n | BK(n) | Move pen n units back * LT deg | LT(deg) | Turn pen deg degrees left * RT deg | RT(deg) | Turn pen deg degrees right * UP | UP() | Pen up - move only * DN | DN() | Pen down - draw * WIDTH w | WIDTH(w) | Set stroke width * COLOR c | COLOR("c") | Set drawing color */ /* Draws a colored square */ COLOR("red") FD(10) LT(90) COLOR("yellow") FD(10) LT(90) COLOR("green") FD(10) LT(90) COLOR("blue") FD(10) LT(90)
// You can loop over a section of code like so: REPEAT 12 BEGIN FD(10) LT(30) END
// REPEAT loops can be nested: REPEAT 6 BEGIN WIDTH(2) FD(10) LT(60) WIDTH(1) RT(45) REPEAT 12 BEGIN FD(2) RT(30) END LT(45) END
// Using constants makes the code easier to read and change: const nr_segments = 12 REPEAT nr_segments BEGIN FD(10) LT(360/nr_segments) END
/* Functions group instructions, that can be called from different * locations in the program. */ function nested_polygon( outer_steps, inner_steps ) { const outer_size = 10 const outer_width = 2 const outer_angle = 360/outer_steps const inner_size = 5 const inner_width = 1 const inner_angle = 360/inner_steps const inner_rotation = (outer_angle + inner_angle)/2 REPEAT outer_steps BEGIN WIDTH(outer_width) FD(outer_size) LT(outer_angle) RT(inner_rotation) WIDTH(inner_width) REPEAT inner_steps BEGIN FD(inner_size) RT(inner_angle) END LT(inner_rotation) END } nested_polygon(4, 3) nested_polygon(4, 5)
// Unlike constants, variables can change their contents in run time. const colors = [ // Define an array of strings "red", "yellow", "green", "cyan", "blue", "magenta", ]; var index = 0; // Counts through the colors WIDTH(5); UP(); RT(90); FD(11.5); LT(90); // Move down 11.5 units, BK(2) // centering the circle REPEAT 12 BEGIN index = index + 1 // Select next color // The colors[] array has a range of [0..5] in this example. // So we clamp index to values from 0 to (colors.length-1). // "%" is like "/", but the result is the remainder of the division: index = index % colors.length COLOR( colors[index] ) // Set the color DN() FD(4) // Draw line UP() FD(1) LT(30) FD(1) // Move to next line END
// "The code is the documentation." // - 1337 hax0r function recurse( distance, angle ) { if (distance > 0) { FD(distance); LT(angle); recurse(distance - 1, angle); } } function multiple( distance, angle, iterations ) { for( let i = 0 ; i < iterations ; ++i ) { recurse(distance, angle); } } const selected_variant = 0; switch (selected_variant) { case 1: recurse ( 20, 30 ); break; case 2: multiple( 20, 30, 3 ); break; case 3: recurse ( 10, 60 ); break; case 4: multiple( 10, 60, 3 ); break; default: throw Error("Oopsie..."); }
const angle_reduction = 0.8 const length_reduction = 0.65 const hex = "0123456789abcdef"; function draw_branch( angle = 50, length = 32 ) { if (length < 1) return; const brightness = Math.floor((32 - length)/5); COLOR("#6" + hex.charAt(brightness+2) + "0") WIDTH(length/2) FD(length) PUSH() LT(angle) draw_branch( angle *angle_reduction, length*length_reduction ) POP() PUSH() RT(angle) draw_branch( angle *angle_reduction, length*length_reduction ) POP() } RESET(NO_GRID) BACKGROUND("#030") LT(90) UP() BK(40) DN() draw_branch() HIDE()
/* EcmaTurtle provides you with a set of functions, like FD, REPEAT, etc. * Let's take a look, how REPEAT is implemented: */ function MyRepeat( times, callback ) { while (times > 0) { await callback(); // Please ignore the "await". times = times - 1; } } /* The function takes another function as parameter (callback) and * executes that function repeatedly. It is used like so: */ const do_something = async function() { // My parser can't handle callbacks yet //...Xunction do_something() { FD(10) LT(30) } MyRepeat(12, do_something);
/* You don't have to declare a function for using it with repeat; * instead, use "anomnymous functions", which are declared on the spot: */ REPEAT( 12, async function() { // Ignore the "async" for now FD(10) LT(30) } );
// Arrow functions can be used in similar fashion to anonymous functions: REPEAT( 12, ()=>{ FD(10) LT(30) });
/* In reality, all the code you enter here is JavaScript. Before execution, * parts of your code will be replaced with real JS code, for example: * * REPEAT 12 BEGIN * FD(10) LT(30) * END * * will be turned into the following code: */ // REPEAT --> "REPEAT(" REPEAT(12, ()=>{ // BEGIN --> ", ()=>{" FD(10); LT(30); }); // END --> "});" /* The take-away of this lesson is, that EcmaTurtle's replacements may do * something silly, causing your program to crash. Of course I did some * testing and most things will work just fine. If your program crashes * for no apparent reason and you suspect EcmaTurtle to be the culprit, * you can check the actual code being run; It is dumped to the Developer * Console of your browser before execution. */
//...SPEED(NO_ANIMATION) const max_segments = 15 // 16 hexadecimal digits const rotation_speed = 5; BACKGROUND("black") function draw_circles( nr_segments, rotation ) { RESET(NO_GRID | NO_TURTLE | FULL_SPEED) LT(rotation) const hex_digits = "0123456789abcdef"; const R = hex_digits.charAt(nr_segments * (rotation % 3 == 0)); const G = hex_digits.charAt(nr_segments * (rotation % 3 == 1)); const B = hex_digits.charAt(nr_segments * (rotation % 3 == 2)); COLOR("#"+R+G+B); for( let r=0 ; r<nr_segments ; ++r ) { for( let i=0 ; i<36 ; ++i ) { FD(2) LT(10) } RT(360/nr_segments) } RT(360/max_segments) SLEEP(33) UPDATE() } let r = 0 while (true) { for( let s=2 ; s<max_segments ; ++s ) { draw_circles(s, r) r += rotation_speed } for( let s=max_segments ; s>2 ; --s ) { draw_circles(s, r) r += rotation_speed } }
const nr_segments = 36 const radius = 50 function circle( radius, nr_segments ) { const circumference = 2*radius*π const segment_length = circumference/nr_segments UP() FD(radius) LT(90) BK(segment_length/2) DN() REPEAT nr_segments BEGIN FD(segment_length) LT(360/nr_segments) END UP() FD(segment_length/2) RT(90) BK(radius) DN() } function coordinates( radius ) { const length = 2*(radius+10) const dash_length = 2; const nr_dashes = length/(2*dash_length)+1 const distance = length/2 + dash_length/2 LT(90) UP() BK(distance) DN() REPEAT nr_dashes BEGIN FD(2) UP() FD(2) DN() END UP() BK(distance+dash_length) DN() RT(90) UP() BK(distance) DN() REPEAT nr_dashes BEGIN FD(2) UP() FD(2) DN() END UP() BK(distance+dash_length) DN() } function triangle(radius, angle) { const x = COS(angle)*radius const y = SIN(angle)*radius FD(x) LT(90) FD(y) LT(90+angle) FD(radius) LT(180-angle) } WIDTH(1) COLOR("black") coordinates(radius) WIDTH(4) COLOR("black") circle(radius, nr_segments) WIDTH(2) COLOR("red") triangle(radius, 30) WIDTH(2) COLOR("green") triangle(radius, -45) WIDTH(2) COLOR("blue") triangle(radius, 120)
const letter_width = 9; const letter_gap = 4; const curvature = 5; const text = "Hello, World!"; function draw_character( character ) { const w = letter_width // Typical letter width switch (character.toUpperCase()) { case "H": LT(90) FD(20) UP() BK(10) DN() RT(90) FD(w) LT(90) UP() FD(10) DN() BK(20) RT(90) break case "E": LT(90) FD(20) RT(90) FD(w) UP() RT(90) FD(10) RT(90) FD(3) DN() FD(w-3) UP() LT(90) FD(10) LT(90) DN() FD(w) break case "L": LT(90) FD(20) UP() BK(20) DN() RT(90) FD(w) break case "O": UP() LT(90) FD(10) DN() REPEAT 3 BEGIN FD(4) RT(30) END RT(30) REPEAT 3 BEGIN FD(4) RT(30) END LT(30) REPEAT 3 BEGIN FD(4) RT(30) END RT(30) REPEAT 3 BEGIN FD(4) RT(30) END LT(30) UP() BK(10) RT(90) FD(11) DN() break case ",": LT(75) BK(5) FD(5) REPEAT 6 BEGIN FD(1) LT(60) END RT(75) break //case "W": //break //case "R": //break //case "D": //break case "!": LT(90) FD(1) UP() FD(2) DN() FD(17) UP() BK(20) DN() RT(90) break case " ": UP() FD(8) DN() break default: COLOR("red") FD(w) COLOR("BLACK") } // switch UP() FD(letter_gap) DN() } function draw_text( text, angle=0 ) { // Move half the text width to the left UP() REPEAT text.length BEGIN BK((letter_width+letter_gap)/2) END FD( text.length * ((360 - curvature) / 360) ) DN() // Turn left half as much, as the loop below will turn right in total const length = text.length - 1 // The "," has virtually no width - 1 // The "!" has virtually no width ; LT( length*angle/2 ) // Draw each character for( let i=0 ; i<text.length ; ++i ) { const character = text.charAt(i); draw_character(character); RT(angle) // Turn right after each char, creating an arc } } WIDTH(3) draw_text(text, curvature) HIDE()
// Bannkreis GRID(OFF) BACKGROUND("black") const radius = 50 const nr_segments = 360/5 const segment_length = 2*π*radius/nr_segments COLOR("#642") WIDTH(22) LT(72*3) UP() FD(radius) LT(90) BK(segment_length/2) DN() REPEAT nr_segments BEGIN FD(segment_length) LT(360/nr_segments) END UP() FD(segment_length/2) RT(90) BK(radius) DN() LT(72*3) UP() LT(90) FD(16.2) RT(90) BK(50) DN() COLOR("black") WIDTH(33) REPEAT 5 BEGIN FD(38); UP(); FD(2); DN() FD(60) RT(180*4/5) END COLOR("#ca0") WIDTH(1.5) REPEAT 5 BEGIN FD(38); UP(); FD(3.25); DN() FD(58.25) RT(180*4/5) END RT(180*1/5/2) UP() FD(10) DN() LT(180*1/5/2) REPEAT 5 BEGIN FD(27.5); UP(); FD(3.25); DN() FD(49.75) RT(180 *4/5) END HIDE()
// New Program