From 0045c630469da5ff9091a9f7559811cd943b3f3f Mon Sep 17 00:00:00 2001 From: Yanick Champoux Date: Wed, 14 Dec 2022 10:40:00 -0500 Subject: [PATCH] day 14 --- 2022/14/part1.js | 85 ++++++++++++++++++++++++++++++++++++++++++++++++ 2022/14/part2.js | 52 +++++++++++++++++++++++++++++ 2022/14/sample | 2 ++ 2022/14/test.js | 34 +++++++++++++++++++ package.json | 3 ++ 5 files changed, 176 insertions(+) create mode 100644 2022/14/part1.js create mode 100644 2022/14/part2.js create mode 100644 2022/14/sample create mode 100644 2022/14/test.js diff --git a/2022/14/part1.js b/2022/14/part1.js new file mode 100644 index 0000000..8a2cb7e --- /dev/null +++ b/2022/14/part1.js @@ -0,0 +1,85 @@ +import * as R from "remeda"; +import Victor from '@a-robu/victor'; + +import { readFile } from "../05/part1.js"; + +export const V = (...args) => new Victor(...args); +const parseLine = line => line.match(/[\d,]+/g).map( x => eval(`[${x}]`) ); + +const readInput = (...args) => + R.pipe( + readFile(...args), + (lines) => lines.split("\n"), + R.compact, // remove last line + R.map( parseLine ) + ); + +export const puzzleInput = readInput(import.meta.url, "input"); +export const sample = readInput(import.meta.url, "sample"); + + +export function genCave(rocks) { + const cave = {}; + for( const rock of rocks ) { + const points = rock.map( Victor.fromArray ); + let from = points.shift(); + + while( points.length ) { + /** @type Victor */ + const to = points.shift(); + const direction = to.clone().subtract(from).normalize(); + + R.times(to.clone().subtract(from).length()+1, () => { + if(!cave[from.y]) cave[from.y] = {}; + cave[from.y][from.x] = '#'; + from.add(direction); + }); + + from = to; + } + } + return cave; + +} + +function pourSand(cave){ + cave = R.clone(cave); + + let sand = 0; + + /** @type Victor */ + let current; + + const maxDepth = R.pipe( + cave, + R.keys, + R.map( x => parseInt(x) ), + R.maxBy( R.identity ), + ); + + console.log({ maxDepth }); + + while(true) { + if(!current) current = V(500,0); + if( current.y > maxDepth ) return sand; + + const next = [ [0,1],[-1,1],[1,1] ].map( args => V(...args) ).map( + v => v.add(current) + ).find( v => ! (cave[v.y] && cave[v.y][v.x]) ); + if( next ) { + current = next; + } + else { + if( ! cave[current.y] ) cave[current.y] = {}; + cave[current.y][current.x] = 'o'; + sand++; + current = null; + } + } + +}; + +export default R.createPipe( + genCave, + pourSand, +) diff --git a/2022/14/part2.js b/2022/14/part2.js new file mode 100644 index 0000000..18d3beb --- /dev/null +++ b/2022/14/part2.js @@ -0,0 +1,52 @@ +import * as R from "remeda"; +import { genCave, V } from './part1.js'; + +function pourSand(cave){ + cave = R.clone(cave); + + let sand = 0; + + /** @type Victor */ + let current; + + const maxDepth = R.pipe( + cave, + R.keys, + R.map( x => parseInt(x) ), + R.maxBy( R.identity ), + ) + 1; + + while(true) { + if(!current) current = V(500,0); + + if( current.y === maxDepth ) { + if( ! cave[current.y] ) cave[current.y] = {}; + cave[current.y][current.x] = 'o'; + sand++; + current = null; + continue; + } + + const next = [ [0,1],[-1,1],[1,1] ].map( args => V(...args) ).map( + v => v.add(current) + ).find( v => ! (cave[v.y] && cave[v.y][v.x]) ); + + if( next ) { + current = next; + } + else { + if( current.y === 0 ) return 1+sand; + + if( ! cave[current.y] ) cave[current.y] = {}; + cave[current.y][current.x] = 'o'; + sand++; + current = null; + } + } + +}; + +export default R.createPipe( + genCave, + pourSand, +) diff --git a/2022/14/sample b/2022/14/sample new file mode 100644 index 0000000..4e87bb5 --- /dev/null +++ b/2022/14/sample @@ -0,0 +1,2 @@ +498,4 -> 498,6 -> 496,6 +503,4 -> 502,4 -> 502,9 -> 494,9 diff --git a/2022/14/test.js b/2022/14/test.js new file mode 100644 index 0000000..e650603 --- /dev/null +++ b/2022/14/test.js @@ -0,0 +1,34 @@ +import { test, expect, describe } from "vitest"; + +import { expectSolution } from "../01/main.js"; +import part1, { genCave, sample, puzzleInput } from "./part1.js"; +import part2 from "./part2.js"; + +describe("part 1", () => { + test("readInput", () => { + expect(sample).toEqual([ + [[498,4], [498,6], [496,6]], + [[503,4 ], [ 502,4 ], [ 502,9 ], [ 494,9]], + ]) + }); + test( 'genCave', () => { + expect( genCave(sample) ).toMatchObject({ + 4: { 498: '#' } + }); + } ) + test("sample", () => { + expect(part1(sample)).toEqual(24); + }); + test("solution", () => { + expectSolution(part1(puzzleInput)).toEqual(832); + }); +}); + +describe.only("part 2", () => { + test("sample", () => { + expect(part2(sample)).toEqual(93); + }); + test("solution", () => { + expectSolution(part2(puzzleInput)).toEqual(27601); + }); +}); diff --git a/package.json b/package.json index 368555b..86b09f3 100644 --- a/package.json +++ b/package.json @@ -19,5 +19,8 @@ "remeda": "^1.3.0", "vite": "^4.0.1", "vitest": "0.25.7" + }, + "devDependencies": { + "@vitest/ui": "^0.25.8" } }