Sometimes magic is just someone spending more time on something than anyone else might reasonably expect. – Teller
Generate mazes recursively via Turtle graphics.
– Steven E. Pav, shabbychef@gmail.com
This package can be installed from CRAN, via drat, or from github:
# via CRAN:
install.packages("mazealls")
# via drat:
if (require(drat)) {
:::add("shabbychef")
dratinstall.packages("mazealls")
}# get snapshot from github (may be buggy)
if (require(devtools)) {
install_github("shabbychef/mazealls")
}
The simplest maze to generate recursively is a parallelogram. One can
generate a parallelogram maze by splitting the domain into two parts by
an arbitrary cut line with a hole in it, and then recursively creating
mazes on both parts. Unlike some shapes, this method applies for
arbitrary (integral) side lengths, where by ‘length’ we mean in units of
‘hallway widths’, what we call the unit_len
in the API.
Here is a simple parallelogram maze:
library(TurtleGraphics)
library(mazealls)
turtle_init(1000, 1000)
turtle_up()
turtle_hide()
turtle_do({
turtle_left(90)
turtle_forward(distance = 400)
turtle_right(90)
parallelogram_maze(angle = 90, unit_len = 10, width = 75,
height = 55, method = "uniform", draw_boundary = TRUE)
})
The parallelogram_maze
function admits a
balance
parameter which controls how the maze should be
recursively subdivided. A negative value creates imbalanced mazes, while
positive values create more uniform mazes. In the example below we
create seven mazes side by side with an increasing balance
parameter:
library(TurtleGraphics)
library(mazealls)
turtle_init(2000, 2000)
turtle_hide()
turtle_up()
turtle_do({
turtle_left(90)
turtle_forward(930)
turtle_right(90)
<- seq(from = -1.5, to = 1.5, length.out = 7)
valseq <- c(1, 2, 3, 4)
blines <- c(1, 3)
bholes set.seed(1234)
for (iii in seq_along(valseq)) {
parallelogram_maze(angle = 90, unit_len = 12,
width = 22, height = 130, method = "two_parallelograms",
draw_boundary = TRUE, balance = valseq[iii],
end_side = 3, boundary_lines = blines,
boundary_holes = bholes)
turtle_right(180)
<- c(2, 3, 4)
blines <- c(3)
bholes
} })
An equilateral triangle maze can be constructed in a number of different ways:
I illustrate them here:
library(TurtleGraphics)
library(mazealls)
# uniform method
turtle_init(1000, 1000)
turtle_up()
turtle_hide()
turtle_do({
turtle_left(90)
turtle_forward(distance = 300)
turtle_right(90)
eq_triangle_maze(depth = 6, unit_len = 12, method = "uniform",
draw_boundary = TRUE)
})
library(TurtleGraphics)
library(mazealls)
# stacked trapezoids
turtle_init(1000, 1000)
turtle_up()
turtle_hide()
turtle_do({
turtle_left(90)
turtle_forward(distance = 300)
turtle_right(90)
eq_triangle_maze(depth = 6, unit_len = 12, method = "stack_trapezoids",
draw_boundary = TRUE)
})
library(TurtleGraphics)
library(mazealls)
# four triangles
turtle_init(1000, 1000)
turtle_up()
turtle_hide()
turtle_do({
turtle_left(90)
turtle_forward(distance = 300)
turtle_right(90)
eq_triangle_maze(depth = 6, unit_len = 12, method = "triangles",
draw_boundary = TRUE)
})
library(TurtleGraphics)
library(mazealls)
# two ears
turtle_init(1000, 1000)
turtle_up()
turtle_hide()
turtle_do({
turtle_left(90)
turtle_forward(distance = 300)
turtle_right(90)
eq_triangle_maze(depth = 6, unit_len = 12, method = "two_ears",
draw_boundary = TRUE)
})
library(TurtleGraphics)
library(mazealls)
# hex and three
turtle_init(1000, 1000)
turtle_up()
turtle_hide()
turtle_do({
turtle_left(90)
turtle_forward(distance = 300)
turtle_right(90)
eq_triangle_maze(depth = log2(66), unit_len = 12,
method = "hex_and_three", draw_boundary = TRUE)
})
library(TurtleGraphics)
library(mazealls)
# shave
turtle_init(1000, 1000)
turtle_up()
turtle_hide()
turtle_do({
turtle_left(90)
turtle_forward(distance = 300)
turtle_right(90)
eq_triangle_maze(depth = log2(66), unit_len = 12,
method = "shave", draw_boundary = TRUE)
})
library(TurtleGraphics)
library(mazealls)
# shave all
turtle_init(1000, 1000)
turtle_up()
turtle_hide()
turtle_do({
turtle_left(90)
turtle_forward(distance = 300)
turtle_right(90)
eq_triangle_maze(depth = log2(66), unit_len = 12,
method = "shave_all", draw_boundary = TRUE,
boustro = c(35, 2))
})
An regular hexagonal maze can be constructed in a number of different ways:
library(TurtleGraphics)
library(mazealls)
# two trapezoids
turtle_init(1000, 1000)
turtle_up()
turtle_hide()
turtle_do({
turtle_left(90)
turtle_forward(distance = 300)
turtle_right(90)
hexagon_maze(depth = 5, unit_len = 12, method = "two_trapezoids",
draw_boundary = TRUE)
})
library(TurtleGraphics)
library(mazealls)
# six triangles
turtle_init(1000, 1000)
turtle_up()
turtle_hide()
turtle_do({
turtle_left(90)
turtle_forward(distance = 300)
turtle_right(90)
hexagon_maze(depth = 5, unit_len = 12, method = "six_triangles",
draw_boundary = TRUE, boundary_hole_arrows = TRUE)
})
library(TurtleGraphics)
library(mazealls)
# six triangles
turtle_init(1000, 1000)
turtle_up()
turtle_hide()
turtle_do({
turtle_left(90)
turtle_forward(distance = 300)
turtle_right(90)
hexagon_maze(depth = 5, unit_len = 12, method = "three_parallelograms",
draw_boundary = TRUE, boundary_hole_arrows = TRUE)
})
A dodecagon can be dissected into a hexagon and a ring of alternating squares and equilateral triangles:
library(TurtleGraphics)
library(mazealls)
# dodecagon
turtle_init(2200, 2200, mode = "clip")
turtle_hide()
turtle_up()
turtle_do({
turtle_setpos(80, 1100)
turtle_setangle(0)
dodecagon_maze(depth = log2(27), unit_len = 20,
draw_boundary = TRUE, boundary_holes = c(1,
7))
})
An isosceles trapezoid maze can be constructed in a number of different ways:
library(TurtleGraphics)
library(mazealls)
# four trapezoids
turtle_init(1000, 1000)
turtle_up()
turtle_hide()
turtle_do({
turtle_left(90)
turtle_forward(distance = 300)
turtle_right(90)
iso_trapezoid_maze(depth = 5, unit_len = 12, method = "four_trapezoids",
draw_boundary = TRUE)
})
library(TurtleGraphics)
library(mazealls)
# one ear
turtle_init(1000, 1000)
turtle_up()
turtle_hide()
turtle_do({
turtle_left(90)
turtle_forward(distance = 300)
turtle_right(90)
iso_trapezoid_maze(depth = 5, unit_len = 12, method = "one_ear",
draw_boundary = TRUE)
})
Regular 2n gons usually admit a dissection into rhombuses. Sometimes, however, these have extremely acute angles, which do not translate into nice mazes. At the moment, there is only support for octagons, and decagons. While a dodecagon would also admit such a dissection, this would require extremely acute angles which would make an ugly maze.
library(TurtleGraphics)
library(mazealls)
# octagon
turtle_init(2000, 2000, mode = "clip")
turtle_hide()
turtle_up()
turtle_do({
turtle_setpos(75, 1000)
turtle_setangle(0)
octagon_maze(log2(48), 16, draw_boundary = TRUE,
boundary_holes = c(1, 5))
})
library(TurtleGraphics)
library(mazealls)
# decagon
turtle_init(2200, 2200, mode = "clip")
turtle_hide()
turtle_up()
turtle_do({
turtle_setpos(60, 1100)
turtle_setangle(0)
decagon_maze(5, 21, draw_boundary = TRUE, boundary_holes = c(1,
6))
})
Everyone’s favorite snowflake can also be a maze. Simply fill in triangle bumps with triangular mazes and create lines with holes as needed:
library(TurtleGraphics)
library(mazealls)
# koch flake
turtle_init(1000, 1000)
turtle_up()
turtle_hide()
turtle_do({
turtle_left(90)
turtle_forward(distance = 200)
turtle_right(90)
turtle_backward(distance = 300)
koch_maze(depth = 4, unit_len = 8)
})
Koch flakes of different sizes tile the plane:
library(TurtleGraphics)
library(mazealls)
# koch flake
turtle_init(2000, 2000, mode = "clip")
turtle_up()
turtle_hide()
turtle_do({
turtle_setpos(450, 1000)
turtle_setangle(60)
<- 12
ul <- 4
dep koch_maze(depth = dep, unit_len = ul, clockwise = TRUE,
draw_boundary = FALSE)
turtle_left(30)
turtle_col("gray40")
<- 1
dropdown for (iii in c(1:6)) {
if (iii == 1) {
<- c(1, 2)
bholes else if (iii == 4) {
} <- c(1, 3)
bholes else {
} <- c(1)
bholes
}koch_maze(depth = dep - dropdown, unit_len = ul *
3^(dropdown - 0.5)), clockwise = FALSE,
(draw_boundary = TRUE, boundary_holes = bholes,
boundary_hole_arrows = c(2, 3))
turtle_forward(3^(dep - 1) * ul * sqrt(3))
turtle_right(60)
} })
Similarly, one can construct a maze in a Sierpinski triangle.
library(TurtleGraphics)
library(mazealls)
turtle_init(2500, 2500, mode = "clip")
turtle_up()
turtle_hide()
turtle_do({
turtle_setpos(50, 1250)
turtle_setangle(0)
sierpinski_maze(unit_len = 19, depth = 7, draw_boundary = TRUE,
boundary_lines = TRUE, boundary_holes = c(1,
3), color1 = "black", color2 = "gray60")
})
And a Sierpinski Carpet:
library(TurtleGraphics)
library(mazealls)
turtle_init(800, 1000)
turtle_up()
turtle_hide()
turtle_do({
turtle_setpos(50, 450)
turtle_setangle(0)
sierpinski_carpet_maze(angle = 80, unit_len = 8,
width = 90, height = 90, draw_boundary = TRUE,
boundary_holes = c(1, 3), balance = 1.5, color2 = "green")
})
library(TurtleGraphics)
library(mazealls)
turtle_init(2000, 2000, mode = "clip")
turtle_hide()
turtle_up()
<- list(c(1, 2), c(1), c(2))
bholes turtle_do({
turtle_setpos(1000, 1000)
turtle_setangle(180)
for (iii in c(1:3)) {
<- bholes[[iii]]
mybhol sierpinski_carpet_maze(angle = 120, unit_len = 11,
width = 81, height = 81, draw_boundary = TRUE,
boundary_lines = c(1, 2, 3), num_boundary_holes = 0,
boundary_holes = mybhol, balance = 1, color2 = "green",
start_from = "corner")
turtle_left(120)
} })
One can make four different kinds of Sierpinski trapezoids, the traditional four triangles, a hexaflake, and something like a Dragon fractal:
library(TurtleGraphics)
library(mazealls)
turtle_init(1050, 600, mode = "clip")
turtle_hide()
turtle_up()
turtle_do({
for (iii in c(1:4)) {
turtle_setpos(40 + (iii - 1) * 250, 300)
turtle_setangle(0)
sierpinski_trapezoid_maze(unit_len = 8, depth = 5,
draw_boundary = TRUE, start_from = "midpoint",
num_boundary_holes = 2, boundary_holes = c(2,
4), color2 = "green", flip_color_parts = iii) # this controls fractal style
} })
A hexaflake is a cross between a Koch snowflake and a Sierpinski triangle, at least in theory.
library(TurtleGraphics)
library(mazealls)
# hexaflake
<- 2400
long_side <- long_side * sqrt(3)/2
inner_side <- long_side/2
sidelen <- 4
dep <- floor(sidelen/(3^dep))
ul <- 2 * ul * 3^dep * sqrt(3)/2
true_wid
turtle_init(ceiling(1.1 * inner_side), ceiling(1.1 *
mode = "clip")
long_side), turtle_up()
turtle_hide()
turtle_do({
turtle_setpos(0.5 * (ceiling(1.1 * inner_side) -
0.55 * long_side)
true_wid), turtle_setangle(0)
hexaflake_maze(depth = dep, unit_len = floor(sidelen/(3^dep)),
draw_boundary = TRUE, color2 = "gray80")
})
The unit_len
parameter controls the graphical length of
one ‘unit’, which is the length of holes between sections of the mazes,
and is roughly the width of the ‘hallways’ of a maze. Here is an example
of using different unit lengths in a stack of trapezoids
library(TurtleGraphics)
library(mazealls)
# stack some trapezoids with different unit_len
turtle_init(2500, 2500)
turtle_up()
turtle_hide()
turtle_do({
turtle_left(90)
turtle_forward(distance = 800)
turtle_right(90)
<- TRUE
clockwise for (iii in c(1:6)) {
iso_trapezoid_maze(depth = 5, unit_len = 2^(6 -
method = "four_trapezoids", draw_boundary = TRUE,
iii), clockwise = clockwise, end_side = 3, start_from = "midpoint",
boundary_lines = c(1, 2, 4), boundary_holes = c(1))
<- !clockwise
clockwise
} })
The parameters draw_boundary
,
boundary_lines
, boundary_holes
,
num_boundary_holes
and boundary_hole_color
control the drawing of the final outer boundary of polynomial mazes.
Without a boundary the maze can be used in recursive construction.
Adding a boundary provides the typical entry and exit points of a maze.
The parameter draw_boundary
is a single Boolean that
controls whether the boundary is drawn or not. The parameter
boundary_lines
may be a scalar Boolean, or a numeric array
giving the indices of which sides should have drawn boundary lines. The
sides are numbered in the order in which they appear, and are controlled
by the clockwise
parameter. The parameter
boundary_holes
is a numeric array giving the indices of the
boundary lines that should have holes. If NULL
, then we
uniformly choose num_boundary_holes
holes at random. Holes
can be drawn as colored segments with the
boundary_hole_color
, which is a character array giving the
color of each hole. The value ‘clear’ stands in for clear holes.
library(TurtleGraphics)
library(mazealls)
# side by side
turtle_init(1000, 400)
turtle_up()
turtle_hide()
turtle_do({
turtle_left(90)
turtle_forward(distance = 450)
turtle_right(90)
parallelogram_maze(unit_len = 10, height = 25,
draw_boundary = FALSE, end_side = 3)
turtle_left(90)
turtle_forward(distance = 30)
turtle_left(90)
parallelogram_maze(unit_len = 10, height = 25,
draw_boundary = TRUE, boundary_lines = c(1,
3), boundary_holes = FALSE, end_side = 3)
turtle_left(90)
turtle_forward(distance = 30)
turtle_left(90)
parallelogram_maze(unit_len = 10, height = 25,
draw_boundary = TRUE, boundary_lines = c(2,
4), boundary_holes = c(2, 4), boundary_hole_color = c("ignore",
"green", "ignore", "blue"))
})
The end_side
parameter controls which side of the maze
the turtle ends on. The default value of 1 essentially causes the turtle
to end where it started. The sides are numbered in the order in which
the boundary would be drawn. Along with the boundary controls, the
ending side can be useful to join together polygons into more complex
mazes, as below:
library(TurtleGraphics)
library(mazealls)
# triangle of hexes
turtle_init(2500, 2500)
turtle_up()
turtle_hide()
<- 22
ul <- 4
dep turtle_do({
turtle_left(90)
turtle_forward(distance = 1150)
turtle_right(90)
turtle_backward(distance = 650)
hexagon_maze(unit_len = ul, depth = dep, end_side = 4,
draw_boundary = TRUE, boundary_holes = c(1,
3, 4))
parallelogram_maze(unit_len = ul, height = 2^dep,
clockwise = FALSE, width = 3 * (2^dep), end_side = 3,
draw_boundary = TRUE, num_boundary_holes = 0,
boundary_lines = c(2, 4))
hexagon_maze(unit_len = ul, depth = dep, end_side = 2,
draw_boundary = TRUE, boundary_holes = c(1,
2))
parallelogram_maze(unit_len = ul, height = 2^dep,
clockwise = FALSE, width = 3 * (2^dep), end_side = 3,
draw_boundary = TRUE, num_boundary_holes = 0,
boundary_lines = c(2, 4))
hexagon_maze(unit_len = ul, depth = dep, end_side = 2,
draw_boundary = TRUE, boundary_holes = c(1,
5))
parallelogram_maze(unit_len = ul, height = 2^dep,
clockwise = FALSE, width = 3 * (2^dep), end_side = 3,
draw_boundary = TRUE, num_boundary_holes = 0,
boundary_lines = c(2, 4))
})
library(TurtleGraphics)
library(mazealls)
# tiling!
<- function(unit_len, depth, clockwise = TRUE,
tile_bit draw_boundary = FALSE, boundary_holes = NULL) {
turtle_col("black")
parallelogram_maze(unit_len = unit_len, height = 2^depth,
clockwise = clockwise, draw_boundary = TRUE,
num_boundary_holes = 4)
turtle_col("red")
for (iii in c(1:4)) {
turtle_forward(unit_len * 2^(depth - 1))
turtle_right(90)
turtle_forward(unit_len * 2^(depth - 1))
eq_triangle_maze(unit_len = unit_len, depth = depth,
clockwise = !clockwise, draw_boundary = draw_boundary,
boundary_lines = ifelse(iii <= 2, 2, 3),
num_boundary_holes = 3, end_side = ifelse(iii ==
4, 2, 1))
if (iii == 2) {
turtle_col("blue")
}
}turtle_col("black")
if (draw_boundary) {
<- c(1, 2, 4)
blines else {
} = 1
blines
}parallelogram_maze(unit_len = unit_len, height = 2^depth,
clockwise = clockwise, draw_boundary = TRUE,
boundary_lines = blines, boundary_holes = blines,
end_side = 3)
turtle_forward(unit_len * 2^(depth - 1))
turtle_left(60)
turtle_forward(unit_len * 2^(depth - 1))
}
turtle_init(2500, 2500, mode = "clip")
turtle_up()
turtle_hide()
<- 220
x0 <- 0
y0 <- 20
ul <- 5
dep turtle_do({
for (jjj in c(1:5)) {
turtle_setpos(x = x0, y = y0)
turtle_setangle(angle = 0)
replicate(5, tile_bit(unit_len = ul, depth = dep,
draw_boundary = TRUE))
<- x0 + ul * (2^dep) * (1 + sqrt(3)/2)
x0 <- y0 + ul * (2^(dep - 1))
y0
} })
Or whatever you call it. Here are some mazes built using the primitives.
Like it says on the label.
library(TurtleGraphics)
library(mazealls)
<- function(unit_len, depth, height, left_shrink = 3/4,
treeit right_shrink = 1/3) {
<- ceiling(height)
height parallelogram_maze(unit_len = unit_len, height = 2^depth,
width = height, clockwise = TRUE, draw_boundary = TRUE,
boundary_lines = c(1, 2, 4), start_from = "midpoint",
boundary_holes = c(1), end_side = 3)
if (depth > 0) {
iso_trapezoid_maze(depth = depth - 1, unit_len = unit_len,
clockwise = FALSE, draw_boundary = TRUE,
boundary_lines = c(1, 3), start_from = "midpoint",
boundary_holes = c(1), end_side = 4)
treeit(unit_len = unit_len, depth = depth -
1, height = left_shrink * height, left_shrink = left_shrink,
right_shrink = right_shrink)
turtle_right(180)
turtle_forward(unit_len * 2^(depth - 2))
turtle_right(60)
turtle_forward(unit_len * 2^(depth - 1))
turtle_right(60)
turtle_forward(unit_len * 2^(depth - 2))
turtle_right(180)
treeit(unit_len = unit_len, depth = depth -
1, height = right_shrink * height, left_shrink = left_shrink,
right_shrink = right_shrink)
turtle_forward(unit_len * 2^(depth - 2))
turtle_left(60)
turtle_forward(unit_len * 2^(depth - 2))
turtle_left(90)
turtle_forward(unit_len * sqrt(3) * 2^(depth -
2))
turtle_left(90)
}turtle_right(90)
turtle_forward(unit_len * height)
turtle_right(90)
}
turtle_init(2500, 2500, mode = "clip")
turtle_up()
turtle_hide()
turtle_do({
turtle_setpos(1600, 20)
turtle_setangle(270)
treeit(unit_len = 13, depth = 5, height = 70, left_shrink = 2/3,
right_shrink = 1/3)
})
turtle_init(2500, 2500, mode = "clip")
turtle_up()
turtle_hide()
<- -3
della <- seq(from = 120, to = 2 - della, by = della)
lens
<- 10
ulen <- 14
high turtle_do({
turtle_setpos(260, 570)
turtle_setangle(270)
for (iter in seq_along(lens)) {
parallelogram_maze(unit_len = ulen, height = high,
width = lens[iter], start_from = "corner",
clockwise = TRUE, draw_boundary = TRUE,
boundary_holes = c(1, 3), end_side = 3)
eq_triangle_maze(unit_len = ulen, depth = log2(high),
start_from = "corner", clockwise = FALSE,
draw_boundary = TRUE, boundary_lines = c(3),
num_boundary_holes = 0, boundary_holes = rep(FALSE,
3), end_side = 2)
}parallelogram_maze(unit_len = ulen, height = high,
width = lens[iter] + della, start_from = "corner",
clockwise = TRUE, draw_boundary = TRUE, boundary_holes = c(1,
3), end_side = 3)
})
Well, a rhombus spiral.
<- function(unit_len, height, width, thickness = 8L,
rect_spiral angle = 90, clockwise = TRUE, start_hole = FALSE) {
if (start_hole) {
<- 1
bholes <- height - thickness
fourl_dist else {
} <- 4
bholes <- height
fourl_dist
}
<- (width < thickness)
last_one if (last_one) {
<- 1:4
blines <- c(3, bholes)
bholes else {
} <- c(1, 2, 4)
blines
}<- -sample.int(n = thickness, size = 4, replace = TRUE)
blocs
parallelogram_maze(unit_len = unit_len, height = thickness,
width = fourl_dist, angle = 180 - angle, start_from = "corner",
clockwise = clockwise, draw_boundary = TRUE,
boundary_lines = blines, boundary_holes = bholes,
boundary_hole_locations = blocs, end_side = 3)
if (clockwise) {
turtle_left(angle)
else {
} turtle_right(angle)
}
if (!last_one) {
rect_spiral(unit_len, height = width, width = height -
thickness = thickness, angle = 180 -
thickness, clockwise = clockwise, start_hole = FALSE)
angle,
}
}
turtle_init(2500, 2500, mode = "clip")
turtle_up()
turtle_hide()
turtle_do({
turtle_setpos(300, 50)
turtle_setangle(270)
rect_spiral(unit_len = 20, 110, 90, thickness = 15,
angle = 80, start_hole = TRUE)
})
The path spirals in, then out, joining at the center. This might be buggy.
<- function(unit_len, height, width,
double_spiral thickness = 8L, angle = 90, clockwise = TRUE, start_hole = TRUE,
color1 = "black", color2 = "black") {
<- height - thickness
len1 <- c(1, 2, 4)
bline1 <- c(1, 3, 4)
bline2 <- c(2)
bhole1 if (start_hole) {
<- len1
len2 <- c(bline2, 2)
bline2 <- c(bhole1, 4)
bhole1 else {
} <- len1 - 2 * thickness
len2
}<- -sample.int(n = thickness, size = 4,
blocs1 replace = TRUE)
<- -sample.int(n = thickness, size = 4,
blocs2 replace = TRUE)
<- (min(len1, len2) <= 0) || (width <=
last_one 2 * thickness)
if (last_one) {
<- c(4)
bhole2 else {
} <- c(3)
bhole2
}if (start_hole) {
<- c(bhole2, 2)
bhole2
}<- ((len2 > 0) && (width > thickness))
second_stripe
if (len1 > 0) {
turtle_col(color1)
parallelogram_maze(unit_len = unit_len, height = len1,
width = thickness, angle = angle, start_from = "corner",
clockwise = clockwise, draw_boundary = TRUE,
boundary_lines = bline1, boundary_holes = bhole1,
boundary_hole_locations = blocs1, end_side = ifelse(len2 >
0, 3, 2))
if (second_stripe) {
<- min(thickness, width - thickness)
wid2 turtle_col(color2)
parallelogram_maze(unit_len = unit_len,
height = len2, width = wid2, angle = 180 -
start_from = "corner", clockwise = !clockwise,
angle, draw_boundary = TRUE, boundary_lines = bline2,
boundary_holes = bhole2, boundary_hole_locations = blocs2,
end_side = 4)
turtle_col(color1)
turtle_forward(unit_len * (thickness +
wid2))if (clockwise) {
turtle_right(180 - angle)
else {
} turtle_left(180 - angle)
}turtle_forward(unit_len * thickness)
if (clockwise) {
turtle_right(angle)
else {
} turtle_left(angle)
}
}
}<- width
next_height <- ifelse(start_hole, height, height -
next_width 2 * thickness)
if (last_one) {
if (second_stripe) {
parallelogram_maze(unit_len = unit_len,
height = next_height, width = thickness,
start_from = "corner", angle = 180 -
clockwise = clockwise)
angle, else {
} parallelogram_maze(unit_len = unit_len,
height = next_height, width = thickness,
start_from = "corner", angle = angle,
clockwise = !clockwise)
}else {
} double_spiral(unit_len, height = next_height,
width = next_width, thickness = thickness,
angle = 180 - angle, clockwise = clockwise,
start_hole = FALSE, color1 = color1, color2 = color2)
}
}
turtle_init(2500, 2500, mode = "clip")
turtle_up()
turtle_hide()
turtle_do({
turtle_setpos(300, 50)
turtle_setangle(0)
double_spiral(unit_len = 20, height = 100, width = 100,
thickness = 10, angle = 80, start_hole = TRUE,
color2 = "gray40")
})
As in ox that plods back and forth in a field.
<- function(unit_len, height, width, thickness = 8L,
boustro angle = 90, clockwise = TRUE, start_hole = TRUE,
balance = 0) {
if (start_hole) {
<- c(1, 3)
bholes <- 1:4
blines else {
} <- c(1, 3)
bholes <- 2:4
blines
}
<- (width < thickness)
last_one <- sample.int(n = thickness, size = 4, replace = TRUE)
blocs
parallelogram_maze(unit_len = unit_len, height = height,
width = thickness, angle = angle, balance = balance,
start_from = "corner", clockwise = clockwise,
draw_boundary = TRUE, boundary_lines = blines,
boundary_holes = bholes, boundary_hole_locations = blocs,
end_side = 3)
if (!last_one) {
boustro(unit_len, height = height, width = width -
thickness = thickness, angle = 180 -
thickness, clockwise = !clockwise, start_hole = FALSE,
angle, balance = balance)
}
}
turtle_init(2500, 2500, mode = "clip")
turtle_up()
turtle_hide()
turtle_do({
turtle_setpos(100, 50)
turtle_setangle(0)
boustro(unit_len = 26, height = 82, width = 80,
thickness = 8, angle = 85, balance = 1.5)
})