Skip to content

Commit

Permalink
Add solution to 2022/12/22 part 1
Browse files Browse the repository at this point in the history
  • Loading branch information
alexg-axis committed Dec 22, 2022
1 parent f3936e0 commit a96a461
Show file tree
Hide file tree
Showing 3 changed files with 181 additions and 109 deletions.
200 changes: 110 additions & 90 deletions 2022/22/solutions.ts
Original file line number Diff line number Diff line change
@@ -1,128 +1,152 @@
import { max } from "../../utils/deno/arrays.ts";
import { Input } from "../../utils/deno/input.ts";
import { mod } from "../../utils/deno/math.ts";

type Direction = "up" | "down" | "left" | "right";
type Direction = 0 | 1 | 2 | 3;

type Rotation = "R" | "L";
type Rotation = -1 | 1;

type Instruction = number | Rotation;
type Instruction =
| { type: "turn"; value: Rotation }
| { type: "move"; value: number };

type Tile = " " | "." | "#";

function rotate(current: Direction, rotation: Rotation): Direction {
switch (current) {
case "up":
return rotation === "R" ? "right" : "left";
case "down":
return rotation === "R" ? "left" : "right";
case "left":
return rotation === "R" ? "up" : "down";
case "right":
return rotation === "R" ? "down" : "up";
}
interface Position {
x: number;
y: number;
direction: Direction;
}

export function rotate(current: Direction, rotation: Rotation): Direction {
return mod(current + rotation, 4) as Direction;
}

function delta(direction: Direction): { x: number; y: number } {
switch (direction) {
case "up":
return { x: 0, y: -1 };
case "down":
return { x: 0, y: +1 };
case "left":
return { x: -1, y: 0 };
case "right":
return { x: +1, y: 0 };
}
return [
{ x: 1, y: 0 }, // Right
{ x: 0, y: 1 }, // Down
{ x: -1, y: 0 }, // Left
{ x: 0, y: -1 }, // Up
][direction];
}

export function parseInput(input: Input): [Tile[][], Instruction[]] {
const [rawMap, rawPath] = input.raw.trimEnd().split("\n\n");
const maxWidth = rawMap
.trimEnd()
.split("\n")
.map((x) => x.length)
.reduce(max);
const map: Tile[][] = rawMap
.trimEnd()
.split("\n")
.map((x) => x.split("") as Tile[]);
.map((x) => {
const y = x.split("");
return new Array(maxWidth).fill(0).map((_, i) => y[i] || " ") as Tile[];
});
const instructions: Instruction[] = rawPath
.trim()
.replace(/(R|L)/g, ",$1,")
.replace(/^,|,$/g, "")
.split(",")
.map((x) => (x === "R" || x === "L" ? x : Number(x))) as Instruction[];
.map((x) => {
if (x === "R" || x === "L") {
return { type: "turn", value: x === "R" ? 1 : -1 };
} else {
return { type: "move", value: Number(x) };
}
}) as Instruction[];

return [map, instructions];
}

function slice(map: Tile[][], position: Position): string {
const height = map.length;
const width = map.map((x) => x.length).reduce(max);

if (position.direction === 0 || position.direction === 2) {
return new Array(width)
.fill(0)
.map((_, i) => map[position.y][i] || "")
.join("");
} else {
return new Array(height)
.fill(0)
.map((_, i) => map[i][position.x] || "")
.join("");
}
}

export function solve(
map: Tile[][],
instructions: Instruction[]
): { x: number; y: number; direction: Direction } {
instructions: Instruction[],
start?: Position
): Position {
const height = map.length;
const width = map.map((x) => x.length).reduce(max);

if (!start) {
start = {
x: map[0].findIndex((x) => x === "."),
y: 0,
direction: 0,
};
}

const visited = [...map.map((x) => [...x])];

const current = {
x: map[0].findIndex((x) => x === "."),
y: 0,
direction: "right" as Direction,
const current: Position = {
x: start.x,
y: start.y,
direction: start.direction,
};
// console.log(current.x + 1, current.y + 1, current.direction);
visited[current.y][current.x] = current.direction
.replace("left", "<")
.replace("right", ">")
.replace("up", "^")
.replace("down", "v") as Tile;

for (const instruction of instructions) {
if (typeof instruction === "string") {
const rotation = instruction;
const previous = { ...current };
if (instruction.type === "turn") {
const rotation = instruction.value;
current.direction = rotate(current.direction, rotation);
// console.log(current.x + 1, current.y + 1, current.direction);
visited[current.y][current.x] = current.direction
.replace("left", "<")
.replace("right", ">")
.replace("up", "^")
.replace("down", "v") as Tile;
continue;
}

const steps = instruction;

const { x: dx, y: dy } = delta(current.direction);

// Try to move along the direction and wrap as needed, finding out if the
// destination is valid
let nextX = current.x;
let nextY = current.y;
for (let i = 0, j = 1; i < steps; i++, j++) {
const potentialNextY = mod(current.y + dy * j, height);
const width = map[potentialNextY].length;
const potentialNextX = mod(current.x + dx * j, width);
const tile = map[potentialNextY][potentialNextX];
if (tile === "#") {
break;
} else if (tile === ".") {
nextX = potentialNextX;
nextY = potentialNextY;
visited[nextY][nextX] = current.direction
.replace("left", "<")
.replace("right", ">")
.replace("up", "^")
.replace("down", "v") as Tile;
} else if (tile === " ") {
// Don't consume a step whilst wrapping
i--;
} else {
const steps = instruction.value;

const { x: dx, y: dy } = delta(current.direction);

// Try to move along the direction and wrap as needed, finding out if the
// destination is valid
let nextX = current.x;
let nextY = current.y;
for (let i = 0, j = 1; i < steps; i++, j++) {
const potentialNextY = mod(current.y + dy * j, height);
const potentialNextX = mod(current.x + dx * j, width);
const tile = map[potentialNextY][potentialNextX];
if (tile === "#") {
break;
} else if (tile === ".") {
nextX = potentialNextX;
nextY = potentialNextY;
} else {
// Don't consume a step whilst wrapping
i--;
}
}

current.x = nextX;
current.y = nextY;
}

// If the steps led us to a valid location along the path, move
current.x = nextX;
current.y = nextY;
// console.log(
// instruction.type === "turn"
// ? ["l", "", "r"][instruction.value + 1]
// : instruction.value
// );
// console.log(current.x, current.y, current.direction);
const annotated = [...map.map((x) => [...x])];
annotated[previous.y][previous.x] = "F" as Tile;
annotated[current.y][current.x] = "T" as Tile;
// console.log("|" + slice(annotated, current) + "|");
// console.log();
}

// console.log(visited.map((x) => x.join("")).join("\n"));
// console.log(
// current.x + 1,
// current.y + 1,
// ["right", "down", "left", "up"].indexOf(current.direction)
// );
return current;
}

Expand All @@ -131,9 +155,5 @@ export function solvePart1(input: Input): number {

const solved = solve(map, instructions);

return (
1000 * (solved.y + 1) +
4 * (solved.x + 1) +
["right", "down", "left", "up"].indexOf(solved.direction)
);
return 1000 * (solved.y + 1) + 4 * (solved.x + 1) + solved.direction;
}
Loading

0 comments on commit a96a461

Please sign in to comment.