def test_simple_collision(): map_string = "#..#..#" asteroid_map = AsteroidMap.from_string(map_string) best_station_finder = BestStationFinder(asteroid_map) best_station_finder._remove_asteroids_not_seen_from(Coord(0, 0)) assert best_station_finder._seen_by[Coord(0, 0)] == set([Coord(3, 0)])
def get_boundaries(self): leftmost = min(coord.x for coord in self.color_values.keys()) rightmost = max(coord.x for coord in self.color_values.keys()) upmost = min(coord.y for coord in self.color_values.keys()) bottommost = max(coord.y for coord in self.color_values.keys()) return Coord(leftmost, upmost), Coord(rightmost, bottommost)
def test_more_granular(): map_string, expected = case3() asteroid_map = AsteroidMap.from_string(map_string) best_station_finder = BestStationFinder(asteroid_map) best_station_finder._remove_asteroids_in_line_of(Coord(7, 3), Coord(7, 5)) assert Coord(7, 6) not in best_station_finder._seen_by[Coord(7, 3)]
def test_correctly_count_painted_panels(): canvas = Canvas() canvas.draw_at(Coord(42, 55), 1) canvas.draw_at(Coord(42, 55), 0) canvas.draw_at(Coord(1, 2), 1) assert canvas.count_painted_panels() == 2
def __init__(self, asteroid_map, laser_position): self.asteroid_map = asteroid_map self.laser_position = laser_position self.laser_direction = Coord(0, -1) if self.laser_position in self.asteroid_map.asteroid_positions: self.asteroid_map.remove_asteroid(self.laser_position)
def test_disjoint_sets_have_no_intersection(): wire1 = WireStub(set()) wire2 = WireStub(set()) wire1.points_visited.add(Coord(1, 2)) wire2.points_visited.add(Coord(2, 3)) with pytest.raises(IntersectionNotFoundError): find_closest_intersection(wire1, wire2)
def test_firing_laser_removes_hit_asteroid(): asteroid_map = MagicMock() laser_position = Coord(3, 4) asteroid_map.all_asteroids_in_line_of = MagicMock( return_value=iter([Coord(42, 55)])) laser = Laser(asteroid_map, laser_position) laser.fire() asteroid_map.remove_asteroid.assert_called_with(Coord(42, 55))
def test_rotating_to_next_asteroid(): ## Laser map: ## #. ## X# asteroid_map = AsteroidMap.from_string("##\n##") laser_position = Coord(0, 1) laser = Laser(asteroid_map, laser_position) laser.fire() laser.rotate_to_next_asteroid() assert laser.laser_direction == Coord(1, -1)
def test_laser_rotates_to_hit_next_thing(): amap, laser_pos = laser_test() laser = Laser(amap, laser_pos) asteroid_hit = laser.fire() laser.rotate_to_next_asteroid() asteroid_hit = laser.fire() laser.rotate_to_next_asteroid() assert asteroid_hit == Coord(9, 0) asteroid_hit = laser.fire() assert asteroid_hit == Coord(9, 1)
def __init__(self, instructions): self._points_visited = {} self.steps = 0 self.current_pos = Coord(0, 0) self._points_visited[self.current_pos] = 0 self.process_wire_instructions(instructions)
def case4(): map_4 = """.#..##.###...####### ##.############..##. .#.######.########.# .###.#######.####.#. #####.##.#.##.###.## ..#####..#.######### #################### #.####....###.#.#.## ##.################# #####.##.###..####.. ..######..##.####### ####.##.####...##..# .#####..#.######.### ##...#.##########... #.##########.####### .####.#.###.###.#.## ....##.##.###..##### .#.#.###########.### #.#.#.#####.####.### ###.##.####.##.#..## """ best_4 = (Coord(11, 13), 210) return map_4, best_4
def test_first_thing_laser_shoots_is_correct(): amap, laser_pos = laser_test() laser = Laser(amap, laser_pos) asteroid_hit = laser.fire() assert asteroid_hit == Coord(8, 1)
def test_robot_receives_draw_input_and_updates_canvas(): canvas = MagicMock() computer = MagicMock() robot = Robot(computer, canvas) robot.read_command(42) canvas.draw_at.assert_called_once_with(Coord(0, 0), 42)
def laser_test(): map_string = """.#....#####...#.. ##...##.#####..## ##...#...#.#####. ..#.....#...###.. ..#.#.....#....## """ laser_pos = Coord(8, 3) return AsteroidMap.from_string(map_string), laser_pos
def read_grid(read_line=input): """Read the grid from an input (file or stdin).""" width, height = [int(i) for i in read_line().split()] areas = {} for row in range(height): areas.update( {Coord(row, column): int(n) for column, n in enumerate(read_line().split()) if int(n) > 0}) return Grid((height, width), areas)
def test_robot_receives_draw_then_turn_input_and_turns_and_moves_accordingly(): canvas = MagicMock() computer = MagicMock() robot = Robot(computer, canvas) robot.read_command(42) robot.read_command(1) canvas.draw_at.assert_called_once_with(Coord(0, 0), 42) canvas.draw_at.reset_mock() assert robot.pos == Coord(1, 0) # Now might as well turn again a bit robot.read_command(55) robot.read_command(0) canvas.draw_at.assert_called_once_with(Coord(1, 0), 55) assert robot.pos == Coord(1, -1)
def find_intersection(wire1: WireReader, wire2: WireReader, key: callable): common_items = wire1.points_visited.intersection(wire2.points_visited) try: common_items.remove(Coord(0, 0)) except KeyError: pass if not common_items: raise IntersectionNotFoundError else: return min(common_items, key=key)
def test_robot_passes_canvas_color_to_computer_input(): canvas = MagicMock() computer = MagicMock() robot = Robot(computer, canvas) computer.input_src = robot.get_camera computer.read_input = Mock(side_effect=computer.input_src()) computer.read_input() canvas.get.assert_called_once_with(Coord(0, 0))
def plot(self, canvas): symbols = (self.symbol, self.space) if self.invert: symbols = (symbols[1], symbols[0]) top_left, bottom_right = canvas.get_boundaries() for row in range(top_left.y, bottom_right.y + 1): for col in range(top_left.x, bottom_right.x + 1): item = canvas.get(Coord(col, row)) print(f"{symbols[item]}", end="") print()
def case3(): map_3 = """#.#...#.#. .###....#. .#....#... ##.#.#.#.# ....#.#.#. .##..###.# ..#...##.. ..##....## ......#... .####.###. """ best_3 = (Coord(1, 2), 35) return map_3, best_3
def from_string(cls, map_string): rows = map_string.split("\n") asteroids = set() for row_pos, row in enumerate(rows): for col_pos, symbol in enumerate(row): if symbol == "#": asteroids.add(Coord(col_pos, row_pos)) elif symbol != ".": raise ValueError("Invalid symbol in input") num_cols = len(rows[0]) shape = (num_cols, len(rows)) return cls(shape, asteroids)
class Laser: def __init__(self, asteroid_map, laser_position): self.asteroid_map = asteroid_map self.laser_position = laser_position self.laser_direction = Coord(0, -1) if self.laser_position in self.asteroid_map.asteroid_positions: self.asteroid_map.remove_asteroid(self.laser_position) def fire(self): try: asteroid_hit = next( self.asteroid_map.all_asteroids_in_line_of( self.laser_position, self.laser_direction ) ) except StopIteration: raise NoAsteroidInLineOfFireException() self.asteroid_map.remove_asteroid(asteroid_hit) return asteroid_hit def rotate_to_next_asteroid(self): # Find smallest rotation from current position def angle_between_laser_and(asteroid): vector_to_asteroid = asteroid - self.laser_position return self.laser_direction.angle_with(vector_to_asteroid) asteroid_candidates = self.asteroid_map.asteroid_positions.difference( self.asteroid_map.all_asteroids_in_line_of( self.laser_position, self.laser_direction ) ) if asteroid_candidates: next_asteroid = min( asteroid_candidates, key=lambda x: angle_between_laser_and(x), ) self.laser_direction = (next_asteroid - self.laser_position).normalized()
def test_equal_one_item_sets_intersect_at_that_item(): wire1 = WireStub(set([Coord(1, 2)])) wire2 = WireStub(set([Coord(1, 2)])) assert find_closest_intersection(wire1, wire2) == Coord(1, 2)
def test_if_only_00_is_common_have_no_intersection(): wire1 = WireStub(set([Coord(0, 0)])) wire2 = WireStub(set([Coord(0, 0)])) with pytest.raises(IntersectionNotFoundError): find_closest_intersection(wire1, wire2)
def case2(): map_2 = "......#.#.\n#..#.#....\n..#######.\n.#.#.###..\n.#..#.....\n..#....#.#\n#..#....#.\n.##.#..###\n##...#..#.\n.#....####" best_2 = (Coord(5, 8), 33) return map_2, best_2
def test_actually_finds_smallest_intersection(): wire1 = WireStub(set([Coord(0, 0), Coord(2, 3), Coord(1, 20), Coord(10, 0)])) wire2 = WireStub(set([Coord(0, 0), Coord(2, 3), Coord(10, 0), Coord(1, 20)])) assert find_closest_intersection(wire1, wire2) == Coord(2, 3)
def test_empty_canvas_is_zero_everywhere(): canvas = Canvas() assert canvas.get(Coord(0, 0)) == 0 assert canvas.get(Coord(42, 55)) == 0
from helpers import Coord OFFSETS = { 'R': Coord(1, 0), 'U': Coord(0, 1), 'L': Coord(-1, 0), 'D': Coord(0, -1) } class WireReader: def __init__(self, instructions): self._points_visited = {} self.steps = 0 self.current_pos = Coord(0, 0) self._points_visited[self.current_pos] = 0 self.process_wire_instructions(instructions) def process_wire_instructions(self, instructions): for instruction in instructions: self.process_instruction(instruction) def process_instruction(self, instruction): direction, distance = parse_instruction(instruction) offset = OFFSETS[direction] for i in range(distance): self.do_single_step(offset) self.update_step_counter() def do_single_step(self, offset):
def test_if_we_draw_somewhere_it_will_be_that_color(): canvas = Canvas() canvas.draw_at(Coord(42, 55), 1) assert canvas.get(Coord(42, 55)) == 1
def test_visiting_again_doesnt_update(): reader = WireReader(['R2', 'L3']) assert reader.get_step_count(Coord(0, 0)) == 0 assert reader.get_step_count(Coord(1, 0)) == 1 assert reader.get_step_count(Coord(2, 0)) == 2 assert reader.get_step_count(Coord(-1, 0)) == 5