import { Dusa } from "https://unpkg.com/dusa@0.0.11/lib/client.js";
const INPUT = `
rn=1,cm-,qp=3,cm=2,qp-,pc=4,ot=9,ab=5,pc-,pc=6,ot=7
`
.trim()
.split(',')
.map((line) => {
const label = line.split('-')[0].split('=')[0];
return {
label,
length: label.length,
ascii: label.split('').map((ch) => ch.charCodeAt(0)),
focal: line[label.length] === '-' ? null : parseInt(line.slice(label.length + 1)),
};
});
const dusa = new Dusa(`
# AOC Day 15, Part 2
#builtin INT_PLUS plus
#builtin INT_TIMES times
#builtin INT_MINUS minus
#builtin NAT_SUCC s
numBoxes is 256.
entries is N :- field _ "entries" is N.
labelLength Label is Len :-
field Ref "length" is Len,
field Ref "label" is Label.
ascii Label N is Ch :-
field _ Entry is Ref,
field Ref "label" is Label,
field Ref "ascii" is Str,
field Str N is Ch.
label Entry is Label :-
field _ Entry is Ref,
field Ref "label" is Label.
instruction Entry is del :-
field _ Entry is Ref,
field Ref "focal" is ().
instruction Entry is add N :-
field _ Entry is Ref,
field Ref "focal" is N, N != ().
# Hash computation
partialHash Label 0 is 0 :- ascii Label _ is _.
partialHash Label (s N) is Next :-
partialHash Label N is Val,
ascii Label N is Code,
X == times 17 (plus Val Code),
mod256 X is Next.
needMod256 X X :-
partialHash Label N is Val,
ascii Label N is Code,
X == times 17 (plus Val Code).
hash Label is Hash :-
partialHash Label (labelLength Label) is Hash.
# LOL, division by repeated subtraction
mod256 X is Y :-
needMod256 X Y,
Y < 256.
needMod256 X (minus Y 256) :-
needMod256 X Y,
Y >= 256.
instructionBox Box Entry Label Instr :-
label Entry is Label,
hash Label is Box,
instruction Entry is Instr.
`);
dusa.load({ data: INPUT, entries: INPUT.length }, 'field');
const instrs = Array.from({ length: 256 }).map((_, i) => []);
for (const [box, _entry, label, instr] of dusa.solution.lookup('instructionBox')) {
instrs[box].push({ label, instr });
}
const EVAL_PROGRAM = `
#builtin INT_PLUS plus
#builtin INT_TIMES times
#builtin INT_MINUS minus
#builtin NAT_SUCC s
contents 0 is nil.