Monorail as Seen on The Genius

M

If you are unfamiliar with The Genius, then you can read my summary and pitch below. If you are already well-versed, then you can skip ahead to my discussion of the game Monorail.

Even without ever watching the show if you enjoy strategy games, you will likely love Monorail.

Just want to play the game and don’t care about what I have to say? Go to www.MonorailTheGame.com. Check out the code for the game here.

What is The Genius?

The Genius is one of the most amazing reality TV competition shows that has ever existed.

If you have seen it, you likely agree with this statement. If you haven’t watched The Genius before, you may be asking yourself, “if this thing is so great, why have I never heard of it?

The reason is likely because it is in Korean. Once you come to terms with this and you are willing to sit through an hour and a half of Korean subtitles per episode, an entire world of amazing television will be open to you.

The show is an elimination style reality show, like Survivor. Each week, the contestants (mostly Korean celebrities) compete in a Main Match followed by a Death Match. The Main Match includes all contestants, and generally the two people that perform the best gain a Token of Life (immunity) and the worst performing person becomes the elimination candidate for the Death Match.

The elimination candidate gets to choose from those that are not immune who they want to face in the Death Match. This match is usually some kind of two player game that requires skills like pattern recognition, memory, mathematics and intuition. The player that loses the Death Match is eliminated from the show.

There’s a lot of things that make the show so compelling. Some of the contestants are amazingly brilliant and charismatic, Lee Sang-min is quite possibly the greatest reality TV contestant of all time. The games are interesting, the set design is fantastic, the music is awesome and as an outsider to Korean culture, how the contestants relate based on their sexes and age is very interesting.

If you are still on the fence, check out this podcast about why everyone should watch The Genius.

How Monorail works

One of the great Death Match games introduced in Season 3 of The Genius is a game called Monorail. The rules are quite simple.

Two tiles that form a train station are laid out in front of the players. Players take turns where each can lay down between one and three tiles per turn from a set of 16 total tiles. There are only two different types of tiles, a curve and a straight line. The tiles that are laid down by a player must be in a straight line and must connect to the existing pieces already placed to form the board.

Winning the game

The first player to complete a single loop wins the game. There’s a second win condition as well.

If after one player completes their turn the other player determines that the game cannot be completed with the remaining tiles, they can declare that the game is impossible to complete. Once they do that, the other player has the opportunity to use any and all remaining tiles to complete a loop. If they complete the loop, they win, if they cannot, the player that declared the game impossible wins.

Since I saw the first episode that introduced Monorail, I’ve always thought that it would make a fun two-player computer game. Last Christmas, I even went as far as refresh my memory of the rules screen grab some of The Genius Monorail artwork, and write out a preliminary game design including UI and database schema.

But like many ideas, I didn’t actually execute on my designs and implement the game. That is, until now…

Programming Monorail

It’s been about 10 years since I programmed a game and even longer since I created a two-player game, so it took me a little longer to get the basic mechanics of the game working than I thought it would.

In a side project like this, I usually like to use it as an opportunity to learn a new skill. This time I introduced myself to the HTML Canvas. In grad school, I had created a graphing library using Javascript and SVG, and the principles of the Canvas are very similar.

All games follow a similar programming pattern. You have a game loop that based on the state of the game, the loop updates and renders the corresponding information. In the Monorail that I created, the rendering takes place on the HTML Canvas but the basic drawing mechanics are identical regardless of the technology you’re using whether it is OpenGL, DirectX, or some other graphical library.

I went with a retro design for my graphics, buttons, and the sounds used in the game (and included a little Moby too :-). I took some inspiration from a recent book I read called Ready Player One (highly recommend). Check out the source code here.

Basic construction

I setup each game to have a unique 10 character code associated with it. Player 1 initiates the game and this code gets created, they then can send the URL or code to anyone they want to play against. The first person to arrive at the URL and join the game becomes the second player.

I programmed all the game code as client-side Javascript. I created GameStateCanvasState, and Tile classes (yes, I know technically Javascript does not support classes). The Tile class is a single board tile: station tile, straight line or curve. The CanvasState handles the mouse and keyboard interactions in the game, adds/removes/rotates tiles and maintains a reference to all the placed tiles. The GameState keeps track of game configuration and the rules of the game.

