Compare commits

...

12 Commits

Author SHA1 Message Date
magical 9e168db913 day 23 ivy minor cleanup 2022-12-23 16:21:36 -08:00
magical 98a4dffb3c day 23 ivy solution
part 2 is very slow; takes about ~2min on my machine
2022-12-23 16:13:58 -08:00
magical 540bbb9a9e day 23 ivy wip 2022-12-23 13:21:01 -08:00
magical 91da124cf7 day 23 python part 2 2022-12-22 21:54:37 -08:00
magical 8c0cd8e300 day 23 python part 1 2022-12-22 21:37:48 -08:00
magical a299c90401 day 22 python cleanup
also make part 1 work again
2022-12-22 20:56:46 -08:00
magical 77f02a8217 day 22 python part 2 2022-12-21 22:58:32 -08:00
magical 6960c73439 day 22 python part 1 2022-12-21 21:35:46 -08:00
magical b7cfadf7b1 day 21 python part 2 2022-12-20 22:36:28 -08:00
magical cef93e325f day 21 python part 1 solution 2022-12-20 21:56:12 -08:00
magical c4d168689f day 21 rename some files 2022-12-20 21:38:27 -08:00
magical c46feecce9 day 21 go+python solution 2022-12-20 21:35:31 -08:00
17 changed files with 7002 additions and 0 deletions

1
day21/expr.py 100644

File diff suppressed because one or more lines are too long

2037
day21/input 100644

File diff suppressed because it is too large Load Diff

2047
day21/part1.go 100644

File diff suppressed because it is too large Load Diff

2054
day21/part2.go 100644

File diff suppressed because it is too large Load Diff

26
day21/sat.py 100644
View File

@ -0,0 +1,26 @@
import sys
import z3
x = z3.Int('x')
def mul(a,b): return a*b
def div(a,b):
quo = a / b
return z3.If(z3.Or(a % b == 0, a >= 0),
quo,
z3.If(b >= 0, quo + 1, quo - 1))
def add(a,b): return a+b
def sub(a,b): return a-b
def num(a): return z3.IntVal(a)
def eql(a,b): return a==b
z = eval(open("expr.py").read())
s = z3.Solver()
s.add(z)
print(s.check())
m = s.model()
print(m)

103
day21/sol.py 100644
View File

@ -0,0 +1,103 @@
import operator
lines = []
for line in open("input"):
lines.append(line.split())
unused = lines
scope = {}
while unused:
lines, unused = unused, []
for words in lines:
refs = [x for x in words[1:] if x.isalpha()]
if any(r not in scope for r in refs):
unused.append(words)
continue
dst = words[0].rstrip(':')
if len(words) == 2:
_, src = words
scope[dst] = int(src)
continue
_, x, op, y = words
scope[dst] = (op, scope[x], scope[y])
optab = {
'*': operator.mul,
'/': operator.floordiv,
'+': operator.add,
'-': operator.sub,
}
def eval(x):
if type(x) == int:
return x
op = x[0]
args = [eval(a) for a in x[1:]]
return optab[op](*args)
root = scope['root']
print(eval(root))
def solve(x):
_, left, right = x
humn = scope['humn']
path = set()
def find(x):
if x is humn:
path.add(x)
return True
if type(x) is tuple:
for a in x:
if find(a):
path.add(x)
return True
else:
return False
return False
x, y = left, right
if not find(x):
find(y)
x, y = y, x
#print(x)
assert x in path
y = eval(y)
while x is not humn:
assert len(x) == 3
op, a, b = x
if op == '/':
if a in path:
y = ('*', y, b)
else:
raise ValueError("ruh-roh")
elif op == '*':
if a in path:
y = ('/', y, b)
else:
y = ('/', y, a)
elif op == '+':
if a in path:
y = ('-', y, b)
else:
y = ('-', y, a)
elif op == '-':
if a in path:
# x - b = y => x = y + b
y = ('+', y, b)
else:
# a - x = y => x = a - y
y = ('-', a, y)
else:
raise ValueError("unknown op "+repr(op))
if a in path:
x = a
else:
x = b
return eval(y)
print(solve(root))

6
day21/sol.sh 100644
View File

@ -0,0 +1,6 @@
#!/bin/sh
go run part1.go
go run part2.go > expr.py
python sat.py

202
day22/input 100644

File diff suppressed because one or more lines are too long

14
day22/sample1.in 100644
View File

@ -0,0 +1,14 @@
...#
.#..
#...
....
...#.......#
........#...
..#....#....
..........#.
...#....
.....#..
.#......
......#.
10R5L5R10L4R5L5

