2. Triominos Architecture and Design Considerations - AgileBitFlipper/triominos GitHub Wiki
The design of the game is the first step in setting up the automation and finally pooling the results to start analyzing gameplay. So, on to the design.
As I see it, we can represent the game by describing a Game, Round, Board, Player, Tile, Face, and Choice objects. Additional supporting classes will be used to help automate, record, and analyze the results.
- Game - Constructs, sets up and "plays" the game to conclusion.
- Round - Each Game has a number of Rounds until a Player wins by scoring over 400 points.
- Board - A two-dimension array, of 112 x 112 size, representing locations for Tiles to be played. The board's tile locations alternate between UP and DOWN orientation for each NSEW adjacent position and same orientation for NE, NW, SE, SW positions.
- Player - A single player with a name, tray (for tiles in hand), and score.
- Tile - A triangular game piece with a unique three-digit value, with each digit inscribed in a corner, moving in a clockwise fashion around the tile.
- Face - A single side of a tile, consisting of two corner values. Faces are always described as left, right and middle with a single frame of reference regardless of orientation or rotation.
- Choice - A single playable action, describing the placement of a tile on the board in a specific location, orientation, and rotation. Choices are used to evaluate the "optimal" placement of a tile for whatever goal is set (score, coverage, etc).
Game: Gameplay is automated for the purpose of this study. Gameplay is concluded as described in the rules. A single round is represented at each run. At the moment, no recording of the gameplay is done, but this will be in a future version for analysis.
There are 56 tiles in the game, all produced using the following programmatic method. This method eliminates duplicate tiles, and also follows the original Pressman Toy Corporation design. There have been others produced that change the order of a few of the tiles, but I like to stick with the original. The generation I came up with is as follows:
private void generateTiles() {
int id = 1 ;
int cStart ;
for (int a = 0; a <= 5; a++) {
for (int b = a; b <= 5; b++) {
if (a == 5) {
cStart = 4;
} else if (a == 4 && b == 5) {
continue;
} else {
cStart = b;
}
for (int c = cStart; c <= 5; c++) {
Tile tile = new Tile(a, b, c);
tile.setId(id++);
tiles.add(tile);
}
}
}
}
The above method produces the following valued Tiles. The column and row headers are provided for clarity of how each Tile's corners are generated: The 56-pieces generated should match this table. The first digit of the triplet corresponds to Corner A, the second digit to Corner B, and finally the third digit to Corner C. These values will remain with the original corner, and will rotate with the tile ask it is rotated from origin.
// The 56-pieces generated should match this table
// -----------------------------------------------
// 01 | 0-0-0 | 22 | 1-1-1 | 37 | 2-2-2 | 47 | 3-3-3 | 53 | 4-4-4 | 55 | 5-5-4
// 02 | 0-0-1 | 23 | 1-1-2 | 38 | 2-2-3 | 48 | 3-3-4 | 54 | 4-4-5 | 56 | 5-5-5
// 03 | 0-0-2 | 24 | 1-1-3 | 39 | 2-2-4 | 49 | 3-3-5
// 04 | 0-0-3 | 25 | 1-1-4 | 40 | 2-2-5 | 50 | 3-4-4
// 05 | 0-0-4 | 26 | 1-1-5 | 41 | 2-3-3 | 51 | 3-4-5
// 06 | 0-0-5 | 27 | 1-2-2 | 42 | 2-3-4 | 52 | 3-5-5
// 07 | 0-1-1 | 28 | 1-2-3 | 43 | 2-3-5
// 08 | 0-1-2 | 29 | 1-2-4 | 44 | 2-4-4
// 09 | 0-1-3 | 30 | 1-2-5 | 45 | 2-4-5
// 10 | 0-1-4 | 31 | 1-3-3 | 46 | 2-5-5
// 11 | 0-1-5 | 32 | 1-3-4
// 12 | 0-2-2 | 33 | 1-3-5
// 13 | 0-2-3 | 34 | 1-4-4
// 14 | 0-2-4 | 35 | 1-4-5
// 15 | 0-2-5 | 36 | 1-5-5
// 16 | 0-3-3
// 17 | 0-3-4
// 18 | 0-3-5
// 19 | 0-4-4
// 20 | 0-4-5
// 21 | 0-5-5
Note: Each time the game is played, the tiles should be shuffled as to produce a different result.
Tile: A tile can be described as a triangle with a specific set of three values, each one marked in single corner in a clockwise fashion. Each corner is internally described by A, B, and C that remain with the tiles as it is rotated. Orientation of the tile is described as UP or DOWN as can be seen below. Rotation is described as fixed rotation values of 0, 120, and 240, and accounts for the clockwise rotation of the tile from the original 'A-B-C' position.
For example, '0-1-2' describes a tile that looks like the following in both the UP and DOWN orientations:
/A\ /0\ --------- /2\
/ \ / \ \1 2/ / \
/ \ / \ \ / / \
/C B\ /2 1\ \ / /1 0\
--------- --------- \0/ ---------
model UP DOWN UP - 120 rot

