mazing
Hi! Thanks for checking out the
mazing
package! In this document, I’ll provide examples of
some of the things you can do with the package and hopefully inspire you
to make some cool mazes of your own.
The most basic functionality of mazing
is producing a
rectangular maze, which we do with the maze
function.
We can also produce mazes from existing binary matrices. This allows us to create mazes in a wider variety of shapes!
mat <- matrix(1, 20, 20)
for(i in 1:nrow(mat)){
for(j in 1:ncol(mat)){
if((i-10.5)^2+(j-10.5)^2 > 100){
mat[i,j] <- 0
}
}
}
m <- as.maze(mat)
plot(m, lwd = 4)
This is also how I produced the hexagonal maze for the sticker:
There are two ways to plot a object: by showing either the paths or the walls of the maze. Above, we plotted the paths, so here’s what it would look like if we plotted the walls:
Or both together:
plot(m, walls = TRUE)
lines(m, lwd = 3, col = 2)
legend('topright', lwd = c(1,3), col = c(1,2), legend = c('walls','paths'), bty = 'n')
Sometimes, we may want to leave an opening in a wall to indicate the
entrance and exit to a maze. When plotting the walls of the maze, we can
specify a section of wall to omit by using the openings
and
openings_direction
arguments. The first gives a location in
the maze and the latter indicates which wall we want to omit, relative
to that location. For example:
With a little creativity, we can also use this to create a larger open area in the middle of the maze (you know, for the minotaur):
lair <- matrix(c(10,10,11,11, 10,11,10,11), ncol = 2)
plot(m, walls = TRUE, openings = lair, openings_direction = 'all')
points(10.5,10.5, pch = 6, col = 'brown')
points(10.5,10.5, pch = 20, col = 'brown')
While it can be fun to get lost in a maze, sometimes we just want the
computer to solve it for us. This looks like a job for
solve_maze
!
Keywords like 'left'
, 'top'
, and
'bottomright'
can be used to identify reference points
within a maze. If we want to add these points to a plot, we can use the
find_maze_refpoint
function.
plot(m, walls = TRUE)
lines(p, lwd = 3, col = 2)
# add start and end points
endpoints <- find_maze_refpoint(c('left','right'), m)
points(endpoints, pch = 16, col = c(3,2))
But we can also reference specific locations in the maze by coordinates, if it doesn’t align with a reference point.
start <- c(10, 3)
end <- c(15, 16)
p <- solve_maze(m, start = start, end = end)
plot(m, walls = TRUE)
lines(p, lwd = 3, col = 2)
# add start and end points
points(rbind(start,end), pch = 16, col = c(3,2))
One thing I found myself wanting to do was to make a
maze-within-a-maze. I was finally able to achieve this with the
expand_matrix
and widen_paths
functions.
m <- maze(10, 10)
m <- maze2binary(m)
m <- expand_matrix(expand_matrix(expand_matrix(m)))
m <- widen_paths(widen_paths(widen_paths(m)))
m <- as.maze(m)
plot(m, lwd=2)
Another thing I wanted to do was to make a maze from an arbitrary
image. The external function png::readPNG
makes this
surprisingly easy!
First, we have to create an example image, so we’ll use the
emojifont
package to make a little elephant.
require(emojifont)
file <- tempfile(pattern = 'elephant', fileext = 'png')
png(file, width = 500, height = 500)
par(mar=c(0,0,0,0))
plot(1, 1, cex=0, axes = FALSE, xlab = '', ylab = '')
text(1, 1, labels = emoji('elephant'), cex=30, family='EmojiOne')
dev.off()
## png
## 2
Then we’ll read in the PNG image, which consists of four channels
(RGB and alpha), and use it to create our maze. The image is a bit
large, so we also condense it using condense_matrix
.
require(png)
mat <- readPNG(file)
mat <- round(mat[,,1]) # red channel
mat <- condense_matrix(condense_matrix(mat))
mat <- round(mat)
# reverse the order of the rows to flip vertically
m <- as.maze(mat[nrow(mat):1,])
par(mar=c(0,0,0,0))
plot(c(1,ncol(m)), c(1,nrow(m)), cex = 0, asp = 1)
rect(par("usr")[1], par("usr")[3], par("usr")[2], par("usr")[4], col = "black")
lines(m, lwd = 3, col = 'white', lend = 2)
## R version 4.4.2 (2024-10-31)
## Platform: x86_64-pc-linux-gnu
## Running under: Ubuntu 24.04.1 LTS
##
## Matrix products: default
## BLAS: /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3
## LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.26.so; LAPACK version 3.12.0
##
## locale:
## [1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C
## [3] LC_TIME=en_US.UTF-8 LC_COLLATE=C
## [5] LC_MONETARY=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8
## [7] LC_PAPER=en_US.UTF-8 LC_NAME=C
## [9] LC_ADDRESS=C LC_TELEPHONE=C
## [11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C
##
## time zone: Etc/UTC
## tzcode source: system (glibc)
##
## attached base packages:
## [1] stats graphics grDevices utils datasets methods base
##
## other attached packages:
## [1] emojifont_0.5.5 png_0.1-8 scales_1.3.0 RColorBrewer_1.1-3
## [5] mazing_1.0.5
##
## loaded via a namespace (and not attached):
## [1] gtable_0.3.6 jsonlite_1.8.9 compiler_4.4.2 showtext_0.9-7
## [5] jquerylib_0.1.4 yaml_2.3.10 fastmap_1.2.0 ggplot2_3.5.1
## [9] R6_2.5.1 showtextdb_3.0 knitr_1.49 tibble_3.2.1
## [13] maketools_1.3.1 proto_1.0.0 munsell_0.5.1 bslib_0.8.0
## [17] pillar_1.10.1 rlang_1.1.5 cachem_1.1.0 xfun_0.50
## [21] sass_0.4.9 sys_3.4.3 cli_3.6.3 magrittr_2.0.3
## [25] digest_0.6.37 grid_4.4.2 lifecycle_1.0.4 sysfonts_0.8.9
## [29] vctrs_0.6.5 evaluate_1.0.3 glue_1.8.0 codetools_0.2-20
## [33] buildtools_1.0.0 colorspace_2.1-1 rmarkdown_2.29 tools_4.4.2
## [37] pkgconfig_2.0.3 htmltools_0.5.8.1