# Sierpinski arrowhead curve

Produce a graphical or ASCII-art representation of a  Sierpinski arrowhead curve  of at least order  3.

Sierpinski arrowhead curve
You are encouraged to solve this task according to the task description, using any language you may know.
Task

## 11l

Translation of: Nim
```V sqrt3_2 = sqrt(3) / 2

F sierpinski_arrowhead_next(points)
V result = [(0.0, 0.0)] * (3 * (points.len - 1) + 1)
V j = 0
L(i) 0 .< points.len - 1
V (x0, y0) = points[i]
V (x1, y1) = points[i + 1]
V dx = x1 - x0
result[j] = (x0, y0)
I y0 == y1
V d = abs(dx * :sqrt3_2 / 2)
result[j + 1] = (x0 + dx / 4, y0 - d)
result[j + 2] = (x1 - dx / 4, y0 - d)
E I y1 < y0
result[j + 1] = (x1, y0)
result[j + 2] = (x1 + dx / 2, (y0 + y1) / 2)
E
result[j + 1] = (x0 - dx / 2, (y0 + y1) / 2)
result[j + 2] = (x0, y1)
j += 3
result[j] = points.last
R result

V size = 600
V iterations = 8
V outfile = File(‘sierpinski_arrowhead.svg’, ‘w’)

outfile.write(‘<svg xmlns='http://www.w3.org/2000/svg' width='’size‘' height='’size"'>\n")
outfile.write("<rect width='100%' height='100%' fill='white'/>\n")
outfile.write(‘<path stroke-width='1' stroke='black' fill='none' d='’)
V margin = 20.0
V side = size - 2 * margin
V x = margin
V y = 0.5 * size + 0.5 * sqrt3_2 * side
V points = [(x, y), (x + side, y)]
L 0 .< iterations
points = sierpinski_arrowhead_next(points)
L(point) points
outfile.write(I L.index == 0 {‘M’} E ‘L’)
outfile.write(point.x‘,’point.y"\n")
outfile.write("'/>\n</svg>\n")```
Output:

Output is similar to Nim and C++.

## Ada

Library: APDF
Even order curves are drawn pointing downwards.
```with Ada.Command_Line;
with Ada.Numerics.Generic_Elementary_Functions;
with Ada.Text_IO;
with PDF_Out;

procedure Arrowhead_Curve is

package Real_Math is
new Ada.Numerics.Generic_Elementary_Functions (PDF_Out.Real);
use Real_Math, PDF_Out, Ada.Command_Line, Ada.Text_IO;

subtype Angle_Deg  is Real;
type    Order_Type is range 0 .. 7;

Purple : constant Color_Type := (0.7, 0.0, 0.5);
Length : constant Real       := 340.0;
Corner : constant Point      := (120.0, 480.0);

Order     : Order_Type;
Current   : Point      := (0.0, 0.0);
Direction : Angle_Deg  := Angle_Deg'(0.0);
Doc       : PDF_Out_File;

procedure Curve (Order : Order_Type; Length : Real; Angle : Angle_Deg) is
begin
if Order = 0 then
Current := Current + Length * Point'(Cos (Direction, 360.0),
Sin (Direction, 360.0));
Doc.Line (Corner + Current);
else
Curve (Order - 1, Length / 2.0, -Angle);  Direction := Direction + Angle;
Curve (Order - 1, Length / 2.0,  Angle);  Direction := Direction + Angle;
Curve (Order - 1, Length / 2.0, -Angle);
end if;
end Curve;

begin
if Argument_Count /= 1 then
Put_Line ("arrowhead_curve <order>");
Put_Line ("  <order>   0 .. 7");
Put_Line ("open sierpinski-arrowhead-curve.pdf to view ouput");
return;
end if;
Order := Order_Type'Value (Argument (1));

Doc.Create ("sierpinski-arrowhead-curve.pdf");
Doc.Page_Setup (A4_Portrait);
Doc.Margins (Margins_Type'(Left   => Cm_2_5,
others => One_cm));
Doc.Stroking_Color (Purple);
Doc.Line_Width (2.0);
Doc.Move (Corner);
if Order mod 2 = 0 then
Direction := 0.0;
Curve (Order, Length, 60.0);
else
Direction := 60.0;
Curve (Order, Length, -60.0);
end if;
Doc.Finish_Path (Close_Path => False,
Rendering  => Stroke,
Rule       => Nonzero_Winding_Number);
Doc.Close;
end Arrowhead_Curve;
```

## ALGOL W

Produces an Ascii Art Sierpinski Arrowhead Curve using the algorithm from the Wikipedia page.
Note that the Wikipedia algotrithm draws even order curves with the base at the top.

