Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
December 25, 2021 10:22 pm GMT

100 Languages Speedrun: Episode 33: Logo

Logo is a programming language all the way from the 1960s aimed at teaching kids programming. The most notable feature of Logo are "turtle graphics" - simple commands that draw lines on screen by moving an imaginary "turtle".

One issue with covering Logo is that it's meant for interactive use in some Logo GUI environment, and these are platform specific and don't last very long, so every variant of Logo will be quite different. And it's not just their fancy features like 3D graphics, interactivity, and so on. Even very basic commands like like changing color are going to be different in each Logo.

I'll be using in-browser papert Logo, so all examples will work in papers. Different Logo implementations will need some adjustments. I'll try to mention when something is implementation-specific.

I'll post a few of the pictures generated by the programs - if you want to see some that I skipped, just try them out in papert.

Other Logo implementations I'll mention are SLogo (also in-browser), and ACSLogo for OSX.

Basic Drawing Commands

We're not printing anything, we're controlling a "turtle". A turtle has position on a screen as well as orientation.

To draw a square we can tell the turtle to move forward 50 steps, turn 90 degrees to the right, four times:

; Squareforward 50right 90forward 50right 90forward 50right 90forward 50right 90

Line comments use ;.

As these commands are a bit long, and we'll be using them all the time, there are shorter versions too. fd for forward, rt for right and lt for left:

; Trianglefd 60rt 120fd 60rt 120fd 60rt 120

Logo implementation differences

We can also control color and thickness of lines. In papert we can use color [R G B] and penwidth WIDTH. For very simple loops we can do repeat N [COMMANDS]:

; Blue Hexagon - Papertcscolor [200 200 255]penwidth 4repeat 6 [fd 60 rt 60]ht

Blue Hexagon

Logo programs tend to show the turtle on the screen. To show or hide the turtle we can use st and ht commands.

Logo doesn't clear the screen by default when you start the program, so if you want to do so, you should use cs command explicitly.

Anyway, here's the same program in JSLogo, which has RGB 0-100 instead of 0-255, and slightly different commands:

; Blue Hexagon - JSLogocssetpencolor [80 80 100]setpensize 4repeat 6 [fd 60 rt 60]ht

And here's more traditional ACSLogo, which only has fixed colors 0-15, and doesn't have comments:

cssetpencolor 15setpenwidth 4repeat 6 [fd 60 rt 60]ht

As you can see, there's zero hope of writing any kind of "portable" Logo programs.

Procedures

We can define procedures with to name ... end. Like this draws three letters I:

to draw_i  ; draw line  forward 10  penup  ; go to next character  right 90  forward 5  right 90  forward 10  ; reset to facing up, pen down  pendown  right 180endcsrepeat 3 [draw_i]

To move the turtle without touching the screen, we can use penup and pendown commands (or pu and pd).

