def test_smash_col(self): self.assertEqual(Board.smash_col_up([0, 0, 0, 0]), (False, 0, [0, 0, 0, 0])) self.assertEqual(Board.smash_col_up([1, 0, 0, 0]), (False, 0, [1, 0, 0, 0])) self.assertEqual(Board.smash_col_up([1, 2, 0, 0]), (False, 0, [1, 2, 0, 0])) self.assertEqual(Board.smash_col_up([1, 1, 0, 0]), (True, 2, [2, 0, 0, 0])) self.assertEqual(Board.smash_col_up([0, 1, 0, 0]), (True, 0, [1, 0, 0, 0]))
def add_game(self, player_strategy, rnd, starting_game_position=None): """Runs a game with the given strategy and randomness source, then enrolls the outcome in the dataset. If @p starting_position is a Game object, start from that position. Returns the number of examples (moves) added. """ states = np.zeros((1, EXAMPLE_WIDTH)) num_moves = 0 game = starting_game_position or Game(rnd=rnd) running = True while running: intermediate_board, turn_outcome = ( game.do_turn_and_retrieve_intermediate( player_strategy.get_move(game.board(), game.score()))) running = (turn_outcome != GAMEOVER) num_moves += (turn_outcome != ILLEGAL) if turn_outcome == OK: states = np.append(states, Board.as_vector(intermediate_board), axis=0) self._num_examples += 1 player_strategy.notify_outcome(game.board(), game.score()) scores = Dataset.evaluate_states(states, game.board(), game.score) assert(len(states) == len(scores)) batch_size_so_far = self._example_batches[-1].shape[0] if len(states) + batch_size_so_far > MAX_BATCH_SIZE: self._example_batches.append(np.zeros((0, EXAMPLE_WIDTH))) self._score_batches.append(np.zeros((0, 1))) self._example_batches[-1] = \ np.append(self._example_batches[-1], states, axis=0) self._score_batches[-1] = np.append(self._score_batches[-1], scores) return len(states)
class BoardTest(unittest.TestCase): def setUp(self): self.size = 3 self.life_rules = mock.create_autospec(Rules, spec_set=True, instance=True) self.board = Board(self.empty_matrix(self.size), self.life_rules) def test_can_construct_board_with_no_life(self): self.life_rules.apply.return_value = 0 nt.assert_equal(self.board.next_board(), self.empty_matrix(self.size)) def test_next_board_will_have_life_rules_applied(self): self.life_rules.apply.return_value = 1 nt.assert_equal(self.board.next_board(), self.empty_matrix(self.size, 1)) def empty_matrix(self, size, initial_value=0): return [[initial_value for x in range(size)] for x in range(size)]
def json_test(): tiles = [] for row in range(0, 2): tiles.append([]) for col in range(0, 2): tiles[row].append(MockTile("{0} {1}".format(col, row))) board = Board(tiles, {}) json_string = ( '{"tile_data": {}, "tiles": ' '[["serial 0 0", "serial 1 0"], ' '["serial 0 1", "serial 1 1"]]}' ) serial_board = board.as_json() print(serial_board) assert serial_board == json_string
def __init__(self): ''' Initialize fieleds. ''' self._solver = Solver() self._board = Board() self._state = Simulation.INIT
def test_smash(self): # This doesn't comprehensively test smashing because # the tests for Board mostly did that already. for direction in DIRECTIONS: board = Board() board = board.update((1, 1), 2) game = Game(rnd=random.Random(1), board=board) self.assertTrue(game.smash(direction)) self.assertEqual(game.board()[1, 1], 0) for direction in DIRECTIONS: board = Board() board = board.update((0, 0), 2) game = Game(rnd=random.Random(1), board=board) if direction in {UP, LEFT}: self.assertFalse(game.smash(direction)) else: self.assertTrue(game.smash(direction)) self.assertEqual(game.board()[0, 0], 0)
def get_tile_test(): tiles = [] for row in range(0, 30): tiles.append([]) for col in range(0, 5): tiles[row].append(MockTile("{0} {1}".format(col, row))) board = Board(tiles, {}) tile = board.get_tile_at_coordinate(Coordinate(1, 4)) assert tile.tile_type == "1 4" tile = board.get_tile_at_coordinate(Coordinate(3, 10)) assert tile.tile_type == "3 10" tile = board.get_tile_at_coordinate(Coordinate(0, 0)) assert tile.tile_type == "0 0" tile = board.get_tile_at_coordinate(Coordinate(4, 29)) assert tile.tile_type == "4 29" assert_raises(IndexError, board.get_tile_at_coordinate, Coordinate(100, 100))
def setUp(self): # A board that's easy to read for debugging purposes but does # not have real tiles and so will fail smash/encode operations. self.readable_board = Board( [["00", "01", "02", "03"], ["10", "11", "12", "13"], ["20", "21", "22", "23"], ["30", "31", "32", "33"]]) # A board that occurred in real play. self.realistic_board = Board( [[ 2, 128, 8, 8], [ 8, 8, 16, 0], [ 4, 32, 4, 0], [ 2, 4, 0, 0]])
def __init__(self, **kwargs): self.size = kwargs.get('size', 8) self.board = Board(self.size) WhiteAgent = kwargs.get('WhiteAgent', RandomAgent) BlackAgent = kwargs.get('BlackAgent', RandomAgent) self.white_agent = WhiteAgent(self, WHITE, **kwargs) self.black_agent = BlackAgent(self, BLACK, **kwargs) make_silent(kwargs.get('silent', False)) self.reset()
def test_ai(self): b = Board(False) b.set_black(4, 3) b.set_black(3, 4) b.set_white(4, 4) b.set_white(3, 3) b.clear_moves() b.mark_moves(BLACK) result = b.draw() canvas = """ a.b.c.d.e.f.g.h. 1 ................1 2 ................2 3 ......MM........3 4 ....MMWWBB......4 5 ......BBWWMM....5 6 ........MM......6 7 ................7 8 ................8 a.b.c.d.e.f.g.h.""" self.assertEqual(result, canvas)
def show_exemplar(model, x, x_as_onehot, y): """Picks a random example from the data.""" i = np.random.randint(0, x.shape[0]) example = x[i, :] example_as_onehot = x_as_onehot[i] score = y[i] example_as_single_example = np.reshape(example_as_onehot, (1, WIDTH * HEIGHT, MAX_TILE)) prediction = model.predict(example_as_single_example) board = Board.from_vector(example) board.pretty_print() print("Actual score: %d; predicted score: %s" % (score, prediction))
def __init__(self, size, BlackAgent=RandomAgent, WhiteAgent=RandomAgent, **kwargs): self.size = size self.board = Board(self.size) self.board.init_starting_position() # game state is a 2-tuple of the board state, and which player's turn # it is. self.game_state = (self.board, BLACK) self.legal_cache = CacheDict() black_time = kwargs.get('black_time', 5) white_time = kwargs.get('white_time', 5) self.white_agent = WhiteAgent(self, WHITE, time=white_time, **kwargs) self.black_agent = BlackAgent(self, BLACK, time=black_time, **kwargs) # storing legal moves allows us to avoid needlessly recalculating them self.legal_white_moves = [] self.legal_black_moves = []
def _state_prompt_restart(self): ''' Determine whether to re-run simulation and update state to either PROMPT_TEAM of FINISHED Return str, board representation ''' # ask whether player wants to play again choice = Simulation.get_input( static.UTIL['retry_prompt'], static.BINARY) if choice in static.YES: self._board = Board() self._state = Simulation.PROMPT_TEAM else: self._state = Simulation.FINISHED return '' # return empty line to print
def __init__(self, timeout=1000, display_moves=True, players=['ai', 'ai'], colour=False): self.board = Board(colour) self.timeout = timeout self.ai_counter = 0 self.list_of_colours = [BLACK, WHITE] self.players = players self.display_moves = display_moves self.controllers = deque([self._make_controller(c, p) for c, p in zip(self.list_of_colours, self.players)]) self.player = self.controllers[0].get_colour() self.board.set_black(4, 3) self.board.set_black(3, 4) self.board.set_white(4, 4) self.board.set_white(3, 3) self.board.mark_moves(self.player) self.previous_move = None
def add_generate_row(self, board: Board) -> bool: if 0 == self.current_frame % (self.FRAME_RATE * 10): new_row = board.random_row(rows=1, has_bomb=True) else: new_row = board.random_row(rows=1) new_board = np.vstack((new_row, board.board)) if (board.board[-1, :] == Icon.Empty.value).all(): new_board = np.delete(new_board, -1, axis=0) board.replace(new_board) self.trace('\nnew game board (append row):') if self._enable_trace: board.print() self.trace('') return True self.__is_alive = False return False
def test_piece_about_to_exit(self): board = Board() center_piece = Piece(PLAYER_1_ID, PieceType.two) center_piece.set_movement_direction(Direction.east) board.get_tile(2, 2).place_piece(center_piece) assert center_piece.is_exiting_board() is False top_piece = Piece(PLAYER_1_ID, PieceType.two) top_piece.set_movement_direction(Direction.north) board.get_tile(2, 3).place_piece(top_piece) assert top_piece.is_exiting_board() is True top_piece.set_movement_direction(Direction.west) assert top_piece.is_exiting_board() is False east_piece = Piece(PLAYER_1_ID, PieceType.two) east_piece.set_movement_direction(Direction.east) board.get_tile(3, 1).place_piece(east_piece) assert east_piece.is_exiting_board() is True east_piece.set_movement_direction(Direction.west) assert east_piece.is_exiting_board() is False
def evaluateNextChild(self): for x in range(self.x, 8): for y in range(self.y, 8): for x2 in range(self.x2, 8): for y2 in range(self.y2, 8): if self.testB.isLegal(x, y, x2, y2, True): tempB = Board() tempB.setBoard(self.testB.getBoard()) if self.attackingTeam == "Black": tempB.incrementTurn() tempB.movePiece(x, y, x2, y2) if x != self.prevX: x += 1 elif y != self.prevY: y += 1 elif x2 != self.prevX2: x2 += 1 else: y2 += 1 self.x, self.y, self.x2, self.y2 = x, y, x2, y2 return Node(tempB, parent=self.evaluationNode) self.setPreviousVars(x, y, x2, y2) return False
def alpha_beta(board: Board, depth: int = 3, board_eval: Callable = weighted_eval, print_count: bool = False): """ Implementation of Alpha-Beta pruning to optimise the MiniMax algorithm. This stops evaluating a move when at least one possibility has been found that proves the move to be worse than a previously examined move. Should play identically to negamax for the same search depth. https://en.wikipedia.org/wiki/Alpha%E2%80%93beta_pruning """ best_move = None start_time = time.time() assert depth > 0 legal_moves = list(board.legal_moves) jobs = [] for move in legal_moves: new_board = Board(board.fen) jobs.append((new_board, depth, move, board_eval)) pool = multiprocessing.Pool(multiprocessing.cpu_count()) result = pool.starmap(_get_best_move, jobs) counter = 0 score = LOW_BOUND for move, value, sub_counter in result: counter += sub_counter if value > score: score = value best_move = move if print_count: elapsed = time.time() - start_time log.info( f"Evaluations: {counter} in {elapsed}s at {counter / elapsed} evals/s." ) return best_move
def test_create_board_from_another_one(self): self.board.move_pawn((0, 1), PLAYER_1) self.board.move_pawn((0, 2), PLAYER_2) self.board.move_pawn((0, 2), PLAYER_3) self.board.move_pawn((0, 2), PLAYER_4) self.board.add_wall((1, 1), is_horiz=True, player=PLAYER_1) self.board.add_wall((1, 2), is_horiz=True, player=PLAYER_2) self.board.add_wall((1, 3), is_horiz=True, player=PLAYER_3) self.board.add_wall((1, 4), is_horiz=True, player=PLAYER_4) self.board.add_wall((2, 1), is_horiz=False, player=PLAYER_1) self.board.add_wall((3, 1), is_horiz=False, player=PLAYER_2) self.board.add_wall((4, 1), is_horiz=False, player=PLAYER_3) self.board.add_wall((5, 1), is_horiz=False, player=PLAYER_4) board2 = Board(self.board, len(self.board.pawns)) self.assertEqual(4, len(board2.pawns)) self.assertEqual(self.board.pawns, board2.pawns) self.assertEqual(4, len(board2.goals)) self.assertEqual(self.board.goals, board2.goals) self.assertEqual(4, len(board2.player_walls)) self.assertEqual(self.board.player_walls, board2.player_walls) self.assertEqual(self.board.verti_walls, board2.verti_walls) self.assertEqual(self.board.horiz_walls, board2.horiz_walls)
def add_n_examples(self, strategy, rnd, n, starting_positions_dataset=None): """Runs games and adds them to the dataset until at least @p n examples have been added. Returns the number of examples added. If @p starting_positions_dataset is set, games will be started from a randomly selected position from that dataset rather than from a blank board.""" print("Adding", n, "examples to dataset.") added = 0 while added < n: starting_game = None if starting_positions_dataset: random_position = starting_positions_dataset.nth_example( rnd.randint(0, starting_positions_dataset.num_examples() - 1)) starting_game = Game(Board.from_vector(random_position)) if not starting_game.board().can_move(): continue num_added = self.add_game(strategy, rnd, starting_game) if (added // 10000) != ((num_added + added) // 10000): print("Added %d so far..." % (num_added + added)) added += num_added return added
def test_get_rent(self): chloe = Player("Chloe", 0) lucien = Player("Lucien", 1) gildas = Player("Gildas", 1) board = Board() chloe.buy_good(board.boxes[1]) board.boxes[1].nb_houses = 2 chloe.buy_good(board.boxes[3]) board.boxes[3].nb_houses = 3 chloe.buy_good(board.boxes[5]) chloe.buy_good(board.boxes[6]) chloe.buy_good(board.boxes[12]) gildas.buy_good(board.boxes[15]) gildas.buy_good(board.boxes[25]) lucien.dices = [3, 4] self.assertEqual(0, board.boxes[1].get_rent(chloe)) self.assertEqual(0, board.boxes[8].get_rent(chloe)) self.assertEqual(0, board.boxes[16].get_rent(chloe)) self.assertEqual(30, board.boxes[1].get_rent(lucien)) self.assertEqual(180, board.boxes[3].get_rent(lucien)) self.assertEqual(50, board.boxes[5].get_rent(lucien)) self.assertEqual((3 + 4) * 4, board.boxes[12].get_rent(lucien)) self.assertEqual(0, board.boxes[13].get_rent(lucien)) self.assertEqual(100, board.boxes[15].get_rent(lucien))
def move(self, board: Board): """ Ask for the user's input until a valid one appears, and then update the board :param board: :return: """ while 1: coord = input(">") coord = coord.split(" ") row = coord[0] try: col = coord[1] except IndexError: print("col is invalid") continue try: row = int(row) except ValueError: print("row is not an int") continue try: col = int(col) except ValueError: print("col is not an int") continue if row < 0 or row >= board.rows: print("row out of bound") continue if col < 0 or col >= board.cols: print("col out of bound") continue if board.get(row, col) != 0: print(f"({row}, {col}) has been occupied") continue return row, col
class ChildEvaluator(object): def __init__(self, node, attackingTeam): self.x, self.y, self.x2, self.y2 = 0, 0, 0, 0 self.testB = Board() self.testB.setBoard(node.name.getBoard()) if attackingTeam == "Black": self.testB.incrementTurn() self.attackingTeam = attackingTeam self.evaluationNode = node def setPreviousVars(self, x, y, x2, y2): self.prevX = x self.prevY = y self.prevX2 = x2 self.prevY2 = y2 def evaluateNextChild(self): for x in range(self.x, 8): for y in range(self.y, 8): for x2 in range(self.x2, 8): for y2 in range(self.y2, 8): if self.testB.isLegal(x, y, x2, y2, True): tempB = Board() tempB.setBoard(self.testB.getBoard()) if self.attackingTeam == "Black": tempB.incrementTurn() tempB.movePiece(x, y, x2, y2) if x != self.prevX: x += 1 elif y != self.prevY: y += 1 elif x2 != self.prevX2: x2 += 1 else: y2 += 1 self.x, self.y, self.x2, self.y2 = x, y, x2, y2 return Node(tempB, parent=self.evaluationNode) self.setPreviousVars(x, y, x2, y2) return False def isComplete(self): return self.x == 7 and self.y == 7 and self.x2 == 7 and self.y2 == 7
def get_input(self, board): # best_move = None # best_score = -100 # TBD - perhaps use some partial scores to decide somewhat better moves for i in range(0, board.shape[0]): for j in range(0, board.shape[1]): if board[i, j] != 0: continue current_board = Board(array=board.copy()) current_player = self.player_no current_board.move(i, j, self.player_no) while not current_board.is_finished(): current_player = self.switch_player(current_player) next_move = ScorePlayer(self.player_no).get_input( current_board.board) # that's just one step current_board.move(next_move[0], next_move[1], current_player) if current_board.player_who_won == self.player_no: # if game played was won by the Player, than finish search (no way to evaluate which wining strategy is better, for now ;P) return [i, j] return ScorePlayer(self.player_no).get_input( board ) # we didn't find a winning solution, so fallback to simple 1-step score based
class TicTacToeGame(IGame): first_player = SmartBot second_player = SmartBot def start(self): self.board = Board() self.players = [ self.first_player('X', 'O'), self.second_player('O', 'X') ] self.turn = 0 print("Tic Tac Toa %s vs %s" % tuple(player.__class__.__name__ for player in self.players)) def update(self): os.system('cls') self.board.print() player = self.players[self.turn] if player.is_bot: print("Bot is thinking") # time.sleep(1) player.next_move(self.board) self.turn = 1 - self.turn # Check win conditions for token in ['X', 'O']: if self.board.does_token_won(token): self.board.print() print("Player %s won the game" % token) return False return not self.board.is_full()
from game.board import Board if __name__ == '__main__': pawns = [[[1, 1], [2, 1], [3, 1]], [[1, 3], [2, 3], [3, 3]]] bridges = [] for y in range(5): for x in range(5): if x < 4: bridges.append((x, y, x + 1, y)) if y < 4: bridges.append((x, y, x, y + 1)) b = Board(bridges, pawns) bestMove = b.findBestMove() newpawns = pawns[0].copy() newpawns.remove([bestMove[0], bestMove[1]]) newpawns.append([bestMove[2], bestMove[3]]) newBoard = Board(bridges, [newpawns, pawns[1]]) bestBridge = newBoard.removeBestBridge() newBridges = bridges.copy() newBridges.remove(bestBridge) newBoard = Board(newBridges, [newpawns, pawns[1]]) newBoard.printboard()
def test_push_movements_execution(self): board = Board() piece_four = Piece(PLAYER_1_ID, PieceType.four) piece_four.set_movement_direction(Direction.north) board.get_tile(2, 1).place_piece(piece_four) piece_three = Piece(PLAYER_1_ID, PieceType.three) piece_three.set_movement_direction(Direction.east) board.get_tile(1, 2).place_piece(piece_three) piece_three_2 = Piece(PLAYER_2_ID, PieceType.three) piece_three_2.set_movement_direction(Direction.west) board.get_tile(2, 2).place_piece(piece_three_2) piece_five = Piece(PLAYER_2_ID, PieceType.five) piece_five.set_movement_direction(Direction.east) board.get_tile(2, 3).place_piece(piece_five) piece_two = Piece(PLAYER_1_ID, PieceType.two) piece_two.set_movement_direction(Direction.south) board.get_tile(3, 3).place_piece(piece_two) piece_one = Piece(PLAYER_2_ID, PieceType.one) piece_one.set_movement_direction(Direction.west) board.get_tile(3, 2).place_piece(piece_one) assert board.execute_board_movements(PLAYER_1_ID) == 5 assert board.get_tile(1, 1).piece is None assert board.get_tile(2, 1).piece is None assert board.get_tile(3, 1).piece == piece_one assert board.get_tile(1, 2).piece == piece_three assert board.get_tile(2, 2).piece == piece_four assert board.get_tile(3, 2).piece == piece_two assert board.get_tile(1, 3).piece is None assert board.get_tile(2, 3).piece == piece_three_2 assert board.get_tile(3, 3).piece is None assert piece_five.tile is None
def test_one_not_pushable_if_piece_behind(self): board = Board() five = Piece(PLAYER_1_ID, PieceType.five) five.set_movement_direction(Direction.south) board.get_tile(2, 2).place_piece(five) one = Piece(PLAYER_1_ID, PieceType.one) one.set_movement_direction(Direction.north) board.get_tile(1, 1).place_piece(one) enemy_two = Piece(PLAYER_2_ID, PieceType.two) enemy_two.set_movement_direction(Direction.east) board.get_tile(0, 2).place_piece(enemy_two) board.execute_board_movements(PLAYER_2_ID) assert board.get_tile(2, 1).piece == five assert board.get_tile(1, 2).piece == one assert board.get_tile(0, 2).piece is None
def test_draw(self): b = Board(False) b.set_black(0, 0) b.set_black(1, 0) b.set_white(1, 1) b.set_move(0, 1) result = b.draw() canvas = """ a.b.c.d.e.f.g.h. 1 BBBB............1 2 MMWW............2 3 ................3 4 ................4 5 ................5 6 ................6 7 ................7 8 ................8 a.b.c.d.e.f.g.h.""" self.assertEqual(result, canvas) b.clear_moves() b.mark_moves(BLACK) result = b.draw() canvas = """ a.b.c.d.e.f.g.h. 1 BBBB............1 2 ..WW............2 3 ..MMMM..........3 4 ................4 5 ................5 6 ................6 7 ................7 8 ................8 a.b.c.d.e.f.g.h.""" self.assertEqual(result, canvas) b.clear_moves() b = Board(False) b.set_white(3, 3) b.set_white(3, 4) b.set_white(4, 4) b.set_white(4, 3) b.set_black(2, 2) b.set_black(3, 2) b.set_black(4, 2) b.set_black(5, 2) b.set_black(2, 3) b.set_black(5, 3) b.set_black(2, 4) b.set_black(5, 4) b.set_black(2, 5) b.set_black(3, 5) b.set_black(4, 5) b.set_black(5, 5) b.clear_moves() b.mark_moves(WHITE) result = b.draw() canvas = """ a.b.c.d.e.f.g.h. 1 ................1 2 ..MMMMMMMMMMMM..2 3 ..MMBBBBBBBBMM..3 4 ..MMBBWWWWBBMM..4 5 ..MMBBWWWWBBMM..5 6 ..MMBBBBBBBBMM..6 7 ..MMMMMMMMMMMM..7 8 ................8 a.b.c.d.e.f.g.h.""" self.assertEqual(result, canvas) b = Board(False) b.set_white(3, 3) b.set_white(4, 4) b.set_black(3, 4) b.set_black(4, 3) b.mark_moves(BLACK) result = b.draw() canvas = """ a.b.c.d.e.f.g.h. 1 ................1 2 ................2 3 ......MM........3 4 ....MMWWBB......4 5 ......BBWWMM....5 6 ........MM......6 7 ................7 8 ................8 a.b.c.d.e.f.g.h.""" b.clear_moves() b.make_move((3, 2), BLACK) b.mark_moves(WHITE) result = b.draw() canvas = """ a.b.c.d.e.f.g.h. 1 ................1 2 ................2 3 ....MMBBMM......3 4 ......BBBB......4 5 ....MMBBWW......5 6 ................6 7 ................7 8 ................8 a.b.c.d.e.f.g.h.""" b.clear_moves() b.make_move((2, 2), WHITE) b.mark_moves(BLACK) result = b.draw() canvas = """ a.b.c.d.e.f.g.h. 1 ................1 2 ................2 3 ..MMWWBB........3 4 ....MMWWBB......4 5 ......BBWWMM....5 6 ........MM......6 7 ................7 8 ................8 a.b.c.d.e.f.g.h.""" b = Board(False) b.set_white(6, 0) b.set_white(5, 1) b.set_white(3, 1) b.set_white(3, 2) b.set_white(4, 2) b.set_white(5, 2) b.set_white(3, 3) b.set_white(4, 3) b.set_black(2, 3) b.set_black(2, 4) b.set_black(3, 4) b.set_black(4, 4) b.set_black(1, 5) b.set_black(4, 5) b.mark_moves(BLACK) result = b.draw() canvas = """ a.b.c.d.e.f.g.h. 1 ......MM....WW..1 2 ......WWMMWWMM..2 3 ....MMWWWWWW....3 4 ....BBWWWWMM....4 5 ....BBBBBB......5 6 ..BB....BB......6 7 ................7 8 ................8 a.b.c.d.e.f.g.h.""" self.assertEqual(result, canvas) b = Board(False) b.set_white(3, 4) b.set_white(4, 0) b.set_white(4, 3) b.set_white(4, 4) b.set_white(5, 0) b.set_white(5, 1) b.set_white(5, 3) b.set_white(6, 0) b.set_white(6, 1) b.set_white(7, 0) b.set_black(2, 0) b.set_black(3, 1) b.set_black(4, 1) b.set_black(7, 1) b.set_black(3, 2) b.set_black(4, 2) b.set_black(5, 2) b.set_black(6, 2) b.set_black(7, 2) b.set_black(3, 3) b.set_black(2, 3) b.set_black(2, 4) b.set_black(1, 5) b.mark_moves(BLACK) result = b.draw() #0 1 2 3 4 5 6 7 canvas = """ a.b.c.d.e.f.g.h. 1 ....BB..WWWWWWWW1 2 ......BBBBWWWWBB2 3 ......BBBBBBBBBB3 4 ....BBBBWWWWMM..4 5 ....BBWWWWMMMM..5 6 ..BBMMMMMMMM....6 7 ................7 8 ................8 a.b.c.d.e.f.g.h.""" self.assertEqual(result, canvas) b = Board(False) b.set_white(3, 4) b.set_white(4, 0) b.set_white(4, 3) b.set_white(4, 4) b.set_white(5, 0) b.set_white(5, 1) b.set_white(5, 3) b.set_white(6, 0) b.set_white(6, 1) b.set_white(7, 0) b.set_black(2, 0) b.set_black(3, 1) b.set_black(4, 1) b.set_black(7, 1) b.set_black(3, 2) b.set_black(4, 2) b.set_black(5, 2) b.set_black(6, 2) b.set_black(7, 2) b.set_black(3, 3) b.set_black(2, 3) b.set_black(2, 4) b.set_black(1, 5) b.mark_moves(BLACK) result = b.draw() #0 1 2 3 4 5 6 7 canvas = """ a.b.c.d.e.f.g.h. 1 ....BB..WWWWWWWW1 2 ......BBBBWWWWBB2 3 ......BBBBBBBBBB3 4 ....BBBBWWWWMM..4 5 ....BBWWWWMMMM..5 6 ..BBMMMMMMMM....6 7 ................7 8 ................8 a.b.c.d.e.f.g.h.""" self.assertEqual(result, canvas) b = Board(False) b.set_white(3, 2) b.set_white(4, 1) b.set_white(4, 2) b.set_white(5, 1) b.set_white(5, 2) b.set_white(6, 0) b.set_white(6, 1) b.set_white(6, 2) b.set_white(6, 3) b.set_black(1, 3) b.set_black(1, 5) b.set_black(2, 0) b.set_black(2, 3) b.set_black(2, 4) b.set_black(3, 1) b.set_black(3, 3) b.set_black(3, 4) b.set_black(3, 5) b.set_black(4, 3) b.set_black(4, 4) b.set_black(5, 3) b.set_black(5, 5) b.set_black(6, 4) b.set_black(7, 0) b.mark_moves(BLACK) result = b.draw() #0 1 2 3 4 5 6 7 canvas = """ a.b.c.d.e.f.g.h. 1 ....BB..MMMMWWBB1 2 ....MMBBWWWWWWMM2 3 ......WWWWWWWW..3 4 ..BBBBBBBBBBWWMM4 5 ....BBBBBB..BB..5 6 ..BB..BB..BB....6 7 ................7 8 ................8 a.b.c.d.e.f.g.h.""" self.assertEqual(result, canvas) b.clear_moves() b.mark_moves(WHITE) result = b.draw() canvas = """ a.b.c.d.e.f.g.h. 1 ....BBMM....WWBB1 2 ....MMBBWWWWWW..2 3 ......WWWWWWWW..3 4 MMBBBBBBBBBBWW..4 5 ..MMBBBBBBMMBB..5 6 ..BBMMBBMMBBMMMM6 7 MM..MMMM........7 8 ................8 a.b.c.d.e.f.g.h.""" self.assertEqual(result, canvas) ##b.clear_moves() ##b.mark_moves(WHITE) b.clear_moves() b.make_move((0, 3), WHITE) result = b.draw() #0 1 2 3 4 5 6 7 canvas = """ a.b.c.d.e.f.g.h. 1 ....BB......WWBB1 2 ......BBWWWWWW..2 3 ......WWWWWWWW..3 4 WWWWWWWWWWWWWW..4 5 ....BBBBBB..BB..5 6 ..BB..BB..BB....6 7 ................7 8 ................8 a.b.c.d.e.f.g.h.""" self.assertEqual(result, canvas)
def test_smash_and_can_move(self): # Empty board does not move. board = Board() self.assertFalse(board.can_move()) changed, score, smashed = board.smash_up() self.assertFalse(changed) self.assertEqual(score, 0) self.assertEqual(smashed, Board()) self.assertIsNot(smashed, board) # Board with a floating tile slides that tile. board = board.update([1, 2], 1) self.assertTrue(board.can_move()) changed, score, smashed = board.smash_up() self.assertTrue(changed) self.assertEqual(score, 0) self.assertNotEqual(smashed, board) self.assertEqual(smashed, Board().update([1, 0], 1)) # Board with aligned tiles smashes those tiles. board = board.update([1, 0], 1) self.assertTrue(board.can_move()) changed, score, smashed = board.smash_up() self.assertTrue(changed) self.assertEqual(score, 2) self.assertNotEqual(smashed, board) self.assertEqual(smashed, Board().update([1, 0], 2)) # Locked board does not move. board = Board([[1, 2, 1, 2], [2, 1, 2, 1], [1, 2, 1, 2], [2, 1, 2, 1]]) self.assertFalse(board.can_move()) changed, score, smashed = board.smash_up() self.assertFalse(changed) self.assertEqual(score, 0) self.assertEqual(smashed, board) self.assertIsNot(smashed, board)
"""Classes and functions related to dataset generation for learning Q functions. Datasets in this sense are mappings from board positions (represented as flattened arrays of tile numbers) to score values. """ import argparse import sys import numpy as np from game.common import * from game.board import Board from game.game import Game EXAMPLE_WIDTH = Board.vector_width() MAX_BATCH_SIZE = 4096 # numpy arrays get slow to update beyond this size. class Dataset(object): """A set of training data (held as matrices whose rows are examples) and a column vector of the example scores..""" def __init__(self): """Creates a new empty dataset.""" self._num_examples = 0 self._example_batches = [np.zeros((0, EXAMPLE_WIDTH))] self._score_batches = [np.zeros((0, 1))] def add_game(self, player_strategy, rnd, starting_game_position=None): """Runs a game with the given strategy and randomness source, then enrolls the outcome in the dataset.
class sudoku(): def __init__(self): self.board = Board() self.gameboard = self.board.return_board() self.command = Commands() def main(self): """Main game loop. Collects user input and invokes internal commands to fulfill user commands. ->the commands are tested for input by doctest in command.py and board.py. """ clear_screen() print("\n\n A B C D E F\n" " +---+---+---+---+---+---+\n" "1 | S U D | O K U |\n" " + + +\n\n\n" "'h' for help.") getch() clear_screen() exit = False self.board.plot(gameboard = self.gameboard) while exit is False: userstring = input("Geben Sie einen Befehl ein: ").lower() b = self.command.parser(userstring) for i in range(len(b)): if b[i] in ("save", "s"): self.command.save_to_file(i, b, self.gameboard) elif b[i] in ("quit","exit", "q", "e"): exit = True elif b[i] in ("load", "l"): temp = self.command.load_from_file(i,b) if temp != 0: self.gameboard = temp elif b[i] in ("refresh", "r"): self.board.plot(gameboard = self.gameboard) elif b[i] in ("add", "a"): temp = self.command.add(self.gameboard, b[1:]) if temp != 0: self.gameboard = temp self.board.plot(gameboard = self.gameboard) elif b[i] in ("delete", "d"): temp = self.command.delete(self.gameboard, b[1:]) if temp != 0: self.gameboard = temp self.board.plot(gameboard = self.gameboard) elif b[i] in ("change", "c"): temp = self.command.change(self.gameboard, b[1:]) if temp != 0: self.gameboard = temp self.board.plot(gameboard = self.gameboard) elif b[i] in ("help", "h"): clear_screen() f = open('help.txt', encoding="cp1252") print(f.read()) f.close() getch() clear_screen() self.board.plot(gameboard = self.gameboard) else: if b[i] != "filename": b[i] = "" #print("Befehl", b[i], "nicht gefunden!") clear_screen() print("\nBye!\n") getch() clear_screen()
class Director: """A code template for a person who directs the game. The responsibility of this class of objects is to control the sequence of play. Stereotype: Controller Attributes: board (Hunter): An instance of the class of objects known as Board. console (Console): An instance of the class of objects known as Console. keep_playing (boolean): Whether or not the game can continue. move (Rabbit): An instance of the class of objects known as Move. roster (Roster): An instance of the class of objects known as Roster. """ def __init__(self): """The class constructor. Args: self (Director): an instance of Director. """ self._board = Board() self._console = Console() self._keep_playing = True self._move = None self._roster = Roster() def start_game(self): """Starts the game loop to control the sequence of play. Args: self (Director): an instance of Director. """ self._prepare_game() while self._keep_playing: self._get_inputs() self._do_updates() self._do_outputs() def _prepare_game(self): """Prepares the game before it begins. In this case, that means getting the player names and adding them to the roster. Args: self (Director): An instance of Director. """ for n in range(2): name = self._console.read(f"Enter a name for player {n + 1}: ") player = Player(name) self._roster.add_player(player) def _get_inputs(self): """Gets the inputs at the beginning of each round of play. In this case, that means getting the move from the current player. Args: self (Director): An instance of Director. """ # display the game board board = self._board.to_string() self._console.write(board) # get next player's move player = self._roster.get_current() self._console.write(f"{player.get_name()}'s turn:") pile = self._console.read_number("What pile to remove from? ") stones = self._console.read_number("How many stones to remove? ") move = Move(stones, pile) player.set_move(move) def _do_updates(self): """Updates the important game information for each round of play. In this case, that means updating the board with the current move. Args: self (Director): An instance of Director. """ player = self._roster.get_current() move = player.get_move() self._board.apply(move) def _do_outputs(self): """Outputs the important game information for each round of play. In this case, that means checking if there are stones left and declaring the winner. Args: self (Director): An instance of Director. """ if self._board.is_empty(): winner = self._roster.get_current() name = winner.get_name() print(f"\n{name} won!") self._keep_playing = False self._roster.next_player()
class Human_Vs_Human: def __init__(self): self.game_board = Board() self.whos_turn_is_it = 'black' self.game_over = None def white_turn(self): possible_moves = self.game_board.get_all_white_moves() print('Whites Turn. Possible Moves:') while possible_moves: check_for_jumps = [ move for move in possible_moves if len(move) > 2 ] if check_for_jumps: possible_moves = check_for_jumps for index, move in enumerate(possible_moves): print( f'{index}: {self.game_board.get_human_readable_move_path(move)}' ) move_selection = None while move_selection is None: try: move_selection = int(input('Enter choice: ')) self.game_board.make_move(possible_moves[move_selection]) except ValueError: print('Invalid entry.') except IndexError: print('Invalid selection.') if len(possible_moves[move_selection]) > 2: possible_moves = self.game_board.check_for_white_additional_jump( possible_moves[move_selection][-1]) if possible_moves: print('You must continue jumping.') self.game_board.draw_board() else: break def black_turn(self): possible_moves = self.game_board.get_all_black_moves() print('Blacks Turn. Possible Moves:') while possible_moves: check_for_jumps = [ move for move in possible_moves if len(move) > 2 ] if check_for_jumps: possible_moves = check_for_jumps for index, move in enumerate(possible_moves): print( f'{index}: {self.game_board.get_human_readable_move_path(move)}' ) move_selection = None while move_selection is None: try: move_selection = int(input('Enter choice: ')) self.game_board.make_move(possible_moves[move_selection]) except ValueError: print('Invalid entry.') except IndexError: print('Invalid selection.') if len(possible_moves[move_selection]) > 2: possible_moves = self.game_board.check_for_black_additional_jump( possible_moves[move_selection][-1]) if possible_moves: print('You must continue jumping.') self.game_board.draw_board() else: break def run_game(self): while not self.game_over: self.game_board.draw_board() if self.whos_turn_is_it == 'black': self.black_turn() self.whos_turn_is_it = 'white' elif self.whos_turn_is_it == 'white': self.white_turn() self.whos_turn_is_it = 'black' self.game_over = self.game_board.has_someone_won() if self.game_over: print(self.game_over)
class Reversi: """This class enforces the rules of the game of Reversi.""" def __init__(self, size, BlackAgent=RandomAgent, WhiteAgent=RandomAgent, **kwargs): self.size = size self.board = Board(self.size) self.board.init_starting_position() # game state is a 2-tuple of the board state, and which player's turn # it is. self.game_state = (self.board, BLACK) self.legal_cache = CacheDict() black_time = kwargs.get('black_time', 5) white_time = kwargs.get('white_time', 5) self.white_agent = WhiteAgent(self, WHITE, time=white_time, **kwargs) self.black_agent = BlackAgent(self, BLACK, time=black_time, **kwargs) # storing legal moves allows us to avoid needlessly recalculating them self.legal_white_moves = [] self.legal_black_moves = [] def play_game(self): self.update_legal_moves(self.get_state()) while not self.is_won(): self.print_board() game_state = self.get_state() turn_color = game_state[1] self.update_legal_moves(game_state) legal_moves = None if turn_color == BLACK: legal_moves = self.legal_black_moves elif turn_color == WHITE: legal_moves = self.legal_white_moves else: raise ValueError if not legal_moves: print('{} had no moves, and passed their turn.'.format( color_name[turn_color])) self.game_state = (game_state[0], opponent[turn_color]) continue else: picked = self.agent_pick_move(game_state, legal_moves) print('{} plays at {}'.format( color_name[turn_color], str(picked))) updated_game_state = self.apply_move( game_state, picked[0], picked[1]) self.game_state = updated_game_state self.print_board() # figure out who won black_count, white_count = self.board.get_stone_counts() winner = BLACK if black_count > white_count else WHITE return winner, white_count, black_count def print_board(self): print(str(self.get_board())) def agent_pick_move(self, game_state, legal_moves): picked = None color = game_state[1] while picked not in legal_moves: if color == WHITE: picked = self.white_agent.get_action( self.get_state(), legal_moves) elif color == BLACK: picked = self.black_agent.get_action( self.get_state(), legal_moves) else: raise ValueError if picked is None: return None elif picked not in legal_moves: print(str(picked) + ' is not a legal move!') return picked def legal_moves(self, game_state, force_cache=False): # Note: this is a very naive and inefficient way to find # all available moves by brute force. I am sure there is a # more clever way to do this. If you want better performance # from agents, this would probably be the first area to improve. if force_cache: return self.legal_cache.get(game_state) board = game_state[0] if board.is_full(): return [] cached = self.legal_cache.get(game_state) if cached is not None: return cached board_size = board.get_size() moves = [] # list of x,y positions valid for color for y in range(board_size): for x in range(board_size): if self.is_valid_move(game_state, x, y): moves.append((x, y)) self.legal_cache.update(game_state, moves) return moves @staticmethod def is_valid_move(game_state, x, y): board, color = game_state piece = board.board[y][x] if piece != EMPTY: return False enemy = opponent[color] # now check in all directions, including diagonal for dy in range(-1, 2): for dx in range(-1, 2): if dy == 0 and dx == 0: continue # there needs to be >= 1 opponent piece # in this given direction, followed by 1 of player's piece distance = 1 yp = (distance * dy) + y xp = (distance * dx) + x while board.is_in_bounds(xp, yp) and board.board[yp][xp] == enemy: distance += 1 yp = (distance * dy) + y xp = (distance * dx) + x if distance > 1 and board.is_in_bounds(xp, yp) and board.board[yp][xp] == color: return True return False def next_state(self, game_state, x, y): """Given a game_state and a position for a new piece, return a new game_state reflecting the change. Does not modify the input game_state.""" game_state_copy = copy.deepcopy(game_state) result = self.apply_move(game_state_copy, x, y) return result @staticmethod def apply_move(game_state, x, y): """Given a game_state (which includes info about whose turn it is) and an x,y position to place a piece, transform it into the game_state that follows this play.""" color = game_state[1] board = game_state[0] board.place_stone_at(color, x, y) # now flip all the stones in every direction opponent = BLACK if color == BLACK: opponent = WHITE # now check in all directions, including diagonal to_flip = [] for dy in range(-1, 2): for dx in range(-1, 2): if dy == 0 and dx == 0: continue # there needs to be >= 1 opponent piece # in this given direction, followed by 1 of player's piece distance = 1 yp = (distance * dy) + y xp = (distance * dx) + x flip_candidates = [] while board.is_in_bounds(xp, yp) and board.board[yp][xp] == opponent: flip_candidates.append((xp, yp)) distance += 1 yp = (distance * dy) + y xp = (distance * dx) + x if distance > 1 and board.is_in_bounds(xp, yp) and board.board[yp][xp] == color: to_flip.extend(flip_candidates) for each in to_flip: board.flip_stone(each[0], each[1]) # board.place_stone_at(color, each[0], each[1]) if game_state[1] == WHITE: game_state = (game_state[0], BLACK) elif game_state[1] == BLACK: game_state = (game_state[0], WHITE) return game_state def is_won(self): """The game is over when neither player can make a move.""" return self.get_board().is_full() or (len(self.legal_black_moves) == 0 and len(self.legal_white_moves) == 0) def winner(self, game_state): """Given a game_state, return the color of the winner if there is one, otherwise return False to indicate the game isn't won yet. Note that legal_moves() is a slow operation, so this method tries to call it as few times as possible.""" board = game_state[0] black_count, white_count = board.get_stone_counts() # a full board means no more moves can be made, game over. if board.is_full(): if black_count > white_count: return BLACK else: # tie goes to white return WHITE # a non-full board can still be game-over if neither player can move. black_legal = self.legal_moves((game_state[0], BLACK)) if black_legal: return False white_legal = self.legal_moves((game_state[0], WHITE)) if white_legal: return False # neither black nor white has valid moves if black_count > white_count: return BLACK else: # tie goes to white return WHITE def update_legal_moves(self, game_state): legal_moves = self.legal_moves(game_state) color = game_state[1] if color == WHITE: self.legal_white_moves = legal_moves elif color == BLACK: self.legal_black_moves = legal_moves else: raise ValueError def get_board(self): """Return the board from the current game_state.""" return self.game_state[0] def get_state(self): """Returns a tuple representing the board state.""" return self.game_state def __str__(self): return str(self.board)
def setUp(self): self.size = 3 self.life_rules = mock.create_autospec(Rules, spec_set=True, instance=True) self.board = Board(self.empty_matrix(self.size), self.life_rules)
def __init__(self): self.board = Board() self.gameboard = self.board.return_board() self.ignoreit = False pass
class Commands(object): """class that contains the functions to convert the user input to internal commands """ def __init__(self): self.board = Board() self.gameboard = self.board.return_board() self.ignoreit = False pass def parser(self, command:str): """ Hacks the user-string into substrings >>> t.parser("test1 test2 -1.723434") ['test1', 'test2', '-1.723434'] """ x = [] temp = '' i = 0 while i < (len(command)): while command[i] != " ": temp += command[i] i = i + 1 if i == len(command): break i = i + 1 if temp != '': x.append(temp) temp = '' return x def save_to_file(self, i, b, sd): """saves the gameboard (sd) into to a binary file. In case the user submits no name the file name is default.sav. If the user provides a name, the data is written in name.sav. "i" is the index of the save-command in the command-string "b" """ if (i+1) < len(b): #make sure that second argument is filename and not a command if b[i+1] not in ("quit", "q", "exit", "e", "refresh", "r"): if ".sav" not in b[i+1]: file = b[i+1] + ".sav" b[i+1] = "filename" #prevent double-use else: file = b[i+1] b[i+1] = "filename" #prevent double-use else: file = "default.sav" else: file = "default.sav" try: filehandler = open(file,"wb") print("\n----------------------------------------") print("\n Bord gespeichert unter", file,"\n") print("----------------------------------------\n") except IOError: print("\n-----------------------------------------------") print("\n Datei", file,"kann nicht angelegt werden! \n") print("-----------------------------------------------\n") return 0 pickle.dump(sd, filehandler) filehandler.close() def load_from_file(self, i, b): """loads the gameboard from a binary file. In case the user submits no name the file name is default.sav. If the user provides a name, the routine is looking for a file in name.sav. "i" is the index of the save-command in the command-string "b" """ if (i+1) < len(b): #make sure that second argument is filename and not a command if b[i+1] not in ("quit", "q", "exit", "e", "refresh", "r"): if ".sav" not in b[i+1]: file = b[i+1] + ".sav" b[i+1] = "filename" #prevent double-use else: file = b[i+1] b[i+1] = "filename" #prevent double-use else: file ="default.sav" else: file ="default.sav" sd = {} try: filehandler = open(file, "rb") print("\n----------------------------------------") print("\n Spielfeld geladen aus", file,"\n") print("----------------------------------------\n") except IOError: print("\n---------------------------------------------------") print("\n Datei", file,"kann nicht geöffnet werden!\n") print("---------------------------------------------------\n") return 0 sd = pickle.load(filehandler) filehandler.close() return sd def add(self, gameboard, command): """ adds one number or several numbers to the gameboard. Format is "a(dd) YXValue" or "a(dd) X1Y1Value1 X2Y2Value2 ..." >>> sd = {} >>> for row in ["a", "b", "c", "d", "e", "f", "g", "h", "i"]: ... for col in range(1,10): ... sd[(row,col)] = " " >>> t.ignoreit = True #if False doctest hangs endless at getchar() >>> t.add(sd,['a51']) 'done' >>> t.add(sd,['aaa']) <BLANKLINE> ------------------------------------------ <BLANKLINE> Reihe (1 - 9) bitte benennen! <BLANKLINE> ------------------------------------------ <BLANKLINE> 0 >>> t.add(sd,['111']) <BLANKLINE> ------------------------------------------ <BLANKLINE> Spalte (A - I) bitte benennen! <BLANKLINE> ------------------------------------------ <BLANKLINE> 0 >>> t.add(sd,['b10']) <BLANKLINE> ------------------------------------------ <BLANKLINE> Zahl muss zwischen 1 und 9 liegen! <BLANKLINE> ------------------------------------------ <BLANKLINE> 0 >>> t.add(sd,['11']) <BLANKLINE> ----------------------------------------------------------- <BLANKLINE> Bitte nach add DREI Zeichen angeben: SpalteZeileWert <BLANKLINE> ----------------------------------------------------------- <BLANKLINE> 0 """ for x in command: if len(x) == 3: #error check if x[0] not in ("a b c d e f g h i"): print("\n------------------------------------------") print("\n Spalte (A - I) bitte benennen! \n") print("------------------------------------------\n") if self.ignoreit == False: getch() return 0 elif x[1] not in ("1 2 3 4 5 6 7 8 9"): print("\n------------------------------------------") print("\n Reihe (1 - 9) bitte benennen! \n") print("------------------------------------------\n") if self.ignoreit == False: getch() return 0 elif x[2] not in ("1 2 3 4 5 6 7 8 9"): print("\n------------------------------------------") print("\n Zahl muss zwischen 1 und 9 liegen! \n") print("------------------------------------------\n") if self.ignoreit == False: getch() return 0 else: if gameboard[x[0],int(x[1])] == " ": legal = self.board.check_rules(gameboard,x[0],x[1],str(x[2])) if legal: gameboard[x[0],int(x[1])] = x[2] else: return 0 else: print("\n------------------------------------------") print("\n Zahl schon gesetzt! Change benutzen! \n") print("------------------------------------------\n") if self.ignoreit == False: getch() return 0 else: print("\n-----------------------------------------------------------") print("\n Bitte nach add DREI Zeichen angeben: ZeileSpalteWert \n") print("-----------------------------------------------------------\n") if self.ignoreit == False: getch() return 0 if self.ignoreit == False: return gameboard else: return "done" #special flag for doctest to avaid return full gameboard def delete(self, gameboard, command): """ deletes a number from the gameboard. Format is "d(elete) YX" >>> sd = {} >>> for row in ["a", "b", "c", "d", "e", "f", "g", "h", "i"]: ... for col in range(1,10): ... sd[(row,col)] = " " >>> t.ignoreit = True #if False doctest hangs endless at getchar() >>> t.delete(sd,['aa']) <BLANKLINE> ------------------------------------------ <BLANKLINE> Reihe (1 - 9) bitte benennen! <BLANKLINE> ------------------------------------------ <BLANKLINE> 0 >>> t.delete(sd,['11']) <BLANKLINE> ------------------------------------------ <BLANKLINE> Spalte (A - I) bitte benennen! <BLANKLINE> ------------------------------------------ <BLANKLINE> 0 >>> t.delete(sd,['111']) <BLANKLINE> ------------------------------------------ <BLANKLINE> Bitte nach delete ZWEI Zeichen angeben! <BLANKLINE> ------------------------------------------ <BLANKLINE> 0 >>> t.delete(sd,['a1']) <BLANKLINE> ------------------------------------------ <BLANKLINE> Das Feld ist schon leer! <BLANKLINE> ------------------------------------------ <BLANKLINE> 0 >>> t.add(sd,['a51']) 'done' >>> t.delete(sd,['a5']) 'done' """ for x in command: if len(x) == 2: #error check if x[0] not in ("a b c d e f g h i"): print("\n------------------------------------------") print("\n Spalte (A - I) bitte benennen! \n") print("------------------------------------------\n") if self.ignoreit == False: getch() return 0 elif x[1] not in ("1 2 3 4 5 6 7 8 9"): print("\n------------------------------------------") print("\n Reihe (1 - 9) bitte benennen! \n") print("------------------------------------------\n") if self.ignoreit == False: getch() return 0 elif gameboard[x[0],int(x[1])] != " ": gameboard[x[0],int(x[1])] = " " else: print("\n------------------------------------------") print("\n Das Feld ist schon leer! \n") print("------------------------------------------\n") if self.ignoreit == False: getch() return 0 else: print("\n------------------------------------------") print("\n Bitte nach delete ZWEI Zeichen angeben! \n") print("------------------------------------------\n") if self.ignoreit == False: getch() return 0 if self.ignoreit == False: return gameboard else: return "done" def change(self, gameboard, command): """ adds one number or several numbers to the gameboard. Format is "a(dd) YXValue" or "a(dd) X1Y1Value1 X2Y2Value2 ..." >>> sd = {} >>> for row in ["a", "b", "c", "d", "e", "f", "g", "h", "i"]: ... for col in range(1,10): ... sd[(row,col)] = " " >>> t.ignoreit = True #if False doctest hangs endless at getchar() >>> t.change(sd,['aaa']) <BLANKLINE> ------------------------------------------ <BLANKLINE> Reihe (1 - 9) bitte benennen! <BLANKLINE> ------------------------------------------ <BLANKLINE> 0 >>> t.change(sd,['111']) <BLANKLINE> ------------------------------------------ <BLANKLINE> Spalte (A - I) bitte benennen! <BLANKLINE> ------------------------------------------ <BLANKLINE> 0 >>> t.change(sd,['b10']) <BLANKLINE> ------------------------------------------ <BLANKLINE> Zahl muss zwischen 1 und 9 liegen! <BLANKLINE> ------------------------------------------ <BLANKLINE> 0 >>> t.change(sd,['11']) <BLANKLINE> ------------------------------------------ <BLANKLINE> Bitte nach change DREI Zeichen angeben! <BLANKLINE> ------------------------------------------ <BLANKLINE> 0 >>> t.change(sd,['b15']) <BLANKLINE> ------------------------------------------ <BLANKLINE> Kann nur belegte Felder ändern! <BLANKLINE> ------------------------------------------ <BLANKLINE> 0 >>> t.add(sd,['a21']) 'done' >>> t.change(sd,['a23']) 'done' """ for x in command: if len(x) == 3: #error check if x[0] not in ("a b c d e f g h i"): print("\n------------------------------------------") print("\n Spalte (A - I) bitte benennen! \n") print("------------------------------------------\n") if self.ignoreit == False: getch() return 0 elif x[1] not in ("1 2 3 4 5 6 7 8 9"): print("\n------------------------------------------") print("\n Reihe (1 - 9) bitte benennen! \n") print("------------------------------------------\n") if self.ignoreit == False: getch() return 0 elif x[2] not in ("1 2 3 4 5 6 7 8 9"): print("\n------------------------------------------") print("\n Zahl muss zwischen 1 und 9 liegen! \n") print("------------------------------------------\n") if self.ignoreit == False: getch() return 0 elif gameboard[x[0],int(x[1])] != " ": legal = self.board.check_rules(gameboard,x[0],x[1],str(x[2])) if legal: self.gameboard = self.delete(gameboard, [x[:-1]]) self.gameboard = self.add(gameboard, [x]) else: return 0 else: print("\n------------------------------------------") print("\n Kann nur belegte Felder ändern! \n") print("------------------------------------------\n") if self.ignoreit == False: getch() return 0 else: print("\n------------------------------------------") print("\n Bitte nach change DREI Zeichen angeben! \n") print("------------------------------------------\n") if self.ignoreit == False: getch() return 0 if self.ignoreit == False: return gameboard else: return "done"
class Game(object): """Game ties everything together. It has a board, two controllers, and can draw to the screen.""" def __init__(self, timeout=1000, display_moves=True, players=['ai', 'ai'], colour=False): self.board = Board(colour) self.timeout = timeout self.ai_counter = 0 self.list_of_colours = [BLACK, WHITE] self.players = players self.display_moves = display_moves self.controllers = deque([self._make_controller(c, p) for c, p in zip(self.list_of_colours, self.players)]) self.player = self.controllers[0].get_colour() self.board.set_black(4, 3) self.board.set_black(3, 4) self.board.set_white(4, 4) self.board.set_white(3, 3) self.board.mark_moves(self.player) self.previous_move = None def _make_controller(self, colour, controller_type): """ Returns a controller with the specified colour. 'player' == PlayerController, 'ai' == AiController. """ if controller_type == 'player': return PlayerController(colour) else: self.ai_counter += 1 return AiController(self.ai_counter, colour, self.timeout) def show_info(self): """ Prints game information to stdout. """ print("Playing as: " + self.player) print("Displaying moves: " + str(self.display_moves)) print("Current turn: " + str(self.controllers[0])) print("Number of Black: " + str( len([p for p in self.board.pieces if p.get_state() == BLACK]))) print("Number of White: " + str( len([p for p in self.board.pieces if p.get_state() == WHITE]))) def show_board(self): """ Prints the current state of the board to stdout. """ self.player = self.controllers[0].get_colour() self.board.mark_moves(self.player) print(self.board.draw()) def show_commands(self): """ Prints the possible moves to stdout. """ moves = [self.to_board_coordinates(piece.get_position()) for piece in self.board.get_move_pieces(self.player)] if not moves: raise NoMovesError print("Possible moves are: ", moves) self.board.clear_moves() def run(self): """ The game loop will print game information, the board, the possible moves, and then wait for the current player to make its decision before it processes it and then goes on repeating itself. """ while True: os.system('clear') self.show_info() self.show_board() try: self.show_commands() next_move = self.controllers[0].next_move(self.board) self.board.make_move(next_move, self.controllers[0].get_colour()) except NoMovesError: print("Game Over") blacks = len([p for p in self.board.pieces if p.get_state() == BLACK]) whites = len([p for p in self.board.pieces if p.get_state() == WHITE]) if blacks > whites: print("Black won this game.") exit() elif blacks == whites: print("This game was a tie.") exit() else: print("White won this game.") exit() self.controllers.rotate() print("Current move is: ", self.to_board_coordinates(next_move)) self.previous_move = next_move def to_board_coordinates(self, coordinate): """ Transforms an (x, y) tuple into (a-h, 1-8) tuple. """ x, y = coordinate return '{0}{1}'.format(chr(ord('a') + x), y + 1)
class Reversi: """This class enforces the rules of the game of Reversi.""" def __init__(self, **kwargs): self.size = kwargs.get('size', 8) self.board = Board(self.size) WhiteAgent = kwargs.get('WhiteAgent', RandomAgent) BlackAgent = kwargs.get('BlackAgent', RandomAgent) self.white_agent = WhiteAgent(self, WHITE, **kwargs) self.black_agent = BlackAgent(self, BLACK, **kwargs) make_silent(kwargs.get('silent', False)) self.reset() def reset(self): """Reset the game to initial positions.""" self.board.init_starting_position() self.game_state = (self.board, BLACK) self.legal_cache = CacheDict() self.white_agent.reset() self.black_agent.reset() def play_game(self): state = self.get_state() self.print_board(state) info_newline() while self.winner(state) is False: color = state[1] picked = self.agent_pick_move(state) state = self.next_state(state, picked) self.print_board(state) if not picked: info('{} had no moves and passed their turn.'.format( color_name[color])) else: info('{} plays at {}'.format(color_name[color], str(picked))) info_newline() self.white_agent.observe_win(state) self.black_agent.observe_win(state) self.print_board(state) # figure out who won black_count, white_count = state[0].get_stone_counts() winner = BLACK if black_count > white_count else WHITE info('{} wins.'.format(color_name[winner])) self.reset() return winner, white_count, black_count @staticmethod def print_board(state): board = state[0] info(board) def agent_pick_move(self, state): color = state[1] legal_moves = self.legal_moves(state) picked = None if color == WHITE: picked = self.white_agent.get_action(state, legal_moves) elif color == BLACK: picked = self.black_agent.get_action(state, legal_moves) else: raise ValueError if picked is None: return None elif picked not in legal_moves: info(str(picked) + ' is not a legal move! Game over.') quit() return picked def legal_moves(self, game_state, force_cache=False): # Note: this is a very naive and inefficient way to find # all available moves by brute force. I am sure there is a # more clever way to do this. If you want better performance # from agents, this would probably be the first area to improve. if force_cache: return self.legal_cache.get(game_state) board = game_state[0] if board.is_full(): return [] cached = self.legal_cache.get(game_state) if cached is not None: return cached board_size = board.get_size() moves = [] # list of x,y positions valid for color for y in range(board_size): for x in range(board_size): if self.is_valid_move(game_state, x, y): moves.append((x, y)) self.legal_cache.update(game_state, moves) return moves @staticmethod def is_valid_move(game_state, x, y): board, color = game_state piece = board.board[y][x] if piece != EMPTY: return False enemy = opponent[color] # now check in all directions, including diagonal for dy in range(-1, 2): for dx in range(-1, 2): if dy == 0 and dx == 0: continue # there needs to be >= 1 opponent piece # in this given direction, followed by 1 of player's piece distance = 1 yp = (distance * dy) + y xp = (distance * dx) + x while is_in_bounds(xp, yp, board.size) and board.board[yp][xp] == enemy: distance += 1 yp = (distance * dy) + y xp = (distance * dx) + x if distance > 1 and is_in_bounds(xp, yp, board.size) and board.board[yp][xp] == color: return True return False def next_state(self, game_state, move): """Given a game_state and a position for a new piece, return a new game_state reflecting the change. Does not modify the input game_state.""" return self.apply_move(deepcopy(game_state), move) @staticmethod def apply_move(game_state, move): """Given a game_state (which includes info about whose turn it is) and an x,y position to place a piece, transform it into the game_state that follows this play.""" # if move is None, then the player simply passed their turn if not move: game_state = (game_state[0], opponent[game_state[1]]) return game_state x, y = move color = game_state[1] board = game_state[0] board.place_stone_at(color, x, y) # now flip all the stones in every direction enemy_color = BLACK if color == BLACK: enemy_color = WHITE # now check in all directions, including diagonal to_flip = [] for dy in range(-1, 2): for dx in range(-1, 2): if dy == 0 and dx == 0: continue # there needs to be >= 1 opponent piece # in this given direction, followed by 1 of player's piece distance = 1 yp = (distance * dy) + y xp = (distance * dx) + x flip_candidates = [] while is_in_bounds(xp, yp, board.size) and board.board[yp][xp] == enemy_color: flip_candidates.append((xp, yp)) distance += 1 yp = (distance * dy) + y xp = (distance * dx) + x if distance > 1 and is_in_bounds(xp, yp, board.size) and board.board[yp][xp] == color: to_flip.extend(flip_candidates) for each in to_flip: board.flip_stone(each[0], each[1]) # board.place_stone_at(color, each[0], each[1]) game_state = (game_state[0], opponent[game_state[1]]) return game_state def winner(self, game_state): """Given a game_state, return the color of the winner if there is one, otherwise return False to indicate the game isn't won yet. Note that legal_moves() is a slow operation, so this method tries to call it as few times as possible.""" board = game_state[0] black_count, white_count = board.get_stone_counts() # a full board means no more moves can be made, game over. if board.is_full(): if black_count > white_count: return BLACK else: # tie goes to white return WHITE # a non-full board can still be game-over if neither player can move. black_legal = self.legal_moves((game_state[0], BLACK)) if black_legal: return False white_legal = self.legal_moves((game_state[0], WHITE)) if white_legal: return False # neither black nor white has valid moves if black_count > white_count: return BLACK else: # tie goes to white return WHITE def get_board(self): """Return the board from the current game_state.""" return self.game_state[0] def get_state(self): """Returns a tuple representing the board state.""" return self.game_state
def __init__(self, ai_player: int = 1) -> None: self._board = Board(ai_player) self._turn = 0 self._ai_player = ai_player
def __init__(self): self.game_board = Board() self.whos_turn_is_it = 'black' self.game_over = None
def testAi(self): b = Board(False) b.set_white(4, 0) b.set_white(5, 0) b.set_white(6, 0) b.set_white(7, 0) b.set_white(3, 4) b.set_white(4, 4) b.set_white(4, 3) b.set_white(5, 3) b.set_white(5, 1) b.set_white(6, 1) b.set_black(1, 5) b.set_black(2, 0) b.set_black(2, 3) b.set_black(2, 4) b.set_black(3, 1) b.set_black(3, 2) b.set_black(3, 3) b.set_black(4, 1) b.set_black(4, 2) b.set_black(5, 2) b.set_black(6, 2) b.set_black(7, 1) b.set_black(7, 2) print(b.draw()) ai = AiController(0, WHITE) move = ai.next_move(b) #self.assertEqual(, ) self.assertIn(move, [p.get_position() for p in b.get_move_pieces(WHITE)])
def __init__(self, players): self.players = self.init_players(players) self.board = Board() self.players_order = self.order_players(self.players) self.current_player_turn = 0 self.board.boxes[0].players = list(players.keys())
def test_can_smash(self): self.assertFalse(Board.can_smash_up([0, 0, 0, 0])) self.assertFalse(Board.can_smash_up([1, 0, 0, 0])) self.assertFalse(Board.can_smash_up([1, 2, 0, 0])) self.assertTrue(Board.can_smash_up([1, 1, 0, 0])) self.assertTrue(Board.can_smash_up([0, 1, 0, 0]))
def __init__(self): self.board = Board() self.gameboard = self.board.return_board() self.command = Commands()
class TestBoard(unittest.TestCase): def setUp(self): # A board that's easy to read for debugging purposes but does # not have real tiles and so will fail smash/encode operations. self.readable_board = Board( [["00", "01", "02", "03"], ["10", "11", "12", "13"], ["20", "21", "22", "23"], ["30", "31", "32", "33"]]) # A board that occurred in real play. self.realistic_board = Board( [[ 2, 128, 8, 8], [ 8, 8, 16, 0], [ 4, 32, 4, 0], [ 2, 4, 0, 0]]) def test_smoke(self): board = Board() self.assertIsNotNone(board) def test_get(self): self.assertEqual(self.readable_board[1, 0], "10") self.assertEqual(self.readable_board[0, 2], "02") self.assertEqual(self.readable_board[3, 3], "33") def test_column(self): self.assertEqual(list(self.readable_board.column(0)), ["00", "01", "02", "03"]) def test_row(self): self.assertEqual(list(self.readable_board.row(0)), ["00", "10", "20", "30"]) def test_columns(self): self.assertEqual(list(self.readable_board.columns()), [list(self.readable_board.column(i)) for i in range(WIDTH)]) def test_rows(self): self.assertEqual(list(self.readable_board.rows()), [list(self.readable_board.row(i)) for i in range(WIDTH)]) def test_copy_and_update(self): original = self.readable_board copy = original.copy() self.assertIs(original, self.readable_board) self.assertIsNot(original, copy) self.assertEqual(original, copy) changed = copy.update([1, 2], "Wibble!") self.assertIsNot(changed, copy) self.assertNotEqual(changed, copy) self.assertEqual(changed[1, 2], "Wibble!") def test_rotate_cw(self): rotated = self.readable_board.rotate_cw() self.assertEqual(self.readable_board[0, 1], rotated[2, 0]) def test_rotate_ccw(self): rotated = self.readable_board.rotate_ccw() self.assertEqual(self.readable_board[0, 1], rotated[1, 3]) def test_rotate_against_rotate(self): self.assertEqual(self.readable_board, self.readable_board.rotate_ccw(). rotate_ccw().rotate_ccw().rotate_ccw()) self.assertEqual(self.readable_board.rotate_cw(), self.readable_board.rotate_ccw(). rotate_ccw().rotate_ccw()) self.assertEqual(self.readable_board.rotate_cw().rotate_cw(), self.readable_board.rotate_ccw().rotate_ccw()) self.assertEqual(self.readable_board.rotate_cw().rotate_cw(). rotate_cw(), self.readable_board.rotate_ccw()) self.assertEqual(self.readable_board.rotate_cw().rotate_cw(). rotate_cw().rotate_cw(), self.readable_board) def test_can_smash(self): self.assertFalse(Board.can_smash_up([0, 0, 0, 0])) self.assertFalse(Board.can_smash_up([1, 0, 0, 0])) self.assertFalse(Board.can_smash_up([1, 2, 0, 0])) self.assertTrue(Board.can_smash_up([1, 1, 0, 0])) self.assertTrue(Board.can_smash_up([0, 1, 0, 0])) def test_smash_col(self): self.assertEqual(Board.smash_col_up([0, 0, 0, 0]), (False, 0, [0, 0, 0, 0])) self.assertEqual(Board.smash_col_up([1, 0, 0, 0]), (False, 0, [1, 0, 0, 0])) self.assertEqual(Board.smash_col_up([1, 2, 0, 0]), (False, 0, [1, 2, 0, 0])) self.assertEqual(Board.smash_col_up([1, 1, 0, 0]), (True, 2, [2, 0, 0, 0])) self.assertEqual(Board.smash_col_up([0, 1, 0, 0]), (True, 0, [1, 0, 0, 0])) def test_smash_and_can_move(self): # Empty board does not move. board = Board() self.assertFalse(board.can_move()) changed, score, smashed = board.smash_up() self.assertFalse(changed) self.assertEqual(score, 0) self.assertEqual(smashed, Board()) self.assertIsNot(smashed, board) # Board with a floating tile slides that tile. board = board.update([1, 2], 1) self.assertTrue(board.can_move()) changed, score, smashed = board.smash_up() self.assertTrue(changed) self.assertEqual(score, 0) self.assertNotEqual(smashed, board) self.assertEqual(smashed, Board().update([1, 0], 1)) # Board with aligned tiles smashes those tiles. board = board.update([1, 0], 1) self.assertTrue(board.can_move()) changed, score, smashed = board.smash_up() self.assertTrue(changed) self.assertEqual(score, 2) self.assertNotEqual(smashed, board) self.assertEqual(smashed, Board().update([1, 0], 2)) # Locked board does not move. board = Board([[1, 2, 1, 2], [2, 1, 2, 1], [1, 2, 1, 2], [2, 1, 2, 1]]) self.assertFalse(board.can_move()) changed, score, smashed = board.smash_up() self.assertFalse(changed) self.assertEqual(score, 0) self.assertEqual(smashed, board) self.assertIsNot(smashed, board) def test_encoding(self): board = self.realistic_board encoding = board.as_vector() self.assertEqual(encoding.size, Board.vector_width()) decoding = Board.from_vector(encoding) self.assertEqual(board, decoding)
def get_next_move(self, board: Board) -> Coordinate: # ______________________________ # Get previously experienced board position possible_moves = [] try: current_state = board.get_board() possible_moves = self._matrix[current_state] except: try: current_state = board.get_negative_board() possible_moves = self._matrix[current_state] except: pass # ______________________________ # Get previously experienced board positions by rotating must_rotate = False if len(possible_moves) == 0: must_rotate = True else: for i in range(len(possible_moves)): if possible_moves[i].value > 0: must_rotate = False break if must_rotate: possible_moves.extend( self._get_rotated_possible_moves(board.get_board())) possible_moves.extend( self._get_rotated_possible_moves(board.get_negative_board())) # ______________________________ # Get best moves if len(possible_moves) == 0: return None best_value = 1 best_coordinates = [] for i in range(len(possible_moves)): if possible_moves[i].value > best_value: best_value = possible_moves[i].value best_coordinates.clear() best_coordinates.append(possible_moves[i].coordinate) elif possible_moves[i].value == best_value: best_coordinates.append(possible_moves[i].coordinate) # ______________________________ # Return random best move if len(best_coordinates) == 0: return None elif len(best_coordinates) == 1: return best_coordinates[0] else: ret_index = random.randint(0, len(best_coordinates) - 1) return best_coordinates[ret_index]
def test_encoding(self): board = self.realistic_board encoding = board.as_vector() self.assertEqual(encoding.size, Board.vector_width()) decoding = Board.from_vector(encoding) self.assertEqual(board, decoding)
class Game(): def __init__(self, ai_player: int = 1) -> None: self._board = Board(ai_player) self._turn = 0 self._ai_player = ai_player def play(self) -> None: while not self._board.victory(): print(self._board) print(" Last play: {}{}".format(*self._board.last_play)) if (self._turn % 2) + 1 == self._ai_player: self._board, _ = \ ab_pruning(self._board, 2, -2**32, 2**32, True) else: pos = self._player_input() self._board.place_stone(pos) self._turn += 1 print(self._board) def play_ia_vs_ia(self) -> None: while not self._board.victory(): print(self._board) print(" Last play: {}{}".format(*self._board.last_play)) if (self._turn % 2) + 1 == self._ai_player: self._board, _ = \ ab_pruning(self._board, 2, -2**32, 2**32, True) else: self._board, _ = \ ab_pruning(self._board, 2, -2**32, 2**32, False) self._turn += 1 print(self._board) def _player_input(self) -> Tuple[int, int]: """ Input loop for the game. Matches valid coordinates on the board. Returns: A tuple with the (x, y) coordinates Code snippet removed from github.com/zambonin/multivac """ while True: raw = input(" Place {} on which coordinate? ".format( Board.stones[self._turn % 2 + 1])) raw = raw.upper() if raw else 'error' if re.match(r'Q(UIT)?', raw): raise SystemExit if raw[-1] in map(chr, range(65, 80)): # invert raw input if letter was typed after number raw = raw[len(raw) - 1:] + raw[:len(raw) - 1] if not re.match(r'[A-O](0?[1-9]|1[0-5])\Z', raw): continue pos = (ord(raw[:1]) - 65, int(raw[1:]) - 1) if len(pos) != 2 or not self._board.is_empty(pos): continue break return pos
class Simulation: ''' Handle IO logic for simulation. Simulation objects function as iterable finite state machines. ''' # State variables INIT = 0 PROMPT_TEAM = 1 PLAYER_MOVE = 2 CPU_MOVE = 3 PROMPT_RESTART = 4 FINISHED = 5 @staticmethod def get_input(prompt, restrictions): ''' Get input from user while applying given constraints Parameters prompt: str, message to guide user restrictions: str[], list of valid input options Return str, input from user ''' # keep requesting until valid input received while True: result = input(prompt) if result in restrictions: return result else: print(static.UTIL['input_error']) def __init__(self): ''' Initialize fieleds. ''' self._solver = Solver() self._board = Board() self._state = Simulation.INIT def __iter__(self): ''' Mark Simulation objects as iterable Return Simulation, this object ''' return self def __next__(self): ''' Continue simulation until next piece of output is available Return str, output from game since last call to next() ''' if self._state == Simulation.INIT: return self._state_init() elif self._state == Simulation.PROMPT_TEAM: return self._state_prompt_team() elif self._state == Simulation.CPU_MOVE: return self._state_cpu_move() elif self._state == Simulation.PLAYER_MOVE: return self._state_player_move() elif self._state == Simulation.PROMPT_RESTART: return self._state_prompt_restart() else: # self._state == Simulation.FINISHED raise StopIteration def _state_init(self): ''' Update state to PROMPT_TEAM Return str, rules for simulation ''' self._state = Simulation.PROMPT_TEAM return '\n%s\n' % static.INFO['man'] def _state_prompt_team(self): ''' Determine teams and update state to either CPU_MOVE or PLAYER_MOVE Return str, board representation ''' # ask user is they would like to go first choice = Simulation.get_input( static.UTIL['team_prompt'], static.BINARY) if choice in static.YES: self._state = Simulation.PLAYER_MOVE else: self._state = Simulation.CPU_MOVE return str(self._board) def _state_cpu_move(self): ''' Make cpu move and update state to either PROMPT_RESTART or PLAYER_MOVE Return str, board representation and optional end of game message ''' move = self._solver.get_next_move(self._board) turn = str(self._board.turn()) self._board = self._board.move(move) # result is cpu move and string representation of board result = ['%s >>> %d' % (turn, move), str(self._board)] # if game is over, append game over message if self._board.game_over(): result.append(static.UTIL['lose_game'] if self._board.winner() else static.UTIL['tie_game']) self._state = Simulation.PROMPT_RESTART else: self._state = Simulation.PLAYER_MOVE return '\n'.join(result) def _state_player_move(self): ''' Request player move and update state to either PROMPT_RESTART or PLAYER_MOVE Return str, board representation and optional end of game message ''' # commands include available spaces, an action, or a help command options = [str(x) for x in self._board.get(Team.NEITHER)] + \ static.ACTIONS + list(static.INFO.keys()) prompt = '%s >>> ' % str(self._board.turn()) command = Simulation.get_input(prompt, options) if command in static.INFO: # print help message return static.INFO[command] elif command == 'undo': if self._board.turn() in self._board: # check that player has a move that can be undone # undo twice to undo cpu's move as well self._board = self._board.undo().undo() return str(self._board) else: return static.UTIL['undo_error'] elif command == 'print': return str(self._board) elif command == 'quit': self._state = Simulation.PROMPT_RESTART return '' # return empty line to print else: # integer coordinate self._board = self._board.move(int(command)) result = [str(self._board)] # if game is over, append game over message if self._board.game_over(): result.append(static.UTIL['tie_game']) self._state = Simulation.PROMPT_RESTART else: self._state = Simulation.CPU_MOVE return '\n'.join(result) def _state_prompt_restart(self): ''' Determine whether to re-run simulation and update state to either PROMPT_TEAM of FINISHED Return str, board representation ''' # ask whether player wants to play again choice = Simulation.get_input( static.UTIL['retry_prompt'], static.BINARY) if choice in static.YES: self._board = Board() self._state = Simulation.PROMPT_TEAM else: self._state = Simulation.FINISHED return '' # return empty line to print def board(self): ''' Return Board, current board for this simulation ''' return self._board def state(self): ''' Return int, current Simulation state constant for this simulation ''' return self._state
def test_init(self): b = Board(False) self.assertEqual(len(b.get_move_pieces(WHITE)), 0) self.assertEqual(len(b.get_move_pieces(BLACK)), 0)
class Game(object): def __init__(self, window, player_color, theme): self.window = window self.theme = theme self.move_history = MoveHistory() self.human = Human(player_color, self) self.turn = "White" # Game Over Conditions self.checkmate_win = False self.stalemate_draw = False self.threefold_draw = False self.no_captures_50 = False self.insufficient_material_draw = False self.resign = False if player_color == "White": self.board = Board("White") self.computer = Computer("Black") else: self.board = Board("Black") self.computer = Computer("White") def game_over(self): if self.checkmate_win or self.stalemate_draw or self.threefold_draw or \ self.no_captures_50 or self.insufficient_material_draw or self.resign: return True return False def update_screen(self, valid_moves, board): # Draw Board self.board.create_board(self.window, themes[self.theme]) # Draw Previous Move self.board.draw_previous_move(self.window) # Draw all valid moves for selected piece if self.board.show_valid_moves: self.board.draw_valid_moves(valid_moves, self.window) # Draw change theme buttons self.board.draw_theme_window(self.window) # Draw Game Buttons self.board.draw_game_buttons(self.window, themes[self.theme]) # Draw Move Log self.move_history.draw_move_log(self.window) # Draw captured and advantages self.board.material.draw_captured(self.window, self.human.color) self.board.material.draw_advantages(self.window, self.human.color) # Draw the chess pieces self.board.draw(self.window, board) # Draw Promotion Menu if self.human.promoting: self.board.promotion_menu(self.human.color, self.window) # Update the screen pygame.display.update() def update_game(self): self.board.material.update_advantages(self.board) self.change_turn() self.update_all_valid_moves() def check_game_status(self): if self.king_checked(): self.checkmate() self.stalemate() self.threefold_repetition() self.insufficient_material() self.no_captures_in_50() def update_all_valid_moves(self): for row in self.board.board: for piece in row: if isinstance(piece, (Knight, Bishop, Rook, Queen, King)): piece.update_valid_moves(self.board.board) elif isinstance(piece, Pawn): piece.update_valid_moves(self.board.board, self.move_history.move_log) def get_dangerous_squares(self): dangerous_squares = [] for row in self.board.board: for piece in row: if isinstance(piece, (Pawn, Knight, Bishop, Rook, Queen, King)): if piece.color != self.turn: for move in piece.valid_moves: dangerous_squares.append(move) return dangerous_squares def king_checked(self): self.update_all_valid_moves() king = None dangerous_squares = self.get_dangerous_squares() king_pos = (None, None) for row in self.board.board: for piece in row: if isinstance(piece, King): if piece.color == self.turn: king = piece king_pos = (piece.row, piece.col) break if king_pos in dangerous_squares: king.is_checked = True return True king.is_checked = False return False def checkmate(self): for row in self.board.board: for piece in row: # Get all pieces that are the same color as the king in check if isinstance(piece, (Pawn, Knight, Bishop, Rook, Queen, King)): if piece.color == self.turn: prev_row = piece.row prev_col = piece.col # Try all the moves available for each piece to see if they can escape check for move in piece.valid_moves: target = self.board.board[move[0]][move[1]] # If capturing an enemy piece if isinstance( target, (Pawn, Knight, Bishop, Rook, Queen, King)): if target.color != self.turn: self.board.board[move[0]][move[1]] = 0 self.board.move(piece, move[0], move[1]) # If king is still checked, undo move and go next if self.king_checked(): self.board.move( piece, prev_row, prev_col) self.board.board[move[0]][ move[1]] = target # If king is no longer checked, then there is no checkmate yet else: self.board.move( piece, prev_row, prev_col) self.board.board[move[0]][ move[1]] = target return False # If moving to an empty square else: self.board.move(piece, move[0], move[1]) # If king is still checked, undo move and go next if self.king_checked(): self.board.move(piece, prev_row, prev_col) # If king is no longer checked, then there is no checkmate yet else: self.board.move(piece, prev_row, prev_col) return False self.update_screen(self.human.valid_moves, self.board) self.checkmate_win = True def threefold_repetition(self): unique_moves = set() if len(self.move_history.move_log) > 9: for i in range(-1, -10, -1): move = self.move_history.move_log[i] unique_moves.add(move) if len(unique_moves) == 4: self.update_screen(self.human.valid_moves, self.board) self.threefold_draw = True def stalemate(self): all_valid_moves = [] dangerous_squares = self.get_dangerous_squares() for row in self.board.board: for piece in row: # Get all pieces that are the same color as the current player's team if isinstance(piece, (Pawn, Knight, Bishop, Rook, Queen, King)): if piece.color == self.turn: # Go through all possible moves to see if any are legal if isinstance(piece, King): for move in piece.valid_moves: if move not in dangerous_squares: all_valid_moves.append(move) else: for move in piece.valid_moves: all_valid_moves.append(move) # If there was a legal move, there is no stalemate yet if len(all_valid_moves) > 0: return False # If there were no legal moves for the current player, its a stalemate if len(all_valid_moves) == 0: self.update_screen(self.human.valid_moves, self.board) self.stalemate_draw = True def no_captures_in_50(self): if len(self.move_history.move_log) > 50: moves = self.move_history.move_log[-50:] captures = [move for move in moves if "x" in move] if len(captures) == 0: self.no_captures_50 = True def insufficient_material(self): white_pieces = {"Knights": 0, "Bishops": 0} black_pieces = {"Knights": 0, "Bishops": 0} for row in self.board.board: for piece in row: # If there is a pawn, rook, or queen on the board, the game is still winnable if isinstance(piece, (Pawn, Rook, Queen)): return False # Count number of knights on board elif isinstance(piece, Knight): if piece.color == "White": white_pieces["Knights"] += 1 else: black_pieces["Knights"] += 1 # Count number of bishops on board elif isinstance(piece, Bishop): if piece.color == "Black": black_pieces["Bishops"] += 1 else: white_pieces["Bishops"] += 1 white_material_remaining = white_pieces["Knights"] + white_pieces[ "Bishops"] black_material_remaining = black_pieces["Knights"] + black_pieces[ "Bishops"] # In the best case, there is a King + Knight or King + Bishop for either side (still a draw). if white_material_remaining * 3 <= 3 and black_material_remaining * 3 <= 3: self.update_screen(self.human.valid_moves, self.board) self.insufficient_material_draw = True def move_creates_check(self, move): self.change_turn() if self.king_checked(): move += "+" self.change_turn() return move def change_turn(self): self.human.valid_moves = [] if self.turn == "White": self.turn = "Black" else: self.turn = "White" def capture(self, piece): if piece.color == "Black": self.board.material.add_to_captured_pieces( piece, self.board.material.captured_black_pieces) if piece.color == "White": self.board.material.add_to_captured_pieces( piece, self.board.material.captured_white_pieces) def castle(self, king, rook, row, col, dangerous_squares, board): # Save a temp variable for rook column rook_col = rook.col # Long Castle if row == 0: if ((row + 1, col) and (row + 2, col) and (row + 3, col)) not in dangerous_squares: board.move(rook, 3, king.col) board.move(king, 2, rook_col) board.move_notation = "O-O-O" else: return False # Short Castle elif row == 7: if (row - 1, col) and (row - 2, col) not in dangerous_squares: board.move(rook, 5, king.col) board.move(king, 6, rook_col) board.move_notation = "O-O" else: return False king.can_castle = False return True def detect_promotion(self, piece): # If a pawn reaches the other side of the board (any promotion square, let player choose how to promote) if isinstance(piece, Pawn): if (piece.color == "White" and piece.col == 0) or (piece.color == "Black" and piece.col == 7): return True return False
def setUp(self) -> None: self.board = Board(self.input_board)
def test_get_chained_push_movements(self): board = Board() board.get_tile(0, 3).place_piece(Piece(PLAYER_1_ID, PieceType.four)) board.get_tile(1, 3).place_piece(Piece(PLAYER_1_ID, PieceType.two)) board.get_tile(2, 3).place_piece(Piece(PLAYER_2_ID, PieceType.three)) board.get_tile(4, 3).place_piece(Piece(PLAYER_2_ID, PieceType.one)) movements = board.get_chained_push_movements(board.get_tile(0, 3), board.get_tile(1, 3)) assert len(movements) == 3 assert movements == [ (Tile(0, 3), Tile(1, 3)), (Tile(1, 3), Tile(2, 3)), (Tile(2, 3), Tile(3, 3)), ]
def test_build_board(self): expected_board = [ [ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' ], [ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' ], [ 'p', 'p', 'p', 'p', 'p', 'p', 'p', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' ], [ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' ], [ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' ], [ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' ], [ ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'p', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' ], [ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' ], [ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' ], [ ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'P', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' ], [ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' ], [ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' ], [ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' ], [ 'P', 'P', 'P', 'P', 'P', 'P', 'P', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' ], [ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' ], [ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' ], ] board = Board.build_board(self.input_board) self.assertEqual(board, expected_board)
def test_pieces_movement_order(self): board = Board() board.get_tile(1, 1).place_piece(Piece(PLAYER_1_ID, PieceType.two)) assert board.get_movement_ordered_pieces(PLAYER_1_ID) == [ Piece(PLAYER_1_ID, PieceType.two) ] board.get_tile(1, 2).place_piece(Piece(PLAYER_2_ID, PieceType.one)) board.get_tile(1, 3).place_piece(Piece(PLAYER_2_ID, PieceType.two)) board.get_tile(2, 1).place_piece(Piece(PLAYER_1_ID, PieceType.four)) assert board.get_movement_ordered_pieces(PLAYER_1_ID) == [ Piece(PLAYER_2_ID, PieceType.one), Piece(PLAYER_1_ID, PieceType.two), Piece(PLAYER_2_ID, PieceType.two), Piece(PLAYER_1_ID, PieceType.four) ] assert board.get_movement_ordered_pieces(PLAYER_2_ID) == [ Piece(PLAYER_2_ID, PieceType.one), Piece(PLAYER_2_ID, PieceType.two), Piece(PLAYER_1_ID, PieceType.two), Piece(PLAYER_1_ID, PieceType.four) ]
class TestBoard(unittest.TestCase): @classmethod def setUpClass(cls) -> None: cls.input_board = ' ' \ ' ' \ 'ppppppp ' \ ' ' \ ' ' \ ' ' \ ' p ' \ ' ' \ ' ' \ ' P ' \ ' ' \ ' ' \ ' ' \ 'PPPPPPP ' \ ' ' \ ' ' def setUp(self) -> None: self.board = Board(self.input_board) def test_build_board(self): expected_board = [ [ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' ], [ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' ], [ 'p', 'p', 'p', 'p', 'p', 'p', 'p', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' ], [ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' ], [ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' ], [ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' ], [ ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'p', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' ], [ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' ], [ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' ], [ ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'P', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' ], [ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' ], [ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' ], [ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' ], [ 'P', 'P', 'P', 'P', 'P', 'P', 'P', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' ], [ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' ], [ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' ], ] board = Board.build_board(self.input_board) self.assertEqual(board, expected_board) def test_to_char_array(self): expected = list(self.input_board) self.assertEqual(self.board.to_char_array(), expected) @parameterized.expand([ ( ' ' ' ' 'ppp ppp ' ' p ' ' ' ' ' ' p ' ' ' ' ' ' P ' ' ' ' ' ' ' 'PPPPPPP ' ' ' ' ', 'black', (3, 2, 3, 3), 10, ), ( ' ' ' ' 'ppppppp ' ' ' ' ' ' ' ' p ' ' ' ' ' ' P ' ' ' ' ' ' P ' 'PPP PPP ' ' ' ' ', 'white', (3, 13, 3, 12), 10, ), ( ' ' ' ' 'ppppppp ' ' ' ' ' ' ' ' p ' ' ' ' ' ' P ' ' ' ' ' ' ' 'PPPPPPP ' ' ' ' ', 'white', (0, 0, 0, 0), -20, ), ]) def test_update_board(self, modified_board, color, expected_move, points): move = self.board.update(modified_board, color) self.assertEqual(move.to_coords(), expected_move) self.assertEqual(move.points, points) @parameterized.expand([ (' ' ' ' 'ppp ppp ' ' p ' ' ' ' ' ' p ' ' ' ' ' ' P ' ' ' ' ' ' P ' 'PPP PPP ' ' ' ' ', ), ]) def test_update_board_exception(self, desynchronized_board): self.assertRaises( BoardDesyncException, self.board.update, desynchronized_board, 'white', ) @parameterized.expand([ ('white', [ (0, 13, 0, 12), (1, 13, 1, 12), (2, 13, 2, 12), (3, 13, 3, 12), (4, 13, 4, 12), (5, 13, 5, 12), (6, 13, 6, 12), (7, 9, 7, 8), (0, 13, 0, 11), (1, 13, 1, 11), (2, 13, 2, 11), (3, 13, 3, 11), (4, 13, 4, 11), (5, 13, 5, 11), (6, 13, 6, 11), ]), ('black', [ (0, 2, 0, 3), (1, 2, 1, 3), (2, 2, 2, 3), (3, 2, 3, 3), (4, 2, 4, 3), (5, 2, 5, 3), (6, 2, 6, 3), (7, 6, 7, 7), (0, 2, 0, 4), (1, 2, 1, 4), (2, 2, 2, 4), (3, 2, 3, 4), (4, 2, 4, 4), (5, 2, 5, 4), (6, 2, 6, 4), ]), ]) def test_get_moves(self, color, expected_moves): moves = self.board.get_moves(color) moves_as_coords = [m.to_coords() for m in moves] self.assertCountEqual(moves_as_coords, expected_moves) @parameterized.expand([ ('white', [ (0, 13, 0, 12), (1, 13, 1, 12), (2, 13, 2, 12), (3, 13, 3, 12), (4, 13, 4, 12), (5, 13, 5, 12), (6, 13, 6, 12), (7, 9, 7, 8), (0, 13, 0, 11), (1, 13, 1, 11), (2, 13, 2, 11), (3, 13, 3, 11), (4, 13, 4, 11), (5, 13, 5, 11), (6, 13, 6, 11), ], [ (0, 2, 0, 3), (1, 2, 1, 3), (2, 2, 2, 3), (3, 2, 3, 3), (4, 2, 4, 3), (5, 2, 5, 3), (6, 2, 6, 3), (7, 6, 7, 7), (0, 2, 0, 4), (1, 2, 1, 4), (2, 2, 2, 4), (3, 2, 3, 4), (4, 2, 4, 4), (5, 2, 5, 4), (6, 2, 6, 4), ]), ('black', [ (0, 2, 0, 3), (1, 2, 1, 3), (2, 2, 2, 3), (3, 2, 3, 3), (4, 2, 4, 3), (5, 2, 5, 3), (6, 2, 6, 3), (7, 6, 7, 7), (0, 2, 0, 4), (1, 2, 1, 4), (2, 2, 2, 4), (3, 2, 3, 4), (4, 2, 4, 4), (5, 2, 5, 4), (6, 2, 6, 4), ], [ (0, 13, 0, 12), (1, 13, 1, 12), (2, 13, 2, 12), (3, 13, 3, 12), (4, 13, 4, 12), (5, 13, 5, 12), (6, 13, 6, 12), (7, 9, 7, 8), (0, 13, 0, 11), (1, 13, 1, 11), (2, 13, 2, 11), (3, 13, 3, 11), (4, 13, 4, 11), (5, 13, 5, 11), (6, 13, 6, 11), ]), ]) def test_get_all_moves(self, color, expected_player_moves, expected_opponent_moves): raw_player_moves, raw_opponent_moves = self.board.get_all_moves(color) player_moves = [m.to_coords() for m in raw_player_moves] opponent_moves = [m.to_coords() for m in raw_opponent_moves] self.assertCountEqual(player_moves, expected_player_moves) self.assertCountEqual(opponent_moves, expected_opponent_moves) @parameterized.expand([ (2, 2, pieces.Pawn), (4, 4, pieces.Blank), ]) def test_get_piece(self, x, y, expected_piece): piece = self.board.get_piece(x, y) self.assertEqual(piece, expected_piece) @parameterized.expand([ (2, 2, False), (4, 4, True), ]) def test_is_empty(self, x, y, expected): result = self.board.is_empty(x, y) self.assertEqual(result, expected) @parameterized.expand([ (2, 2, 2, 4, False), (7, 6, 7, 7, True), (7, 9, 7, 8, True), ]) def test_move(self, from_x, from_y, to_x, to_y, should_promote): from_piece_pre_move = self.board.get_piece(from_x, from_y) self.board.move(from_x, from_y, to_x, to_y) from_piece_post_move = self.board.get_piece(from_x, from_y) to_piece_post_move = self.board.get_piece(to_x, to_y) self.assertEqual(from_piece_post_move, pieces.Blank) if should_promote: self.assertEqual(from_piece_pre_move, pieces.Pawn) self.assertEqual(to_piece_post_move, pieces.Queen) else: self.assertEqual(from_piece_pre_move, to_piece_post_move) @parameterized.expand([ (2, 2, 2, 4, False), (7, 6, 7, 7, True), (7, 9, 7, 8, True), ]) def test_undo_move(self, from_x, from_y, to_x, to_y, should_unpromote): from_piece_pre_move = self.board.get_piece(from_x, from_y) to_piece_pre_move = self.board.get_piece(to_x, to_y) self.board.move(from_x, from_y, to_x, to_y) self.board.move(to_x, to_y, from_x, from_y, unpromote=should_unpromote) from_piece_post_move = self.board.get_piece(from_x, from_y) to_piece_post_move = self.board.get_piece(to_x, to_y) self.assertEqual(from_piece_pre_move, from_piece_post_move) self.assertEqual(to_piece_pre_move, to_piece_post_move)