Mancala

Game logic

Game Logic code
def init_game(game_settings):
    state = {
        'player_turn_idx': 0,
        'board': [0, 4, 4, 4, 4, 4, 4, 0, 4, 4, 4, 4, 4, 4]
    }
    return state

"""
The last piece in Mancala has special rules. [__handle_last_piece] determines whether the piece lands in 
a Mancala or an empty pocket on the player's own side. If landing on own Mancala, the player gains a second turn. 
(state['player_turn_idx'] stays the same). If the piece lands on an empty pocket, and there are pieces in the 
corresponding pocket on the opponent's side, the player gains both the last piece and those on the opponents side. 
"""
def __handle_last_piece(state, index):
    player_idx = state['player_turn_idx']
    if player_idx == 0:
        #Gain a turn if last piece lands on that user's own Mancala
        if index == 7:
            state['player_turn_idx'] = 0
            return

        #Take over pieces from other side if landing on empty space on user's own side
        elif (1 <= index < 7) and state['board'][index] == 1 and state['board'][14 - index] != 0:
            state['board'][7] += (state['board'][14 - index] + 1)
            state['board'][14 - index] = 0
            state['board'][index] = 0

        state['player_turn_idx'] = 1

    else:
        if index == 0:
            state['player_turn_idx'] = 1
            return

        elif (8 <= index < 14) and state['board'][index] == 1 and state['board'][14 - index] != 0:
            state['board'][0] += (state['board'][14 - index] + 1)
            state['board'][14 - index] = 0
            state['board'][index] = 0

        state['player_turn_idx'] = 0
        
"""
Function that moves the pieces on the board. Given the amount of pieces at the given index, this function will 
loop around the board until the pieces run out. One piece goes into each pocket (except for the opponent's Mancala.)
"""
def __move_pieces(state, index):
    pieces_left = state['board'][index]
    state['board'][index] = 0          #Empty out chosen pocket
    player_idx = state['player_turn_idx']
    while pieces_left != 0:
        index = (index + 1) % 14
        #player 1 does not put pieces in pocket 0
        #player 2 does not put pieces in pocket 7
        if (player_idx == 0 and index == 0) or (player_idx == 1 and index == 7):
            continue
            
        state['board'][index] += 1         
        pieces_left -= 1

    __handle_last_piece(state, index)

"""
Determines if the pocket the user chose is valid. Movies pieces around board and checks whether the current
user will have an extra turn.

Returns a new state. 
"""
def choose_pocket(state, index):
    if index < 0 or index > 13:
        raise InvalidActionError("Index out of bound")

    #Invalid action if user picks either Mancala.
    if index == 0 or index == 7:
        raise InvalidActionError("You cannot choose to move pieces out of a Mancala.")

    #Invalid action if user tries to move pieces from the opponent's side
    player_idx = state['player_turn_idx']
    if (player_idx == 0 and index > 6) or (player_idx == 1 and index < 8):
        raise InvalidActionError("You cannot choose a pocket from your opponent's side.")
    
    #Invalid action if user picks pocket without pieces in it.
    if state['board'][index] == 0:
        raise InvalidActionError("There are no pieces in this pocket.")

    __move_pieces(state, index)

    return state

"""
Checks whether one of the sides is empty. If so, calculates the totals for both sides and returns
a game result. If neither side is empty, returns an ongoing result. 
"""
def get_game_result(state):
    #Detect if one of the sides is empty, otherwise, the game is ongoing
    if (__side_empty(state, 2) or __side_empty(state, 1)):
        player1_score = sum(state['board'][1:8])
        player2_score = sum(state['board'][8:14]) + state['board'][0]
        if player2_score > player1_score:
            return {
                "game_result": "Winner",
                "winner_idx": 1
            }
        elif player1_score > player2_score:
            return {
                "game_result": "Winner",
                "winner_idx": 0
            }
        else: 
            return {
                "game_result": "Draw"
            }
    else:
        return {
            "game_result": "NoWinnerYet"
        }

""" 
Checks if one of the sides of the mancala board is empty. 

Returns [True] if the side is empty, [False] otherwise. 
"""
def __side_empty(state, side):
    if side == 1:
        for i in range(1, 7):
            if state['board'][i] != 0:
                return False
        return True
    else:
        for i in range(8, 14):
            if state['board'][i] != 0:
                return False 
        return True

Game state schema

message State {
  // Required field to indicate the player who should be making the next move
  // Values = 0 or 1
  int32 player_turn_idx = 1;

  /*
    Array of size 14, indicating the 12 pockets and 2 Mancala. The indices go 
    counter-counterclockwise where indices 1-7 is player_idx 0 and the remaining 
    are player_idx 1. Index 7 is player_idx 0's Mancala. Index 0 is player_idx 1's
    Mancala. The values of the board indicate how many pieces are in them.
    *************************
    * 0 13 12 11 10 9  8    *
    *   1  2  3  4  5  6  7 *
    *************************
  */
  repeated int32 board = 4;
}

Action schema

choose_pocket(int index)

Start building now

Last updated