Big update: Adding all advent of codes to same repo

This commit is contained in:
2024-12-06 00:14:09 +00:00
parent 5116bd4696
commit 233dda4fe9
106 changed files with 7790 additions and 0 deletions

View File

@@ -0,0 +1,18 @@
import { DayFunc } from "..";
export const Day1: DayFunc = (input) => {
const elfFood: number[][] = input
.split("\n\n")
.map((i) => i.split("\n"))
.map((i) => i.map((j) => parseInt(j)));
let highest = [0, 0, 0];
elfFood.forEach((n) => {
const h = n.reduce((prev, current) => (current += prev));
const index = highest.findIndex(v => v < h);
if (index !== -1) highest[index] = h;
highest.sort();
});
return [highest[0], highest.reduce((p, c) => c += p)];
};

View File

@@ -0,0 +1,42 @@
import { DayFunc } from "..";
export const Day10: DayFunc = (input) => {
const parsed = input.trim().split('\n').map(v => {
const s = v.split(' ');
if (s.length === 1) return [s[0]];
return [s[0], parseInt(s[1])];
});
let x = 1;
let cycles: number[] = [x];
parsed.forEach(i => {
if (i[0] === "noop") {
cycles.push(x);
} else {
cycles.push(x);
cycles.push(x);
x += i[1] as number;
}
});
const part1 = cycles[20] * 20 + cycles[60] * 60 + cycles[100] * 100 + cycles[140] * 140 + cycles[180] * 180 + cycles[220] * 220;
let outStr = "";
for (let i = 1; i < cycles.length; i++) {
if ((i - 1) % 40 === 0) {
outStr += '\n';
}
if (cycles[i] === (i - 1) % 40 || cycles[i] === (i - 2) % 40 || cycles[i] === i % 40) {
outStr += '#';
} else {
outStr += '.';
}
}
console.log(outStr);
return [part1, 0];
}

View File

@@ -0,0 +1,103 @@
import { DayFunc } from "..";
type MonkeyList = Record<
number,
{
inspected: number;
items: string[];
operation: string;
test: number;
ifTrue: number;
ifFalse: number;
}
>;
const Hcf = (a: number, b: number): number => {
let larger = a > b ? a : b;
let smaller = a > b ? b : a;
let r = -1;
while (true) {
if (larger % smaller === 0) break;
r = larger % smaller;
larger = smaller;
smaller = r;
}
return r;
}
export const Day11: DayFunc = (input) => {
const parsed = input
.trim()
.split("\n\n")
.map((v) => v.split("\n").map((i) => i.trim()));
const list: MonkeyList = parsed.reduce((prev, next) => {
const num = next[0].split(" ")[1].slice(0, -1);
const items = next[1]
.split(" ")
.slice(2)
.map((i) => i.replace(",", ""));
const op = next[2].split("new = old ")[1];
const test = parseInt(next[3].split(" ").pop());
const ifTrue = parseInt(next[4].split(" ").pop());
const ifFalse = parseInt(next[5].split(" ").pop());
prev[num] = {
items: items,
operation: op,
test: test,
ifTrue: ifTrue,
ifFalse: ifFalse,
inspected: 0,
};
return prev;
}, {});
const part1List: MonkeyList = JSON.parse(JSON.stringify(list));
const part2List: MonkeyList = JSON.parse(JSON.stringify(list));
for (let round = 1; round <= 20; round++) {
Object.values(part1List).forEach((v) => {
v.items.forEach(old => {
v.inspected++;
let newVal = eval(`${old}${v.operation.replace('old', old.toString())}`);
newVal = Math.floor(newVal / 3);
if (newVal % v.test === 0) {
part1List[v.ifTrue].items.push(newVal);
} else {
part1List[v.ifFalse].items.push(newVal);
}
});
v.items = [];
});
}
const part1 = Object.values(part1List).map(v => v.inspected).sort((a, b) => b - a);
const product = Object.values(part2List).reduce((p, v) => p * v.test, 1);
for (let round = 0; round < 10000; round++) {
Object.values(part2List).forEach((v) => {
v.inspected += v.items.length;
v.items.forEach(old => {
let newVal = eval(`${old}${v.operation.replace('old', old.toString())}`);
if (newVal > product) {
newVal = newVal % product;
}
if (newVal % v.test === 0) {
part2List[v.ifTrue].items.push(newVal);
} else {
part2List[v.ifFalse].items.push(newVal);
}
});
v.items = [];
});
}
const part2 = Object.values(part2List).map(v => v.inspected).sort((a, b) => b - a);
console.log(part2);
return [part1[0] * part1[1], part2[0] * part2[1]];
};

