Last active
December 11, 2025 11:14
-
-
Save dkaraush/a4f61dd3a7eb7b03ea93e169e2c4407b to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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