```begin % draw sierpinski arrowhead curves using ascii art %
integer CANVAS_WIDTH;
CANVAS_WIDTH := 200;
begin
% the ascii art canvas and related items %
string(1) array canvas ( 1 :: CANVAS_WIDTH, 1 :: CANVAS_WIDTH );
integer         heading, asciiX, asciiY, width, maxX, maxY, minX, minY;
% draw a line using ascii art - the length is ignored and the heading determines the %
%                               character to use                                     %
% the position is updated                                                            %
procedure drawLine( real value length ) ;
begin
% stores the min and max coordinates %
procedure updateCoordinateRange ;
begin
if asciiX > maxX then maxX := asciiX;
if asciiY > maxY then maxY := asciiY;
if asciiX < minX then minX := asciiX;
if asciiY < minY then minY := asciiY
end updateCoordinateRange ;
if      heading =   0 then begin
updateCoordinateRange;
canvas( asciiX, asciiY ) := "_";
asciiX := asciiX + 1
end
else if heading =  60 then begin
updateCoordinateRange;
canvas( asciiX, asciiY ) := "/";
asciiY := asciiY - 1;
asciiX := asciiX + 1
end
else if heading = 120 then begin
asciiX := asciiX - 1;
updateCoordinateRange;
canvas( asciiX, asciiY ) := "\";
asciiY := asciiY - 1
end
else if heading = 180 then begin
asciiX := asciiX - 1;
updateCoordinateRange;
canvas( asciiX, asciiY ) := "_"
end
else if heading = 240 then begin
asciiX := asciiX - 1;
asciiY := asciiY + 1;
updateCoordinateRange;
canvas( asciiX, asciiY ) := "/"
end
else if heading = 300 then begin
asciiY := asciiY + 1;
updateCoordinateRange;
canvas( asciiX, asciiY ) := "\";
asciiX := asciiX + 1
end if_various_headings
end drawLine ;
% changes the heading by the specified angle ( in degrees ) - angle must be +/- 60 %
procedure turn( integer value angle ) ;
if angle > 0
then heading := ( heading + angle ) rem 360
else begin
heading := heading + angle;
if heading < 0 then heading := heading + 360
end tuen ;
% initialises the ascii art canvas %
procedure initArt ;
begin
heading :=   0;
asciiX  :=  CANVAS_WIDTH div 2;
asciiY  := asciiX;
maxX    := asciiX;
maxY    := asciiY;
minX    := asciiX;
minY    := asciiY;
for x := 1 until CANVAS_WIDTH do for y := 1 until CANVAS_WIDTH do canvas( x, y ) := " "
end initArt ;
% shows the used parts of the canvas %
procedure drawArt ;
begin
for y := minY until maxY do begin
write();
for x := minX until maxX do writeon( canvas( x, y ) )
end for_y ;
write()
end drawIArt ;
% draws a sierpinski arrowhead curve of the specified order and line length %
procedure sierpinskiArrowheadCurve( integer value order; real value length ) ;
begin
% recursively draws a segment of the sierpinski arrowhead curve %
procedure curve( integer value order; real value length; integer value angle ) ;
if 0 = order then drawline( length )
else begin
curve( order - 1, length / 2, - angle );
turn(  angle );
curve( order - 1, length / 2,   angle );
turn(  angle );
curve( order - 1, length / 2, - angle )
end curve ;
if not odd( order ) then begin % order is even, we can just draw the curve. %
curve( order, length, +60 );
end
else begin % order is odd %
turn( +60 );
curve( order, length, -60 )
end if_not_odd_order__
end sierpinskiArrowheadCurve ;
% draw curves %
i_w := 1; s_w := 0; % set output formatting %
for order := 5 do begin
write( "Sierpinski arrowhead curve of order ", order );
write( "=====================================" );
write();
initArt;
sierpinskiArrowheadCurve( order, 1 );
drawArt
end for_order
end
end.```
Output:
```Sierpinski arrowhead curve of order 5
=====================================

_
/ \
\ /
_/ \_
/     \
\_   _/
_  \ /  _
/ \_/ \_/ \
\         /
_/         \_
/  _       _  \
\_/ \     / \_/
_    /     \    _
/ \   \_   _/   / \
\ /  _  \ /  _  \ /
_/ \_/ \_/ \_/ \_/ \_
/                     \
\_                   _/
_  \                 /  _
/ \_/                 \_/ \
\    _               _    /
_/   / \             / \   \_
/  _  \ /             \ /  _  \
\_/ \_/ \_           _/ \_/ \_/
_          \         /          _
/ \        _/         \_        / \
\ /       /  _       _  \       \ /
_/ \_      \_/ \     / \_/      _/ \_
/     \    _    /     \    _    /     \
\_   _/   / \   \_   _/   / \   \_   _/
_  \ /  _  \ /  _  \ /  _  \ /  _  \ /  _
/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \
```

## AutoHotkey

Translation of: Go

Requires Gdip Library

```order	:= 7
theta	:= 0

curve := []
curve.curveW	:= 1000
curve.curveH	:= 1000
curve.iy	:= 1
curve.cx	:= curve.curveW/2
curve.cy	:= curve.curveH
curve.ch	:= curve.cx/2

arrowhead(order, curve, theta, Arr :=[])
xmin := xmax := ymin := ymax := 0
for i, point in Arr
{
xmin := A_Index = 1 ? point.x : xmin < point.x ? xmin : point.x
xmax := point.x > xmax ? point.x : xmax
ymin := A_Index = 1 ? point.y : ymin < point.y ? ymin : point.y
ymax := point.y > ymax ? point.y : ymax
}
arrowheadX := A_ScreenWidth/2 - (xmax-xmin)/2	, arrowheadY := A_ScreenHeight/2 - (ymax-ymin)/2
for i, point in Arr
points .= point.x - xmin + arrowheadX "," point.y - ymin + arrowheadY "|"

points := Trim(points, "|")
gdip1()
Gdip_DrawLines(G, pPen, Points)
UpdateLayeredWindow(hwnd1, hdc, 0, 0, Width, Height)
return

; ---------------------------------------------------------------
arrowhead(order, curve, theta, Arr) {
length := curve.cx
if (order&1 = 0)
curve(order, length, theta, 60, Arr)
else
{
theta := turn(theta, 60)
theta := curve(order, length, theta, -60, Arr)
}
drawLine(length, theta, Arr)
}
; ---------------------------------------------------------------
drawLine(length, theta, Arr) {
global curve
Arr[Arr.count()+1, "x"] := curve.cx-curve.curveW/2+curve.ch
Arr[Arr.count(), "y"] := (curve.curveH-curve.cy)*curve.iy+2*curve.ch
pi := 3.141592653589793
curve.cx := curve.cx + length * Cos(theta*pi/180)
curve.cy := curve.cy + length * Sin(theta*pi/180)
}
; ---------------------------------------------------------------
turn(theta, angle) {
return theta := Mod(theta+angle, 360)
}
; ---------------------------------------------------------------
curve(order, length, theta, angle, Arr) {
if (order = 0)
drawLine(length, theta, Arr)
else
{
theta := curve(order-1, length/2, theta, -angle, Arr)
theta := turn(theta, angle)
theta := curve(order-1, length/2, theta, angle, Arr)
theta := turn(theta, angle)
theta := curve(order-1, length/2, theta, -angle, Arr)
}
return theta
}
; ---------------------------------------------------------------
gdip1(){
global
If !pToken := Gdip_Startup()
{
MsgBox, 48, gdiplus error!, Gdiplus failed to start. Please ensure you have gdiplus on your system
ExitApp
}
OnExit, Exit
Width := A_ScreenWidth, Height := A_ScreenHeight
Gui, 1: -Caption +E0x80000 +LastFound +OwnDialogs +Owner +AlwaysOnTop
Gui, 1: Show, NA
hwnd1 := WinExist()
hbm := CreateDIBSection(Width, Height)
hdc := CreateCompatibleDC()
obm := SelectObject(hdc, hbm)
G := Gdip_GraphicsFromHDC(hdc)
Gdip_SetSmoothingMode(G, 4)
pPen := Gdip_CreatePen(0xFFFF0000, 2)
}
; ---------------------------------------------------------------
gdip2(){
global
Gdip_DeleteBrush(pBrush)
Gdip_DeletePen(pPen)
SelectObject(hdc, obm)
DeleteObject(hbm)
DeleteDC(hdc)
Gdip_DeleteGraphics(G)
}
; ---------------------------------------------------------------
Exit:
gdip2()
Gdip_Shutdown(pToken)
ExitApp
Return
```

## C

This code is based on the Phix and Go solutions, but produces a file in SVG format.

```// See https://en.wikipedia.org/wiki/Sierpi%C5%84ski_curve#Arrowhead_curve
#include <math.h>
#include <stdio.h>
#include <stdlib.h>

// Structure to keep track of current position and orientation
typedef struct cursor_tag {
double x;
double y;
int angle;
} cursor_t;

void turn(cursor_t* cursor, int angle) {
cursor->angle = (cursor->angle + angle) % 360;
}

void draw_line(FILE* out, cursor_t* cursor, double length) {
double theta = (M_PI * cursor->angle)/180.0;
cursor->x += length * cos(theta);
cursor->y += length * sin(theta);
fprintf(out, "L%g,%g\n", cursor->x, cursor->y);
}

void curve(FILE* out, int order, double length, cursor_t* cursor, int angle) {
if (order == 0) {
draw_line(out, cursor, length);
} else {
curve(out, order - 1, length/2, cursor, -angle);
turn(cursor, angle);
curve(out, order - 1, length/2, cursor, angle);
turn(cursor, angle);
curve(out, order - 1, length/2, cursor, -angle);
}
}

void write_sierpinski_arrowhead(FILE* out, int size, int order) {
const double margin = 20.0;
const double side = size - 2.0 * margin;
cursor_t cursor;
cursor.angle = 0;
cursor.x = margin;
cursor.y = 0.5 * size + 0.25 * sqrt(3) * side;
if ((order & 1) != 0)
turn(&cursor, -60);
fprintf(out, "<svg xmlns='http://www.w3.org/2000/svg' width='%d' height='%d'>\n",
size, size);
fprintf(out, "<rect width='100%%' height='100%%' fill='white'/>\n");
fprintf(out, "<path stroke-width='1' stroke='black' fill='none' d='");
fprintf(out, "M%g,%g\n", cursor.x, cursor.y);
curve(out, order, side, &cursor, 60);
fprintf(out, "'/>\n</svg>\n");
}

int main(int argc, char** argv) {
const char* filename = "sierpinski_arrowhead.svg";
if (argc == 2)
filename = argv[1];
FILE* out = fopen(filename, "w");
if (!out) {
perror(filename);
return EXIT_FAILURE;
}
write_sierpinski_arrowhead(out, 600, 8);
fclose(out);
return EXIT_SUCCESS;
}
```
Output:

## C++

The output of this program is an SVG file.

```#include <fstream>
#include <iostream>
#include <vector>

constexpr double sqrt3_2 = 0.86602540378444; // sqrt(3)/2

struct point {
double x;
double y;
};

std::vector<point> sierpinski_arrowhead_next(const std::vector<point>& points) {
size_t size = points.size();
std::vector<point> output(3*(size - 1) + 1);
double x0, y0, x1, y1;
size_t j = 0;
for (size_t i = 0; i + 1 < size; ++i, j += 3) {
x0 = points[i].x;
y0 = points[i].y;
x1 = points[i + 1].x;
y1 = points[i + 1].y;
double dx = x1 - x0;
output[j] = {x0, y0};
if (y0 == y1) {
double d = dx * sqrt3_2/2;
if (d < 0) d = -d;
output[j + 1] = {x0 + dx/4, y0 - d};
output[j + 2] = {x1 - dx/4, y0 - d};
} else if (y1 < y0) {
output[j + 1] = {x1, y0};
output[j + 2] = {x1 + dx/2, (y0 + y1)/2};
} else {
output[j + 1] = {x0 - dx/2, (y0 + y1)/2};
output[j + 2] = {x0, y1};
}
}
output[j] = {x1, y1};
return output;
}

void write_sierpinski_arrowhead(std::ostream& out, int size, int iterations) {
out << "<svg xmlns='http://www.w3.org/2000/svg' width='"
<< size << "' height='" << size << "'>\n";
out << "<rect width='100%' height='100%' fill='white'/>\n";
out << "<path stroke-width='1' stroke='black' fill='none' d='";
const double margin = 20.0;
const double side = size - 2.0 * margin;
const double x = margin;
const double y = 0.5 * size + 0.5 * sqrt3_2 * side;
std::vector<point> points{{x, y}, {x + side, y}};
for (int i = 0; i < iterations; ++i)
points = sierpinski_arrowhead_next(points);
for (size_t i = 0, n = points.size(); i < n; ++i)
out << (i == 0 ? "M" : "L") << points[i].x << ',' << points[i].y << '\n';
out << "'/>\n</svg>\n";
}

int main() {
std::ofstream out("sierpinski_arrowhead.svg");
if (!out) {
std::cerr << "Cannot open output file\n";
return EXIT_FAILURE;
}
write_sierpinski_arrowhead(out, 600, 8);
return EXIT_SUCCESS;
}
```
Output:

## Factor

Works with: Factor version 0.99 2020-08-14
```USING: accessors L-system ui ;

: arrowhead ( L-system -- L-system )
L-parser-dialect >>commands
[ 60 >>angle ] >>turtle-values
"XF" >>axiom
{
{ "X" "YF+XF+Y" }
{ "Y" "XF-YF-X" }
} >>rules ;

[ <L-system> arrowhead "Arrowhead" open-window ] with-ui
```

When using the L-system visualizer, the following controls apply:

Camera controls
Button Command
a zoom in
z zoom out
left arrow turn left
right arrow turn right
up arrow pitch down
down arrow pitch up
q roll left
w roll right
Other controls
Button Command
x iterate L-system

## Forth

Works with: gforth version 0.7.3

### ASCII

```( ASCII output with use of ANSI terminal control )

: draw-line ( direction -- )
case
0 of  .\" _"              endof ( horizontal right:          _          )
1 of  .\" \e[B\\"         endof (       down right:     CUD  \          )
2 of  .\" \e[D\e[B/\e[D"  endof (        down left: CUB CUD  /  CUB     )
3 of  .\" \e[D_\e[D"      endof (  horizontal left:     CUB  _  CUB     )
4 of  .\" \e[D\\\e[A\e[D" endof (          up left:     CUB  \  CUU CUB )
5 of  .\" /\e[A"          endof (         up right:          /  CUU     )
endcase                         ( cursor is up-right of the last point  )
;

: turn+ 1+ 6 mod ;
: turn- 1- 6 mod ;

defer curve
: A-rule ( order direction -- ) turn+  2dup 'B curve  turn-  2dup 'A curve  turn-  'B curve ;
: B-rule ( order direction -- ) turn-  2dup 'A curve  turn+  2dup 'B curve  turn+  'A curve ;

:noname ( order direction type -- )
2 pick 0 = if drop draw-line drop exit then \ draw line when order is 0
rot 1- rot rot
'A = if A-rule else B-rule then
; is curve

: arrowhead ( order -- )
page
s" Sierpinski arrowhead curve of order " type dup . cr
s" =====================================" type cr
0 'A curve
;

5 arrowhead
```
Output:
```Sierpinski arrowhead curve of order 5
=====================================
_   _   _   _   _   _   _   _   _   _    ok
\_/ \ / \_/ \ / \_/ \ / \_/ \ / \_/ \ / \_/
_/ \_    / \    _/ \_    / \    _/ \_
/     \   \_/   /     \   \_/   /     \
\_   _/      _  \     /  _      \_   _/
\ /       / \_/     \_/ \       \ /
/ \       \_           _/       / \
\_/         \         /         \_/
_   _   _/         \_   _   _
/ \_/ \ /             \ / \_/ \
\_    / \             / \    _/
\   \_/             \_/   /
/  _                   _  \
\_/ \                 / \_/
_/                 \_
/                     \
\_   _   _   _   _   _/
\ / \_/ \ / \_/ \ /
/ \    _/ \_    / \
\_/   /     \   \_/
_  \     /  _
/ \_/     \_/ \
\_           _/
\         /
/  _   _  \
\_/ \ / \_/
_/ \_
/     \
\_   _/
\ /
/ \
\_/
```

