Published
Edited
Dec 14, 2020
Insert cell
Insert cell
Insert cell
function parseInput(input) {
return input
.trim()
.split('\n')
.map(line => {
line = line.split(' = ');
if (line[0].startsWith("mem")) {
line[0] = +line[0].substring(4, line[0].indexOf("]"));
line[1] = BigInt(line[1]);
} else {
const mask = line[1];
let and = 0n, // 111111111111111111111111111111111111
or = 0n,
idx = 1n;
for (let i = mask.length - 1; i >= 0; i--) {
const char = mask[i];
if (char === "X") {
// don't and-mask away if "X"
and += idx;
} else if (char === "1") {
and += idx; // or-mask should be applied after and, but still
or += idx;
} else if (char === "0") {
// and += idx; // and-mask away
}
idx *= 2n;
}
line[1] = { mask, and, or };
}
return line;
});
}
Insert cell
input_text = FileAttachment("Avent of Code 2020 - Day 14.txt").text()
Insert cell
Insert cell
testInput = parseInput(`mask = XXXXXXXXXXXXXXXXXXXXXXXXXXXXX1XXXX0X
mem[8] = 11
mem[7] = 101
mem[8] = 0`)
Insert cell
function* q1(input) {
const memory = new Map();
let and = 0n;
let or = 0n;
let address = 0;
let value = 0n,
maskedVal = 0n;
for (let i = 0; i < input.length; i++) {
const instruction = input[i];
if (instruction[0] === "mask") {
and = instruction[1].and;
or = instruction[1].or;
} else {
[address, value] = instruction;
maskedVal = (value & and) | or;
memory.set(address, maskedVal);
}
yield {
i,
mask: instruction[0] === "mask",
address,
value,
maskedVal,
and: and.toString(2),
or: or.toString(2),
memory,
sum: "?"
};
}
let sum = 0n;
for (const [key, value] of memory) {
sum += value;
}

yield {
i: input.length - 1,
mask: input[input.length - 1][0] === "mask",
address,
value,
maskedVal,
and: and.toString(2),
or: or.toString(2),
memory,
sum
};
}
Insert cell
q1(testInput)
Insert cell
answer1 = q1(input)
Insert cell
Insert cell
function parseInput2(input) {
return input
.trim()
.split('\n')
.map(line => {
line = line.split(' = ');
if (line[0].startsWith("mem")) {
line[0] = BigInt(line[0].substring(4, line[0].indexOf("]")));
line[1] = BigInt(line[1]);
} else {
const mask = line[1];
let and = [0n],
or = [0n];
let bit = 1n;
for (let i = mask.length - 1; i >= 0; i--) {
const char = mask[i];
if (char === "X") {
// duplicate all masks: one that writes a 0, so ((&0)|0),
// and one that writes a 1, so ((&1)|1). Note that both
// masks default to 0, so only the latter has to be made.
const length = and.length;
for (let i = 0; i < length; i++) {
and.push(and[i] + bit);
or.push(or[i] + bit);
}
} else if (char === "1") {
// set current bit in all "or" masks to 1
for (let i = 0; i < or.length; i++) {
and[i] += bit;
or[i] += bit;
}
} else if (char === "0") {
// "do nothing" = "& 1 | 0" for the current bit
for (let i = 0; i < and.length; i++) {
and[i] += bit;
}
}
bit *= 2n;
}
line[1] = { mask, and, or };
}
return line;
});
}
Insert cell
function* q2(input) {
const memory = new Map();
let and = [];
let or = [];
let address = 0;
let value = 0n,
maskedVal = 0n;
for (let i = 0; i < input.length; i++) {
const instruction = input[i];
if (instruction[0] === "mask") {
and = instruction[1].and;
or = instruction[1].or;
} else {
[address, value] = instruction;
for (let j = 0; j < and.length; j++) {
const maskedAddress = (address & and[j]) | or[j];
memory.set(maskedAddress, value);
}
}
yield {
i,
mask: instruction[0] === "mask",
address,
value,
memory,
sum: "?"
};
}
let sum = 0n;
for (const [key, value] of memory) {
sum += value;
}

yield {
i: input.length - 1,
mask: input[input.length - 1][0] === "mask",
address,
value,
memory,
sum
};
}
Insert cell
Insert cell
q2(testInput2)
Insert cell
input2 = parseInput2(input_text)
Insert cell
answer2 = q2(input2)
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more