def setUp(self): self.sample_ships = ( Ship(Position(2, 7), 3, Series.ROW), Ship(Position(1, 1), 1, Series.ROW), Ship(Position(7, 10), 4, Series.COLUMN), Ship(Position(3, 3), 2, Series.COLUMN), )
def test_no_disallowed_overlapping_fields_for_ship(self): parameters_vector = ( ( "╔═════════════════════╗\n" "║ x x x x . ║(3)\n" "║ x x x x x ║(2)\n" "║ x x O x x ║(2)\n" "║ x . x x x ║(1)\n" "║ x x x x x ║(2)\n" "╚═════════════════════╝\n" " (4) (1) (2) (1) (2) ", Ship(Position(1, 2), 3, Series.ROW), True, ), ( "╔═════════════════════╗\n" "║ x x x x . ║(3)\n" "║ x . . . x ║(2)\n" "║ x x O x x ║(2)\n" "║ x . x x x ║(1)\n" "║ x x x x x ║(2)\n" "╚═════════════════════╝\n" " (4) (1) (2) (1) (2) ", Ship(Position(1, 2), 3, Series.ROW), True, ), ( "╔═════════════════════╗\n" "║ x x . x . ║(3)\n" "║ x x x x x ║(2)\n" "║ x x O x x ║(2)\n" "║ x . x x x ║(1)\n" "║ x x x x x ║(2)\n" "╚═════════════════════╝\n" " (4) (1) (2) (1) (2) ", Ship(Position(1, 2), 3, Series.ROW), False, ), ( "╔═════════════════════╗\n" "║ x x x O . ║(3)\n" "║ x x x x x ║(2)\n" "║ x x O x x ║(2)\n" "║ x . x x x ║(1)\n" "║ x x x x x ║(2)\n" "╚═════════════════════╝\n" " (4) (1) (2) (1) (2) ", Ship(Position(1, 2), 3, Series.ROW), False, ), ) for board_repr, ship, expected_result in parameters_vector: with self.subTest(): self.assertEqual( expected_result, parse_board(board_repr).no_disallowed_overlapping_fields_for_ship( ship ), )
def test_mark_ship_and_surrounding_sea(self): actual_board = parse_board( "╔═════════════════════════════════════════╗\n" "║ . x x x x x x x x x ║(0)\n" "║ x x . x x x x x x x ║(2)\n" "║ x . x x x x x x x x ║(0)\n" "║ x x x x x . x x x x ║(0)\n" "║ x x x x x x x x x x ║(1)\n" "║ x x x x x x x x x x ║(1)\n" "║ x x x x x x x x x x ║(1)\n" "║ x x x x . x x x x x ║(1)\n" "║ x x x x x x . x x x ║(0)\n" "║ x x x x x x x x x x ║(0)\n" "╚═════════════════════════════════════════╝\n" " (1) (1) (0) (0) (0) (4) (0) (0) (0) (0) " ) actual_board.mark_ship_and_surrounding_sea( Ship(Position(5, 6), 4, Series.COLUMN) ) expected_board = parse_board( "╔═════════════════════════════════════════╗\n" "║ . x x x x x x x x x ║(0)\n" "║ x x . x x x x x x x ║(2)\n" "║ x . x x x x x x x x ║(0)\n" "║ x x x x . . . x x x ║(0)\n" "║ x x x x . O . x x x ║(0)\n" "║ x x x x . O . x x x ║(0)\n" "║ x x x x . O . x x x ║(0)\n" "║ x x x x . O . x x x ║(0)\n" "║ x x x x . . . x x x ║(0)\n" "║ x x x x x x x x x x ║(0)\n" "╚═════════════════════════════════════════╝\n" " (1) (1) (0) (0) (0) (0) (0) (0) (0) (0) " ) self.assertEqual(expected_board, actual_board) actual_board.mark_ship_and_surrounding_sea(Ship(Position(2, 1), 2, Series.ROW)) expected_board = parse_board( "╔═════════════════════════════════════════╗\n" "║ . . . x x x x x x x ║(0)\n" "║ O O . x x x x x x x ║(0)\n" "║ . . . x x x x x x x ║(0)\n" "║ x x x x . . . x x x ║(0)\n" "║ x x x x . O . x x x ║(0)\n" "║ x x x x . O . x x x ║(0)\n" "║ x x x x . O . x x x ║(0)\n" "║ x x x x . O . x x x ║(0)\n" "║ x x x x . . . x x x ║(0)\n" "║ x x x x x x x x x x ║(0)\n" "╚═════════════════════════════════════════╝\n" " (0) (0) (0) (0) (0) (0) (0) (0) (0) (0) " ) self.assertEqual(expected_board, actual_board)
def test_fieldtype_positions_in_series(self): params_vector = ( (FieldType.SHIP, Series.ROW, 2), (FieldType.SHIP, Series.COLUMN, 2), ) expected_results_vectors = ( ({Position(2, 1)}, set()), (set(), {Position(1, 2)}), (set(), set()), ( { Position(2, 2), Position(2, 3), Position(2, 6), Position(2, 7) }, {Position(1, 2), Position(2, 2)}, ), ) for sample_grid, expected_result_vector in zip( self.sample_fieldtypegrids, expected_results_vectors): for params, expected_result in zip(params_vector, expected_result_vector): with self.subTest(): self.assertEqual( expected_result, sample_grid.fieldtype_positions_in_series(*params), )
def test_simulate_marking_of_ships(self): actual_board = parse_board( "╔═════════════════════╗\n" "║ x x x x . ║(3)\n" "║ x x x x x ║(0)\n" "║ x x O x x ║(2)\n" "║ x . x x x ║(1)\n" "║ x x x x x ║(2)\n" "╚═════════════════════╝\n" " (4) (1) (2) (1) (2) " ) ships = { Ship(Position(1, 1), 3, Series.ROW), Ship(Position(3, 5), 2, Series.COLUMN), } ships_orig = set(ships) actual_board.mark_ship_group(ships) expected_board = parse_board( "╔═════════════════════╗\n" "║ O O O . . ║(0)\n" "║ . . . . . ║(0)\n" "║ x . O . O ║(1)\n" "║ . . . . O ║(0)\n" "║ x . x . . ║(2)\n" "╚═════════════════════╝\n" " (3) (0) (1) (1) (0) " ) self.assertEqual(actual_board, expected_board) self.assertEqual(ships, ships_orig) actual_board = parse_board( "╔═════════════════════╗\n" "║ x x x x . ║(3)\n" "║ x x x x x ║(0)\n" "║ x x O x x ║(2)\n" "║ x . x x x ║(1)\n" "║ x x x x x ║(2)\n" "╚═════════════════════╝\n" " (4) (1) (2) (1) (2) " ) ships = { Ship(Position(1, 1), 3, Series.ROW), Ship(Position(3, 5), 2, Series.COLUMN), Ship(Position(5, 1), 3, Series.ROW), } ships_orig = set(ships) with self.assertRaises(InvalidShipPlacementException): actual_board.mark_ship_group(ships)
def test_solve(self): fleet = Fleet({3: 1, 2: 2, 1: 2}) puzzle = Puzzle( parse_board("╔═════════════════════╗\n" "║ x x x x . ║(3)\n" "║ x x x x x ║(2)\n" "║ x x O x x ║(2)\n" "║ x . x x x ║(1)\n" "║ x x x x x ║(2)\n" "╚═════════════════════╝\n" " (4) (0) (2) (1) (2) "), Fleet(fleet), ) with unittest.mock.patch.object( battleships.puzzle.Puzzle, "decide_how_to_proceed") as mock_decide_how_to_proceed: puzzle.solve() self.assertEqual( puzzle.board, parse_board("╔═════════════════════╗\n" "║ x . x x . ║(3)\n" "║ x . x . x ║(2)\n" "║ x . x x x ║(3)\n" "║ x . x . x ║(1)\n" "║ x . x x x ║(2)\n" "╚═════════════════════╝\n" " (4) (0) (3) (1) (2) "), ) self.assertEqual(puzzle.fleet, fleet) mock_decide_how_to_proceed.assert_called_once_with({Position(3, 3)})
def test_decide_how_to_proceed( self, mocked_find_definite_ship_fields_positions, mocked_try_to_cover_all_ship_fields_to_be, mocked_mark_subfleet_of_biggest_remaining_ships, ): mocked_find_definite_ship_fields_positions.side_effect = ( set(), set(), {Position(3, 3)}, {Position(3, 3)}, ) positions = set() positions_orig = set() self.sample_puzzle.decide_how_to_proceed(positions) self.assertEqual(positions, positions_orig) mocked_try_to_cover_all_ship_fields_to_be.assert_not_called() mocked_mark_subfleet_of_biggest_remaining_ships.assert_called_once_with( ) mocked_try_to_cover_all_ship_fields_to_be.reset_mock() mocked_mark_subfleet_of_biggest_remaining_ships.reset_mock() positions = {Position(5, 3)} positions_orig = set(positions) self.sample_puzzle.decide_how_to_proceed(positions) self.assertEqual(positions, positions_orig) mocked_try_to_cover_all_ship_fields_to_be.assert_called_once_with( {Position(5, 3)}) mocked_mark_subfleet_of_biggest_remaining_ships.assert_not_called() mocked_try_to_cover_all_ship_fields_to_be.reset_mock() mocked_mark_subfleet_of_biggest_remaining_ships.reset_mock() positions = set() positions_orig = set(positions) self.sample_puzzle.decide_how_to_proceed(positions) self.assertEqual(positions, positions_orig) mocked_try_to_cover_all_ship_fields_to_be.assert_called_once_with( {Position(3, 3)}) mocked_mark_subfleet_of_biggest_remaining_ships.assert_not_called() mocked_try_to_cover_all_ship_fields_to_be.reset_mock() mocked_mark_subfleet_of_biggest_remaining_ships.reset_mock() positions = set({Position(5, 3)}) positions_orig = set(positions) self.sample_puzzle.decide_how_to_proceed(positions) self.assertEqual(positions, positions_orig) mocked_try_to_cover_all_ship_fields_to_be.assert_called_once_with( {Position(5, 3), Position(3, 3)}) mocked_mark_subfleet_of_biggest_remaining_ships.assert_not_called()
def test_mark_diagonal_sea_fields_for_positions(self): actual_board = parse_board( "╔═════════════════════════════════════════╗\n" "║ . x x x x x x x x x ║(0)\n" "║ x x . x x x x x x x ║(2)\n" "║ x . x x x x x x x x ║(0)\n" "║ x x x x x . x x x x ║(0)\n" "║ x x x x x x x x x x ║(1)\n" "║ x x x x x x x x x x ║(1)\n" "║ x x x x x x x x x x ║(1)\n" "║ x x x x . x x x x x ║(1)\n" "║ x x x x x x . x x x ║(0)\n" "║ x x x x x x x x x x ║(0)\n" "╚═════════════════════════════════════════╝\n" " (1) (1) (0) (0) (0) (4) (0) (0) (0) (0) " ) positions = {Position(5, 9), Position(2, 1), Position(10, 10)} positions_orig = set(positions) actual_board.mark_diagonal_sea_fields_for_positions(positions) expected_board = parse_board( "╔═════════════════════════════════════════╗\n" "║ . . x x x x x x x x ║(0)\n" "║ x x . x x x x x x x ║(2)\n" "║ x . x x x x x x x x ║(0)\n" "║ x x x x x . x . x . ║(0)\n" "║ x x x x x x x x x x ║(1)\n" "║ x x x x x x x . x . ║(1)\n" "║ x x x x x x x x x x ║(1)\n" "║ x x x x . x x x x x ║(1)\n" "║ x x x x x x . x . x ║(0)\n" "║ x x x x x x x x x x ║(0)\n" "╚═════════════════════════════════════════╝\n" " (1) (1) (0) (0) (0) (4) (0) (0) (0) (0) " ) self.assertEqual(expected_board, actual_board) self.assertEqual(positions, positions_orig)
def test_set_ship_fields_as_unknown(self): actual_board = parse_board( "╔═════════════════════════════════════════╗\n" "║ . . . . . . . . . . ║(0)\n" "║ x . . . O . . . . . ║(0)\n" "║ . . O . O . . x . . ║(0)\n" "║ . . O . O . x . . O ║(0)\n" "║ x . O . . . x . . . ║(0)\n" "║ . . . . O . x . . . ║(0)\n" "║ . x . . O . x . . . ║(0)\n" "║ x . . x . . . . O O ║(0)\n" "║ . . . . . . . . . . ║(0)\n" "║ O . O O O O . O O . ║(0)\n" "╚═════════════════════════════════════════╝\n" " (0) (0) (0) (0) (0) (0) (0) (0) (0) (0) " ) ship_fields = { Position(3, 3), Position(4, 3), Position(5, 3), Position(10, 3), Position(10, 6), Position(8, 9), Position(8, 10), } ship_fields_orig = set(ship_fields) actual_board.set_ship_fields_as_unknown(ship_fields) expected_board = parse_board( "╔═════════════════════════════════════════╗\n" "║ . . . . . . . . . . ║(0)\n" "║ x . . . O . . . . . ║(0)\n" "║ . . x . O . . x . . ║(1)\n" "║ . . x . O . x . . O ║(1)\n" "║ x . x . . . x . . . ║(1)\n" "║ . . . . O . x . . . ║(0)\n" "║ . x . . O . x . . . ║(0)\n" "║ x . . x . . . . x x ║(2)\n" "║ . . . . . . . . . . ║(0)\n" "║ O . x O O x . O O . ║(2)\n" "╚═════════════════════════════════════════╝\n" " (0) (0) (4) (0) (0) (1) (0) (0) (1) (1) " ) self.assertEqual(expected_board, actual_board) self.assertEqual(ship_fields, ship_fields_orig)
def test_find_definite_ship_fields_positions(self): board = parse_board( "╔═════════════════════╗\n" "║ x x x . . ║(3)\n" "║ x x . x x ║(0)\n" "║ x x O x . ║(2)\n" "║ x . . x x ║(1)\n" "║ x x x x x ║(2)\n" "╚═════════════════════╝\n" " (4) (1) (2) (1) (0) " ) expected_result = { Position(1, 3), Position(5, 3), Position(1, 1), Position(1, 2), Position(3, 1), Position(4, 1), Position(5, 1), Position(3, 4), } self.assertEqual(expected_result, board.find_definite_ship_fields_positions())
def test_get_possible_ships_occupying_positions(self): actual_board = parse_board( "╔═════════════════════╗\n" "║ x x x x . ║(3)\n" "║ x x x x x ║(0)\n" "║ x x O x x ║(2)\n" "║ x . x x x ║(1)\n" "║ x x x x x ║(2)\n" "╚═════════════════════╝\n" " (4) (1) (2) (1) (2) " ) positions = {Position(1, 3), Position(5, 1)} positions_orig = set(positions) ship_sizes = {3, 2, 1} ship_sizes_orig = set(ship_sizes) expected_ship_occupying_positions = { Position(1, 3): { Ship(Position(1, 1), 3, Series.ROW), Ship(Position(1, 2), 3, Series.ROW), Ship(Position(1, 2), 2, Series.ROW), Ship(Position(1, 3), 2, Series.ROW), Ship(Position(1, 3), 1, Series.ROW), }, Position(5, 1): { Ship(Position(5, 1), 2, Series.ROW), Ship(Position(5, 1), 1, Series.ROW), Ship(Position(3, 1), 3, Series.COLUMN), Ship(Position(4, 1), 2, Series.COLUMN), }, } self.assertEqual( expected_ship_occupying_positions, actual_board.get_possible_ships_occupying_positions(positions, ship_sizes), ) self.assertEqual(positions, positions_orig) self.assertEqual(ship_sizes, ship_sizes_orig)
def test_try_to_cover_all_ship_fields_to_be(self, mocked_decide_how_to_proceed): board_repr = ("╔═════════════════════╗\n" "║ x x . x x ║(1)\n" "║ x x x x . ║(1)\n" "║ x x x x x ║(2)\n" "║ x . x x x ║(2)\n" "║ x x x x x ║(3)\n" "╚═════════════════════╝\n" " (2) (1) (4) (1) (4) ") fleet = Fleet({4: 1, 3: 1, 2: 1}) puzzle = Puzzle(parse_board(board_repr), Fleet.get_copy_of(fleet)) positions = {Position(1, 5)} positions_orig = set(positions) puzzle.try_to_cover_all_ship_fields_to_be(positions) self.assertEqual(positions, positions_orig) mocked_decide_how_to_proceed.assert_not_called() puzzle = Puzzle(parse_board(board_repr), Fleet.get_copy_of(fleet)) positions = { Position(2, 3), Position(4, 3), Position(3, 5), Position(5, 5) } positions_orig = set(positions) puzzle.try_to_cover_all_ship_fields_to_be(positions) self.assertEqual( puzzle, Puzzle( parse_board("╔═════════════════════╗\n" "║ x . . . x ║(1)\n" "║ . . O . . ║(0)\n" "║ . . O . O ║(0)\n" "║ . . O . O ║(0)\n" "║ x . O . O ║(1)\n" "╚═════════════════════╝\n" " (2) (1) (0) (1) (1) "), Fleet({2: 1}), ), ) self.assertEqual(positions, positions_orig) mocked_decide_how_to_proceed.assert_called_once() mocked_decide_how_to_proceed.reset_mock() puzzle = Puzzle(parse_board(board_repr), Fleet.get_copy_of(fleet)) positions = {Position(5, 3), Position(5, 5)} positions_orig = set({Position(5, 3), Position(5, 5)}) puzzle.try_to_cover_all_ship_fields_to_be(positions) self.assertEqual(mocked_decide_how_to_proceed.call_count, 6) mocked_decide_how_to_proceed.assert_has_calls( [ unittest.mock.call( Puzzle( parse_board("╔═════════════════════╗\n" "║ x . . . x ║(1)\n" "║ . . O . . ║(0)\n" "║ . . O . O ║(0)\n" "║ . . O . O ║(0)\n" "║ x . O . O ║(1)\n" "╚═════════════════════╝\n" " (2) (1) (0) (1) (1) "), Fleet({2: 1}), )), unittest.mock.call( Puzzle( parse_board("╔═════════════════════╗\n" "║ x x . x x ║(1)\n" "║ x x x . . ║(1)\n" "║ x . . . O ║(1)\n" "║ . . O . O ║(0)\n" "║ x . O . O ║(1)\n" "╚═════════════════════╝\n" " (2) (1) (2) (1) (1) "), Fleet({4: 1}), )), unittest.mock.call( Puzzle( parse_board("╔═════════════════════╗\n" "║ x . . x x ║(1)\n" "║ x . x . . ║(1)\n" "║ x . x . O ║(1)\n" "║ . . . . O ║(1)\n" "║ . O O . O ║(0)\n" "╚═════════════════════╝\n" " (2) (0) (3) (1) (1) "), Fleet({4: 1}), )), unittest.mock.call( Puzzle( parse_board("╔═════════════════════╗\n" "║ x . . . x ║(1)\n" "║ . . O . . ║(0)\n" "║ x . O . . ║(1)\n" "║ . . O . O ║(0)\n" "║ x . O . O ║(1)\n" "╚═════════════════════╝\n" " (2) (1) (0) (1) (2) "), Fleet({3: 1}), )), unittest.mock.call( Puzzle( parse_board("╔═════════════════════╗\n" "║ x x . x x ║(1)\n" "║ x . . . . ║(1)\n" "║ x . O . . ║(1)\n" "║ . . O . O ║(0)\n" "║ x . O . O ║(1)\n" "╚═════════════════════╝\n" " (2) (1) (1) (1) (2) "), Fleet({4: 1}), )), unittest.mock.call( Puzzle( parse_board("╔═════════════════════╗\n" "║ x x . . x ║(1)\n" "║ x x x . . ║(1)\n" "║ x x x . x ║(2)\n" "║ x . . . . ║(2)\n" "║ . . O O O ║(0)\n" "╚═════════════════════╝\n" " (2) (1) (3) (0) (3) "), Fleet({ 4: 1, 2: 1 }), )), ], any_order=True, ) self.assertEqual(positions, positions_orig)
def test_mark_ship_group(self, mocked_decide_how_to_proceed): board_repr = ("╔═════════════════════╗\n" "║ x x x x x ║(1)\n" "║ x x x x . ║(1)\n" "║ x x x x x ║(2)\n" "║ x . x x x ║(2)\n" "║ x x x x x ║(3)\n" "╚═════════════════════╝\n" " (2) (1) (4) (1) (4) ") fleet = Fleet({4: 1, 3: 2, 1: 2}) puzzle = Puzzle(parse_board(board_repr), Fleet.get_copy_of(fleet)) ship_group = { Ship(Position(1, 3), 4, Series.COLUMN), Ship(Position(2, 3), 4, Series.COLUMN), } with self.assertRaises(InvalidShipPlacementException): puzzle.mark_ship_group(ship_group) # test when board is overmarked puzzle = Puzzle(parse_board(board_repr), Fleet.get_copy_of(fleet)) ship_group = { Ship(Position(5, 2), 1, Series.ROW), Ship(Position(5, 4), 1, Series.ROW), } ship_group_orig = set(ship_group) puzzle.mark_ship_group(ship_group) self.assertEqual( puzzle.board, parse_board("╔═════════════════════╗\n" "║ x . x . x ║(1)\n" "║ x . x . . ║(1)\n" "║ x . x . x ║(2)\n" "║ . . . . . ║(2)\n" "║ . O . O . ║(1)\n" "╚═════════════════════╝\n" " (2) (0) (4) (0) (4) "), ) self.assertEqual(ship_group, ship_group_orig) mocked_decide_how_to_proceed.assert_not_called() mocked_decide_how_to_proceed.reset_mock() puzzle = Puzzle(parse_board(board_repr), Fleet.get_copy_of(fleet)) fleet = Fleet({4: 1, 3: 2, 1: 2}) ship_group = { Ship(Position(3, 3), 3, Series.COLUMN), Ship(Position(3, 5), 3, Series.COLUMN), } ship_group_orig = set(ship_group) puzzle.mark_ship_group(ship_group) self.assertEqual( puzzle, Puzzle( parse_board("╔═════════════════════╗\n" "║ x x x x x ║(1)\n" "║ x . . . . ║(1)\n" "║ . . O . O ║(0)\n" "║ . . O . O ║(0)\n" "║ x . O . O ║(1)\n" "╚═════════════════════╝\n" " (2) (1) (1) (1) (1) "), Fleet({ 4: 1, 1: 2 }), ), ) self.assertEqual(ship_group, ship_group_orig) mocked_decide_how_to_proceed.assert_called_once()
def test_mark_subfleet_of_biggest_remaining_ships(self): board_repr = ("╔═════════════════════╗\n" "║ x x x x x ║(0)\n" "║ x x x x . ║(2)\n" "║ x x x x x ║(2)\n" "║ x . x x x ║(2)\n" "║ x x x x x ║(3)\n" "╚═════════════════════╝\n" " (2) (1) (4) (1) (4) ") fleet1 = Fleet({}) puzzle1 = Puzzle(parse_board(board_repr), Fleet(fleet1)) puzzle1.mark_subfleet_of_biggest_remaining_ships() self.assertEqual(puzzle1.board, parse_board(board_repr)) self.assertEqual(puzzle1.fleet, fleet1) self.assertEqual( puzzle1.__class__.solutions, [ "╔═════════════════════╗\n" "║ x x x x x ║\n" "║ x x x x . ║\n" "║ x x x x x ║\n" "║ x . x x x ║\n" "║ x x x x x ║\n" "╚═════════════════════╝" ], ) fleet2 = Fleet({4: 1, 3: 2, 1: 1}) puzzle2 = Puzzle(parse_board(board_repr), Fleet(fleet2)) with unittest.mock.patch.object( battleships.puzzle.Puzzle, "mark_ship_group") as mocked_try_to_mark_ship_group: puzzle2.mark_subfleet_of_biggest_remaining_ships() self.assertEqual(puzzle2, Puzzle(parse_board(board_repr), Fleet(fleet2))) mocked_try_to_mark_ship_group.assert_called_once_with( {Ship(Position(2, 3), 4, Series.COLUMN)}) fleet3 = Fleet({3: 2, 1: 1}) puzzle3 = Puzzle(parse_board(board_repr), Fleet(fleet3)) with unittest.mock.patch.object( battleships.puzzle.Puzzle, "mark_ship_group") as mocked_try_to_mark_ship_group: puzzle3.mark_subfleet_of_biggest_remaining_ships() self.assertEqual(puzzle3, Puzzle(parse_board(board_repr), Fleet(fleet3))) self.assertEqual(mocked_try_to_mark_ship_group.call_count, 15) mocked_try_to_mark_ship_group.assert_has_calls( [ unittest.mock.call({ Ship(Position(5, 1), 3, Series.ROW), Ship(Position(5, 2), 3, Series.ROW), }), unittest.mock.call({ Ship(Position(5, 1), 3, Series.ROW), Ship(Position(5, 3), 3, Series.ROW), }), unittest.mock.call({ Ship(Position(5, 1), 3, Series.ROW), Ship(Position(2, 3), 3, Series.COLUMN), }), unittest.mock.call({ Ship(Position(5, 1), 3, Series.ROW), Ship(Position(3, 3), 3, Series.COLUMN), }), unittest.mock.call({ Ship(Position(5, 1), 3, Series.ROW), Ship(Position(3, 5), 3, Series.COLUMN), }), unittest.mock.call({ Ship(Position(5, 2), 3, Series.ROW), Ship(Position(5, 3), 3, Series.ROW), }), unittest.mock.call({ Ship(Position(5, 2), 3, Series.ROW), Ship(Position(2, 3), 3, Series.COLUMN), }), unittest.mock.call({ Ship(Position(5, 2), 3, Series.ROW), Ship(Position(3, 3), 3, Series.COLUMN), }), unittest.mock.call({ Ship(Position(5, 2), 3, Series.ROW), Ship(Position(3, 5), 3, Series.COLUMN), }), unittest.mock.call({ Ship(Position(5, 3), 3, Series.ROW), Ship(Position(2, 3), 3, Series.COLUMN), }), unittest.mock.call({ Ship(Position(5, 3), 3, Series.ROW), Ship(Position(3, 3), 3, Series.COLUMN), }), unittest.mock.call({ Ship(Position(5, 3), 3, Series.ROW), Ship(Position(3, 5), 3, Series.COLUMN), }), unittest.mock.call({ Ship(Position(2, 3), 3, Series.COLUMN), Ship(Position(3, 3), 3, Series.COLUMN), }), unittest.mock.call({ Ship(Position(2, 3), 3, Series.COLUMN), Ship(Position(3, 5), 3, Series.COLUMN), }), unittest.mock.call({ Ship(Position(3, 3), 3, Series.COLUMN), Ship(Position(3, 5), 3, Series.COLUMN), }), ], any_order=True, )
def test_get_possible_puzzles(self): puzzle = Puzzle( parse_board("╔═════════════════════╗\n" "║ x x x x x ║(0)\n" "║ x x x x . ║(2)\n" "║ x x x x x ║(2)\n" "║ x . x x x ║(2)\n" "║ x x x x x ║(3)\n" "╚═════════════════════╝\n" " (2) (1) (4) (1) (4) "), Fleet({5: 1}), ) ships_occupying_position = puzzle.board.get_possible_ships_occupying_positions( {Position(3, 3)}, puzzle.fleet.distinct_ship_sizes) ships_occupying_position_orig = copy.deepcopy(ships_occupying_position) self.assertEqual(puzzle.get_possible_puzzles(ships_occupying_position), []) self.assertEqual(ships_occupying_position, ships_occupying_position_orig) puzzle = Puzzle( parse_board("╔═════════════════════╗\n" "║ x x x x x ║(0)\n" "║ x x x x . ║(2)\n" "║ x x x x x ║(2)\n" "║ x . x x x ║(2)\n" "║ x x x x x ║(3)\n" "╚═════════════════════╝\n" " (2) (1) (4) (1) (4) "), Fleet({ 4: 1, 3: 2, 1: 3 }), ) ships_occupying_position = puzzle.board.get_possible_ships_occupying_positions( {Position(2, 1), Position(3, 3), Position(5, 3)}, puzzle.fleet.distinct_ship_sizes, ) ships_occupying_position_orig = copy.deepcopy(ships_occupying_position) actual_possible_puzzles_list = puzzle.get_possible_puzzles( ships_occupying_position) self.assertEqual(ships_occupying_position, ships_occupying_position_orig) expected_possible_puzzles_list = [ Puzzle( parse_board("╔═════════════════════╗\n" "║ . . . . . ║(0)\n" "║ O . . . . ║(1)\n" "║ . . O . x ║(1)\n" "║ . . . . x ║(2)\n" "║ O O O . . ║(0)\n" "╚═════════════════════╝\n" " (0) (0) (2) (1) (4) "), Fleet({ 4: 1, 3: 1, 1: 1 }), ), Puzzle( parse_board("╔═════════════════════╗\n" "║ . . . . . ║(0)\n" "║ O . . . . ║(1)\n" "║ . . O . x ║(1)\n" "║ . . . . . ║(2)\n" "║ . O O O . ║(0)\n" "╚═════════════════════╝\n" " (1) (0) (2) (0) (4) "), Fleet({ 4: 1, 3: 1, 1: 1 }), ), Puzzle( parse_board("╔═════════════════════╗\n" "║ . . . . . ║(0)\n" "║ O . . . . ║(1)\n" "║ . . O . x ║(1)\n" "║ x . . . . ║(2)\n" "║ . . O O O ║(0)\n" "╚═════════════════════╝\n" " (1) (1) (2) (0) (3) "), Fleet({ 4: 1, 3: 1, 1: 1 }), ), Puzzle( parse_board("╔═════════════════════╗\n" "║ . . . . . ║(0)\n" "║ O . . . . ║(1)\n" "║ . . O . x ║(1)\n" "║ x . . . x ║(2)\n" "║ x . O . x ║(2)\n" "╚═════════════════════╝\n" " (1) (1) (2) (1) (4) "), Fleet({ 4: 1, 3: 2 }), ), Puzzle( parse_board("╔═════════════════════╗\n" "║ . . . . . ║(0)\n" "║ O . O . . ║(0)\n" "║ . . O . x ║(1)\n" "║ x . O . x ║(1)\n" "║ x . O . x ║(2)\n" "╚═════════════════════╝\n" " (1) (1) (0) (1) (4) "), Fleet({ 3: 2, 1: 2 }), ), Puzzle( parse_board("╔═════════════════════╗\n" "║ . . . . . ║(0)\n" "║ O . . . . ║(1)\n" "║ . . O . x ║(1)\n" "║ x . O . x ║(1)\n" "║ x . O . x ║(2)\n" "╚═════════════════════╝\n" " (1) (1) (1) (1) (4) "), Fleet({ 4: 1, 3: 1, 1: 2 }), ), ] self.assertEqual( { self.__class__.hashable_object_from_puzzle(puzzle) for puzzle in actual_possible_puzzles_list }, { self.__class__.hashable_object_from_puzzle(puzzle) for puzzle in expected_possible_puzzles_list }, )
def test_get_ship_fields_positions(self): board = parse_board( "╔═════════════════════════════════════════╗\n" "║ . . . . . . . . . . ║(0)\n" "║ x . . . O . . . . . ║(0)\n" "║ . . x . O . . x . . ║(1)\n" "║ . . x . O . x . . O ║(1)\n" "║ x . x . . . x . . . ║(1)\n" "║ . . . . O . x . . . ║(0)\n" "║ . x . . O . x . . . ║(0)\n" "║ x . . x . . . . x x ║(2)\n" "║ . . . . . . . . . . ║(0)\n" "║ O . x O O x . O O . ║(2)\n" "╚═════════════════════════════════════════╝\n" " (0) (0) (4) (0) (0) (1) (0) (0) (1) (1) " ) self.assertEqual( { Position(10, 1), Position(10, 4), Position(10, 5), Position(10, 8), Position(10, 9), Position(4, 10), Position(2, 5), Position(3, 5), Position(4, 5), Position(6, 5), Position(7, 5), }, board.get_ship_fields_positions(), )
def test_get_possible_ships_of_size(self): board = parse_board( "╔═════════════════════╗\n" "║ x x x x . ║(3)\n" "║ x x x x x ║(2)\n" "║ x x O x x ║(2)\n" "║ x . x x x ║(1)\n" "║ x x x x x ║(2)\n" "╚═════════════════════╝\n" " (4) (1) (2) (1) (2) " ) self.assertEqual( { Ship(Position(1, 1), 3, Series.ROW), Ship(Position(1, 2), 3, Series.ROW), Ship(Position(1, 1), 3, Series.COLUMN), Ship(Position(2, 1), 3, Series.COLUMN), Ship(Position(3, 1), 3, Series.COLUMN), }, board.get_possible_ships_of_size(3), ) self.assertEqual( { Ship(Position(1, 1), 2, Series.ROW), Ship(Position(1, 2), 2, Series.ROW), Ship(Position(1, 3), 2, Series.ROW), Ship(Position(5, 1), 2, Series.ROW), Ship(Position(5, 2), 2, Series.ROW), Ship(Position(5, 3), 2, Series.ROW), Ship(Position(5, 4), 2, Series.ROW), Ship(Position(1, 1), 2, Series.COLUMN), Ship(Position(2, 1), 2, Series.COLUMN), Ship(Position(3, 1), 2, Series.COLUMN), Ship(Position(4, 1), 2, Series.COLUMN), Ship(Position(2, 5), 2, Series.COLUMN), Ship(Position(3, 5), 2, Series.COLUMN), Ship(Position(4, 5), 2, Series.COLUMN), }, board.get_possible_ships_of_size(2), ) self.assertEqual( { Ship(Position(1, 1), 1, Series.ROW), Ship(Position(1, 2), 1, Series.ROW), Ship(Position(1, 3), 1, Series.ROW), Ship(Position(1, 4), 1, Series.ROW), Ship(Position(2, 1), 1, Series.ROW), Ship(Position(2, 5), 1, Series.ROW), Ship(Position(3, 1), 1, Series.ROW), Ship(Position(3, 5), 1, Series.ROW), Ship(Position(4, 1), 1, Series.ROW), Ship(Position(4, 5), 1, Series.ROW), Ship(Position(5, 1), 1, Series.ROW), Ship(Position(5, 2), 1, Series.ROW), Ship(Position(5, 3), 1, Series.ROW), Ship(Position(5, 4), 1, Series.ROW), Ship(Position(5, 5), 1, Series.ROW), }, board.get_possible_ships_of_size(1), )
def test_sufficient_remaining_ship_fields_to_mark_ship(self): parameters_vector = ( ( "╔═════════════════════╗\n" "║ x x x x . ║(3)\n" "║ x x x x x ║(2)\n" "║ x x O x x ║(2)\n" "║ x . x x x ║(1)\n" "║ x x x x x ║(2)\n" "╚═════════════════════╝\n" " (4) (1) (2) (1) (2) ", Ship(Position(1, 1), 3, Series.ROW), True, ), ( "╔═════════════════════╗\n" "║ x x x x . ║(2)\n" "║ x x x x x ║(2)\n" "║ x x O x x ║(2)\n" "║ x . x x x ║(1)\n" "║ x x x x x ║(2)\n" "╚═════════════════════╝\n" " (4) (1) (2) (1) (2) ", Ship(Position(1, 1), 3, Series.ROW), False, ), ( "╔═════════════════════╗\n" "║ x x x x . ║(3)\n" "║ x x x x x ║(2)\n" "║ x x O x x ║(2)\n" "║ x . x x x ║(1)\n" "║ x x x x x ║(2)\n" "╚═════════════════════╝\n" " (4) (0) (2) (1) (2) ", Ship(Position(1, 1), 3, Series.ROW), False, ), ( "╔═════════════════════╗\n" "║ x x x x . ║(3)\n" "║ x x x x x ║(2)\n" "║ x x O x x ║(2)\n" "║ x . x x x ║(1)\n" "║ x x x x x ║(2)\n" "╚═════════════════════╝\n" " (4) (1) (2) (1) (2) ", Ship(Position(1, 1), 3, Series.COLUMN), True, ), ( "╔═════════════════════╗\n" "║ x x x x . ║(3)\n" "║ x x x x x ║(2)\n" "║ x x O x x ║(2)\n" "║ x . x x x ║(1)\n" "║ x x x x x ║(2)\n" "╚═════════════════════╝\n" " (2) (1) (2) (1) (2) ", Ship(Position(1, 1), 3, Series.COLUMN), False, ), ( "╔═════════════════════╗\n" "║ x x x x . ║(3)\n" "║ x x x x x ║(2)\n" "║ x x O x x ║(0)\n" "║ x . x x x ║(1)\n" "║ x x x x x ║(2)\n" "╚═════════════════════╝\n" " (4) (1) (2) (1) (2) ", Ship(Position(1, 1), 3, Series.COLUMN), False, ), ) for board_repr, ship, expected_result in parameters_vector: with self.subTest(): self.assertEqual( expected_result, parse_board( board_repr ).sufficient_remaining_ship_fields_to_mark_ship(ship), )
def test_ship_is_within_playable_grid(self): board = parse_board( "╔═════════════════════════════════════════╗\n" "║ . x x x x x x x x x ║(0)\n" "║ x x . x x x x x x x ║(2)\n" "║ x . x x x x x x x x ║(0)\n" "║ x x x x x . x x x x ║(0)\n" "║ x x x x x x x x x x ║(1)\n" "║ x x x x x x x x x x ║(1)\n" "║ x x x x x x x x x x ║(1)\n" "║ x x x x . x x x x x ║(1)\n" "║ x x x x x x . x x x ║(0)\n" "║ x x x x x x x x x x ║(0)\n" "╚═════════════════════════════════════════╝\n" " (1) (1) (0) (0) (0) (4) (0) (0) (0) (0) " ) ships_within_playable_grid = ( Ship(Position(1, 1), 3, Series.ROW), Ship(Position(1, 8), 3, Series.ROW), Ship(Position(5, 5), 3, Series.ROW), Ship(Position(10, 5), 3, Series.ROW), Ship(Position(1, 1), 3, Series.COLUMN), Ship(Position(8, 1), 3, Series.COLUMN), Ship(Position(5, 5), 3, Series.COLUMN), Ship(Position(5, 10), 3, Series.COLUMN), Ship(Position(1, 1), 1, Series.ROW), Ship(Position(6, 6), 1, Series.ROW), Ship(Position(10, 10), 1, Series.ROW), ) for ship in ships_within_playable_grid: with self.subTest(ship): self.assertTrue(board.ship_is_within_playable_grid(ship)) ships_outside_playable_grid = ( Ship(Position(-1, 4), 3, Series.ROW), Ship(Position(0, 4), 3, Series.ROW), Ship(Position(1, 0), 3, Series.ROW), Ship(Position(1, 9), 3, Series.ROW), Ship(Position(11, 5), 3, Series.ROW), Ship(Position(4, -1), 3, Series.COLUMN), Ship(Position(4, 0), 3, Series.COLUMN), Ship(Position(0, 1), 3, Series.COLUMN), Ship(Position(9, 1), 3, Series.COLUMN), Ship(Position(5, 11), 3, Series.COLUMN), Ship(Position(0, 1), 1, Series.ROW), Ship(Position(1, 0), 1, Series.ROW), Ship(Position(11, 10), 1, Series.ROW), Ship(Position(10, 11), 1, Series.ROW), ) for ship in ships_outside_playable_grid: with self.subTest(ship): self.assertFalse(board.ship_is_within_playable_grid(ship))