import { readFileSync } from 'fs'; const lines = readFileSync('day14/input').toString().split(/\r?\n/).filter(s => s != ""); type Mask = { mask: string, maskOne: bigint, maskZero: bigint } type MemoryToChange = { memPos: number, newValue: bigint } type Memory = { [id: number] : bigint; } let curMask: Mask; const maskPrefix = "mask = "; const maskX = /X/g; const memRegex = new RegExp('mem\\[(?\\d+)\\] = (?\\d+)'); let memoryPart1: Memory = {}; let memoryPart2: Memory = {}; const calculateMask = (line: string): Mask => { const mask = line.substr(maskPrefix.length); return { mask, maskOne: BigInt("0b" + mask.replace(maskX, '1')), maskZero: BigInt("0b" + mask.replace(maskX, '0')), } } const getMemory = (line: string): MemoryToChange => { const match = memRegex.exec(line); if (match == null || match.groups == undefined) { throw new Error("regex could not find anything"); } return { memPos: parseInt(match.groups['mem']), newValue: BigInt(match.groups['num']) } } const changeMemoryPart1 = (memory: Memory, mask: Mask, memoryToChange: MemoryToChange) => { memory[memoryToChange.memPos] = mask.maskZero | (mask.maskOne & memoryToChange.newValue); } const memoryPosCombinations = (memPosWithX: string, index: number): string[] => { if (index > memPosWithX.length) { return [""]; } const partialMemPositions = memoryPosCombinations(memPosWithX, index + 1); if (memPosWithX[index] != 'X') { return partialMemPositions.map(partialMemPos => memPosWithX[index] + partialMemPos); } return partialMemPositions.map(partialMemPos => '0' + partialMemPos).concat(partialMemPositions.map(partialMemPos => '1' + partialMemPos)); } const combineMaskAndMemPos = (memPosAsBinary: string): ((mask: string, i: number) => string) => { return (mask, i) => { if (mask == '0') { return memPosAsBinary[i]; } else { return mask } }; } const parseBinaryInt = (s: string): number => parseInt(s, 2); const calculateMemoryPositions = (mask: string, memPos: number): number[] => { const memPosAsBinary = memPos.toString(2).padStart(mask.length, "0"); const memPosWithMask = mask.split('').map(combineMaskAndMemPos(memPosAsBinary)).join(''); return memoryPosCombinations(memPosWithMask, 0).map(parseBinaryInt); } const changeMemoryPart2 = (memory: Memory, mask: Mask, memoryToChange: MemoryToChange) => { calculateMemoryPositions(mask.mask, memoryToChange.memPos).forEach(pos => memory[pos] = memoryToChange.newValue); } curMask = calculateMask(lines[0]); for (const line of lines.slice(1)) { if (line.startsWith(maskPrefix)) { curMask = calculateMask(line); continue; } const memoryToChange = getMemory(line); changeMemoryPart1(memoryPart1, curMask, memoryToChange); changeMemoryPart2(memoryPart2, curMask, memoryToChange); } const sumOfMemory1 = Object.values(memoryPart1).reduce(((previousValue, currentValue) => previousValue + currentValue), 0n); const sumOfMemory2 = Object.values(memoryPart2).reduce(((previousValue, currentValue) => previousValue + currentValue), 0n); console.log(sumOfMemory1); console.log(sumOfMemory2);