Chinese Checker

Game logic

Game Logic code
def init_game(game_settings):
    state = {
        "player_turn_idx": 0,
        "board": [[-1]*9 for i in range(9)],
        "players": [[None]*10, [None]*10],
        "last_jumped": None,
        "turn": 0
    }
    count = 0
    for i in range(4):
        for j in range(i+1):
            _set_piece(state, 0, count, 3 - i, j)
            _set_piece(state, 1, count, 5 + i, 8 - j)
            count += 1
    return state

def move(state, piece_idx, x, y):
    if not _within_bound(x, y):
        raise InvalidActionError("Coordinte out of bound. Should be between 0 and 8.")
    if piece_idx < 0 or piece_idx >= 10:
        raise InvalidActionError("piece_idx out of bound. Should be between 0 and 9.")
    board = state['board']
    if board[x][y] != -1:
        raise InvalidActionError("There is already a piece at this target coordinate.")
    player_turn_idx = state['player_turn_idx']
    start = state['players'][player_turn_idx][piece_idx]
    start_x = start['x']
    start_y = start['y']

    if _is_adjacent(start_x, start_y, x, y):
        if state['last_jumped'] is not None:
            raise InvalidActionError("This piece must be used to jump over another piece.")
        board[start_x][start_y] = -1
        _set_piece(state, player_turn_idx, piece_idx, x, y)
        state['player_turn_idx'] = (player_turn_idx + 1)%2
        state['turn'] += 1
        return state
    skipped = _is_skip_adjacent(start_x, start_y, x, y)
    if skipped and board[skipped[0]][skipped[1]] != -1:
        if state['last_jumped'] is not None:
            last_jumped = state['last_jumped']
            if last_jumped['piece_idx'] != piece_idx:
                raise InvalidActionError(f"Must use piece {piece_idx} to jump or make a done_move.")
            if last_jumped['last_x'] == x and last_jumped['last_y'] == y:
                raise InvalidActionError(f"Cannot jump back to a previous location.")
        state['board'][start_x][start_y] = -1
        _set_piece(state, player_turn_idx, piece_idx, x, y)
        state['last_jumped'] = {
            'piece_idx': piece_idx,
            'last_x': start_x,
            'last_y': start_y
        }
        return state
    raise InvalidActionError("Cannot move this piece to the target position.")

def done_move(state):
    if state['last_jumped'] is None:
        raise InvalidActionError(f"Cannot make a done_move when you haven't jumped previously.")
    state['player_turn_idx'] = (state['player_turn_idx'] + 1)%2
    state['last_jumped'] = None
    state['turn'] += 1
    return state

def get_game_result(state):
    board = state['board']
    count_player_1 = 0
    count_player_2 = 0
    for i in range(4):
        for j in range(i+1):
            if board[3-i][j] == 1:
                count_player_2 += 1
            if board[5+i][8-j] == 0:
                count_player_1 += 1
    if count_player_1 == 10:
        return {
            "game_result": "Winner",
            "winner_idx": 0
        }
    elif count_player_2 == 10:
        return {
            "game_result": "Winner",
            "winner_idx": 1
        }
    if state['turn'] >= 300:
        if count_player_1 == 0 and count_player_2 == 0:
            return {
                "game_result": "Draw",
            }
        return {
            "game_result": "Winner",
            "winner_idx": 0 if count_player_1 > count_player_2 else 1
        }
    return {
        "game_result": "NoWinnerYet",
    }


def _within_bound(x, y):
    if x < 0 or y < 0 or x >= 9 or y >= 9:
        return False
    return True

def _set_piece(state, player_idx, piece_idx, x, y):
    state["board"][x][y] = player_idx
    state["players"][player_idx][piece_idx] = {
        "x": x,
        "y": y
    }

def _is_adjacent(start_x, start_y, target_x, target_y):
    directions = [(0, 1), (0, -1), (1, 0), (-1, 0), (1, -1), (-1, 1)]
    for dir_x, dir_y in directions:
        if target_x - start_x == dir_x and target_y - start_y == dir_y:
            return True
    return False

def _is_skip_adjacent(start_x, start_y, target_x, target_y):
    directions = [(0, 1), (0, -1), (1, 0), (-1, 0), (1, -1), (-1, 1)]
    for dir_x, dir_y in directions:
        if target_x - start_x == dir_x*2 and target_y - start_y == dir_y*2:
            return (start_x + dir_x, start_y + dir_y)
    return None

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;

  repeated int32 board = 2;
}

Action schema

move(int piece_idx, int x, int y)
done_move()

Start building now

Last updated