main
Yanick Champoux 2022-12-14 10:40:00 -05:00
parent 88dfa7677a
commit 0045c63046
5 changed files with 176 additions and 0 deletions

85
2022/14/part1.js Normal file
View File

@ -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,
)

52
2022/14/part2.js Normal file
View File

@ -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,
)

2
2022/14/sample Normal file
View File

@ -0,0 +1,2 @@
498,4 -> 498,6 -> 496,6
503,4 -> 502,4 -> 502,9 -> 494,9

34
2022/14/test.js Normal file
View File

@ -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);
});
});

View File

@ -19,5 +19,8 @@
"remeda": "^1.3.0",
"vite": "^4.0.1",
"vitest": "0.25.7"
},
"devDependencies": {
"@vitest/ui": "^0.25.8"
}
}