def test_should_return_vertical_positions(): front_position = Position(1, 1) affected_positions = retrieve_affected_positions(2, front_position, ShipDirection.V) expected_positions = [Position(i, 1) for i in range(1, 3)] assert sorted(affected_positions) == sorted(expected_positions)
def test_should_return_horizontal_positions(): front_position = Position(1, 1) affected_positions = retrieve_affected_positions(2, front_position, ShipDirection.H) expected_positions = [Position(1, j) for j in range(1, 3)] assert sorted(affected_positions) == sorted(expected_positions)
def retrieve_affected_positions(ship_length: int, front_position: Position, direction: ShipDirection) -> List[Position]: if direction == ShipDirection.H: return [ Position(front_position.x, j) for j in range(front_position.y, front_position.y + ship_length) ] if direction == ShipDirection.V: return [ Position(i, front_position.y) for i in range(front_position.x, front_position.x + ship_length) ] raise UnknownDirection
def test_shouldnt_bomb_an_already_bombed_position(): board, position = Board2D(4, 4), Position(0, 0) board.chart[position.x][position.y] = BoardPosition(PositionStatus.BOMBED) with pytest.raises(CannotBombPosition): bomb_position(board, position)
def test_should_return_true_when_position_is_bombed_on_board(): board = Board2D(4, 4) board.chart[0][0] = BoardPosition(PositionStatus.BOMBED) assert cannot_occupy_board_in_the_positions( board, [Position(i, j) for i, j in itertools.product(range(4), range(4))])
def test_should_bomb_a_free_position(): board, position = Board2D(4, 4), Position(0, 0) outcome = bomb_position(board, position) assert board.chart[0][0].status == PositionStatus.BOMBED assert not outcome.has_hit_something assert not outcome.has_destroyed_a_ship
def test_should_raise_exception_that_cannot_occupy_board_position(): board = Board2D(4, 4) # A new board completely free board.chart[1][1] = BoardPosition( PositionStatus.BOMBED) # Occupy position (1,1) with pytest.raises(CannotOccupyPositions): occupy_board_positions_with_ship(board, [Position(1, 1)], Ship("destroyer", 3))
def test_should_occupy_free_positions_from_board_with_ship(): board = Board2D(4, 4) # A new board completely free ship = Ship("destroyer", 3) occupy_board_positions_with_ship(board, [Position(1, 1)], ship) assert board.chart[1][1].status == PositionStatus.OCCUPIED assert board.chart[1][1].ship == ship assert len(board.ships) == 1
def test_should_raise_exception_when_ship_isnt_available(): game_option: GameOption = { "ABC": AvailableShip(kind="abc", length=3, quantity=0), "DEF": AvailableShip(kind="def", length=4, quantity=99), "GHI": AvailableShip(kind="ghi", length=10, quantity=1), } player = Player("player_1", game_option=game_option) with pytest.raises(UnavailableShip): place_ship(player, game_option["ABC"], Position(0, 0), ShipDirection.H)
def test_should_raise_exception_when_cannot_occupy_all_positions_from_board(): game_option: GameOption = { "ABC": AvailableShip(kind="abc", length=3, quantity=0), "DEF": AvailableShip(kind="def", length=4, quantity=99), "GHI": AvailableShip(kind="ghi", length=10, quantity=1), } player = Player("player_1", game_option=game_option) player.board.chart[0][1] = BoardPosition(PositionStatus.BOMBED) with pytest.raises(CannotOccupyPositions): place_ship(player, game_option["DEF"], Position(0, 0), ShipDirection.H)
def test_should_place_ship_vertically(): board, ship, front_position = Board2D(4, 4), Ship("destroyer", 3), Position(0, 0) place_ship_on_board(ship, board, front_position, ShipDirection.V) expected_board_position = BoardPosition(PositionStatus.OCCUPIED, ship) assert board.chart[0][0] == expected_board_position assert board.chart[1][0] == expected_board_position assert board.chart[2][0] == expected_board_position
def test_should_bomb_and_destroy_an_occupied_position(): board, position, ship = Board2D(4, 4), Position(0, 0), Ship("destroyer", 1) board.chart[position.x][position.y] = BoardPosition( PositionStatus.OCCUPIED, ship) outcome = bomb_position(board, position) assert ship.hits_taken == 1 assert board.chart[0][0].status == PositionStatus.BOMBED assert outcome.has_hit_something assert outcome.has_destroyed_a_ship
def test_should_succesfully_parse_a_valid_line_input(): game_option: GameOption = { "ABC": AvailableShip(kind="abc", length=3, quantity=0), "DEF": AvailableShip(kind="def", length=4, quantity=99), "GHI": AvailableShip(kind="ghi", length=10, quantity=1), } line_horizontal_direction = "DEF 0 0 H" available_ship, position, ship_direction = parse_line_input( line_horizontal_direction, game_option) assert id(available_ship) == id(game_option["DEF"]) # Same reference! assert position == Position(0, 0) assert ship_direction == ShipDirection.H line_vertical_direction = "GHI 1 0 V" available_ship, position, ship_direction = parse_line_input( line_vertical_direction, game_option) assert id(available_ship) == id(game_option["GHI"]) # Same reference assert position == Position(1, 0) assert ship_direction == ShipDirection.V
def test_should_successfully_place_ship(): game_option: GameOption = { "ABC": AvailableShip(kind="abc", length=3, quantity=0), "DEF": AvailableShip(kind="def", length=4, quantity=99), "GHI": AvailableShip(kind="ghi", length=10, quantity=1), } player = Player("player_1", game_option=game_option) place_ship(player, game_option["DEF"], Position(0, 0), ShipDirection.H) assert game_option["DEF"]["quantity"] == 98 # 99 - 1! assert len(player.board.ships) == 1 assert player.board.ships[0] == Ship("def", 4)
def parse_line_input( line: str, game_option: GameOption ) -> Tuple[AvailableShip, Position, ShipDirection]: try: ship_slug, x, y, direction_slug = line.split(maxsplit=3) return ( game_option[ship_slug], Position(int(x), int(y)), ShipDirection[direction_slug], ) except (ValueError, KeyError): print(""" Couldn't understand the given input, please input in the following format: - if horizontally: SLG X Y H - if vertically: SLG X Y V For example, if you have a destroyer (DES) and you want to put at position (0, 0) horizontally, write: DES 0 0 H """) raise InputWithError
def test_shouldnt_bomb_a_position_outside_the_board(): board, position = Board2D(4, 4), Position(5, 5) with pytest.raises(CannotBombPosition): bomb_position(board, position)
def test_should_return_false_when_board_has_all_positions_free(): board = Board2D(4, 4) # A new board completely free assert not cannot_occupy_board_in_the_positions( board, [Position(i, j) for i, j in itertools.product(range(4), range(4))])
def get_random_position(length: int, width: int) -> Position: return Position(randint(0, length), randint(0, width))
def test_should_raise_exception_for_unknown_direction(): with pytest.raises(UnknownDirection): retrieve_affected_positions(2, Position(1, 1), "unknown_direction")
def test_should_return_true_when_given_position_isnt_inside_the_board(): board = Board2D(4, 4) assert cannot_occupy_board_in_the_positions(board, [Position(10, 2)])