### SVG file

```( SVG ouput )

: draw-line ( direction -- ) \ line-length=10 ; sin(60)=0.87 ; cos(60)=0.5
case
0 of s" h 10"      type cr endof
1 of s" l  5  8.7" type cr endof
2 of s" l -5  8.7" type cr endof
3 of s" h -10"     type cr endof
4 of s" l -5 -8.7" type cr endof
5 of s" l  5 -8.7" type cr endof
endcase
;

: turn+ 1+ 6 mod ;
: turn- 1- 6 mod ;

defer curve
: A-rule ( order direction -- ) turn+  2dup 'B curve  turn-  2dup 'A curve  turn-  'B curve ;
: B-rule ( order direction -- ) turn-  2dup 'A curve  turn+  2dup 'B curve  turn+  'A curve ;

:noname ( order direction type -- )
2 pick 0 = if drop draw-line drop exit then \ draw line when order is 0
rot 1- rot rot
'A = if A-rule else B-rule then
; is curve

: raw. ( u -- ) 0 <# #s #> type ;

: svg-start
dup 1 swap lshift 10 * ( -- order image-width ) \ image-width is 2 power order
s" sierpinski_arrowhead.svg" w/o create-file throw to outfile-id
s" <svg xmlns='http://www.w3.org/2000/svg' width='" type dup raw.
87 * 100 / ( -- order image-height ) \ image-height; sin(60)=0.87
s" ' height='" type raw. s" '>" type cr
s" <rect width='100%' height='100%' fill='white'/>" type cr
s" <path stroke-width='1' stroke='black' fill='none' d='" type cr
s" M 0 0" type cr
;
: svg-end
s" '/> </svg>" type cr
outfile-id close-file throw
;

: arrowhead ( order -- )
outfile-id >r svg-start
0 'A curve
svg-end r> to outfile-id
;

5 arrowhead
```

## Go

Library: Go Graphics
Translation of: Phix

A partial translation anyway which produces a static image of a SAC of order 6, magenta on black, which can be viewed with a utility such as EOG.

```package main

import (
"github.com/fogleman/gg"
"math"
)

var (
width  = 770.0
height = 770.0
dc     = gg.NewContext(int(width), int(height))
iy     = 1.0
theta  = 0
)

var cx, cy, h float64

func arrowhead(order int, length float64) {
// if order is even, we can just draw the curve
if order&1 == 0 {
curve(order, length, 60)
} else {
turn(60)
curve(order, length, -60)
}
drawLine(length) // needed to make base symmetric
}

func drawLine(length float64) {
dc.LineTo(cx-width/2+h, (height-cy)*iy+2*h)
rads := gg.Radians(float64(theta))
cx += length * math.Cos(rads)
cy += length * math.Sin(rads)
}

func turn(angle int) {
theta = (theta + angle) % 360
}

func curve(order int, length float64, angle int) {
if order == 0 {
drawLine(length)
} else {
curve(order-1, length/2, -angle)
turn(angle)
curve(order-1, length/2, angle)
turn(angle)
curve(order-1, length/2, -angle)
}
}

func main() {
dc.SetRGB(0, 0, 0) // black background
dc.Clear()
order := 6
if order&1 == 0 {
iy = -1 // apex will point upwards
}
cx, cy = width/2, height
h = cx / 2
arrowhead(order, cx)
dc.SetRGB255(255, 0, 255) // magenta curve
dc.SetLineWidth(2)
dc.Stroke()
dc.SavePNG("sierpinski_arrowhead_curve.png")
}
```

## jq

Works with: jq

Works with gojq, the Go implementation of jq

This entry uses an L-system and turtle graphics to generate an SVG file, which can be viewed using a web browser, at least if the file type is `.svg`.

See Category_talk:Jq-turtle for the turtle.jq module used here. Please note that the `include` directive may need to be modified depending on the location of the included file, and the command-line options used.

```include "turtle" {search: "."};

# Compute the curve using a Lindenmayer system of rules
def rules:
{X: "Yf+Xf+Y", Y: "Xf-Yf-X", "": "X"};

def sierpinski(\$count):
rules as \$rules
| def repeat(\$count):
if \$count == 0 then .
else ascii_downcase | gsub("x"; \$rules["X"]) | gsub("y"; \$rules["Y"])
| repeat(\$count-1)
end;
\$rules[""] | repeat(\$count) ;

def interpret(\$x):
if   \$x == "+" then turtleRotate(60)
elif \$x == "-" then turtleRotate(-60)
elif \$x == "f" then turtleForward(3)
else .
end;

def sierpinski_curve(\$n):
sierpinski(\$n)
| split("")
| reduce .[] as \$action (
turtle([0,-350]) | turtleDown | turtleRotate(60);
interpret(\$action) ) ;

# viewBox = <min-x> <min-y> <width> <height>
# Input: {svg, minx, miny, maxx, maxy}
def svg:
"<svg viewBox='\(.minx|floor) \(.miny - 4 |floor) \(.maxx - .minx|ceil) \(6 + .maxy - .miny|ceil)'",
"     preserveAspectRatio='xMinYmin meet'",
"     xmlns='http://www.w3.org/2000/svg' >",
path("none"; "red"; 1),
"</svg>";

sierpinski_curve(8)
| svg```

## Julia

```using Lindenmayer # https://github.com/cormullion/Lindenmayer.jl

scurve = LSystem(Dict("F" => "G+F+Gt", "G"=>"F-G-F"), "G")

drawLSystem(scurve,
forward = 3,
turn = 60,
startingy = -350,
iterations = 8,
startingorientation = π/3,
filename = "sierpinski_arrowhead_curve.png",
showpreview = true
)
```

## Lambdatalk

```{def sierp
{def sierp.r
{lambda {:order :length :angle}
{if {= :order 0}
then M:length
else {sierp.r {- :order 1} {/ :length 2} {- :angle}}
T:angle
{sierp.r {- :order 1} {/ :length 2} :angle}
T:angle
{sierp.r {- :order 1} {/ :length 2} {- :angle}}
}}}
{lambda {:order :length}
{if {= {% :order 2} 0}
then {sierp.r :order :length 60}
else T60
{sierp.r :order :length -60}
}}}

the output can be seen in http://lambdaway.free.fr/lambdawalks/?view=sierpinsky
```

## Mathematica / Wolfram Language