View File

@@ -0,0 +1,132 @@
import { DayFunc } from "..";
const FunnyCharCode = (input: string): number => {
if (input === "S") return "a".charCodeAt(0);
if (input === "E") return "z".charCodeAt(0);
return input.charCodeAt(0);
};
const IsOk = (
input: string[][],
edges: Record<string, string[]>,
a: [number, number],
b: [number, number]
) => {
if (!edges[`${a[0]},${a[1]}`]) {
edges[`${a[0]},${a[1]}`] = [];
}
const c = edges[`${a[0]},${a[1]}`];
if (FunnyCharCode(input[a[0]][a[1]]) - FunnyCharCode(input[b[0]][b[1]]) >= -1) {
c.push(`${b[0]},${b[1]}`);
}
};
export const Day12: DayFunc = (input) => {
const parsed = input
.trim()
.split("\n")
.map((i) => i.split(""));
const edges: Record<string, string[]> = {};
const visited: { letter: string; node: string; visited: boolean }[] = [];
for (let i = 0; i < parsed.length; i++) {
for (let j = 0; j < parsed[0].length; j++) {
visited.push({
letter: parsed[i][j],
node: `${i},${j}`,
visited: false,
});
if (i > 0 && j > 0 && i < parsed.length - 1 && j < parsed[0].length - 1) {
IsOk(parsed, edges, [i, j], [i + 1, j]);
IsOk(parsed, edges, [i, j], [i - 1, j]);
IsOk(parsed, edges, [i, j], [i, j + 1]);
IsOk(parsed, edges, [i, j], [i, j - 1]);
} else if (i > 0 && j > 0 && i < parsed.length - 1) {
IsOk(parsed, edges, [i, j], [i + 1, j]);
IsOk(parsed, edges, [i, j], [i - 1, j]);
IsOk(parsed, edges, [i, j], [i, j - 1]);
} else if (i > 0 && j > 0 && j < parsed[0].length - 1) {
IsOk(parsed, edges, [i, j], [i - 1, j]);
IsOk(parsed, edges, [i, j], [i, j + 1]);
IsOk(parsed, edges, [i, j], [i, j - 1]);
} else if (i === 0 && j > 0 && j < parsed[0].length - 1) {
IsOk(parsed, edges, [i, j], [i + 1, j]);
IsOk(parsed, edges, [i, j], [i, j + 1]);
IsOk(parsed, edges, [i, j], [i, j - 1]);
} else if (j === 0 && i > 0 && i < parsed.length - 1) {
IsOk(parsed, edges, [i, j], [i + 1, j]);
IsOk(parsed, edges, [i, j], [i - 1, j]);
IsOk(parsed, edges, [i, j], [i, j + 1]);
}
}
}
IsOk(parsed, edges, [0, 0], [0, 1]);
IsOk(parsed, edges, [0, 0], [1, 0]);
IsOk(
parsed,
edges,
[parsed.length - 1, parsed[0].length - 1],
[parsed.length - 1, parsed[0].length - 2]
);
IsOk(
parsed,
edges,
[parsed.length - 1, parsed[0].length - 1],
[parsed.length - 2, parsed[0].length - 1]
);
IsOk(parsed, edges, [parsed.length - 1, 0], [parsed.length - 2, 0]);
IsOk(parsed, edges, [parsed.length - 1, 0], [parsed.length - 1, 1]);
IsOk(parsed, edges, [0, parsed[0].length - 1], [0, parsed[0].length - 2]);
IsOk(parsed, edges, [0, parsed[0].length - 1], [1, parsed[0].length - 1]);
const startNode = visited.find((v) => v.letter === "S");
const part1 = BFS(startNode.node, edges, visited);
const part2 = visited.filter(v => v.letter === 'a').map(n => BFS(n.node, edges, visited));
return [part1, Math.min(...part2)];
};
const BFS = (
currentNode: string,
edges: Record<string, string[]>,
visited: { letter: string; node: string; visited: boolean }[]
): number => {
const q: Array<{ letter: string; node: string; visited: boolean } | null> =
[];
const marked = new Set();
const c = visited.find((v) => v.node === currentNode);
q.push(c);
const depthQueue = [0];
marked.add(c.node);
while (q.length > 0) {
const head = q.shift();
const level = depthQueue.shift();
marked.add(head.node);
if (head.letter === "E") {
return level;
}
edges[head.node].filter(p => !marked.has(p)).forEach(v => {
const n = visited.find(i => i.node === v);
marked.add(n.node);
q.push(n);
depthQueue.push(level + 1);
});
}
return 10000000;
};

View File

