Public
Edited
Dec 17, 2022
1 fork
Importers
1 star
Insert cell
Insert cell
aoc = ({
lines,
resultTable,
paragraphs,
paragraphLines,
identity,
meta,
gcd,
lcm
})
Insert cell
Insert cell
identity = (d) => d
Insert cell
stringPrep = (s) => s.trim().replace(/\r/g, "")
Insert cell
function lines(accessor = identity) {
return (s) => stringPrep(s).split("\n").map(accessor);
}
Insert cell
paragraphLines = (lineMapper) =>
paragraphs((p) => p.split("\n").map(lineMapper))
Insert cell
function paragraphs(paragraphMapper = identity) {
return (s) => stringPrep(s).split("\n\n").map(paragraphMapper);
}
Insert cell
meta = (info) => {
for (const key of ["day", "parse", "inputs", "parts", "expected"]) {
if (!Object.hasOwn(info, key)) throw new Error(`missing meta key ${key}`);
}
return {
year: 2022,
...info
};
}
Insert cell
gcd = (a, b) => {
while (a != b) {
if (a > b) {
a = a - b;
} else {
b = b - a;
}
}
return a;
}
Insert cell
lcm = (a, b) => (a * b) / gcd(a, b)
Insert cell
Insert cell
async function* resultTable({ parse, inputs, parts, expected, skip = [] }) {
function render(data) {
return htl.html`<table>
<thead>
<tr>
<th>Case</th>
${parts.map(
(d, i) => htl.html`<th style="text-align: end">Part ${i + 1}</th>`
)}
</tr>
</thead>
<tbody>
${Object.entries(data).map(
([k, v]) =>
htl.html`<tr>
<td>${k}</td>
${v.map((d) => {
return htl.html`<td style="text-align: end">
${
d.duration !== undefined
? htl.html`<span style="font-size: 0.7em; color: #888;">(${d.duration.toFixed(
1
)}ms)</span>`
: ""
}
${
!d.running &&
!d.error &&
d.expected !== undefined &&
d.actual !== undefined
? d.expected === d.actual
? "✅"
: "❌"
: ""
}
${d.running ? "⏰" : d.error ?? d.actual}
${
d.skip
? htl.html`<span style="font-size: 0.7em; color: #888;">N/A</span>`
: ""
}
</td>`;
})}
</tr>`
)}
</tbody>
</table>`;
}

let results = Object.fromEntries(
Object.keys(inputs).map((name) => [
name,
parts.map((d, idx) => ({
expected: expected?.[name]?.[idx],
actual: undefined,
error: undefined,
running: false
}))
])
);
yield render(results);

for (const [name, input] of Object.entries(inputs)) {
for (const [part, idx] of Array.from(parts, (d, i) => [d, i])) {
let target = results[name][idx];
if (skip.some((s) => s.input === name && s.part === idx + 1)) {
target.skip = true;
continue;
}
target.running = true;
yield render(results);
let start = performance.now();
let parsed = parse(input);
try {
target.actual = await part(parsed);
} catch (err) {
target.error = err;
}
let end = performance.now();
target.duration = end - start;
target.running = false;
yield render(results);
}
}
}
Insert cell
/**
* Input: a list of {parse, input, solver, expected} which represents one cell in the table.
* output: yield one row per input, with the result of evaluating the solver,
* including any errors, if it matched the expectations, and timing data.
* Returned in an arbitrary order.
*/
async function* genResults(specs) {
let results = specs.map(({ idObj, expected }) => ({
...idObj,
actual: null,
error: null,
duration: null,
expected,
state: "waiting"
}));

let indexes = d3.shuffle(Object.keys(specs));
for (const idx of indexes) {
const { parse, input, solver, expected, idObj } = specs[idx];
let r = results[idx];
r.state = "running";
yield results;
let start = performance.now();
try {
let parsed = parse(input);
r.actual = solver(parsed);
r.state = "done";
} catch (err) {
r.error = err;
r.state = "error";
}
r.duration = performance.now() - start;
yield results;
}
}
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