```ClearAll[DoStep]
DoStep[Line[{x_, y_}]] := Module[{diff, perp, pts},
diff = y - x;
perp = Cross[diff] Sqrt[3]/2;
pts = {x, x + diff/4 + perp/2, x + 3 diff/4 + perp/2, y};
{Line[pts[[{2, 1}]]], Line[pts[[{2, 3}]]], Line[pts[[{4, 3}]]]}
]
lns = {Line[{{0.0, 0.0}, {1.0, 0.0}}]};
lns = Nest[Catenate[DoStep /@ #] &, lns, 5];
Graphics[lns]
```

## Nim

Translation of: C++

Output is an SVG file.

```import math

const Sqrt3_2 = sqrt(3.0) / 2.0

type Point = tuple[x, y: float]

func sierpinskiArrowheadNext(points: seq[Point]): seq[Point] =
result.setLen(3 * (points.len - 1) + 1)
var j = 0
for i in 0..<points.high:
let (x0, y0) = points[i]
let (x1, y1) = points[i + 1]
let dx = x1 - x0
result[j] = (x0, y0)
if y0 == y1:
let d = abs(dx * Sqrt3_2 / 2)
result[j + 1] = (x0 + dx / 4, y0 - d)
result[j + 2] = (x1 - dx / 4, y0 - d)
elif y1 < y0:
result[j + 1] = (x1, y0)
result[j + 2] = (x1 + dx / 2, (y0 + y1) / 2)
else:
result[j + 1] = (x0 - dx / 2, (y0 + y1) / 2)
result[j + 2] = (x0, y1)
inc j, 3
result[j] = points[^1]

proc writeSierpinskiArrowhead(outfile: File; size, iterations: int) =
outfile.write "<svg xmlns='http://www.w3.org/2000/svg' width='", size, "' height='", size, "'>\n"
outfile.write "<rect width='100%' height='100%' fill='white'/>\n"
outfile.write "<path stroke-width='1' stroke='black' fill='none' d='"
const Margin = 20.0
let side = size.toFloat - 2 * Margin
let x = Margin
let y = 0.5 * size.toFloat + 0.5 * Sqrt3_2 * side
var points = @[(x: x, y: y), (x: x + side, y: y)]
for _ in 1..iterations:
points = sierpinskiArrowheadNext(points)
for i, point in points:
outfile.write if i == 0: 'M' else: 'L', point.x, ',', point.y, '\n'
outfile.write "'/>\n</svg>\n"

let outfile = open("sierpinski_arrowhead.svg", fmWrite)
outfile.writeSierpinskiArrowhead(600, 8)
outfile.close()
```
Output:

See output of C++ program.

## Perl

```use strict;
use warnings;
use SVG;
use List::Util qw(max min);
use constant pi => 2 * atan2(1, 0);

my %rules = (
X => 'YF+XF+Y',
Y => 'XF-YF-X'
);
my \$S = 'Y';
\$S =~ s/([XY])/\$rules{\$1}/eg for 1..7;

my (@X, @Y);
my (\$x, \$y) = (0, 0);
my \$theta   = 0;
my \$r       = 6;

for (split //, \$S) {
if (/F/) {
push @X, sprintf "%.0f", \$x;
push @Y, sprintf "%.0f", \$y;
\$x += \$r * cos(\$theta);
\$y += \$r * sin(\$theta);
}
elsif (/\+/) { \$theta += pi/3; }
elsif (/\-/) { \$theta -= pi/3; }
}

my (\$xrng, \$yrng) = ( max(@X) - min(@X),  max(@Y) - min(@Y));
my (\$xt,   \$yt)   = (-min(@X) + 10,      -min(@Y) + 10);

my \$svg = SVG->new(width=>\$xrng+20, height=>\$yrng+20);
my \$points = \$svg->get_path(x=>\@X, y=>\@Y, -type=>'polyline');
\$svg->rect(width=>"100%", height=>"100%", style=>{'fill'=>'black'});
\$svg->polyline(%\$points, style=>{'stroke'=>'orange', 'stroke-width'=>1}, transform=>"translate(\$xt,\$yt)");

open my \$fh, '>', 'sierpinski-arrowhead-curve.svg';
print \$fh  \$svg->xmlify(-namespace=>'svg');
close \$fh;
```

See: sierpinski-arrowhead-curve.svg (offsite SVG image)

## Phix

Library: Phix/pGUI

You can run this online here, and experiment with [shift] +/- as noted below.

```--
-- demo\rosetta\Sierpinski_arrowhead_curve.exw
-- ===========================================
--
--  Draws curves lo to hi (simultaneously), initially {6,6}, max {10,10}, min {1,1}
--  Press +/- to change hi, shift +/- to change lo.
--  ("=_" are also mapped to "+-", for the non-numpad +/-)
--
with javascript_semantics
include pGUI.e

Ihandle dlg, canvas
cdCanvas cddbuffer, cdcanvas

integer width, height,
lo = 6, hi = 6
atom cx, cy, h, theta

integer iy = +1

procedure draw_line(atom l)
cdCanvasVertex(cddbuffer, cx-width/2+h, (height-cy)*iy+2*h)
cx += l*cos(theta*CD_DEG2RAD)
cy += l*sin(theta*CD_DEG2RAD)
end procedure

procedure turn(integer angle)
theta = mod(theta+angle,360)
end procedure

procedure curve(integer order, atom l, integer angle)
if order=0 then
draw_line(l)
else
curve(order-1, l/2, -angle)
turn(angle)
curve(order-1, l/2,  angle)
turn(angle)
curve(order-1, l/2, -angle)
end if
end procedure

procedure sierpinski_arrowhead_curve(integer order, atom l)
-- If order is even we can just draw the curve.
if and_bits(order,1)=0 then
curve(order, l, +60)
else -- order is odd
turn( +60)
curve(order, l, -60)
end if
draw_line(l)
end procedure

function redraw_cb(Ihandle /*ih*/, integer /*posx*/, /*posy*/)
{width, height} = IupGetIntInt(canvas, "DRAWSIZE")
cdCanvasActivate(cddbuffer)
for order=lo to hi do
cx = width/2
cy = height
h = cx/2
theta = 0
iy = iff(and_bits(order,1)?-1:+1)
cdCanvasBegin(cddbuffer, CD_OPEN_LINES)
sierpinski_arrowhead_curve(order, cx)
cdCanvasEnd(cddbuffer)
end for
cdCanvasFlush(cddbuffer)
return IUP_DEFAULT
end function

function map_cb(Ihandle ih)
cdcanvas = cdCreateCanvas(CD_IUP, ih)
cddbuffer = cdCreateCanvas(CD_DBUFFER, cdcanvas)
cdCanvasSetBackground(cddbuffer, CD_WHITE)
cdCanvasSetForeground(cddbuffer, CD_BLUE)
return IUP_DEFAULT
end function

function key_cb(Ihandle /*ih*/, atom c)
if c=K_ESC then return IUP_CLOSE end if
if find(c,"+=-_") then
bool bShift = IupGetInt(NULL,"SHIFTKEY")
if c='+' or c='=' then
if bShift then
lo = min(lo+1,hi)
else
hi = min(10,hi+1)
end if
elsif c='-' or c='_' then
if bShift then
lo = max(1,lo-1)
else
hi = max(lo,hi-1)
end if
end if
IupSetStrAttribute(dlg, "TITLE", "Sierpinski arrowhead curve (%d..%d)",{lo,hi})
cdCanvasClear(cddbuffer)
IupUpdate(canvas)
end if
return IUP_DEFAULT
end function

procedure main()
IupOpen()

canvas = IupCanvas(NULL)
IupSetAttribute(canvas, "RASTERSIZE", "770x770")
IupSetCallback(canvas, "MAP_CB", Icallback("map_cb"))
IupSetCallback(canvas, "ACTION", Icallback("redraw_cb"))

dlg = IupDialog(canvas)
IupSetAttribute(dlg, "TITLE", "Sierpinski arrowhead curve (6..6)")
IupSetCallback(dlg, "K_ANY", Icallback("key_cb"))

IupMap(dlg)
IupShowXY(dlg,IUP_CENTER,IUP_CENTER)
if platform()!=JS then
IupMainLoop()
IupClose()
end if
end procedure

main()
```

