Compare commits
12 Commits
acbbbd329d
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| bac2144c17 | |||
| 8d97abb44f | |||
| f40997cc1b | |||
| 45ddaf4247 | |||
| 82357f660e | |||
| b34b8fce66 | |||
| 24cd18c21d | |||
| 2d9b37be55 | |||
| 482d5e4aa7 | |||
| a449964cbe | |||
| 4e8bd8a60c | |||
| 8ba8eaa55f |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1 +1,4 @@
|
||||
all.py
|
||||
__pycache__
|
||||
*.txt
|
||||
*.md
|
||||
|
||||
40
README.md
40
README.md
@@ -1,18 +1,44 @@
|
||||
# Times
|
||||
Done with this. Overall everything is solvable. It's more about consistency
|
||||
and focus. Of course, learning more algorithms and techniques helps.
|
||||
|
||||
Possible to-dos:
|
||||
|
||||
- [ ] Optimize day 19 because it is terrible.
|
||||
|
||||
# Times (and comments)
|
||||
|
||||
- Day 1: 7:52 ... so slow brah :/ top 100 required 2:05...
|
||||
- Day 2: 22:30 ... I mistyped the first and second was just bad top 100 would have been 6:16 (doable?)
|
||||
- Day 2: 22:30 ... I mistyped the first and second was just bad top 100 would
|
||||
have been 6:16 (doable?)
|
||||
- Day 3: 13:08 actually decent but top 100 required 5:24
|
||||
- Day 4: 7:08 but top 100 required 3:33 still okay
|
||||
- Day 5: 11:56 but 7:58 for top 100... getting better?
|
||||
- Day 6: 3:50 but 2:25 for leaderboard :D
|
||||
- Day 7: 27:55 and 14:47 for leaderboard; okay, I would say
|
||||
- Day 8: 61:00 and 10:00 for leaderboard; I need template code for searching coordinate systems
|
||||
- Day 8: 61:00 and 10:00 for leaderboard; I need template code for searching
|
||||
coordinate systems
|
||||
- Day 9: 58:00 and 7:32 for leaderboard; I need code for 2D stuff
|
||||
- Day 10: 25:20 and 12:17 for leaderboard; okay, okay
|
||||
- Day 11: 45:00 and 18:00 for leaderboard; arg, it was doable man
|
||||
- Day 12: 39:45 and 9:46 for leaderboard; the people are ready for there searches :D
|
||||
- Day 13: 44:00 and 12:56 for leaderboard; these people are just good, seriously
|
||||
- Day 12: 39:45 and 9:46 for leaderboard; the people are ready for their
|
||||
searches :D
|
||||
- Day 13: 44:00 and 12:56 for leaderboard; these people are just good,
|
||||
seriously
|
||||
- Day 14: 35:00 and 14:54; I just have to get that much quicker... 2D code!
|
||||
- Day 15: 150:00 and 27:00; I didn't use Manhatten dist initially, lot's of debugging
|
||||
- Day 16:
|
||||
- Day 15: 150:00 and 27:00; I didn't use Manhattan dist initially, lot's of
|
||||
debugging
|
||||
- Day 16: 52:00 and 64:00; ARE YOU SAYING I WOULD HAVE MADE THE
|
||||
LEADERBOARD?!?!?!?!?!?!?!
|
||||
- Day 17: Second one was fun with having to detect the repetition.
|
||||
- Day 18: 12:00 and 32:00; really straightforward and of course way too slow.
|
||||
- Day 19: Slow.
|
||||
- Day 20: Struggled way too much.
|
||||
- Day 21: Straightforward and relatively fast.
|
||||
- Day 22: Very hard and wasn't able to do hands free. Even the best guys took
|
||||
over an hour.
|
||||
- Day 23: Super straightforward, but took me way longer than it should have
|
||||
because I loose focus and make silly errors. Like back in Middleschool.
|
||||
- Day 24: Easy. Should have been faster, but no crazy mistakes. Still way too
|
||||
slow for something easy like this.
|
||||
- Day 25: Quickly solved via constraint solver. Actual solution much simpler. Don't know
|
||||
if I would have been able to figure it out.
|
||||
|
||||
72
d1.py
72
d1.py
@@ -1,64 +1,20 @@
|
||||
import re
|
||||
from lib import *
|
||||
|
||||
EXAMPLE = """
|
||||
1000
|
||||
2000
|
||||
3000
|
||||
|
||||
4000
|
||||
|
||||
5000
|
||||
6000
|
||||
|
||||
7000
|
||||
8000
|
||||
9000
|
||||
|
||||
10000
|
||||
"""
|
||||
|
||||
def solve(lines: list[str]):
|
||||
counter = 0
|
||||
count_max = 0
|
||||
for line in lines.splitlines():
|
||||
if line.strip() == "":
|
||||
if counter >= count_max:
|
||||
count_max = counter
|
||||
counter = 0
|
||||
else:
|
||||
counter += int(line)
|
||||
return count_max
|
||||
|
||||
def solve2(lines: list[str]):
|
||||
counter = 0
|
||||
count_max = 0
|
||||
counts = []
|
||||
for line in lines.splitlines():
|
||||
if line.strip() == "":
|
||||
if counter >= count_max:
|
||||
count_max = counter
|
||||
counts.append(counter)
|
||||
counter = 0
|
||||
else:
|
||||
counter += int(line)
|
||||
counts.append(counter)
|
||||
|
||||
counts.sort(reverse=True)
|
||||
return sum(counts[:3])
|
||||
def solve(input: Input, second=False):
|
||||
ps = input.text.split("\n\n")
|
||||
xss = map(lambda p: map(int, p.splitlines()), ps)
|
||||
xs = list(map(sum, xss))
|
||||
if not second:
|
||||
return max(xs)
|
||||
xs.sort()
|
||||
return sum(xs[-3:])
|
||||
|
||||
def main():
|
||||
example = str(EXAMPLE)
|
||||
print("Example 1:", solve(example))
|
||||
|
||||
data = open("i1.txt").read()
|
||||
print("Solution 1:", solve(data))
|
||||
|
||||
example = str(EXAMPLE)
|
||||
print("Example 2:", solve2(example))
|
||||
|
||||
data = open("i1.txt").read()
|
||||
print("Solution 2:", solve2(data))
|
||||
return
|
||||
DAY_INPUT = "i1.txt"
|
||||
print("Solution 1:", solve(Input(DAY_INPUT)))
|
||||
assert solve(Input(DAY_INPUT)) == 69883
|
||||
print("Solution 2:", solve(Input(DAY_INPUT), True))
|
||||
assert solve(Input(DAY_INPUT), True) == 207576
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
4
d15.py
4
d15.py
@@ -73,7 +73,7 @@ def solve(lines: list[str], yt):
|
||||
sensors = []
|
||||
bacons = set()
|
||||
for (i, line) in enumerate(lines):
|
||||
digits = lib.str_to_int_list(line)
|
||||
digits = lib.str_to_ints(line)
|
||||
sx, sy, bx, by = digits
|
||||
sm = mdist(bx - sx, by - sy)
|
||||
sensors.append([sx, sy, sm])
|
||||
@@ -102,7 +102,7 @@ def solve2(lines: list[str], xymax):
|
||||
sensors = []
|
||||
bacons = set()
|
||||
for (i, line) in enumerate(lines):
|
||||
digits = lib.str_to_int_list(line)
|
||||
digits = lib.str_to_ints(line)
|
||||
sx, sy, bx, by = digits
|
||||
sm = mdist(bx - sx, by - sy)
|
||||
sensors.append([sx, sy, sm])
|
||||
|
||||
100
d16.py
Normal file
100
d16.py
Normal file
@@ -0,0 +1,100 @@
|
||||
import lib
|
||||
|
||||
EXAMPLE = """
|
||||
Valve AA has flow rate=0; tunnels lead to valves DD, II, BB
|
||||
Valve BB has flow rate=13; tunnels lead to valves CC, AA
|
||||
Valve CC has flow rate=2; tunnels lead to valves DD, BB
|
||||
Valve DD has flow rate=20; tunnels lead to valves CC, AA, EE
|
||||
Valve EE has flow rate=3; tunnels lead to valves FF, DD
|
||||
Valve FF has flow rate=0; tunnels lead to valves EE, GG
|
||||
Valve GG has flow rate=0; tunnels lead to valves FF, HH
|
||||
Valve HH has flow rate=22; tunnel leads to valve GG
|
||||
Valve II has flow rate=0; tunnels lead to valves AA, JJ
|
||||
Valve JJ has flow rate=21; tunnel leads to valve II
|
||||
"""
|
||||
|
||||
def solve(lines: list[str]):
|
||||
nodes = {}
|
||||
for (i, line) in enumerate(lines):
|
||||
source = line.split(" ")[1]
|
||||
to_valves = list(map(lambda v: v.replace(",", ""), line.split(" ")[9:]))
|
||||
flow_rate = lib.str_to_int(line)
|
||||
nodes[source] = (flow_rate, to_valves)
|
||||
|
||||
|
||||
options = [(0, 0, "AA", ())]
|
||||
visited = set()
|
||||
for _ in range(30):
|
||||
new_options = []
|
||||
for (total, flow, current, valves) in options:
|
||||
valve_flow_rate = nodes[current][0]
|
||||
if not current in valves and valve_flow_rate > 0:
|
||||
o = (total + flow, flow + valve_flow_rate, current, valves + (current, ))
|
||||
new_options.append(o)
|
||||
for new_valve in nodes[current][1]:
|
||||
o = (total + flow, flow, new_valve, valves)
|
||||
new_options.append(o)
|
||||
|
||||
options = sorted(list(set(new_options)))[-100:]
|
||||
return options[-1][0]
|
||||
|
||||
|
||||
def solve2(lines: list[str]):
|
||||
nodes = {}
|
||||
for (i, line) in enumerate(lines):
|
||||
source = line.split(" ")[1]
|
||||
to_valves = list(map(lambda v: v.replace(",", ""), line.split(" ")[9:]))
|
||||
flow_rate = lib.str_to_int(line)
|
||||
nodes[source] = (flow_rate, to_valves)
|
||||
|
||||
options = [(0, 0, ("AA", "AA"), ())]
|
||||
for _ in range(26):
|
||||
new_options = []
|
||||
for (total, flow, (a, b), valves) in options:
|
||||
flow_a = nodes[a][0]
|
||||
flow_b = nodes[b][0]
|
||||
|
||||
# a turns on b moves
|
||||
if not a in valves and flow_a > 0:
|
||||
for new_valve_b in nodes[b][1]:
|
||||
o = (total + flow, flow + flow_a, (a, new_valve_b), valves + (a, ))
|
||||
new_options.append(o)
|
||||
|
||||
# a moves and b turns on
|
||||
if not b in valves and flow_b > 0:
|
||||
for new_valve_a in nodes[a][1]:
|
||||
o = (total + flow, flow + flow_b, (new_valve_a, b), valves + (b, ))
|
||||
new_options.append(o)
|
||||
|
||||
# both turn on
|
||||
if a != b and flow_a > 0 and flow_b > 0 and not a in valves and not b in valves:
|
||||
o = (total + flow, flow + flow_a + flow_b, (a, b), valves + (a, b, ))
|
||||
new_options.append(o)
|
||||
|
||||
# both move
|
||||
for new_valve_a in nodes[a][1]:
|
||||
for new_valve_b in nodes[b][1]:
|
||||
o = (total + flow, flow, (new_valve_a, new_valve_b), valves)
|
||||
new_options.append(o)
|
||||
|
||||
options = sorted(list(set(new_options)))[-1000:]
|
||||
# 52:00
|
||||
return options[-1][0]
|
||||
|
||||
|
||||
def main():
|
||||
lines = lib.str_to_lines_no_empty(EXAMPLE)
|
||||
print("Example 1:", solve(lines))
|
||||
|
||||
lines = lib.str_to_lines_no_empty(open("i16.txt").read())
|
||||
print("Solution 1:", solve(lines))
|
||||
|
||||
lines = lib.str_to_lines_no_empty(EXAMPLE)
|
||||
print("Example 2:", solve2(lines))
|
||||
|
||||
lines = lib.str_to_lines_no_empty(open("i16.txt").read())
|
||||
print("Solution 2:", solve2(lines))
|
||||
assert solve2(lines) == 2591
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
119
d17.py
Normal file
119
d17.py
Normal file
@@ -0,0 +1,119 @@
|
||||
from lib import *
|
||||
|
||||
EXAMPLE = """>>><<><>><<<>><>>><<<>>><<<><<<>><>><<>>"""
|
||||
|
||||
ROCKS = [
|
||||
[(0, 0), (0, 1), (0, 2), (0, 3)],
|
||||
[(0, 1), (-1, 0), (-1, 1), (-1, 2), (-2, 1)],
|
||||
[(0, 0), (0, 1), (0, 2), (-1, 2), (-2, 2)],
|
||||
[(0, 0), (-1, 0), (-2, 0), (-3, 0)],
|
||||
[(0, 0), (0, 1), (-1, 0), (-1, 1)],
|
||||
]
|
||||
|
||||
def printfall(coords):
|
||||
row_coords = list(map(lambda c: c[0], coords))
|
||||
col_coords = list(map(lambda c: c[1], coords))
|
||||
min_row, max_row = min(row_coords), max(row_coords)
|
||||
min_col, max_col = min(col_coords), max(col_coords)
|
||||
|
||||
s = ""
|
||||
for r in range(min_row, max_row + 1):
|
||||
for c in range(min_col, max_col + 1):
|
||||
s += "."
|
||||
s += "\n"
|
||||
g = Input(s).grid2()
|
||||
for c in coords:
|
||||
c = (c[0] + -min_row, c[1])
|
||||
g[tuple(c)] = "#"
|
||||
g.print()
|
||||
print()
|
||||
|
||||
def solve(input: Input, second=False):
|
||||
BLOWS = list(input.text.strip())
|
||||
width, blow_index = 7, 0
|
||||
|
||||
heighest = [0 for _ in range(width)]
|
||||
rocks = set([(0, i) for i in range(width)])
|
||||
|
||||
if second:
|
||||
target = 1000000000000
|
||||
nhs = {}
|
||||
else:
|
||||
target = 2022
|
||||
|
||||
i = 0
|
||||
while i < target:
|
||||
rock = ROCKS[i % len(ROCKS)]
|
||||
pos = (min(heighest) - 4, 2)
|
||||
|
||||
if second and i > 0 and all(abs(heighest[i] - heighest[i + 1]) <= 2 for i in range(len(heighest) - 1)):
|
||||
# long winded code to find repeating sequence
|
||||
nh = tuple([h - min(heighest) for h in heighest])
|
||||
if nh in nhs:
|
||||
nhs[nh].append((i, heighest[0]))
|
||||
else:
|
||||
nhs[nh] = [(i, heighest[0])]
|
||||
xs = nhs[nh]
|
||||
if len(xs) > 4 and all(xs[1][0] - xs[0][0] == xs[i + 1][0] - xs[i][0] for i in range(len(xs) - 1)):
|
||||
# we found a repeating sequence and can skip forward
|
||||
di = xs[-1][0] - xs[-2][0]
|
||||
dh = xs[-1][1] - xs[-2][1]
|
||||
repeat = (target - i) // di
|
||||
i += repeat * di
|
||||
heighest = [h + repeat * dh for h in heighest]
|
||||
for c, r in enumerate(heighest):
|
||||
rocks.add((r, c))
|
||||
nhs = {}
|
||||
continue
|
||||
|
||||
falling = True
|
||||
while falling:
|
||||
blow = BLOWS[blow_index % len(BLOWS)]
|
||||
blow_index += 1
|
||||
|
||||
dc = None
|
||||
if blow == ">":
|
||||
dc = 1
|
||||
elif blow == "<":
|
||||
dc = -1
|
||||
|
||||
for (ro, co) in rock:
|
||||
r = pos[0] + ro
|
||||
c = pos[1] + co + dc
|
||||
if c < 0 or c >= width or (r, c) in rocks:
|
||||
break
|
||||
else:
|
||||
pos = (pos[0], pos[1] + dc)
|
||||
|
||||
for (ro, co) in rock:
|
||||
r = pos[0] + ro + 1
|
||||
c = pos[1] + co
|
||||
if (r, c) in rocks:
|
||||
falling = False
|
||||
break
|
||||
else:
|
||||
pos = (pos[0] + 1, pos[1])
|
||||
|
||||
for (ro, co) in rock:
|
||||
r = pos[0] + ro
|
||||
c = pos[1] + co
|
||||
rocks.add((r, c))
|
||||
heighest[c] = min(heighest[c], r)
|
||||
|
||||
i += 1
|
||||
|
||||
return -min(heighest)
|
||||
|
||||
def main():
|
||||
_, day = extract_year_and_date(__file__)
|
||||
DAY_INPUT = f"i{day}.txt"
|
||||
print("Example 1:", solve(Input(EXAMPLE)))
|
||||
s1 = solve(Input(DAY_INPUT))
|
||||
assert s1 == 3102
|
||||
print("Solution 1:", s1)
|
||||
print("Example 2:", solve(Input(EXAMPLE), True))
|
||||
print("Solution 2:", solve(Input(DAY_INPUT), True))
|
||||
assert solve(Input(DAY_INPUT), True) == 1539823008825
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
71
d18.py
Normal file
71
d18.py
Normal file
@@ -0,0 +1,71 @@
|
||||
from lib import *
|
||||
|
||||
EXAMPLE = """2,2,2
|
||||
1,2,2
|
||||
3,2,2
|
||||
2,1,2
|
||||
2,3,2
|
||||
2,2,1
|
||||
2,2,3
|
||||
2,2,4
|
||||
2,2,6
|
||||
1,2,5
|
||||
3,2,5
|
||||
2,1,5
|
||||
2,3,5
|
||||
"""
|
||||
|
||||
|
||||
def solve(input: Input, second=False):
|
||||
cubes = set([tuple(map(int, l.split(",")))for l in input.text.splitlines()])
|
||||
res = len(cubes) * 6
|
||||
|
||||
if second:
|
||||
min_x = min([c[0] for c in cubes]) - 1
|
||||
max_x = max([c[0] for c in cubes]) + 1
|
||||
min_y = min([c[1] for c in cubes]) - 1
|
||||
max_y = max([c[1] for c in cubes]) + 1
|
||||
min_z = min([c[2] for c in cubes]) - 1
|
||||
max_z = max([c[2] for c in cubes]) + 1
|
||||
surrounded = set([(x, y, z)
|
||||
for x in range(min_x, max_x + 1)
|
||||
for y in range(min_y, max_y + 1)
|
||||
for z in range(min_z, max_z + 1)])
|
||||
surrounded -= cubes
|
||||
vs = [(min_x, min_y, min_z)]
|
||||
while vs:
|
||||
(x, y, z) = vs.pop()
|
||||
for dx, dy, dz in [(1, 0, 0), (-1, 0, 0), (0, 1, 0), (0, -1, 0), (0, 0, 1), (0, 0, -1)]:
|
||||
t = x + dx, y + dy, z + dz
|
||||
if t in surrounded:
|
||||
surrounded.remove(t)
|
||||
vs.append(t)
|
||||
for x, y, z in list(surrounded):
|
||||
for dx, dy, dz in [(1, 0, 0), (-1, 0, 0), (0, 1, 0), (0, -1, 0), (0, 0, 1), (0, 0, -1)]:
|
||||
nc = x + dx, y + dy, z + dz
|
||||
if nc in cubes:
|
||||
res -= 1
|
||||
|
||||
for x, y, z in list(cubes):
|
||||
for dx, dy, dz in [(1, 0, 0), (-1, 0, 0), (0, 1, 0), (0, -1, 0), (0, 0, 1), (0, 0, -1)]:
|
||||
nc = x + dx, y + dy, z + dz
|
||||
if nc in cubes:
|
||||
res -= 1
|
||||
return res
|
||||
|
||||
def main():
|
||||
DAY_INPUT = "i18.txt"
|
||||
|
||||
print("Example 1:", solve(Input(EXAMPLE)))
|
||||
print("Solution 1:", solve(Input(DAY_INPUT)))
|
||||
# 10:30........
|
||||
|
||||
print("Example 2:", solve(Input(EXAMPLE), True))
|
||||
print("Solution 2:", solve(Input(DAY_INPUT), True))
|
||||
assert solve(Input(DAY_INPUT), True) == 2064
|
||||
# 30:00
|
||||
|
||||
return
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
117
d19.py
Normal file
117
d19.py
Normal file
@@ -0,0 +1,117 @@
|
||||
from lib import *
|
||||
|
||||
EXAMPLE = """
|
||||
Blueprint 1:
|
||||
Each ore robot costs 4 ore.
|
||||
Each clay robot costs 2 ore.
|
||||
Each obsidian robot costs 3 ore and 14 clay.
|
||||
Each geode robot costs 2 ore and 7 obsidian.
|
||||
|
||||
Blueprint 2:
|
||||
Each ore robot costs 2 ore.
|
||||
Each clay robot costs 3 ore.
|
||||
Each obsidian robot costs 3 ore and 8 clay.
|
||||
Each geode robot costs 3 ore and 12 obsidian.
|
||||
"""
|
||||
|
||||
def solve(input: Input, second=False):
|
||||
if not second:
|
||||
res = 0
|
||||
else:
|
||||
res = 1
|
||||
bps = []
|
||||
for line in input.text.replace(".", ".\n").replace(":", ":\n").splitlines():
|
||||
if "Blueprint" in line:
|
||||
bps.append([])
|
||||
elif "ore robot" in line:
|
||||
cost = str_to_ints(line)
|
||||
cost += [0, 0]
|
||||
bps[-1].append(cost)
|
||||
elif "clay robot" in line:
|
||||
cost = str_to_ints(line)
|
||||
cost += [0, 0]
|
||||
bps[-1].append(cost)
|
||||
elif "obsidian robot" in line:
|
||||
cost = str_to_ints(line)
|
||||
cost += [0,]
|
||||
bps[-1].append(cost)
|
||||
elif "geode robot" in line:
|
||||
cost = str_to_ints(line)
|
||||
cost.insert(1, 0)
|
||||
bps[-1].append(cost)
|
||||
|
||||
if second:
|
||||
bps = bps[:3]
|
||||
time = 32
|
||||
else:
|
||||
time = 24
|
||||
|
||||
end_states = []
|
||||
for i, bp in enumerate(bps):
|
||||
# ((ore bots, clay bots, obs bots, geo bots), (ore, clay, obs, geo))
|
||||
start = ((1, 0, 0, 0), (0, 0, 0, 0))
|
||||
states = [start]
|
||||
seen = set(states)
|
||||
|
||||
for _ in range(time):
|
||||
new_states = []
|
||||
while states:
|
||||
bots, ress = states.pop()
|
||||
|
||||
add_ress = [0, 0, 0, 0]
|
||||
for boti, count in enumerate(bots):
|
||||
add_ress[boti] += count
|
||||
|
||||
all_built = True
|
||||
for boti, cost in enumerate(bp):
|
||||
if ress[0] >= cost[0] and ress[1] >= cost[1] and ress[2] >= cost[2]:
|
||||
new_ress = list(ress)
|
||||
new_ress[0] -= cost[0]
|
||||
new_ress[1] -= cost[1]
|
||||
new_ress[2] -= cost[2]
|
||||
new_ress = tuple(map(sum, zip(new_ress, add_ress)))
|
||||
new_bots = list(bots)
|
||||
new_bots[boti] += 1
|
||||
new_state = (tuple(new_bots), new_ress)
|
||||
if not new_state in seen:
|
||||
new_states.append(new_state)
|
||||
seen.add(new_state)
|
||||
else:
|
||||
all_built = False
|
||||
|
||||
# XXX: our search space is too large here it is possible to
|
||||
# optimze by not storing reduntant paths (paths where we acrue
|
||||
# more of a resource than we need), but I don't know how to
|
||||
# make it more efficient right now.
|
||||
if not all_built:
|
||||
new_ress = tuple(map(sum, zip(ress, add_ress)))
|
||||
new_state = (bots, new_ress)
|
||||
if not new_state in seen:
|
||||
new_states.append(new_state)
|
||||
seen.add(new_state)
|
||||
|
||||
# prune to keep search space "reasonable"
|
||||
states = sorted(new_states, key=lambda s: list(reversed(s[0])), reverse=True)[:100000]
|
||||
|
||||
if not second:
|
||||
r = max(states, key=lambda s: s[1][3])
|
||||
q = (i + 1) * r[1][3]
|
||||
# print(i + 1, r, q)
|
||||
res += q
|
||||
else:
|
||||
r = max(states, key=lambda r: r[1][3])
|
||||
res *= r[1][3]
|
||||
return res
|
||||
|
||||
def main():
|
||||
DAY_INPUT = "i19.txt"
|
||||
e1 = solve(Input(EXAMPLE))
|
||||
print("Example 1:", e1)
|
||||
assert e1 == 33
|
||||
print("Solution 1:", solve(Input(DAY_INPUT)))
|
||||
print("Example 2:", solve(Input(EXAMPLE), True))
|
||||
print("Solution 2:", solve(Input(DAY_INPUT), True))
|
||||
return
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
2
d2.py
2
d2.py
@@ -85,12 +85,14 @@ def main():
|
||||
|
||||
data = clean(open("i2.txt").read())
|
||||
print("Solution 1:", solve(data))
|
||||
assert solve(data) == 14069
|
||||
|
||||
example = clean(EXAMPLE)
|
||||
print("Example 2:", solve2(example))
|
||||
|
||||
data = clean(open("i2.txt").read())
|
||||
print("Solution 2:", solve2(data))
|
||||
assert solve2(data) == 12411
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
73
d20.py
Normal file
73
d20.py
Normal file
@@ -0,0 +1,73 @@
|
||||
from lib import *
|
||||
|
||||
EXAMPLE = """1
|
||||
2
|
||||
-3
|
||||
3
|
||||
-2
|
||||
0
|
||||
4
|
||||
"""
|
||||
|
||||
|
||||
def move(xs, i, move):
|
||||
move = move % (len(xs) - 1)
|
||||
ni = (i + move + 1) % len(xs)
|
||||
xsi, xs[i] = xs[i], None
|
||||
xs.insert(ni, xsi)
|
||||
xs.remove(None)
|
||||
return xs
|
||||
|
||||
|
||||
def asserts():
|
||||
assert move([1, 2, 3], 0, 0) == [1, 2, 3]
|
||||
assert move([1, 2, 3], 0, 1) == [2, 1, 3]
|
||||
assert move([1, 2, 3], 0, 2) == [1, 2, 3]
|
||||
assert move([1, 2, 3], 0, 3) == [2, 1, 3]
|
||||
assert move([1, 2, 3], 0, 4) == [1, 2, 3]
|
||||
assert move([1, 2, 3], 0, 5) == [2, 1, 3]
|
||||
assert move([1, 2, 3], 0, 2) == [1, 2, 3]
|
||||
assert move([3, 2, 1], 2, 1) == [3, 1, 2]
|
||||
assert move([3, 2, 1], 2, 2) == [1, 3, 2]
|
||||
|
||||
assert move([4, -2, 5, 6, 7, 8, 9,], 1, -2) == [4, 5, 6, 7, 8, -2, 9]
|
||||
assert move([1, 2, -2, -3, 0, 3, 4], 2, -2) == [-2, 1, 2, -3, 0, 3, 4]
|
||||
|
||||
|
||||
def solve(input: Input, second=False):
|
||||
xs = list(map(int, input.lines()))
|
||||
if second:
|
||||
xs = list(map(lambda n: n * 811589153, xs))
|
||||
ys = list(range(len(xs)))
|
||||
oys = ys[:]
|
||||
|
||||
repeat = 1
|
||||
if second:
|
||||
repeat = 10
|
||||
for _ in range(repeat):
|
||||
for o in oys:
|
||||
i = ys.index(o)
|
||||
movev = xs[o]
|
||||
move(ys, i, movev)
|
||||
|
||||
xs = [xs[i] for i in ys]
|
||||
s = 0
|
||||
i0 = xs.index(0)
|
||||
for i in range(1, 4):
|
||||
ni = (i0 + i * 1000) % len(ys)
|
||||
s += xs[ni]
|
||||
return s
|
||||
|
||||
|
||||
def main():
|
||||
DAY_INPUT = "i20.txt"
|
||||
print("Example 1:", solve(Input(EXAMPLE)))
|
||||
print("Solution 1:", solve(Input(DAY_INPUT)))
|
||||
print("Example 2:", solve(Input(EXAMPLE), True))
|
||||
print("Solution 2:", solve(Input(DAY_INPUT), True))
|
||||
assert solve(Input(DAY_INPUT), True) == 6704537992933
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asserts()
|
||||
main()
|
||||
105
d21.py
Normal file
105
d21.py
Normal file
@@ -0,0 +1,105 @@
|
||||
from lib import *
|
||||
|
||||
EXAMPLE = """root: pppw + sjmn
|
||||
dbpl: 5
|
||||
cczh: sllz + lgvd
|
||||
zczc: 2
|
||||
ptdq: humn - dvpt
|
||||
dvpt: 3
|
||||
lfqf: 4
|
||||
humn: 5
|
||||
ljgn: 2
|
||||
sjmn: drzm * dbpl
|
||||
sllz: 4
|
||||
pppw: cczh / lfqf
|
||||
lgvd: ljgn * ptdq
|
||||
drzm: hmdt - zczc
|
||||
hmdt: 32
|
||||
"""
|
||||
|
||||
def resolve(monkeys, s):
|
||||
equ = monkeys[s]
|
||||
try:
|
||||
return int(equ)
|
||||
except ValueError:
|
||||
pass
|
||||
l, op, r = equ.split(" ")
|
||||
l = resolve(monkeys, l)
|
||||
r = resolve(monkeys, r)
|
||||
res = eval(f"{l}{op}{r}")
|
||||
monkeys[s] = res
|
||||
return res
|
||||
|
||||
|
||||
def resolve2(monkeys, s):
|
||||
if s == "humn":
|
||||
return tuple()
|
||||
|
||||
equ = monkeys[s]
|
||||
try:
|
||||
return int(equ)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
l, op, r = equ.split(" ")
|
||||
if s == "root":
|
||||
op = "=="
|
||||
|
||||
l = resolve2(monkeys, l)
|
||||
r = resolve2(monkeys, r)
|
||||
|
||||
if isinstance(l, tuple) or isinstance(r, tuple):
|
||||
return (l, op, r)
|
||||
if op == "/":
|
||||
op = "//"
|
||||
res = eval(f"{l}{op}{r}")
|
||||
monkeys[s] = res
|
||||
return res
|
||||
|
||||
|
||||
def simplify(equ, exp):
|
||||
if equ == tuple():
|
||||
return exp
|
||||
l, op, r = equ
|
||||
if op == '/' and isinstance(r, int):
|
||||
return simplify(l, exp * r)
|
||||
elif op == '+' and isinstance(l, int):
|
||||
return simplify(r, exp - l)
|
||||
elif op == '+' and isinstance(r, int):
|
||||
return simplify(l, exp - r)
|
||||
elif op == '-' and isinstance(l, int):
|
||||
return simplify(r, -(exp - l))
|
||||
elif op == '-' and isinstance(r, int):
|
||||
return simplify(l, exp + r)
|
||||
elif op == '*' and isinstance(r, int):
|
||||
return simplify(l, exp // r)
|
||||
elif op == '*' and isinstance(l, int):
|
||||
return simplify(r, exp // l)
|
||||
|
||||
|
||||
def solve(input: Input, second=False):
|
||||
res = 0
|
||||
monkeys = {}
|
||||
for line in input.lines():
|
||||
l, r = line.split(": ")
|
||||
monkeys[l] = r
|
||||
|
||||
if not second:
|
||||
return int(resolve(monkeys, "root"))
|
||||
else:
|
||||
equ = resolve2(monkeys, "root")
|
||||
assert equ[1] == '=='
|
||||
return simplify(equ[0], equ[2])
|
||||
|
||||
|
||||
def main():
|
||||
DAY_INPUT = "i21.txt"
|
||||
print("Example 1:", solve(Input(EXAMPLE)))
|
||||
print("Solution 1:", solve(Input(DAY_INPUT)))
|
||||
print("Example 2:", solve(Input(EXAMPLE), True))
|
||||
print("Solution 2:", solve(Input(DAY_INPUT), True))
|
||||
assert solve(Input(DAY_INPUT), True) == 3243420789721
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
237
d22.py
Normal file
237
d22.py
Normal file
@@ -0,0 +1,237 @@
|
||||
from lib import *
|
||||
|
||||
EXAMPLE = """ 0..#
|
||||
.#..
|
||||
#...
|
||||
....
|
||||
1..#2...3..#
|
||||
........#...
|
||||
..#....#....
|
||||
..........#.
|
||||
4..#5...
|
||||
.....#..
|
||||
.#......
|
||||
......#.
|
||||
|
||||
10R5L5R10L4R5L5"""
|
||||
|
||||
|
||||
E = (0, 1)
|
||||
S = (1, 0)
|
||||
W = (0, -1)
|
||||
N = (-1, 0)
|
||||
|
||||
DIRS = [
|
||||
E,
|
||||
S,
|
||||
W,
|
||||
N,
|
||||
]
|
||||
|
||||
# XXX: not hands free - i created this manually probably there is some way to
|
||||
# figure it out from the input, but id don't know how right now.
|
||||
trans_example = {
|
||||
(0, N): (1, S),
|
||||
(0, E): (5, W),
|
||||
(0, S): (3, S),
|
||||
(0, W): (2, S),
|
||||
(1, N): (0, S),
|
||||
(1, E): (2, E),
|
||||
(1, S): (4, N),
|
||||
(1, W): (5, N),
|
||||
(2, N): (0, E),
|
||||
(2, E): (3, E),
|
||||
(2, S): (4, E),
|
||||
(2, W): (1, W),
|
||||
(3, N): (0, N),
|
||||
(3, E): (5, S),
|
||||
(3, S): (4, S),
|
||||
(3, W): (2, W),
|
||||
(4, N): (3, N),
|
||||
(4, E): (5, E),
|
||||
(4, S): (1, N),
|
||||
(4, W): (2, N),
|
||||
(5, N): (3, W),
|
||||
(5, E): (0, W),
|
||||
(5, S): (1, E),
|
||||
(5, W): (4, W),
|
||||
}
|
||||
|
||||
trans_input = {
|
||||
(0, N): (5, E),
|
||||
(0, E): (1, E),
|
||||
(0, S): (2, S),
|
||||
(0, W): (3, E),
|
||||
(1, N): (5, N),
|
||||
(1, E): (4, W),
|
||||
(1, S): (2, W),
|
||||
(1, W): (0, W),
|
||||
(2, N): (0, N),
|
||||
(2, E): (1, N),
|
||||
(2, S): (4, S),
|
||||
(2, W): (3, S),
|
||||
(3, N): (2, E),
|
||||
(3, E): (4, E),
|
||||
(3, S): (5, S),
|
||||
(3, W): (0, E),
|
||||
(4, N): (2, N),
|
||||
(4, E): (1, W),
|
||||
(4, S): (5, W),
|
||||
(4, W): (3, W),
|
||||
(5, N): (3, N),
|
||||
(5, E): (4, N),
|
||||
(5, S): (1, S),
|
||||
(5, W): (0, S),
|
||||
}
|
||||
|
||||
def parse_steps(steps):
|
||||
insts = re.compile(r"(\d+)([LR])").findall(steps)
|
||||
lastn = re.compile(r"\d+").findall(steps)[-1]
|
||||
insts.append((lastn, None))
|
||||
return insts
|
||||
|
||||
|
||||
def solve(input: Input):
|
||||
grid, steps = input.text.split("\n\n")
|
||||
insts = parse_steps(steps)
|
||||
|
||||
grid = list(map(list, grid.splitlines()))
|
||||
rows = len(grid)
|
||||
|
||||
startcol = 0
|
||||
while grid[0][startcol] == ' ':
|
||||
startcol += 1
|
||||
pos = (0, startcol)
|
||||
dir = (0, 1)
|
||||
for n, turn in insts:
|
||||
nrow, ncol = pos
|
||||
for _ in range(int(n)):
|
||||
nrow = (nrow + dir[0]) % rows
|
||||
ncol = (ncol + dir[1]) % len(grid[nrow])
|
||||
while grid[nrow][ncol] == ' ':
|
||||
nrow = (nrow + dir[0]) % rows
|
||||
ncol = (ncol + dir[1]) % len(grid[nrow])
|
||||
if grid[nrow][ncol] == '#':
|
||||
break
|
||||
pos = (nrow, ncol)
|
||||
if turn is not None:
|
||||
dir = DIRS[(DIRS.index(dir) + 1 if turn == 'R' else DIRS.index(dir) - 1) % 4]
|
||||
|
||||
return 1000 * (pos[0] + 1) + 4 * (pos[1] + 1) + DIRS.index(dir)
|
||||
|
||||
|
||||
def solve2(input: Input, square_size=4):
|
||||
squares = []
|
||||
grid, steps = input.text.split("\n\n")
|
||||
insts = parse_steps(steps)
|
||||
grid_rows = grid.splitlines()
|
||||
for r in range(0, len(grid_rows), square_size):
|
||||
for c in range(0, len(grid_rows[r]), square_size):
|
||||
square = []
|
||||
for sr in range(r, r + square_size):
|
||||
square.append(grid_rows[sr][c:c+square_size])
|
||||
if square[0][0] != ' ':
|
||||
squares.append(square)
|
||||
|
||||
def flip(n):
|
||||
return square_size - 1 - n
|
||||
|
||||
def teleport(dir, sqi, row, col):
|
||||
if square_size == 4:
|
||||
nsqi, ndir = trans_example[(sqi, dir)]
|
||||
elif square_size == 50:
|
||||
nsqi, ndir = trans_input[(sqi, dir)]
|
||||
else:
|
||||
assert False
|
||||
nrow, ncol = None, None
|
||||
|
||||
if ndir == N:
|
||||
nrow = square_size - 1
|
||||
elif ndir == S:
|
||||
nrow = 0
|
||||
elif ndir == E:
|
||||
ncol = 0
|
||||
elif ndir == W:
|
||||
ncol = square_size - 1
|
||||
|
||||
if dir == N:
|
||||
if ndir == N:
|
||||
ncol = col
|
||||
elif ndir == S:
|
||||
ncol = flip(col)
|
||||
elif ndir == E:
|
||||
nrow = col
|
||||
elif ndir == W:
|
||||
nrow = square_size - 1 - col
|
||||
elif dir == S:
|
||||
if ndir == N:
|
||||
ncol = flip(col)
|
||||
elif ndir == S:
|
||||
ncol = col
|
||||
elif ndir == E:
|
||||
nrow = square_size - 1 - col
|
||||
elif ndir == W:
|
||||
nrow = col
|
||||
elif dir == E:
|
||||
if ndir == N:
|
||||
ncol = row
|
||||
elif ndir == S:
|
||||
ncol = flip(row)
|
||||
elif ndir == E:
|
||||
nrow = row
|
||||
elif ndir == W:
|
||||
nrow = square_size - 1 - row
|
||||
elif dir == W:
|
||||
if ndir == N:
|
||||
ncol = flip(row)
|
||||
elif ndir == S:
|
||||
ncol = row
|
||||
elif ndir == E:
|
||||
nrow = flip(row)
|
||||
elif ndir == W:
|
||||
nrow = row
|
||||
|
||||
assert nrow is not None
|
||||
assert ncol is not None
|
||||
return ndir, nsqi, nrow, ncol
|
||||
|
||||
# for square in squares:
|
||||
# print("\n".join(square), "\n")
|
||||
|
||||
dir, sqi, row, col = E, 0, 0, 0
|
||||
for n, turn in insts:
|
||||
# print(f"{sqi=} {row=} {col=} {dir=}")
|
||||
for _ in range(int(n)):
|
||||
nrow = row + dir[0]
|
||||
ncol = col + dir[1]
|
||||
if nrow < 0 or nrow >= square_size or ncol < 0 or ncol >= square_size:
|
||||
ndir, nsqi, nrow, ncol = teleport(dir, sqi, nrow, ncol)
|
||||
else:
|
||||
ndir, nsqi = dir, sqi
|
||||
if squares[nsqi][nrow][ncol] != '#':
|
||||
dir, sqi, row, col = ndir, nsqi, nrow, ncol
|
||||
if turn is not None:
|
||||
dir = DIRS[(DIRS.index(dir) + 1 if turn == 'R' else DIRS.index(dir) - 1) % 4]
|
||||
print(f"{sqi=} {row=} {col=} {dir=}")
|
||||
|
||||
if square_size == 4:
|
||||
# sqi=2 row=0 col=2 dir=(-1, 0)
|
||||
return 1000 * (4 + 0 + 1) + 4 * (4 + 2 + 1) + DIRS.index((-1, 0))
|
||||
elif square_size == 50:
|
||||
# sqi=1 row=11 col=14 dir=(0, -1)
|
||||
return 1000 * (0 + 11 + 1) + 4 * (100 + 14 + 1) + DIRS.index((0, -1))
|
||||
else:
|
||||
assert False
|
||||
|
||||
def main():
|
||||
DAY_INPUT = "i22.txt"
|
||||
print("Example 1:", solve(Input(EXAMPLE)))
|
||||
print("Solution 1:", solve(Input(DAY_INPUT)))
|
||||
assert solve(Input(DAY_INPUT)) == 149250
|
||||
|
||||
print("Example 2:", solve2(Input(EXAMPLE)))
|
||||
print("Solution 2:", solve2(Input("i22.txt"), 50))
|
||||
return
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
120
d23.py
Normal file
120
d23.py
Normal file
@@ -0,0 +1,120 @@
|
||||
from lib import *
|
||||
|
||||
EXAMPLE = """....#..
|
||||
..###.#
|
||||
#...#.#
|
||||
.#...##
|
||||
#.###..
|
||||
##.#.##
|
||||
.#..#..
|
||||
"""
|
||||
|
||||
# EXAMPLE = """.....
|
||||
# ..##.
|
||||
# ..#..
|
||||
# .....
|
||||
# ..##.
|
||||
# .....
|
||||
# """
|
||||
|
||||
N = (-1, 0)
|
||||
NE = (-1, 1)
|
||||
E = (0, 1)
|
||||
SE = (1, 1)
|
||||
S = (1, 0)
|
||||
SW = (1, -1)
|
||||
W = (0, -1)
|
||||
NW = (-1, -1)
|
||||
|
||||
adj8 = [
|
||||
N,
|
||||
NE,
|
||||
E,
|
||||
SE,
|
||||
S,
|
||||
SW,
|
||||
W,
|
||||
NW,
|
||||
]
|
||||
|
||||
def print_field(elves):
|
||||
rmin, rmax = min(map(fst, elves)), max(map(fst, elves))
|
||||
cmin, cmax = min(map(snd, elves)), max(map(snd, elves))
|
||||
count = 0
|
||||
for row in range(rmin, rmax + 1):
|
||||
rs = ""
|
||||
for col in range(cmin, cmax + 1):
|
||||
if (row, col) in elves:
|
||||
rs += "#"
|
||||
else:
|
||||
rs += "."
|
||||
count += 1
|
||||
print(rs)
|
||||
print()
|
||||
return count
|
||||
|
||||
def solve(input: Input, second=False):
|
||||
dirs_to_check = [
|
||||
(N, NE, NW),
|
||||
(S, SE, SW),
|
||||
(W, NW, SW),
|
||||
(E, NE, SE),
|
||||
]
|
||||
|
||||
round = 0
|
||||
elves = input.grid2().find('#')
|
||||
while True:
|
||||
# print_field(elves)
|
||||
nes = set()
|
||||
proposed_fields = {}
|
||||
for e in list(elves):
|
||||
for o in adj8:
|
||||
adj = (e[0] + o[0], e[1] + o[1])
|
||||
if adj in elves:
|
||||
break
|
||||
else:
|
||||
nes.add(e)
|
||||
continue
|
||||
|
||||
proposed_field = None
|
||||
for dirs in dirs_to_check:
|
||||
for o in dirs:
|
||||
adj = (e[0] + o[0], e[1] + o[1])
|
||||
if adj in elves:
|
||||
break
|
||||
else:
|
||||
o = dirs[0]
|
||||
proposed_field = (e[0] + o[0], e[1] + o[1])
|
||||
break
|
||||
|
||||
if proposed_field is None:
|
||||
nes.add(e)
|
||||
elif proposed_field in proposed_fields:
|
||||
proposed_fields[proposed_field].append(e)
|
||||
else:
|
||||
proposed_fields[proposed_field] = [e]
|
||||
|
||||
for ne, olves in proposed_fields.items():
|
||||
if len(olves) == 1:
|
||||
nes.add(ne)
|
||||
else:
|
||||
for e in olves:
|
||||
nes.add(e)
|
||||
|
||||
dirs_to_check = dirs_to_check[1:] + dirs_to_check[:1]
|
||||
round += 1
|
||||
if second and elves == nes:
|
||||
return round
|
||||
elif not second and round == 10:
|
||||
return print_field(nes)
|
||||
elves = nes
|
||||
|
||||
def main():
|
||||
DAY_INPUT = "i23.txt"
|
||||
print("Example 1:", solve(Input(EXAMPLE)))
|
||||
print("Solution 1:", solve(Input(DAY_INPUT)))
|
||||
print("Example 2:", solve(Input(EXAMPLE), True))
|
||||
print("Solution 2:", solve(Input(DAY_INPUT), True))
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
93
d24.py
Normal file
93
d24.py
Normal file
@@ -0,0 +1,93 @@
|
||||
from lib import *
|
||||
|
||||
EXAMPLE = """#.#####
|
||||
#.....#
|
||||
#>....#
|
||||
#.....#
|
||||
#...v.#
|
||||
#.....#
|
||||
#####.#
|
||||
"""
|
||||
|
||||
EXAMPLE = """#.######
|
||||
#>>.<^<#
|
||||
#.<..<<#
|
||||
#>v.><>#
|
||||
#<^v^^>#
|
||||
######.#
|
||||
"""
|
||||
|
||||
B2DIR = {
|
||||
">": (0, 1),
|
||||
"v": (1, 0),
|
||||
"<": (0, -1),
|
||||
"^": (-1, 0),
|
||||
}
|
||||
|
||||
ADJ5 = [
|
||||
(-1, 0),
|
||||
(0, 1),
|
||||
(1, 0),
|
||||
(0, -1),
|
||||
(0, 0),
|
||||
]
|
||||
|
||||
def solve(input: Input, second=False):
|
||||
g = input.grid2()
|
||||
start = (0, g.rows()[0].index('.'))
|
||||
poss = set([(start, 0)])
|
||||
end = (g.n_rows - 1, g.rows()[-1].index('.'))
|
||||
bzs = []
|
||||
for d in B2DIR.keys():
|
||||
for b in g.find(d):
|
||||
bzs.append((b, B2DIR[d]))
|
||||
|
||||
for time in range(10**9):
|
||||
nbzs = []
|
||||
bzsset = set()
|
||||
for pos, dir in bzs:
|
||||
row, col = add2(pos, dir)
|
||||
if row == 0:
|
||||
row = g.n_rows - 2
|
||||
elif row == g.n_rows - 1:
|
||||
row = 1
|
||||
if col == 0:
|
||||
col = g.n_cols - 2
|
||||
elif col == g.n_cols - 1:
|
||||
col = 1
|
||||
nbzs.append(((row, col), dir))
|
||||
bzsset.add((row, col))
|
||||
bzs = nbzs
|
||||
|
||||
nposs = set()
|
||||
while poss:
|
||||
pos, round = poss.pop()
|
||||
for adj in ADJ5:
|
||||
npos = add2(pos, adj)
|
||||
if npos[0] < 0 or npos[0] >= g.n_rows or npos[1] < 0 or npos[1] >= g.n_cols:
|
||||
continue
|
||||
if not second:
|
||||
if npos not in bzsset and g[npos] != '#':
|
||||
nposs.add((npos, round))
|
||||
if npos == end:
|
||||
return time + 1
|
||||
else:
|
||||
if npos == end and round == 0:
|
||||
nposs.add((npos, round + 1))
|
||||
elif npos == end and round == 2:
|
||||
return time + 1
|
||||
elif npos == start and round == 1:
|
||||
nposs.add((npos, round + 1))
|
||||
elif npos not in bzsset and g[npos] != '#':
|
||||
nposs.add((npos, round))
|
||||
poss = nposs
|
||||
|
||||
def main():
|
||||
DAY_INPUT = "i24.txt"
|
||||
print("Example 1:", solve(Input(EXAMPLE)))
|
||||
print("Solution 1:", solve(Input(DAY_INPUT)))
|
||||
print("Example 2:", solve(Input(EXAMPLE), True))
|
||||
print("Solution 2:", solve(Input(DAY_INPUT), True))
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
82
d25.py
Normal file
82
d25.py
Normal file
@@ -0,0 +1,82 @@
|
||||
from lib import *
|
||||
|
||||
EXAMPLE = """1=-0-2
|
||||
12111
|
||||
2=0=
|
||||
21
|
||||
2=01
|
||||
111
|
||||
20012
|
||||
112
|
||||
1=-1=
|
||||
1-12
|
||||
12
|
||||
1=
|
||||
122
|
||||
"""
|
||||
|
||||
def snafu_to_dec(n: str) -> int:
|
||||
r = 0
|
||||
for i, c in enumerate(reversed(n)):
|
||||
c = "=-012".index(c) - 2
|
||||
r += c * 5**i
|
||||
return r
|
||||
|
||||
def dec_to_snafu(n: int) -> str:
|
||||
r = ""
|
||||
while n != 0:
|
||||
rem = n % 5
|
||||
n //= 5
|
||||
if rem <= 2:
|
||||
r = str(rem) + r
|
||||
else:
|
||||
r = " =-"[rem] + r
|
||||
n += 1
|
||||
return r
|
||||
|
||||
def dec_to_snafu_cs(n: int) -> str:
|
||||
import cpmpy as cp
|
||||
import numpy as np
|
||||
size = 20
|
||||
xs = cp.intvar(-2, 2, shape=size, name="xs")
|
||||
ns = np.array([5**i for i in range(size)])
|
||||
m = cp.Model(cp.sum(ns * xs) == n)
|
||||
m.solve()
|
||||
|
||||
value = xs.value()
|
||||
assert value is not None
|
||||
# print(value)
|
||||
|
||||
r = ""
|
||||
for v in value:
|
||||
if v >= 0:
|
||||
r += str(v)
|
||||
elif v == -1:
|
||||
r += "-"
|
||||
elif v == -2:
|
||||
r += "="
|
||||
else:
|
||||
assert False
|
||||
r = "".join(reversed(r))
|
||||
r = r.lstrip("0")
|
||||
return r
|
||||
|
||||
def solve(input: Input):
|
||||
res = 0
|
||||
for s in input.lines():
|
||||
d = snafu_to_dec(s)
|
||||
res += d
|
||||
try:
|
||||
assert dec_to_snafu_cs(res) == dec_to_snafu(res)
|
||||
except ModuleNotFoundError:
|
||||
print("Install 'cpmpy' to solve with constraint solver.")
|
||||
return dec_to_snafu(res)
|
||||
|
||||
def main():
|
||||
DAY_INPUT = "i25.txt"
|
||||
print("Example 1:", solve(Input(EXAMPLE)))
|
||||
print("Solution 1:", solve(Input(DAY_INPUT)))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
37
dx.py
37
dx.py
@@ -1,37 +0,0 @@
|
||||
import lib
|
||||
|
||||
EXAMPLE = """
|
||||
"""
|
||||
|
||||
def solve(lines: list[str]):
|
||||
res = 0
|
||||
for (i, line) in enumerate(lines):
|
||||
print(i, line)
|
||||
# digits = lib.str_to_int_list(line)
|
||||
# digit = lib.str_to_single_int(line)
|
||||
return res
|
||||
|
||||
def solve2(lines: list[str]):
|
||||
res = 0
|
||||
for (i, line) in enumerate(lines):
|
||||
print(i, line)
|
||||
return res
|
||||
|
||||
def main():
|
||||
lines = lib.str_to_lines_no_empty(EXAMPLE)
|
||||
print("Example 1:", solve(lines))
|
||||
return
|
||||
|
||||
lines = lib.str_to_lines_no_empty(open("ix.txt").read())
|
||||
print("Solution 1:", solve(lines))
|
||||
return
|
||||
|
||||
lines = lib.str_to_lines_no_empty(EXAMPLE)
|
||||
print("Example 2:", solve2(lines))
|
||||
return
|
||||
|
||||
lines = lib.str_to_lines_no_empty(open("ix.txt").read())
|
||||
print("Solution 2:", solve2(lines))
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
18
lib.py
18
lib.py
@@ -1,18 +0,0 @@
|
||||
import re
|
||||
|
||||
def str_to_single_int(line: str) -> int:
|
||||
line = line.replace(" ", "")
|
||||
r = re.compile(r"-?\d+")
|
||||
for m in r.findall(line):
|
||||
return int(m)
|
||||
raise Exception("No single digit sequence in '{line}'")
|
||||
|
||||
def str_to_int_list(line: str) -> list[int]:
|
||||
r = re.compile(r"-?\d+")
|
||||
return list(map(int, r.findall(line)))
|
||||
|
||||
def str_to_lines_no_empty(text: str) -> list[str]:
|
||||
return list(filter(lambda l: l.strip() != "", text.splitlines()))
|
||||
|
||||
def str_to_lines(text: str) -> list[str]:
|
||||
return list(text.splitlines())
|
||||
1
monitor.py
Symbolic link
1
monitor.py
Symbolic link
@@ -0,0 +1 @@
|
||||
../aoc2023/monitor.py
|
||||
Reference in New Issue
Block a user