Skip to content

Commit bb9eb6b

Browse files
committed
chore: wip on 2024 day 24b
This one is not fun. I should have solved it manually.
1 parent 3f84a4f commit bb9eb6b

File tree

1 file changed

+180
-0
lines changed

1 file changed

+180
-0
lines changed

2024/24b.py

+180
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
from aoc import *
2+
from itertools import pairwise, combinations, repeat, product, accumulate, permutations, cycle, combinations_with_replacement
3+
from more_itertools import first_true, flatten, ncycles, first_true, zip_broadcast, windowed, chunked, take, peekable
4+
import re
5+
from blessed import BlessedList
6+
from collections import namedtuple, defaultdict, OrderedDict, Counter, deque, UserList
7+
import operator
8+
from operator import itemgetter
9+
from bisect import *
10+
from functools import reduce, cache, cmp_to_key
11+
import math
12+
from copy import deepcopy
13+
from math import ceil
14+
from heapq import *
15+
import sys
16+
from pprint import pprint as pp
17+
from statistics import mode
18+
from string import ascii_uppercase
19+
import random
20+
21+
def incorrect_z(s: int, n: int) -> [str]:
22+
i = 0
23+
incorrect = []
24+
while s or n:
25+
a = s % 2
26+
b = n % 2
27+
s //= 2
28+
n //= 2
29+
if a != b:
30+
incorrect.append(f'z{i:02}')
31+
i += 1
32+
return incorrect
33+
34+
def first_incorrect_z(s: int, n: int) -> str:
35+
i = 0
36+
while s or n:
37+
a = s % 2
38+
b = n % 2
39+
s //= 2
40+
n //= 2
41+
if a != b:
42+
return f'z{i:02}'
43+
i += 1
44+
45+
def random_number() -> int:
46+
return random.randrange(2**44, 2**45)
47+
return random.randrange(2**45)
48+
49+
def find_all_deps(dependencies, wire, current_set):
50+
if dependencies[wire][0][0] not in 'xy':
51+
current_set.add(dependencies[wire][0])
52+
find_all_deps(dependencies, dependencies[wire][0], current_set)
53+
if dependencies[wire][1][0] not in 'xy':
54+
current_set.add(dependencies[wire][1])
55+
find_all_deps(dependencies, dependencies[wire][1], current_set)
56+
57+
def to_values(num: int, letter: str, values: dict):
58+
for i in range(45):
59+
a = num % 2
60+
num //= 2
61+
values[f'{letter}{a:02}'] = bool(a)
62+
63+
64+
def compute(x: int, y: int, swap) -> int:
65+
values = {}
66+
to_values(x, 'x', values)
67+
to_values(y, 'y', values)
68+
changed = True
69+
while changed:
70+
changed = False
71+
for a, oper, b, c in rul:
72+
# print(a, oper, b, c)
73+
a = swap[a]
74+
b = swap[b]
75+
c = swap[c]
76+
if c not in values and a in values and b in values:
77+
if oper == 'OR':
78+
values[c] = values[a] or values[b]
79+
elif oper == 'AND':
80+
values[c] = values[a] and values[b]
81+
elif oper == 'XOR':
82+
values[c] = values[a] ^ values[b]
83+
else:
84+
print('BAD')
85+
changed = True
86+
# print(rul)
87+
# print(values)
88+
ooo = sorted(((k, c) for k, c in values.items() if k[0] == 'z'), key=lambda x: x[0], reverse=True)
89+
# print(ooo)
90+
return int(''.join(str(int(c)) for _, c in ooo), base=2)
91+
92+
def first_bad(swap):
93+
x = random_number()
94+
y = random_number()
95+
n = x+y
96+
computed = compute(x, y, swap)
97+
if n == computed:
98+
return None
99+
return first_incorrect_z(n, computed)
100+
101+
def main(infi: str):
102+
inp = filerstrip(infi)
103+
inputs, rules = inp.split('\n\n')
104+
values = {}
105+
for i in inputs.split('\n'):
106+
name, val = i.split(': ')
107+
values[name] = bool(int(val))
108+
# print(values)
109+
global rul
110+
rul = []
111+
# print(rules)
112+
dependencies = {}
113+
possible_outputs = set()
114+
for r in rules.split('\n'):
115+
# print(r)
116+
match = re.fullmatch(r'^(.*?) (.*?) (.*?) -> (.*?)$', r)
117+
rul.append((match[1], match[2], match[3], match[4]))
118+
dependencies[match[4]] = (match[1], match[3])
119+
possible_outputs.add(match[4])
120+
possible_outputs.add(match[1])
121+
possible_outputs.add(match[3])
122+
basic_swapper = {k: k for k in possible_outputs}
123+
# print([(k, c) for k, c in values.items() if k[0] == 'z'])
124+
# print(sorted(((k, c) for k, c in values.items() if k[0] == 'z'), key=lambda x: x[0], reverse=True))
125+
# ooo = sorted(((k, c) for k, c in values.items() if k[0] == 'z'), key=lambda x: x[0], reverse=True)
126+
# aaa = sorted(((k, c) for k, c in values.items() if k[0] == 'x'), key=lambda x: x[0], reverse=True)
127+
# bbb = sorted(((k, c) for k, c in values.items() if k[0] == 'y'), key=lambda x: x[0], reverse=True)
128+
# number = int(''.join(str(int(c)) for _, c in ooo), base=2)
129+
# x = int(''.join(str(int(c)) for _, c in aaa), base=2)
130+
# y = int(''.join(str(int(c)) for _, c in bbb), base=2)
131+
# print(bin(x+y))
132+
# print(bin(number))
133+
134+
# deps = incorrect_z(x+y, number)
135+
# print(deps)
136+
# sets = []
137+
# for dep in deps:
138+
# dep_set = set()
139+
# find_all_deps(dependencies, dep, dep_set)
140+
# # print(dep_set)
141+
# sets.append(dep_set)
142+
# print(reduce(operator.and_, sets))
143+
# return
144+
# [find_all_deps(dependencies, dep, dep_set) for dep in deps]
145+
# comb = list(combinations(dep_set, 2))
146+
# # for c in combinations(comb, 4):
147+
# # if len(set(flatten(c))) != 8:
148+
# # continue
149+
# # print(c)
150+
# print(dep_set)
151+
152+
active_swapper = basic_swapper.copy()
153+
while True:
154+
first_incorrect = first_bad(active_swapper)
155+
print('at', first_incorrect)
156+
if first_incorrect is None:
157+
print(active_swapper)
158+
break
159+
dep_set = set()
160+
find_all_deps(dependencies, first_incorrect, dep_set)
161+
for a, b in combinations(dep_set, 2):
162+
new_swapper = active_swapper.copy()
163+
new_swapper[a] = b
164+
new_swapper[b] = a
165+
if any(int(first_bad(new_swapper)[1:]) <= int(first_incorrect[1:]) for i in range(100)):
166+
continue
167+
else:
168+
active_swapper = new_swapper
169+
break
170+
171+
return
172+
173+
DAY = 24
174+
FILE_TEST = f"{DAY}_testa.txt"
175+
# FILE_TEST = f"{DAY}_testb.txt"
176+
FILE_EXP = f"{DAY}_exp.txt"
177+
FILE = f"{DAY}.txt"
178+
# test_and_submit(main, FILE_TEST, FILE_EXP, FILE, DAY)
179+
# print(main(FILE_TEST))
180+
print(main(FILE))

0 commit comments

Comments
 (0)