## Processing

```final PVector t = new PVector(20, 30, 60);

void setup() {
size(450, 400);
noLoop();
background(0, 0, 200);
stroke(-1);
sc(7, 400, -60, t);
}

PVector sc(int o, float l, final int a, final PVector s) {
if (o > 0) {
sc(--o, l *= .5, -a, s).z += a;
sc(o, l, a, s).z += a;
sc(o, l, -a, s);
} else line(s.x, s.y,
s.x += cos(radians(s.z)) * l,
s.y += sin(radians(s.z)) * l);
return s;
}
```
The sketch can be run online :
here.

### Processing Python mode

```t = { 'x': 20, 'y': 30, 'a': 60 }

def setup():
size(450, 400)
background(0, 0, 200)
stroke(-1)
sc(7, 400, -60)

def sc(o, l, a, s = t, X = 'x', Y = 'y', A = 'a', HALF = .5):
if o:
o -= 1
l *= HALF
sc(o, l, -a)[A] += a
sc(o, l, a)[A] += a
sc(o, l, -a)
else:
x, y = s[X], s[Y]
s[X] += cos(radians(s[A])) * l
s[Y] += sin(radians(s[A])) * l
line(x, y, s[X], s[Y])

return s
```

The sketch can be run online :
here.

## Python

```import matplotlib.pyplot as plt
import math

def nextPoint(x, y, angle):
a = math.pi * angle / 180
x2 = (int)(round(x + (1 * math.cos(a))))
y2 = (int)(round(y + (1 * math.sin(a))))
return x2, y2

def expand(axiom, rules, level):
for l in range(0, level):
a2 = ""
for c in axiom:
if c in rules:
a2 += rules[c]
else:
a2 += c
axiom = a2
return axiom

def draw_lsystem(axiom, rules, angle, iterations):
xp = [1]
yp = [1]
direction = 0
for c in expand(axiom, rules, iterations):
if c == "F":
xn, yn = nextPoint(xp[-1], yp[-1], direction)
xp.append(xn)
yp.append(yn)
elif c == "-":
direction = direction - angle
if direction < 0:
direction = 360 + direction
elif c == "+":
direction = (direction + angle) % 360

plt.plot(xp, yp)
plt.show()

if __name__ == '__main__':
# Sierpinski Arrowhead Curve L-System Definition
s_axiom = "XF"
s_rules = {"X": "YF+XF+Y",
"Y": "XF-YF-X"}
s_angle = 60

draw_lsystem(s_axiom, s_rules, s_angle, 7)
```

## Prolog

Works with: SWI Prolog
Translation of: C
```main:-
write_sierpinski_arrowhead('sierpinski_arrowhead.svg', 600, 8).

write_sierpinski_arrowhead(File, Size, Order):-
open(File, write, Stream),
format(Stream,
"<svg xmlns='http://www.w3.org/2000/svg' width='~d' height='~d'>\n",
[Size, Size]),
write(Stream, "<rect width='100%' height='100%' fill='white'/>\n"),
write(Stream, "<path stroke-width='1' stroke='black' fill='none' d='"),
Margin = 20.0,
Side is Size - 2.0 * Margin,
X = Margin,
Y is 0.5 * Size + 0.25 * sqrt(3) * Side,
Cursor = cursor(X, Y, 0),
(Order mod 2 == 1 -> turn(Cursor, -60, Cursor1) ; Cursor1 = Cursor),
format(Stream, "M~g,~g", [X, Y]),
curve(Stream, Order, Side, Cursor1, _, 60),
write(Stream, "'/>\n</svg>\n"),
close(Stream).

turn(cursor(X, Y, A), Angle, cursor(X, Y, A1)):-
A1 is (A + Angle) mod 360.

draw_line(Stream, cursor(X, Y, A), Length, cursor(X1, Y1, A)):-
Theta is (pi * A)/180.0,
X1 is X + Length * cos(Theta),
Y1 is Y + Length * sin(Theta),
format(Stream, "L~g,~g", [X1, Y1]).

curve(Stream, 0, Length, Cursor, Cursor1, _):-
!,
draw_line(Stream, Cursor, Length, Cursor1).
curve(Stream, Order, Length, Cursor, Cursor1, Angle):-
Order1 is Order - 1,
Angle1 is -Angle,
Length2 is Length/2.0,
curve(Stream, Order1, Length2, Cursor, Cursor2, Angle1),
turn(Cursor2, Angle, Cursor3),
curve(Stream, Order1, Length2, Cursor3, Cursor4, Angle),
turn(Cursor4, Angle, Cursor5),
curve(Stream, Order1, Length2, Cursor5, Cursor1, Angle1).
```
Output:

## Quackery

Using an L-system.

```  [ \$ "turtleduck.qky" loadfile ] now!

[ stack ]                      is switch.arg (   --> [ )

[ switch.arg put ]             is switch     ( x -->   )

[ switch.arg release ]         is otherwise  (   -->   )

[ switch.arg share
!= iff ]else[ done
otherwise ]'[ do ]done[ ]    is case       ( x -->   )

[ \$ "" swap witheach
[ nested quackery join ] ] is expand     ( \$ --> \$ )

[ \$ "L" ]                      is L          ( \$ --> \$ )

[ \$ "R" ]                      is R          ( \$ --> \$ )

[ \$ "BLALB" ]                  is A          ( \$ --> \$ )

[ \$ "ARBRA" ]                  is B          ( \$ --> \$ )

\$ "A"

6 times expand

turtle
10 frames
witheach
[ switch
[ char L case [ -1 6 turn ]
char R case [  1 6 turn ]
otherwise   [  4 1 walk ] ] ]
1 frames```
Output:

## Raku

(formerly Perl 6)