12
day22/sample3.in 100644
View File

@ -0,0 +1,12 @@
>>v#
.#v.
#.v.
..v.
...#...v..v#
&gt;&gt;&gt;v...<em>&gt;</em>#.&gt;&gt;
..#v...#....
...&gt;&gt;&gt;&gt;v..#.
...#....
.....#..
.#......
......#.

179
day22/sol.py 100644
View File

@ -0,0 +1,179 @@
map = []
moves = ""
with open("input") as f:
for line in f:
if line == "\n":
break
map.append(line.rstrip("\n"))
moves = f.readline().strip()
# 0 - E
# 1 - S
# 2 - W
# 3 - N
F = {
0: (+1, 0),
1: (0, +1),
2: (-1, 0),
3: (0, -1),
}
#assert len(set(len(l) for l in map)) == 1
class Map:
def __init__(self, map, region_size=50):
self.map = map
self.row = 0
self.col = 0
self.face = 0
self.region_size = region_size
while self.map[self.row][self.col] == ' ':
self.col += 1
# 9'
# 1 2
# \ 4 \
# 6 7
# 9 \
self.region_map = {
# R D L U
1: [(2,0), (4, 0), (6,2), (9, 1)],
4: [(2,-1), (7,0), (6,-1), (1, 0)],
7: [(2,2), (9,+1), (6,0), (4,0)],
6: [(7,0), (9,0), (1,2), (4,+1)],
9: [(7,-1), (2,0), (1,-1), (6,0)],
2: [(7,2), (4,+1), (1, 0), (9,0)],
}
ok = True
for f in range(4):
for r in self.region_map:
orig = (r,f)
s = repr(orig)
for _ in range(4):
r, h = self.region_map[r][f]
f = (f+h)%4
s += "-> {} {}".format(r, f)
if (r,f) != orig:
print("!!", s)
ok = False
assert ok, "topology failure"
def set_simple_region_map(self):
R = self.region_size
def exists(x,y):
return 0 <= y < len(self.map) and 0 <= x < len(self.map[y]) and self.map[y][x] != ' '
for y in range(0,len(self.map), R):
for x in range(0, len(self.map[y]), R):
if exists(x,y):
warps = []
for f in range(4):
dx, dy = F[f]
dx, dy = dx*R, dy*R
x1, y1 = x+dx, y+dy
if exists(x1, y1):
dest = self.region(x1,y1)
else:
if dy:
y1 %= len(self.map)
while not exists(x1, y1):
y1 = (y1+dy)%len(self.map)
if dx:
x1 %= len(self.map[y1])
while not exists(x1, y1):
x1 = (x1+dx)%len(self.map[y1])
dest = self.region(x1, y1)
warps.append((dest, 0))
r = self.region(x,y)
self.region_map[r] = warps
print(self.region_map)
def nextTile(self, x, y, face):
R = self.region_size
dx, dy = F[face]
if 0 <= (x%R + dx) < R and 0 <= (y%R + dy) < R:
x, y = x+dx, y+dy
else:
r = self.region(x,y)
u = (x+dx) % R
v = (y+dy) % R
new_r, rotate = self.region_map[r][face]
if rotate == 0:
pass
elif rotate == -1:
u, v = v, R-u-1
elif rotate == 1:
u, v = R-v-1, u
elif rotate == 2:
u, v = R-u-1, R-v-1
x, y = self.to_abs(u, v, new_r)
face = (face + rotate) % 4
c = self.map[y][x]
assert c != ' '
return x, y, face, c
def to_abs(self, u, v, r):
"""returns the absolute coords of the local point (u,v) in region r"""
R = self.region_size
u %= R
v %= R
rx = r % 3
ry = r // 3
return (rx*R + u), (ry*R + v)
def region(self, x, y):
R = self.region_size
return y//R * 3 + x//R
def turnLeft(self):
self.face = (self.face - 1) % 4
def turnRight(self):
self.face = (self.face + 1) % 4
def walk(self, n, noclip=True):
x, y, face = self.col, self.row, self.face
while n > 0:
x,y,face,c = self.nextTile(x, y, face)
if c == '#' and noclip:
break
n -= 1
self.row = y
self.col = x
self.face = face
#print(self.pos())
def pos(self):
return self.row+1, self.col+1
def score(self):
r, c = self.pos()
return r*1000 + c*4 + self.face
#print(moves)
m = Map(map)
#m.set_simple_region_map()
i = 0
while i < len(moves):
if moves[i].isdigit():
j = i+1
while j < len(moves) and moves[j].isdigit():
j += 1
n = int(moves[i:j])
m.walk(n)
i = j
elif moves[i] == 'L':
m.turnLeft()
i += 1
elif moves[i] == 'R':
m.turnRight()
i += 1
else:
print("invalid move", moves[i], "at", i)
i += 1
print(m.row, m.col)
print(m.score())

