--- title: "A Beginner's Guide to `mazing`" author: "Kelly Street" date: "`r Sys.Date()`" output: html_document vignette: > %\VignetteIndexEntry{inspiration} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include=FALSE} knitr::opts_chunk$set(echo = TRUE, cache = TRUE) library(mazing) oldpar <- par(mar=c(0,0,0,0)) ``` 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. ```{r m1} 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! ```{r mcircle} 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: ![](../inst/mazing.png){#id .class width=250} ## Plotting mazes There are two ways to plot a \code{maze} 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: ```{r mcircWalls} plot(m, walls = TRUE) ``` Or both together: ```{r mcircBoth} 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: ```{r openings} 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): ```{r openings2} 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. ```{r mAdjust} plot(m, lwd = 8) lines(m, lwd = 8, col = 4, adjust = c(.2,.2)) ``` ```{r mAdjust2} 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`! ```{r solve} 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. ```{r solvepoints} 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. ```{r customsolve} 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. ```{r msquared, fig.height=8} 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. ```{r external} 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() ``` 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`. ```{r elephantmaze, fig.height=8} 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 ```{r reset, echo=FALSE} par(oldpar) ``` ```{r info} sessionInfo() ```