With Monorail, since it is a turn-based two-player game, I have to maintain who’s turn it is and let them make moves in the game while the other player waits for their turn. I also have to communicate the game state changes (win, loss, turn switch, etc.) and the board changes to both players as turns are completed.

After each player’s turn, the current state of the game is sent to a server and saved into a database. For the board, I saved the entire JSON representation of the tiles. The new version of the board and game state is reported to both clients and the game is re-rendered based on the new information.

Once I had all that in place, along with a way for two players that are remote from each other to actually start and join a game, I had to program the drag and drop movement of tiles, detect whether a move is valid and detect the two win conditions.

Drag and drop

Drag and drop is pretty simple. You just have to be able to detect when a mouse click takes place within a tile and as long as the mouse has not fired an up event, move the tile with the mouse pointer. To make sure tiles connect properly, I wrote my own snapToGrid function that places the dropped tile into a valid board grid square. I also make sure that tiles can never overlap.

Testing validity of moves

As mentioned in the Monorail rules section of this post, any tiles placed on the board during a player’s turn have to be in a straight vertical or horizontal line, have to all be connected and have to be touching an existing piece in the pre-existing board.

When you’re playing the physical version of the game, the two players can enforce the rules and make sure any moves that are made are valid. In the digital version I was creating, I wanted to make sure any placed tiles were valid before accepting that a player’s turn was complete.

To accomplish testing that the three pieces are connected and in a straight line, I wrote the following algorithm.

function isValid(placedTiles) {
  // sort by x axis
  tiles.sort(function(a, b) { return a.x - b.x; });

  // compute maximum distance between tiles along x-axis
  for(var i = 1; i < tiles.length; i++) {
    diffX = Math.max(diffX, Math.abs(tiles[0].x - tiles[i].x));
  }

  // sort by y axis 
  tiles.sort(function(a, b) { return a.y - b.y; });

  // compute maximum distance between tiles along y-axis
  for(var i = 1; i < tiles.length; i++) {
    diffY = Math.max(diffY, Math.abs(tiles[0].y - tiles[i].y));
  }

  var maxDistance = (tiles.length - 1) * cellSize;

  // one of these has to be zero, or we don't have a straight line
  // and the difference has to be smaller than maxDistance 
  // or the tiles are not connected
  return (diffX == 0 || diffY == 0) && (diffX <= maxDistance && diffY <= maxDistance); 
}

To test that the placed tiles are connected to the existing board, I just check all existing tiles and see if any of their neighbors are one of the newly placed tiles.

Handling the win conditions

As mentioned, there’s two types of win conditions. The first is that one player completes a full loop of the track, the other is that one player declares the game impossible to complete and then either the other player proves him/her wrong and as a consequence they win, or they can’t complete the board and the person that declared the game impossible wins.

To detect a full loop, all that’s needed is to walk the track starting with the left train station and make sure that all tiles are reachable and return to the left train station. This is done recursively, as a depth-first search, where each recursive call is the consequence of moving right, left, up or down depending on the orientation and type of tile currently being processed.

To support the second win scenario, any player can declare the game impossible at any point. The other player is informed and given the chance to use all the remaining tiles to complete the board. If they can’t, they can concede the game.

Launching the game

Once I had the game actually working, I wanted to make it available to other people to play. To do this, I needed a server to actually host the game, so I setup an AWS EC2 Instance with a basic LAMP Stack. I manage version control with Git and deployment to my EC2 Instance with Jenkins.

Limitations and Further Iterations

I think there’s a lot of things that could be done with the game. Right now player’s are limited to a single game at a time because I store some information about their current game in session, but this could be more flexible. Also, it would be nice to be able to join a game without a player explicitly sending you the join URL.

There’s also more advanced versions of the game that I’ve considered. For example, having a time limit for a move and adding more tiles, could both be interesting.

This would also make a great mobile app game.

Final Remarks

I hope people enjoy getting a chance to play Monorail. It was a lot of fun to work on. If you run into issues playing, have suggestions, or questions, please contact me.

Now go play!

http://www.MonorailTheGame.com

About the author

Sean Falconer

7 Comments

By Sean Falconer

Sean Falconer

Get in touch

I write about programming, developer relations, technology, startup life, occasionally Survivor, and really anything that interests me.