@@ -0,0 +1,56 @@
import { DayFunc } from "..";
const Compare = (a: any, b: any): "left" | "right" | null => {
if (typeof a === "number" && typeof b === "number") {
if (a < b) {
return "right";
} else if (a > b) {
return "left";
} else {
return null;
}
} else if (typeof a === "object" && typeof b === "object") {
if (a.length === 0 && b.length > 0) return "right";
if (b.length === 0 && a.length > 0) return "left";
if (a.length === 0 && b.length === 0) return null;
const ans = Compare(a[0], b[0]);
if (ans !== null) return ans;
a.shift();
b.shift();
return Compare(a, b);
} else if (typeof a === "object") {
return Compare(a, [b]);
} else if (typeof b === "object") {
return Compare([a], b);
}
};
export const Day13: DayFunc = (input) => {
const parsed = input
.trim()
.split("\n\n")
.map((v) => v.split("\n").map((w) => JSON.parse(w)));
const part2Parsed = input.trim().replaceAll('\n\n', '\n').split('\n').map(v => JSON.parse(v));
part2Parsed.push([[2]]);
part2Parsed.push([[6]]);
let part1 = 0;
parsed.forEach(([a, b], i) => {
const side = Compare(a, b);
if (side === "right") {
part1 += i + 1;
}
});
part2Parsed.sort((a, b) => {
if (Compare(JSON.parse(JSON.stringify(a)), JSON.parse(JSON.stringify(b))) === "left") return 1
return -1;
});
const two = part2Parsed.findIndex(i => JSON.stringify(i) === JSON.stringify([[2]])) + 1;
const six = part2Parsed.findIndex(i => JSON.stringify(i) === JSON.stringify([[6]])) + 1;
return [part1, two * six];
};

View File

@@ -0,0 +1,178 @@
import { DayFunc, UP } from "..";
const writer = Bun.stdout.writer();
const PrintGrid = async (g: string[][]) => {
for (let i = 0; i < g.length; i++) {
for (let j = 0; j < g[0].length; j++) {
process.stdout.write(g[i][j]);
}
process.stdout.write('\n');
}
for (let i = 0; i < g.length; i++) {
process.stdout.write(UP)
}
};
const EraseSand = ([x, y]: [number, number]) => {
process.stdout.write(`\033[${y}B`);
process.stdout.write(`\033[${x}C`);
process.stdout.write('.');
process.stdout.write(`\033[${y}A`);
process.stdout.write(`\033[${x + 1}D`);
}
const PrintSand = ([x, y]: [number, number]) => {
process.stdout.write(`\033[${y}B`);
process.stdout.write(`\033[${x}C`);
process.stdout.write('+');
process.stdout.write(`\033[${y}A`);
process.stdout.write(`\033[${x + 1}D`);
}
let minX = 0;
let maxX = 0;
let ySize = 0;
// Returns true if the sand has settled.
const OneTick = (
[y, x]: [number, number],
grid: string[][]
): [boolean, boolean, [number, number]] => {
const next = grid[y + 1][x];
if (grid[y + 1][x] === undefined) {
return [false, true, [0, 0]];
}
if (next === ".") {
grid[y][x] = ".";
grid[y + 1][x] = "+";
return [false, false, [y + 1, x]];
} else {
if (grid[y + 1][x - 1] === ".") {
grid[y][x] = ".";
grid[y + 1][x - 1] = "+";
return [false, false, [y + 1, x - 1]];
} else if (grid[y + 1][x - 1] === undefined) {
return [false, true, [0, 0]];
} else if (grid[y + 1][x + 1] === ".") {
grid[y][x] = ".";
grid[y + 1][x + 1] = "+";
return [false, false, [y + 1, x + 1]];
} else if (grid[y + 1][x + 1] === undefined) {
return [false, true, [0, 0]];
} else {
//Settled
grid[y][x] = "o";
return [true, false, [y, x]];
}
}
};
export const Day14: DayFunc = (input) => {
const parsed = input
.trim()
.split("\n")
.map((i) =>
i.split(" -> ").map((v) => v.split(",").map((w) => parseInt(w)))
);
const xs = parsed.flatMap((v) => v).map((v) => v[0]);
const ys = parsed.flatMap((v) => v).map((v) => v[1]);
minX = Math.min(...xs);
maxX = Math.max(...xs);
const xSize = maxX - minX;
ySize = Math.max(...ys);
let sand: [number, number] = [0, 500 - minX];
const grid = Array.from({ length: ySize + 1 }, (_) =>
new Array(xSize + 1).fill(".")
);
parsed.forEach((rocks) => {
for (let i = 0; i < rocks.length - 1; i++) {
const [x1, y1] = rocks[i];
const [x2, y2] = rocks[i + 1];
if (x1 === x2) {
const startY = Math.min(y1, y2);
const endY = Math.max(y1, y2);
for (let j = startY; j <= endY; j++) {
grid[j][x1 - minX] = "#";
}
} else {
const startX = Math.min(x1, x2) - minX;
const endX = Math.max(x1, x2) - minX;
for (let j = startX; j <= endX; j++) {
grid[y1][j] = "#";
}
}
}
});
PrintGrid(grid);
grid[sand[0]][sand[1]] = "+";
const increaseSize = 200;
const part2Grid: string[][] = JSON.parse(JSON.stringify(grid));
for (let i = 0; i < part2Grid.length; i++) {
part2Grid[i] = [...Array(increaseSize).fill("."), ...part2Grid[i], ...Array(increaseSize).fill(".")];
}
part2Grid.push(Array(xSize + increaseSize * 2 + 1).fill("."));
part2Grid.push(Array(xSize + increaseSize * 2 + 1).fill("#"));
while (true) {
Bun.sleepSync(0.01);
const [settled, gameOver, newSand] = OneTick(sand, grid);
EraseSand([sand[1], sand[0]]);
if (gameOver) {
grid[sand[0]][sand[1]] = ".";
break;
}
if (!settled) {
sand = newSand;
} else {
sand = [0, 500 - minX];
grid[sand[0]][sand[1]] = "+";
}
PrintSand([sand[1], sand[0]]);
}
for (let i = 0; i < grid.length; i++) {
process.stdout.write('\n');
}
const part1 = grid.reduce((p, n) => p + n.filter((i) => i === "o").length, 0);
minX = minX - increaseSize;
ySize = ySize + 2;
sand = [0, 500 - minX];
while (true) {
// Bun.sleepSync(0.001);
// PrintGrid(part2Grid);
const [settled, gameOver, newSand] = OneTick(sand, part2Grid);
if (gameOver) {
part2Grid[sand[0]][sand[1]] = ".";
break;
}
if (!settled) {
sand = newSand;
} else {
if (newSand[0] === 0 && newSand[1] === 500 - minX) {
part2Grid[0][500 - minX] = 'o';
break;
}
sand = [0, 500 - minX];
part2Grid[sand[0]][sand[1]] = "+";
}
}
for (let i = 0; i < grid.length; i++) {
writer.write('\n');
}
const part2 = part2Grid.reduce((p, n) => p + n.filter((i) => i === "o").length, 0);
return [part1, part2];
};

