mazingHi! 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')## Warning in text.default(1, 1, labels = emoji("elephant"), cex = 30, family =
## "EmojiOne"): font family 'EmojiOne' not found, will use 'wqy-microhei' instead
## Warning in text.default(1, 1, labels = emoji("elephant"), cex = 30, family =
## "EmojiOne"): font family 'EmojiOne' not found, will use 'sans' instead
## Warning in text.default(1, 1, labels = emoji("elephant"), cex = 30, family =
## "EmojiOne"): font family 'EmojiOne' not found, will use 'wqy-microhei' instead
## Warning in text.default(1, 1, labels = emoji("elephant"), cex = 30, family =
## "EmojiOne"): font family 'EmojiOne' not found, will use 'wqy-microhei' instead
## 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.6.0 (2026-04-24)
## Platform: x86_64-pc-linux-gnu
## Running under: Ubuntu 24.04.4 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=en_US.UTF-8
## [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.6.0 png_0.1-9 scales_1.4.0 RColorBrewer_1.1-3
## [5] mazing_1.0.5
##
## loaded via a namespace (and not attached):
## [1] vctrs_0.7.3 cli_3.6.6 knitr_1.51 rlang_1.2.0
## [5] xfun_0.57 showtextdb_3.0 sysfonts_0.8.9 proto_1.0.0
## [9] S7_0.2.2 jsonlite_2.0.0 glue_1.8.1 buildtools_1.0.0
## [13] htmltools_0.5.9 maketools_1.3.2 sys_3.4.3 sass_0.4.10
## [17] rmarkdown_2.31 grid_4.6.0 evaluate_1.0.5 jquerylib_0.1.4
## [21] fastmap_1.2.0 yaml_2.3.12 lifecycle_1.0.5 compiler_4.6.0
## [25] codetools_0.2-20 farver_2.1.2 digest_0.6.39 R6_2.6.1
## [29] showtext_0.9-8 bslib_0.10.0 gtable_0.3.6 tools_4.6.0
## [33] ggplot2_4.0.3 cachem_1.1.0