I'm working on modernizing Rosetta Code's infrastructure. Starting with communications. Please accept this time-limited open invite to RC's Slack.. --Michael Mol (talk) 20:59, 30 May 2020 (UTC)

# Simple turtle graphics

Simple turtle graphics
You are encouraged to solve this task according to the task description, using any language you may know.

The first turtle graphic discussed in Mindstorms: Children, Computers, and Powerful Ideas by Seymour Papert is a simple drawing of a house. It is a square with a triangle on top for the roof.

For a slightly more advanced audience, a more practical introduction to turtle graphics might be to draw a bar chart.

See image here: https://i.imgur.com/B7YbTbZ.png

• Create a function (or subroutine) that uses turtle graphics to draw a house of a specified size as described above. Optionally make it lovely by adding details such as, for example, doors and windows.
• Create a function (or subroutine) that takes a list (array, vector) of non-negative numbers and draws a bar chart from them, scaled to fit exactly in a square of a specified size. The enclosing square need not be drawn.
• Both functions should return the turtle to the location it was at and facing in the same direction as it was immediately before the function was executed.

## Action!

`INCLUDE "D2:TURTLE.ACT" ;from the Action! Tool Kit PROC Rectangle(INT w,h)  BYTE i   FOR i=1 TO 2  DO    Forward(h)    Left(90)    Forward(w)    Left(90)  ODRETURN PROC Square(INT w)  Rectangle(w,w)RETURN PROC Triangle(INT w)  BYTE i   FOR i=1 TO 3  DO    Forward(w)    Right(120)  ODRETURN PROC House(INT w)  Left(90)  Square(w)  Triangle(w)  Right(90)RETURN INT FUNC GetMax(INT ARRAY a INT count)  INT i,max   max=0  FOR i=0 TO count-1  DO    IF a(i)>max THEN      max=a(i)    FI  ODRETURN (max) PROC BarChart(INT ARRAY a INT count,w)  INT max,st,i   IF count=0 THEN RETURN FI  max=GetMax(a,count)  st=w/count  Right(90)  FOR i=0 TO count-1  DO    Rectangle(a(i)*w/max,st)    Forward(st)  OD  Left(180)  Forward(w)RETURN PROC Main()  BYTE CH=\$02FC,COLOR1=\$02C5,COLOR2=\$02C6  INT ARRAY a=[50 33 200 130 50]   Graphics(8+16)  COLOR1=\$0C  COLOR2=\$02   Color=1  SetTurtle(150,110,90)  House(75)   Color=0  Right(90)  Forward(5)  Left(90)   Color=1  BarChart(a,5,100)  Right(90)  Forward(5)  Right(90)   DO UNTIL CH#\$FF OD  CH=\$FFRETURN`
Output:

` with Ada.Text_IO; use Ada.Text_IO;with Ada.Characters; use Ada.Characters;with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;with Ada.Strings; use Ada.Strings; -- procedure main - begins program executionprocedure main is    type Sketch_Pad is array(1 .. 50, 1 .. 50) of Character;    thePen : Boolean := True; -- pen raised by default    sketch : Sketch_Pad;    ycorr, xcorr : Integer := 25;     -- specifications    function penPosition(thePen : in out Boolean) return String;    procedure initGrid(sketch : in out Sketch_Pad);    procedure commandMenu(thePen : in out Boolean; xcorr : in out Integer;                          ycorr : in out Integer);    procedure showMenu(xcorr : in out Integer; ycorr : in out Integer;                       thePen : in out Boolean; sketch : in Sketch_Pad);    procedure moveCursor(thePen : in Boolean; sketch : in out Sketch_Pad;                         xcorr : in out Integer; ycorr : in out Integer;                         ch : in Integer);    procedure showGrid(sketch : in Sketch_Pad);     -- procedure initGrid - creates the sketchpad and initializes elements    procedure initGrid(sketch : in out Sketch_Pad) is    begin        sketch := (others => (others => ' '));    end initGrid;     -- procedure showMenu - displays the menu for the application    procedure showMenu(xcorr : in out Integer; ycorr : in out Integer;                       thePen : in out Boolean; sketch : in Sketch_Pad) is         choice : Integer := 0;    begin        while choice /= 4 loop            Set_Col(15);            Put("TURTLE GRAPHICS APPLICATION");            Set_Col(15);            Put("===========================");            New_Line(2);             Put_Line("Enter 1 to print the grid map");            Put_Line("Enter 2 for command menu");            Put_Line("Enter 3 to raise pen up / down");            Put_Line("Enter 4 to exit the application");            choice := integer'value(Get_Line);             exit when choice = 4;             case choice is                when 1 => showGrid(sketch);                when 2 => commandMenu(thePen, xcorr, ycorr);                when 3 => Put_Line("Pen is "                              & penPosition(thePen));                when others => Put_Line("Invalid input");            end case;        end loop;    end showMenu;     -- function penPosition - checks changes the state of whether the pen is    -- raised up or down. If value is True, pen is rasied up    function penPosition(thePen : in out Boolean) return String is        str1 : constant String := "raised UP";        str2 : constant String := "raised DOWN";    begin        if thePen = True then            thePen := False;            return str2;        else            thePen := True;        end if;         return str1;    end penPosition;     -- procedure command menu - provides a list of directions for the turtle    -- to move along the grid    procedure commandMenu(thePen : in out Boolean; xcorr : in out Integer;                          ycorr : in  out Integer) is         choice : Integer := 0;    begin        while choice <= 0 or choice > 5 loop            Set_Col(15);            Put("Command Menu");            Set_Col(15);            Put("============");            New_Line(2);             Put_Line("To move North enter 1");            Put_Line("To move South enter 2");            Put_Line("To move East enter 3");            Put_Line("To move West enter 4");            Put_Line("To return to previous menu enter 5");            choice := integer'value(Get_Line);             case choice is                when 1 => moveCursor(thePen, sketch, xcorr, ycorr, choice);                when 2 => moveCursor(thePen, sketch, xcorr, ycorr, choice);                when 3 => moveCursor(thePen, sketch, xcorr, ycorr, choice);                when 4 => moveCursor(thePen, sketch, xcorr, ycorr, choice);                when 5 => showMenu(xcorr, ycorr, thePen, sketch);                when others => Put_Line("Invalid choice");            end case;        end loop;    end commandMenu;      -- procedure moveCursor - moves the cursor around the board by taking the    -- x and y coordinates from the user. If the pen is down, a character is    -- printed at that location. If the pen is up, nothing is printed but the    -- cursor still moves to that position    procedure moveCursor(thePen : in Boolean; sketch : in out Sketch_Pad;                         xcorr : in out Integer; ycorr : in out Integer;                         ch : in Integer) is     begin        if thePen = True then -- pen up so move cursor but do not draw            case ch is                when 1 => xcorr := xcorr - 1; ycorr := ycorr;                    sketch(xcorr, ycorr) := ' ';                when 2 => xcorr := xcorr + 1; ycorr := ycorr;                    sketch(xcorr, ycorr) := ' ';                when 3 => xcorr := xcorr; ycorr := ycorr + 1;                    sketch(xcorr, ycorr) := ' ';                when 4 => xcorr := xcorr; ycorr := ycorr - 1;                    sketch(xcorr, ycorr) := ' ';                when others => Put("Unreachable Code");            end case;         else -- pen is down so move cursor and draw            case ch is                when 1 => xcorr := xcorr - 1; ycorr := ycorr;                    sketch(xcorr, ycorr) := '#';                when 2 => xcorr := xcorr + 1; ycorr := ycorr;                    sketch(xcorr, ycorr) := '#';                when 3 => xcorr := xcorr; ycorr := ycorr + 1;                    sketch(xcorr, ycorr) := '#';                when 4 => xcorr := xcorr; ycorr := ycorr - 1;                    sketch(xcorr, ycorr) := '#';                when others => Put("Unreachable Code");            end case;        end if;    end moveCursor;     -- procedure showGrid - prints the sketchpad showing the plotted moves    procedure showGrid(sketch : in Sketch_Pad) is    begin        New_Line;         for I in sketch'Range(1) loop            for J in sketch'Range(2) loop                Put(character'image(sketch(I,J)));            end loop;            New_Line;        end loop;        New_Line;    end showGrid; begin    New_Line;     initGrid(sketch);    showMenu(xcorr, ycorr, thePen, sketch);    New_Line;end main; `

## J

Translation of: Logo