72
day23/input 100644
View File

@ -0,0 +1,72 @@
#.#####..#..##......##.#..####....#.#.####..##.#######..##..##.###...#..
..#..##.#.#.#.##.#......######.#...###....#....#.#..#####.....#..#.####.
....#..#.###.####.......#.#.###..#.######...##..#.#.#..#.######.####..##
...#.#..####...#..##.#.####..#..##.#####..##.#...#..##..#..#.#.#.####...
.##..###..###.#.##...#..#.#.##.##.###.##....#.####.#.##.#..##.#####.#..#
#.#.###.#######..#...#####.##..##..##.#...#.#...#####.##....###.#...###.
...#...##.#..#.###....#.#.##..#.#..##.#.#.#..#...#.....#.####.##.#..##..
####.#...##.##.#..#.#####.#.##.###..#...#.#.##.##......##..#.#..##..##..
..#.##.##.####....##.....#.#.......##.#..#.###.####.###.#.....#.#.#...##
##...###..###.#.####.#..#...###...####..#####.#.#..##....#.#.####...#..#
####..#.#.##.##....#..##.###.#..#..###.##.#.....#######..##.##....#.#.##
.##...#.#####...#......##.#.##..#.####......#..###.##.##..#.#...##....##
.#.##.#.##.#..#..###.#.###....#.#.#.#.#.###....##..####.#######.##.##.#.
#######.##.#...###.#..#######.#..##.#..#.#...#.#.#.#..##.##.#.#.#....#..
#.#.#.#.##..##..#.##...##.#.###.####...####.##..#.##.##.###.###.#....##.
#...######.#....####.#.#.##....#..#...##.........#####.###..##.#.#..#.#.
#.#.#.#.#...#.###...#.....#.#....######......#..#..#.###.#..#.#.##.#....
#.##.#...#####.#....#.#.#..##...##.##.##.#####.####.#.##.#.###...#.##.##
#...#.#.###........##..#...#.###...###.##......##.####..#.##....##.#..##
#####.#..#.....#######..........#..####..##.#.#####..###...#...##.#.####
...###..##.##.##.##.#..###...###.#.##.#.###.##.#.#........###...#....##.
###.##...##.###..#..#.#.#...##.#.#.....##.#.##....####.####..#######..##
##.#.#..#..###.#.#######..#..#.#.#..#####...####...#.####....##.###..##.
..#.#.#....####.#.......#..#..###.##.#...##.####..###.#.#..####..#.####.
.#.#..##.##..#...##...###.##.#.#.#..#####...#...#####..##.#...###..#.##.
..###.#...#.#...#.###...###.##.#.#....#.#...##...##.....#.##.#.###.#....
##....#..#........###..#.##.#..##...#.#.#..##.####.#...#.########.###...
..#####.##.#...#..##...###.#####...#....#.##.######.#..#.##....###..##..
.####.##..###...#.##...#.#.##..###.......#.###.#.##...#.#....#.#.##..##.
#..#..###....#..#.#.....#.#.#####..##...####....####.#.#.##....#####.##.
##########.####.#...##.##...#....##..##...###....#..###.##..##.###...###
##.###..##.####.....#.#.....#.##...#...###..#.#...#....###..###.......#.
##..###.#....##..#.#....###...#.####.#.###.#.#.#..##.##..##.######.##...
#...####...#.##..##.##.#..####.#..#..#.##.##....#..#.##..##.#.###..#.###
#.#..##.###.....#....###.##.##.#.###.#####.#.....##.##.##..#.##.###..###
#...#..##..#..###....#..#...#..###...#.##.#.#.###...###..#.##..#..##.##.
#.#..#.##.#...#..............#.###...##.##.#.....########.###....#.....#
#..#.#...##..#.#.###.##.#.#....####.#.##.#.###.###.#..#..##.....#..####.
.....###....##.##..##..#....######......##.###..#.#......#.#..#..#...#.#
.##...###.#.#.###...##...##.#.####..#.###.#.#.#.###...##.#...#....###..#
#..####.#...#.##..#..#.###.###...#.#.#..##....####..#...##........####..
....##.##....#.....#..##..###..####..##.#.#.######..#....#..####.###.#..
.#.##..#..#.#.....#........#..###.##.###.##.#..#..##.....#.#.###.###..#.
#.#.#.#..#.###.#..#.##.##..######.##.######.#...#.###..#...#...##....#.#
##..#...##.#.#.#.######.####.###...####..#....####...#.#..###...##.##..#
.##.#....#...##...#...##.##.####..#.##..#.##.####..#.##..#..###..######.
.##.#.#.##.#.####..#..#..##.#....#...####.###.##.####.....###..#..#.#..#
#.##..#....##....##...#.##..####.#..####....###.##...###....##.###.##...
..##..##.#...#.#..###...#.#.#.###.#.#######..#..###.#.###..#.###....#..#
#..##.##.####..##.#....##..#.#......###....######..#.....###.....#.#.#..
.#...###.##...#.##.##...##...##..####...#..########.###..########.#..#.#
###.##.###.#.##.#..#.###....##...###.#.###.##..#.#...#..#####.##.##...#.
.###.####..###.#.....####.#...###.##.#.##..#..#....##....#.#..#....###..
##.#.#..##.#####..########..##...####....#.##.#.#.###.###.####.....####.
#....###.....####.###.###.##..#...#.##.##...##.#..#.........#####......#
##.####.#.#..#..#.##...#.##......#...#.#.#.####.##..##...####.....#.#.#.
...#.###.#..###.....#.#####.#.....####.###...#.###....#...#..#.#...##.#.
.#.......#...#......##..#.###....#.######..###.##...###...##.#.#.##..#.#
.##.###.#..#.#####..###...#.###...##.#.####.#.#.#..#....#####...#..##.##
.###..#...##..#.....##.#...#.#...##..##.#.###..###.#....##.###.###..#...
#######.##..#..#.#...#..#.#..#.#..###..#########.#.....#.....####.##.#.#
#.##..####...##.#..###.###...#....####...####..#...#####...##.#...#####.
#..##.#..#.######.#.#.#.##...##..#...##...#.......#.#####.#...#.##..#.#.
.##..#..###..#####.#.##..######.##...#.###.##.##.#..#....#..#.###..####.
...#...##.#...##.#.###.#.#..##..####.....#..........#..#.........##..##.
#####..##......##.##...#.##.###...####....##.##..#.###.#..##..#.##.#....
.###....##.#####.#.###.#.##...##.####....###..#......#.#..#....##.#.#.##
..###.#....#######.#.#..#.###.##.##..#..###...##.###.##.####.##.##.####.
.#.#...##.#..##.....###.#..#.#...##..#..#.#.#.###.##.##.#.....#.##..#...
.#####.#....#..#.####..####..#....#....##.#...#.##...###.#.#...#########
###.####....#.####..#..###....#.###.##...#####.###...#.#..#.#........###
#.#.######...#.#..#####.#.####.....##...#.###.#.##..##.#.#.##..#.####.#.