Face: A face is described by the corner values of a side of the Tile. The face's values are always described in clockwise order, and they are always in the frame of reference of the viewer of the board. Left face faces left, right face faces right, and middle face faces up or down depending on the orientation of the Tile. In the example above, the UP oriented tile's left face would be described by '2-0' and the DOWN oriented tile's left face would be '0-1'. Note, that these two tiles are the same tile in two different orientations. The tiles could also be rotated by 120 or 240 degrees, thus changing the left, right and middles faces again.

Board: The board is currently 112x112 as there are 56 tiles. If the gameplay could go in a single direction playing all of the tiles, this board could accommodate the situation. I'm sure after analysis this board could be shrunk considerably as all gameplay rarely goes even 10 tiles from center. Gameplay starts with the first piece being played at (56,56). It doesn't make much sense to display the full board, so display is dynamic with the code "zooming" to the smallest displayable X,Y representation of the board. An example can be seen below. Note: Played piece count, boundaries, and scales are all optional (but very useful) tools.
Board:
Played Piece Count:21
Boundaries:(53,58,53,59)
-------------------------------------------------
53 54 55 56 57 58 59
-------------------------------------------------
| |=+++++++++^+++++++++^+++++++++=+++++++++
| |==+++++++/5\+++++++/1\+++++++===+++++++
| 53 |===+++++/ B \+++++/ A \+++++=====+++++
| |====+++/4 0\+++/0 2\+++=======+++
| |=====+ -- 20-- + -- 8-- +=========+
| |+++++^ -- 5-- ^ -- 12-- ^ -- 41-- ^
| |++++/4\\4 0//0\\0 2//2\\2 3//3\
| 54 |+++/ B \\ B // B \\ B // B \\ A // A \
| |++/4 0\\0//0 2\\2//2 3\\3//3 1\
| |+ -- 19-- v -- 3-- v -- 38-- v -- 31--
| |=+++++++++= -- 15-- ^ -- 43-- =+++++++++
| |==+++++++===\0 2//2\\2 3/===+++++++
| 55 |===+++++=====\ A // B \\ B /=====+++++
| |====+++=======\5//5 5\\5/=======+++
| |=====+=========v -- 46-- v=========+
| |+++++=+++++++++^ -- 56-- ^ -- 26-- ^
| |++++===+++++++/5\\5 5//5\\5 1//1\
| 56 |+++=====+++++/ B \\ A // A \\ A // A \
| |++=======+++/4 5\\5//5 1\\1//1 0\
| |+=========+ -- 55-- v -- 36-- v -- 7--

Player: The players, for now, are all automated. Each player has a name, a tray of tiles, a score, and the will to win! The starting player is chosen following the Pressman rules, and the play continues in round-robin order from that player. As a player plays a tile on the board, the tile should be marked in some way to identify the user that played it.
Choice: Since there can be a multitude of plays per turn, a Choice represents the placement of a tile in a specific place, orientation, and rotation. This choice should include the score if that placement where chosen so that the algorithm can use that information to choose the most-logical (or valuable) move.