Roderic Day 1 anno fa
parent
commit
374c3b8b70
4 ha cambiato i file con 141 aggiunte e 5 eliminazioni
  1. +1
    -1
      VERSION
  2. +5
    -4
      makefile
  3. +69
    -0
      y2023/p24.py
  4. +66
    -0
      y2023/p25.py

+ 1
- 1
VERSION Vedi File

@@ -1 +1 @@
🐄
🐰

+ 5
- 4
makefile Vedi File

@@ -4,6 +4,7 @@ export
.SILENT:

FILE := $(shell find . -path "./y????/p??.*" -type f | xargs ls -rt | tail -n 1)
PYTHON := docker compose run --rm advent python

YEAR := $(shell echo ${FILE} | sed -E 's/.+y([0-9]+).+/\1/')
DAY := $(shell echo ${FILE} | sed -E 's/.+p([0-9]+).+/\1/' | bc)
@@ -14,20 +15,20 @@ CODE := $(BASE).py
DATA := $(BASE).dat
TEST := $(BASE).dtt


main: ${TEST}
echo 'test':
cat ${TEST} | docker compose run --rm advent python -u ${CODE}
echo 'test:'
cat ${TEST} | ${PYTHON} -u ${CODE}

clean: ${DATA}
echo 'real:'
cat ${DATA} | docker compose run --rm advent python -u ${CODE}
cat ${DATA} | ${PYTHON} -u ${CODE}

save:
git add .
test `git log -1 --format=%s` == `cat VERSION` \
&& git commit --amend --reuse-message=head \
|| git commit -m `cat VERSION`
git push -f

${DATA} ${TEST}:
# avoid spam in the lead up to the event

+ 69
- 0
y2023/p24.py Vedi File

@@ -0,0 +1,69 @@
import collections
import itertools
import re


def part1(H):
"""
2 variables, 2 equations

px1 + vx1 * t1 == px2 + vx2 * t2
py1 + vy1 * t1 == py2 + vy2 * t2

t1 = (px2 - px1) / vx1 + (vx2 / vx1) * t2
t1 = (py2 - py1) / vy1 + (vy2 / vy1) * t2

(px2 - px1) / vx1 - (py2 - py1) / vy1 = (vy2 / vy1 - vx2 / vx1) * t2
t2 = c1 / c2
c1 = (px2 - px1) / vx1 - (py2 - py1) / vy1
c2 = (vy2 / vy1 - vx2 / vx1)
"""
n = 0
lo, hi = (7, 27) if len(H) < 100 else (2e14, 4e14)
for aa, bb in itertools.combinations(H, 2):
px1, py1, pz1, vx1, vy1, vz1 = aa
px2, py2, pz2, vx2, vy2, vz2 = bb

c1 = (px2 - px1) / vx1 - (py2 - py1) / vy1
c2 = (vy2 / vy1 - vx2 / vx1)
if c2 == 0: continue
t2 = (c1 / c2)
t1 = (px2 - px1) / vx1 + (vx2 / vx1) * t2
if t1 <= 0 or t2 <= 0: continue
if not lo < px1 + vx1 * t1 < hi: continue
if not lo < py1 + vy1 * t1 < hi: continue
if not lo < px2 + vx2 * t2 < hi: continue
if not lo < py2 + vy2 * t2 < hi: continue
n += 1
return n


def part2(H):
"""
6 + t variables, 3 * t equations
"""
try:
import z3
except:
return 'Need z3-solver'
Q = {k: z3.Real(k) for k in 'px py pz vx vy vz t0 t1 t2'.split()}
solver = z3.Solver()
solver.add(H[0].px + H[0].vx * Q['t0'] == Q['px'] + Q['vx'] * Q['t0'])
solver.add(H[0].py + H[0].vy * Q['t0'] == Q['py'] + Q['vy'] * Q['t0'])
solver.add(H[0].pz + H[0].vz * Q['t0'] == Q['pz'] + Q['vz'] * Q['t0'])
solver.add(H[1].px + H[1].vx * Q['t1'] == Q['px'] + Q['vx'] * Q['t1'])
solver.add(H[1].py + H[1].vy * Q['t1'] == Q['py'] + Q['vy'] * Q['t1'])
solver.add(H[1].pz + H[1].vz * Q['t1'] == Q['pz'] + Q['vz'] * Q['t1'])
solver.add(H[2].px + H[2].vx * Q['t2'] == Q['px'] + Q['vx'] * Q['t2'])
solver.add(H[2].py + H[2].vy * Q['t2'] == Q['py'] + Q['vy'] * Q['t2'])
solver.add(H[2].pz + H[2].vz * Q['t2'] == Q['pz'] + Q['vz'] * Q['t2'])
solver.check()
model = solver.model()
return model.eval(Q['px'] + Q['py'] + Q['pz'])


text = open(0).read()
Hail = collections.namedtuple('Hail', 'px py pz vx vy vz')
H = [Hail(*[int(n) for n in re.findall(r'-?\d+', line)]) for line in text.splitlines()]
print(part1(H))
print(part2(H))

+ 66
- 0
y2023/p25.py Vedi File

@@ -0,0 +1,66 @@
import random
import itertools
import copy
import collections


def make_graph(text):
graph = collections.defaultdict(set)
for aa, *bbs in map(str.split, text.replace(':', '').splitlines()):
graph[aa] |= set(bbs)
for bb in bbs:
graph[bb] |= {aa}
return graph


def cut(graph, wires):
graph = graph.copy()
for aa, bb in wires:
graph[aa] = graph[aa] - {bb}
graph[bb] = graph[bb] - {aa}
return graph


def subgraphs(graph):
conns = []
while graph:
state = {next(iter(graph))}
seen = set()
while state:
state = {new for old in state for new in graph[old] if new not in seen}
seen |= state
conns.append(seen)
for node in seen:
graph.pop(node)
return conns


def shortest_path(graph, aa, bb):
state = {aa: None}
seen = {}
while bb not in state:
state = {new: old for old in state for new in graph[old] if new not in seen}
seen |= state

path = [bb]
while path[-1] != aa:
path.append(seen[path[-1]])
return path


def rank_wires(graph, n_cycles=100, n_top=20):
tally = collections.Counter()
for aa, bb in sorted(itertools.combinations(graph, 2))[:n_cycles]:
path = shortest_path(graph, aa, bb)
tally.update(frozenset(pair) for pair in zip(path, path[1:]))
return [k for k, _ in tally.most_common(n_top)]


text = open(0).read()
graph = make_graph(text)
for triplet in itertools.combinations(rank_wires(graph), 3):
mod_graph = cut(graph, triplet)
subs = subgraphs(mod_graph)
if len(subs) == 2:
print(len(subs[0]) * len(subs[1]))
break

Loading…
Annulla
Salva