01 Aug 2014
In this post I present Mauler, a JavaScript framework for abstract strategy games. So what is an abstract strategy game? Almost all abstract strategy games conform to the strictest definition of: a game board, card, or tile game in which there is no hidden information, no non-deterministic elements, and (usually) two players or teams taking a finite number of alternating turns.
Mauler consists of three main elements:
Here are a few games that can be implemented and played with Mauler:
The game of Tic-Tac-Toe will be used as an example to show how Mauler works. Tic-Tac-Toe was chosen because is one of the simplest, yet most popular abstract strategy board games, and most people are familiar with the rules. Here you can play the game, however, you will be playing against a perfect player (using the Alpha-Beta pruning algorithm), so the best you can expect is a draw:
As I mentioned before, the framework consists of two interfaces that will be described next:
What is a game? From the game theoretical point of view a game is a description of strategic interaction that includes the constraints on the actions that the players can take and the players’ interests, but does not specify the actions that the players do take (Rasmusen, 2006). Based on this definition, we can define an interface for abstract strategy games as follows:
Now here is a more detailed description of each of these methods with examples of their behavior. For simplicity, let's assume that there is a render() function that renders the game.
.copy()Returns a copy of the game.
Examplevar tic = new TicTacToe();
tic.move("5");
tic.move("9");
render(tic);
var ticCopy = tic.copy();
render(ticCopy);
Returns the player whose turn it is.
var tic = new TicTacToe();
render(tic);
tic.currentPlayer(); // "1"
tic.move("5");
render(tic);
tic.currentPlayer(); // "2"
Returns true if the game is over, false otherwise.
var tic = new TicTacToe();
render(tic);
tic.isGameOver(); // false
tic.move("5");
tic.move("4");
tic.move("1");
tic.move("9");
tic.move("3");
tic.move("2");
tic.move("7");
render(tic);
tic.isGameOver(); // true
Makes a move for the player whose turn it is.
Example:var tic = new TicTacToe();
render(tic);
tic.move("5");
render(tic);
Returns an Array of legal moves for the player in turn.
Example:var tic = new TicTacToe();
render(tic);
tic.moves(); // ["1", "2", "3", "4", "5", "6", "7", "8", "9"]
tic.move("5");
tic.move("4");
tic.move("1");
render(tic);
tic.moves(); // ["2", "3", "6", "7", "8", "9"]
tic.move("9");
tic.move("3");
tic.move("2");
tic.move("7");
render(tic);
tic.moves(); // []
Returns a new game.
Example:var tic = new TicTacToe();
tic.move("5");
tic.move("9");
render(tic);
var newGame = tic.newGame();
render(newGame);
render(tic);
Returns a dictionary with the outcomes for each of the players.
var tic = new TicTacToe();
render(tic);
tic.move("5");
tic.move("4");
tic.move("1");
tic.move("9");
tic.move("3");
tic.move("2");
tic.move("7");
render(tic);
tic.isGameOver(); // true
tic.outcomes(); // { "1": "WIN", "2": "LOSS" }
Restarts the game.
var tic = new TicTacToe();
tic.move("5");
tic.move("9");
render(tic);
tic.restart();
render(tic);
function player(game) {
return "Move 1";
}
function randomPlayer(game) {
return Math.floor(Math.random() * game.moves().length);
}
var tic = new TicTacToe();
render(tic);
while (!tic.isGameOver()) {
tic.move(randomPlayer(tic));
}
You can get the source code of Mauler on Github.
Mauler is a very simple, yet concise enough framework to describe games and game-playing algorithms. This framework will be used in following blog posts to describe algorithms such as Minimax, Alpha-Beta pruning and Monte-Carlo Tree Search.