Simple turtle graphics

From Rosetta Code
Revision as of 19:53, 2 August 2021 by GordonCharlton (talk | contribs) (β†’β€Ž{{header|Python}}: added "translated from")
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

Task
  • 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.

Julia

Translation of: Wren

Outputs a PNG file. <lang julia>using Luxor, Colors

function house(🐒, x, y, siz)

   oldorientation = 🐒.orientation
   xpos, ypos = 🐒.xpos, 🐒.ypos
   # house wall
   Reposition(🐒, x, y)
   Rectangle(🐒, siz, siz)
   # roof
   HueShift(🐒)
   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)
   HueShift(🐒)
   Reposition(🐒, x, y + doorheight / 2)
   Rectangle(🐒, doorwidth, doorheight)
   # window
   windowheight, windowwidth = siz /3, siz / 4
   HueShift(🐒)
   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
       HueShift(🐒)
       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() </lang>

Translation of: Quackery

<lang Logo>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</lang>

Output:

https://imgur.com/4V1UrcN

Python

Translation of: Quackery

<lang Python>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()</lang>

Output:

https://imgur.com/oBXTDem

Quackery

<lang 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</lang>
Output:

https://imgur.com/B7YbTbZ

Wren

Library: DOME
Library: Wren-turtle

<lang ecmascript>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)</lang>

Output:
Similar to Quackery image except that the house has a door and a single window.