Works with: Rakudo version 2020.02
```use SVG;

role Lindenmayer {
has %.rules;
method succ {
self.comb.map( { %!rules{\$^c} // \$c } ).join but Lindenmayer(%!rules)
}
}

my \$arrow = 'X' but Lindenmayer( { X => 'YF+XF+Y', Y => 'XF-YF-X' } );

\$arrow++ xx 7;

my \$w = 800;
my \$h = (\$w * 3**.5 / 2).round(1);

my \$scale = 6;
my @points = (400, 15);
my \$dir = pi/3;

for \$arrow.comb {
state (\$x, \$y) = @points[0,1];
state \$d = \$dir;
when 'F' { @points.append: (\$x += \$scale * \$d.cos).round(1), (\$y += \$scale * \$d.sin).round(1) }
when '+' { \$d += \$dir }
when '-' { \$d -= \$dir }
default { }
}

my \$out = './sierpinski-arrowhead-curve-perl6.svg'.IO;

\$out.spurt:  SVG.serialize(
svg => [
:width(\$w), :height(\$h),
:rect[:width<100%>, :height<100%>, :fill<black>],
:polyline[ :points(@points.join: ','), :fill<black>, :style<stroke:#FF4EA9> ],
],
);
```

See: Sierpinski-arrowhead-curve-perl6.svg (offsite SVG image)

## REXX

Translation of: Algol W
```/*REXX pgm computes and displays a Sierpinski Arrowhead Curve using the characters: \_/ */
parse arg order .                                /*obtain optional argument from the CL.*/
if order=='' | order==","  then order=   5       /*Not specified?  Then use the default.*/
say '  Sierpinski arrowhead curve of order'   order             /*display the   title.  */
say '═════════════════════════════════════════'                 /*   "     "  separator.*/
\$= init()                                        /*initialize a bunch of variables.     */
if order//2  then do;  call turn +60;  call curve order, len, -60;  end    /*CURVE odd? */
else                      call curve order, len, +60          /*CURVE even.*/

do    row=Ly  to Hy;   a=                 /*show arrowhead graph 1 row at a time.*/
do col=Lx  to Hx;   a= a || @.col.row  /*build a row of   "   " col  " "   "  */
end   /*col*/;  say strip(a, 'T')      /*show  "  "   "   "     row  " "   "  */
end      /*row*/
exit 0                                           /*stick a fork in it,  we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
init:  @.=" "; #=0; len=512; x=len; y=x;Hx=x;Hy=y;Lx=x;Ly=y; return '@. # Hx Hy Lx Ly x y'
turn:  parse arg angle; #= (#+angle)//360;  if #<0  then #= #+360;  return  /*normalize.*/
/*──────────────────────────────────────────────────────────────────────────────────────*/
curve: procedure expose (\$);  parse arg order,len,angle  /*\$:  list of exposed variables*/
if order==0  then call draw len                   /*Is ORDER zero?  Then draw it.*/
else do;  call curve order-1, len/2, -angle;      call turn angle
call curve order-1, len/2, +angle;      call turn angle
call curve order-1, len/2, -angle
end
return                                    /*The  CURVE  function is recursive.   */
/*──────────────────────────────────────────────────────────────────────────────────────*/
draw:  select                                    /*draw part of the curve using a char. */
when #==  0  then do;    @.x.y= '_';      x= x + 1;                        end
when #== 60  then do;    @.x.y= '/';      x= x + 1;        y= y - 1;       end
when #==120  then do;    x= x - 1;        @.x.y= '\';      y= y - 1;       end
when #==180  then do;    x= x - 1;        @.x.y= '_';                      end
when #==240  then do;    x= x - 1;        y= y + 1;        @.x.y= '/';     end
when #==300  then do;    y= y + 1;        @.x.y= '\';      x= x + 1;       end
end   /*select*/                      /*curve character is based on direction*/
Lx= min(Lx,x);  Hx= max(Hx,x);  Ly= min(Ly,y);  Hy= max(Hy,y)  /*min&max  of  x,y*/
return                                    /*#:  heading in degrees of the curve. */
```
output   when using the default input value of:     5
```  Sierpinski arrowhead curve of order 5
═════════════════════════════════════════
_
/ \
\ /
_/ \_
/     \
\_   _/
_  \ /  _
/ \_/ \_/ \
\         /
_/         \_
/  _       _  \
\_/ \     / \_/
_    /     \    _
/ \   \_   _/   / \
\ /  _  \ /  _  \ /
_/ \_/ \_/ \_/ \_/ \_
/                     \
\_                   _/
_  \                 /  _
/ \_/                 \_/ \
\    _               _    /
_/   / \             / \   \_
/  _  \ /             \ /  _  \
\_/ \_/ \_           _/ \_/ \_/
_          \         /          _
/ \        _/         \_        / \
\ /       /  _       _  \       \ /
_/ \_      \_/ \     / \_/      _/ \_
/     \    _    /     \    _    /     \
\_   _/   / \   \_   _/   / \   \_   _/
_  \ /  _  \ /  _  \ /  _  \ /  _  \ /  _
/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \
```

## Ruby

Library: RubyGems
Library: JRubyArt

For grammar see Hilbert Curve

```load_libraries :grammar
attr_reader :points

def setup
sketch_title 'Sierpinski Arrowhead'
sierpinski = SierpinskiArrowhead.new(Vec2D.new(width * 0.15, height * 0.7))
production = sierpinski.generate 6 # 6 generations looks OK
@points = sierpinski.translate_rules(production)
no_loop
end

def draw
background(0)
render points
end

def render(points)
no_fill
stroke 200.0
stroke_weight 3
begin_shape
points.each_slice(2) do |v0, v1|
v0.to_vertex(renderer)
v1.to_vertex(renderer)
end
end_shape
end

def renderer
@renderer ||= GfxRender.new(g)
end

def settings
size(800, 800)
end

# SierpinskiArrowhead class
class SierpinskiArrowhead
include Processing::Proxy
attr_reader :draw_length, :pos, :theta, :axiom, :grammar
DELTA = PI / 3 # 60 degrees
def initialize(pos)
@axiom = 'XF' # Axiom
rules = {
'X' => 'YF+XF+Y',
'Y' => 'XF-YF-X'
}
@grammar = Grammar.new(axiom, rules)
@theta = 0
@draw_length = 200
@pos = pos
end

def generate(gen)
@draw_length = draw_length * 0.6**gen
grammar.generate gen
end

def forward(pos)
pos + Vec2D.from_angle(theta) * draw_length
end

def translate_rules(prod)
[].tap do |pts| # An array to store line vertices as Vec2D
prod.scan(/./) do |ch|
case ch
when 'F'
new_pos = forward(pos)
pts << pos << new_pos
@pos = new_pos
when '+'
@theta += DELTA
when '-'
@theta -= DELTA
when 'X', 'Y'
else
puts("character #{ch} not in grammar")
end
end
end
end
end
```

## Rust

Output is a file in SVG format. Another variation on the same theme as the C, Go and Phix solutions.

