Simple turtle graphics

From Rosetta Code
Task
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.

Task
  • Create a function (or subroutine) that uses turtle graphics to draw a house of a specified size as depicted. 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)
  OD
RETURN

PROC Square(INT w)
  Rectangle(w,w)
RETURN

PROC Triangle(INT w)
  BYTE i

  FOR i=1 TO 3
  DO
    Forward(w)
    Right(120)
  OD
RETURN

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
  OD
RETURN (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=$FF
RETURN
Output:

Screenshot from Atari 8-bit computer

Ada

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 execution
procedure 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;

EasyLang

Run it

subr home
   deg = 0
   x = 50
   y = 50
   down = 0
   move x y
.
home
# 
proc forward n . .
   x += cos deg * n
   y += sin deg * n
   if down = 1
      line x y
   else
      move x y
   .
   sleep 0.1
.
proc turn a . .
   deg -= a
.
# 
proc house . .
   turn 180
   forward 45
   turn 180
   down = 1
   # 
   forward 30
   turn 90
   forward 30
   turn 90
   forward 30
   turn 90
   forward 30
   # 
   turn 30
   forward 30
   turn 120
   forward 30
   home
.
house
# 
proc bar a[] . .
   turn 90
   forward 30
   turn -90
   down = 1
   for i to len a[]
      max = higher max a[i]
   .
   for i to len a[]
      h = a[i] / max * 50
      w = 45 / len a[]
      turn -90
      forward h
      turn 90
      forward w
      turn 90
      forward h
      turn -90
   .
   turn 180
   forward 45
   home
.
bar [ 50 33 200 130 50 ]

FreeBASIC

Library: Turtle_Graphics.bi

' Turtle Graphics Library by Angelo Rosina 1995
' Ported to Freebasic by Angelo Rosina 2007
'
'(RIGH and LEF because RIGHT and LEFT are reserved keywords, of course)

Declare Sub LEF (gradi As Integer)
Declare Sub SETCOL (C As Integer)
Declare Sub SETSIZE (C As Integer)
Declare Sub RIGH (gradi As Integer)
Declare Sub FORW (passi As Integer)
Declare Sub BACK (passi As Integer)
Declare Sub TURTLE (numero As Integer)
Declare Sub UP ()
Declare Sub DOWN ()
Declare Sub DTurtle ()

Dim Shared As Integer graph, dimen, angulo, N, dis, su, pasos
Dim Shared As Integer colore(10), figura(5000,10), figura2()
Dim Shared As Long X(10), Y(10)
Dim Shared As String comando

Sub BACK (passi As Integer)
    pasos = passi
    comando = "d " & Str(passi)
    DTurtle
    comando = ""
    pasos = 0
End Sub

Sub DOWN
    su = 0
End Sub

Sub DTurtle Static
    Dim As Integer rifa, lavora, XX, YY, scher(), FX, FY
    Dim As String R
    
    If rifa = 0 Then rifa = 1: Redim scher(5000)
    If lavora Then Put (XX - dimen * 4, YY - dimen * 2), scher, Pset
    'SCREEN graph
    If su Then comando = "b" & comando
    FX = X(N)
    FY = Y(N)
    R = "s" & Str(dimen) & "bm" & Str(FX) & "," & Str(FY) & "c" & Str(colore(N)) & "Ta" & Str(angulo) & comando
    Draw R
    X(N) = X(N) + Sin(angulo / 57.2957) * dimen / 4 * pasos
    Y(N) = Y(N) + Cos(angulo / 57.2957) * dimen / 4 * pasos
    XX = X(N)
    YY = Y(N)
    Get (X(N) - dimen * 4, Y(N) - dimen * 2)-(X(N) + dimen * 4, Y(N) + dimen * 2), scher: lavora = 1
    If dis = 0 Then
        R = "bm" & Str(XX) & "," & Str(YY) & "Ta" & Str(angulo) & "r1 ta " & Str(angulo + 15 + 360 * (angulo + 15 > 360)) & "u7 ta " & Str(angulo + 165 + 360 * (angulo + 165 > 360)) & "u7 ta" & Str(angulo) & " m" & Str(XX) & "," & Str(YY)
        Draw R
    Else
        Put (XX, YY), figura2, Or
    End If
End Sub

Sub FORW (passi As Integer)
    pasos = -passi
    comando = "u " & Str(passi)
    DTurtle
    comando = ""
    pasos = 0
End Sub

Sub LEF (gradi As Integer)
    angulo += gradi
    Do Until angulo <= 360
        angulo -= 360
    Loop
    DTurtle
End Sub

Sub RIGH (gradi As Integer)
    angulo -= gradi
    Do Until angulo >= 0
        angulo += 360
    Loop
    DTurtle
End Sub

Sub SETCOL (C As Integer)
    colore(N) = C
    DTurtle
End Sub

Sub SETSIZE (C As Integer)
    dimen = C
    DTurtle
End Sub

Sub TURTLE (numero As Integer) Static
    Dim As Integer i, NN, j
    Dim As Integer ang()
    
    Redim figura2(dis)
    If dis <> 0 And graph <> 0 Then
        For i = 0 To dis
            figura2(i) = figura(i, numero)
        Next i
    End If
    NN = N
    N = numero
    If j = 0 Then j = 1: Redim ang(10): dimen = 4
    If X(numero) = 0 Then X(numero) = 320
    If Y(numero) = 0 Then Y(numero) = 100: colore(numero) = 15
    ang(NN) = angulo
    angulo = ang(N)
    DTurtle
End Sub

Sub UP
    su = 1
End Sub

Turtle test:

'Rosetta Code problem: https://rosettacode.org/wiki/Simple_turtle_graphics 
 
'by Jjuanhdez, 03/2023

#include "Turtle_Graphics.bi"

Sub rectangle(ancho As Short, alto As Short)
    For i As Short = 1 To 2
        FORW alto
        LEF 90 
        FORW ancho
        LEF 90 
    Next i
End Sub

Sub square(lado As Short)
    rectangle(lado, lado)
End Sub

Sub triangle(lado As Short)
    For i As Short = 1 To 3
        FORW lado 
        RIGH 120 
    Next i
End Sub

Sub house(lado As Short)
    LEF 90
    square lado
    triangle lado
    RIGH 90 
End Sub

Sub barchart(lst() As Double, lado As Short)
    Dim As Short i, min, max
    max = lst(Ubound(lst))
    
    For i = Lbound(lst) To Ubound(lst)
        If lst(i) > max Then max = lst(i)
    Next i
    
    Dim As Short escala = lado/max
    Dim As Short ancho = lado/Ubound(lst)
    
    For i = Lbound(lst) To Ubound(lst)
        rectangle lst(i), ancho
        UP
        FORW ancho 
        DOWN
    Next i
    UP
    BACK lado
    DOWN
End Sub

Screenres 800,600
Windowtitle "Simple turtle graphics"
Cls

TURTLE 1
SETSIZE 3
SETCOL 0    'black

DOWN
BACK 200
SETCOL 2    'green

house 150
UP
RIGH 90
FORW 50

Dim As Double s(1 To 6) = {1, 50, 33, 200, 130, 50}
barchart s(), 200
SETCOL 0
Sleep
Output:

Simple turtle graphics FreeBasic image

IS-BASIC

100 PROGRAM "Turtle.bas"
110 OPTION ANGLE DEGREES
120 GRAPHICS HIRES 4
130 CALL HOUSE(200,200,200)
140 SET INK 2:CALL CHART(450,200,1000,700)
150 DEF HOUSE(X,Y,L)
160   PLOT X,Y,ANGLE 0;
170   FOR I=1 TO 4
180     PLOT FORWARD 200,RIGHT 90;
190   NEXT
200   PLOT LEFT 60;FORWARD L;RIGHT 120;FORWARD L;X,Y,
210 END DEF 
220 DEF CHART(X,Y,X1,Y1)
230   LET PC,MX=0
240   DO
250     READ IF MISSING EXIT DO:Z
260     LET PC=PC+1:LET MX=MAX(MX,Z)
270   LOOP
280   RESTORE 
290   LET L=(X1-X)/PC:LET MX=(Y1-Y)/MX
300   PLOT X,Y,
310   DO
320     READ IF MISSING EXIT DO:Z
330     PLOT ANGLE 90;FORWARD Z*MX;RIGHT 90;FORWARD L;RIGHT 90;FORWARD Z*MX;RIGHT 90;FORWARD L
340     PLOT ANGLE 0;FORWARD L
350   LOOP 
360   PLOT X,Y,
370 END DEF
380 DATA 90,60,300,200,90

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 _90
translate 0 0 _40
clearscreen ''
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 Red
house 150
pen 0
right 90
forward 10
left 90
pen 1 [ penColor Blue
barchart 0.5 0.3333 2 1.3 0.5; 200
pen 0
left 90
forward 10
left 270
pen 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)

Java

Opens a javax.swing.JFrame, displaying the graphics shown in the screenshot:

Screenshot of the Java implementation of task "Simple turtle graphics"

/* Class Turtle starts here */

import java.awt.geom.AffineTransform;

public class Turtle extends java.lang.Object
{
	private final java.awt.Graphics2D origin;
	private java.awt.Graphics2D g2;

	public Turtle(java.awt.Graphics2D origin)
	{
		this.origin = origin;
		origin();
	}
	public void origin()
	{
		g2=(java.awt.Graphics2D)origin.create();
	}
	public void relativePosition(int xoff, int yoff)
	{
		AffineTransform at=g2.getTransform();
		at.concatenate(AffineTransform.
                       getTranslateInstance(xoff,yoff));
		g2.setTransform(at);
	}
	public void turnByDegrees(int thetaInDegrees)
	{
		AffineTransform at=g2.getTransform();
		at.concatenate(AffineTransform.
                       getRotateInstance(Math.toRadians(thetaInDegrees)));
		g2.setTransform(at);
	}
	public void forward(int len)
	{
		g2.drawLine(0,0,len,0);
		relativePosition(len,0);
	}
}

/* Class CanvasComponent starts here*/

import java.awt.Graphics;
import java.awt.Graphics2D;

public class CanvasComponent extends javax.swing.JComponent
{
    protected void paintComponent(Graphics g)
    {
        Turtle turtle=new Turtle((Graphics2D)g);

        turtle.origin();

        turtle.relativePosition(50,50);

        house(turtle,100,200,50);

        turtle.origin();

        turtle.relativePosition(200,50);

        double[] numbers=new double[]{0.5, 0.33333, 2, 1.3, 0.5};

        barchart(turtle,200,numbers);
    }
    private void barchart(Turtle turtle,int size,double[] numbers)
    {
        double max=0;
        for(double d:numbers)
        {
            if(d>max)
                max=d;
        }
        double width=size/ numbers.length;
        int xpos=400;
        for(double d:numbers)
        {
            int h=(int) (size * (d / max));
            rectangle(turtle, (int)width, h);
            xpos+=width;
            turtle.relativePosition((int)width,0);
        }
    }
    private void house(Turtle turtle,int width, 
                       int height, int roofheight)
    {
        rectangle(turtle,width,height);
        turtle.relativePosition(0,height);
        double dist= Math.sqrt(roofheight*roofheight+width/2*width/2);
        double angle= Math.toDegrees(Math.asin(roofheight/dist));
        turtle.turnByDegrees((int)angle);
        turtle.forward((int)dist);
        turtle.turnByDegrees(-2*(int)angle);
        turtle.forward((int)dist);
    }
    private void rectangle(Turtle turtle,int width, int height)
    {
        for(int i=0;i<2;++i)
        {
            turtle.forward(width);
            turtle.turnByDegrees(90);
            turtle.forward(height);
            turtle.turnByDegrees(90);
        }

    }
}

/* Class MainClass starts here */

import javax.swing.*;
import java.awt.*;

public class MainClass
{
    public static void main(String[] args)
    {
        CanvasComponent canvas=new CanvasComponent();
        canvas.setPreferredSize(new Dimension(800,600));
        JFrame f=new JFrame();
        JPanel p=new JPanel(new BorderLayout());
        p.add(canvas);
        f.setContentPane(p);
        f.setDefaultCloseOperation(f.EXIT_ON_CLOSE);
        f.pack();
        f.setVisible(true);
    }
}

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()

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 hideturtle
house 150
penup
right 90 forward 10 left 90
pendown
barchart [ 0.5 0.33333 2 1.3 0.5 ] 200
left 90 back 10 right 90
Output:

Perl

Added octangle window to house attic.

#!/usr/bin/perl

use strict; # https://rosettacode.org/wiki/Simple_turtle_graphics
use warnings;
use Tk;
use List::Util qw( max );

my $c; # the canvas

# turtle routines

my $pen = 1; # true for pendown,  false for penup
my @location = (0, 0); # upper left corner
my $direction = 0; # 0 for East, increasing clockwise
my @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.
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)
    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})
