Skip to content

Instantly share code, notes, and snippets.

@dkaraush
Last active December 11, 2025 11:14
Show Gist options
  • Select an option

  • Save dkaraush/a4f61dd3a7eb7b03ea93e169e2c4407b to your computer and use it in GitHub Desktop.

Select an option

Save dkaraush/a4f61dd3a7eb7b03ea93e169e2c4407b to your computer and use it in GitHub Desktop.
input = document.querySelector('pre').innerText.trim().split('\n').map(line => line.substring(1,line.length-1).split(/\] \(|\) \{/g)).map(([a,b,c]) => [a.split('').map(c=>c=='#'), b.split(') (').map(b => b.split(',').map(x=>parseInt(x))), c.split(',').map(x=>parseInt(x))])
const sumOfValues = o => Object.values(o).reduce((a,b)=>a+b,0)
const matrix = (buttons, joltage) =>
joltage.map((r, i) => [...buttons.map(btn => btn.indexOf(i) >= 0 ? 1 : 0), r])
// Gaussian elimination
// https://en.wikipedia.org/wiki/Gaussian_elimination
function gaussian(
M,
EPS = 1e-8,
m = M.length, n = M[0].length,
upper = [...Array(n - 1)].map((_, c, __, upper = Infinity) => {
for (let r = 0; r < m; ++r)
if (M[r][c] > 0)
upper = Math.min(upper, Math.ceil(M[r][n - 1] / M[r][c]))
return !Number.isFinite(upper) ? 0 : upper
}),
indexOfMax = (from, to, predicate, max = 0, idx = -1) => {
for (let i = from; i < to; ++i) {
const x = predicate(i)
if (x > max) { max = x; idx = i; }
}
return idx
},
swap = (i, j, tmp = M[i]) => { M[i] = M[j]; M[j] = tmp; },
solve = (M, solution = {}) => {
for (let r = m - 1; r >= 0; --r) {
let sum = M[r][n - 1]
let unknown = -1
for (let c = 0; c < n - 1; ++c) {
if (Math.abs(M[r][c]) > EPS) {
if (unknown < 0) unknown = c
else if (solution[c] === undefined) return null
else sum -= M[r][c] * solution[c]
}
}
if (unknown >= 0) {
sum /= M[r][unknown]
if (Math.abs(sum - Math.round(sum)) > EPS) return null
if (Math.round(sum) < 0) return null
solution[unknown] = Math.round(sum)
} else if (Math.abs(sum) > EPS)
return null
}
return solution
}
) {
// https://en.wikipedia.org/wiki/Gaussian_elimination#Pseudocode
let h = 0, k = 0
for (let k = 0; k < n && h < m; ++k) {
const i_max = indexOfMax(h, m, i => Math.abs(M[i][k]))
if (i_max < 0) continue
swap(h, i_max)
for (let i = h + 1; i < m; ++i) {
const f = M[i][k] / M[h][k]
M[i][k] = 0
for (let j = k + 1; j < n; ++j)
M[i][j] -= M[h][j] * f
}
h++
}
// gather solution
const solution = solve(M)
if (solution && Object.keys(solution).length == n - 1)
return solution
// free unknown variables, gotta loop through each up to upper bound
const free = [...Array(n - 1)].map((_,i)=>i).filter(C => {
for (let r = 0; r < m; ++r)
for (let c = 0; c < n - 1; ++c) {
if (Math.abs(M[r][c]) > EPS) {
if (c === C) return false
break
}
}
return true
})
return (function i(values = []) {
if (values.length == free.length)
return solve(M, Object.fromEntries(free.map((idx, i) => [idx, values[i]])))
let solution = null
for (let v = 0; v <= upper[free[values.length]]; ++v) {
const thisSolution = i([...values, v])
if (!thisSolution) continue
if (solution == null || sumOfValues(thisSolution) < sumOfValues(solution))
solution = thisSolution
}
return solution
})()
}
const result2 = input.reduce((acc, [_, buttons, joltage]) => acc + sumOfValues(gaussian(matrix(buttons, joltage))), 0)
console.log({ result2 })
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment