Solve 2018 day 16 and add function to download input
This commit is contained in:
parent
db82589857
commit
ab2e6f4ddb
147
2018/d16.py
Normal file
147
2018/d16.py
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
from lib import str_to_ints, get_data
|
||||||
|
|
||||||
|
|
||||||
|
def addr(regs, a, b, c):
|
||||||
|
regs[c] = regs[a] + regs[b]
|
||||||
|
|
||||||
|
|
||||||
|
def addi(regs, a, b, c):
|
||||||
|
regs[c] = regs[a] + b
|
||||||
|
|
||||||
|
|
||||||
|
def mulr(regs, a, b, c):
|
||||||
|
regs[c] = regs[a] * regs[b]
|
||||||
|
|
||||||
|
|
||||||
|
def muli(regs, a, b, c):
|
||||||
|
regs[c] = regs[a] * b
|
||||||
|
|
||||||
|
|
||||||
|
def banr(regs, a, b, c):
|
||||||
|
regs[c] = regs[a] & regs[b]
|
||||||
|
|
||||||
|
|
||||||
|
def bani(regs, a, b, c):
|
||||||
|
regs[c] = regs[a] & b
|
||||||
|
|
||||||
|
|
||||||
|
def borr(regs, a, b, c):
|
||||||
|
regs[c] = regs[a] | regs[b]
|
||||||
|
|
||||||
|
|
||||||
|
def bori(regs, a, b, c):
|
||||||
|
regs[c] = regs[a] | b
|
||||||
|
|
||||||
|
|
||||||
|
def setr(regs, a, _, c):
|
||||||
|
regs[c] = regs[a]
|
||||||
|
|
||||||
|
|
||||||
|
def seti(regs, a, _, c):
|
||||||
|
regs[c] = a
|
||||||
|
|
||||||
|
|
||||||
|
def gtir(regs, a, b, c):
|
||||||
|
regs[c] = 1 if a > regs[b] else 0
|
||||||
|
|
||||||
|
|
||||||
|
def gtri(regs, a, b, c):
|
||||||
|
regs[c] = 1 if regs[a] > b else 0
|
||||||
|
|
||||||
|
|
||||||
|
def gtrr(regs, a, b, c):
|
||||||
|
regs[c] = 1 if regs[a] > regs[b] else 0
|
||||||
|
|
||||||
|
|
||||||
|
def eqir(regs, a, b, c):
|
||||||
|
regs[c] = 1 if a == regs[b] else 0
|
||||||
|
|
||||||
|
|
||||||
|
def eqri(regs, a, b, c):
|
||||||
|
regs[c] = 1 if regs[a] == b else 0
|
||||||
|
|
||||||
|
|
||||||
|
def eqrr(regs, a, b, c):
|
||||||
|
regs[c] = 1 if regs[a] == regs[b] else 0
|
||||||
|
|
||||||
|
|
||||||
|
OPS = [
|
||||||
|
addr,
|
||||||
|
addi,
|
||||||
|
mulr,
|
||||||
|
muli,
|
||||||
|
banr,
|
||||||
|
bani,
|
||||||
|
borr,
|
||||||
|
bori,
|
||||||
|
setr,
|
||||||
|
seti,
|
||||||
|
gtir,
|
||||||
|
gtri,
|
||||||
|
gtrr,
|
||||||
|
eqir,
|
||||||
|
eqri,
|
||||||
|
eqrr,
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def part_1(data):
|
||||||
|
examples = []
|
||||||
|
|
||||||
|
lines = data.splitlines()
|
||||||
|
test_prog = []
|
||||||
|
last_i = None
|
||||||
|
for i in range(len(lines)):
|
||||||
|
line = lines[i]
|
||||||
|
if line.startswith("Before:"):
|
||||||
|
regs = str_to_ints(line)
|
||||||
|
inst = str_to_ints(lines[i + 1])
|
||||||
|
regs_after = str_to_ints(lines[i + 2])
|
||||||
|
examples.append((regs, inst, regs_after))
|
||||||
|
last_i = i + 2
|
||||||
|
|
||||||
|
assert last_i is not None
|
||||||
|
for line in lines[last_i:]:
|
||||||
|
if line.strip() != "":
|
||||||
|
test_prog.append(str_to_ints(line))
|
||||||
|
|
||||||
|
r = 0
|
||||||
|
for before_orig, inst, after in examples:
|
||||||
|
ops_correct = []
|
||||||
|
for op in OPS:
|
||||||
|
before = list(before_orig)
|
||||||
|
op(before, *inst[1:])
|
||||||
|
if before == after:
|
||||||
|
ops_correct.append(op)
|
||||||
|
if len(ops_correct) >= 3:
|
||||||
|
r += 1
|
||||||
|
print(r)
|
||||||
|
|
||||||
|
code_to_op = {}
|
||||||
|
while len(OPS) > 0:
|
||||||
|
for before_orig, inst, after in examples:
|
||||||
|
ops_correct = []
|
||||||
|
for op in OPS:
|
||||||
|
before = list(before_orig)
|
||||||
|
op(before, *inst[1:])
|
||||||
|
if before == after:
|
||||||
|
ops_correct.append(op)
|
||||||
|
if len(ops_correct) == 1:
|
||||||
|
code_to_op[inst[0]] = ops_correct[0]
|
||||||
|
OPS.remove(ops_correct[0])
|
||||||
|
|
||||||
|
regs = [0, 0, 0, 0]
|
||||||
|
for line in test_prog:
|
||||||
|
op_code = line[0]
|
||||||
|
vals = line[1:]
|
||||||
|
code_to_op[op_code](regs, *vals)
|
||||||
|
print(regs[0])
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
data = get_data(__file__)
|
||||||
|
part_1(data)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
@ -104,6 +104,7 @@ written in Python.
|
|||||||
- Day 13: 73:09
|
- Day 13: 73:09
|
||||||
- Day 14: 20:48
|
- Day 14: 20:48
|
||||||
- Day 15: 185:11
|
- Day 15: 185:11
|
||||||
|
- Day 16: 36:10
|
||||||
|
|
||||||
|
|
||||||
# 2022
|
# 2022
|
||||||
|
58
lib.py
58
lib.py
@ -11,20 +11,25 @@ INF = float("inf")
|
|||||||
fst = lambda l: l[0]
|
fst = lambda l: l[0]
|
||||||
snd = lambda l: l[1]
|
snd = lambda l: l[1]
|
||||||
|
|
||||||
|
|
||||||
def nth(n):
|
def nth(n):
|
||||||
return lambda l: l[n]
|
return lambda l: l[n]
|
||||||
|
|
||||||
|
|
||||||
def maps(f, xs):
|
def maps(f, xs):
|
||||||
if isinstance(xs, list):
|
if isinstance(xs, list):
|
||||||
return [maps(f, x) for x in xs]
|
return [maps(f, x) for x in xs]
|
||||||
return f(xs)
|
return f(xs)
|
||||||
|
|
||||||
|
|
||||||
def mape(f, xs):
|
def mape(f, xs):
|
||||||
return list(map(f, xs))
|
return list(map(f, xs))
|
||||||
|
|
||||||
|
|
||||||
def add2(a: tuple[int, int], b: tuple[int, int]) -> tuple[int, int]:
|
def add2(a: tuple[int, int], b: tuple[int, int]) -> tuple[int, int]:
|
||||||
return (a[0] + b[0], a[1] + b[1])
|
return (a[0] + b[0], a[1] + b[1])
|
||||||
|
|
||||||
|
|
||||||
class Grid2D:
|
class Grid2D:
|
||||||
N = (-1, 0)
|
N = (-1, 0)
|
||||||
E = (0, 1)
|
E = (0, 1)
|
||||||
@ -55,8 +60,7 @@ class Grid2D:
|
|||||||
c = Grid2D("d\nd")
|
c = Grid2D("d\nd")
|
||||||
c.n_rows = self.n_rows
|
c.n_rows = self.n_rows
|
||||||
c.n_cols = self.n_cols
|
c.n_cols = self.n_cols
|
||||||
c.grid = [[val for _ in range(c.n_cols)]
|
c.grid = [[val for _ in range(c.n_cols)] for _ in range(self.n_rows)]
|
||||||
for _ in range(self.n_rows)]
|
|
||||||
return c
|
return c
|
||||||
|
|
||||||
def rows(self) -> list[list[str]]:
|
def rows(self) -> list[list[str]]:
|
||||||
@ -64,8 +68,7 @@ class Grid2D:
|
|||||||
|
|
||||||
def cols(self) -> list[list[str]]:
|
def cols(self) -> list[list[str]]:
|
||||||
rows = self.rows()
|
rows = self.rows()
|
||||||
return [[row[col_i] for row in rows]
|
return [[row[col_i] for row in rows] for col_i in range(self.n_cols)]
|
||||||
for col_i in range(self.n_cols)]
|
|
||||||
|
|
||||||
def find(self, chars: str) -> list[tuple[int, int]]:
|
def find(self, chars: str) -> list[tuple[int, int]]:
|
||||||
return [c for c in self.all_coords() if self[c] in chars]
|
return [c for c in self.all_coords() if self[c] in chars]
|
||||||
@ -74,9 +77,11 @@ class Grid2D:
|
|||||||
return [c for c in self.all_coords() if self[c] not in chars]
|
return [c for c in self.all_coords() if self[c] not in chars]
|
||||||
|
|
||||||
def all_coords(self) -> list[tuple[int, int]]:
|
def all_coords(self) -> list[tuple[int, int]]:
|
||||||
return [(row_i, col_i)
|
return [
|
||||||
for row_i in range(self.n_rows)
|
(row_i, col_i)
|
||||||
for col_i in range(self.n_cols)]
|
for row_i in range(self.n_rows)
|
||||||
|
for col_i in range(self.n_cols)
|
||||||
|
]
|
||||||
|
|
||||||
def row_coords(self, row_i) -> list[tuple[int, int]]:
|
def row_coords(self, row_i) -> list[tuple[int, int]]:
|
||||||
assert row_i < self.n_rows, f"{row_i=} must be smaller than {self.n_rows=}"
|
assert row_i < self.n_rows, f"{row_i=} must be smaller than {self.n_rows=}"
|
||||||
@ -94,10 +99,14 @@ class Grid2D:
|
|||||||
return self.contains(pos)
|
return self.contains(pos)
|
||||||
|
|
||||||
def neighbors_ort(self, pos: tuple[int, int]) -> list[tuple[int, int]]:
|
def neighbors_ort(self, pos: tuple[int, int]) -> list[tuple[int, int]]:
|
||||||
return [add2(pos, off) for off in self.dirs_ort() if self.contains(add2(pos, off))]
|
return [
|
||||||
|
add2(pos, off) for off in self.dirs_ort() if self.contains(add2(pos, off))
|
||||||
|
]
|
||||||
|
|
||||||
def neighbors_vert(self, pos: tuple[int, int]) -> list[tuple[int, int]]:
|
def neighbors_vert(self, pos: tuple[int, int]) -> list[tuple[int, int]]:
|
||||||
return [add2(pos, off) for off in self.dirs_vert() if self.contains(add2(pos, off))]
|
return [
|
||||||
|
add2(pos, off) for off in self.dirs_vert() if self.contains(add2(pos, off))
|
||||||
|
]
|
||||||
|
|
||||||
def neighbors_adj(self, pos: tuple[int, int]) -> list[tuple[int, int]]:
|
def neighbors_adj(self, pos: tuple[int, int]) -> list[tuple[int, int]]:
|
||||||
return self.neighbors_ort(pos) + self.neighbors_vert(pos)
|
return self.neighbors_ort(pos) + self.neighbors_vert(pos)
|
||||||
@ -119,6 +128,7 @@ class Grid2D:
|
|||||||
for r in self.rows():
|
for r in self.rows():
|
||||||
print(" ".join(map(str, r)))
|
print(" ".join(map(str, r)))
|
||||||
|
|
||||||
|
|
||||||
class Input:
|
class Input:
|
||||||
def __init__(self, text: str):
|
def __init__(self, text: str):
|
||||||
if os.path.isfile(text):
|
if os.path.isfile(text):
|
||||||
@ -141,6 +151,7 @@ class Input:
|
|||||||
def grid2(self) -> Grid2D:
|
def grid2(self) -> Grid2D:
|
||||||
return Grid2D(self.text)
|
return Grid2D(self.text)
|
||||||
|
|
||||||
|
|
||||||
def prime_factors(n):
|
def prime_factors(n):
|
||||||
"""
|
"""
|
||||||
Returns a list of prime factors for n.
|
Returns a list of prime factors for n.
|
||||||
@ -163,6 +174,7 @@ def prime_factors(n):
|
|||||||
factors.append(rest)
|
factors.append(rest)
|
||||||
return factors
|
return factors
|
||||||
|
|
||||||
|
|
||||||
def lcm(numbers: list[int]) -> int:
|
def lcm(numbers: list[int]) -> int:
|
||||||
fs = []
|
fs = []
|
||||||
for n in numbers:
|
for n in numbers:
|
||||||
@ -173,6 +185,7 @@ def lcm(numbers: list[int]) -> int:
|
|||||||
s *= f
|
s *= f
|
||||||
return s
|
return s
|
||||||
|
|
||||||
|
|
||||||
def str_to_int(line: str) -> int:
|
def str_to_int(line: str) -> int:
|
||||||
line = line.replace(" ", "")
|
line = line.replace(" ", "")
|
||||||
r = re.compile(r"(-?\d+)")
|
r = re.compile(r"(-?\d+)")
|
||||||
@ -180,16 +193,20 @@ def str_to_int(line: str) -> int:
|
|||||||
(x,) = m
|
(x,) = m
|
||||||
return int(x)
|
return int(x)
|
||||||
|
|
||||||
|
|
||||||
def str_to_ints(line: str) -> list[int]:
|
def str_to_ints(line: str) -> list[int]:
|
||||||
r = re.compile(r"-?\d+")
|
r = re.compile(r"-?\d+")
|
||||||
return list(map(int, r.findall(line)))
|
return list(map(int, r.findall(line)))
|
||||||
|
|
||||||
|
|
||||||
def str_to_lines_no_empty(text: str) -> list[str]:
|
def str_to_lines_no_empty(text: str) -> list[str]:
|
||||||
return list(filter(lambda l: l.strip() != "", text.splitlines()))
|
return list(filter(lambda l: l.strip() != "", text.splitlines()))
|
||||||
|
|
||||||
|
|
||||||
def str_to_lines(text: str) -> list[str]:
|
def str_to_lines(text: str) -> list[str]:
|
||||||
return list(text.splitlines())
|
return list(text.splitlines())
|
||||||
|
|
||||||
|
|
||||||
def count_trailing_repeats(lst):
|
def count_trailing_repeats(lst):
|
||||||
count = 0
|
count = 0
|
||||||
for elem in reversed(lst):
|
for elem in reversed(lst):
|
||||||
@ -199,6 +216,7 @@ def count_trailing_repeats(lst):
|
|||||||
count += 1
|
count += 1
|
||||||
return count
|
return count
|
||||||
|
|
||||||
|
|
||||||
class A_Star(object):
|
class A_Star(object):
|
||||||
def __init__(self, starts, is_goal, h, d, neighbors):
|
def __init__(self, starts, is_goal, h, d, neighbors):
|
||||||
"""
|
"""
|
||||||
@ -221,12 +239,12 @@ class A_Star(object):
|
|||||||
|
|
||||||
for neighbor in neighbors(current):
|
for neighbor in neighbors(current):
|
||||||
tentative_g_score = g_score[current] + d(current, neighbor)
|
tentative_g_score = g_score[current] + d(current, neighbor)
|
||||||
if neighbor not in g_score or \
|
if neighbor not in g_score or tentative_g_score < g_score[neighbor]:
|
||||||
tentative_g_score < g_score[neighbor]:
|
|
||||||
g_score[neighbor] = tentative_g_score
|
g_score[neighbor] = tentative_g_score
|
||||||
f_score = g_score[neighbor] + h(neighbor)
|
f_score = g_score[neighbor] + h(neighbor)
|
||||||
heapq.heappush(open_set, (f_score, neighbor))
|
heapq.heappush(open_set, (f_score, neighbor))
|
||||||
|
|
||||||
|
|
||||||
def shoelace_area(corners):
|
def shoelace_area(corners):
|
||||||
n = len(corners)
|
n = len(corners)
|
||||||
area = 0
|
area = 0
|
||||||
@ -236,7 +254,25 @@ def shoelace_area(corners):
|
|||||||
area += (x1 * y2) - (x2 * y1)
|
area += (x1 * y2) - (x2 * y1)
|
||||||
return abs(area) / 2.0
|
return abs(area) / 2.0
|
||||||
|
|
||||||
|
|
||||||
def extract_year_and_date(scriptname) -> tuple[str, str]:
|
def extract_year_and_date(scriptname) -> tuple[str, str]:
|
||||||
r = re.compile(r"aoc(\d\d\d\d)/d(\d+).py")
|
r = re.compile(r"aoc(\d\d\d\d)/d(\d+).py")
|
||||||
[(year, day)] = r.findall(scriptname)
|
[(year, day)] = r.findall(scriptname)
|
||||||
return (year, day)
|
return (year, day)
|
||||||
|
|
||||||
|
|
||||||
|
def get_data(filename):
|
||||||
|
path, file = os.path.split(filename)
|
||||||
|
year = path[-4:]
|
||||||
|
day = file.replace("d", "").replace(".py", "")
|
||||||
|
txt_file = f"d{day}.txt"
|
||||||
|
|
||||||
|
if os.path.isfile(txt_file):
|
||||||
|
with open(txt_file) as f:
|
||||||
|
return f.read()
|
||||||
|
else:
|
||||||
|
import subprocess
|
||||||
|
subprocess.call(["../get.py", year, day])
|
||||||
|
assert os.path.isfile(txt_file), "Could not download AoC file"
|
||||||
|
with open(txt_file) as f:
|
||||||
|
return f.read()
|
||||||
|
Loading…
Reference in New Issue
Block a user