136 lines
3.6 KiB
TypeScript
136 lines
3.6 KiB
TypeScript
const sample = await Deno.readTextFile("sample.txt");
|
|
const input = await Deno.readTextFile("input.txt");
|
|
|
|
type Direction = "D" | "R" | "L" | "U";
|
|
type Vector = [number, number];
|
|
type Step = { h: Vector; t: Vector };
|
|
|
|
const vector = {
|
|
add(vec1: Vector, vec2: Vector): Vector {
|
|
return [vec1[0] + vec2[0], vec1[1] + vec2[1]];
|
|
},
|
|
distance(vec1: Vector, vec2: Vector): number {
|
|
return Math.sqrt((vec2[0] - vec1[0]) ** 2 + (vec2[1] - vec1[1]) ** 2);
|
|
},
|
|
between(vec1: Vector, vec2: Vector): Vector {
|
|
return [
|
|
Math.floor((vec1[0] + vec2[0]) / 2),
|
|
Math.floor((vec1[1] + vec2[1]) / 2),
|
|
];
|
|
},
|
|
} as const;
|
|
|
|
const directions: Record<Direction, Vector> = {
|
|
R: [1, 0],
|
|
D: [0, 1],
|
|
L: [-1, 0],
|
|
U: [0, -1],
|
|
};
|
|
|
|
/**** PART 1 ********************************/
|
|
function lerp(start: number, end: number, t: number): number {
|
|
return (1 - t) * start + t * end;
|
|
}
|
|
|
|
function mapRange(
|
|
value: number,
|
|
start1: number,
|
|
end1: number,
|
|
start2: number,
|
|
end2: number
|
|
): number {
|
|
const t = (value - start1) / (end1 - start1);
|
|
return lerp(start2, end2, t);
|
|
}
|
|
|
|
const print = (width: number, height: number, steps: Step[]): void => {
|
|
const grid = Array.from(new Array(height), () =>
|
|
Array.from(new Array(width), () => ".")
|
|
);
|
|
|
|
steps.forEach(({ t }) => {
|
|
grid[t[0]][t[1]] = "#";
|
|
});
|
|
|
|
for (let y = 0; y < height; y += 1) {
|
|
let line = "";
|
|
for (let x = 0; x < width; x += 1) {
|
|
line += grid[y][x];
|
|
}
|
|
console.log(line);
|
|
}
|
|
};
|
|
|
|
const solvePart1 = (data: string): number | any => {
|
|
const visitedSteps = data
|
|
.split("\n")
|
|
.filter(Boolean)
|
|
.map((line) => line.split(" ") as [string, string])
|
|
.map(([dir, amount]): [Direction, number] => [
|
|
dir as Direction,
|
|
parseFloat(amount),
|
|
])
|
|
.reduce(
|
|
(steps, [dir, amount]) => {
|
|
for (let i = 0; i < amount; i += 1) {
|
|
const { h, t } = steps[steps.length - 1];
|
|
const h2 = vector.add(h, directions[dir]);
|
|
const t2 = vector.distance(h2, t) >= 1.5 ? h : t;
|
|
steps.push({ h: h2, t: t2 });
|
|
}
|
|
return steps;
|
|
},
|
|
[{ h: [0, 0], t: [0, 0] }] as Step[]
|
|
);
|
|
|
|
const widthRange = visitedSteps.reduce(
|
|
({ min, max }, { h, t }) => {
|
|
const stepMin = h[0] < t[0] ? h[0] : t[0];
|
|
const stepMax = h[0] > t[0] ? h[0] : t[0];
|
|
return {
|
|
min: min < stepMin ? min : stepMin,
|
|
max: max > stepMax ? max : stepMax,
|
|
};
|
|
},
|
|
{ min: 0, max: 0 }
|
|
);
|
|
const width = widthRange.max - widthRange.min + 1;
|
|
|
|
const heightRange = visitedSteps.reduce(
|
|
({ min, max }, { h, t }) => {
|
|
const stepMin = h[1] < t[1] ? h[1] : t[1];
|
|
const stepMax = h[1] > t[1] ? h[1] : t[1];
|
|
return {
|
|
min: min < stepMin ? min : stepMin,
|
|
max: max > stepMax ? max : stepMax,
|
|
};
|
|
},
|
|
{ min: 0, max: 0 }
|
|
);
|
|
const height = heightRange.max - heightRange.min + 1;
|
|
|
|
const normalizedVisistedSteps = visitedSteps.map(({ h, t }) => {
|
|
const yT = Math.round(
|
|
mapRange(t[1], heightRange.min, heightRange.max, 0, height - 1)
|
|
);
|
|
const xT = Math.round(
|
|
mapRange(t[0], widthRange.min, widthRange.max, 0, width - 1)
|
|
);
|
|
const yH = Math.round(
|
|
mapRange(h[1], heightRange.min, heightRange.max, 0, height - 1)
|
|
);
|
|
const xH = Math.round(
|
|
mapRange(h[0], widthRange.min, widthRange.max, 0, width - 1)
|
|
);
|
|
return { h: [yH, xH], t: [yT, xT] } as Step;
|
|
});
|
|
|
|
print(width, height, normalizedVisistedSteps);
|
|
|
|
return new Set(normalizedVisistedSteps.map(({ t }) => `${t[0]},${t[1]}`))
|
|
.size;
|
|
};
|
|
|
|
console.log("Sample:", solvePart1(sample)); // 13
|
|
console.log("Input", solvePart1(input)); // 1851
|