def solve_13(input_path, remove_crashed_carts=False): map_grid = parse_map(input_path) carts = [] for y in range(0, len(map_grid)): for x in range(0, len(map_grid[0])): if map_grid[y][x] == '<' or map_grid[y][x] == '>': carts.append(Cart(map_grid[y][x], Point(x, y))) map_grid[y][x] = '-' elif map_grid[y][x] == '^' or map_grid[y][x] == 'v': carts.append(Cart(map_grid[y][x], Point(x, y))) map_grid[y][x] = '|' run = True result_loc = None while run: for cart in sorted(carts, key=lambda c: (c.loc.y, c.loc.x)): cart.move() if cart.collision(carts, remove_crashed_carts): if not remove_crashed_carts: run = False result_loc = Point(cart.loc.x, cart.loc.y) # print_map(map_grid, carts) if len(carts) == 1: run = False cart.rotate(map_grid[cart.loc.y][cart.loc.x]) # print_map(map_grid, carts) if not run and remove_crashed_carts: result_loc = Point(carts[0].loc.x, carts[0].loc.y) # print_map(map_grid, carts) return result_loc
def test_load_gml_for_debugging(self): g: nx.DiGraph = nx.read_gml('real-nodes.gml', destringizer=self.make_points) all_paths = nx.single_source_shortest_path(g, source=Point(0, 0)) max_distance = 0 i = 0 node_count = len(g.nodes) greater_than_1000 = 0 for k in all_paths.keys(): i += 1 if len(all_paths[k]) > max_distance: max_distance = len(all_paths[k]) if len(all_paths[k]) >= 1001: greater_than_1000 += 1 print('{}/{}'.format(i, node_count)) print('max: {}'.format(max_distance - 1)) print('more than 1000: {}'.format(greater_than_1000)) for node in g.nodes: i += 1 distance = nx.shortest_path_length(g, source=Point(0, 0), target=node) if distance > max_distance: max_distance = distance print(max_distance)
def simulate_flow(puzzle_input): clay = set() for line in puzzle_input: a, b, c = map(int, re.findall(r"([\d]+)", line)) if line.startswith('x'): for y in range(b, c + 1): clay.add(Point(a, y)) else: for x in range(b, c + 1): clay.add(Point(x, a)) lowest_y = max(p.y for p in clay) water_spring = Point(500, 0) still = set() flowing = set() to_fall = set() to_spread = set() to_fall.add(water_spring) while to_fall or to_spread: while to_fall: falling_point = to_fall.pop() res = fall(falling_point, lowest_y, clay, flowing) if res: to_spread.add(res) while to_spread: spreading_point = to_spread.pop() res_left, res_right = spread(spreading_point, clay, flowing, still) if not res_left and not res_right: to_spread.add(Point(spreading_point.x, spreading_point.y - 1)) else: if res_left: to_fall.add(res_left) if res_right: to_fall.add(res_right) return flowing, still, clay
def solve_22_part_2(depth, target): cave = {} for x in range(0, target.x + 50): for y in range(0, target.y + 50): region = Region(Point(x, y), target, cave, depth) cave[Point(x, y)] = region g = nx.Graph() for k, region in cave.items(): allowed_tools = region.allowed_tools() g.add_edge(region.nodes[allowed_tools[0]], region.nodes[allowed_tools[1]], weight=7) for direction in [Point(-1, 0), Point(0, -1)]: if (region.loc.x == 0 and direction.x == -1) or (region.loc.y == 0 and direction.y == -1): continue neighbor = cave[region.loc + direction] for tool in allowed_tools: if tool in neighbor.allowed_tools(): g.add_edge(region.nodes[tool], neighbor.nodes[tool], weight=1) path_length = nx.dijkstra_path_length(g, source=cave[Point(0, 0)].nodes['T'], target=cave[target].nodes['T']) return path_length
def on_paint(cr): if client.width_mm == 0 or client.height_mm == 0: print("Wayland reports bogus monitor dimensions!") scale = Point(1, 1) else: scale = Point(client.width_pixels / client.width_mm, client.height_pixels / client.height_mm) script.run(cr, scale, window)
def compute_destination(input): counter = Counter(input) # We're using a normal grid, but every orthogonal move is +2 and diagonal moves are +1, +1 loc = Point(0, 0) for direction, count in counter.items(): loc.x = loc.x + (dir_offsets[direction].x * count) loc.y = loc.y + (dir_offsets[direction].y * count) return loc
def getScale(self, widget): """Return the dpi of the current monitor as a Point.""" s = widget.get_screen() m = s.get_monitor_at_window(widget.get_window()) geom = s.get_monitor_geometry(m) mm = Point(s.get_monitor_width_mm(m), s.get_monitor_height_mm(m)) size = Point(float(geom.width), float(geom.height)) return size / mm
def get_input(): data = process_input() data = [re.findall(r"(-?\d+)", d) for d in data] data = [list(map(int, d)) for d in data] data = [ Particle(Point(a, b, c), Point(d, e, f), Point(g, h, i)) for a, b, c, d, e, f, g, h, i in data ] return data
def spread_vertical(pos, off, clay, still, tmp): pos1 = pos while pos1 not in clay: tmp.add(pos1) pos2 = Point(pos1.x, pos1.y + 1) if pos2 not in clay and pos2 not in still: return pos1 pos1 = Point(pos1.x + off.x, pos1.y + off.y) return None
def setup_grid_and_start(entries): grid = defaultdict(lambda: '.') for y in range(len(entries)): for x in range(len(entries[y])): grid[Point(x, y)] = entries[y][x] start = Point(len(entries[0]) / 2, len(entries) / 2) return grid, start
def spread(pos, clay, flowing, still): tmp = set() pl = spread_vertical(pos, Point(-1, 0), clay, still, tmp) pr = spread_vertical(pos, Point(1, 0), clay, still, tmp) if not pl and not pr: still.update(tmp) else: flowing.update(tmp) return pl, pr
def convert_points(entries: List[str]) -> List[Point]: points = [] i = 0 for entry in entries: x, y = map(lambda v: int(v), entry.split(',')) p = Point(x, y) p.id = i points.append(p) i += 1 return points
def solve_22_part_1(depth, target): cave = {} risk = 0 for x in range(0, target.x + 1): for y in range(0, target.y + 1): region = Region(Point(x, y), target, cave, depth) cave[Point(x, y)] = region risk += region.type() return risk
def __parse_map(self, puzzle_input, elf_attack_power): for y in range(len(puzzle_input)): for x, c in enumerate(puzzle_input[y]): if c == 'E': self.units.append( Unit(Point(x, y), Team.ELF, attack_power=elf_attack_power)) elif c == 'G': self.units.append(Unit(Point(x, y), Team.GOBLIN)) elif c == '#': self.walls.add(Point(x, y))
def traverse_grid(origin, side_length, input, target_max=None): if target_max == 1: return origin grid = [] for x in range(0, side_length): grid.append([]) for y in range(0, side_length): grid[x].append(0) d = deque( [Point(x=1, y=0), Point(x=0, y=-1), Point(x=-1, y=0), Point(x=0, y=1)]) cell = Point(x=origin.x, y=origin.y) grid[cell.x][cell.y] = 1 cell += d[0] grid[cell.x][cell.y] = 1 d.rotate(-1) i = 3 temp_side_limit = 1 inc_toggle = True while i <= input: for l in range(0, temp_side_limit): cell += d[0] if i == input: return cell value = compute_value(cell, grid) grid[cell.x][cell.y] = value if target_max is not None and value > target_max: print( 'Part 2: found larger than target value: {}'.format(value)) exit() i += 1 if inc_toggle: temp_side_limit += 1 inc_toggle = False else: inc_toggle = True d.rotate(-1)
def compute_farthest_point(input): # We're using a normal grid, but every orthogonal move is +2 and diagonal moves are +1, +1 positions = set() loc = Point(0, 0) for direction in input: loc.x = loc.x + dir_offsets[direction].x loc.y = loc.y + dir_offsets[direction].y positions.add(Point(loc.x, loc.y)) return max(map(lambda p: (p, compute_shortest_distance(p)), positions), key=lambda p: p[1])
def draw(self, widget, cr): helper = Helper(cr) alloc = widget.get_allocation() window = Rect.from_top_left(Point(0, 0), alloc.width, alloc.height) with helper.box(window.inset(5), clip=False) as bounds: radius = min(bounds.width, bounds.height) * 0.5 helper.circle(bounds.center, radius) cr.set_line_width(2.5) cr.stroke() cr.rotate(self.value) helper.circle(Point(radius/2, 0), radius/4) cr.fill()
def __find_closest_enemy(self, unit): frontier = deque() start = Point(unit.pos.x, unit.pos.y) frontier.append(start) came_from = {} came_from[start] = None team_mates = set( [u.pos for u in self.units if u.team == unit.team and u.alive]) while frontier: current = frontier.popleft() for new_position in sorted(get_adjecent_4(current), key=lambda p: (p.y, p.x)): if new_position not in self.walls and new_position not in came_from and new_position not in team_mates: frontier.append(new_position) came_from[new_position] = current targets = [] for u in self.units: if u.team != unit.team and u.alive: targets.extend(get_adjecent_4(u.pos)) paths = [] for current in sorted(targets, key=lambda p: (p.y, p.x)): if current in came_from: path = [] while current != start: path.append(current) current = came_from[current] path.append(start) path.reverse() paths.append(path) if len(paths) == 0: return None return min(paths, key=len)
def compute_shortest_distance(loc): # Since all we care about is distance, let's make it easy on ourselves # and make everything positive _loc = Point(abs(loc.x), abs(loc.y)) # Now let's walk back to the start # Easy cases, we're already on an axis if _loc.x == 0: return _loc.y / 2 if _loc.y == 0: return _loc.x / 2 # Now we're not on an axis, so: # - get to an axis on a diagonal # - and then walk on axis back to origin dist = 0 if _loc.x < _loc.y: dist += _loc.x dist += (_loc.y - _loc.x) / 2 elif _loc.y < _loc.x: dist += _loc.y dist += (_loc.x - _loc.y) / 2 else: dist = _loc.x # answer: 834 return int(dist)
def fill_grid(serial_number): grid = defaultdict(dict) for x in range(0, GRID_SIZE + 1): for y in range(0, GRID_SIZE + 1): grid[x][y] = compute_cell(Point(x, y), serial_number) return grid
def fall(pos, lowest_y, clay, flowing): while pos.y < lowest_y: pos_down = Point(pos.x, pos.y + 1) if pos_down not in clay: flowing.add(pos_down) pos = pos_down elif pos_down in clay: return pos return None
def solve_3(input, target_max=None): # Adding 5 to give us some buffer side_length = math.ceil(math.sqrt(input)) + 5 center_index = math.floor(side_length / 2.0) origin = Point(x=center_index, y=center_index, id=1) target = traverse_grid(origin, side_length, input, target_max) return manhattan_distance(origin, target)
def find_start_pos(network_map): # Find starting position start = None x = 0 while start is None: if network_map[(x, 0)] == '|': start = Point(x, 0) x += 1 return start
def print_state(time_id, grid): print('Time: {}'.format(time_id)) min_x, max_x, min_y, max_y = get_min_max(list(grid.keys())) for x in range(min_x, max_x + 1): for y in range(min_y, max_y + 1): print(grid[Point(x, y)], end='') print('') print('') print('')
def test_find_aa(self): # Should be 88 locations entries = read_raw_entries('tests/find-accessible-test.txt') grid_map, elves, goblins = parse_map(entries) filled_map = fill_temp_map(elves + goblins, grid_map) aa = find_accessible_areas_from_point(goblins[0].loc + Point(1, 0), filled_map, []) print(len(set(aa))) self.assertEqual(329, len(set(aa)))
def geo_index(self): if self._geo_index is not None: return self._geo_index if self.loc == Point(0, 0): self._geo_index = 0 elif self.loc == self.target: self._geo_index = 0 elif self.loc.y == 0: self._geo_index = self.loc.x * 16807 elif self.loc.x == 0: self._geo_index = self.loc.y * 48271 else: x_minus_one = self.cave[Point(self.loc.x - 1, self.loc.y)].erosion_level() y_minus_one = self.cave[Point(self.loc.x, self.loc.y - 1)].erosion_level() self._geo_index = x_minus_one * y_minus_one return self._geo_index
def part2(): g: nx.DiGraph = nx.read_gml('real-nodes.gml', destringizer=make_points) all_paths = nx.single_source_shortest_path(g, source=Point(0, 0)) greater_than_1000 = 0 for k in all_paths.keys(): # greater than 1001 since every path start at (and includes) the origin if len(all_paths[k]) >= 1001: greater_than_1000 += 1 return greater_than_1000
def test_shortest_path_go_right(self): paths = shortest_path(Point(1, 1), Point(4, 1)) self.assertEqual(len(paths), 1) self.assertEqual( paths[0], [Point(1, 1), Point(2, 1), Point(3, 1), Point(4, 1)])
def print_state(clay, water, min_x, max_x, min_y, max_y): f = open("test_out.txt", "w") for x in range(min_x-1, max_x + 2): if x == 500: print('x', end='') f.write('x\n') else: print('.', end='') f.write('.') print('') f.write('\n') for y in range(min_y-1, max_y + 2): for x in range(min_x-1, max_x + 2): if Point(x, y) in clay: print(clay[Point(x, y)], end='') f.write(clay[Point(x, y)]) elif Point(x, y) in water: print(water[Point(x, y)], end='') f.write(water[Point(x, y)]) else: print('.', end='') f.write('.') print('') f.write('\n') print('') f.write('\n') f.close()
def parse_real_input(input_path): entries = read_raw_entries(input_path) points = [] for entry in entries: parts = entry.split() if 'x' in parts[0]: x = parts[0].split('=')[1].replace(',', '') s, e = parts[1].split('=')[1].split('..') for y in range(int(s), int(e) + 1): p = Point(x, y) points.append(p) else: y = parts[0].split('=')[1].replace(',', '') s, e = parts[1].split('=')[1].split('..') for x in range(int(s), int(e) + 1): p = Point(x, y) points.append(p) return points