View File

@@ -0,0 +1,69 @@
import { DayFunc } from "..";
type Pos = { x: number; y: number };
export const Day15: DayFunc = (input) => {
const parsed = input
.trim()
.split("\n")
.map((v) => v.split(" at "))
.map((v) => [v[1].slice(0, v[1].indexOf(":")), v[2]])
.map((v) => v.map((i) => i.replaceAll(/[a-z]=/g, "").replaceAll(" ", "")))
.map((v) => {
const oneSplit = v[0].split(",");
const twoSplit = v[1].split(",");
return [
[parseInt(oneSplit[0]), parseInt(oneSplit[1])],
[parseInt(twoSplit[0]), parseInt(twoSplit[1])],
];
});
const grid: Array<{ sensor: Pos; beacon: Pos; distance: number }> = [];
let smallestX = 10000;
let largestX = 0;
parsed.forEach((i) => {
const dist = Math.abs(i[0][0] - i[1][0]) + Math.abs(i[0][1] - i[1][1]);
if (i[0][0] < smallestX) smallestX = i[0][0];
if (i[1][0] < smallestX) smallestX = i[1][0];
if (i[0][0] > largestX) largestX = i[0][0];
if (i[1][0] > largestX) largestX = i[1][0];
grid.push({
sensor: {
x: i[0][0],
y: i[0][1],
},
beacon: {
x: i[1][0],
y: i[1][1],
},
distance: dist,
});
});
const y = 10;
let part1 = 0;
console.log(smallestX);
console.log(largestX);
for (let i = smallestX - 10000000; i <= largestX + 10000000; i++) {
const testPos: Pos = {
x: i,
y: y,
};
const beaconHere = grid.find(p => p.beacon.x === testPos.x && p.beacon.y === testPos.y);
if (beaconHere) {
continue;
}
const testPoint = grid.find(p => Math.abs(p.sensor.x - testPos.x) + Math.abs(p.sensor.y - testPos.y) <= p.distance);
if (testPoint) {
part1++;
}
}
return [part1, 0];
};

View File

