diff --git a/.prettierignore b/.prettierignore index bbb2427..1a8aed7 100644 --- a/.prettierignore +++ b/.prettierignore @@ -5,3 +5,4 @@ sample input *.t *.pm +*.ejs diff --git a/2022/08/part1.js b/2022/08/part1.js new file mode 100644 index 0000000..34dd036 --- /dev/null +++ b/2022/08/part1.js @@ -0,0 +1,89 @@ +import * as R from "remeda"; +import { readFile } from "../05/part1.js"; +import Victor from "@a-robu/victor"; + +const V = (...args) => new Victor(...args); + +const readInput = (...args) => + readFile(...args) + .split("\n") + .filter((x) => x) + .map((l) => l.split("").map((x) => parseInt(x))); + +export const outOfBound = (size) => (pos) => { + if (Math.min(pos.x, pos.y) < 0) return true; + if (Math.max(pos.x, pos.y) >= size) return true; + return false; +}; + +export function generateVisibilityGrid(forest) { + const size = forest.length; + const visibility = Array(size) + .fill(null) + .map(() => Array(size).fill(false)); + + // top + const positions = R.range(size)(0).map((x) => ({ + height: -1, + position: V(x, -1), + inc: V(0, 1), + })); + + // bottom + positions.push( + ...R.range(size)(0).map((x) => ({ + height: -1, + position: V(x, size), + inc: V(0, -1), + })) + ); + + positions.push( + ...R.range(size)(0).map((x) => ({ + height: -1, + position: V(-1, x), + inc: V(1, 0), + })) + ); + positions.push( + ...R.range(size)(0).map((x) => ({ + height: -1, + position: V(size, x), + inc: V(-1, 0), + })) + ); + + while (positions.length) { + const pos = positions.shift(); + pos.position.add(pos.inc); + + if (outOfBound(size)(pos.position)) continue; + + if (forest[pos.position.x][pos.position.y] > pos.height) { + visibility[pos.position.x][pos.position.y] = true; + pos.height = forest[pos.position.x][pos.position.y]; + } + + positions.push(pos); + } + + return visibility; +} + +export const puzzleInput = readInput(import.meta.url, "input"); +export const sample = readInput(import.meta.url, "sample"); + +export const passthru = (func) => (arg) => { + func(arg); + return arg; +}; + +export const printMap = passthru((forest) => + forest.forEach((line) => console.log(line.join(" "))) +); + +export default R.createPipe( + generateVisibilityGrid, + R.flatten, + R.countBy(R.identity) +); diff --git a/2022/08/part2.js b/2022/08/part2.js new file mode 100644 index 0000000..061879c --- /dev/null +++ b/2022/08/part2.js @@ -0,0 +1,40 @@ +import * as R from "remeda"; +import Victor from "@a-robu/victor"; + +import { outOfBound } from "./part1"; + +const V = (...args) => new Victor(...args); + +function visibility(forest, x, y, dx, dy) { + const pos = V(x, y); + const inc = V(dx, dy); + + let vis = 0; + + while (true) { + pos.add(inc); + if (outOfBound(forest.length)(pos)) return vis; + + if (forest[x][y] <= forest[pos.x][pos.y]) return 1 + vis; + vis++; + } +} + +const visibilityAround = (forest) => (x, y) => + [ + [0, 1], + [0, -1], + [1, 0], + [-1, 0], + ] + .map((d) => visibility(forest, x, y, ...d)) + .reduce((a, b) => a * b); + +export default R.createPipe( + (forest) => { + const va = visibilityAround(forest); + return forest.map((l, x) => l.map((_, y) => va(x, y))); + }, + R.flatten, + R.maxBy(R.identity) +); diff --git a/2022/08/sample b/2022/08/sample new file mode 100644 index 0000000..16d6fbd --- /dev/null +++ b/2022/08/sample @@ -0,0 +1,5 @@ +30373 +25512 +65332 +33549 +35390 diff --git a/2022/08/test.js b/2022/08/test.js new file mode 100644 index 0000000..37e84b4 --- /dev/null +++ b/2022/08/test.js @@ -0,0 +1,25 @@ +import { test, expect, describe } from "vitest"; + +import { expectSolution } from "../01/main.js"; +import part1, { sample, puzzleInput } from "./part1.js"; +import part2 from "./part2.js"; + +describe("part 1", () => { + test("sample", () => { + expect(part1(sample)).toBe(21); + }); + test("solution", () => { + expectSolution(part1(puzzleInput)).toEqual(1703); + }); +}); + +describe("part 2", () => { + test("sample", () => { + expect(part2(sample)).toBe(8); + }); + test("solution", () => { + const solution = part2(puzzleInput); + expect(solution).toBeGreaterThan(160); + expectSolution(solution).toEqual(496650); + }); +}); diff --git a/2022/template/part1.js b/2022/template/part1.js deleted file mode 100644 index b509eb0..0000000 --- a/2022/template/part1.js +++ /dev/null @@ -1 +0,0 @@ -import * as R from "remeda"; diff --git a/2022/template/part2.js b/2022/template/part2.js deleted file mode 100644 index b509eb0..0000000 --- a/2022/template/part2.js +++ /dev/null @@ -1 +0,0 @@ -import * as R from "remeda"; diff --git a/Taskfile.yaml b/Taskfile.yaml index af75c42..eaa296d 100644 --- a/Taskfile.yaml +++ b/Taskfile.yaml @@ -6,6 +6,8 @@ vars: YEAR: 2022 DAY: sh: date '+%d' | perl -pe's/^0//' + DAY_FORMATTED: + sh: date '+%d' GREETING: Hello, World! tasks: @@ -25,6 +27,10 @@ tasks: cmds: - firefox https://adventofcode.com/{{.YEAR}}/day/{{.DAY}} + download: + cmds: + - aoc download -d {{.DAY}} -o -p 2022/{{.DAY_FORMATTED}}/puzzle.md -i 2022/{{.DAY_FORMATTED}}/input + default: cmds: - echo "{{.GREETING}}" diff --git a/_templates/day/new/hello.ejs.t b/_templates/day/new/hello.ejs.t new file mode 100644 index 0000000..095a04e --- /dev/null +++ b/_templates/day/new/hello.ejs.t @@ -0,0 +1,15 @@ +--- +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 new file mode 100644 index 0000000..14531b0 --- /dev/null +++ b/_templates/day/new/part1.ejs @@ -0,0 +1,16 @@ +--- +to: 2022/<%= day %>/part1.js +--- +import * as R from "remeda"; + +import { readFile } from "../05/part1.js"; + +const readInput = (...args) => + readFile(...args) + .split("\n") + .filter((x) => x); + +export const puzzleInput = readInput(import.meta.url, "input"); +export const sample = readInput(import.meta.url, "sample"); + +export default = () => {}; diff --git a/_templates/day/new/part2.ejs b/_templates/day/new/part2.ejs new file mode 100644 index 0000000..e59c761 --- /dev/null +++ b/_templates/day/new/part2.ejs @@ -0,0 +1,7 @@ +--- +to: 2022/<%= day %>/part2.js +--- +import * as R from "remeda"; + + +export default = () => {}; diff --git a/_templates/day/new/prompt.js b/_templates/day/new/prompt.js new file mode 100644 index 0000000..bfff832 --- /dev/null +++ b/_templates/day/new/prompt.js @@ -0,0 +1,7 @@ +module.exports = [ + { + type: 'input', + name: 'day', + message: "advent day?" + } +] diff --git a/2022/template/test.js b/_templates/day/new/test.ejs similarity index 50% rename from 2022/template/test.js rename to _templates/day/new/test.ejs index 07ae1e1..f82ac18 100644 --- a/2022/template/test.js +++ b/_templates/day/new/test.ejs @@ -1,17 +1,20 @@ +--- +to: 2022/<%= day %>/test.js +--- import { test, expect, describe } from "vitest"; import { expectSolution } from "../01/main.js"; -import { solutionPart1, puzzleInput } from "./part1.js"; -import { solutionPart2 } from "./part2.js"; +import part1, { sample, puzzleInput } from "./part1.js"; +import part2 from "./part2.js"; describe("part 1", () => { test.todo("solution", () => { - expectSolution(solutionPart1(puzzleInput)).toEqual("TODO"); + expectSolution(part1(puzzleInput)).toEqual("TODO"); }); }); describe("part 2", () => { test.todo("solution", () => { - expectSolution(solutionPart2(puzzleInput)).toEqual("TODO"); + expectSolution(part2(puzzleInput)).toEqual("TODO"); }); }); diff --git a/_templates/generator/help/index.ejs.t b/_templates/generator/help/index.ejs.t new file mode 100644 index 0000000..90a29af --- /dev/null +++ b/_templates/generator/help/index.ejs.t @@ -0,0 +1,5 @@ +--- +message: | + hygen {bold generator new} --name [NAME] --action [ACTION] + hygen {bold generator with-prompt} --name [NAME] --action [ACTION] +--- \ No newline at end of file diff --git a/_templates/generator/new/hello.ejs.t b/_templates/generator/new/hello.ejs.t new file mode 100644 index 0000000..5680d96 --- /dev/null +++ b/_templates/generator/new/hello.ejs.t @@ -0,0 +1,18 @@ +--- +to: _templates/<%= name %>/<%= action || 'new' %>/hello.ejs.t +--- +--- +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/generator/with-prompt/hello.ejs.t b/_templates/generator/with-prompt/hello.ejs.t new file mode 100644 index 0000000..ba6abc5 --- /dev/null +++ b/_templates/generator/with-prompt/hello.ejs.t @@ -0,0 +1,18 @@ +--- +to: _templates/<%= name %>/<%= action || 'new' %>/hello.ejs.t +--- +--- +to: app/hello.js +--- +const hello = ``` +Hello! +This is your first prompt based hygen template. + +Learn what it can do here: + +https://github.com/jondot/hygen +``` + +console.log(hello) + + diff --git a/_templates/generator/with-prompt/prompt.ejs.t b/_templates/generator/with-prompt/prompt.ejs.t new file mode 100644 index 0000000..76ea532 --- /dev/null +++ b/_templates/generator/with-prompt/prompt.ejs.t @@ -0,0 +1,14 @@ +--- +to: _templates/<%= name %>/<%= action || 'new' %>/prompt.js +--- + +// see types of prompts: +// https://github.com/enquirer/enquirer/tree/master/examples +// +module.exports = [ + { + type: 'input', + name: 'message', + message: "What's your message?" + } +] diff --git a/_templates/init/repo/new-repo.ejs.t b/_templates/init/repo/new-repo.ejs.t new file mode 100644 index 0000000..08e7cff --- /dev/null +++ b/_templates/init/repo/new-repo.ejs.t @@ -0,0 +1,4 @@ +--- +setup: <%= name %> +force: true # this is because mostly, people init into existing folders is safe +--- diff --git a/package.json b/package.json index c1baac4..232dcb9 100644 --- a/package.json +++ b/package.json @@ -10,8 +10,10 @@ "author": "Yanick Champoux (http://techblog.babyl.ca/)", "license": "ISC", "dependencies": { + "@a-robu/victor": "^2.2.2", "debug": "^4.3.4", "fs-extra": "^11.1.0", + "memoizerific": "^1.11.3", "prettier": "^2.8.0", "remeda": "^1.3.0", "vitest": "^0.25.3"