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.

Creating mazes

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:

Plotting mazes

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')

Openings

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')

Adjustments

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))

Solving mazes

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))

Maze-within-a-maze

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)

Session Info

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