Prerequisites (requires a network connection or, for a non-networked system, significant technical savvy), and assumes user is running the a recent version of J's qtide (perhaps J 9.3):

`   ;install each cut 'gl2 gles github:zerowords/tgsjo'`

Implementation (note that this is meant to be copied and pasted to a file which J will load, rather than being typed in line by line -- manual typing would work if no errors were made, but that would be a painstaking approach):

`load'zerowords/tgsjo'rotR   0 0 _90translate 0 0 _40clearscreen ''createTurtle 0 0 0 rectangle=: {{    2 repeats {{ 'width height'=. y        forward height        left 90        forward width         left 90 }} y}} square=: {{size=. y     rectangle size,size}} triangle=:{{  3 repeats {{size=. y        forward size         right 120}} y}} house=:{{size=. y    left 90    square size    triangle size    right 90}} barchart=: {{'lst size'=. y    if.#lst do.        scale=. size%>./lst        width=. size%#lst        right 90        for_j. lst do.            rectangle (j * scale),width            forward width        end.        back size        left 90    end.}} penColor Redhouse 150pen 0right 90forward 10left 90pen 1 [ penColor Bluebarchart 0.5 0.3333 2 1.3 0.5; 200pen 0left 90forward 10left 270pen 1`

Opens a window with the indicated content. House is red, barchart is blue.

Note that we have used the Logo naming convention, which means that the height of our barchart is the width parameter in rectangle (and, likewise, the width of each bar is the height parameter in rectangle)

## Julia

Translation of: Wren

Outputs a PNG file.

`using Luxor, Colors function house(🐢, x, y, siz)    oldorientation = 🐢.orientation    xpos, ypos = 🐢.xpos, 🐢.ypos    # house wall    Reposition(🐢, x, y)    Rectangle(🐢, siz, siz)    # roof    Reposition(🐢, x - siz / 2, y -  siz / 2)    Turn(🐢, -60)    Forward(🐢, siz)    Turn(🐢, 120)    Forward(🐢, siz)    # turtle_demo    doorheight, doorwidth = siz / 2, siz / 4    Pencolor(🐢, 0, 0, 0)    Reposition(🐢, x, y + doorheight / 2)    Rectangle(🐢, doorwidth, doorheight)    # window    windowheight, windowwidth = siz /3, siz / 4    Reposition(🐢, x + siz / 4, y - siz / 4)    Rectangle(🐢, windowwidth, windowheight)    Reposition(🐢, x - siz / 4, y - siz / 4)    Rectangle(🐢, windowwidth, windowheight)    Orientation(🐢, oldorientation)    Reposition(🐢, xpos, ypos)end function barchart(🐢, data, x, y, siz)    oldorientation = 🐢.orientation    xpos, ypos = 🐢.xpos, 🐢.ypos    maxdata = maximum(data)    # scale to fit within a square with sides `siz` and draw bars of chart    barwidth = siz / length(data)    Pencolor(🐢, 1.0, 0.0, 0.5)    Reposition(🐢, x, y)    for n in data  # draw each bar in chart        barheight = n * siz / maxdata        Reposition(🐢, x, y - barheight / 2)        Rectangle(🐢, barwidth, barheight)        x += barwidth    end    Orientation(🐢, oldorientation)    Reposition(🐢, xpos, ypos)end function testturtle(width = 400, height = 600)    dra = Drawing(600, 400, "turtle_demo.png")    origin()    background("midnightblue")    🐢 = Turtle()    Pencolor(🐢, "cyan")    Penwidth(🐢, 1.5)    house(🐢, -width / 3, height / 7, width / 2)    barchart(🐢, [15, 10, 50, 35, 20], width / 8, height / 8, width / 2)    finish()end testturtle() `

## Logo

Translation of: Quackery
`to rectangle :width :height    repeat 2 [        forward :height        left 90        forward :width         left 90 ]    end to square :size    rectangle size size    end to triangle :size    repeat 3 [         forward size         right 120 ]      end to house :size    left 90    square size    triangle size    right 90    end to max :lst   if equalp count lst 1 [ output first lst ]   make "x max butfirst lst    if x > first lst [ output x ]    output first lst      end to barchart :lst :size    right 90    if emptyp lst [ stop ]    make "scale size / (max lst)    make "width size / count lst    foreach lst [         rectangle ? * scale width         forward width ]    back size    left 90    end clearscreen hideturtlehouse 150penupright 90 forward 10 left 90pendownbarchart [ 0.5 0.33333 2 1.3 0.5 ] 200left 90 back 10 right 90`
Output:

## Perl

Added octangle window to house attic.

`#!/usr/bin/perl use strict; # https://rosettacode.org/wiki/Simple_turtle_graphicsuse warnings;use Tk;use List::Util qw( max ); my \$c; # the canvas # turtle routines my \$pen = 1; # true for pendown,  false for penupmy @location = (0, 0); # upper left cornermy \$direction = 0; # 0 for East, increasing clockwisemy @stack;my \$radian = 180 / atan2 0, -1;sub dsin { sin \$_ / \$radian }sub dcos { cos \$_ / \$radian }sub save { push @stack, [ \$direction, @location ] }sub restore { (\$direction, @location) = @{ pop @stack } }sub turn { \$direction += shift }sub right { turn shift }sub left { turn -shift }sub forward  {  my \$x = \$location + \$_ * dcos \$direction;  my \$y = \$location + \$_ * dsin \$direction;  \$pen and \$c->createLine( @location, \$x, \$y, -width => 3 );  @location = (\$x, \$y);  }sub back { turn 180; forward shift; turn 180 }sub penup { \$pen = 0 }sub pendown { \$pen = 1 }sub text { \$c->createText( @location, -text => shift ) } # make window my \$mw = MainWindow->new;\$c = \$mw->Canvas(  -width => 900, -height => 900,  )->pack;\$mw->Button(-text => 'Exit', -command => sub {\$mw->destroy},  )->pack(-fill => 'x');\$mw->after(0, \&run);MainLoop;-M \$0 < 0 and exec \$0; sub box  {  my (\$w, \$h) = @_;  for (1 .. 2)    {    forward \$w;    left 90;    forward \$h;    left 90;    }  } sub house  {  my \$size = shift;  box \$size, \$size;  right 90;  for ( 1 .. 3 )    {    right 120;    forward \$size;    }  penup;  left 90;  forward \$size;  left 90;  save;  forward \$size * 1 / 4;  pendown;  box \$size / 4, \$size / 2;  penup;  forward \$size * 3 / 8;  left 90;  forward \$size / 4;  right 90;  pendown;  box \$size / 4, \$size / 4;  penup;  restore;  save;  forward \$size / 2;  left 90;  forward \$size + 40;  right 90;  pendown;  for (1 .. 8)    {    forward 15;    left 45;    forward 15;    }  restore;  penup;  } sub graph  {  save;  my \$size = shift;  my \$width = \$size / @_;  my \$hscale = \$size / max @_;  for ( @_ )    {    box \$width, \$hscale * \$_;    save;    penup;    forward \$width / 2;    left 90;    forward 10;    text \$_;    pendown;    restore;    forward \$width;    }  restore;  } sub run  {  penup;  forward 50;  right 90;  forward 400;  pendown;  house(300);  penup;  forward 400;  pendown;  graph( 400, 2,7,4,5,1,8,6 );  }`

## Phix

Library: Phix/pGUI
Library: Phix/online

You can run this online here.
I factored out some common code for the 2D and 3D versions (or started to, distributed version contains some additional diag aids)