@@ -0,0 +1,218 @@
import { DayFunc } from "..";
const blocks = [
[["@", "@", "@", "@"]],
[
[".", "@", "."],
["@", "@", "@"],
[".", "@", "."],
],
[
[".", ".", "@"],
[".", ".", "@"],
["@", "@", "@"],
],
[["@"], ["@"], ["@"], ["@"]],
[
["@", "@"],
["@", "@"],
],
];
function PrintGrid(grid: string[][]) {
for (let i = grid.length - 1; i >= 0; i--) {
for (let j = 0; j < grid[0].length; j++) {
process.stdout.write(grid[i][j]);
}
process.stdout.write("\n");
}
process.stdout.write("++++++++++++++++++++++++++++\n");
}
function MoveDown(
grid: string[][],
block: string[][],
[x, y]: [number, number]
): boolean {
// Moving through the floor.
if (y - block.length + 1 === 0) return false;
for (let i = block.length - 1; i >= 0; i--) {
for (let j = 0; j < block[0].length; j++) {
if (block[i][j] === "@" && grid[y - i - 1][j + x] === "#") {
return false;
}
}
}
// No collision. Clear block.
for (let i = block.length - 1; i >= 0; i--) {
for (let j = 0; j < block[0].length; j++) {
if (block[i][j] === "@") {
grid[y - i][j + x] = ".";
}
}
}
y--;
for (let i = block.length - 1; i >= 0; i--) {
for (let j = 0; j < block[0].length; j++) {
if (block[i][j] === "@") {
grid[y - i][j + x] = "@";
}
}
}
return true;
}
function MoveSides(
grid: string[][],
block: string[][],
[x, y]: [number, number],
unit: -1 | 1
): boolean {
// Goes off the sides
if (x + unit < 0 || x + block[0].length + unit > grid[0].length) return false;
for (let i = block.length - 1; i >= 0; i--) {
for (let j = 0; j < block[0].length; j++) {
if (block[i][j] === "@" && grid[y - i][j + x + unit] === "#") {
return false;
}
}
}
// No collision. Clear block.
for (let i = block.length - 1; i >= 0; i--) {
for (let j = 0; j < block[0].length; j++) {
if (block[i][j] === "@") {
grid[y - i][j + x] = ".";
}
}
}
x += unit;
for (let i = block.length - 1; i >= 0; i--) {
for (let j = 0; j < block[0].length; j++) {
if (block[i][j] === "@") {
grid[y - i][j + x] = "@";
}
}
}
return true;
}
function SettleBlock(
grid: string[][],
block: string[][],
[x, y]: [number, number]
) {
for (let i = block.length - 1; i >= 0; i--) {
for (let j = 0; j < block[0].length; j++) {
if (block[i][j] === "@") {
grid[y - i][j + x] = "#";
}
}
}
}
function* BlockGen(start = 0, end = Infinity, step = 1) {
for (let i = start; i < end; i += step) {
yield { block: blocks[i % blocks.length]!, index: i % blocks.length };
}
}
function CalcHeight(grid: string[][]) {
let e = 0;
for (let i = grid.length - 1; i >= 0; i--) {
if (grid[i].some((j) => j === "#")) {
break;
}
e++;
}
return grid.length - e;
}
export const Day17: DayFunc = (input) => {
const parsed = input.trim().split("");
const gen = BlockGen();
const grid: string[][] = [];
let jet = 0;
let part1: number;
let addedOnHeight = 0;
const depthMap: Record<string, {height: number; index: number}> = {};
for (let i = 0; i < 1e12; i++) {
if (i === 2022) {
part1 = CalcHeight(grid);
}
const g = gen.next().value;
if (!g) return;
const block = g.block;
// Not right, not necessarily the top row.
let emptyRows = 0;
let rock = -1;
for (let c = grid.length - 1; c >= 0; c--) {
if (grid[c].some((i) => i === "#")) {
rock = c;
break;
}
emptyRows++;
}
if (emptyRows < 3 + block.length) {
for (let c = 0; c <= 2 + block.length - emptyRows; c++) {
grid.push([".", ".", ".", ".", ".", ".", "."]);
}
}
const topLeft: [number, number] = [2, rock + 3 + block.length];
for (let j = block.length - 1; j >= 0; j--) {
const newRow = [".", ".", ...block[j]];
for (let k = 0; k < 5 - block[j].length; k++) {
newRow.push(".");
}
grid[rock === -1 ? 3 - j : block.length - j + rock + 3] = newRow;
}
let movedDown = true;
do {
if (parsed[jet % parsed.length] === "<") {
const moved = MoveSides(grid, block, topLeft, -1);
if (moved) topLeft[0]--;
} else {
const moved = MoveSides(grid, block, topLeft, 1);
if (moved) topLeft[0]++;
}
jet++;
movedDown = MoveDown(grid, block, topLeft);
if (movedDown) {
topLeft[1]--;
}
} while (movedDown);
SettleBlock(grid, block, topLeft);
const depth = [0, 0, 0, 0, 0, 0, 0];
for (let x = 0; x < 7; x++) {
for (let y = grid.length - 1; y >= 0; y--) {
if (grid[y][x] === '#') {
depth[x] = grid.length - y;
break;
}
}
}
const key = `${g.index},${jet % parsed.length},${JSON.stringify(depth)}`;
if (key in depthMap) {
const height = CalcHeight(grid);
const mapEntry = depthMap[key];
const diff = height - mapEntry.height;
const cycleNum = Math.floor((1e12 - i) / (i - mapEntry.index));
i += cycleNum * (i - mapEntry.index);
addedOnHeight += diff * cycleNum;
} else {
depthMap[key] = { height: CalcHeight(grid), index: i };
}
}
return [part1, CalcHeight(grid) + addedOnHeight];
};

