lily's recent activity
-
Comment on Day 25: Snowverload in ~comp.advent_of_code
-
Comment on Day 20: Pulse Propagation in ~comp.advent_of_code
lily (edited )LinkTricky part 2 today. I honestly wasn't the hugest fan of today's problem, since the solution ended up being dependent on a quirk in the input, and so it took me longer to figure out than it...Tricky part 2 today. I honestly wasn't the hugest fan of today's problem, since the solution ended up being dependent on a quirk in the input, and so it took me longer to figure out than it probably should have.
Solution
# Advent of Code 2023 # Day 20: Pulse Propagation from math import lcm class FlipFlop: def __init__(self, destinations): self.destinations = destinations self.on = False def recieve(self, name, pulse): if pulse == "low": self.on = not self.on if self.on: return [(name, "high") for name in self.destinations] else: return [(name, "low") for name in self.destinations] else: return [] class Conjunction: def __init__(self, destinations): self.destinations = destinations def init_memory(self, connected_modules): self.memory = {name: "low" for name in connected_modules} def recieve(self, name, pulse): self.memory[name] = pulse if all(pulse == "high" for pulse in self.memory.values()): return [(name, "low") for name in self.destinations] else: return [(name, "high") for name in self.destinations] modules = {} conjunctions = {} with open("inputs/day_20.txt") as file: for line in file: if line.startswith("broadcaster"): starting_destinations = ( line.split(" -> ")[1].rstrip("\n").split(", ") ) else: halves = line.split(" -> ") kind = (FlipFlop, Conjunction)[halves[0][0] == "&"] name = halves[0][1:] destinations = halves[1].rstrip("\n").split(", ") modules[name] = kind(destinations) if kind == Conjunction: conjunctions[name] = modules[name] if "rx" in destinations: final_conjunction = modules[name] for conjunction_name, conjunction in conjunctions.items(): connected_modules = [] if conjunction_name in starting_destinations: connected_modules.append("broadcaster") for name, module in modules.items(): if conjunction_name in module.destinations: connected_modules.append(name) conjunction.init_memory(connected_modules) low_pulses = 1000 high_pulses = 0 presses = 1 cycles = {name:None for name in final_conjunction.memory} while presses <= 1000 or any(cycle is None for cycle in cycles.values()): pulses = [("broadcaster", name, "low") for name in starting_destinations] while pulses: next_pulses = [] for pulse in pulses: if ( pulse[0] in cycles and pulse[2] == "high" and cycles[pulse[0]] is None ): cycles[pulse[0]] = presses if pulse[1] in modules: for next_pulse in modules[pulse[1]].recieve( pulse[0], pulse[2] ): next_pulses.append((pulse[1],) + next_pulse) if presses <= 1000: if pulse[2] == "low": low_pulses += 1 else: high_pulses += 1 pulses = next_pulses presses += 1 print(f"Part 1: {low_pulses * high_pulses}") print(f"Part 2: {lcm(*cycles.values())}")
-
Comment on Day 19: Aplenty in ~comp.advent_of_code
lily (edited )LinkToday's problem was a lot of fun. I was glad for the easier problem after not having time to finish yesterday's part 2. This one reminded me a bit of day 5, what with having to use ranges for part...Today's problem was a lot of fun. I was glad for the easier problem after not having time to finish yesterday's part 2. This one reminded me a bit of day 5, what with having to use ranges for part 2. My solution ended up being pretty long, but I think it's reasonably efficient.
Solution
# Advent of Code 2023 # Day 19: Aplenty from copy import deepcopy from functools import reduce from json import loads from operator import mul from re import sub workflows = {} parts = [] with open("inputs/day_19.txt") as file: half = 0 for line in file: if half == 0: if line == "\n": half = 1 else: halves = line.split("{") halves[1] = halves[1].rstrip("\n")[:-1] conditions = [] for condition in halves[1].split(","): if condition == "A": conditions.append(True) elif condition == "R": conditions.append(False) elif ":" not in condition: conditions.append(condition) else: condition_halves = condition.split(":") if condition_halves[1] == "A": result = True elif condition_halves[1] == "R": result = False else: result = condition_halves[1] conditions.append(( condition_halves[0][1], "xmas".index(condition_halves[0][0]), int(condition_halves[0][2:]), result )) workflows[halves[0]] = conditions else: parts.append(list(loads(sub( r"([xmas])=", r'"\g<1>": ', line.rstrip("\n") )).values())) rating_sum = 0 for part in parts: workflow = workflows["in"] done = False while not done: for condition in workflow: if condition == True: rating_sum += sum(part) done = True break elif condition == False: done = True break elif isinstance(condition, str): workflow = workflows[condition] else: if condition[0] == "<": pass_ = part[condition[1]] < condition[2] else: pass_ = part[condition[1]] > condition[2] if pass_: if condition[3] == True: rating_sum += sum(part) done = True elif condition[3] == False: done = True else: workflow = workflows[condition[3]] break print(f"Part 1: {rating_sum}") states = (["in", [1, 4000], [1, 4000], [1, 4000], [1, 4000]],) combinations = 0 while states: new_states = [] for state in states: for condition in workflows[state[0]]: if condition == True: combinations += reduce( mul, (range_[1] - range_[0] + 1 for range_ in state[1:]) ) break elif isinstance(condition, str): state[0] = condition new_states.append(state) break elif condition != False: state_pass = deepcopy(state) range_pass = state_pass[condition[1] + 1] range_pass[condition[0] == "<"] = ( condition[2] + (1, -1)[condition[0] == "<"] ) state[condition[1] + 1][condition[0] == ">"] = condition[2] if range_pass[0] <= range_pass[1]: if condition[3] == True: combinations += reduce(mul, ( range_[1] - range_[0] + 1 for range_ in state_pass[1:] )) elif condition[3] != False: state_pass[0] = condition[3] new_states.append(state_pass) states = new_states print(f"Part 2: {combinations}")
-
Comment on Tildes Game Giveaway: Holiday 2023 in ~games
lily If Broken Age is still available that would be great. As for a holiday tradition, as a kid I always used to get two stockings: one on Christmas Day, and one on New Year's Eve. I never really...If Broken Age is still available that would be great. As for a holiday tradition, as a kid I always used to get two stockings: one on Christmas Day, and one on New Year's Eve. I never really thought much about it, to be honest. But other than that I don't think we ever did much interesting.
-
Comment on Day 17: Clumsy Crucible in ~comp.advent_of_code
lily Forgot to post this last night. It could've been a lot faster if I'd used another algorithm like A*, but I was lazy and Djikstra was fast enough that I didn't think I needed to bother implementing...Forgot to post this last night. It could've been a lot faster if I'd used another algorithm like A*, but I was lazy and Djikstra was fast enough that I didn't think I needed to bother implementing anything else. I was glad to finally see this year's requisite pathfinding problem, though I thought it wasn't an especially interesting example of one.
Solution
# Advent of Code 2023 # Day 17: Clumsy Crucible import heapq with open("inputs/day_17.txt") as file: loss_map = [[int(char) for char in line.rstrip("\n")] for line in file] width = len(loss_map[0]) height = len(loss_map) class Node: def __init__(self, x, y, direction, consecutive, heat_loss, part): self.x = x self.y = y self.direction = direction self.consecutive = consecutive self.heat_loss = heat_loss self.part = part def __lt__(self, other): return self.heat_loss < other.heat_loss heap = [Node(0, 0, None, 0, 0, 1), Node(0, 0, None, 0, 0, 2)] heapq.heapify(heap) seen = set() end_x = width - 1 end_y = height - 1 while heap: current = heapq.heappop(heap) if current.x == end_x and current.y == end_y: print(f"Part {current.part}: {current.heat_loss}") for node in heap.copy(): if node.part == current.part: heap.remove(node) continue for new_pos in ( (current.x + 1, current.y, "right"), (current.x, current.y + 1, "down"), (current.x - 1, current.y, "left"), (current.x, current.y - 1, "up") ): if ( 0 <= new_pos[0] < width and 0 <= new_pos[1] < height and not ( current.direction == "right" and new_pos[2] == "left" or current.direction == "down" and new_pos[2] == "up" or current.direction == "left" and new_pos[2] == "right" or current.direction == "up" and new_pos[2] == "down" ) and not ( current.direction == new_pos[2] and current.consecutive == (3, 10)[current.part - 1] ) ): node = Node( *new_pos, ( current.consecutive + 1 if current.direction == new_pos[2] else 1 ), current.heat_loss + loss_map[new_pos[1]][new_pos[0]], current.part ) if current.part == 2 and node.consecutive == 1: if node.direction == "right": change = (1, 0) elif node.direction == "down": change = (0, 1) elif node.direction == "left": change = (-1, 0) else: change = (0, -1) for i in range(3): node.x += change[0] node.y += change[1] try: node.heat_loss += loss_map[node.y][node.x] except IndexError: pass node.consecutive = 4 values = (node.x, node.y, node.direction, node.consecutive) if values not in seen: heapq.heappush(heap, node) seen.add(values)
-
Comment on Tildes Game Giveaway: Holiday 2023 in ~games
lily Xer Kzesfrums Istyms Hocktoo sounds lovely; those are all genres I enjoy. As for an upbeat song, I never get tired of the VVVVVV soundtrack. Thanks for your generosity!Xer Kzesfrums Istyms Hocktoo sounds lovely; those are all genres I enjoy. As for an upbeat song, I never get tired of the VVVVVV soundtrack. Thanks for your generosity!
-
Comment on Tildes Game Giveaway: Holiday 2023 in ~games
lily I'd be interested in Rakuen and Cocoon. I'll do the opening quote from a game I just played recently, Slay the Princess (which I recommend highly if you haven't tried it, by the way): "Whatever...I'd be interested in Rakuen and Cocoon. I'll do the opening quote from a game I just played recently, Slay the Princess (which I recommend highly if you haven't tried it, by the way): "Whatever horrors you may find in these dark spaces, have heart and see them through. There are no premature endings. There are no wrong answers. There are only fresh perspectives and new beginnings. This is a love story."
Thanks for doing this!
-
Comment on Day 16: The Floor Will Be Lava in ~comp.advent_of_code
lily Only just got to this problem now, but it really didn't take long. Didn't have time to make my solution any faster, but it's not slow enough to be a big deal, so I don't mind keeping it like this....Only just got to this problem now, but it really didn't take long. Didn't have time to make my solution any faster, but it's not slow enough to be a big deal, so I don't mind keeping it like this. I was honestly a bit disappointed the naïve solution was enough for today, but to be fair, if it wasn't, I might not have been able to finish the problem before midnight, so I guess I should be grateful. Hopefully tomorrow is a bit more interesting.
Solution
# Advent of Code 2023 # Day 16: The Floor Will Be Lava with open("inputs/day_16.txt") as file: machine = [list(line.rstrip("\n")) for line in file] width = len(machine[0]) height = len(machine) def energized_tiles(x, y, direction): beams = [[x, y, direction]] seen_beams = set() energized = set() while beams: for beam in beams.copy(): if ( beam[0] < 0 or beam[0] >= width or beam[1] < 0 or beam[1] >= height or tuple(beam) in seen_beams ): beams.remove(beam) continue seen_beams.add(tuple(beam)) energized.add((beam[0], beam[1])) tile = machine[beam[1]][beam[0]] if tile == "/": if beam[2] == "right": beam[2] = "up" elif beam[2] == "down": beam[2] = "left" elif beam[2] == "left": beam[2] = "down" else: beam[2] = "right" elif tile == "\\": if beam[2] == "right": beam[2] = "down" elif beam[2] == "down": beam[2] = "right" elif beam[2] == "left": beam[2] = "up" else: beam[2] = "left" elif tile == "|" and beam[2] in ("right", "left"): beam[2] = "down" beams.append([beam[0], beam[1] - 1, "up"]) elif tile == "-" and beam[2] in ("down", "up"): beam[2] = "right" beams.append([beam[0] - 1, beam[1], "left"]) if beam[2] == "right": beam[0] += 1 elif beam[2] == "down": beam[1] += 1 elif beam[2] == "left": beam[0] -= 1 else: beam[1] -= 1 return len(energized) print(f"Part 1: {energized_tiles(0, 0, 'right')}") starts = [] for x in range(width): starts.append([x, 0, "down"]) starts.append([x, height - 1, "up"]) for y in range(height): starts.append([0, y, "right"]) starts.append([width - 1, y, "left"]) print(f"Part 2: {max(energized_tiles(*start) for start in starts)}")
-
Comment on Day 15: Lens Library in ~comp.advent_of_code
lily Surprisingly easy for day 15, though I wasn't quite as fast as I would've liked (I'm posting quite a bit later, but I finished in around 22 minutes or so). I expected the part 2 twist to be more...Surprisingly easy for day 15, though I wasn't quite as fast as I would've liked (I'm posting quite a bit later, but I finished in around 22 minutes or so). I expected the part 2 twist to be more difficult than it ended up being.
Solution
# Advent of Code 2023 # Day 15: Lens Library def hash_(s): current = 0 for char in s: current += ord(char) current *= 17 current %= 256 return current hash_sum = 0 boxes = [[] for _ in range(256)] with open("inputs/day_15.txt") as file: for step in file.read().rstrip("\n").split(","): hash_sum += hash_(step) label = "".join(char for char in step if char.isalpha()) label_len = len(label) box = boxes[hash_(label)] if step[label_len] == "=": existing = False for lens in box: if lens[0] == label: lens[1] = int(step[label_len + 1]) existing = True break if not existing: box.append([label, int(step[label_len + 1])]) else: for lens in box: if lens[0] == label: box.remove(lens) break print(f"Part 1: {hash_sum}") focusing_power = 0 for i, box in enumerate(boxes): for j, lens in enumerate(box): old = focusing_power focusing_power += (i + 1) * (j + 1) * lens[1] print(f"Part 2: {focusing_power}")
-
Comment on Day 14: Reflector Dish in ~comp.advent_of_code
lily Forgot to post this last night. I wasn't quite able to get top 1000 on part 2, but thought I did pretty well otherwise. Part 2 was pretty simple once I realized I needed to detect cycles. Solution...Forgot to post this last night. I wasn't quite able to get top 1000 on part 2, but thought I did pretty well otherwise. Part 2 was pretty simple once I realized I needed to detect cycles.
Solution
# Advent of Code 2023 # Day 14: Parabolic Reflector Dish with open("inputs/day_14.txt") as file: platform = [list(line.rstrip("\n")) for line in file.readlines()] size = len(platform) def total_load(platform): total_load = 0 for y, row in enumerate(platform): for char in row: if char == "O": total_load += size - y return total_load seen = {} part_1_finished = False iteration = 0 while iteration < 1000000000: for _ in range(4): for x in range(size): for y in range(1, size): if platform[y][x] == "O" and platform[y - 1][x] == ".": for new_y in range(y - 1, -1, -1): if platform[new_y][x] != ".": new_y += 1 break platform[y][x] = "." platform[new_y][x] = "O" if not part_1_finished: print(f"Part 1: {total_load(platform)}") part_1_finished = True platform = [list(reversed(row)) for row in zip(*platform)] key = "".join("".join(row) for row in platform) if key in seen: cycle_length = iteration - seen[key] iteration += (1000000000 - iteration) // cycle_length * cycle_length else: seen[key] = iteration iteration += 1 print(f"Part 2: {total_load(platform)}")
-
Comment on Day 12: Hot Spring in ~comp.advent_of_code
lily Wondering if anyone could point me in the right direction for this day's part 2? I tried for hours to get it working but hadn't ever done dynamic programming before and so wasn't able to figure...Wondering if anyone could point me in the right direction for this day's part 2? I tried for hours to get it working but hadn't ever done dynamic programming before and so wasn't able to figure out what to memoize to make my program fast enough.
-
Comment on Day 13: Point of Incidence in ~comp.advent_of_code
lily Was glad for the break after how hard yesterday was (I wasn't able to solve part 2 yesterday, unfortunately, which is why I didn't post my solution). I could probably optimize this quite a bit...Was glad for the break after how hard yesterday was (I wasn't able to solve part 2 yesterday, unfortunately, which is why I didn't post my solution). I could probably optimize this quite a bit further, but I don't really see the need to; it's plenty fast enough as it is. Hopefully the difficulty is a bit more consistent from here on out.
Solution
# Advent of Code 2023 # Day 13: Point of Incidence def find_vertical_reflection(pattern, compare): for x in range(1, len(pattern[0])): left_side = [row[:x] for row in pattern] right_side = [list(reversed(row[x:])) for row in pattern] left_width = len(left_side[0]) right_width = len(right_side[0]) if left_width > right_width: difference = left_width - right_width left_side_adjusted = [row[difference:] for row in left_side] right_side_adjusted = right_side elif right_width > left_width: difference = right_width - left_width left_side_adjusted = left_side right_side_adjusted = [row[difference:] for row in right_side] else: left_side_adjusted = left_side right_side_adjusted = right_side if compare(left_side_adjusted, right_side_adjusted): return left_width return 0 def smudged_compare(left_side, right_side): left_side = [char for row in left_side for char in row] right_side = [char for row in right_side for char in row] return sum( left_side[i] != right_side[i] for i in range(len(left_side)) ) == 1 notes_sum = 0 notes_sum_smudged = 0 with open("inputs/day_13.txt") as file: for pattern in file.read().split("\n\n"): pattern = [list(row.rstrip("\n")) for row in pattern.splitlines()] notes_sum += find_vertical_reflection(pattern, list.__eq__) notes_sum += find_vertical_reflection( [list(row) for row in list(zip(*pattern))[::-1]], list.__eq__ ) * 100 notes_sum_smudged += find_vertical_reflection(pattern, smudged_compare) notes_sum_smudged += find_vertical_reflection( [list(row) for row in list(zip(*pattern))[::-1]], smudged_compare ) * 100 print(f"Part 1: {notes_sum}") print(f"Part 2: {notes_sum_smudged}")
-
Comment on Day 11: Cosmic Expansion in ~comp.advent_of_code
lily Had an irritating error that prevented me from getting a leaderboard spot on part 2, but other than that, today was a nice break after yesterday. I did part 1 pretty naïvely, so had to rewrite my...Had an irritating error that prevented me from getting a leaderboard spot on part 2, but other than that, today was a nice break after yesterday. I did part 1 pretty naïvely, so had to rewrite my solution for part 2.
Solution
# Advent of Code 2023 # Day 11: Cosmic Expansion from itertools import combinations with open("inputs/day_11.txt") as file: image = [list(line[:-1]) for line in file.readlines()] galaxies = [] for y, row in enumerate(image): for x, tile in enumerate(row): if tile == "#": galaxies.append([x, y]) moved_galaxies_part_1 = [galaxy.copy() for galaxy in galaxies] moved_galaxies_part_2 = [galaxy.copy() for galaxy in galaxies] for y, row in enumerate(image): if "#" not in row: for i, galaxy in enumerate(galaxies): if galaxy[1] > y: moved_galaxies_part_1[i][1] += 1 moved_galaxies_part_2[i][1] += 999999 for x in range(len(image[0])): if not any(image[y][x] == "#" for y in range(len(image))): for i, galaxy in enumerate(galaxies): if galaxy[0] > x: moved_galaxies_part_1[i][0] += 1 moved_galaxies_part_2[i][0] += 999999 distance_sum_part_1 = 0 for pair in combinations(moved_galaxies_part_1, 2): distance_sum_part_1 += ( abs(pair[1][0] - pair[0][0]) + abs(pair[1][1] - pair[0][1]) ) print(f"Part 1: {distance_sum_part_1}") distance_sum_part_2 = 0 for pair in combinations(moved_galaxies_part_2, 2): distance_sum_part_2 += ( abs(pair[1][0] - pair[0][0]) + abs(pair[1][1] - pair[0][1]) ) print(f"Part 2: {distance_sum_part_2}")
-
Comment on Day 10: Pipe Maze in ~comp.advent_of_code
lily I was a complete idiot solving this one. I spent multiple hours trying to solve part 2 without increasing the resolution of the grid and without raycasting like @Hvv (I was basically special...I was a complete idiot solving this one. I spent multiple hours trying to solve part 2 without increasing the resolution of the grid and without raycasting like @Hvv (I was basically special casing the individual combinations of characters that could be "squeezed" through; it was horrible), and ended up writing an insanely long and complicated program that didn't actually work. I eventually figured out that I could increase the resolution, and once I did I solved part 2 in about 10 minutes. If I'd figured that out earlier I might've been able to snag a leaderboard spot. But oh well. At least I got top 300 for part 1. I'm not very happy with my solution (it's slow and inelegant), but it works and I don't think I have the energy to improve it any further, haha.
Solution
# Advent of Code 2023 # Day 10: Pipe Maze with open("inputs/day_10.txt") as file: sketch = [list(line[:-1]) for line in file.readlines()] for y, row in enumerate(sketch): for x, tile in enumerate(row): if tile == "S": start_x = x start_y = y width = len(sketch[0]) height = len(sketch) current_x = start_x current_y = start_y if current_x < len(sketch[0]) and sketch[current_y][current_x + 1] in "-J7": current_x += 1 current_dir = "right" elif current_y < height and sketch[current_y + 1][current_x] in "|LJ": current_y += 1 current_dir = "down" elif current_x > 0 and sketch[current_y][current_x - 1] in "-LF": current_x -= 1 current_dir = "left" else: current_y -= 1 current_dir = "up" start_dir = current_dir loop = [(current_x, current_y)] while current_x != start_x or current_y != start_y: tile = sketch[current_y][current_x] if tile == "|": if current_dir == "down": current_y += 1 elif current_dir == "up": current_y -= 1 elif tile == "-": if current_dir == "right": current_x += 1 elif current_dir == "left": current_x -= 1 elif tile == "L": if current_dir == "down": current_x += 1 current_dir = "right" elif current_dir == "left": current_y -= 1 current_dir = "up" elif tile == "J": if current_dir == "right": current_y -= 1 current_dir = "up" elif current_dir == "down": current_x -= 1 current_dir = "left" elif tile == "7": if current_dir == "right": current_y += 1 current_dir = "down" elif current_dir == "up": current_x -= 1 current_dir = "left" elif tile == "F": if current_dir == "left": current_y += 1 current_dir = "down" elif current_dir == "up": current_x += 1 current_dir = "right" loop.append((current_x, current_y)) print(f"Part 1: {len(loop) // 2}") if current_dir == "right": if start_dir == "right": sketch[start_y][start_x] = "-" elif start_dir == "down": sketch[start_y][start_x] = "7" elif start_dir == "up": sketch[start_y][start_x] = "J" elif current_dir == "down": if start_dir == "right": sketch[start_y][start_x] = "L" elif start_dir == "down": sketch[start_y][start_x] = "|" elif start_dir == "left": sketch[start_y][start_x] = "J" elif current_dir == "left": if start_dir == "down": sketch[start_y][start_x] = "F" elif start_dir == "left": sketch[start_y][start_x] = "-" elif start_dir == "up": sketch[start_y][start_x] = "L" elif start_dir == "right": sketch[start_y][start_x] = "F" elif start_dir == "left": sketch[start_y][start_x] = "7" else: sketch[start_y][start_x] = "|" detailed = [[False for _ in range(width * 3)] for _ in range(height * 3)] for y, row in enumerate(sketch): for x, tile in enumerate(row): if (x, y) in loop: if tile == "|": detailed[y * 3][x * 3:x * 3 + 3] = False, True, False detailed[y * 3 + 1][x * 3:x * 3 + 3] = False, True, False detailed[y * 3 + 2][x * 3:x * 3 + 3] = False, True, False elif tile == "-": detailed[y * 3][x * 3:x * 3 + 3] = False, False, False detailed[y * 3 + 1][x * 3:x * 3 + 3] = True, True, True detailed[y * 3 + 2][x * 3:x * 3 + 3] = False, False, False elif tile == "L": detailed[y * 3][x * 3:x * 3 + 3] = False, True, False detailed[y * 3 + 1][x * 3:x * 3 + 3] = False, True, True detailed[y * 3 + 2][x * 3:x * 3 + 3] = False, False, False elif tile == "J": detailed[y * 3][x * 3:x * 3 + 3] = False, True, False detailed[y * 3 + 1][x * 3:x * 3 + 3] = True, True, False detailed[y * 3 + 2][x * 3:x * 3 + 3] = False, False, False elif tile == "7": detailed[y * 3][x * 3:x * 3 + 3] = False, False, False detailed[y * 3 + 1][x * 3:x * 3 + 3] = True, True, False detailed[y * 3 + 2][x * 3:x * 3 + 3] = False, True, False elif tile == "F": detailed[y * 3][x * 3:x * 3 + 3] = False, False, False detailed[y * 3 + 1][x * 3:x * 3 + 3] = False, True, True detailed[y * 3 + 2][x * 3:x * 3 + 3] = False, True, False queue = [] for y, row in enumerate(detailed): if y in (0, height * 3 - 1): search = range(width * 3) else: search = (0, width * 3 - 1) for x in search: if not row[x]: queue.append((x, y)) visited = set() while queue: pos = queue.pop(0) for new_pos in ( (pos[0] + 1, pos[1]), (pos[0], pos[1] + 1), (pos[0] - 1, pos[1]), (pos[0], pos[1] - 1) ): try: if not detailed[new_pos[1]][new_pos[0]] and new_pos not in visited: queue.append(new_pos) visited.add(new_pos) except IndexError: pass inside = 0 for y in range(height): for x in range(width): if ( (x * 3 + 1, y * 3 + 1) not in visited and not detailed[y * 3 + 1][x * 3 + 1] ): inside += 1 print(f"Part 2: {inside}")
-
Comment on Day 9: Mirage Maintenance in ~comp.advent_of_code
lily Now that I think about it, part of what made this problem feel so easy was that the entire solution was basically described in the problem text itself. I feel like that wasn't really necessary...Now that I think about it, part of what made this problem feel so easy was that the entire solution was basically described in the problem text itself. I feel like that wasn't really necessary...
-
Comment on Day 9: Mirage Maintenance in ~comp.advent_of_code
lily Well, this one was... weirdly easy. And part 2 was almost exactly the same difficulty as part 1. It took me about a minute. I feel this problem would be much better suited for around day 4....Well, this one was... weirdly easy. And part 2 was almost exactly the same difficulty as part 1. It took me about a minute. I feel this problem would be much better suited for around day 4.
Solution
# Advent of Code 2023 # Day 9: Mirage Maintenance histories = [] with open("inputs/day_9.txt") as file: for line in file: histories.append([int(n) for n in line.split(" ")]) next_prediction_sum = 0 prev_prediction_sum = 0 for history in histories: right_ends = [history[-1]] left_ends = [history[0]] working = history.copy() while True: for i in range(len(working) - 1, -1, -1): if i >= 1: working[i] = working[i] - working[i - 1] working = working[1:] if all(n == working[0] for n in working): next_prediction = working[-1] prev_prediction = working[0] for n in reversed(right_ends): next_prediction += n for n in reversed(left_ends): prev_prediction = n - prev_prediction next_prediction_sum += next_prediction prev_prediction_sum += prev_prediction break else: right_ends.append(working[-1]) left_ends.append(working[0]) print(f"Part 1: {next_prediction_sum}") print(f"Part 2: {prev_prediction_sum}")
-
Comment on Day 8: Haunted Wasteland in ~comp.advent_of_code
lily Really fun problem, and felt just about the right level of difficulty for this far into the month. The solution was clever, but not too hard to figure out - I like solutions like that, since they...Really fun problem, and felt just about the right level of difficulty for this far into the month. The solution was clever, but not too hard to figure out - I like solutions like that, since they make me feel smart ;)
I solved the problem a while before posting this, but took some time to assemble a nice program that solves both parts at once and to write actual input parsing (I initially just copied the input into my program and used a regex to convert it to a Python dictionary). I got top 400 on part 1, but unfortunately wasn't quite so fast doing part 2.
(Also, yes, I know the input parsing is horrible. It's just Advent of Code though, it's fine I promise)
Solution
# Advent of Code 2023 # Day 8: Haunted Wasteland import math graph = {} with open("inputs/day_8.txt") as file: for i, line in enumerate(file): if i == 0: instructions = line.rstrip("\n") elif i > 1: graph[line[:3]] = (line[7:10], line[12:15]) def next_location(graph, location): return graph[location]["LR".index(instructions[steps % len(instructions)])] steps = 0 location = "AAA" while location != "ZZZ": location = next_location(graph, location) steps += 1 print(f"Part 1: {steps}") locations = [location for location in graph if location[-1] == "A"] steps_per_location = [] for i in range(len(locations)): steps = 0 z_count = 0 while z_count < 2: locations[i] = next_location(graph, locations[i]) steps += 1 if locations[i][-1] == "Z": if z_count == 0: steps = 0 z_count += 1 steps_per_location.append(steps) print(f"Part 2: {math.lcm(*steps_per_location)}")
-
Comment on Day 7: Camel Cards in ~comp.advent_of_code
lily This was a fun problem, though I think I might have overcomplicated things a bit. I always like to try to write a single program that does both part 1 and 2 at once if possible, and that was a...This was a fun problem, though I think I might have overcomplicated things a bit. I always like to try to write a single program that does both part 1 and 2 at once if possible, and that was a little trickier than usual today. Nevertheless, I'm glad the problems are more interesting now. Today's still wasn't too difficult (especially compared to day 5), but it wasn't just parsing the input like the first few. Part 2 probably could have changed things up a bit more, though.
Solution
# Advent of Code 2023 # Day 7: Camel Cards from copy import deepcopy from functools import cmp_to_key special_cards = { "T": 10, "J": 11, "Q": 12, "K": 13, "A": 14 } hands_part_1 = [] with open("inputs/day_7.txt") as file: for line in file: halves = line.split(" ") hands_part_1.append({ "cards": [ int(card) if card in "123456789" else special_cards[card] for card in halves[0] ], "bid": int(halves[1]) }) hands_part_2 = deepcopy(hands_part_1) for hand in hands_part_2: hand["cards"] = [0 if card == 11 else card for card in hand["cards"]] def find_type(cards): set_ = set(cards) unique_cards = len(set_) if unique_cards == 1: return 0 elif unique_cards == 2: if cards.count(cards[0]) in (1, 4): return 1 else: return 2 elif unique_cards == 3: if any(cards.count(card) == 3 for card in set_): return 3 elif any(cards.count(card) == 2 for card in set_): return 4 elif unique_cards == 4: return 5 else: return 6 for hand in hands_part_1: hand["type"] = find_type(hand["cards"]) for hand in hands_part_2: if 0 in hand["cards"]: hand["type"] = None for new_card in range(15): if new_card != 0: modified_cards = [ new_card if card == 0 else card for card in hand["cards"] ] type_ = find_type(modified_cards) if hand["type"] is None or type_ < hand["type"]: hand["type"] = type_ else: hand["type"] = find_type(hand["cards"]) def compare_hands(hand_1, hand_2): if hand_1["type"] < hand_2["type"]: return 1 elif hand_2["type"] < hand_1["type"]: return -1 else: for card_1, card_2 in zip(hand_1["cards"], hand_2["cards"]): if card_1 > card_2: return 1 elif card_2 > card_1: return -1 return 0 key = cmp_to_key(compare_hands) hands_part_1.sort(key=key) hands_part_2.sort(key=key) print(f"""Part 1: { sum(hand['bid'] * (i + 1) for i, hand in enumerate(hands_part_1)) }""") print(f"""Part 2: { sum(hand['bid'] * (i + 1) for i, hand in enumerate(hands_part_2)) }""")
-
Comment on Day 5: If You Give A Seed A Fertilizer in ~comp.advent_of_code
lily I was going to wait to post here until I wrote a solution that wasn't brute force, but I haven't been able to. I figured out what I'm supposed to do, but for some reason I can only get my program...I was going to wait to post here until I wrote a solution that wasn't brute force, but I haven't been able to. I figured out what I'm supposed to do, but for some reason I can only get my program to work with either the test input or the proper input, not both. The only way I can get the correct answer for the proper input is by forcing my program to have what I believe is the incorrect behavior? It's really weird. Since it's been a day and I haven't figured it out, though, I'll just post my brute force solution from last night.
Solution
# Advent of Code 2023 # Day 5: If You Give A Seed A Fertilizer mappings = [] with open("inputs/day_5.txt") as file: current = {} waiting_for_nums = True for i, line in enumerate(file): if i == 0: seeds = [int(n) for n in line.split(": ")[1].split()] else: if line[0] in "0123456789": nums = [int(n) for n in line.split()] current[range(nums[1], nums[1] + nums[2])] = nums[0] - nums[1] waiting_for_nums = False elif not waiting_for_nums: mappings.append(current) current = {} waiting_for_nums = True mappings.append(current) def find_lowest_location(seeds, mappings): lowest_location = None for seed in seeds: current = seed for depth in mappings: for range_ in depth: if current in range_: current += depth[range_] break if lowest_location is None or current < lowest_location: lowest_location = current return lowest_location print(f"Part 1: {find_lowest_location(seeds, mappings)}") def seeds_part_2(): for start, length in zip(seeds[0::2], seeds[1::2]): for seed in range(start, start + length): yield seed print(f"Part 2: {find_lowest_location(seeds_part_2(), mappings)}")
-
Comment on Day 6: Wait For It in ~comp.advent_of_code
lily I wasted time on parsing or I would've done better. Should've just copied the values straight into my code and I probably could've gotten a leaderboard spot. But oh well, can't win 'em all....I wasted time on parsing or I would've done better. Should've just copied the values straight into my code and I probably could've gotten a leaderboard spot. But oh well, can't win 'em all.
Solution
# Advent of Code 2023 # Day 6: Wait For It from functools import reduce from operator import mul with open("inputs/day_6.txt") as file: line_1 = next(file) line_2 = next(file) races_part_1 = list(zip( (int(n) for n in line_1.split()[1:]), (int(n) for n in line_2.split()[1:]) )) race_part_2 = ( int("".join(line_1.split()[1:])), int("".join(line_2.split()[1:])) ) def find_ways(race): ways = 0 for hold_duration in range(1, race[0]): distance = (race[0] - hold_duration) * hold_duration if distance > race[1]: ways += 1 return ways print(f"Part 1: {reduce(mul, (find_ways(race) for race in races_part_1))}") print(f"Part 2: {find_ways(race_part_2)}")
I should've been faster with this one. I haven't done a great job at finishing the last few problems, but today's wasn't too bad thanks to NetworkX doing most of the work for me. I might go back to this at some point and try to implement the algorithm myself, but I don't have time for that right now.
Solution