Merge branch '2022-04'
This commit is contained in:
commit
0a55d68dfd
11
2022/01/main.js
Normal file
11
2022/01/main.js
Normal 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);
|
||||||
|
}
|
@ -1,16 +1,14 @@
|
|||||||
import * as R from "remeda";
|
import * as R from "remeda";
|
||||||
import { test, expect } from "vitest";
|
import { test, expect } from "vitest";
|
||||||
import fs from "fs-extra";
|
import fs from "fs-extra";
|
||||||
|
import path from 'path';
|
||||||
|
import { expectSolution } from './main.js';
|
||||||
|
|
||||||
const split = (splitter) => (text) => text.split(splitter);
|
const split = (splitter) => (text) => text.split(splitter);
|
||||||
const sum = R.sumBy(R.identity);
|
const sum = R.sumBy(R.identity);
|
||||||
const spy = (x) => {
|
|
||||||
console.debug(x);
|
|
||||||
return x;
|
|
||||||
};
|
|
||||||
|
|
||||||
const input = R.pipe(
|
const input = R.pipe(
|
||||||
fs.readFileSync("input", "utf8"),
|
fs.readFileSync( path.join( path.dirname(import.meta.url), "input").replace('file:',''), "utf8"),
|
||||||
split("\n\n"),
|
split("\n\n"),
|
||||||
R.map((x) =>
|
R.map((x) =>
|
||||||
split("\n")(x)
|
split("\n")(x)
|
||||||
@ -20,10 +18,6 @@ const input = R.pipe(
|
|||||||
R.map(sum)
|
R.map(sum)
|
||||||
);
|
);
|
||||||
|
|
||||||
function expectSolution(result) {
|
|
||||||
console.info(result);
|
|
||||||
return expect(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
test("part 1", () => {
|
test("part 1", () => {
|
||||||
const maxCalories = R.pipe(input, (calories) => Math.max(...calories));
|
const maxCalories = R.pipe(input, (calories) => Math.max(...calories));
|
||||||
|
60
2022/02/part1.js
Normal file
60
2022/02/part1.js
Normal 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
25
2022/02/part2.js
Normal 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
41
2022/02/test.js
Normal 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
20
2022/03/part1.js
Normal 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
12
2022/03/part2.js
Normal 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
6
2022/03/sample
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
vJrwpWtwJgWrhcsFMMfFFhFp
|
||||||
|
jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL
|
||||||
|
PmmdzqPrVvPwwTWBwg
|
||||||
|
wMqvLMZHhHMvwLHjbvcjnnSBnvTQFn
|
||||||
|
ttgJtRGJQctTZtZT
|
||||||
|
CrZsJsPPZsGzwwsLwLmpwMDw
|
25
2022/03/test.js
Normal file
25
2022/03/test.js
Normal 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
20
2022/04/part1.js
Normal 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
13
2022/04/part2.js
Normal 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
6
2022/04/sample
Normal 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
23
2022/04/test.js
Normal 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
1
2022/template/part1.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
import * as R from "remeda";
|
2
2022/template/part2.js
Normal file
2
2022/template/part2.js
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
import * as R from "remeda";
|
||||||
|
|
20
2022/template/test.js
Normal file
20
2022/template/test.js
Normal 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');
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in New Issue
Block a user