```-- demo\rosetta\turtle.e
include pGUI.e
global Ihandle canvas, dlg
global cdCanvas cdcanvas
global bool pen_down = false

global procedure pendown(atom colour=CD_BLACK)
pen_down = true
cdCanvasSetForeground(cdcanvas, colour)
end procedure

global procedure penup()
pen_down = false
end procedure
```
```--
-- demo\rosetta\Simple_turtle_graphics.exw
-- =======================================
--
with javascript_semantics
include turtle.e -- (common code for 2D and 3D versions)

atom x = 0,
y = 0,
direction = 0

procedure walk(atom distance)
//
// Move forward by distance pixels.
//
atom start_x = x,
start_y = y,
angle = direction*PI/180
x += distance*sin(angle)
y += distance*cos(angle)
if pen_down then
cdCanvasLine(cdcanvas,start_x,start_y,x,y)
end if
end procedure

procedure right(atom angle)
direction = remainder(direction+angle,360)
end procedure

procedure left(atom angle)
right(360-angle)
end procedure

procedure move(sequence s)
-- s is a list of angles (odd elements)
--        and distances (even elements)
for i=1 to length(s) do
if odd(i) then
right(s[i])
else
walk(s[i])
end if
end for
end procedure

procedure rectangle(atom width, height)
move({0,height,90,width,90,height,90,width,90})
end procedure

procedure draw_house(atom width, height)
//
// Draw a house at the current x,y
// direction must be 0 for house to be upright
--  left(10) -- (deliberately wonky works fine too)
//       -- (as long as you undo it at the end)
// house walls
rectangle(width, height)
// door (maybe some windows too would be nice...)
penup()
move({90,width/7,-90})
pendown(CD_BLUE)
rectangle(width/8,height/2.5)
penup()
move({-90,width/7,90})
// roof
walk(height)
pendown(CD_RED)
d = sqrt(width*width+height*height)/2
move({a,d,180-a*2,d})
penup()
move({90+a,width,-90,height,180})
--  right(10)
end procedure

procedure draw_barchart(sequence nums, atom w, h)
// draw a barchart occupying the middle 60% of w,h
// nums can contain +ve and/or -ve values.
--  right(10) -- (ditto)
integer n = length(nums)
atom mx = max(max(nums),0),
mn = min(min(nums),0),
r = mx-mn,                 -- range
zl = abs(mn)/r*h*0.6+h/5,  -- zero line
bw = w*0.6/n               -- bar width
move({90,w/5,-90,zl})
pendown()
for i=1 to n do
atom ni = nums[i]/r*h*0.6
if ni>0 then
rectangle(bw,ni)
else
pendown(CD_RED)
right(90)
rectangle(-ni,bw)
left(90)
pendown(CD_BLACK)
end if
move({90,bw,-90})
end for
penup()
move({180,zl,90,w/5+bw*n,90})
--  left(10)
end procedure

function redraw_cb(Ihandle /*ih*/)
integer {width, height} = IupGetIntInt(canvas, "DRAWSIZE")
cdCanvasActivate(cdcanvas)
cdCanvasClear(cdcanvas)
atom w2 = width/2,
qw = width/4,
qh = height/4
penup()
move({0,qh,90,qw,-90})
pendown()

draw_house(qw,qh)   -- house in the left half

penup()

move({90,w2,-90})   -- barchart in the right half

draw_barchart({0.5, -4/3, 2, 1.3, 0.5},width/2,height)

-- sanity checks
if round(x)!=0 then ?9/0 end if
if round(y)!=0 then ?9/0 end if
if round(direction)!=0 then ?9/0 end if

cdCanvasFlush(cdcanvas)
return IUP_DEFAULT
end function

IupOpen()
canvas = IupCanvas(Icallback("redraw_cb"),"RASTERSIZE=600x400")
dlg = IupDialog(canvas,`TITLE="Simple turtle graphics"`)
IupMap(dlg)
cdcanvas = cdCreateCanvas(CD_IUP, canvas)
IupShow(dlg)
IupSetAttribute(canvas, "RASTERSIZE", NULL) -- release the minimum limitation
if platform()!=JS then
IupMainLoop()
IupClose()
end if
```

## Python

Translation of: Quackery
`from turtle import * def rectangle(width, height):    for _ in range(2):        forward(height)        left(90)        forward(width)        left(90) def square(size):    rectangle(size, size) def triangle(size):    for _ in range(3):        forward(size)        right(120) def house(size):    right(180)    square(size)    triangle(size)    right(180) def barchart(lst, size):    scale = size/max(lst)    width = size/len(lst)    for i in lst:        rectangle(i*scale, width)        penup()        forward(width)        pendown()    penup()    back(size)    pendown() clearscreen()hideturtle()house(150)penup()forward(10)pendown()barchart([0.5, (1/3), 2, 1.3, 0.5], 200)penup()back(10)pendown()`
Output:

## Quackery