1
day23/input.ivy 100644

File diff suppressed because one or more lines are too long

7
day23/sample1.in 100644
View File

@ -0,0 +1,7 @@
....#..
..###.#
#...#.#
.#...##
#.###..
##.#.##
.#..#..

107
day23/sol.ivy 100644
View File

@ -0,0 +1,107 @@
)get "input.ivy"
sample = 7 7 rho '....#..' '..###.#' '#...#.#' '.#...##' '#.###..' '##.#.##' '.#..#..'
#board = sample == '#'
board = input == '#'
#board
op show a = (text ".#23456789"[1+a]),"\n-"
op lift a = (1,rho a) rho a
op n moveNSWE a = (lift n flip a[1]), (lift (-n) flip a[2]), (lift n rot a[3]), (lift (-n) rot a[4])
op any a = or/,a
op maybePad1 a =
c1 = any a[1]
c2 = any a[(rho a)[1]]
c1 and c2: 0,a,0
c1: 0,a
c2: a,0
a
op maybePad a =
a = maybePad1 a
(any a[;1]) or (any a[;(rho a)[2]]): transp maybePad1 transp a
a
op smearWE a = a or (1 rot a) or (-1 rot a)
op smearNS a = a or (1 flip a) or (-1 flip a)
op look a =
ns = lift smearNS a
we = lift smearWE a
-1 moveNSWE (we, we, ns, ns)
op axis1 a = 3 1 2 transp a
op dup4 a = (4,rho a) rho a
# look in each direction
# an elf can move in a direction if there is no elf in said direction and there is an elf somewhere nearby
# returns a 4x(rho a) matrix
op canMove a =
C = look a
(not C) and dup4 (a and or/axis1 C)
# prepare moves
# assign each move a priority and take the max
# remove lower priority moves
op p prepare choices =
best = max/ p * axis1 choices # select best direction
p o.== best # decompose into 4x?x? matrix
# count how many elves want to move to each square
# filter out moves which conflict
op unblocked moves =
open = 1 == +/axis1 1 moveNSWE moves
moves and -1 moveNSWE dup4 open
priority = 4 3 2 1
M = 0
changed = 0
op M round a =
a = maybePad a
moves = unblocked (M flip priority) prepare canMove a
moved = or/axis1 moves
changed; changed = +/, moved
b = (a and not moved) + +/axis1 1 moveNSWE moves
b
op round a = M round a
# this is implemented using globals
# to store the board instead of recursion
# in order to avoid keeping a bunch of large
# intermediate values alive on the stack
B = 0
op i loop n =
i > n: i
changed; changed = 0
B = M round B
M = M - 1
changed == 0: i
(i+1) loop n
op n rounds a =
B; B = a
M; M = 0
1 loop n
B
op n numrounds a =
B; B = a
M; M = 0
1 loop n
op score a =
a = maybePad a
n = */ (rho a) - 2
n - +/, a
show board
#show round board
show 10 rounds board
score 10 rounds board
1000 numrounds board

