def calc_valid_actions(piece: Piece) -> None: """ Converts representation from state/engine representation to game/main representation to reuse logic """ from game import is_valid_move from piece import Piece as GamePiece b = self.state.board pl = b.players # in game terms players are 0..n, in state terms they are (not necessarily ordered unique identifiers) game_piece = GamePiece(pl.index(piece.player), piece.number, piece.progress) status = [ GamePiece(pl.index(p.player), p.number, p.progress) for p in b.pieces ] if is_valid_move( game_piece, dice, status, b.player_shift, b.path_zone_length, b.end_progress, ): if piece.progress == 0: valid_actions.append( GameMove.piece_out(player, piece.number, dice)) else: valid_actions.append( GameMove.move_piece(player, piece.number, dice))
def test_do_not_move_piece_to_end_on_bigger_dice(monkeypatch): # Given we have started the game and a piece is in the safe zone board = Board.create(players=[0, 2], pieces_per_player=1) state = GameState.create(board) dice = Dice() monkeypatch.setattr(dice, "roll", lambda: 5) game = GameEngine(board, dice) state.board.pieces[0].progress = board.end_progress - 3 # When we roll the dice with 5 which is bigger then we need to # get to the goal new_state = game.play(GameMove.roll_dice(player=0)) # Then the piece should not go to the goal and it should be the # next player turn assert new_state == game.get_state() assert new_state.number == 1 assert new_state.dice == 5 assert new_state.valid_actions == [ GameMove.roll_dice(player=2), ] assert new_state.board.pieces == [ Piece(number=0, player=0, progress=board.end_progress - 3), Piece(number=0, player=2, progress=0), ] assert new_state.winners == []
def test_play_roll_dice_3(monkeypatch): # Given board = Board.create(players=[1, 3]) state = GameState.create(board) dice = Dice() monkeypatch.setattr(dice, "roll", lambda: 3) game = GameEngine(board, dice) # When new_state = game.play(GameMove.roll_dice(player=1)) # Then assert new_state == game.get_state() assert new_state.number == 1 assert new_state.dice == 3 assert new_state.valid_actions == [GameMove.roll_dice(player=3)] # And When new_state = game.play(GameMove.roll_dice(player=3)) # Then assert new_state == game.get_state() assert new_state.number == 2 assert new_state.dice == 3 assert new_state.valid_actions == [GameMove.roll_dice(player=1)]
def test_play_invalid_action_on_initial_state(monkeypatch): # Given board = Board.create(players=[1, 3]) state = GameState.create(board) game = GameEngine(board) # When we try to play an invalid action PieceOut with pytest.raises(Exception): game.play(GameMove.piece_out(1, 1)) # When we try to play valid action for an invalid Player with pytest.raises(Exception): game.play(GameMove.roll_dice(player=3))
def __on_next_player(self) -> GameMove: """ Update engine state for next player's turn and return corresponding dice roll """ current_player_index = self.state.board.players.index( self.state.current_player) next_index = (current_player_index + 1) % len(self.state.board.players) next_player = self.state.board.players[next_index] self.state.current_player = next_player return GameMove.roll_dice(next_player)
def __on_piece_out(self, piece: Piece, dice: int) -> GameState: assert self.state.board.is_on_start(piece) assert dice == 6 piece.progress = 1 self.__knock_out_other_players(piece) self.state.valid_actions = [GameMove.roll_dice(piece.player)] self.state.number = self.state.number + 1 return self.state
def test_game_state_defaults(monkeypatch): board = Board.create() state = GameState.create(board) assert state.board == board assert state.number == 0 assert state.dice == -1 assert state.winners == [] assert state.current_player == 0 assert state.valid_actions == [GameMove.roll_dice(player=0)]
def test_play_roll_dice_6(monkeypatch): # Given board = Board.create(players=[1, 3]) state = GameState.create(board) dice = Dice() monkeypatch.setattr(dice, "roll", lambda: 6) game = GameEngine(board, dice) # When new_state = game.play(GameMove.roll_dice(player=1)) # Then # assert new_state == game.get_state() assert new_state.number == 1 assert new_state.dice == 6 assert new_state.valid_actions == [ GameMove.piece_out(player=1, piece=0, dice=6), GameMove.piece_out(player=1, piece=1, dice=6), GameMove.piece_out(player=1, piece=2, dice=6), GameMove.piece_out(player=1, piece=3, dice=6), ]
def play_roll(): try: engine.state except: return __no_game_response() try: player = __get_player_number() except ValueError as ve: return __error_response(str(ve.args[0])) else: new_state = engine.play(GameMove.roll_dice(player)) return __state_to_json(new_state)
def play_out(piece: int, dice: int): piece = int(piece) dice = int(dice) try: engine.state except: return __no_game_response() try: player = __get_player_number() except ValueError as ve: return __error_response(str(ve.__str__)) else: new_state = engine.play(GameMove.piece_out(player, piece, dice)) return __state_to_json(new_state)
def test_roll(monkeypatch, client): # Given 4 players had joined in the previous tests and the game had starte # When we try to play with the correct user token rv = client.get("/play/roll", headers={"4oBe4e-user-token": player1_token}) game_state = json.loads(rv.data) board = Board.create(players=[0, 1, 2, 3]) dice = Dice() monkeypatch.setattr(dice, "roll", lambda: game_state["dice"]) game = GameEngine(board, dice) game.play(GameMove.roll_dice(player=0)) # Then we want the same state as the default for 4 players assert game_state == dataclasses.asdict(game.get_state())
def get_action(state): try: location = input("Your move: ") if isinstance(location, str): location = [int(n, 10) for n in location.split(",")] if len(location) != 4: return -1 x_from = location[0] y_from = location[1] x_to = location[2] y_to = location[3] pos_from = Position(x_from, y_from) pos_to = Position(x_to, y_to) move = GameMove(-1, pos_from, pos_to) except Exception as e: move = -1 if move == -1 or not state.is_move_legal(move): print("invalid move") move = get_action(state) return move
def test_do_move_take_out_of_home_and_knock_out(monkeypatch): dice4 = Dice() monkeypatch.setattr(dice4, "roll", lambda: 4) dice6 = Dice() monkeypatch.setattr(dice6, "roll", lambda: 6) b = Board.create(players=[0, 1], pieces_per_player=1) g = GameEngine(b) assert GameMove.roll_dice(0) in g.state.valid_actions g.dice = dice4 s = g.play(GameMove.roll_dice(0)) assert GameMove.roll_dice(1) in s.valid_actions g.dice = dice6 s = g.play(GameMove.roll_dice(1)) s = g.play(GameMove.piece_out(1, 0)) assert s.board.pieces == [Piece(0, 0, 0), Piece(0, 1, 1)] assert s.valid_actions == [GameMove.roll_dice(1)] s = g.play(GameMove.roll_dice(1)) s = g.play(GameMove.move_piece(1, 0, 6)) assert s.board.pieces == [Piece(0, 0, 0), Piece(0, 1, 7)] assert s.valid_actions == [GameMove.roll_dice(1)] s = g.play(GameMove.roll_dice(1)) s = g.play(GameMove.move_piece(1, 0, 6)) assert s.board.pieces == [Piece(0, 0, 0), Piece(0, 1, 13)] assert s.valid_actions == [GameMove.roll_dice(1)] s = g.play(GameMove.roll_dice(1)) s = g.play(GameMove.move_piece(1, 0, 6)) assert s.board.pieces == [Piece(0, 0, 0), Piece(0, 1, 19)] assert s.valid_actions == [GameMove.roll_dice(1)] s = g.play(GameMove.roll_dice(1)) s = g.play(GameMove.move_piece(1, 0, 6)) assert s.board.pieces == [Piece(0, 0, 0), Piece(0, 1, 25)] assert s.valid_actions == [GameMove.roll_dice(1)] g.dice = dice4 s = g.play(GameMove.roll_dice(1)) s = g.play(GameMove.move_piece(1, 0, 4)) assert s.board.pieces == [Piece(0, 0, 0), Piece(0, 1, 29)] assert s.valid_actions == [GameMove.roll_dice(0)] g.dice = dice6 s = g.play(GameMove.roll_dice(0)) assert GameMove.piece_out(0, 0) in s.valid_actions s = g.play(GameMove.piece_out(0, 0)) assert s.board.pieces == [Piece(0, 0, 1), Piece(0, 1, 0)]
def test_do_move_blocked_out_of_home(monkeypatch): dice4 = Dice() monkeypatch.setattr(dice4, "roll", lambda: 4) dice6 = Dice() monkeypatch.setattr(dice6, "roll", lambda: 6) b = Board.create(players=[0, 1], pieces_per_player=2) g = GameEngine(b) assert GameMove.roll_dice(0) in g.state.valid_actions g.dice = dice4 s = g.play(GameMove.roll_dice(0)) assert GameMove.roll_dice(1) in s.valid_actions g.dice = dice6 s = g.play(GameMove.roll_dice(1)) s = g.play(GameMove.piece_out(1, 0)) assert s.board.pieces == [Piece(0, 0), Piece(1, 0), Piece(0, 1, 1), Piece(1, 1)] assert GameMove.roll_dice(1) in s.valid_actions g.dice = dice6 s = g.play(GameMove.roll_dice(1)) s = g.play(GameMove.piece_out(1, 1)) assert s.board.pieces == [Piece(0, 0), Piece(1, 0), Piece(0, 1, 1), Piece(1, 1, 1)] assert GameMove.roll_dice(1) in s.valid_actions s = g.play(GameMove.roll_dice(1)) s = g.play(GameMove.move_piece(1, 0, 6)) s = g.play(GameMove.roll_dice(1)) s = g.play(GameMove.move_piece(1, 1, 6)) assert s.board.pieces == [Piece(0, 0), Piece(1, 0), Piece(0, 1, 7), Piece(1, 1, 7)] assert GameMove.roll_dice(1) in s.valid_actions s = g.play(GameMove.roll_dice(1)) s = g.play(GameMove.move_piece(1, 0, 6)) s = g.play(GameMove.roll_dice(1)) s = g.play(GameMove.move_piece(1, 1, 6)) assert s.board.pieces == [ Piece(0, 0), Piece(1, 0), Piece(0, 1, 13), Piece(1, 1, 13), ] assert GameMove.roll_dice(1) in s.valid_actions s = g.play(GameMove.roll_dice(1)) s = g.play(GameMove.move_piece(1, 0, 6)) s = g.play(GameMove.roll_dice(1)) s = g.play(GameMove.move_piece(1, 1, 6)) assert s.board.pieces == [ Piece(0, 0), Piece(1, 0), Piece(0, 1, 19), Piece(1, 1, 19), ] assert GameMove.roll_dice(1) in s.valid_actions s = g.play(GameMove.roll_dice(1)) s = g.play(GameMove.move_piece(1, 0, 6)) s = g.play(GameMove.roll_dice(1)) s = g.play(GameMove.move_piece(1, 1, 6)) assert s.board.pieces == [ Piece(0, 0), Piece(1, 0), Piece(0, 1, 25), Piece(1, 1, 25), ] assert GameMove.roll_dice(1) in s.valid_actions g.dice = dice4 s = g.play(GameMove.roll_dice(1)) s = g.play(GameMove.move_piece(1, 0, 4)) assert s.board.pieces == [ Piece(0, 0), Piece(1, 0), Piece(0, 1, 29), Piece(1, 1, 25), ] assert s.valid_actions == [GameMove.roll_dice(0)] s = g.play(GameMove.roll_dice(0)) # i.e. player 0 can't move assert s.valid_actions == [GameMove.roll_dice(1)] s = g.play(GameMove.roll_dice(1)) s = g.play(GameMove.move_piece(1, 1, 4)) assert s.board.pieces == [ Piece(0, 0), Piece(1, 0), Piece(0, 1, 29), Piece(1, 1, 29), ] assert s.valid_actions == [GameMove.roll_dice(0)] assert s.board.pieces == [ Piece(0, 0, 0), Piece(1, 0, 0), Piece(0, 1, 29), Piece(1, 1, 29), ] g.dice = dice6 s = g.play(GameMove.roll_dice(0)) # i.e. player 0 can't move, but since she drew 6, repeats turn assert s.current_player == 0 assert s.valid_actions == [GameMove.roll_dice(0)]
def __on_end_move(self) -> GameMove: if self.state.dice == 6: return GameMove.roll_dice(self.state.current_player) return self.__on_next_player()
def test_do_move_and_knock_out(monkeypatch): dice1 = Dice() monkeypatch.setattr(dice1, "roll", lambda: 1) dice5 = Dice() monkeypatch.setattr(dice5, "roll", lambda: 5) dice6 = Dice() monkeypatch.setattr(dice6, "roll", lambda: 6) b = Board.create(players=[0, 1], pieces_per_player=1) g = GameEngine(b) assert GameMove.roll_dice(0) in g.state.valid_actions g.dice = dice1 s = g.play(GameMove.roll_dice(0)) assert GameMove.roll_dice(1) in s.valid_actions g.dice = dice6 s = g.play(GameMove.roll_dice(1)) s = g.play(GameMove.piece_out(1, 0)) assert s.board.pieces == [Piece(0, 0, 0), Piece(0, 1, 1)] assert GameMove.roll_dice(1) in s.valid_actions s = g.play(GameMove.roll_dice(1)) s = g.play(GameMove.move_piece(1, 0, 6)) assert s.board.pieces == [Piece(0, 0, 0), Piece(0, 1, 7)] assert GameMove.roll_dice(1) in s.valid_actions s = g.play(GameMove.roll_dice(1)) s = g.play(GameMove.move_piece(1, 0, 6)) assert s.board.pieces == [Piece(0, 0, 0), Piece(0, 1, 13)] assert GameMove.roll_dice(1) in s.valid_actions s = g.play(GameMove.roll_dice(1)) s = g.play(GameMove.move_piece(1, 0, 6)) assert s.board.pieces == [Piece(0, 0, 0), Piece(0, 1, 19)] assert GameMove.roll_dice(1) in s.valid_actions g.dice = dice5 s = g.play(GameMove.roll_dice(1)) s = g.play(GameMove.move_piece(1, 0, 5)) assert s.board.pieces == [Piece(0, 0, 0), Piece(0, 1, 24)] assert GameMove.roll_dice(0) in s.valid_actions g.dice = dice6 s = g.play(GameMove.roll_dice(0)) assert GameMove.piece_out(0, 0) in s.valid_actions s = g.play(GameMove.piece_out(0, 0)) assert s.board.pieces == [Piece(0, 0, 1), Piece(0, 1, 24)] g.dice = dice1 s = g.play(GameMove.roll_dice(0)) s = g.play(GameMove.move_piece(0, 0, 1)) assert s.board.pieces == [Piece(0, 0, 2), Piece(0, 1, 24)] g.dice = dice6 s = g.play(GameMove.roll_dice(1)) assert GameMove.move_piece(1, 0, 6) in s.valid_actions s = g.play(GameMove.move_piece(1, 0, 6)) # player 1 hits player 0 and sends her home assert s.board.pieces == [Piece(0, 0, 0), Piece(0, 1, 30)]
def test_move_blocked(monkeypatch): dice1 = Dice() monkeypatch.setattr(dice1, "roll", lambda: 1) dice5 = Dice() monkeypatch.setattr(dice5, "roll", lambda: 5) dice6 = Dice() monkeypatch.setattr(dice6, "roll", lambda: 6) b = Board.create(players=[0, 1], pieces_per_player=2) g = GameEngine(b) assert GameMove.roll_dice(0) in g.state.valid_actions g.dice = dice5 s = g.play(GameMove.roll_dice(0)) assert GameMove.roll_dice(1) in s.valid_actions g.dice = dice6 s = g.play(GameMove.roll_dice(1)) s = g.play(GameMove.piece_out(1, 0)) assert s.board.pieces == [Piece(0, 0), Piece(1, 0), Piece(0, 1, 1), Piece(1, 1)] assert GameMove.roll_dice(1) in s.valid_actions s = g.play(GameMove.roll_dice(1)) s = g.play(GameMove.piece_out(1, 1)) assert s.board.pieces == [Piece(0, 0), Piece(1, 0), Piece(0, 1, 1), Piece(1, 1, 1)] assert GameMove.roll_dice(1) in s.valid_actions s = g.play(GameMove.roll_dice(1)) s = g.play(GameMove.move_piece(1, 0, 6)) s = g.play(GameMove.roll_dice(1)) s = g.play(GameMove.move_piece(1, 1, 6)) assert s.board.pieces == [Piece(0, 0), Piece(1, 0), Piece(0, 1, 7), Piece(1, 1, 7)] assert GameMove.roll_dice(1) in s.valid_actions s = g.play(GameMove.roll_dice(1)) s = g.play(GameMove.move_piece(1, 0, 6)) s = g.play(GameMove.roll_dice(1)) s = g.play(GameMove.move_piece(1, 1, 6)) assert s.board.pieces == [ Piece(0, 0), Piece(1, 0), Piece(0, 1, 13), Piece(1, 1, 13), ] assert GameMove.roll_dice(1) in s.valid_actions s = g.play(GameMove.roll_dice(1)) s = g.play(GameMove.move_piece(1, 0, 6)) s = g.play(GameMove.roll_dice(1)) s = g.play(GameMove.move_piece(1, 1, 6)) assert s.board.pieces == [ Piece(0, 0), Piece(1, 0), Piece(0, 1, 19), Piece(1, 1, 19), ] assert GameMove.roll_dice(1) in s.valid_actions s = g.play(GameMove.roll_dice(1)) s = g.play(GameMove.move_piece(1, 0, 6)) s = g.play(GameMove.roll_dice(1)) s = g.play(GameMove.move_piece(1, 1, 6)) assert s.board.pieces == [ Piece(0, 0), Piece(1, 0), Piece(0, 1, 25), Piece(1, 1, 25), ] assert GameMove.roll_dice(1) in s.valid_actions g.dice = dice5 s = g.play(GameMove.roll_dice(1)) s = g.play(GameMove.move_piece(1, 0, 5)) assert s.board.pieces == [ Piece(0, 0), Piece(1, 0), Piece(0, 1, 30), Piece(1, 1, 25), ] assert s.valid_actions == [GameMove.roll_dice(0)] s = g.play(GameMove.roll_dice(0)) # i.e. player 0 can't move assert s.valid_actions == [GameMove.roll_dice(1)] s = g.play(GameMove.roll_dice(1)) s = g.play(GameMove.move_piece(1, 1, 5)) assert s.board.pieces == [ Piece(0, 0), Piece(1, 0), Piece(0, 1, 30), Piece(1, 1, 30), ] assert s.valid_actions == [GameMove.roll_dice(0)] g.dice = dice6 s = g.play(GameMove.roll_dice(0)) s = g.play(GameMove.piece_out(0, 0)) assert s.board.pieces == [ Piece(0, 0, 1), Piece(1, 0), Piece(0, 1, 30), Piece(1, 1, 30), ] assert s.valid_actions == [GameMove.roll_dice(0)] g.dice = dice1 s = g.play(GameMove.roll_dice(0)) # i.e. player 0 can't move: piece 1 is not out, and piece 0 is blocked assert s.valid_actions == [GameMove.roll_dice(1)]
def test_play_until_the_end_two_players_once_piece(monkeypatch): # Given we have started the game board = Board.create(players=[0, 2], pieces_per_player=1) state = GameState.create(board) dice = Dice() monkeypatch.setattr(dice, "roll", lambda: 6) game = GameEngine(board, dice) # When we roll the dice new_state = game.play(GameMove.roll_dice(player=0)) # Then the state should be as expected assert new_state == game.get_state() assert new_state.number == 1 assert new_state.dice == 6 assert new_state.valid_actions == [ GameMove.piece_out(player=0, piece=0, dice=6), ] # And When we play getting out with the first peice new_state = game.play(GameMove.piece_out(player=0, piece=0, dice=6)) # Then the first piece should be out assert new_state.current_player == 0 assert new_state.number == 2 assert new_state.dice == 6 assert new_state.board.pieces == [ Piece(number=0, player=0, progress=1), Piece(number=0, player=2, progress=0), ] assert new_state.valid_actions == [GameMove.roll_dice(player=0)] # And When we row the dice again with 6 new_state = game.play(GameMove.roll_dice(player=0)) # Then we should should be able to move the piece forward assert new_state.number == 3 assert new_state.dice == 6 assert new_state.valid_actions == [GameMove.move_piece(player=0, piece=0, dice=6)] # And When we move the piece new_state = game.play(GameMove.move_piece(player=0, piece=0, dice=6)) # Then it should go forward and we should be able to roll the dice again assert new_state.number == 4 assert new_state.winners == [] assert new_state.board.pieces == [ Piece(number=0, player=0, progress=7), Piece(number=0, player=2, progress=0), ] assert new_state.valid_actions == [GameMove.roll_dice(player=0)] # And When we roll the dice again with 6 new_state = game.play(GameMove.roll_dice(player=0)) # Then we should be able to move the piece forward assert new_state.dice == 6 assert new_state.number == 5 assert new_state.valid_actions == [GameMove.move_piece(player=0, piece=0, dice=6)] # And When we move the piece new_state = game.play(GameMove.move_piece(player=0, piece=0, dice=6)) # Then the piece should go forward and we should be able to roll the dice again assert new_state.number == 6 assert new_state.board.pieces == [ Piece(number=0, player=0, progress=13), Piece(number=0, player=2, progress=0), ] assert new_state.winners == [] assert new_state.valid_actions == [GameMove.roll_dice(player=0)] # And When we position the piece toward the end of the board new_state.board.pieces[0].progress = board.end_progress - 6 # And When we roll the dice again with 6 new_state = game.play(GameMove.roll_dice(player=0)) # Then we should be able to move the piece forward into the safe zone and to the goal assert new_state.dice == 6 assert new_state.number == 7 assert new_state.valid_actions == [GameMove.move_piece(player=0, piece=0, dice=6)] # And When we move the piece new_state = game.play(GameMove.move_piece(player=0, piece=0, dice=6)) # Then the piece should go forward and we should be able to roll the dice again assert new_state.number == 8 assert new_state.board.pieces == [ Piece(number=0, player=0, progress=board.end_progress), Piece(number=0, player=2, progress=0), ] assert new_state.winners == [0] assert new_state.valid_actions == []