import numpy as np
import random
with open('data-2025-10.txt', 'r') as f:
inp = f.read().splitlines()
lights = [i.split() for i in inp]
bins = []
# https://stackoverflow.com/a/38311834
replacements = {'.': 0, '#': 1}
replacer = replacements.get
def convert_butts(bb, k):
bl = []
for b in bb:
c = b[1:-1].split(',')
c = [int(z) for z in c]
d = [int(i in c) for i in range(k)]
bl.append(d)
return bl
# preparation
for l in lights[:]:
# convert the lights to binary list
ind = list(l[0][1:-1])
ind = [replacer(n, n) for n in ind]
# convert the joltage to list of integers
jolt = l[-1][1:-1].split(',')
jolt = [int(j) for j in jolt]
# convert the button lists into binary lists
butt = l[1:-1]
butt = convert_butts(butt, len(ind))
bins.append([ind, butt, jolt])
# binsAdvent of Code 2025 Day 10
— Day 10: Factory —
Press some buttons and turn on some lights. Ignore the joltage for now.
Analyze each machine’s indicator light diagram and button wiring schematics. What is the fewest button presses required to correctly configure the indicator lights on all of the machines?
That’s quite a lot of preparation! But I think we are on the right path.
I think we need to do some matrix multiplication, for the number of each button press, to equal the light indicators. Pushing a button more than once means wasted operations - turning the lights on then off again, which is pointless. Watch out for this in part two, I’m sure!
Counting to 10 bits in binary is not ideal, but we will go with it.
Is it actually multiplication? Could just be addition. It’s more like a sumproduct?
summer = 0
for b in bins:
# loop all the things
# create high number for initial comparison
num = 999
# length of lights
# b
# b[0]
j = len(b[0])
k = len(b[1])
# j,k
# loop our binary number of times for buttons
for m in range(2**k-1):
# m
s = list(bin(m))[2:]
s = [int(t) for t in s]
s = [0]*(k-len(s)) + s
# s
v = [0] * j
# # do the math
for t in range(k):
if s[t] == 1:
v = [sum(x) for x in zip(v,b[1][t])]
# do a comparison to see if the lights are correct
# if they are correct, check if it's a good solution
# replace num
v = [w % 2 for w in v]
# v
if v == b[0]:
# v
# s
if sum(s) < num:
num = sum(s)
# once we have checked all the possibilities, update summer
summer += num
summer404
— Part Two —
Now we have to worry about the joltage requirements. We can press the buttons as many times as we like.
Analyze each machine’s joltage requirements and button wiring schematics. What is the fewest button presses required to correctly configure the joltage level counters on all of the machines?
Keep doing a similar loop to the above and we will sooner or later find the right one. Is it always going to be the first combination we find? Let’s try it and see.
mx = 0
for b in bins:
# test the maximum of the joltage
if max(b[2]) > mx:
mx = max(b[2])
# the differences in highest and lowest joltage for each row
# max(b[2]) - min(b[2])
# the length of each button list
# if len(b[1]) >10:
# b
# mxWe have to go through 305 times, at least, just in case the right combination doesn’t come along in that time. Let’s assume it does at first. We can figure the maximum for each loop. But we also have to find a way to efficiently try different numbers of button presses up to that maximum.
There’s also a minimum we have - the smallest number in the joltage. That helps us a little bit.
Is there just one answer for each thing or could there be many? We could try an optimisation technique for linear programming, move around until we get a better answer. “If this number needs to go up then increase one of the lists that has that index in it”. Or: “if this change decreases the difference between our current joltage and the required joltage then make the change”. Enumerating the options for this is probably better than brute force.
summer = 0
for b in bins[:2]:
# loop all the things
# create high number for initial comparison
num = 9999
# length of lights
# b
# b[0]
j = len(b[2])
k = len(b[1])
# j,k
# np array of buttons
bnp = np.array(b[1])
# minimum and maximum of target
mn = min(b[2])
mx = max(b[2])
# create initial button press list
press = np.array([random.randint(mn, mx) for _ in range(k)])
press
bnp.T.dot(press)
# once we have checked all the possibilities, update summer
summer += num
summer19998
Insight 1: There is likely to be at least one press of each button. We can’t count on that because Advent of Code, but it’s likely.
Insight 2: The sum of the joltage numbers divided by the sum of the button numbers gives us the average number of presses for each button.
There’s going to be some weird scenarios where [0,1,0], [0,0,1] needs to equal [0,3,47]. Do I start at zero and make my way up? What movement gets us closer to the objective. Yeah, I think this takes me back to a linear program.
https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.milp.html
from scipy.optimize import LinearConstraint, milp
obj = np.array([1,1,1,1,1])
lhs = np.array(bins[0][1]).T
rhs = bins[0][2]
constraints = LinearConstraint(lhs, rhs, rhs)
integrality = np.ones_like(obj)
res = milp(c=obj, constraints=constraints, integrality=integrality)
res.x
sum(res.x)np.float64(32.0)
Yeah fuck yeah
summer = 0
for b in bins:
obj = np.array([1]*len(b[1]))
# np array of buttons
lhs = np.array(b[1]).T
# target joltage
rhs = b[2]
# problem specification and solution
constraints = LinearConstraint(lhs, rhs, rhs)
integrality = np.ones_like(obj)
res = milp(c=obj, constraints=constraints, integrality=integrality)
# add the result
summer += sum(res.x)
int(summer)16474