mirror of
https://github.com/Threnklyn/advent-of-code-go.git
synced 2026-06-05 11:50:12 +02:00
251 lines
7.8 KiB
Python
251 lines
7.8 KiB
Python
from collections import defaultdict
|
|
import copy
|
|
|
|
|
|
def part1(input: str) -> int:
|
|
wires, instructions = parse_input(input)
|
|
run(instructions, wires)
|
|
return get_num(wires, "z")
|
|
|
|
|
|
def parse_input(input: str) -> tuple[dict[str, int], list[list[str]]]:
|
|
parts = input.split("\n\n")
|
|
|
|
wires: dict[str, int] = defaultdict(int)
|
|
|
|
for line in parts[0].splitlines():
|
|
wires[line[:3]] = int(line[5:])
|
|
|
|
instructions: list[list[str]] = []
|
|
for line in parts[1].splitlines():
|
|
in1, op, in2, _, out = line.split(" ")
|
|
instructions.append([in1, op, in2, out])
|
|
|
|
return (wires, instructions)
|
|
|
|
|
|
def get_num(wires: dict[str, int], char: str) -> int:
|
|
if len(char) != 1:
|
|
raise Exception("exactly one char needed for get_num")
|
|
keys: list[str] = []
|
|
for wire in wires:
|
|
if wire[0] == char:
|
|
keys.append(wire)
|
|
keys.sort()
|
|
binary_num: str = ""
|
|
for key in reversed(keys):
|
|
binary_num += str(wires[key])
|
|
|
|
return int(binary_num, 2)
|
|
|
|
|
|
def run(instructions: list[list[str]], wires: dict[str, int]):
|
|
processed_lines: set[int] = set()
|
|
while len(processed_lines) < len(instructions):
|
|
processed_before: int = len(processed_lines)
|
|
|
|
for i, inst in enumerate(instructions):
|
|
if i in processed_lines:
|
|
continue
|
|
in1, op, in2, out = inst
|
|
if in1 not in wires or in2 not in wires:
|
|
continue
|
|
|
|
if op == "AND":
|
|
wires[out] = wires[in1] & wires[in2]
|
|
elif op == "OR":
|
|
wires[out] = wires[in1] | wires[in2]
|
|
elif op == "XOR":
|
|
wires[out] = wires[in1] ^ wires[in2]
|
|
|
|
processed_lines.add(i)
|
|
|
|
if len(processed_lines) == processed_before:
|
|
# print("no new lines processed")
|
|
return
|
|
|
|
|
|
# this code is way too slow, works for the examples but unsurprisingly way too
|
|
# slow for the actual input. ditching python for a go solution...
|
|
def part2(input: str) -> str:
|
|
wires, instructions = parse_input(input)
|
|
expected_sum: int = get_num(wires, "x") & get_num(wires, "y")
|
|
|
|
def any_values_are_equal(*args: int) -> bool:
|
|
seen: set[int] = set()
|
|
for val in args:
|
|
if val in seen:
|
|
return True
|
|
seen.add(val)
|
|
return False
|
|
|
|
# generate swaps... maybe 8 nested for loops...
|
|
for a in range(len(instructions)):
|
|
print(a)
|
|
for b in range(a + 1, len(instructions)):
|
|
for c in range(a + 1, len(instructions)):
|
|
if any_values_are_equal(b, c):
|
|
continue
|
|
for d in range(a + 1, len(instructions)):
|
|
if any_values_are_equal(b, c, d):
|
|
continue
|
|
for e in range(a + 1, len(instructions)):
|
|
if any_values_are_equal(b, c, d, e):
|
|
continue
|
|
for f in range(a + 1, len(instructions)):
|
|
if any_values_are_equal(b, c, d, e, f):
|
|
continue
|
|
for g in range(a + 1, len(instructions)):
|
|
if any_values_are_equal(b, c, d, e, f, g):
|
|
continue
|
|
for h in range(a + 1, len(instructions)):
|
|
if any_values_are_equal(b, c, d, e, f, g, h):
|
|
continue
|
|
|
|
instructions[a][3], instructions[b][3] = (
|
|
instructions[b][3],
|
|
instructions[a][3],
|
|
)
|
|
instructions[c][3], instructions[d][3] = (
|
|
instructions[d][3],
|
|
instructions[c][3],
|
|
)
|
|
|
|
instructions[e][3], instructions[f][3] = (
|
|
instructions[f][3],
|
|
instructions[e][3],
|
|
)
|
|
instructions[g][3], instructions[h][3] = (
|
|
instructions[h][3],
|
|
instructions[g][3],
|
|
)
|
|
|
|
wires_copy = copy.deepcopy(wires)
|
|
run(instructions, wires_copy)
|
|
sum = get_num(wires_copy, "z")
|
|
if sum == expected_sum:
|
|
swaps: list[str] = [
|
|
instructions[a][3],
|
|
instructions[b][3],
|
|
instructions[c][3],
|
|
instructions[d][3],
|
|
instructions[e][3],
|
|
instructions[f][3],
|
|
instructions[g][3],
|
|
instructions[h][3],
|
|
]
|
|
swaps.sort()
|
|
return ",".join(swaps)
|
|
# backtrack
|
|
instructions[a][3], instructions[b][3] = (
|
|
instructions[b][3],
|
|
instructions[a][3],
|
|
)
|
|
instructions[c][3], instructions[d][3] = (
|
|
instructions[d][3],
|
|
instructions[c][3],
|
|
)
|
|
instructions[e][3], instructions[f][3] = (
|
|
instructions[f][3],
|
|
instructions[e][3],
|
|
)
|
|
instructions[g][3], instructions[h][3] = (
|
|
instructions[h][3],
|
|
instructions[g][3],
|
|
)
|
|
|
|
raise Exception("should return from loop")
|
|
|
|
|
|
example = """x00: 1
|
|
x01: 1
|
|
x02: 1
|
|
y00: 0
|
|
y01: 1
|
|
y02: 0
|
|
|
|
x00 AND y00 -> z00
|
|
x01 XOR y01 -> z01
|
|
x02 OR y02 -> z02"""
|
|
|
|
print(f"part1 example: {part1(example)} want 4")
|
|
|
|
big_example = """x00: 1
|
|
x01: 0
|
|
x02: 1
|
|
x03: 1
|
|
x04: 0
|
|
y00: 1
|
|
y01: 1
|
|
y02: 1
|
|
y03: 1
|
|
y04: 1
|
|
|
|
ntg XOR fgs -> mjb
|
|
y02 OR x01 -> tnw
|
|
kwq OR kpj -> z05
|
|
x00 OR x03 -> fst
|
|
tgd XOR rvg -> z01
|
|
vdt OR tnw -> bfw
|
|
bfw AND frj -> z10
|
|
ffh OR nrd -> bqk
|
|
y00 AND y03 -> djm
|
|
y03 OR y00 -> psh
|
|
bqk OR frj -> z08
|
|
tnw OR fst -> frj
|
|
gnj AND tgd -> z11
|
|
bfw XOR mjb -> z00
|
|
x03 OR x00 -> vdt
|
|
gnj AND wpb -> z02
|
|
x04 AND y00 -> kjc
|
|
djm OR pbm -> qhw
|
|
nrd AND vdt -> hwm
|
|
kjc AND fst -> rvg
|
|
y04 OR y02 -> fgs
|
|
y01 AND x02 -> pbm
|
|
ntg OR kjc -> kwq
|
|
psh XOR fgs -> tgd
|
|
qhw XOR tgd -> z09
|
|
pbm OR djm -> kpj
|
|
x03 XOR y03 -> ffh
|
|
x00 XOR y04 -> ntg
|
|
bfw OR bqk -> z06
|
|
nrd XOR fgs -> wpb
|
|
frj XOR qhw -> z04
|
|
bqk OR frj -> z07
|
|
y03 OR x01 -> nrd
|
|
hwm AND bqk -> z03
|
|
tgd XOR rvg -> z12
|
|
tnw OR pbm -> gnj"""
|
|
|
|
print(f"part1 big_example: {part1(big_example)} want 2024")
|
|
|
|
input = open("input.txt").read().strip()
|
|
print(f"part1 actual: {part1(input)} want 38869984335432")
|
|
|
|
part2_example_2_pairs_swapped = """x00: 0
|
|
x01: 1
|
|
x02: 0
|
|
x03: 1
|
|
x04: 0
|
|
x05: 1
|
|
y00: 0
|
|
y01: 0
|
|
y02: 1
|
|
y03: 1
|
|
y04: 0
|
|
y05: 1
|
|
|
|
x00 AND y00 -> z05
|
|
x01 AND y01 -> z02
|
|
x02 AND y02 -> z01
|
|
x03 AND y03 -> z03
|
|
x04 AND y04 -> z04
|
|
x05 AND y05 -> z00"""
|
|
|
|
# print(
|
|
# f"part2 example with two swapped {part2(part2_example_2_pairs_swapped)} want z00,z01,z02,z05"
|
|
# )
|
|
|
|
print(f"part2 actual: {part2(input)} want QQ")
|