index.js (6637B)
1 #!/usr/bin/env node 2 3 const fs = require('node:fs'); 4 5 // Parse input into something digestable 6 const input = fs 7 .readFileSync('example.txt', 'utf-8') 8 .split('\r\n').join('\n') 9 .split('\r').join('\n') 10 .split('\n') 11 .filter(e => e) 12 .map(line => { 13 const specs = line.split(' '); 14 const target = specs.shift() 15 .slice(1,-1) 16 .split('') 17 .map(light => light === '#' ? 1 : 0); 18 const joltage_req = specs.pop().slice(1,-1).split(',').map(n => parseInt(n, 10)); 19 const buttons = specs 20 .map(button => button.slice(1,-1) 21 .split(',') 22 .map(toggle => parseInt(toggle, 10)) 23 ) 24 // .sort((a,b) => b.length - a.length) 25 return { 26 target, 27 buttons, 28 joltage_req, 29 30 part1_pattern: null, 31 part1_presses: Infinity, 32 }; 33 }); 34 35 // Caution, modifies in-place 36 function patternResult(lights, buttonSpecs, pressPattern) { 37 if ('number' === typeof pressPattern) pressPattern = pressPattern.toString(2); 38 pressPattern = '0'.repeat(buttonSpecs.length - pressPattern.length) + pressPattern; 39 const result = new Array(lights).fill(0).map(_=>0); 40 for(let i = 0; i < buttonSpecs.length; i++) { 41 if (pressPattern[i] !== '1') continue; 42 const increments = buttonSpecs[i]; 43 for(const j of increments) { 44 result[j]++; 45 } 46 } 47 return result; 48 } 49 50 function patternPresses(pressPattern) { 51 if ('number' === typeof pressPattern) pressPattern = pressPattern.toString(2); 52 return pressPattern.split('').filter(c => c === '1').length; 53 } 54 55 function parityPresses( 56 target, 57 buttons 58 ) { 59 let chosen_pattern = ''; 60 let chosen_presses = Infinity; 61 let chosen_result = []; 62 63 for(let combination = 0; combination < 2**buttons.length; combination++) { 64 const pattern = ('0'.repeat(buttons.length) + combination.toString(2)).slice(-(buttons.length)); 65 const presses = patternPresses(pattern); 66 const result = patternResult(target.length, buttons, pattern); 67 const parity = result.map(n => n % 2); 68 if (parity.join('') !== target) continue; 69 if (presses < chosen_presses) { 70 chosen_presses = presses; 71 chosen_pattern = pattern; 72 chosen_result = result; 73 } 74 } 75 76 return { 77 pattern: chosen_pattern, 78 presses: chosen_presses, 79 result : chosen_result, 80 }; 81 } 82 83 const machines = []; 84 for(const machine of input) { 85 machines.push(machine); 86 const target = machine.target.join(''); 87 const _part1 = parityPresses(target, machine.buttons); 88 machine.part1_pattern = _part1.pattern; 89 machine.part1_presses = _part1.presses; 90 } 91 92 const part1 = machines.reduce((r,machine) => r + machine.part1_presses, 0); 93 process.stdout.write(`------[ Part 1: ${part1} ]------\n`); 94 95 const dict = { 96 light : [], 97 button: [], 98 }; 99 for(let i=0; i<1e2; i++) { 100 dict.light[i] = `_${i.toString(36)}`; 101 dict.button[i] = `__${i.toString(36)}`; 102 } 103 104 const Solver = require('js-solver'); 105 for(const machine of machines) { 106 const equations = {}; 107 const known = {}; 108 109 // Add button<>light mapping 110 for(let btn_idx = 0; btn_idx < machine.buttons.length ; btn_idx++) { 111 for(const light_idx of machine.buttons[btn_idx]) { 112 equations[dict.light[light_idx]] ||= []; 113 equations[dict.light[light_idx]].push(dict.button[btn_idx]) 114 } 115 } 116 // Add inverse for each button 117 for(let btn_idx = 0; btn_idx < machine.buttons.length ; btn_idx++) { 118 119 const selected_light = machine.buttons[btn_idx][0]; 120 const self = dict.button[btn_idx]; 121 const others = equations[dict.light[selected_light]].filter(n => n !== self); 122 equations[self] = `${dict.light[selected_light]} - (${others.join(' + ')})`; 123 124 // // for(const light_idx of machine.buttons[btn_idx]) { 125 // console.log({ btn_idx, selected_light, others, self }); 126 } 127 128 for(const key of Object.keys(equations)) { 129 if (dict.light.includes(key)) equations[key] = equations[key].join(' + '); 130 } 131 132 // console.log({ equations }); 133 134 // Inject known values 135 for(let light_idx = 0; light_idx < machine.joltage_req.length; light_idx++) { 136 known[dict.light[light_idx]] = machine.joltage_req[light_idx]; 137 } 138 139 // console.log({ equations, known }); 140 141 // Let's see what the solver does 142 const machineSolver = new Solver(equations); 143 const output = machineSolver.solve(known); 144 145 console.log({ equations, output }); 146 } 147 148 // const Solver = require('js-solver'); 149 // const methSolver = new Solver({ 150 // }); 151 152 // console.log({ Solver }); 153 154 // // Compare prioritizes overflow 155 // function joltage_cmp(a: number[], b: number[]): number { 156 // for(let idx = 0; idx < b.length; idx++) { 157 // if (a[idx] > b[idx]) return 1; 158 // } 159 // for(let idx = 0; idx < b.length; idx++) { 160 // if (a[idx] < b[idx]) return -1; 161 // } 162 // return 0; // match 163 // } 164 165 // function joltage_mult(len: number, weights: number[], buttons: number[][]) { 166 // const result = new Array(len).fill(0).map(_=>0); 167 // for(let b = 0 ; b < buttons.length ; b++) { 168 // for(const idx of buttons[b]) result[idx] += weights[b]; 169 // } 170 // return result; 171 // } 172 173 // part2_outer: for(const machine of machines) { 174 175 // const weights = new Array(machine.buttons.length).fill(0).map(_=>0); 176 // const len = machine.joltage_req.length; 177 178 // // console.log({ weights, buttons: machine.buttons, m: joltage_mult(machine.joltage_req.length, weights, machine.buttons) }); 179 180 // let cpu_limit = 1e6; 181 182 // let j = 0; 183 // while(1) { 184 185 // if (cpu_limit-- < 0) break; 186 187 // let i = j; 188 // weights[i]++; 189 // let cmp_result = joltage_cmp(joltage_mult(len, weights, machine.buttons), machine.joltage_req); 190 // while(cmp_result > 0) { 191 // weights[i]--; 192 // // i++; 193 // // if (i >= weights.length) { 194 // // weights[j] = Math.max(0, weights[j] - 1); 195 // // j = (j + 1) % weights.length; 196 // // if (j === 0) { 197 // // for(let k = 0 ; k < weights.length ; k++ ) { 198 // // weights[k] = Math.max(0, weights[k] - 1); 199 // // } 200 // // } 201 // // break; 202 // // } 203 // // weights[i]++; 204 // cmp_result = joltage_cmp(joltage_mult(len, weights, machine.buttons), machine.joltage_req); 205 // } 206 // console.log({ weights, cmp_result }); 207 // // if (cmp_result === 0) { 208 // // machine.part2 = weights.reduce((r,a) => r+a, 0); 209 // // continue part2_outer; 210 // // } 211 212 213 // } 214 215 // console.log({ cpu_limit, weights }); 216 217 // // for(let i=0 ; i < weights.length ; i++) { 218 219 220 // // while(joltage_cmp(joltage_mult(len, weights, machine.buttons), machine.joltage_req) < 0) { 221 // // weights[i]++; 222 // // } 223 // // weights[i]--; 224 // // } 225 226 // console.log(machine, weights); 227 // } 228 229 230