66 lines
2 KiB
JavaScript
66 lines
2 KiB
JavaScript
|
const fs = require('fs');
|
||
|
const input = fs.readFileSync('input.txt', 'utf-8').split('\n').map(l=>l.split(' = '));
|
||
|
|
||
|
let mask = [];
|
||
|
let mem = new Map();
|
||
|
let memo = new Map()
|
||
|
let runningTotal = 0
|
||
|
input.forEach((command,i) => {
|
||
|
if (command[0] == 'mask') {
|
||
|
// reset the mask and memorised values from that mask
|
||
|
mask = command[1].split('');
|
||
|
memo = new Map();
|
||
|
} else {
|
||
|
let value = Number(command[1]);
|
||
|
let index = Number(command[0].substring(4,command[0].length-1)).toString(2);
|
||
|
while (index.length < mask.length) {
|
||
|
index = '0' + index;
|
||
|
}
|
||
|
let addresses = [...address(index.split(''))]
|
||
|
addresses.forEach(add => {
|
||
|
// keep a running total instead of adding it up at the end by adding the value and subtracting the value that it replaces
|
||
|
runningTotal += value - (mem.get(parseInt(add, 2))||0)
|
||
|
mem.set(parseInt(add, 2), value)
|
||
|
})
|
||
|
}
|
||
|
});
|
||
|
console.log(runningTotal)
|
||
|
|
||
|
// calculate all addresses from a given address after the mask is applied
|
||
|
function address(loc, i = 0, found = new Set()) {
|
||
|
// reached the end of the address
|
||
|
if (i >= mask.length) {
|
||
|
// add the new address
|
||
|
return found.add(loc.join(''))
|
||
|
}
|
||
|
// if I have already seen this address ending
|
||
|
let key = loc.slice(i).join('')
|
||
|
if (memo.has(key)) {
|
||
|
// add all the addresses that result from this ending
|
||
|
let prefix = loc.slice(0,i).join('');
|
||
|
[...memo.get(key)].forEach(suffix => {found.add(prefix+suffix)});
|
||
|
return found
|
||
|
}
|
||
|
// apply the mask from point i and get all possibilities into the array rem
|
||
|
let rem = []
|
||
|
switch (mask[i]) {
|
||
|
case '1':
|
||
|
loc[i] = '1'
|
||
|
case '0':
|
||
|
rem = [...address([...loc],i+1,found)]
|
||
|
break;
|
||
|
case 'X':
|
||
|
loc[i] = '0';
|
||
|
rem = [...address([...loc],i+1,found)]
|
||
|
loc[i] = '1';
|
||
|
rem.push(...[...address([...loc],i+1,found)])
|
||
|
break;
|
||
|
default:
|
||
|
console.log('oops, bad mask at index', i)
|
||
|
}
|
||
|
// store the possibilities in the memo in case we come across this pattern again.
|
||
|
memo.set(key, new Set(rem.map(o => o.slice(i))))
|
||
|
return found
|
||
|
}
|
||
|
|