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
}