Last week at the New York R Conference, I gave a presentation on using R in Minecraft. (I've embedded the slides below.) The demo gods were not kind to me, and while I was able to show building a randomly-generated maze in the Minecraft world, my attempt to have the player solve it automatically was stymied by some server issues. In this blog post, I'll show you how you can write an R function to build a maze, and use the left-hand rule to solve it automatically.
If you want to play along, you'll need to launch a Spigot server with the RaspberryJuice plugin. An easy way to do this is to use a Dockerfile to launch the Minecraft server. I used a Ubuntu instance of the Data Science Virtual Machine to do this, mainly because it comes with Docker already installed. Once you have your server running, you can join the multiplayer with from the Minecraft Java Edition using its IP address.
The R script mazebot.R steps through the process of connecting to the server from R, and building and solving a maze. It uses the miner package (which you will need to install from Github), which provides functions to interface between R and Minecraft. After connecting to the server, the first step is to get the ID code used to identify the player in Minecraft. (It's best to have just one player in the Minecraft world for this step, so you're guaranteed to get the active player's ID.)
id <- getPlayerIds()
You'll use that
id code to identify the player later on. Next, we use the
make_maze function (in the script genmaze.R) to design a random maze. This uses a simple recursive backtracking algorithm algorithm: explore in random directions until you can go no further, and then retreat until a new route is available to explore. Once we've generated the maze, we use
print_maze to convert it to a matrix of characters, and place a marker
"!" for the exit.
## Maze dimensions (we'll create a square maze) mazeSize <- 8 ## using the functions in genmaze.R: m <- print_maze(make_maze(mazeSize,mazeSize), print=FALSE) nmaze <- ncol(m) # dimensions m[nmaze,nmaze-1] <- "!" ## end of the maze.
Now for the fun bit: building the maze in the world. This is a simple matter of looping over the character matrix representing the maze, and building a stack of three blocks (enough so you can't see over the top while playing) where the walls should go. The function
build_maze (in solvemaze.R) does this, so all we need to do is provide a location for the maze. Find a clear spot of land, and the code below builds the maze nearby:
## get the current player position v <- getPlayerPos(id, TRUE) altitude <- -1 ## height offset of maze pos <- v+c(3, altitude, 3) # corner ## Build a maze near the player buildMaze(m, pos, id)
You can try solving the maze yourself, just by moving the player in Minecraft. It's surprisingly how difficult even small mazes can be, if you don't cheat by looking at the layout of the maze from above! A simple way to solve this and many other mazes is by using the left hand rule: follow the wall on your left until you find the exit. This is something we can also code in R to solve the maze automatically, to check the positions of walls around the player, and move the player according to the left hand rule. Unfortunately, you can't actually make the player avatar turn using Spigot, so we track the direction the player should be facing with the
botheading variable in the solveMaze function, which we use like this:
## Move the player into the start of the maze, and then solveMaze(id)
And here's what it looks like from a third-person view (use F5 in the game to change the view):
You can find all of the R code to implement the maze-building and maze-solving at the Github repository below. For more on using R in Minecraft, check out the online book R Programming in Minecraft, which has lots of other ideas for building and playing in Minecraft with R.
Github (revodavid): minecraft-maze