diff --git a/.prettierignore b/.prettierignore index 1a8aed7..69eb8c3 100644 --- a/.prettierignore +++ b/.prettierignore @@ -6,3 +6,4 @@ input *.t *.pm *.ejs +bigSample diff --git a/2022/09/bigSample b/2022/09/bigSample new file mode 100644 index 0000000..60bd43b --- /dev/null +++ b/2022/09/bigSample @@ -0,0 +1,8 @@ +R 5 +U 8 +L 8 +D 3 +R 17 +D 10 +L 25 +U 20 diff --git a/2022/09/part1.js b/2022/09/part1.js new file mode 100644 index 0000000..fcad02d --- /dev/null +++ b/2022/09/part1.js @@ -0,0 +1,59 @@ +import * as R from "remeda"; +import Victor from "@a-robu/victor"; + +import { readFile } from "../05/part1.js"; +import { passthru } from "../08/part1.js"; + +const directions = { + R: new Victor(1, 0), + L: new Victor(-1, 0), + U: new Victor(0, 1), + D: new Victor(0, -1), +}; + +const parseLine = R.createPipe( + (line) => line.split(" "), + ([direction, times]) => Array(parseInt(times)).fill(directions[direction]) +); + +export const readInput = (...args) => + R.pipe( + readFile(...args), + (text) => text.split("\n"), + R.compact, + R.map(parseLine), + R.flatten + ); + +export const puzzleInput = readInput(import.meta.url, "input"); +export const sample = readInput(import.meta.url, "sample"); + +export const touching = (v1, v2) => + [v1.distanceX(v2), v1.distanceY(v2)].every((x) => x * x <= 1); + +export const moveOnce = (head, tail) => (d) => { + head.add(d); + + if (touching(head, tail)) return tail.toString(); + + const delta = head.clone().subtract(tail).normalize(); + + if (delta.x * delta.y) { + delta.x = delta.x > 0 ? 1 : -1; + delta.y = delta.y > 0 ? 1 : -1; + } + + tail.add(delta); + + return tail.toString(); +}; + +const moveAround = (directives) => { + const head = new Victor(0, 0); + const tail = new Victor(0, 0); + + const move = moveOnce(head, tail); + return directives.map(move); +}; + +export default R.createPipe(moveAround, R.uniq, (moves) => moves.length); diff --git a/2022/09/part2.js b/2022/09/part2.js new file mode 100644 index 0000000..5221a09 --- /dev/null +++ b/2022/09/part2.js @@ -0,0 +1,36 @@ +import * as R from "remeda"; +import Victor from "@a-robu/victor"; + +import { touching, readInput } from "./part1.js"; + +export const bigSample = readInput(import.meta.url, "bigSample"); + +export const moveOnce = (knots) => (d) => { + R.first(knots).add(d); + + for (const i of R.range(1, knots.length)) { + if (touching(knots[i - 1], knots[i])) break; + + const delta = knots[i - 1].clone().subtract(knots[i]).normalize(); + + if (delta.x * delta.y) { + delta.x = delta.x > 0 ? 1 : -1; + delta.y = delta.y > 0 ? 1 : -1; + } + + knots[i].add(delta); + } + + return R.last(knots).toString(); +}; + +const moveAround = (directives) => { + const knots = Array(10) + .fill(null) + .map(() => new Victor(0, 0)); + + const move = moveOnce(knots); + return directives.map(move); +}; + +export default R.createPipe(moveAround, R.uniq, (moves) => moves.length); diff --git a/2022/09/sample b/2022/09/sample new file mode 100644 index 0000000..9874df2 --- /dev/null +++ b/2022/09/sample @@ -0,0 +1,8 @@ +R 4 +U 4 +L 3 +D 1 +R 4 +D 1 +L 5 +R 2 diff --git a/2022/09/test.js b/2022/09/test.js new file mode 100644 index 0000000..6692da7 --- /dev/null +++ b/2022/09/test.js @@ -0,0 +1,44 @@ +import { test, expect, describe } from "vitest"; +import Victor from "@a-robu/victor"; + +const V = (...args) => new Victor(...args); + +import { expectSolution } from "../01/main.js"; +import part1, { moveOnce, sample, puzzleInput } from "./part1.js"; +import part2, { bigSample } from "./part2.js"; + +describe("part 1", () => { + test("moveOnce", () => { + let head = V(1, 0); + let tail = V(0, 0); + moveOnce(head, tail)(V(1, 0)); + + expect(tail).toMatchObject({ x: 1, y: 0 }); + + moveOnce(head, tail)(V(0, 1)); + + expect(tail).toMatchObject({ x: 1, y: 0 }); + + moveOnce(head, tail)(V(0, 1)); + + expect(tail).toMatchObject({ x: 2, y: 1 }); + }); + + test("sample", () => { + expect(part1(sample)).toEqual(13); + }); + test("solution", () => { + expectSolution(part1(puzzleInput)).toEqual(6030); + }); +}); + +describe("part 2", () => { + test("sample", () => { + expect(part2(sample)).toEqual(1); + expect(part2(bigSample)).toEqual(36); + }); + + test("solution", () => { + expectSolution(part2(puzzleInput)).toEqual(2545); + }); +}); diff --git a/_templates/day/new/hello.ejs.t b/_templates/day/new/hello.ejs.t deleted file mode 100644 index 099ef04..0000000 --- a/_templates/day/new/hello.ejs.t +++ /dev/null @@ -1,13 +0,0 @@ ---- -to: app/hello.js ---- -const hello = ``` -Hello! -This is your first hygen template. - -Learn what it can do here: - -https://github.com/jondot/hygen -``` - -console.log(hello) diff --git a/_templates/day/new/part1.ejs b/_templates/day/new/part1.ejs index 14531b0..33430d6 100644 --- a/_templates/day/new/part1.ejs +++ b/_templates/day/new/part1.ejs @@ -13,4 +13,4 @@ const readInput = (...args) => export const puzzleInput = readInput(import.meta.url, "input"); export const sample = readInput(import.meta.url, "sample"); -export default = () => {}; +export default () => {}; diff --git a/_templates/day/new/part2.ejs b/_templates/day/new/part2.ejs index e59c761..ec6f9e3 100644 --- a/_templates/day/new/part2.ejs +++ b/_templates/day/new/part2.ejs @@ -4,4 +4,4 @@ to: 2022/<%= day %>/part2.js import * as R from "remeda"; -export default = () => {}; +export default () => {};