Hex
Game logic
Game Logic code
def init_game(game_settings):
state = {
'player_turn_idx': 0,
'pieces': []
}
return state
def place_piece(state, row, column):
WIDTH = 11
HEIGHT = 11
INVALID_ACTION_NOT_YOUR_TURN = "Not your turn."
INVALID_ACTION_OUT_OF_BOUND = "Location is out of bound."
INVALID_ACTION_ALREADY_PLACED = "A piece is already placed here."
if __is_out_of_bound(row, column, WIDTH, HEIGHT):
raise InvalidActionError(INVALID_ACTION_OUT_OF_BOUND)
for piece in state['pieces']:
if piece['row'] == row and piece['column'] == column:
raise InvalidActionError(INVALID_ACTION_ALREADY_PLACED)
player_idx = state['player_turn_idx']
state['pieces'].append({
'row': row,
'column': column,
'value': player_idx
})
state['player_turn_idx'] = (player_idx + 1) % 2
return state
def __is_bottom(coord, board_width, board_height):
return coord[0] == 0
def __is_top(coord, board_width, board_height):
return coord[0] == board_height - 1
def __is_left(coord, board_width, board_height):
return coord[1] == 0
def __is_right(coord, board_width, board_height):
return coord[1] == board_width - 1
def __has_path_to(state, is_initial_func, is_target_func, player_idx, board_width, board_height):
"""
Does a dfs search to see if a piece that satisfies the initial func
is connected to a piece that satisfies sthe target func.
<is_initial_func> is a function that returns a boolean if a piece
satisfies the initial condition.
"""
visited = set()
stack = []
has_target = False
piece_coords = set()
for piece in state['pieces']:
coord = (piece['row'], piece['column'])
if piece['value'] == player_idx:
piece_coords.add(coord)
else:
continue
if is_initial_func(coord, board_width, board_height):
stack.append(coord)
if is_target_func(coord, board_width, board_height):
has_target = True
if not is_initial_func or not has_target:
return False
while len(stack) > 0:
this_coord = stack.pop()
if is_target_func(this_coord, board_width, board_height):
return True
if this_coord in visited:
continue
visited.add(this_coord)
neighbors = __get_neighbors(this_coord[0], this_coord[1], board_width, board_height)
for n in neighbors:
if n in piece_coords:
stack.append(n)
return False
def __is_out_of_bound(row, column, board_width, board_height):
return (row < 0 or row >= board_height
or column < 0 or column >= board_width)
def __get_neighbors(row, column, board_width, board_height):
if __is_out_of_bound(row, column, board_width, board_height):
return []
neighbors = []
if column > 0:
neighbors.append((row, column - 1))
if column < board_width - 1:
neighbors.append((row, column + 1))
if row > 0:
neighbors.append((row - 1, column))
if column < board_width - 1:
neighbors.append((row - 1, column + 1))
if row < board_height - 1:
neighbors.append((row + 1, column))
if column > 0:
neighbors.append((row + 1, column - 1))
return neighbors
def get_game_result(state):
WIDTH = 11
HEIGHT = 11
player1_has_path = __has_path_to(
state, __is_left, __is_right, 0, WIDTH, HEIGHT)
player2_has_path = __has_path_to(
state, __is_top, __is_bottom, 1, WIDTH, HEIGHT)
if (player1_has_path and player2_has_path):
return {
"game_result": "Draw"
}
elif (player1_has_path and not player2_has_path):
return {
"game_result": "Winner",
"winner_idx": 0
}
elif (player2_has_path and not player1_has_path):
return {
"game_result": "Winner",
"winner_idx": 1
}
else:
return {
"game_result": "NoWinnerYet"
}
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;
// All the pieces on the board that a player has put down. Player idx 0 tries
// to connect left to right (column = 0 to column = 10). Plyaer idx 1 tries
// to connect bottom to top (row = 0 to row = 10).
repeated Piece pieces = 2;
}
message Piece {
// Row of the piece that has been placed.
int32 row = 1;
// Column of the piece that has been placed.
int32 column = 2;
// value is the player_idx who placed this piece, can be 0 or 1.
int32 value = 3;
}
Action schema
place_piece(int row, int column)
Last updated