92
day23/sol.py 100644
View File

@ -0,0 +1,92 @@
from collections import Counter
pos = {}
y = 0
for line in open("input"):
for x, c in enumerate(line):
if c == '#':
pos[x,y] = 1
y += 1
def choices(pos, dir):
x,y = pos
dy = (dir == 'S') - (dir == 'N')
dx = (dir == 'E') - (dir == 'W')
if dx:
for dy in -1,0,+1:
yield x+dx,y+dy
else:
assert dy
for dx in -1,0,+1:
yield x+dx, y+dy
def go(pos, dir):
x,y = pos
dy = (dir == 'S') - (dir == 'N')
dx = (dir == 'E') - (dir == 'W')
return x+dx,y+dy
def neighbors(pos):
x,y = pos
for dx in -1,0,+1:
for dy in -1,0,+1:
if dx or dy:
yield x+dx,y+dy
def migrate(start, rounds):
moves = ['N', 'S', 'W', 'E']
for i in range(rounds):
#show(start)
#print("-")
propose = {}
destCount = Counter()
for p in start:
propose[p] = p
if any(n in start for n in neighbors(p)):
for m in moves:
if not any(c in start for c in choices(p, m)):
c = go(p,m)
propose[p] = c
destCount[c] += 1
break
next = {}
moved = 0
for p, d in propose.items():
if destCount[d] <= 1:
next[d] = 1
moved += p != d
else:
next[p] = 1
if not moved:
break
moves.append(moves.pop(0))
start = next
return start, i+1
def show(pos):
xmin = min(x for x,y in pos)
ymin = min(y for x,y in pos)
xmax = max(x for x,y in pos)
ymax = max(y for x,y in pos)
for y in range(ymin, ymax+1):
print("".join(".#"[(x,y) in pos] for x in range(xmin,xmax+1)))
def count_empty(pos):
n = 0
xmin = min(x for x,y in pos)
ymin = min(y for x,y in pos)
xmax = max(x for x,y in pos)
ymax = max(y for x,y in pos)
return (ymax-ymin+1)*(xmax-xmin+1) - len(pos)
#print(pos)
end, _ = migrate(pos, 10)
print(count_empty(end))
_, n = migrate(pos, 100000)
print(n)

42
day23/toivy.py 100755
View File

@ -0,0 +1,42 @@
#!/usr/bin/env python3
"""
Converts a text file containing a list of integers
into a format that can be loaded by ivy.
"""
import sys
if sys.argv[1:]:
filename = sys.argv[1]
else:
filename = "input"
varname = filename.split(".",1)[0]
with open(filename) as f:
lines = f.read().splitlines()
data = []
for line in lines:
line = line.replace("-", ",")
data.append(line.split(","))
def count(row):
n = 0
for x in row:
if x.isdigit():
n += 1
else:
n += len(x)
return n
cols = max(map(count, data))
print("{} = {} {} rho".format(varname, len(data), cols), end="")
for row in data:
print("", " ".join(
x if x.isdigit() else repr(x)
for x in row), end="")
n = count(row)
if n < cols:
print(" 0" * (cols - n), end="")