Public
Edited
Dec 2
Paused
1 fork
1 star
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function parse(input) {
const [boardTxt, movesTxt] = input.split("\n\n");
const board = boardTxt.split("\n").map((l) => {
const row = [];
l.split("").forEach((c, i) => {
if (c === "." || c === "#") {
row[i] = c;
}
});
return row;
});
const moves = movesTxt
.split(/([RL])/)
.map((instr) => (isNaN(instr) ? instr : Number(instr)));

return [board, moves];
}
Insert cell
Insert cell
Insert cell
Dir = ({
Up: AOC.type("Up", []),
Down: AOC.type("Down", []),
Left: AOC.type("Left", []),
Right: AOC.type("Right", [])
})
Insert cell
Insert cell
function dirVector(dir) {
return dir.case({
Up: () => [-1, 0],
Down: () => [1, 0],
Left: () => [0, -1],
Right: () => [0, 1]
});
}
Insert cell
Insert cell
function dirScore(dir) {
return dir.case({
Up: () => 3,
Down: () => 1,
Left: () => 2,
Right: () => 0
});
}
Insert cell
Insert cell
function turn(t, dir) {
return dir.case({
Up: () => (t === "L" ? Dir.Left : Dir.Right),
Down: () => (t === "L" ? Dir.Right : Dir.Left),
Left: () => (t === "L" ? Dir.Down : Dir.Up),
Right: () => (t === "L" ? Dir.Up : Dir.Down)
});
}
Insert cell
Insert cell
function move(instr, [r, c, dir], board) {
if (isNaN(instr)) {
return [r, c, turn(instr, dir)]; // Turn instruction.
} else {
// Move in current direction
const next = (r, c, [dr, dc]) => {
let rNext = r;
let cNext = c;
do {
rNext = dr === 0 ? rNext : (rNext + dr + board.length) % board.length;
cNext =
dc === 0
? cNext
: (cNext + dc + board[rNext].length) % board[rNext].length;
} while (board[rNext][cNext] === undefined);
return [rNext, cNext];
};

let [rNext, cNext] = next(r, c, dirVector(dir));
let nMoves = instr;
while (nMoves > 0 && board[rNext][cNext] === ".") {
nMoves--;
r = rNext;
c = cNext;
[rNext, cNext] = next(r, c, dirVector(dir));
}
return [r, c, dir];
}
}
Insert cell
Insert cell
function part1(input) {
const [board, moves] = parse(input);
let [r, c, dir] = [0, board[0].indexOf("."), Dir.Right];
moves.forEach((instr) => {
[r, c, dir] = move(instr, [r, c, dir], board);
});
return 1000 * (r + 1) + 4 * (c + 1) + dirScore(dir);
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function edgeCrossing(row, col, dir) {
const fSize = 50;
const maxF = fSize - 1;
const nCols = 3; // Specific to the net in the puzzle input.
const toFace = (r, c) =>
Math.floor(r / fSize) * nCols + Math.floor(c / fSize);
const fromFace = (f) => [fSize * Math.floor(f / nCols), fSize * (f % nCols)];
const fRow = row % fSize;
const fCol = col % fSize;
const currentFace = toFace(row, col);

if (currentFace === 1) {
return dir.case({
Right: () => [Dir.Right, AOC.vAdd(fromFace(2), [fRow, maxF - fCol])],
Down: () => [Dir.Down, AOC.vAdd(fromFace(4), [maxF - fRow, fCol])],
Left: () => [Dir.Right, AOC.vAdd(fromFace(6), [maxF - fRow, fCol])],
Up: () => [Dir.Right, AOC.vAdd(fromFace(9), [fCol, fRow])]
});
}
if (currentFace === 2) {
return dir.case({
Left: () => [Dir.Left, AOC.vAdd(fromFace(1), [fRow, maxF - fCol])],
Down: () => [Dir.Left, AOC.vAdd(fromFace(4), [fCol, fRow])],
Right: () => [Dir.Left, AOC.vAdd(fromFace(7), [maxF - fRow, fCol])],
Up: () => [Dir.Up, AOC.vAdd(fromFace(9), [maxF - fRow, fCol])]
});
}
if (currentFace === 4) {
return dir.case({
Up: () => [Dir.Up, AOC.vAdd(fromFace(1), [maxF - fRow, fCol])],
Right: () => [Dir.Up, AOC.vAdd(fromFace(2), [fCol, fRow])],
Left: () => [Dir.Down, AOC.vAdd(fromFace(6), [fCol, fRow])],
Down: () => [Dir.Down, AOC.vAdd(fromFace(7), [maxF - fRow, fCol])]
});
}
if (currentFace === 6) {
return dir.case({
Left: () => [Dir.Right, AOC.vAdd(fromFace(1), [maxF - fRow, fCol])],
Up: () => [Dir.Right, AOC.vAdd(fromFace(4), [fCol, fRow])],
Right: () => [Dir.Right, AOC.vAdd(fromFace(7), [fRow, maxF - fCol])],
Down: () => [Dir.Down, AOC.vAdd(fromFace(9), [maxF - fRow, fCol])]
});
}
if (currentFace === 7) {
return dir.case({
Right: () => [Dir.Left, AOC.vAdd(fromFace(2), [maxF - fRow, fCol])],
Up: () => [Dir.Up, AOC.vAdd(fromFace(4), [maxF - fRow, fCol])],
Left: () => [Dir.Left, AOC.vAdd(fromFace(6), [fRow, maxF - fCol])],
Down: () => [Dir.Left, AOC.vAdd(fromFace(9), [fCol, fRow])]
});
}
if (currentFace === 9) {
return dir.case({
Left: () => [Dir.Down, AOC.vAdd(fromFace(1), [fCol, fRow])],
Down: () => [Dir.Down, AOC.vAdd(fromFace(2), [maxF - fRow, fCol])],
Up: () => [Dir.Up, AOC.vAdd(fromFace(6), [maxF - fRow, fCol])],
Right: () => [Dir.Up, AOC.vAdd(fromFace(7), [fCol, fRow])]
});
}
}
Insert cell
Insert cell
function move2(instr, [r, c, dir], board) {
if (isNaN(instr)) {
return [r, c, turn(instr, dir)]; // Turn instruction.
} else {
// Move in current direction
const next = (r, c, [dr, dc]) => {
if (board[r + dr] === undefined || board[r + dr][c + dc] === undefined) {
// We've crossed an edge.
const [newDir, [newRow, newCol]] = edgeCrossing(r, c, dir);
return [newRow, newCol, newDir];
}
return [r + dr, c + dc, dir];
};

let [rNext, cNext, dirNext] = next(r, c, dirVector(dir));
let nMoves = instr;
while (nMoves > 0 && board[rNext][cNext] === ".") {
nMoves--;
r = rNext;
c = cNext;
dir = dirNext;
[rNext, cNext, dirNext] = next(r, c, dirVector(dir));
}
return [r, c, dir];
}
}
Insert cell
function part2(input) {
const [board, moves] = parse(input);
let [r, c, dir] = [0, board[0].indexOf("."), Dir.Right];
moves.forEach((instr) => {
[r, c, dir] = move2(instr, [r, c, dir], board);
});
return 1000 * (r + 1) + 4 * (c + 1) + dirScore(dir);
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
import { Renderer } from "@jwolondon/renderer"
Insert cell
Insert cell
Insert cell
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