35. Level 4 - Sequencium Game#

35.1. Introduction#

This goal is to implement of the game Sequencium. The game is extracted from the book “100 Strategic Games for Pen and Paper” by Walter Joris.

Sequencium is a strategic game, it can be played on various grids. The game involves creating sequences of numbers by moving across a grid, and the goal is to maximize your score while preventing your opponent from making high-scoring moves.

Rules:

  • The game is played on a grid, the first player is red, the second is blue. Each player start by placing the value 1 (one in red and one in blue) in two opposite corner cells.

  • The goal of the game is to create the longuest sequence of numbers.

  • On each turn, a player can fill an empty cell with a number \(x\) of it’s color if an adjacent cell (either orthogonally or diagonally) contains a value of it’s color which is \(x-1\).

  • The game ends when neither player can make a legal move (i.e., there are no more adjacent empty cells to place a new number).

  • The player who has placed the highest value wins.

If you want more informations on this game : mathwithbaddrawings web site

By developping this topic you will show us the ability you have to developp a programm using: functions, for loop, while loop, if statement, list, list of list and dictionary.

35.2. The Board#

35.2.1. Creation#

The board will be represented by a dictionary where the keys are the coordinates of the cells and the values are tuples (player, value). The board is initialized with the two corner cells filled with the values 1 and 1 for the two players.


SIZE=6
def create_board():
    # TO COMPLETE

35.2.2. Representing a cell#

We want to represent the board as a grid of characters, like the following example.

terminal colors

We need

  • to use color to represent the cell

  • to format the string representing the cells such that they always are represented using two characters.

We can switch the color of a text in terminal by using a special character. For example, to switch the color to red, we can use the character "\033[0;31;40m", to switch the color to blue, we can use the character "\033[0;34;40m" and for gray "\033[0;37;40m".

For example:

  • "\033[0;31;40mXXX" will display “XXX” in red

  • "\033[0;37;40m" to switch back the default color

terminal colors

Using the format string we can represent number with two characters even if the value is less than 10.

We provide a function converting a cell of the board into a str. You can try it.

def cell_to_str(board, x, y):
    if (x, y) not in board:
        return "\033[0;37m .\033[0;37m"

    if board[x, y][0] == 0:
        return f"\033[0;31m{board[x, y][1]:2d}\033[0;37m"
    else:
        return f"\033[0;34m{board[x, y][1]:2d}\033[0;37m"

board = create_board()
print(cell_to_str(board, 0, 0))
print(cell_to_str(board, 5, 5))
print(cell_to_str(board, 0, 2))
def cell_to_str(board, x, y):
    if (x, y) not in board:
        return "\033[0;37m .\033[0;37m"

    if board[x, y][0] == 0:
        return f"\033[0;31m{board[x, y][1]:2d}\033[0;37m"
    else:
        return f"\033[0;34m{board[x, y][1]:2d}\033[0;37m"

35.3. Moves#

35.3.1. Playable Cells#

Create a function is_cell_playable(board, x, y, p) which checks if a cell is playable. A cell is playable if the cell is empty and if there is an adjacent cell (either orthogonally or diagonally) that contains a value of the player p.

def is_cell_playable(board, x, y, p):
    # TO COMPLETE

board = create_board()
print(is_cell_playable(board, 0, 0, 0)) # False
print(is_cell_playable(board, 0, 1, 0)) # True
print(is_cell_playable(board, 0, 1, 1)) # False

35.3.2. Valid Move#

Create a function is_valid_move(board, x, y, p, v) which checks if a move (placing value v for player p in cell with coordinates (x, y)) is valid. A move is valid if the cell is empty and if there is an adjacent cell (either orthogonally or diagonally) that contains the value v - 1 of the player p.

def is_valid_move(board, x, y, p, v):
    # To COMPLETE

board = create_board()
print(is_valid_move(board, 0, 1, 0, 1)) # False
print(is_valid_move(board, 0, 1, 0, 2)) # True
print(is_valid_move(board, 0, 1, 0, 1)) # False

35.3.3. Has Valid Move#

Implement a function has_valid_move(board, p) that checks if the player p has a valid move. A player has a valid move if there is an empty cell and an adjacent cell that contains a value of the player p.

def has_valid_move(board, p):
    # TO COMPLETE

35.4. Playing#

35.4.1. Getting a Move#

Implement a function get_move(board, p) to get a move from the player p. The player has to enter a valid move, if the move is not valid, the player has to enter a new move. Return the move (x, y, v).

def get_move(board, p):
    # TO COMPLETE

35.4.2. Winner#

Implement a print_winner(board) function. It prints the winner of the game. The winner is the player who has placed the highest value. If the two players have placed the same value, the game is a draw.

def print_winner(board):
    # TO COMPLETE

35.4.3. Play a Move#

Implement a play(board, p) function which plays a move for the player p. The player has to enter a valid move. The move is then played on the board.

def play(board, p):
    # TO COMPLETE

35.4.4. A Full Game#

If everything is ok, the following function should work nicely.

def play_game():
    """
    Play the game. The game ends when neither player can make a legal move. The player who has placed the highest value
    wins.
    """
    board = create_board()
    p = 0
    while has_valid_move(board, p):
        play(board, p)
        p = 1 - p
    print_winner(board)
    print_board(board)


play_game()

35.5. Advanced Features#

You are now free to complete the project with any extension that you may imagine. This is an opportunity to show that you are now confident and can propose and develop new leads independently.

Here, an example of extension: the player one has a real advantage. In fact, if he plays correctly, player two can only make a draw. The most efficient strategy is to mirror all plays of the first player. An adaptation of the rule to reduce the advantage of player one is to make two consecutive moves. The player starts with one move, and then all players make two consecutive moves.