Skip to content

Commit 20822a4

Browse files
committed
Add days 14-22, 2018
1 parent 018be98 commit 20822a4

File tree

10 files changed

+679
-1
lines changed

10 files changed

+679
-1
lines changed

2018/day13/solution.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ def update(carts):
3737
global first
3838
new_carts = []
3939
carts = sorted(carts, key = lambda x: (x[0].imag, x[0].real))
40-
#for pc, dc, ic in carts:
4140
while carts:
4241
collision = False
4342
pc, dc, ic = carts.pop(0)

2018/day14/solution.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
class Recipe:
2+
def __init__(self, value):
3+
self.value = value
4+
self.next = None
5+
self.prev = None
6+
7+
8+
inp = 580741
9+
a = Recipe(3)
10+
b = Recipe(7)
11+
a.next = b
12+
a.prev = b
13+
b.next = a
14+
b.prev = a
15+
last_six = [a.value, b.value]
16+
target = [int(v) for v in str(inp)]
17+
first = a
18+
last = b
19+
20+
n = 0
21+
stop = False
22+
while True:
23+
for v in str(a.value + b.value):
24+
new_recipe = Recipe(int(v))
25+
new_recipe.prev = last
26+
new_recipe.next = first
27+
first.prev = new_recipe
28+
last.next = new_recipe
29+
last = new_recipe
30+
last_six.append(int(v))
31+
last_six = last_six[-6:]
32+
n += 1
33+
if last_six == target:
34+
print(n - 4)
35+
stop = True
36+
for _ in range(1 + a.value):
37+
a = a.next
38+
for _ in range(1 + b.value):
39+
b = b.next
40+
if stop:
41+
break
42+
if n == inp + 8:
43+
res = ""
44+
cur = last
45+
for _ in range(10):
46+
res += str(cur.value)
47+
cur = cur.prev
48+
print(res[::-1])

2018/day15/solution.py

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
import networkx as nx
2+
from itertools import count
3+
4+
with open("input") as f:
5+
inp = f.read().strip().split("\n")
6+
7+
8+
def print_():
9+
maxx = int(max(p.real for p in cavern))
10+
maxy = int(max(p.imag for p in cavern))
11+
for y in range(0, maxy + 2):
12+
res = ""
13+
for x in range(0, maxx + 2):
14+
p = x + y*1j
15+
if p in goblins:
16+
res += "G"
17+
elif p in elves:
18+
res += "E"
19+
elif p in cavern:
20+
res += "."
21+
else:
22+
res += "#"
23+
print(res)
24+
25+
26+
def valid(p):
27+
if p not in cavern:
28+
return False
29+
if p in (goblins.keys() | elves.keys()):
30+
return False
31+
return True
32+
33+
34+
def get_move(p_unit):
35+
enemies = goblins if p_unit in elves else elves
36+
paths = []
37+
for dp in (1, -1, 1j, -1j):
38+
p_from = p_unit + dp
39+
if p_from not in g.nodes():
40+
continue
41+
for p_enemy in enemies:
42+
for dq in (1, -1, 1j, -1j):
43+
p_to = p_enemy + dq
44+
if p_to not in g.nodes():
45+
continue
46+
if nx.has_path(g, p_from, p_to):
47+
paths.append((p_from, p_to, nx.shortest_path_length(g, p_from, p_to)))
48+
49+
paths = sorted(paths, key = lambda x: (x[2], x[1].imag, x[1].real))
50+
dirs = {path[0] - p_unit for path in paths if path[2] == paths[0][2] and path[1] == paths[0][1]}
51+
for dir_ in (-1j, -1, 1, 1j):
52+
if dir_ in dirs:
53+
return dir_
54+
55+
return None
56+
57+
58+
def move(p_unit):
59+
enemies = goblins if p_unit in elves else elves
60+
allies = goblins if p_unit in goblins else elves
61+
for dp in (1, -1, 1j, -1j):
62+
if p_unit + dp in enemies:
63+
return 0
64+
dp = get_move(p_unit)
65+
if dp:
66+
allies[p_unit + dp] = allies[p_unit]
67+
allies.pop(p_unit)
68+
g.remove_node(p_unit + dp)
69+
for dq in (1, -1, 1j, -1j):
70+
if not valid(p_unit + dq):
71+
continue
72+
g.add_edge(p_unit, p_unit + dq)
73+
return dp
74+
else:
75+
return 0
76+
77+
def attack(p, attack_power):
78+
enemies = goblins if p in elves else elves
79+
allies = goblins if p in goblins else elves
80+
attack_power = attack_power if p in elves else 3
81+
res = [(p + dp, enemies[p + dp]) for dp in (1, -1, 1j, -1j) if p + dp in enemies]
82+
if res:
83+
res = sorted(res, key = lambda x: (x[1], x[0].imag, x[0].real))
84+
p_target = res[0][0]
85+
enemies[p_target] -= attack_power
86+
87+
88+
def clean_up():
89+
res = []
90+
for units in [goblins, elves]:
91+
for p, hp in list(units.items()):
92+
if hp <= 0:
93+
units.pop(p)
94+
res.append(p)
95+
for p in res:
96+
for dp in (1, -1, 1j, -1j):
97+
if not valid(p + dp):
98+
continue
99+
g.add_edge(p, p + dp)
100+
return res
101+
102+
103+
def round(attack_power):
104+
ps = list(goblins.keys()) + list(elves.keys())
105+
ps = sorted(ps, key = lambda x: (x.imag, x.real))
106+
killed = []
107+
while ps:
108+
p = ps.pop(0)
109+
if p in killed:
110+
continue
111+
dp = move(p)
112+
attack(p + dp, attack_power)
113+
killed += clean_up()
114+
if len(elves) == 0 or len(goblins) == 0:
115+
if ps:
116+
return 2
117+
else:
118+
return 1
119+
return 0
120+
121+
122+
def combat(attack_power = 3):
123+
global cavern
124+
global goblins
125+
global elves
126+
global g
127+
cavern = set()
128+
goblins = {}
129+
elves = {}
130+
for y, line in enumerate(inp):
131+
for x, c in enumerate(line):
132+
p = x + y*1j
133+
if c != "#":
134+
cavern.add(p)
135+
if c == "G":
136+
goblins[p] = 200
137+
if c == "E":
138+
elves[p] = 200
139+
140+
g = nx.Graph()
141+
for p in cavern - (goblins.keys() | elves.keys()):
142+
for dp in (1, -1, 1j, -1j):
143+
np = p + dp
144+
if not valid(np):
145+
continue
146+
g.add_edge(p, np)
147+
148+
for c in count():
149+
res = round(attack_power)
150+
if res:
151+
if res == 2:
152+
c -= 1
153+
break
154+
155+
return (c + 1)*(sum(elves.values()) + sum(goblins.values()))
156+
157+
# Part 1
158+
print(combat())
159+
160+
# Part 2
161+
low, high = 3, 200
162+
while (low < high):
163+
mid = low + (high - low) // 2
164+
res = combat(mid)
165+
if len(elves) < 10:
166+
low = mid + 1
167+
if len(elves) == 10:
168+
high = mid
169+
170+
print(combat(mid))