View File

@@ -0,0 +1,31 @@
import { DayFunc } from "..";
function CalcDist(
[x1, y1, z1]: [number, number, number],
[x2, y2, z2]: [number, number, number]
): number {
return Math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2 + (z1 - z2) ** 2);
}
export const Day18: DayFunc = (input) => {
const parsed = input
.trim()
.split("\n")
.map((i) => i.split(",").map((j) => parseInt(j)));
let part1 = parsed.length * 6;
for (let i = 0; i < parsed.length; i++) {
const a = parsed[i];
for (let j = 0; j < parsed.length; j++) {
if (i === j) continue;
const b = parsed[j];
// @ts-ignore
const dist = CalcDist(a, b);
if (dist === 1) {
part1--;
}
}
}
return [part1, 0];
};

View File

@@ -0,0 +1,70 @@
import { DayFunc } from "..";
// A = Rock, B = Paper, C = Scissors
// X = Rock, Y = Paper, Z = Scissors
// 1 = Rock, 2 = Paper, 3 = Scissors
// 0 = Lose, 3 = Draw, 6 = Win
type Options = 'r' | 'p' | 's';
const mapping: {[key: string]: Options} = {
A: 'r',
B: 'p',
C: 's',
X: 'r',
Y: 'p',
Z: 's',
}
const scores: Record<
Options,
{
score: number;
beats: Options;
loses: Options;
}
> = {
'r': {
score: 1,
beats: "s",
loses: "p",
},
'p': {
score: 2,
beats: "r",
loses: "s",
},
's': {
score: 3,
beats: "p",
loses: "r",
},
};
export const Day2: DayFunc = (input) => {
const plays: string[][] = input
.trim()
.split("\n")
.map((line) => line.split(" "));
let part1 = 0;
let part2 = 0;
plays.forEach(([opp, you]) => {
part1 += scores[mapping[you]].score;
if (mapping[you] === mapping[opp]) {
part1 += 3;
} else if (scores[mapping[you]].beats === mapping[opp]) {
part1 += 6;
}
if (you === 'X') {
part2 += scores[scores[mapping[opp]].beats].score;
} else if (you === 'Y') {
part2 += 3 + scores[mapping[opp]].score;
} else {
part2 += 6 + scores[scores[mapping[opp]].loses].score;
}
});
return [part1, part2];
};

View File

@@ -0,0 +1,35 @@
import { DayFunc } from "..";
const getCode = (x: Set<string>): number => {
const code = x.values().next().value.charCodeAt(0);
return code + (code <= 90 ? -38 : -96);
};
export const Day3: DayFunc = (input) => {
const bags: string[] = input
.trim()
.split("\n")
const part1Bags = bags.map((i) => [i.slice(0, i.length / 2), i.slice(i.length / 2)]);
const part2Bags = []
for (let i = 0; i < bags.length; i += 3) {
part2Bags.push(bags.slice(i, i + 3));
}
const part1 = part1Bags.reduce((prev, [c1, c2]) => {
const set1 = new Set(c1);
const set2 = new Set(c2);
const n = new Set([...set1].filter((x) => set2.has(x)));
return prev + getCode(n);
}, 0);
const part2 = part2Bags.reduce((prev, [c1, c2, c3]) => {
const set1 = new Set(c1);
const set2 = new Set(c2);
const set3 = new Set(c3);
const n = new Set([...set1].filter((x) => set2.has(x)).filter(x => set3.has(x)));
return prev + getCode(n as Set<string>);
}, 0)
return [part1, part2];
};

