If you’re a Star Trek fan, you likely know that Captain Kirk and Mr. Spock frequently play a variant of chess called Tri-Dimensional Chess, or 3D chess, a game that’s similar to standard chess but with notable differences. In this article, we’ll build a data model for a 3D chess application that allows players to compete against each other. Beam us up, Scotty!
The Concept of 3D Chess
While chess itself is already a complex game, combining boards and multiple sets of pieces can significantly increase the game’s complexity.
In 3D chess, boards are stacked in parallel layers, and special movement rules apply to certain pieces, depending on where they’re located. For instance, pawns on the middle board can mimic the behavior of a queen. Pieces can also move from one board to another, with certain restrictions applied, and the boards themselves can even move around and rotate. No wonder Kirk and Spock enjoyed 3D chess so much—it requires quite a lot of tactical finesse!
Tri-Dimensional chess also deviates from standard chess in terms of the properties of its boards. In 3D chess, there are seven distinct boards with different properties. Three of these boards are 4x4, while the remaining four boards are 2x2. You can move these smaller boards around.
Our data model will hopefully cover everything we need to play a game of 3D chess in a web app. We’ll work under the assumption that everything can move around and that boards can impose different movement restrictions on the same pieces. This should be sufficient to cover all possible 3D chess variants. Let’s jump right into the data model!
The Data Model
Our data model consists of three sections:
- Players and Games
- Game Setup
We’ll now discuss each of these areas in greater detail.
Section 1: Players and Games
Everything in our model is either directly or indirectly related to games. Of course, a game can’t proceed without players!
The list of all players is stored in the
player table. In our model, players are all the registered users of our application. For each player, we’ll store the following information:
last_name– the first and last names of the player, respectively.
user_name– the username the player selected, which must be unique.
password– a hash value of the player’s password.
nickname– the player’s screen name, which, like their username, must be unique.
confirmation_code– the code that was sent to the player’s email address in order to complete their registration process.
confirmation_date– the timestamp of when the player confirmed their email address. This attribute will store NULL until the player confirms their email.
current_rating– the current rating of the player, calculated based on their performance against other players. Players will start with some initial value, and their ratings will increase or decrease according to the ranks of their opponents and their game outcomes.
result table is a dictionary that stores the values of all possible unique game outcomes, namely “in_progress”, “draw”, “win”, and “lose”.
Perhaps the most important table in the entire data model is
game, which stores information about each game of 3D chess. In this model, we’ll assume that two human players will compete against each other and that they may choose to save their current game state and resume at a later time (such as if they’d like to make one move per day, in which case the players will log in to the app, see their opponent’s most recent move, think of their own move, execute their move, and then log out). We’ll store the following values in this table:
player_id_2– references to the
playertable denoting both participants of a game. As mentioned, we’re assuming a game will strictly occur between two human players.
number_of_moves– denotes the number of moves that have been executed so far in the current game. When the game starts, this number is set to 0 and increases by 1 each time a player makes a move.
player_id_next– a reference to the player who must make the next move in the current game.
result_id_2– references to the
resulttable that store the outcome of the game for each player.
player_2_points_won– denote the number of points the players were awarded, in accordance with the result of the game.
We’ll discuss how players can keep track of all moves in the Matches section near the end of this article. For now, we’ll move on to the Game Setup.
Section 2: Game Setup
The Game Setup section contains a description of all boards and pieces in 3D chess, as well as a list of all legal moves players can make.
As we mentioned earlier, 3D chess often involves more than one board. These boards can adhere to the standard 8x8 dimensions with fixed positions, but that need not be the case. The list of all boards is stored in the
board table. For each board, we’ll store a unique
starting_position of the board in relation to our chosen 3D coordinates, and all additional
Next, we’ll define all possible types of pieces that could appear on our chess boards. To do so, we’ll use the
piece_type dictionary. In addition to its primary key, this dictionary contains only one unique value, type_name. For a standard chess set, we expect to see the values “pawn”, “rook”, “knight”, “bishop”, “king”, and “queen” in this dictionary.
The list of all individual pieces that are used in a game of 3D chess is stored in the
piece table. For each piece, we’ll store the following information:
piece_name– a unique name describing the piece type and its starting position.
starting_position– a value denoting the precise board and square on which the piece is initially positioned.
board_id– a reference to the board on which the piece is originally positioned.
piece_type_id– a reference denoting the piece’s type.
Finally, we’ll use the
move_type table to store the list of all possible moves the pieces can make on our boards (as well as any moves the boards themselves can make). Recall from the introduction that certain boards apply special movement rules to their pieces. For each move, we’ll define the following:
type_name– a name we’ll use to denote the move that was made, which won’t be a unique value (e.g., we can have “pawn advanced 1 square forward” as many times as needed).
piece_type_id– a reference to the type of piece that was moved. If this value happens to be NULL, then the movement concerns an entire board and not a particular piece.
board_id– denotes the board on which this move will take place (if a chess piece is moving). If the board itself is moving, this value will naturally represent the board that is being moved. Together with two previous attributes, this forms the unique key for this table.
is_board_move– denote whether a move concerns a chess piece or a board. Only one of these flags may be set to true for a particular move.
Since there are too many piece moves and rotations to consider, we won’t store all such possibilities in our database. Instead, we’ll just store the move names and implement the actual logic in the application itself. For example, we’ll define that pawns can either advance forward a single square, advance two squares from their starting position, claim pieces diagonally, move from one board to another, and move as a queen on the central board. So, we’ll have five possible move types defined for pawns, depending on the board they are placed on and their current position.
Section 3: Matches
We’re nearly finished! The last section of our model is named Matches and contains three new tables that we’ll use to keep track of the movement history in a game of 3D chess. The remaining tables are just copies of other tables from our data model, which helps avoid overlapping relations. We’ll also store the current positions of all boards and their pieces in this area. Let’s dive right in.
move table is actually the most complex table in this section. It contains the list of all moves executed during a game. This table will display the list of all moves to players, which can later be used to review or analyze the match. For each move, we’ll store the following:
game_id– a reference to the
gamein which the move was made.
player_id– a reference to the
playerwho made the move.
move_in_the_game– the ordinal number of the move. This number, combined with a piece’s starting position and all other moves, can be used to recreate the whole game. The idea is to allow players to simulate the game once it’s completed so they can analyze the results of the match.
piece_id– a reference to the
piecethat was moved. This makes it easy to track a piece’s movement from beginning to end (mainly for analysis purposes).
piece_type_id– a reference to the type of piece that was moved. While a piece’s reference will always remain constant, its type may change throughout the game (such as if a pawn is promoted). If we’re moving the board, this attribute will contain a value of NULL.
board_id– a reference to the
boardon which the move took place.
move_notation– an agreed-upon notation that we’ll use to represent moves.
The remaining two tables allow us to store a snapshot of the current game state in the database, which is helpful if the players wish to resume the game at a later time.
current_board_position is used to store the position of all boards in our 3D coordinate system. This is necessary for 3D chess games in which at least one board can change its position. For each record in this table, we’ll store a reference to the related game and board, as well the notation of a board’s position. Two specific attribute pairs,
position_notation, form the unique keys for this table.
Our last table is
current_piece_position, which stores references to the related game, a particular piece, the piece’s type, and a position notation for the piece. We’ll again have two pairs of attributes that serve as the unique keys for this table: the
piece_id pair and the
That’s about it for this data model—we’re proud to announce that Captain Kirk and Mr. Spock can now play 3D chess on a computer!
Do you have any suggestions for improving our data model? Feel free to leave your comments down below. Live long and prosper ??