2018/day16/solution.py

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
import re
2+
from collections import defaultdict
3+
4+
with open("input") as f:
5+
first, last = f.read().strip().split("\n\n\n\n")
6+
7+
8+
first = first.split("\n\n")
9+
samples = []
10+
for section in first:
11+
nums = list(map(int, re.findall("\d+", section)))
12+
samples.append((nums[:4], nums[4:8], nums[8:]))
13+
14+
15+
def addr(regs, a, b, c):
16+
regs = list(regs)
17+
regs[c] = regs[a] + regs[b]
18+
return regs
19+
20+
21+
def addi(regs, a, b, c):
22+
regs = list(regs)
23+
regs[c] = regs[a] + b
24+
return regs
25+
26+
27+
def mulr(regs, a, b, c):
28+
regs = list(regs)
29+
regs[c] = regs[a]*regs[b]
30+
return regs
31+
32+
33+
def muli(regs, a, b, c):
34+
regs = list(regs)
35+
regs[c] = regs[a]*b
36+
return regs
37+
38+
39+
def banr(regs, a, b, c):
40+
regs = list(regs)
41+
regs[c] = regs[a] & regs[b]
42+
return regs
43+
44+
45+
def bani(regs, a, b, c):
46+
regs = list(regs)
47+
regs[c] = regs[a] & b
48+
return regs
49+
50+
51+
def borr(regs, a, b, c):
52+
regs = list(regs)
53+
regs[c] = regs[a] | regs[b]
54+
return regs
55+
56+
57+
def bori(regs, a, b, c):
58+
regs = list(regs)
59+
regs[c] = regs[a] | b
60+
return regs
61+
62+
63+
def setr(regs, a, b, c):
64+
regs = list(regs)
65+
regs[c] = regs[a]
66+
return regs
67+
68+
69+
def seti(regs, a, b, c):
70+
regs = list(regs)
71+
regs[c] = a
72+
return regs
73+
74+
75+
def gtir(regs, a, b, c):
76+
regs = list(regs)
77+
regs[c] = int(a > regs[b])
78+
return regs
79+
80+
81+
def gtri(regs, a, b, c):
82+
regs = list(regs)
83+
regs[c] = int(regs[b] > b)
84+
return regs
85+
86+
87+
def gtrr(regs, a, b, c):
88+
regs = list(regs)
89+
regs[c] = int(regs[a] > regs[b])
90+
return regs
91+
92+
93+
def eqir(regs, a, b, c):
94+
regs = list(regs)
95+
regs[c] = int(a == regs[b])
96+
return regs
97+
98+
99+
def eqri(regs, a, b, c):
100+
regs = list(regs)
101+
regs[c] = int(regs[a] == b)
102+
return regs
103+
104+
105+
def eqrr(regs, a, b, c):
106+
regs = list(regs)
107+
regs[c] = int(regs[a] == regs[b])
108+
return regs
109+
110+
111+
ops = {addr, addi, mulr, muli, banr, bani, borr, bori, setr, seti, gtir, gtri, gtrr, eqir, eqri, eqrr}
112+
functions = defaultdict(lambda: set(ops))
113+
ans = 0
114+
for sample in samples:
115+
res = set()
116+
regs_bef, instr, regs_aft = sample
117+
n, a, b, c = instr
118+
res = {op for op in ops if regs_aft == op(regs_bef, a, b, c)}
119+
if len(res) >= 3:
120+
ans += 1
121+
functions[n] &= res
122+
123+
print(ans)
124+
125+
# Part 2
126+
opcodes = {}
127+
while len(opcodes) < len(ops):
128+
for n, fcts in functions.items():
129+
if len(fcts) == 1:
130+
opcodes[n] = fcts.pop()
131+
for fcts in functions.values():
132+
fcts -= set(opcodes.values())
133+
134+
regs = [0]*4
135+
for line in last.split("\n"):
136+
nums = list(map(int, re.findall("\d+", line)))
137+
n, a, b, c = nums
138+
regs = opcodes[n](regs, a, b, c)
139+
140+
print(regs[0])

0 commit comments

Comments
 (0)