View File

@@ -0,0 +1,29 @@
import { DayFunc } from "..";
export const Day4: DayFunc = (input) => {
const pairs: number[][][] = input
.trim()
.split("\n")
.map((l) => l.split(",").map((p) => p.split("-").map((v) => parseInt(v))));
const [part1, part2] = pairs.reduce(
([part1, part2], next) => {
if (
(next[0][0] <= next[1][0] && next[0][1] >= next[1][1]) ||
(next[1][0] <= next[0][0] && next[1][1] >= next[0][1])
) {
part1++;
part2++;
} else if (
(next[0][0] <= next[1][0] && next[1][0] <= next[0][1]) ||
(next[1][0] <= next[0][0] && next[0][0] <= next[1][1])
) {
part2++;
}
return [part1, part2];
},
[0, 0]
);
return [part1, part2];
};

View File

@@ -0,0 +1,45 @@
import { DayFunc } from "..";
export const Day5: DayFunc = (input) => {
let [inStacks, instructions] = input
.split("\n\n")
const stacks = inStacks.split('\n')
stacks.pop();
const numOfStacks = (stacks[0].length + 1) / 4;
let realStacks = [...Array(numOfStacks)].map(() => []);
for (let i = 0; i < stacks.length; i++) {
for (let j = 1; j < stacks[i].length; j += 4) {
const c = stacks[i].charAt(j);
const stackNum = (j - 1) / 4;
if (c !== " ") {
realStacks[stackNum].push(c);
}
}
}
realStacks.map(s => s.reverse());
const realStacks2 = [...realStacks].map(i => [...i]);
const rules = instructions.split('\n').map((i) => {
const is = i.split(" ");
return [parseInt(is[1]), parseInt(is[3]) - 1, parseInt(is[5]) - 1];
});
rules.pop();
rules.forEach(r => {
for (let i = 0; i < r[0]; i++) {
const popped = realStacks[r[1]].pop();
realStacks[r[2]].push(popped);
}
const crates = realStacks2[r[1]].splice(-r[0]);
realStacks2[r[2]].push(...crates);
});
const part1 = realStacks.reduce((prev, next) => prev + next[next.length - 1], "");
const part2 = realStacks2.reduce((prev, next) => prev + next[next.length - 1], "");
return [part1, part2];
};

View File

@@ -0,0 +1,21 @@
import { DayFunc } from "..";
const FindRepeated = (input: string, gap: number): number => {
for (let i = 0; i < input.length - gap; i++) {
const sub = input.substring(i, i + gap);
let changed = false;
for (const c of sub) {
if (sub.split(c).length > 2) {
i += sub.indexOf(c);
changed = true;
break;
}
}
if (!changed) return i + gap;
}
return -1;
}
export const Day6: DayFunc = (input) => {
return [FindRepeated(input, 4), FindRepeated(input, 14)];
}

View File

@@ -0,0 +1,92 @@
import { DayFunc } from "..";
type Node = {
name: string;
type: "file" | "dir";
size: number;
};
type Files = {
[key: string]: { size: number; children: Node[] };
};
const totalItems: Files = {};
const CalcSize = (dirName: string): number => {
const dir = totalItems[dirName];
let size = 0;
for (const c of dir.children) {
if (c.type === "file") {
size += c.size;
} else {
size += CalcSize(c.name);
}
}
dir.size = size;
return size;
};
export const Day7: DayFunc = (input) => {
const parsed = input
.trim()
.split("\n")
.filter((i) => i !== "$ ls").slice(1);
let path: string[] = [];
let items: Node[] = [];
parsed.forEach((i) => {
let pathReduced = "/";
for (const c of path) {
pathReduced += c + "/";
}
if (i === "$ cd ..") {
if (!(pathReduced in totalItems)) {
totalItems[pathReduced] = { size: 0, children: [...items] };
items = [];
}
path.pop();
} else if (i.charAt(0) === "$") {
if (!(pathReduced in totalItems)) {
totalItems[pathReduced] = { size: 0, children: [...items] };
items = [];
}
path.push(i.split(" ")[2]);
} else {
const s = i.split(" ");
items.push({
type: s[0] === "dir" ? "dir" : "file",
size: s[0] === "dir" ? 0 : parseInt(s[0]),
name: s[0] === "dir" ? pathReduced + s[1] + "/" : s[1],
});
}
});
let pathReduced = "/";
for (const c of path) {
pathReduced += c + "/";
}
if (!(pathReduced in totalItems)) {
totalItems[pathReduced] = { size: -1, children: [...items] };
items = [];
}
CalcSize("/");
const part1 = Object.values(totalItems).reduce((p, n) => {
if (n.size <= 100000) {
return p + n.size;
}
return p;
}, 0);
const usedSize = totalItems["/"].size;
const toFree = 30000000 - (70000000 - usedSize);
const part2 = Object.entries(totalItems).map(v => {
if (v[1].size > toFree) {
return v[1].size;
}
}).filter(v => v).sort()[0];
return [part1, part2];
};