```// [dependencies]
// svg = "0.8.0"

const SQRT3_2: f64 = 0.86602540378444;

use svg::node::element::path::Data;

struct Cursor {
x: f64,
y: f64,
angle: i32,
}

impl Cursor {
fn new(x: f64, y: f64) -> Cursor {
Cursor {
x: x,
y: y,
angle: 0,
}
}
fn turn(&mut self, angle: i32) {
self.angle = (self.angle + angle) % 360;
}
fn draw_line(&mut self, data: Data, length: f64) -> Data {
let theta = (self.angle as f64).to_radians();
self.x += length * theta.cos();
self.y += length * theta.sin();
data.line_to((self.x, self.y))
}
}

fn curve(mut data: Data, order: usize, length: f64, cursor: &mut Cursor, angle: i32) -> Data {
if order == 0 {
return cursor.draw_line(data, length);
}
data = curve(data, order - 1, length / 2.0, cursor, -angle);
cursor.turn(angle);
data = curve(data, order - 1, length / 2.0, cursor, angle);
cursor.turn(angle);
curve(data, order - 1, length / 2.0, cursor, -angle)
}

fn write_sierpinski_arrowhead(file: &str, size: usize, order: usize) -> std::io::Result<()> {
use svg::node::element::Path;
use svg::node::element::Rectangle;

let margin = 20.0;
let side = (size as f64) - 2.0 * margin;
let y = 0.5 * (size as f64) + 0.5 * SQRT3_2 * side;
let x = margin;
let mut cursor = Cursor::new(x, y);
if (order & 1) != 0 {
cursor.turn(-60);
}
let mut data = Data::new().move_to((x, y));
data = curve(data, order, side, &mut cursor, 60);
let rect = Rectangle::new()
.set("width", "100%")
.set("height", "100%")
.set("fill", "white");
let mut document = svg::Document::new()
.set("width", size)
.set("height", size)
.add(rect);
let path = Path::new()
.set("fill", "none")
.set("stroke", "black")
.set("stroke-width", "1")
.set("d", data);
document = document.add(path);
svg::save(file, &document)
}

fn main() {
write_sierpinski_arrowhead("sierpinski_arrowhead.svg", 600, 8).unwrap();
}
```
Output:

## Sidef

Uses the LSystem() class from Hilbert curve.

```var rules = Hash(
x => 'yF+xF+y',
y => 'xF-yF-x',
)

var lsys = LSystem(
width:  550,
height: 500,

xoff: -20,
yoff: -30,

len:   4,
turn: -90,
angle: 60,
color: 'dark green',
)

lsys.execute('xF', 7, "sierpiński_arrowhead.png", rules)
```

Output image: Sierpiński arrowhead

## Wren

Translation of: Go
Library: DOME
```import "graphics" for Canvas, Color, Point
import "dome" for Window

class Game {
static init() {
Window.title = "Sierpinski Arrowhead Curve"
__width = 770
__height = 770
Window.resize(__width, __height)
Canvas.resize(__width, __height)
var order = 6
__iy = (order&1 == 0) ? -1: 1  // apex will point upwards
__theta = 0
__cx = __width / 2
__cy = __height
__h  = __cx / 2
__prev = Point.new(__cx-__width/2 +__h, (__height-__cy)*__iy + 2*__h)
__col = Color.white
arrowhead(order, __cx)
}

static update() {}

static draw(alpha) {}

static arrowhead(order, length) {
// if order is even, we can just draw the curve
if (order&1 == 0) {
curve(order, length, 60)
} else {
turn(60)
curve(order, length, -60)
}
drawLine(length) // needed to make base symmetric
}

static drawLine(length) {
var curr = Point.new(__cx-__width/2 +__h, (__height-__cy)*__iy + 2*__h)
Canvas.line(__prev.x, __prev.y, curr.x, curr.y, __col)
var rads = __theta * Num.pi / 180
__cx = __cx + length*(rads.cos)
__cy = __cy + length*(rads.sin)
__prev = curr
}

static turn(angle) { __theta = (__theta + angle) % 360 }

static curve(order, length, angle) {
if (order == 0) {
drawLine(length)
} else {
curve(order-1, length/2, -angle)
turn(angle)
curve(order-1, length/2, angle)
turn(angle)
curve(order-1, length/2, -angle)
}
}
}
```

## XPL0

```int  PosX, PosY;
real Dir;

proc Curve(Order, Length, Angle);
int  Order; real Length, Angle;
[if Order = 0 then
[PosX:= PosX + fix(Length*Cos(Dir));
PosY:= PosY - fix(Length*Sin(Dir));
Line(PosX, PosY, \$E \yellow\);
]
else    [Curve(Order-1, Length/2.0, -Angle);
Dir:= Dir + Angle;
Curve(Order-1, Length/2.0, +Angle);
Dir:= Dir + Angle;
Curve(Order-1, Length/2.0, -Angle);
];
];

def Order=5, Length=300.0, Pi=3.141592654, Sixty=Pi/3.0;
[SetVid(\$12);   \VGA graphics: 640x480x8
PosX:= 640/4;  PosY:= 3*480/4;
Move(PosX, PosY);
Dir:= 0.0;
if (Order&1) = 0 then
Curve(Order, Length, +Sixty)
else    [Dir:= Dir + Sixty;
Curve(Order, Length, -Sixty);
];
]```
Output:
```http://www.xpl0.org/rcarrow.gif
```

## zkl

Uses Image Magick and the PPM class from http://rosettacode.org/wiki/Bitmap/Bresenham%27s_line_algorithm#zkl

```order:=7;
sierpinskiArrowheadCurve(order) : turtle(_,order);

fcn sierpinskiArrowheadCurve(n){   // Lindenmayer system --> Data of As & Bs
var [const] A="BF+AF+B", B="AF-BF-A";  // Production rules
var [const] Axiom="AF";
buf1,buf2 := Data(Void,Axiom).howza(3), Data().howza(3);  // characters
do(n){
buf1.pump(buf2.clear(),fcn(c){ if(c=="A") A else if(c=="B") B else c });
t:=buf1; buf1=buf2; buf2=t;	// swap buffers
}
buf1		// n=7 --> 6,560 characters
}

fcn turtle(curve,order){	// Turtle with that can turn +-60*
const D=10.0, a60=60;
dir:=order.isOdd and a60 or 0;	   // start direction depends on order
img,color := PPM(1300,1200), 0x00ff00;  // green on black
x,y := 10, 10;
foreach c in (curve){  // A & B are no-op during drawing
switch(c){
case("F"){   // draw forward
a,b := D.toRectangular(dir.toFloat().toRad());
img.line(x,y, (x+=a.round()),(y+=b.round()), color)
}
case("+"){ dir=(dir - a60)%360; } // turn left  60*
case("-"){ dir=(dir + a60)%360; } // turn right 60*
}
}
img.writeJPGFile("sierpinskiArrowheadCurve.zkl.jpg");
}```
Output:

Offsite image at Sierpinski arrowhead curve order 7