102 lines
2.9 KiB
TypeScript
102 lines
2.9 KiB
TypeScript
|
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);
|
||
|
}
|