View File

@@ -0,0 +1,57 @@
import { DayFunc } from "..";
const GetSmaller = (arr: number[], target: number): number => {
let i = 0;
for (; i < arr.length && arr[i] < target; i++) {}
return i;
};
const Part2 = (arr: number[], target: number): number => {
const i = arr.findIndex(i => i >= target);
if (i === -1) {
return arr.length;
}
return i + 1;
}
export const Day8: DayFunc = (input) => {
const parsed: number[][] = input
.trim()
.split("\n")
.map((v) => v.split("").map((i) => parseInt(i)));
const transposed = parsed[0].map((_, colIndex) =>
parsed.map((row) => row[colIndex])
);
let part1 = parsed.length * 2 + parsed[0].length * 2 - 4;
let part2 = 0;
for (let i = 1; i < parsed.length - 1; i++) {
for (let j = 1; j < parsed[0].length - 1; j++) {
const c = parsed[i][j];
const row = parsed[i];
const col = transposed[j];
const left = row.slice(0, j).reverse();
const right = row.slice(j + 1);
const top = col.slice(0, i).reverse();
const bottom = col.slice(i + 1);
if (
GetSmaller(left, c) === left.length ||
GetSmaller(right, c) === right.length ||
GetSmaller(top, c) === top.length ||
GetSmaller(bottom, c) === bottom.length
) {
part1++;
}
const view = Part2(left, c) * Part2(right, c) * Part2(top, c) * Part2(bottom, c);
if (view > part2) {
part2 = view;
}
}
}
return [part1, part2];
};

View File

@@ -0,0 +1,71 @@
import { DayFunc } from "..";
type Pos = { x: number; y: number };
// Returns the non square rooted distance
const CalcDist = (a: Pos, b: Pos) => {
return (a.x - b.x) ** 2 + (a.y - b.y) ** 2;
};
const CalcVisited = (snake: Pos[], parsed: [string, number][]): Record<string, number> => {
const visited: Record<string, number> = {};
visited[JSON.stringify(snake[1])] = 1;
parsed.forEach(([direction, num]) => {
for (let i = 0; i < num; i++) {
if (direction === "R") snake[0].x++;
else if (direction === "L") snake[0].x--;
else if (direction === "U") snake[0].y++;
else if (direction === "D") snake[0].y--;
for (let j = 1; j < snake.length; j++) {
const t = snake[j];
const h = snake[j - 1]
const dist = CalcDist(h, t);
if (dist === 4) {
if (t.x === h.x) {
t.y += (h.y < t.y) ? -1 : 1;
} else if (t.y === h.y) {
t.x += (h.x < t.x) ? -1 : 1;
}
} else if (dist === 5 || dist === 8) {
t.x += (h.x > t.x) ? 1 : -1;
t.y += (h.y > t.y) ? 1 : -1;
}
}
const tailString = JSON.stringify(snake[snake.length - 1]);
if (tailString in visited) {
visited[tailString] = visited[tailString] + 1;
} else {
visited[tailString] = 1;
}
}
});
return visited;
}
export const Day9: DayFunc = (input) => {
const parsed: [string, number][] = input
.trim()
.split("\n")
.map((v) => v.split(" "))
.map(([a, b]) => [a, parseInt(b)]);
// 0th index is the head;
const part1Snake: Pos[] = [
{ x: 0, y: 0 },
{ x: 0, y: 0 },
];
const part2Snake: Pos[] = [];
for (let i = 0; i < 10; i++) {
part2Snake.push({x: 0, y: 0});
}
const part1 = CalcVisited(part1Snake, parsed)
const part2 = CalcVisited(part2Snake, parsed)
return [Object.keys(part1).length, Object.keys(part2).length];
};

View File

@@ -0,0 +1,17 @@
export * from './Day1';
export * from './Day2';
export * from './Day3';
export * from './Day4';
export * from './Day5';
export * from './Day6';
export * from './Day7';
export * from './Day8';
export * from './Day9';
export * from './Day10';
export * from './Day11';
export * from './Day12';
export * from './Day13';
export * from './Day14';
export * from './Day15';
export * from './Day17';
export * from './Day18';