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 is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

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; `

## 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 \$_[0] / \$radian }sub dcos { cos \$_[0] / \$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[0] + \$_[0] * dcos \$direction;  my \$y = \$location[1] + \$_[0] * 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.

```--
-- demo\rosetta\Simple_turtle_graphics.exw
-- =======================================
--
with javascript_semantics
include pGUI.e
Ihandle canvas, dlg
cdCanvas cdcanvas

atom x = 0,
y = 0,
direction = 0
bool pen_down = true

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 penup()
pen_down = false
end procedure

procedure pendown(atom colour=CD_BLACK)
pen_down = true
cdCanvasSetForeground(cdcanvas, colour)
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
//
// 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)
atom a = arctan(width/height)*CD_RAD2DEG,
d = sqrt(width*width+height*height)/2
move({a,d,180-a*2,d})
penup()
// return to origin({qw,qh}) and direction 0:
move({90+a,width,-90,height,180})
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.
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()
// return to origin({w/2,0}) and direction 0:
move({180,zl,90,w/5+bw*n,90})
end procedure

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

draw_house(qw,qh)       -- (at current x,y)

penup()

move({90,width/2,-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)`