aoc-2023/day_18/solver.ts

102 lines
2.9 KiB
TypeScript
Raw Permalink Normal View History

2024-12-09 22:41:02 +09:00
export type Direction = "R" | "L" | "U" | "D";
export type Instruction = {
direction: Direction;
steps: number;
color: number;
}
export function parseInput(content: string): Instruction[] {
const lines = content.split("\n").map(x => x.trim()).filter(x => x.length > 0);
return lines.map(line => {
const m = /^([RDLU])\s+(\d+)\s+\(#([0-9a-f]+)\)$/.exec(line);
if (!m) {
throw new Error(`unknown line ${line}`);
}
return {
direction: m[1] as Direction,
steps: parseInt(m[2]),
color: parseInt(m[3], 16),
}
});
}
export async function readInput(filename: string): Promise<Instruction[]> {
const input = await Deno.readTextFile(filename);
return parseInput(input);
}
/**
* Clockwise direction
*/
const CW = [
"R", "D", "L", "U"
]
/**
* generate a line of edge
* @param insts array of instructions
*/
export function transformEdgeLine(insts: Instruction[]) {
const newInst = [];
let nextInstBonus = 1;
for (let i = 0; i < insts.length - 1; i++) {
const inst = insts[i];
const nextInst = insts[i + 1];
const dir = CW.indexOf(inst.direction);
const nextDir = CW.indexOf(nextInst.direction);
if (dir === nextDir) {
nextInstBonus += inst.steps;
}
else if ((dir + 2) % CW.length === nextDir) {
throw new Error("invalid direction");
}
else if ((dir + 1) % CW.length === nextDir) {
newInst.push({
direction: inst.direction,
steps: inst.steps + nextInstBonus,
color: inst.color
});
nextInstBonus = 1;
}
else if ((dir + CW.length - 1) % CW.length === nextDir) {
newInst.push({
direction: inst.direction,
steps: inst.steps + nextInstBonus - 1,
color: inst.color
});
nextInstBonus = 0;
}
else {
console.log(`unknown direction ${inst.direction} ${nextInst.direction}`);
}
}
newInst.push({
direction: insts[insts.length - 1].direction,
steps: insts[insts.length - 1].steps + nextInstBonus,
color: insts[insts.length - 1].color
});
return newInst;
}
export function calcArea(insts: Instruction[]) {
let pos = [0, 0];
let area = 0;
transformEdgeLine(insts).forEach(inst => {
if (inst.direction === "R") {
pos = [pos[0] + inst.steps, pos[1]];
area += inst.steps * pos[1];
}
if (inst.direction === "L") {
pos = [pos[0] - inst.steps, pos[1]];
area -= inst.steps * pos[1];
}
if (inst.direction === "U") {
pos = [pos[0], pos[1] - inst.steps];
}
if (inst.direction === "D") {
pos = [pos[0], pos[1] + inst.steps];
}
});
return Math.abs(area);
}