`  [ \$ "turtleduck.qky" loadfile ] now!   [ behead do    rot witheach      [ do 2over 2over        v< if 2swap         2drop ] ]                 is largest   (       [ --> n/d )   [ 2 times     [ 2dup walk      -1 4 turn      2over walk       -1 4 turn ]     2drop 2drop ]                 is rectangle ( n/d n/d -->     )    [ 2dup rectangle ]              is square    (     n/d -->     )   [ 3 times      [ 2dup walk        1 3 turn ]     2drop ]                       is triangle  (    n/d  -->     )   [ 1 2 turn     2dup square triangle     1 2 turn ]                    is house     (     n/d -->     )   [ stack ]                       is bar.width (         --> s   )   [ stack ]                       is bar.scale (         --> s   )   [ join temp put    dup size n->v     temp share do v/ 1/v    join bar.width put    dup largest    temp share do v/    join bar.scale put        witheach       [ do         bar.scale share do v/        bar.width share do        rectangle        bar.width share do fly ]    temp take do -v fly    bar.width release    bar.scale release ]          is barchart  (   [ n/d -->     )    turtle   150 1 house   10 1 fly   ' [ [ 1 2 ] [ 1 3 ] [ 2 1 ] [ 13 10 ] [ 1 2 ] ] 200 1 barchart   -10 1 fly`
Output:

## Wren

Library: DOME
Library: Wren-turtle
`import "dome" for Windowimport "graphics" for Canvas, Colorimport "./turtle" for Turtle class Main {    construct new(width, height) {        Window.resize(width, height)        Canvas.resize(width, height)        Window.title = "Simple turtle graphics"        _w = width        _h = height    }     init() {        Canvas.cls(Color.white)        _t = Turtle.new()        drawHouse(_w/4)        barChart([15, 10, 50, 35, 20], _w/3)    }     drawHouse(size) {        // save initial turtle position and direction        var saveX = _t.x        var saveY = _t.y        var saveD = _t.dir         _t.pen.width = 2         // draw house        _t.drawRect(_w/4, _h/2, size, size)         // draw roof        _t.right(30)        _t.walk(size)        _t.right(120)        _t.walk(size)         // draw door        var doorWidth  = (size/4).floor        var doorHeight = (size/2).floor        _t.drawRect(_w/4 + doorWidth/2, _h/2 + doorHeight, doorWidth, doorHeight)         // draw window        var windWidth  = (size/3).floor        var windHeight = (size/4).floor        _t.drawRect(_w/4 + size/2, _h/2 + size/2, windWidth, windHeight)         // restore initial turtle position and direction        _t.x = saveX        _t.y = saveY        _t.dir = saveD    }     // nums assumed to be all non-negative    barChart(nums, size) {        // save intial turtle position and direction        var saveX = _t.x        var saveY = _t.y        var saveD = _t.dir         // find maximum        var max = 0        for (n in nums) if (n > max) max = n         // scale to fit within a square with sides 'size' and draw chart        var barWidth = (size / nums.count).floor        var startX = _w / 2 + 20        var startY = _h / 2        for (i in 0...nums.count) {            var barHeight = (nums[i] * size / max).round            _t.drawRect(startX, startY - barHeight, barWidth, barHeight)            startX = startX + barWidth        }         // restore intial turtle position and direction        _t.x = saveX        _t.y = saveY        _t.dir = saveD    }     update() {}     draw(alpha) {}} var Game = Main.new(600, 600)`
Output:
```Similar to Quackery image except that the house has a door and a single window.
```

## Yabasic

Translation of: Python
`// Rosetta Code problem: http://rosettacode.org/wiki/Simple_turtle_graphics// Adapted from Python to Yabasic by Galileo, 01/2022 import turtle sub rectang(width, height)    local i     for i = 1 to 2        move(height)        turn(-90)        move(width)        turn(-90)    nextend sub sub square(size)    rectang(size, size)end sub sub triang(size)    local i     for i = 1 to 3        move(size)        turn(120)    nextend sub sub house(size)    turn(180)    square(size)    triang(size)    turn(180)end sub sub barchart(lst\$, size)    local t\$(1), t(1), n, m, i, scale, width     n = token(lst\$, t\$())    redim t(n)     for i = 1 to n        t(i) = val(t\$(i))        if t(i) > m m = t(i)    next     scale = size/m    width = size/n    for i = 1 to n        rectang(t(i)*scale, width)        pen(false)        move(width)        pen(true)    next    pen(false)    move(-size)    pen(true)end sub startTurtle()color 255, 255, 255turn(90)house(150)pen(false)move(10)pen(true)barchart("0.5 0.333 2 1.3 0.5", 200)`