Generals
Game logic
Game Logic code
import random
def init_game(game_settings):
width = 10
height = 10
mountain_count = 10
tower_count = 2
board_list = []
for i in range(mountain_count):
board_list.append(_build_tile('mountain', 0))
for i in range(tower_count):
board_list.append(_build_tile('tower', 40))
board_list.append(_build_tile('king', 1, 0))
board_list.append(_build_tile('king', 1, 1))
for i in range(width*height - len(board_list)):
board_list.append(_build_tile('regular', 0, None))
board = _make_2d_board(board_list, width, height)
return {
"player_turn_idx": 0,
"player1_total_count": 1,
"player2_total_count": 1,
"board": board,
"round": 0,
"board_width": width,
"board_height": height
}
def _build_tile(tile_type, count, tile_player_idx = None, is_visible = True):
return {
'type': tile_type,
'tile_player_idx': tile_player_idx,
'count': count,
'is_visible': is_visible
}
def _make_2d_board(board_list, width, height):
random.shuffle(board_list)
index = 0
board = []
for r in range(height):
row = []
for c in range(width):
row.append(board_list[index])
index += 1
board.append(row)
return board
def _is_out_of_bound(row, column, board):
if row < 0 or row >= len(board):
return True
if column < 0 or column >= len(board[row]):
return True
return False
def move(state, row, column, direction, move_half):
board = state['board']
if _is_out_of_bound(row, column, board):
raise InvalidActionError("Start position is out of bound")
start_piece = board[row][column]
player_idx = state['player_turn_idx']
if start_piece["tile_player_idx"] != player_idx:
raise InvalidActionError("Cannot move from a tile you do not control")
end_row = row
end_column = column
if direction == "UP":
end_row -= 1
if end_row < 0:
raise InvalidActionError("Moving out of bound")
elif direction == "DOWN":
end_row += 1
if end_row >= len(board):
raise InvalidActionError("Moving out of bound")
elif direction == "LEFT":
end_column -= 1
if end_column < 0:
raise InvalidActionError("Moving out of bound")
elif direction == "RIGHT":
end_column += 1
if end_column >= len(board[row]):
raise InvalidActionError("Moving out of bound")
else:
raise InvalidActionError("Direction should be UP, DOWN, LEFT, or RIGHT")
end_piece = board[end_row][end_column]
number_to_move = int(start_piece["count"]/2) if move_half else start_piece["count"] - 1
number_to_move = max(number_to_move, 0)
if end_piece["type"] != "mountain":
start_piece["count"] -= number_to_move
if end_piece["tile_player_idx"] == None:
end_piece["count"] -= number_to_move
elif end_piece["tile_player_idx"] == start_piece["tile_player_idx"]:
end_piece["count"] += number_to_move
else:
end_piece["count"] -= number_to_move
if end_piece["count"] < 0:
end_piece["count"] = -end_piece["count"]
end_piece["tile_player_idx"] = player_idx
state = _auto_update(state)
state = _recompute_count(state)
return state
def _recompute_count(state):
player1_count = 0
player2_count = 0
for row in state["board"]:
for piece in row:
if piece["tile_player_idx"] == 0:
player1_count += piece["count"]
if piece["tile_player_idx"] == 1:
player2_count += piece["count"]
state["player1_total_count"] = player1_count
state["player2_total_count"] = player2_count
return state
def do_nothing(state):
state = _auto_update(state)
state = _recompute_count(state)
return state
def _auto_update(state):
player_idx = state['player_turn_idx']
if player_idx == 0:
state["player_turn_idx"] = 1
return state
state["player_turn_idx"] = 0
if state["round"] % 25 == 0:
for row in state["board"]:
for piece in row:
if piece["tile_player_idx"] != None:
piece["count"] += 1
else:
for row in state["board"]:
for piece in row:
piece_type = piece["type"]
if (piece_type == "tower" or piece_type == "king") and piece["tile_player_idx"] != None:
piece["count"] += 1
state["round"] += 1
return state
def get_game_result(state):
has_player1 = False
has_player2 = False
for row in state["board"]:
for piece in row:
if piece["tile_player_idx"] == 0:
if piece["type"] == "king":
has_player1 = True
if piece["tile_player_idx"] == 1:
if piece["type"] == "king":
has_player2 = True
if has_player1 and not has_player2:
return {
"game_result": "Winner",
"winner_idx": 0
}
if has_player2 and not has_player1:
return {
"game_result": "Winner",
"winner_idx": 1
}
if state["round"] > 500:
if state["player1_total_count"] == state["player2_total_count"]:
return {
"game_result": "Draw"
}
elif state["player1_total_count"] > state["player2_total_count"]:
return {
"game_result": "Winner",
"winner_idx": 0
}
else:
return {
"game_result": "Winner",
"winner_idx": 1
}
return {
"game_result": "NoWinnerYet"
}
def _get_visible(state, player_idx):
initial_visible = set()
visible = set()
board = state["board"]
for row_idx, row in enumerate(board):
for column_idx, piece in enumerate(row):
if piece["tile_player_idx"] == player_idx:
visible.add((row_idx, column_idx))
initial_visible.add((row_idx, column_idx))
for r, c in initial_visible:
for i in [-1, 0, 1]:
for j in [-1, 0, 1]:
if not _is_out_of_bound(r + i, c + j, board):
visible.add((r + i, c + j))
return visible
def get_player_states(state):
player_states = []
for i in range(2):
visible_coordinates = _get_visible(state, i)
player_board = []
for row_idx, row in enumerate(state["board"]):
player_board.append([])
for column_idx, piece in enumerate(row):
if (row_idx, column_idx) in visible_coordinates:
player_board[row_idx].append(piece)
elif piece["type"] == "mountain":
player_board[row_idx].append(piece)
else:
player_board[row_idx].append(_build_tile('regular', 0, None, False))
player_states.append({
"player_turn_idx": state["player_turn_idx"],
"board": player_board,
"round": state["round"],
"board_width": state["board_width"],
"board_height": state["board_height"],
"player1_total_count": state["player1_total_count"],
"player2_total_count": state["player2_total_count"]
})
return player_states
Game state schema
message State {
int32 player_turn_idx = 1;
int32 player1_total_count = 2;
int32 player2_total_count = 3;
repeated Tile board = 4 [packed = true];
int32 round = 5;
int32 board_width = 6;
int32 board_height = 7;
}
message Tile {
string tile_type = 1;
int32 tile_player_idx = 2;
int32 count = 3;
bool is_visible = 4;
}
Action schema
move(int row, int column, string direction, bool move_half)
do_nothing()
Last updated