Step by step:

  • turtle faces up, at some point, let's say (100, 100), Logo normally doesn't use coordinates at all, but let's say these are normal computer graphics coordinates (X points right, Y points down). Pen is down.
  • forward 10 makes turtle draw line up to (100, 90)
  • penup ends drawing, but we still need to position turtle at the next letter
  • right 90 and forward 5 makes turtle turn clockwise by 90 degrees (so it's pointing right for us) and advance to (105, 90) without drawing.
  • right 90 and forward 10 makes turtle turn clockwise by 90 degrees (so it's pointing down for us) and advance to (105, 100) without drawing.
  • pendown and right 180 makes turtle press the pen down turn clockwise by 180 degrees (so it's pointing up for us), so we end up 5 pixels to the right from where we started, in same orientation and pen state

Fizz

You can probably see where this is going, here's a program that says FIZZ three times:

to draw_i  fd 10 ; main stroke  ; go to next character  pu  rt 90 fd 5  rt 90 fd 10  ; reset pen state  pd  rt 180endto draw_f  fd 10 ; main line  rt 90 fd 5 ; top stroke  pu rt 180 fd 5 lt 90 fd 5; move to next stroke  pd lt 90 fd 5; middle stroke  ; go to next character  pu fd 5 rt 90 fd 5  ; reset pen state  pd  rt 180endto draw_z  rt 90 fd 5; bottom line  pu rt 180 fd 5 ; return  pd rt 120 fd 11 ; diagonal stroke  lt 120 fd 5 ; top line  ; advance to next character  pu rt 180 fd 5 rt 120 fd 11 lt 120 fd 10  ; reset pen state  pd lt 90endto draw_fizz  draw_f draw_i draw_z draw_zendcsrepeat 3 [draw_fizz]

Fizz

I could explain it step by step, but it's probably easier if you try to run it in Papert using "run slowly" button to see how turtle moves step by step.

As we didn't use any special commands, this program runs in JSLogo as well. It doesn't work with ACSLogo as it doesn't support comments, and it needs its GUI to define procedures.

Buzz

Drawing BUZZ is basically saem as drawing FIZZ, except loops work weird way - instead of drawing starting where the turtle is, the arc degrees radius command draws an arc around the turtle, starting where the turtle is facing and going up.

to draw_b  fd 2.5 ; main stroke a bit  arc 2.5 180 ; bottom loop  fd 5 ; more main stroke  arc 2.5 180 ; top loop  fd 2.5 ; finish main stroke  pu rt 180 fd 10 ; go back  ; go to next character  lt 90 fd 7  ; reset pen state  pd lt 90endto draw_u  pu fw 3 pd fd 7 ; left stroke  pu rt 90 fd 6 ; move to right stroke  pd rt 90 fd 7 ; right stroke  pu rt 90 fd 3 ; move to center of arc  pd rt 180 arc 3 180 ; arc  ; go to next character  pu fd 8 rt 90 fd 3  ; reset pen state  pd rt 180endto draw_z  rt 90 fd 5; bottom line  pu rt 180 fd 5 ; return  pd rt 120 fd 11 ; diagonal stroke  lt 120 fd 5 ; top line  ; advance to next character  pu rt 180 fd 5 rt 120 fd 11 lt 120 fd 10  ; reset pen state  pd lt 90endto draw_buzz  draw_b draw_u draw_z draw_zendcsrepeat 3 [draw_buzz]

Digits

Doing this 10 more times with proper loops for each digit would be a bit much, so let's do them in style of 7-segment display.

For 1 I'll use the I code instead to avoid awkward spacing.

Here's the code:

;  C; B D;  G; A E;  Fto seven_seg :a :b :c :d :e :f :g  ifelse :a [pd] [pu]  fd 5  ifelse :b [pd] [pu]  fd 5  rt 90  ifelse :c [pd] [pu]  fd 5  rt 90  ifelse :d [pd] [pu]  fd 5  ifelse :e [pd] [pu]  fd 5  rt 90  ifelse :f [pd] [pu]  fd 5  pu rt 90 fd 5 rt 90  ifelse :g [pd] [pu]  fd 5  pu fd 5 rt 90 fd 5 rt 180 pdendto draw_0  seven_seg true true true true true true falseendto draw_1  fd 10 pu  rt 90 fd 5  rt 90 fd 10  pd rt 180endto draw_2  seven_seg true false true true false true trueendto draw_3  seven_seg false false true true true true trueendto draw_4  seven_seg false true false true true false trueendto draw_5  seven_seg false true true false true true trueendto draw_6  seven_seg true true true false true true trueendto draw_7  seven_seg false false true true true false falseendto draw_8  seven_seg true true true true true true trueendto draw_9  seven_seg false true true true true true trueendto draw_digits  draw_0 draw_1 draw_2 draw_3 draw_4  draw_5 draw_6 draw_7 draw_8 draw_9endresetcsdraw_digitsht

And here are the digits:

Digits

As you can see procedures can take parameters, and ifelse condition [then] [else] can do some simple logic.

Numbers

To draw numbers we just need to add a bit of code and some recursion:

...to draw_digit :digit  if (:digit = 0) [draw_0]  if (:digit = 1) [draw_1]  if (:digit = 2) [draw_2]  if (:digit = 3) [draw_3]  if (:digit = 4) [draw_4]  if (:digit = 5) [draw_5]  if (:digit = 6) [draw_6]  if (:digit = 7) [draw_7]  if (:digit = 8) [draw_8]  if (:digit = 9) [draw_9]endto draw_number :number  make "a (:number % 10)  make "b (:number - :a)  make "c (:b / 10)  if (:c > 0) [draw_number :c]  draw_digit :aendresetcsdraw_number 42069ht

Numbers

make "var (...) is how you can assign variables. We need to use a bunch of extra variables, as Logo lacks integer division.

FizzBuzz

And here's the moment we've all been waiting for, the FizzBuzz in Logo!

Here's the complete program, mostly the code we wrote before:

;  C; B D;  G; A E;  Fto seven_seg :a :b :c :d :e :f :g  ifelse :a [pd] [pu]  fd 5  ifelse :b [pd] [pu]  fd 5  rt 90  ifelse :c [pd] [pu]  fd 5  rt 90  ifelse :d [pd] [pu]  fd 5  ifelse :e [pd] [pu]  fd 5  rt 90  ifelse :f [pd] [pu]  fd 5  pu rt 90 fd 5 rt 90  ifelse :g [pd] [pu]  fd 5  pu fd 5 rt 90 fd 5 rt 180 pdendto draw_0  seven_seg true true true true true true falseendto draw_1  fd 10 pu  rt 90 fd 5  rt 90 fd 10  pd rt 180endto draw_2  seven_seg true false true true false true trueendto draw_3  seven_seg false false true true true true trueendto draw_4  seven_seg false true false true true false trueendto draw_5  seven_seg false true true false true true trueendto draw_6  seven_seg true true true false true true trueendto draw_7  seven_seg false false true true true false falseendto draw_8  seven_seg true true true true true true trueendto draw_9  seven_seg false true true true true true trueendto draw_digit :digit  if (:digit = 0) [draw_0]  if (:digit = 1) [draw_1]  if (:digit = 2) [draw_2]  if (:digit = 3) [draw_3]  if (:digit = 4) [draw_4]  if (:digit = 5) [draw_5]  if (:digit = 6) [draw_6]  if (:digit = 7) [draw_7]  if (:digit = 8) [draw_8]  if (:digit = 9) [draw_9]endto draw_number :number  make "a (:number % 10)  make "b (:number - :a)  make "c (:b / 10)  if (:c > 0) [draw_number :c]  draw_digit :aendto draw_i  fd 10 ; main stroke  ; go to next character  pu  rt 90 fd 5  rt 90 fd 10  ; reset pen state  pd  rt 180endto draw_f  fd 10 ; main line  rt 90 fd 5 ; top stroke  pu rt 180 fd 5 lt 90 fd 5; move to next stroke  pd lt 90 fd 5; middle stroke  ; go to next character  pu fd 5 rt 90 fd 5  ; reset pen state  pd  rt 180endto draw_b  fd 2.5 ; main stroke a bit  arc 2.5 180 ; bottom loop  fd 5 ; more main stroke  arc 2.5 180 ; top loop  fd 2.5 ; finish main stroke  pu rt 180 fd 10 ; go back  ; go to next character  lt 90 fd 7  ; reset pen state  pd lt 90endto draw_u  pu fw 3 pd fd 7 ; left stroke  pu rt 90 fd 6 ; move to right stroke  pd rt 90 fd 7 ; right stroke  pu rt 90 fd 3 ; move to center of arc  pd rt 180 arc 3 180 ; arc  ; go to next character  pu fd 8 rt 90 fd 3  ; reset pen state  pd rt 180endto draw_z  rt 90 fd 5; bottom line  pu rt 180 fd 5 ; return  pd rt 120 fd 11 ; diagonal stroke  lt 120 fd 5 ; top line  ; advance to next character  pu rt 180 fd 5 rt 120 fd 11 lt 120 fd 10  ; reset pen state  pd lt 90endto draw_fizz  draw_f draw_i draw_z draw_zendto draw_buzz  draw_b draw_u draw_z draw_zendto draw_fizzbuzz  draw_fizz draw_buzzendto draw_line :i  setxy 15 (:i * 15)  ifelse (:i % 15 = 0) [draw_fizzbuzz] [    ifelse (:i % 5 = 0) [draw_buzz] [      ifelse (:i % 3 = 0) [draw_fizz] [draw_number :i]    ]  ]endresetcsmake "i 1repeat 30 [  draw_line :i  make "i (1 + :i)]ht

Which generates the FizzBuzz we want:

FizzBuzz

We had to do a few more things:

  • setxy x y moves the turtle to specific point on the screen - we use turtle position to go to the next letter, so we don't really know how far it went - it's a lot easier this way
  • make "i 1 - there's no for loops in Logo, so we make a weird while/for hybrid by defining i and increasing it 30 times

That's enough Logo for now.

Should you use Logo?

No.

Turtle graphics is "easier" for children only in some evil mirror universe where children's favorite subject is trigonometry. In this universe coordinate graphics with damn graph paper is drastically more approachable. And if you absolutely need to do turtle graphics, there's packages for that in every regular language anyway. Even disregarding turtle vs coordinate graphics issue, Logo is absolutely dreadful as a programming language, and learning Logo teaches no useful skill.

As for teaching programming to total beginners, the easiest ways are either HTML+CSS then Javascript path (the junior web dev path), or spreadsheets then SQL path (the business analyst path). Or do what ambitious bootcamps do and start with Ruby or Python, with proper TDD from right away and so on. These approaches are all proven to work. Nobody teaches programming with Logo, as it would be horribly ineffective and completely ridiculous.

Code

All code examples for the series will be in this repository.

Code for the Logo episode is available here.


Original Link: https://dev.to/taw/100-languages-speedrun-episode-33-logo-3gb8

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To