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.
m <- maze(35,100)
plot(m, lwd = 3)
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:
plot(m, walls = TRUE)
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:
plot(m, walls = TRUE, openings = c('left','right'),
openings_direction = c('left','right'))
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')
We can also add an offset to shift the entire maze by a fixed vector. This can be used to create a 3D effect or just a funky layering effect.
plot(m, lwd = 8)
lines(m, lwd = 8, col = 4, adjust = c(.2,.2))
plot(m, lwd=10, col = 'pink')
lines(m, lwd=8, col = 'black', adjust = c(.2,.2))
lines(m, lwd=6, col='turquoise', adjust = c(.4,.4))
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
!
p <- solve_maze(m, start = 'left', end = 'right')
plot(m, walls = TRUE)
lines(p, lwd = 3, col = 2)
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()
## quartz_off_screen
## 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)
sessionInfo()
## R version 4.1.1 (2021-08-10)
## Platform: x86_64-apple-darwin17.0 (64-bit)
## Running under: macOS Big Sur 10.16
##
## Matrix products: default
## BLAS: /Library/Frameworks/R.framework/Versions/4.1/Resources/lib/libRblas.0.dylib
## LAPACK: /Library/Frameworks/R.framework/Versions/4.1/Resources/lib/libRlapack.dylib
##
## locale:
## [1] C/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
##
## attached base packages:
## [1] stats graphics grDevices utils datasets methods base
##
## other attached packages:
## [1] emojifont_0.5.5 png_0.1-7 scales_1.1.1 RColorBrewer_1.1-2
## [5] mazing_1.0.5
##
## loaded via a namespace (and not attached):
## [1] highr_0.9 bslib_0.3.0 compiler_4.1.1 pillar_1.6.3
## [5] jquerylib_0.1.4 sysfonts_0.8.5 tools_4.1.1 digest_0.6.28
## [9] jsonlite_1.7.2 evaluate_0.14 lifecycle_1.0.1 tibble_3.1.5
## [13] gtable_0.3.0 pkgconfig_2.0.3 rlang_0.4.11 DBI_1.1.1
## [17] yaml_2.2.1 xfun_0.26 proto_1.0.0 fastmap_1.1.0
## [21] showtextdb_3.0 dplyr_1.0.7 stringr_1.4.0 knitr_1.36
## [25] generics_0.1.0 sass_0.4.0 vctrs_0.3.8 tidyselect_1.1.1
## [29] grid_4.1.1 glue_1.4.2 R6_2.5.1 fansi_0.5.0
## [33] rmarkdown_2.11 purrr_0.3.4 ggplot2_3.3.5 magrittr_2.0.1
## [37] codetools_0.2-18 htmltools_0.5.2 ellipsis_0.3.2 showtext_0.9-4
## [41] assertthat_0.2.1 colorspace_2.0-2 utf8_1.2.2 stringi_1.7.4
## [45] munsell_0.5.0 crayon_1.4.1