lily's recent activity

lily
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...

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
``````# Advent of Code 2023

import networkx

graph = {}

with open("inputs/day_25.txt") as file:
for line in file:
component = line[:3]

if component in graph:
graph[component].update(set(line[5:].rstrip("\n").split(" ")))
else:
graph[component] = set(line[5:].rstrip("\n").split(" "))

for other in graph[component]:
if other not in graph:
graph[other] = set([component])
else:

to_remove = tuple(networkx.minimum_edge_cut(networkx.from_dict_of_lists(graph)))

for edge in to_remove:
graph[edge[0]].remove(edge[1])
graph[edge[1]].remove(edge[0])

product = 1

for edge in to_remove[0]:
queue = [edge]
seen = set()

while queue:
current = queue.pop(0)

for next_ in graph[current]:
if next_ not in seen:
queue.append(next_)

product *= len(seen)

print(f"Part 1: {product}")
``````
2. Comment on Day 20: Pulse Propagation in ~comp.advent_of_code

lily
(edited )
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...

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:
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:

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())}")
``````
1 vote
3. Comment on Day 19: Aplenty in ~comp.advent_of_code

lily
(edited )
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...

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 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:
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}")
``````
4. 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.

1 vote
5. 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)
``````
1 vote
6. 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!

7. 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!

1 vote
8. 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

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)}")
``````
1 vote
9. 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:
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}")
``````
1 vote
10. 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)

for y, row in enumerate(platform):
for char in row:
if char == "O":

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:
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

``````
1 vote
11. 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.

12. 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]
elif right_width > left_width:
difference = right_width - left_width
right_side_adjusted = [row[difference:] for row in right_side]
else:

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:
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}")
``````
13. 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}")
``````
14. 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)
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}")
``````
1 vote
15. 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...

16. 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}")
``````
1 vote
17. 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)}")
``````
18. 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))
}""")
``````
19. 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)}")
``````
1 vote
20. 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)}")
``````
1 vote