Merge branch '2022-04'

main
Yanick Champoux 2022-12-04 12:44:20 -05:00
commit 0a55d68dfd
16 changed files with 288 additions and 9 deletions

11
2022/01/main.js Normal file
View File

@ -0,0 +1,11 @@
import { expect } from "vitest";
export const spy = (x) => {
console.debug(x);
return x;
};
export function expectSolution(result) {
console.info(result);
return expect(result);
}

View File

@ -1,16 +1,14 @@
import * as R from "remeda";
import { test, expect } from "vitest";
import fs from "fs-extra";
import path from 'path';
import { expectSolution } from './main.js';
const split = (splitter) => (text) => text.split(splitter);
const sum = R.sumBy(R.identity);
const spy = (x) => {
console.debug(x);
return x;
};
const input = R.pipe(
fs.readFileSync("input", "utf8"),
fs.readFileSync( path.join( path.dirname(import.meta.url), "input").replace('file:',''), "utf8"),
split("\n\n"),
R.map((x) =>
split("\n")(x)
@ -20,10 +18,6 @@ const input = R.pipe(
R.map(sum)
);
function expectSolution(result) {
console.info(result);
return expect(result);
}
test("part 1", () => {
const maxCalories = R.pipe(input, (calories) => Math.max(...calories));

60
2022/02/part1.js Normal file
View File

@ -0,0 +1,60 @@
import * as R from "remeda";
import fs from "fs-extra";
import path from "path";
export const sampleInput = `A Y
B X
C Z`;
export const puzzleInput = fs.readFileSync(
path.join(path.dirname(import.meta.url), "input").replace("file:", ""),
"utf8"
);
const playMap = {
X: "A", // rock
Y: "B", // paper
Z: "C", // scissors
};
export const parseInput = R.createPipe(
(text) => text.split("\n"),
R.filter(R.identity), // remove last line
R.map((entry) => entry.split(" "))
);
export const movePositions = ["A", "B", "C"];
const playScore = {
A: 1,
B: 2,
C: 3,
};
const draw = 3;
const lost = 0;
const win = 6;
const outcome = (opponent, me) => {
if (opponent === me) return draw;
if (opponent === "A") {
return me === "C" ? lost : win;
}
if (opponent === "B") {
return me === "A" ? lost : win;
}
return me === "B" ? lost : win;
};
export const mapScores = ([opponent, me]) => [
outcome(opponent, me),
playScore[me],
];
export const solutionPart1 = R.createPipe(
parseInput,
R.map(([a, b]) => [a, playMap[b]]),
R.map(mapScores),
R.map(R.sumBy(R.identity)),
R.sumBy(R.identity)
);

25
2022/02/part2.js Normal file
View File

@ -0,0 +1,25 @@
import * as R from "remeda";
import { movePositions, mapScores, playMap, parseInput } from "./part1.js";
function calculateMove(opponent, verdict) {
const incr = {
Y: 0,
X: 2,
Z: 1,
};
const index =
(movePositions.findIndex((x) => x === opponent) + incr[verdict]) %
movePositions.length;
return movePositions[index];
}
export const solutionPart2 = R.createPipe(
parseInput,
R.map(([a, b]) => [a, calculateMove(a, b)]),
R.map(mapScores),
R.map(R.sumBy(R.identity)),
R.sumBy(R.identity)
);

41
2022/02/test.js Normal file
View File

@ -0,0 +1,41 @@
import { test, expect, describe } from "vitest";
import { expectSolution } from "../01/main.js";
import {
parseInput,
sampleInput,
puzzleInput,
mapScores,
solutionPart1,
} from "./part1.js";
import { solutionPart2 } from "./part2.js";
describe("part 1", () => {
test("input parsing", () => {
expect(parseInput(sampleInput)).toEqual([
["A", "Y"],
["B", "X"],
["C", "Z"],
]);
});
test("mapScore", () => {
expect(mapScores(["A", "B"])).toEqual([6, 2]);
expect(mapScores(["B", "A"])).toEqual([0, 1]);
expect(mapScores(["C", "C"])).toEqual([3, 3]);
});
test("part 1, sample", () => {
expect(solutionPart1(sampleInput)).toEqual(15);
});
test("solution", () => {
expectSolution(solutionPart1(puzzleInput)).toEqual(12458);
});
});
describe("part 2", () => {
test("part 2", () => {
expectSolution(solutionPart2(puzzleInput)).toEqual(12683);
});
});

20
2022/03/part1.js Normal file
View File

@ -0,0 +1,20 @@
import * as R from "remeda";
import fs from "fs-extra";
import path from "path";
export const readFile = (year, day, file) =>
fs.readFileSync(path.join(year, day, file), "utf8");
export const sample = readFile("2022", "03", "sample");
export const puzzleInput = readFile("2022", "03", "input");
export const solutionPart1 = R.createPipe(
(text) => text.split("\n"),
R.filter(R.identity),
R.map((line) => line.split("")),
R.map((line) => [line, line.splice(line.length / 2)]),
R.map((line) => R.intersection(...line)),
R.map((line) => line[0].charCodeAt(0)),
R.map((code) => (code > 96 ? code - 96 : code - 38)),
R.sumBy(R.identity)
);

12
2022/03/part2.js Normal file
View File

@ -0,0 +1,12 @@
import * as R from "remeda";
export const solutionPart2 = R.createPipe(
(text) => text.split("\n"),
R.filter(R.identity),
R.map((line) => line.split("")),
R.chunk(3),
R.map((group) => group.reduce((a, b) => R.intersection(a, b))),
R.map((line) => line[0].charCodeAt(0)),
R.map((code) => (code > 96 ? code - 96 : code - 38)),
R.sumBy(R.identity)
);

6
2022/03/sample Normal file
View File

@ -0,0 +1,6 @@
vJrwpWtwJgWrhcsFMMfFFhFp
jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL
PmmdzqPrVvPwwTWBwg
wMqvLMZHhHMvwLHjbvcjnnSBnvTQFn
ttgJtRGJQctTZtZT
CrZsJsPPZsGzwwsLwLmpwMDw

25
2022/03/test.js Normal file
View File

@ -0,0 +1,25 @@
import { test, expect, describe } from "vitest";
import { solutionPart1, sample, puzzleInput } from "./part1.js";
import { solutionPart2 } from "./part2.js";
function expectSolution(result) {
console.info(result);
return expect(result);
}
describe("part 1", () => {
test("sample", () => {
expect(solutionPart1(sample)).toEqual(157);
});
test("solution", () => {
expectSolution(solutionPart1(puzzleInput)).toEqual(8515);
});
});
describe("part 2", () => {
test("solution", () => {
expectSolution(solutionPart2(puzzleInput)).toEqual(2434);
});
});

20
2022/04/part1.js Normal file
View File

@ -0,0 +1,20 @@
import * as R from "remeda";
import { readFile } from "../03/part1.js";
export const sample = readFile("2022", "04", "sample");
export const puzzleInput = readFile("2022", "04", "input");
const rangeLength = ([a, b]) => b - a + 1;
const isContainedBy = ([a1, a2], [b1, b2]) => a1 >= b1 && a2 <= b2;
export const solutionPart1 = R.createPipe(
(text) => text.split("\n"),
R.filter(R.identity),
R.map((line) =>
line.split(",").map((range) => range.split("-").map((x) => parseInt(x)))
),
R.map(R.sortBy((x) => rangeLength(x))),
R.countBy(([a, b]) => isContainedBy(a, b))
);

13
2022/04/part2.js Normal file
View File

@ -0,0 +1,13 @@
import * as R from "remeda";
const overlapsWith = ([a1, a2], [b1, b2]) => a2 >= b1;
export const solutionPart2 = R.createPipe(
(text) => text.split("\n"),
R.filter(R.identity),
R.map((line) =>
line.split(",").map((range) => range.split("-").map((x) => parseInt(x)))
),
R.map(R.sortBy(([x]) => x)),
R.countBy(([a, b]) => overlapsWith(a, b))
);

6
2022/04/sample Normal file
View File

@ -0,0 +1,6 @@
2-4,6-8
2-3,4-5
5-7,7-9
2-8,3-7
6-6,4-6
2-6,4-8

23
2022/04/test.js Normal file
View File

@ -0,0 +1,23 @@
import { test, describe } from "vitest";
import { expectSolution } from "../01/main.js";
import { solutionPart1, puzzleInput, sample } from "./part1.js";
import { solutionPart2 } from "./part2.js";
describe("part 1", () => {
test("sample", () => {
expectSolution(solutionPart1(sample)).toEqual(2);
});
test("solution", () => {
expectSolution(solutionPart1(puzzleInput)).toEqual(605);
});
});
describe("part 2", () => {
test("sample", () => {
expectSolution(solutionPart2(sample)).toEqual(4);
});
test("solution", () => {
expectSolution(solutionPart2(puzzleInput)).toEqual(914);
});
});

1
2022/template/part1.js Normal file
View File

@ -0,0 +1 @@
import * as R from "remeda";

2
2022/template/part2.js Normal file
View File

@ -0,0 +1,2 @@
import * as R from "remeda";

20
2022/template/test.js Normal file
View File

@ -0,0 +1,20 @@
import { test, expect, describe } from "vitest";
import { expectSolution } from "../01/main.js";
import {
solutionPart1,
puzzleInput,
} from "./part1.js";
import { solutionPart2 } from "./part2.js";
describe("part 1", () => {
test.todo("solution", () => {
expectSolution(solutionPart1(puzzleInput)).toEqual('TODO');
});
});
describe("part 2", () => {
test.todo("solution", () => {
expectSolution(solutionPart2(puzzleInput)).toEqual('TODO');
});
});