Santorini is a board game for 2–4 players. It is played on a $$5 \times 5$$ grid, on a board whose theme is inspired by the architecture of cliffside villages on Santorini1 island in Greece.

game board
The Santorini game board is inspired by the architecture of cliffside villages on Santorini island in Greece.

Each player has two pieces that represent workers. At the start of the game, the board is empty and each player in turn places the two workers of his chosen color into any unoccupied spaces on the board. Players then take turns, starting with the player who first placed his workers on the board. On his turn, a player selects one of his workers that first makes a move and then builds.

Move

A worker may move into one of the (up to) eight neighboring spaces.

move worker
A worker may move into one of the (up to) eight neighboring spaces.

A worker may move up a maximum of one level higher, move down any number of levels lower, or move along the same level. A worker may not move up more than one level.

move worker
A worker may move up a maximum of one level higher, move down any number of levels lower, or move along the same level. The space a workers moves into must not be occupied by another worker or a dome.

The space a workers moves into must not be occupied by another worker or a dome.

Build

A worker can build part of a tower (a block or a dome) on one of the (up to) eight neighboring spaces around him that is not occupied by another worker or a dome.

build tower
A worker can build part of a tower (a block or a dome) on one of the (up to) eight neighboring spaces around him that is not occupied by another worker or a dome.

A worker can build onto a level of any height. For example, if the worker stands on the ground, he can still build a block on the second or third level, or even a dome. He must always choose the correct shape of block or dome for the level being built (see diagram below). A tower with three blocks and a dome is considered a complete tower.

build tower
A worker can build onto a level of any height. He must always choose the correct shape of block or dome for the level being built. A tower with three blocks and a dome is considered a complete tower.

End of the game

A player who is the first to place one of his workers on the third level of a tower wins the game.

win
A player who is the first to place one of his workers on the third level of a tower wins the game.

Assignment

In order to refer to spaces on the Santorini board, its rows are numbered from top to bottom and its columns from left to right, starting from zero. As such, the position of a space on the board can be represented as a tuple $$(r, c)$$, with $$r \in \mathbb{N}$$ (int) the number of the row and $$c \in \mathbb{N}$$ (int) the number of the column containing the space.

directions
The eight possible directions in which a worker can move to or build on neighboring spaces are indicated by one or two uppercase letters.

The eight possible directions in which a worker can move to or build on neighboring spaces are indicated by one or two uppercase letters (str) as shown in the figure above.

Define a class Santorini that can simulate the game play of Santorini games. When creating a new game (Santorini), a sequence (list or tuple) must be passed that contains the positions where the players have placed their workers at the start of the game (4, 6 or 8 workers for 2, 3 or 4 players). The workers are identified by consecutive uppercase letters of the alphabet, in the order in which they are listed in the sequence: worker A is placed at the first position, worker B at the second position, and so on. For example, this is the starting configuration that corresponds to the sequence $$\left[(3, 0), (4, 1), (1, 1), (2, 2)\right]$$:

board
Starting configuration of a Santorini game after two players have placed their workers on the board.

Each game (Santorini) must have a property workers: a dictionary (dict) that maps the letter (str) of each worker onto the position of that worker on the board.

If a game (Santorini) is passed to the built-in function str, a string representation (str) of the board must be returned. Each row forms a separate line (listed from top to bottom) containing characters that describe the consecutive spaces (listed from left to right). A space not occupied by a worker is represented by a digit that indicates the level of the tower on that space: 0 if no blocks have been built on the space, 1 for a one-block tower, 2 for a two-block tower, 3 for a three-block tower and 4 for a three-block tower with a dome. A space occupied by a worker is represented by the uppercase letter identifying the worker (regardless of the level of the tower the worker is standing on).

In addition, each game (Santorini) must support at least the following methods:

Example

>>> board = Santorini([(3, 0), (4, 1), (1, 1), (2, 2)])
>>> print(board)
00000
0C000
00D00
A0000
0B000
>>> board.workers
{'A': (3, 0), 'B': (4, 1), 'C': (1, 1), 'D': (2, 2)}
>>> board.winning_worker()
>>> board.level('B')
0
>>> print(board.move_worker('B', 'E'))
00000
0C000
00D00
A0000
00B00
>>> print(board.build_tower('B', 'W'))
00000
0C000
00D00
A0000
01B00
>>> board.level('B')
0
>>> board.level('C')
0
>>> print(board.move_worker('C', 'SW').build_tower('C', 'E'))
00000
00000
C1D00
A0000
01B00
>>> board.level('C')
0
>>> board.move_worker('A', 'W')
Traceback (most recent call last):
AssertionError: invalid move