--  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()
    // return to origin({w/2,0}) and direction 0:
    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({180,qh,90,qw,90}) -- return to {0,0}

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

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

    move({-90,w2,90})   -- return to {0,0}

    -- 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 Window
import "graphics" for Canvas, Color
import "./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.

XPL0

def  ScrW=320, ScrH=200;
def  Pi = 3.141592654;
def  D2R = Pi/180.0;
real Dir, PosX, PosY;
int  Pen;
def \Pen\ Up, Down;

proc Turn(Ang);
real Ang;
Dir:= Dir + Ang*D2R;

proc MoveTo(Dist);
real Dist;
[PosX:= PosX + Dist*Cos(Dir);
 PosY:= PosY + Dist*Sin(Dir);
if Pen = Down then
    Line(ScrW/2+fix(PosX), ScrH/2-fix(PosY), $0F \white\)
else
    Move(ScrW/2+fix(PosX), ScrH/2-fix(PosY));
];

proc Rectangle(Width, Height);
real Width, Height;
int  N;
[for N:= 1 to 2 do
    [MoveTo(Width);
    Turn(90.0);
    MoveTo(Height);
    Turn(90.0);
    ];
];

proc BarGraph(List, Len, Size);
real List; int Len; real Size;
int  N;
def  BarWidth = 0.4;
[for N:= 0 to Len-1 do
    [Rectangle(Size*BarWidth, List(N)*Size);
    MoveTo(Size*BarWidth);
    ];
MoveTo(-Size*BarWidth*float(Len));
];

proc Triangle(Size);
real Size;
int  N;
[for N:= 1 to 3 do
    [MoveTo(Size);
    Turn(-120.0);
    ];
];

proc Square(Size);
real Size;
Rectangle(Size, Size);

proc House(Size);
real Size;
[Turn(180.0);
Square(Size);
Triangle(Size);
Turn(180.0);
];

[SetVid($13);                   \set VGA graphics
Move(ScrW/2, ScrH/2);           \start Line at center
Dir:= 0.0;  PosX:= 0.0;  PosY:= 0.0;  Pen:= Down;
House(80.0);
Pen:= Up;  MoveTo(10.0);  Pen:= Down;
BarGraph([0.5, 1.0/3.0, 2.0, 1.3, 0.5], 5, 45.0);
]

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)
    next
end sub
 
sub square(size)
    rectang(size, size)
end sub
 
sub triang(size)
    local i
    
    for i = 1 to 3
        move(size)
        turn(120)
    next
end 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, 255
turn(90)
house(150)
pen(false)
move(10)
pen(true)
barchart("0.5 0.333 2 1.3 0.5", 200)