# 10 Generate a maze in Minecraft

This example illustrates how to generate a perfect maze from R and the render in Minecraft.

## 10.1 Generate a random maze

First, we need to generate a maze, for which we will use the `Rmaze` R package’s depth-first search algorithm. As the package is not on CRAN, you have to install from GitHub:

``devtools::install_github('Vessy/Rmaze')``

Then load the package and generate a maze with, for example, 10 x 10 tiles:

``````library(Rmaze)

n <- 10
maze <- makeGraph(n, n)
set.seed(42)
maze <- makeMaze_dfs(maze)``````

This is a graph representation of the maze, which can be rendered with `ggplot2` very easily:

``plotMaze(maze, n, n)``

## 10.2 Transform maze graph into matrix

Now we have to transform this graph representation into a binary matrix, where we see in 2D which blocks need to be air or wall. Let’s start with a large empty `matrix` allowing 4 block for every single cell, as in the matrix we will use blocks for the wall as well (unlike in the above plot):

``df <- matrix(NA, nrow = n*4, ncol = n*4)``

Then let’s mark the surrounding border with ones:

``````df[c(1, nrow(df)), ] <- 1
df[, c(1, nrow(df))] <- 1``````

Here is the top corner of the matrix now:

``df[1:4, 1:4]``
``````##      [,1] [,2] [,3] [,4]
## [1,]    1    1    1    1
## [2,]    1   NA   NA   NA
## [3,]    1   NA   NA   NA
## [4,]    1   NA   NA   NA``````

But we should leave the entrance and exit open in the bottom left and top right corner:

``````df[1, ncol(df) - 1:2] <- NA
df[nrow(df), 2:3] <- NA``````

Here is the top right corner showing the maze exit we just made:

``df[1:4, ncol(df) - 3:0]``
``````##      [,1] [,2] [,3] [,4]
## [1,]    1   NA   NA    1
## [2,]   NA   NA   NA    1
## [3,]   NA   NA   NA    1
## [4,]   NA   NA   NA    1``````

Now we need to convert the graph object into a `data.frame` on which we can iterate later to render the actual wall blocks:

``````library(igraph)
mazedf <- as_data_frame(maze)
library(data.table)
setDT(mazedf)``````

Then let’s extract the `x` and `y` positions from the `A_x_y` names:

``````for (v in c('from', 'to')) {
mazedf[, (paste0(v, 'x')) := as.numeric(sub('A_([0-9]*)_[0-9]*', '\\1', get(v)))]
mazedf[, (paste0(v, 'y')) := as.numeric(sub('A_[0-9]*_([0-9]*)', '\\1', get(v)))]
}``````

And let’s also record in which direction the edge points:

``````mazedf[fromx < tox, direction := 'top']
mazedf[fromy < toy, direction := 'right']``````

Now let’s map the `x` and `y` coordinates to the 2D matrix:

``````mazedf[, x := nrow(df) - fromx * 4 + 3 - as.numeric(direction == 'top') * 2]
mazedf[, y := fromy * 4 - 1 + as.numeric(direction == 'right') * 2]``````

And then let’s update the blank matrix `NA` cells with 1, 2 or 3 to represent the actual walls:

``````for (i in seq_len(nrow(mazedf))) {
cell <- mazedf[i]
if (cell\$wall == 'ON') {
df[cell\$x + -1:0, cell\$y + -1:0] <- 1
}
if (cell\$direction == 'top' & cell\$wall == 'ON') {
df[cell\$x - 0:1, cell\$y - 1:2] <- 2
}
if (cell\$direction == 'right' & cell\$wall == 'ON') {
df[cell\$x - 2:3, cell\$y - 0:1] <- 3
}
}``````

I know it was a bit tricky, and probably there’s a nicer and lot more elegant way to do all this :) But at least this works and results in something like:

## 10.3 Render the maze in Minecraft

Now that we have a binary matrix representation of the maze, it’s very easy to render the related blocks in Minecraft. First, we need to load the `miner` package and establish a connection to a Minecraft server:

``````library(miner)
mc_connect()``````

Next, we will clean up some space, then generate the floor (diamond) and ceiling (glass), then the wall blocks(gold):

``````## create objects with number of columns and rows in the dataframe
nr <- nrow(df)
nc <- ncol(df)

## clean up some space
setBlocks(1, 50, 1, nr, 54, nc, 0)
setBlocks(1, 50, 1, nr, 50, nc, 57)
setBlocks(nr - 4, 51, 2, nr, 52, 4, 50)
## maze ceiling
setBlocks(1, 54, 1, nr, 54, nc, 95)
## 3 blocks tall maze walls
for (i in 1:nrow(df)) {
for (j in 1:ncol(df)) {
if (!is.na(df[i, j])) {
setBlock(i, 51, j, 41)
setBlock(i, 52, j, 41)
setBlock(i, 53, j, 41)
}
}
}``````

The result looks like this:

For a more complete solution, see the `mc_maze` and `mc_mazer` functions. The prior generates a maze with given dimensions right in front of a specified player id, while the latter does the same but triggered from the chat window by any player.