103 lines
3.2 KiB
TypeScript
103 lines
3.2 KiB
TypeScript
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\\[(?<mem>\\d+)\\] = (?<num>\\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); |