From afd191f21b141185575590c2e9f79983294e16d0 Mon Sep 17 00:00:00 2001 From: Alexander Vogt Date: Sat, 23 Nov 2024 18:41:47 +0100 Subject: [PATCH] all of 2020 --- 2020/01/task.ts | 18 +++- 2020/02/runner.ts | 29 ++++++ 2020/02/task.ts | 28 ++++++ 2020/03/runner.ts | 29 ++++++ 2020/03/task.ts | 24 +++++ 2020/04/runner.ts | 29 ++++++ 2020/04/task.ts | 66 ++++++++++++ 2020/05/runner.ts | 29 ++++++ 2020/05/task.ts | 38 +++++++ 2020/06/runner.ts | 29 ++++++ 2020/06/task.ts | 37 +++++++ 2020/07/runner.ts | 29 ++++++ 2020/07/task.ts | 77 ++++++++++++++ 2020/08/runner.ts | 29 ++++++ 2020/08/task.ts | 56 +++++++++++ 2020/09/runner.ts | 29 ++++++ 2020/09/task.ts | 47 +++++++++ 2020/10/runner.ts | 29 ++++++ 2020/10/task.ts | 41 ++++++++ 2020/11/runner.ts | 29 ++++++ 2020/11/task.ts | 62 ++++++++++++ 2020/12/runner.ts | 29 ++++++ 2020/12/task.ts | 69 +++++++++++++ 2020/13/runner.ts | 29 ++++++ 2020/13/task.ts | 46 +++++++++ 2020/14/runner.ts | 29 ++++++ 2020/14/task.ts | 76 ++++++++++++++ 2020/15/runner.ts | 29 ++++++ 2020/15/task.ts | 43 ++++++++ 2020/16/runner.ts | 29 ++++++ 2020/16/task.ts | 129 ++++++++++++++++++++++++ 2020/17/runner.ts | 29 ++++++ 2020/17/task.ts | 127 +++++++++++++++++++++++ 2020/18/runner.ts | 29 ++++++ 2020/18/task.ts | 153 ++++++++++++++++++++++++++++ 2020/19/runner.ts | 29 ++++++ 2020/19/task.ts | 132 ++++++++++++++++++++++++ 2020/20/runner.ts | 29 ++++++ 2020/20/task.ts | 216 ++++++++++++++++++++++++++++++++++++++++ 2020/21/runner.ts | 29 ++++++ 2020/21/task.ts | 88 ++++++++++++++++ 2020/22/runner.ts | 29 ++++++ 2020/22/task.ts | 133 +++++++++++++++++++++++++ 2020/23/runner.ts | 29 ++++++ 2020/23/task.ts | 114 +++++++++++++++++++++ 2020/24/runner.ts | 29 ++++++ 2020/24/task.ts | 68 +++++++++++++ 2020/25/runner.ts | 29 ++++++ 2020/25/task.ts | 21 ++++ base/simpleStructure.ts | 4 +- 50 files changed, 2605 insertions(+), 4 deletions(-) create mode 100644 2020/02/runner.ts create mode 100644 2020/02/task.ts create mode 100644 2020/03/runner.ts create mode 100644 2020/03/task.ts create mode 100644 2020/04/runner.ts create mode 100644 2020/04/task.ts create mode 100644 2020/05/runner.ts create mode 100644 2020/05/task.ts create mode 100644 2020/06/runner.ts create mode 100644 2020/06/task.ts create mode 100644 2020/07/runner.ts create mode 100644 2020/07/task.ts create mode 100644 2020/08/runner.ts create mode 100644 2020/08/task.ts create mode 100644 2020/09/runner.ts create mode 100644 2020/09/task.ts create mode 100644 2020/10/runner.ts create mode 100644 2020/10/task.ts create mode 100644 2020/11/runner.ts create mode 100644 2020/11/task.ts create mode 100644 2020/12/runner.ts create mode 100644 2020/12/task.ts create mode 100644 2020/13/runner.ts create mode 100644 2020/13/task.ts create mode 100644 2020/14/runner.ts create mode 100644 2020/14/task.ts create mode 100644 2020/15/runner.ts create mode 100644 2020/15/task.ts create mode 100644 2020/16/runner.ts create mode 100644 2020/16/task.ts create mode 100644 2020/17/runner.ts create mode 100644 2020/17/task.ts create mode 100644 2020/18/runner.ts create mode 100644 2020/18/task.ts create mode 100644 2020/19/runner.ts create mode 100644 2020/19/task.ts create mode 100644 2020/20/runner.ts create mode 100644 2020/20/task.ts create mode 100644 2020/21/runner.ts create mode 100644 2020/21/task.ts create mode 100644 2020/22/runner.ts create mode 100644 2020/22/task.ts create mode 100644 2020/23/runner.ts create mode 100644 2020/23/task.ts create mode 100644 2020/24/runner.ts create mode 100644 2020/24/task.ts create mode 100644 2020/25/runner.ts create mode 100644 2020/25/task.ts diff --git a/2020/01/task.ts b/2020/01/task.ts index 3d8caba..d23706f 100644 --- a/2020/01/task.ts +++ b/2020/01/task.ts @@ -1,7 +1,21 @@ export async function taskOne(input: string[]): Promise { - console.log("Unimplemented"); + const nums = input.map(Number) + for (let i = 0; i < nums.length; i++) { + for (let j = i+1; j < nums.length; j++) { + if (nums[i] + nums[j] == 2020) console.log(nums[i]*nums[j]) + } + } } export async function taskTwo(input: string[]): Promise { - console.log("Unimplemented"); + const nums = input.map(Number) + for (let i = 0; i < nums.length; i++) { + if (nums[i] > 2020) continue + for (let j = i+1; j < nums.length; j++) { + if (nums[i] + nums[j] > 2020) continue + for (let k = j+1; k < nums.length; k++) { + if (nums[i] + nums[j] + nums[k] == 2020) console.log(nums[i]*nums[j]*nums[k]) + } + } + } } \ No newline at end of file diff --git a/2020/02/runner.ts b/2020/02/runner.ts new file mode 100644 index 0000000..b72c86b --- /dev/null +++ b/2020/02/runner.ts @@ -0,0 +1,29 @@ +import { readFile } from "fs/promises"; +import { taskOne, taskTwo } from "./task"; + +async function main() { + let lastArgument = process.argv.pop() as string; + let taskNumber = 1; + let isTest = false; + + if (lastArgument === "test") { + isTest = true; + taskNumber = parseInt(process.argv.pop() as string); + } else { + taskNumber = parseInt(lastArgument) + } + + const fileToLoad = isTest ? "test.in" : "solve.in"; + const fileContents = await readFile(fileToLoad, "utf-8") + + const lines = fileContents.split("\n"); + + if (taskNumber === 1) { + await taskOne(lines); + } + if (taskNumber === 2) { + await taskTwo(lines); + } +} + +void main(); \ No newline at end of file diff --git a/2020/02/task.ts b/2020/02/task.ts new file mode 100644 index 0000000..13d6a02 --- /dev/null +++ b/2020/02/task.ts @@ -0,0 +1,28 @@ +export async function taskOne(input: string[]): Promise { + // 1-3 a: abcde + console.log(input.map(i => { + const r = /([0-9]+)-([0-9]+) (.): (.*)/.exec(i)! + let min = Number(r[1]) + let max = Number(r[2]) + let letter = r[3] + let pw = r[4] + let c = 0 + for (const l of pw) { + if (l == letter) c++ + } + return (c >= min && c <= max ? 1 : 0) as number + }).reduce((a,b)=>a+b,0)) +} + +export async function taskTwo(input: string[]): Promise { + console.log(input.map(i => { + const r = /([0-9]+)-([0-9]+) (.): (.*)/.exec(i)! + let pos1 = Number(r[1]) + let pos2 = Number(r[2]) + let letter = r[3] + let pw = r[4] + const p2 = pw[pos2-1] == letter + const res = pw[pos1-1] == letter ? !p2 : p2 + return (res ? 1:0) as number + }).reduce((a,b)=>a+b,0)) +} \ No newline at end of file diff --git a/2020/03/runner.ts b/2020/03/runner.ts new file mode 100644 index 0000000..b72c86b --- /dev/null +++ b/2020/03/runner.ts @@ -0,0 +1,29 @@ +import { readFile } from "fs/promises"; +import { taskOne, taskTwo } from "./task"; + +async function main() { + let lastArgument = process.argv.pop() as string; + let taskNumber = 1; + let isTest = false; + + if (lastArgument === "test") { + isTest = true; + taskNumber = parseInt(process.argv.pop() as string); + } else { + taskNumber = parseInt(lastArgument) + } + + const fileToLoad = isTest ? "test.in" : "solve.in"; + const fileContents = await readFile(fileToLoad, "utf-8") + + const lines = fileContents.split("\n"); + + if (taskNumber === 1) { + await taskOne(lines); + } + if (taskNumber === 2) { + await taskTwo(lines); + } +} + +void main(); \ No newline at end of file diff --git a/2020/03/task.ts b/2020/03/task.ts new file mode 100644 index 0000000..482b64a --- /dev/null +++ b/2020/03/task.ts @@ -0,0 +1,24 @@ +export async function taskOne(input: string[]): Promise { + console.log(check(input, 3, 1)) +} + +export async function taskTwo(input: string[]): Promise { + console.log(check(input,1,1)*check(input,3,1)*check(input,5,1)*check(input,7,1)*check(input,1,2)); +} + +function check(input: string[], xD: number, yD: number) { + const map = input.map(i => i.split('')) + const W = map[0].length + function get(x: number, y: number) { + return map[y][x % W] + } + let y = 0 + let c = 0 + let x = 0 + while(y < map.length) { + if (get(x,y) == '#') c++ + x += xD + y += yD + } + return c +} \ No newline at end of file diff --git a/2020/04/runner.ts b/2020/04/runner.ts new file mode 100644 index 0000000..b72c86b --- /dev/null +++ b/2020/04/runner.ts @@ -0,0 +1,29 @@ +import { readFile } from "fs/promises"; +import { taskOne, taskTwo } from "./task"; + +async function main() { + let lastArgument = process.argv.pop() as string; + let taskNumber = 1; + let isTest = false; + + if (lastArgument === "test") { + isTest = true; + taskNumber = parseInt(process.argv.pop() as string); + } else { + taskNumber = parseInt(lastArgument) + } + + const fileToLoad = isTest ? "test.in" : "solve.in"; + const fileContents = await readFile(fileToLoad, "utf-8") + + const lines = fileContents.split("\n"); + + if (taskNumber === 1) { + await taskOne(lines); + } + if (taskNumber === 2) { + await taskTwo(lines); + } +} + +void main(); \ No newline at end of file diff --git a/2020/04/task.ts b/2020/04/task.ts new file mode 100644 index 0000000..75a5ef9 --- /dev/null +++ b/2020/04/task.ts @@ -0,0 +1,66 @@ +export async function taskOne(input: string[]): Promise { + const passportKeys: string[][] = [] + let cur: string[] = [] + for (const i of input) { + if (i == '') { + passportKeys.push(cur) + cur = [] + continue + } + i.split(' ').forEach(j => { + cur.push(j.split(':')[0]) + }) + } + passportKeys.push(cur) + const allNeededKeys = ['byr','iyr','eyr','hgt','hcl','ecl','pid'] + let c = 0 + for (const p of passportKeys) { + if (allNeededKeys.every(k => p.includes(k))) c++ + } + console.log(c) +} + +export async function taskTwo(input: string[]): Promise { + const passportPairs: Record[] = [] + let cur: Record = {} + for (const i of input) { + if (i == '') { + passportPairs.push(cur) + cur = {} + continue + } + i.split(' ').forEach(j => { + const s = j.split(':') + cur[s[0]] = s[1] + }) + } + passportPairs.push(cur) + const allNeededKeys = ['byr','iyr','eyr','hgt','hcl','ecl','pid'] + let c = 0 + for (const p of passportPairs) { + const keys = Object.keys(p) + if (allNeededKeys.some(k => !keys.includes(k))) continue + if (!checkYear(p['byr'], 1920, 2002)) continue + if (!checkYear(p['iyr'], 2010, 2020)) continue + if (!checkYear(p['eyr'], 2020, 2030)) continue + if (!/^#[0-9a-f]{6}$/.test(p['hcl'])) continue + if (!['amb','blu','brn','gry','grn','hzl','oth'].includes(p['ecl'])) continue + if (!/^[0-9]{9}$/.test(p['pid'])) continue + + const h = p['hgt'] + const n = Number(h.substring(0, h.length-2)) + if (h.endsWith('in')) { + if (n > 76 || n < 59) continue + } else if (h.endsWith('cm')) { + if (n > 193 || n < 150) continue + } else continue + c++ + } + console.log(c) + + function checkYear(y: string, min: number, max: number) { + if (!/^[0-9]{4}$/.test(y)) return false + const v = Number(y) + return v >= min && v <= max + } +} \ No newline at end of file diff --git a/2020/05/runner.ts b/2020/05/runner.ts new file mode 100644 index 0000000..b72c86b --- /dev/null +++ b/2020/05/runner.ts @@ -0,0 +1,29 @@ +import { readFile } from "fs/promises"; +import { taskOne, taskTwo } from "./task"; + +async function main() { + let lastArgument = process.argv.pop() as string; + let taskNumber = 1; + let isTest = false; + + if (lastArgument === "test") { + isTest = true; + taskNumber = parseInt(process.argv.pop() as string); + } else { + taskNumber = parseInt(lastArgument) + } + + const fileToLoad = isTest ? "test.in" : "solve.in"; + const fileContents = await readFile(fileToLoad, "utf-8") + + const lines = fileContents.split("\n"); + + if (taskNumber === 1) { + await taskOne(lines); + } + if (taskNumber === 2) { + await taskTwo(lines); + } +} + +void main(); \ No newline at end of file diff --git a/2020/05/task.ts b/2020/05/task.ts new file mode 100644 index 0000000..c968348 --- /dev/null +++ b/2020/05/task.ts @@ -0,0 +1,38 @@ +export async function taskOne(input: string[]): Promise { + let max = 0 + for (const i of input) { + const v = getRow(i)*8+getSeat(i) + if(v > max) max =v + } + console.log(max) +} + +export async function taskTwo(input: string[]): Promise { + const seats = new Set() + let MAX = 128*8 + for (const i of input) { + const v = getRow(i)*8+getSeat(i) + seats.add(v) + } + for (let i = 0; i < MAX; i++) { + if (!seats.has(i) && seats.has(i+1) && seats.has(i-1)) console.log(i) + } +} + +function getRow(s: string) { + const mults = [64,32,16,8,4,2,1] + let c = 0 + for (let i = 0; i < mults.length; i++) { + if (s[i] == 'B') c += mults[i] + } + return c +} + +function getSeat(s: string) { + const mults = [4,2,1] + let c = 0; + for (let i = 0; i < mults.length; i++) { + if (s[i+7] == 'R') c += mults[i] + } + return c +} \ No newline at end of file diff --git a/2020/06/runner.ts b/2020/06/runner.ts new file mode 100644 index 0000000..b72c86b --- /dev/null +++ b/2020/06/runner.ts @@ -0,0 +1,29 @@ +import { readFile } from "fs/promises"; +import { taskOne, taskTwo } from "./task"; + +async function main() { + let lastArgument = process.argv.pop() as string; + let taskNumber = 1; + let isTest = false; + + if (lastArgument === "test") { + isTest = true; + taskNumber = parseInt(process.argv.pop() as string); + } else { + taskNumber = parseInt(lastArgument) + } + + const fileToLoad = isTest ? "test.in" : "solve.in"; + const fileContents = await readFile(fileToLoad, "utf-8") + + const lines = fileContents.split("\n"); + + if (taskNumber === 1) { + await taskOne(lines); + } + if (taskNumber === 2) { + await taskTwo(lines); + } +} + +void main(); \ No newline at end of file diff --git a/2020/06/task.ts b/2020/06/task.ts new file mode 100644 index 0000000..67e3957 --- /dev/null +++ b/2020/06/task.ts @@ -0,0 +1,37 @@ +export async function taskOne(input: string[]): Promise { + input.push('') + const s = new Set() + let c = 0 + for (const i of input) { + if (i == '') { + c += s.size + s.clear() + } + i.split('').forEach(j => s.add(j)) + } + console.log(c) +} + +export async function taskTwo(input: string[]): Promise { + input.push('') + let s: Record = {} + let c = 0 + let pc=0 + for (const i of input) { + if (i == '') { + const keys = Object.keys(s) + for (let k of keys) { + if (s[k] == pc) c++ + } + s = {} + pc = 0 + continue + } + i.split('').forEach(j => { + if(s[j] == undefined) s[j] = 0 + s[j]++ + }) + pc++ + } + console.log(c) +} \ No newline at end of file diff --git a/2020/07/runner.ts b/2020/07/runner.ts new file mode 100644 index 0000000..b72c86b --- /dev/null +++ b/2020/07/runner.ts @@ -0,0 +1,29 @@ +import { readFile } from "fs/promises"; +import { taskOne, taskTwo } from "./task"; + +async function main() { + let lastArgument = process.argv.pop() as string; + let taskNumber = 1; + let isTest = false; + + if (lastArgument === "test") { + isTest = true; + taskNumber = parseInt(process.argv.pop() as string); + } else { + taskNumber = parseInt(lastArgument) + } + + const fileToLoad = isTest ? "test.in" : "solve.in"; + const fileContents = await readFile(fileToLoad, "utf-8") + + const lines = fileContents.split("\n"); + + if (taskNumber === 1) { + await taskOne(lines); + } + if (taskNumber === 2) { + await taskTwo(lines); + } +} + +void main(); \ No newline at end of file diff --git a/2020/07/task.ts b/2020/07/task.ts new file mode 100644 index 0000000..f0b1dd2 --- /dev/null +++ b/2020/07/task.ts @@ -0,0 +1,77 @@ +export async function taskOne(input: string[]): Promise { + const bags = input.map(i => { + const s1 = i.split(' contain ') + const p = extractColor(s1[0]) + if (s1[1] == 'no other bags.') return {p: p, c: []} + const s2 = s1[1].substring(0, s1[1].length-1).split(', ') + const r = s2.map(s => { + return /[0-9]+ (.*)$/.exec(s)![1] + }).map(extractColor) + return {p:p, c: r} + }) + const reverseBags: Record = {} + for (const k of bags) { + reverseBags[k.p] = [] + for (const j of k.c) { + reverseBags[j] = [] + } + } + for (const b of bags) { + for (const k of b.c) { + reverseBags[k].push(b.p) + } + } + const possibles = new Set() + + reverseBags['shiny gold'].forEach(b => possibles.add(b)) + let lastSize = reverseBags.size + do { + lastSize = reverseBags.size + for (const b of possibles) { + reverseBags[b].forEach(c => possibles.add(c)) + } + + } while(lastSize != reverseBags.size) + console.log(possibles.size) +} + +export async function taskTwo(input: string[]): Promise { + const bagMap: Record = {} + input.forEach(i => { + const s1 = i.split(' contain ') + const p = extractColor(s1[0]) + if (s1[1] == 'no other bags.') { + bagMap[p] = [] + + } else { + const s2 = s1[1].substring(0, s1[1].length-1).split(', ') + const r = s2.map(s => { + const t = /([0-9]+) (.*)$/.exec(s)! + return {b: extractColor(t[2]), n:Number(t[1])} + }) + bagMap[p] = r + } + }) + + console.log(goDeeper('shiny gold')) + + function goDeeper(name: string): number { + if (bagMap[name].length == 0) return 0 + let c = 0 + for (const r of bagMap[name]) { + c += r.n + r.n * goDeeper(r.b) + } + return c + } + + interface Rule { + b : string + n: number + } +} + +function extractColor(j:string) { + const t = j.split(' ') + t.pop() + return t.join(' ') +} \ No newline at end of file diff --git a/2020/08/runner.ts b/2020/08/runner.ts new file mode 100644 index 0000000..b72c86b --- /dev/null +++ b/2020/08/runner.ts @@ -0,0 +1,29 @@ +import { readFile } from "fs/promises"; +import { taskOne, taskTwo } from "./task"; + +async function main() { + let lastArgument = process.argv.pop() as string; + let taskNumber = 1; + let isTest = false; + + if (lastArgument === "test") { + isTest = true; + taskNumber = parseInt(process.argv.pop() as string); + } else { + taskNumber = parseInt(lastArgument) + } + + const fileToLoad = isTest ? "test.in" : "solve.in"; + const fileContents = await readFile(fileToLoad, "utf-8") + + const lines = fileContents.split("\n"); + + if (taskNumber === 1) { + await taskOne(lines); + } + if (taskNumber === 2) { + await taskTwo(lines); + } +} + +void main(); \ No newline at end of file diff --git a/2020/08/task.ts b/2020/08/task.ts new file mode 100644 index 0000000..f826566 --- /dev/null +++ b/2020/08/task.ts @@ -0,0 +1,56 @@ +export async function taskOne(input: string[]): Promise { + let i = 0 + let acc = 0 + const V = new Set() + + while(!V.has(i)) { + V.add(i) + + const parts = input[i].split(' ') + const n = Number(parts[1]) + if (parts[0] == 'acc') { + acc += n + } else if (parts[0] == 'jmp') { + i += n - 1 + } else if (parts[0] == 'nop') {} else { + throw i + " | " + input[i] + } + + i++ + } + console.log(acc) +} + +export async function taskTwo(input: string[]): Promise { + for (let changeI = 0; changeI < input.length; changeI++) { + if (input[changeI].startsWith('acc')) continue + + let acc = 0 + let i = 0 + const V = new Set() + while(!V.has(i) && i < input.length) { + V.add(i) + + const parts = input[i].split(' ') + const n = Number(parts[1]) + if (i == changeI) { + if (parts[0] == 'nop') { + i += n - 1 + } else if (parts[0] == 'jmp') {} else { + throw i + } + } else if (parts[0] == 'acc') { + acc += n + } else if (parts[0] == 'jmp') { + i += n - 1 + } else if (parts[0] == 'nop') {} else { + throw i + " | " + input[i] + } + + i++ + } + if (i >= input.length) { + console.log(acc) + } + } +} diff --git a/2020/09/runner.ts b/2020/09/runner.ts new file mode 100644 index 0000000..b72c86b --- /dev/null +++ b/2020/09/runner.ts @@ -0,0 +1,29 @@ +import { readFile } from "fs/promises"; +import { taskOne, taskTwo } from "./task"; + +async function main() { + let lastArgument = process.argv.pop() as string; + let taskNumber = 1; + let isTest = false; + + if (lastArgument === "test") { + isTest = true; + taskNumber = parseInt(process.argv.pop() as string); + } else { + taskNumber = parseInt(lastArgument) + } + + const fileToLoad = isTest ? "test.in" : "solve.in"; + const fileContents = await readFile(fileToLoad, "utf-8") + + const lines = fileContents.split("\n"); + + if (taskNumber === 1) { + await taskOne(lines); + } + if (taskNumber === 2) { + await taskTwo(lines); + } +} + +void main(); \ No newline at end of file diff --git a/2020/09/task.ts b/2020/09/task.ts new file mode 100644 index 0000000..4db8061 --- /dev/null +++ b/2020/09/task.ts @@ -0,0 +1,47 @@ +export async function taskOne(input: string[]): Promise { + console.log(findInvalid(input.map(Number))) +} + +export async function taskTwo(input: string[]): Promise { + const nums = input.map(Number) + let goal = findInvalid(nums) + let minI = 0 + let maxI = 1 + let sum = nums[minI] + nums[maxI] + while(sum != goal) { + if (sum < goal) { + maxI++ + sum += nums[maxI] + } else { + sum -= nums[minI] + minI++ + } + } + let min = Infinity + let max = 0 + for (let i = minI; i <= maxI; i++) { + if (nums[i] < min) min = nums[i] + if (nums[i] > max) max = nums[i] + } + console.log(min + max) +} + +function findInvalid(nums: number[]) { + for (let i = 25; i < nums.length; i++) { + let found = false + for (let j = i-25; j < i; j++) { + if (found) break + for (let k = j+1; k < i; k++) { + if (nums[j] == nums[k]) continue + if (nums[k] + nums[j] == nums[i]) { + found = true + break + } + } + } + if (!found) { + return nums[i] + } + } + throw "all valid" +} \ No newline at end of file diff --git a/2020/10/runner.ts b/2020/10/runner.ts new file mode 100644 index 0000000..b72c86b --- /dev/null +++ b/2020/10/runner.ts @@ -0,0 +1,29 @@ +import { readFile } from "fs/promises"; +import { taskOne, taskTwo } from "./task"; + +async function main() { + let lastArgument = process.argv.pop() as string; + let taskNumber = 1; + let isTest = false; + + if (lastArgument === "test") { + isTest = true; + taskNumber = parseInt(process.argv.pop() as string); + } else { + taskNumber = parseInt(lastArgument) + } + + const fileToLoad = isTest ? "test.in" : "solve.in"; + const fileContents = await readFile(fileToLoad, "utf-8") + + const lines = fileContents.split("\n"); + + if (taskNumber === 1) { + await taskOne(lines); + } + if (taskNumber === 2) { + await taskTwo(lines); + } +} + +void main(); \ No newline at end of file diff --git a/2020/10/task.ts b/2020/10/task.ts new file mode 100644 index 0000000..e2aa264 --- /dev/null +++ b/2020/10/task.ts @@ -0,0 +1,41 @@ +export async function taskOne(input: string[]): Promise { + const nums = input.map(Number).sort((a,b) => a-b) + let d1 = 0 + let d3 = 0 + for (let i = 0; i < nums.length - 1; i++) { + let d = nums[i+1]-nums[i] + if (d == 1) d1++ + if (d == 3) d3++ + } + d3++ + if (nums[0] == 1) d1++ + if (nums[0] == 3) d3++ + console.log(d1*d3) +} + +export async function taskTwo(input: string[]): Promise { + const nums = input.map(Number) + nums.push(0) + nums.sort((a,b) => a-b) + + const prevCount = {} as Record + + prevCount[0] = 1 + + console.log(getPrevCount(nums.length - 1)) + + + function getPrevCount(i: number): number { + const n = nums[i] + if (prevCount[n] != undefined) { + return prevCount[n] + } + let s = 0 + for (let j = i-1; j >= 0; j--) { + if (n - nums[j] > 3) break + s += getPrevCount(j) + } + prevCount[n] = s + return s + } +} \ No newline at end of file diff --git a/2020/11/runner.ts b/2020/11/runner.ts new file mode 100644 index 0000000..b72c86b --- /dev/null +++ b/2020/11/runner.ts @@ -0,0 +1,29 @@ +import { readFile } from "fs/promises"; +import { taskOne, taskTwo } from "./task"; + +async function main() { + let lastArgument = process.argv.pop() as string; + let taskNumber = 1; + let isTest = false; + + if (lastArgument === "test") { + isTest = true; + taskNumber = parseInt(process.argv.pop() as string); + } else { + taskNumber = parseInt(lastArgument) + } + + const fileToLoad = isTest ? "test.in" : "solve.in"; + const fileContents = await readFile(fileToLoad, "utf-8") + + const lines = fileContents.split("\n"); + + if (taskNumber === 1) { + await taskOne(lines); + } + if (taskNumber === 2) { + await taskTwo(lines); + } +} + +void main(); \ No newline at end of file diff --git a/2020/11/task.ts b/2020/11/task.ts new file mode 100644 index 0000000..ada2787 --- /dev/null +++ b/2020/11/task.ts @@ -0,0 +1,62 @@ +export async function taskOne(input: string[]): Promise { + const seats = input.map(i => i.split('')) + let last = '' + + let v = JSON.stringify(seats) + while(v != last) { + last = v + let copy = JSON.parse(v) as string[][] + function get(x: number, y: number) { + if (x < 0 || y < 0 || x >= copy[0].length || y >= copy.length) return '.' + return copy[y][x] + } + + for (let y = 0; y < seats.length; y ++) { + for (let x = 0; x < seats[y].length; x++) { + let o = 0 + for (const d of [[-1,-1],[-1,0],[-1,1],[0,-1],[0,1],[1,-1],[1,0],[1,1]]) { + const s = get(x+d[0], y+d[1]) + if (s == '#') o++ + } + if (get(x,y) == 'L' && o == 0) seats[y][x] = '#' + if (get(x,y) == '#' && o >= 4) seats[y][x] = 'L' + } + } + v = JSON.stringify(seats) + } + console.log(seats.flat().map(i => (i == '#' ? 1:0) as number).reduce((a,b)=>a+b,0)) +} + +export async function taskTwo(input: string[]): Promise { + const seats = input.map(i => i.split('')) + let last = '' + + let v = JSON.stringify(seats) + while(v != last) { + last = v + let copy = JSON.parse(v) as string[][] + function get(x: number, y: number) { + if (x < 0 || y < 0 || x >= copy[0].length || y >= copy.length) return ':' + return copy[y][x] + } + + for (let y = 0; y < seats.length; y ++) { + for (let x = 0; x < seats[y].length; x++) { + let o = 0 + for (const d of [[-1,-1],[-1,0],[-1,1],[0,-1],[0,1],[1,-1],[1,0],[1,1]]) { + let c = 1 + let s = '' + do { + s = get(x+c*d[0], y+c*d[1]) + c++ + } while(s=='.') + if (s == '#') o++ + } + if (get(x,y) == 'L' && o == 0) seats[y][x] = '#' + if (get(x,y) == '#' && o >= 5) seats[y][x] = 'L' + } + } + v = JSON.stringify(seats) + } + console.log(seats.flat().map(i => (i == '#' ? 1:0) as number).reduce((a,b)=>a+b,0)) +} \ No newline at end of file diff --git a/2020/12/runner.ts b/2020/12/runner.ts new file mode 100644 index 0000000..b72c86b --- /dev/null +++ b/2020/12/runner.ts @@ -0,0 +1,29 @@ +import { readFile } from "fs/promises"; +import { taskOne, taskTwo } from "./task"; + +async function main() { + let lastArgument = process.argv.pop() as string; + let taskNumber = 1; + let isTest = false; + + if (lastArgument === "test") { + isTest = true; + taskNumber = parseInt(process.argv.pop() as string); + } else { + taskNumber = parseInt(lastArgument) + } + + const fileToLoad = isTest ? "test.in" : "solve.in"; + const fileContents = await readFile(fileToLoad, "utf-8") + + const lines = fileContents.split("\n"); + + if (taskNumber === 1) { + await taskOne(lines); + } + if (taskNumber === 2) { + await taskTwo(lines); + } +} + +void main(); \ No newline at end of file diff --git a/2020/12/task.ts b/2020/12/task.ts new file mode 100644 index 0000000..7cfde95 --- /dev/null +++ b/2020/12/task.ts @@ -0,0 +1,69 @@ +export async function taskOne(input: string[]): Promise { + let pos = [0,0] + let fac = [0,1] + + for (const i of input) { + const n = Number(i.substring(1)) + if (i.startsWith('F')) { + pos[0] += n * fac[0] + pos[1] += n * fac[1] + } else if(i.startsWith('N')) { + pos[0] += n + } else if(i.startsWith('S')) { + pos[0] -= n + } else if(i.startsWith('E')) { + pos[1] += n + } else if(i.startsWith('W')) { + pos[1] -= n + } else if (i == 'L180' || i == 'R180') { + fac[0] = -fac[0] + fac[1] = -fac[1] + } else if (i == 'R90' || i == 'L270') { + let t = fac[0] + fac[0] = -fac[1] + fac[1] = t + } else if (i == 'L90' || i == 'R270') { + let t = fac[0] + fac[0] = fac[1] + fac[1] = -t + } else { + throw i + } + } + console.log(Math.abs(pos[0])+Math.abs(pos[1])) +} + +export async function taskTwo(input: string[]): Promise { + let pos = [0,0] + let wayRel = [1,10] + + for (const i of input) { + const n = Number(i.substring(1)) + if (i.startsWith('F')) { + pos[0] += n * wayRel[0] + pos[1] += n * wayRel[1] + } else if(i.startsWith('N')) { + wayRel[0] += n + } else if(i.startsWith('S')) { + wayRel[0] -= n + } else if(i.startsWith('E')) { + wayRel[1] += n + } else if(i.startsWith('W')) { + wayRel[1] -= n + } else if (i == 'L180' || i == 'R180') { + wayRel[0] = -wayRel[0] + wayRel[1] = -wayRel[1] + } else if (i == 'R90' || i == 'L270') { + let t = wayRel[0] + wayRel[0] = -wayRel[1] + wayRel[1] = t + } else if (i == 'L90' || i == 'R270') { + let t = wayRel[0] + wayRel[0] = wayRel[1] + wayRel[1] = -t + } else { + throw i + } + } + console.log(Math.abs(pos[0])+Math.abs(pos[1])) +} \ No newline at end of file diff --git a/2020/13/runner.ts b/2020/13/runner.ts new file mode 100644 index 0000000..b72c86b --- /dev/null +++ b/2020/13/runner.ts @@ -0,0 +1,29 @@ +import { readFile } from "fs/promises"; +import { taskOne, taskTwo } from "./task"; + +async function main() { + let lastArgument = process.argv.pop() as string; + let taskNumber = 1; + let isTest = false; + + if (lastArgument === "test") { + isTest = true; + taskNumber = parseInt(process.argv.pop() as string); + } else { + taskNumber = parseInt(lastArgument) + } + + const fileToLoad = isTest ? "test.in" : "solve.in"; + const fileContents = await readFile(fileToLoad, "utf-8") + + const lines = fileContents.split("\n"); + + if (taskNumber === 1) { + await taskOne(lines); + } + if (taskNumber === 2) { + await taskTwo(lines); + } +} + +void main(); \ No newline at end of file diff --git a/2020/13/task.ts b/2020/13/task.ts new file mode 100644 index 0000000..1a008de --- /dev/null +++ b/2020/13/task.ts @@ -0,0 +1,46 @@ +export async function taskOne(input: string[]): Promise { + const time = Number(input[0]) + const busses = input[1].split(',').filter(i => i != 'x').map(Number) + let min = Infinity + let minId = 0 + for (const b of busses) { + let v = Math.ceil(time / b)* b + if (v < min) { + min = v + minId = b + } + } + console.log((min-time) * minId) +} + +export async function taskTwo(input: string[]): Promise { + let busses = input[1].split(',').map((i,idx) => [i,idx] as [string, number]).filter((i: [string, number]) => i[0] != 'x').map((i: [string, number]) => [Number(i[0]), i[1]]) + + let maxBusN = Math.max(...busses.map(b => b[0])) + let maxBus = busses.find(b => b[0] == maxBusN)! + busses = busses.filter(b => b[0] != maxBusN).map(b => [b[0], b[1] - maxBus[1]]) + + let validBus: number[][] = [] + let notNeededBus: number[][] = [] + for (const b of busses) { + if (Math.abs(b[0]) == Math.abs(b[1])) { + notNeededBus.push(b) + } else { + validBus.push(b) + } + } + + let increase = maxBus[0] * notNeededBus.map(b => b[0]).reduce((a,b) => a*b,1) + + let i = 0 + while(validBus.some(b => checkTiming(b,i))) { + i += increase + } + console.log(i - maxBus[1]) + + function checkTiming(b: number[], i: number) { + let goal = i + b[1] + if(goal < b[0]) goal += b[0] + return (i + b[1]) % b[0] != 0 + } +} \ No newline at end of file diff --git a/2020/14/runner.ts b/2020/14/runner.ts new file mode 100644 index 0000000..b72c86b --- /dev/null +++ b/2020/14/runner.ts @@ -0,0 +1,29 @@ +import { readFile } from "fs/promises"; +import { taskOne, taskTwo } from "./task"; + +async function main() { + let lastArgument = process.argv.pop() as string; + let taskNumber = 1; + let isTest = false; + + if (lastArgument === "test") { + isTest = true; + taskNumber = parseInt(process.argv.pop() as string); + } else { + taskNumber = parseInt(lastArgument) + } + + const fileToLoad = isTest ? "test.in" : "solve.in"; + const fileContents = await readFile(fileToLoad, "utf-8") + + const lines = fileContents.split("\n"); + + if (taskNumber === 1) { + await taskOne(lines); + } + if (taskNumber === 2) { + await taskTwo(lines); + } +} + +void main(); \ No newline at end of file diff --git a/2020/14/task.ts b/2020/14/task.ts new file mode 100644 index 0000000..9db0f6a --- /dev/null +++ b/2020/14/task.ts @@ -0,0 +1,76 @@ +export async function taskOne(input: string[]): Promise { + let memory: Record = {} + let mask = "" + for (const i of input) { + if (i.startsWith('mask')) { + mask = i.split(' = ')[1] + } else { + const r = /mem\[([0-9]+)\] = ([0-9]+)/.exec(i)! + memory[Number(r[1])] = applyMask(Number(r[2])) + } + } + + console.log(Object.keys(memory).map(k => memory[Number(k)]).reduce((a,b) => a+b, 0)) + + function applyMask(n: number) { + let r = dec2bin(n).split('') + for (let i = 0; i < mask.length; i++) { + if (mask[i] == "1") r[i] = "1" + if (mask[i] == "0") r[i] = "0" + } + return parseInt(r.join(''), 2) + } +} + +export async function taskTwo(input: string[]): Promise { + let memory: Map = new Map() + let mask = "" + for (const i of input) { + if (i.startsWith('mask')) { + mask = i.split(' = ')[1] + } else { + const r = /mem\[([0-9]+)\] = ([0-9]+)/.exec(i)! + const mems = applyMask(Number(r[1])) + const n = Number(r[2]) + mems.forEach(i => memory.set(i,n)) + } + } + + let c = 0 + for (const v of memory) { + c += v[1] + } + console.log(c) + + function applyMask(n: number) { + let r = dec2bin(n).split('') + for (let i = 0; i < mask.length; i++) { + if (mask[i] == "1") r[i] = "1" + if (mask[i] == "X") r[i] = "X" + } + let options = [r] + for (let i = 0; i < mask.length; i++) { + if (r[i] != 'X') continue + let newOptions = [] as string[][] + for (const o of options) { + const c1 = Array.from(o) + const c2 = Array.from(o) + c1[i] = "1" + c2[i] = "0" + newOptions.push(c1) + newOptions.push(c2) + } + options = newOptions + } + return options.map(i=> parseInt(i.join(''),2)) + } +} + + + + + +function dec2bin(dec: number) { + const l = (dec >>> 0).toString(2); + return "0".repeat(36-l.length) + l +} \ No newline at end of file diff --git a/2020/15/runner.ts b/2020/15/runner.ts new file mode 100644 index 0000000..b72c86b --- /dev/null +++ b/2020/15/runner.ts @@ -0,0 +1,29 @@ +import { readFile } from "fs/promises"; +import { taskOne, taskTwo } from "./task"; + +async function main() { + let lastArgument = process.argv.pop() as string; + let taskNumber = 1; + let isTest = false; + + if (lastArgument === "test") { + isTest = true; + taskNumber = parseInt(process.argv.pop() as string); + } else { + taskNumber = parseInt(lastArgument) + } + + const fileToLoad = isTest ? "test.in" : "solve.in"; + const fileContents = await readFile(fileToLoad, "utf-8") + + const lines = fileContents.split("\n"); + + if (taskNumber === 1) { + await taskOne(lines); + } + if (taskNumber === 2) { + await taskTwo(lines); + } +} + +void main(); \ No newline at end of file diff --git a/2020/15/task.ts b/2020/15/task.ts new file mode 100644 index 0000000..1f372df --- /dev/null +++ b/2020/15/task.ts @@ -0,0 +1,43 @@ +export async function taskOne(input: string[]): Promise { + const inNums = input[0].split(',').map(Number) + const lastSeen = new Map() + let lastNumber = inNums[0] + + for(let i = 1; i < inNums.length; i++) { + lastSeen.set(lastNumber, i) + lastNumber = inNums[i] + } + let i = inNums.length + while (i < 2020) { + let said = 0 + if (lastSeen.has(lastNumber)) { + said = i - lastSeen.get(lastNumber)! + } + lastSeen.set(lastNumber, i) + lastNumber = said + i++ + } + console.log(lastNumber) +} + +export async function taskTwo(input: string[]): Promise { + const inNums = input[0].split(',').map(Number) + const lastSeen = new Map() + let lastNumber = inNums[0] + + for(let i = 1; i < inNums.length; i++) { + lastSeen.set(lastNumber, i) + lastNumber = inNums[i] + } + let i = inNums.length + while (i < 30000000) { + let said = 0 + if (lastSeen.has(lastNumber)) { + said = i - lastSeen.get(lastNumber)! + } + lastSeen.set(lastNumber, i) + lastNumber = said + i++ + } + console.log(lastNumber) +} \ No newline at end of file diff --git a/2020/16/runner.ts b/2020/16/runner.ts new file mode 100644 index 0000000..b72c86b --- /dev/null +++ b/2020/16/runner.ts @@ -0,0 +1,29 @@ +import { readFile } from "fs/promises"; +import { taskOne, taskTwo } from "./task"; + +async function main() { + let lastArgument = process.argv.pop() as string; + let taskNumber = 1; + let isTest = false; + + if (lastArgument === "test") { + isTest = true; + taskNumber = parseInt(process.argv.pop() as string); + } else { + taskNumber = parseInt(lastArgument) + } + + const fileToLoad = isTest ? "test.in" : "solve.in"; + const fileContents = await readFile(fileToLoad, "utf-8") + + const lines = fileContents.split("\n"); + + if (taskNumber === 1) { + await taskOne(lines); + } + if (taskNumber === 2) { + await taskTwo(lines); + } +} + +void main(); \ No newline at end of file diff --git a/2020/16/task.ts b/2020/16/task.ts new file mode 100644 index 0000000..d055417 --- /dev/null +++ b/2020/16/task.ts @@ -0,0 +1,129 @@ +export async function taskOne(input: string[]): Promise { + const ranges: number[][] = [] + let i = 0; + while(input[i] != "") { + const r = /[^:]+: ([0-9]+)-([0-9]+) or ([0-9]+)-([0-9]+)/.exec(input[i])! + ranges.push([Number(r[1]), Number(r[2])]) + ranges.push([Number(r[3]), Number(r[4])]) + i++ + } + i++ + while(input[i] != "") i++ + i++ + i++ + let error = 0 + while(i < input.length) { + const nums = input[i].split(',').map(Number) + for (const n of nums) { + if (!ranges.some(r => n >= r[0] && n <= r[1])) { + error += n + } + } + i++ + } + console.log(error) +} + +export async function taskTwo(input: string[]): Promise { + const ranges: number[][] = [] + const classes: Class[] = [] + let i = 0; + while(input[i] != "") { + const r = /([^:]+): ([0-9]+)-([0-9]+) or ([0-9]+)-([0-9]+)/.exec(input[i])! + const nC = { + name: r[1], + ranges: [ + [Number(r[2]), Number(r[3])], + [Number(r[4]), Number(r[5])] + ] + } + ranges.push(nC.ranges[0]) + ranges.push(nC.ranges[1]) + classes.push(nC) + i++ + } + i++ + i++ + const myTicket = input[i].split(',').map(Number) + i++ + i++ + i++ + const validTickets: number[][] = [] + while(i < input.length) { + const nums = input[i].split(',').map(Number) + let valid = true + for (const n of nums) { + if (!ranges.some(r => n >= r[0] && n <= r[1])) { + valid = false + break + } + } + if (valid) { + validTickets.push(nums) + } + i++ + } + + const possibilities = Array.from({length: myTicket.length}, () => Array.from(classes)) + + while(possibilities.some(p => p.length > 1)) { + let changes = false + for (let i = 0; i < possibilities.length; i++) { + if (possibilities[i].length == 1) { + const cl = possibilities[i][0] + for (let j = 0; j < possibilities.length; j++) { + if (i == j) continue + possibilities[j] = possibilities[j].filter(c => c.name != cl.name) + } + continue + } + + let oldLen = possibilities[i].length + possibilities[i] = possibilities[i].filter(p => { + return !validTickets.some(t => { + const inside1 = p.ranges[0][0] <= t[i] && p.ranges[0][1] >= t[i] + const inside2 = p.ranges[1][0] <= t[i] && p.ranges[1][1] >= t[i] + return !(inside1 || inside2) + }) + }) + if(possibilities[i].length != oldLen) changes = true + + + if (possibilities[i].length == 1) { + changes = true + const cl = possibilities[i][0] + for (let j = 0; j < possibilities.length; j++) { + if (i == j) continue + possibilities[j] = possibilities[j].filter(c => c.name != cl.name) + } + } + } + if (changes) continue + + let occurances: Record = {} + classes.forEach(c => occurances[c.name] = []) + possibilities.forEach((p, idx) => p.forEach(c => occurances[c.name].push(idx))) + + for (const k of Object.keys(occurances)) { + if (occurances[k].length == 1) { + if (possibilities[occurances[k][0]].length != 1) { + possibilities[occurances[k][0]] = possibilities[occurances[k][0]].filter(c => c.name != k) + } + } + } + + } + + let r = 1 + for (let i = 0; i < myTicket.length; i++) { + if (possibilities[i][0].name.startsWith("departure")) { + r *= myTicket[i] + } + } + console.log(r) + + interface Class { + name: string + ranges: number[][] + } +} diff --git a/2020/17/runner.ts b/2020/17/runner.ts new file mode 100644 index 0000000..b72c86b --- /dev/null +++ b/2020/17/runner.ts @@ -0,0 +1,29 @@ +import { readFile } from "fs/promises"; +import { taskOne, taskTwo } from "./task"; + +async function main() { + let lastArgument = process.argv.pop() as string; + let taskNumber = 1; + let isTest = false; + + if (lastArgument === "test") { + isTest = true; + taskNumber = parseInt(process.argv.pop() as string); + } else { + taskNumber = parseInt(lastArgument) + } + + const fileToLoad = isTest ? "test.in" : "solve.in"; + const fileContents = await readFile(fileToLoad, "utf-8") + + const lines = fileContents.split("\n"); + + if (taskNumber === 1) { + await taskOne(lines); + } + if (taskNumber === 2) { + await taskTwo(lines); + } +} + +void main(); \ No newline at end of file diff --git a/2020/17/task.ts b/2020/17/task.ts new file mode 100644 index 0000000..6e6278f --- /dev/null +++ b/2020/17/task.ts @@ -0,0 +1,127 @@ +export async function taskOne(_input: string[]): Promise { + const input = _input.map(i => i.split('')) + let active = new Set() + for (let y = 0; y < input.length; y++) { + for (let x = 0; x < input[y].length; x++) { + if (input[y][x] == '#') { + active.add(getPoint(x,y,0)) + } + } + } + let minX = 0 + let maxX = input[0].length - 1 + let minY = 0 + let maxY = input.length - 1 + let minZ = 0 + let maxZ = 0 + + for (let i = 0; i < 6; i++) { + const newActive = new Set() + for (let x = minX-1; x <= maxX+1; x++) { + for (let y = minY-1; y <= maxY+1; y++) { + for (let z = minZ-1; z <= maxZ+1; z++) { + let actives = 0 + for (let xD = -1; xD <= 1; xD++) { + for (let yD = -1; yD <= 1; yD++) { + for (let zD = -1; zD <= 1; zD++) { + if (xD == 0 && yD == 0 && zD == 0) continue + if (active.has(getPoint(x+xD, y+yD, z+zD))) actives++ + } + } + } + const key = getPoint(x,y,z) + const isActive = active.has(key) + if (isActive && (actives == 2 || actives == 3)) { + newActive.add(key) + } + if (!isActive && actives == 3) { + newActive.add(key) + } + } + } + } + active = newActive + minX-- + maxX++ + minY-- + maxY++ + minZ-- + maxZ++ + } + + console.log(active.size) + + + + function getPoint(x: number, y: number, z:number) { + return `${x}|${y}|${z}` + } +} + +export async function taskTwo(_input: string[]): Promise { + const input = _input.map(i => i.split('')) + let active = new Set() + for (let y = 0; y < input.length; y++) { + for (let x = 0; x < input[y].length; x++) { + if (input[y][x] == '#') { + active.add(getPoint(x,y,0,0)) + } + } + } + let minX = 0 + let maxX = input[0].length - 1 + let minY = 0 + let maxY = input.length - 1 + let minZ = 0 + let maxZ = 0 + let minW = 0 + let maxW = 0 + + for (let i = 0; i < 6; i++) { + const newActive = new Set() + for (let x = minX-1; x <= maxX+1; x++) { + for (let y = minY-1; y <= maxY+1; y++) { + for (let z = minZ-1; z <= maxZ+1; z++) { + for (let w = minW-1; w <= maxW+1; w++) { + let actives = 0 + for (let xD = -1; xD <= 1; xD++) { + for (let yD = -1; yD <= 1; yD++) { + for (let zD = -1; zD <= 1; zD++) { + for (let wD = -1; wD <= 1; wD++) { + if (xD == 0 && yD == 0 && zD == 0 && wD == 0) continue + if (active.has(getPoint(x+xD, y+yD, z+zD, w+wD))) actives++ + } + } + } + } + const key = getPoint(x,y,z,w) + const isActive = active.has(key) + if (isActive && (actives == 2 || actives == 3)) { + newActive.add(key) + } + if (!isActive && actives == 3) { + newActive.add(key) + } + } + } + } + } + active = newActive + minX-- + maxX++ + minY-- + maxY++ + minZ-- + maxZ++ + minW-- + maxW++ + } + + console.log(active.size) + + + + function getPoint(x: number, y: number, z:number, w:number) { + return `${x}|${y}|${z}|${w}` + } +} \ No newline at end of file diff --git a/2020/18/runner.ts b/2020/18/runner.ts new file mode 100644 index 0000000..b72c86b --- /dev/null +++ b/2020/18/runner.ts @@ -0,0 +1,29 @@ +import { readFile } from "fs/promises"; +import { taskOne, taskTwo } from "./task"; + +async function main() { + let lastArgument = process.argv.pop() as string; + let taskNumber = 1; + let isTest = false; + + if (lastArgument === "test") { + isTest = true; + taskNumber = parseInt(process.argv.pop() as string); + } else { + taskNumber = parseInt(lastArgument) + } + + const fileToLoad = isTest ? "test.in" : "solve.in"; + const fileContents = await readFile(fileToLoad, "utf-8") + + const lines = fileContents.split("\n"); + + if (taskNumber === 1) { + await taskOne(lines); + } + if (taskNumber === 2) { + await taskTwo(lines); + } +} + +void main(); \ No newline at end of file diff --git a/2020/18/task.ts b/2020/18/task.ts new file mode 100644 index 0000000..3b597a8 --- /dev/null +++ b/2020/18/task.ts @@ -0,0 +1,153 @@ +export async function taskOne(input: string[]): Promise { + console.log(input.map(i => { + const p = tokenize(i) + return parse(p,0,p.length-1).val() + }).reduce((a,b)=>a+b,0)) + + function parse(line: string[], start: number, end: number): Exp { + if (line[end] == ')') { + let i = end + let closed = 0 + do { + if (line[i] == ')') closed++ + if (line[i] == '(') closed-- + i-- + } while(closed != 0) + const right = parse(line, i+2, end-1) + if (start >= i) return right + const left = parse(line, start, i - 1) + switch (line[i]) { + case '+': return new Sum(left, right) + case '*': return new Mul(left, right) + default: throw 'Unknown op' + } + } else if (line[end].match(/^[0-9]+$/)) { + const right = new Con(Number(line[end])) + if (start == end) return right + const left = parse(line, start, end-2) + switch (line[end-1]) { + case '+': return new Sum(left, right) + case '*': return new Mul(left, right) + default: throw 'Unknown op' + } + } else { + console.log(line, start, end, line[end]) + throw "line error" + } + } +} + +export async function taskTwo(input: string[]): Promise { + console.log(input.map(i => { + const p = tokenize(i) + return parseTerm(p,0,p.length-1).val() + }).reduce((a,b)=>a+b,0)) + + function parseSymbol(line: string[], start:number, end:number, left:Exp): Exp { + if (line[start] == '*') { + return new Mul(left, parseTerm(line, start+1, end)) + } else if (line[start] == '+') { + let right: Exp|undefined + let newStart = 0 + if (line[start+1] == '(') { + [right, newStart] = parseBrackets(line, start + 1) + } else { + right = new Con(Number(line[start+1])) + newStart = start+2 + } + if (newStart >= end) return new Sum(left, right) + return parseSymbol(line, newStart, end, new Sum(left, right)) + } else { + console.log(line, start, end, line[start]) + throw "unknown op" + } + } + + function parseBrackets(line: string[], start:number): [Exp, number] { + let count = 0 + let i = start + do { + if (line[i] == '(') count++ + if (line[i] == ')') count-- + i++ + } while (count != 0); + const nL = parseTerm(line, start+1, i-2) + return [nL, i] + } + + function parseTerm(line:string[], start: number, end: number): Exp { + if (line[start] == '(') { + const [left, nS] = parseBrackets(line, start) + if (nS >= end) return left + return parseSymbol(line, nS, end, left) + } else { + if (start == end) return new Con(Number(line[start])) + return parseSymbol(line, start+1, end, new Con(Number(line[start]))) + } + } +} + +function tokenize(line: string): string[] { + const trimmed = line.replaceAll(' ', '') + const parts: string[] = [] + let curPart = '' + let i = 0 + while(i < trimmed.length) { + if (trimmed[i].match(/[0-9]/)) { + curPart += trimmed[i] + } else { + if (curPart.length > 0) + parts.push(curPart) + parts.push(trimmed[i]) + curPart = '' + } + i++ + } + if (curPart.length > 0) + parts.push(curPart) + return parts +} + + + +abstract class Exp { + public abstract val():number; +} + +class Con extends Exp { + value: number + constructor(_val: number) {super();this.value = _val} + public val() {return this.value} +} + +class Sum extends Exp { + v1: Exp + v2: Exp + constructor(_v1: Exp, _v2: Exp) { + super() + this.v1 = _v1 + this.v2 = _v2 + } + + public val() { + const a1 = this.v1.val() + const a2 = this.v2.val() + return a1 + a2 + } +} + +class Mul extends Exp { + v1: Exp + v2: Exp + constructor(_v1: Exp, _v2: Exp) { + super() + this.v1 = _v1 + this.v2 = _v2 + } + + public val() { + const a1 = this.v1.val() + const a2 = this.v2.val() + return a1 * a2 + } +} \ No newline at end of file diff --git a/2020/19/runner.ts b/2020/19/runner.ts new file mode 100644 index 0000000..b72c86b --- /dev/null +++ b/2020/19/runner.ts @@ -0,0 +1,29 @@ +import { readFile } from "fs/promises"; +import { taskOne, taskTwo } from "./task"; + +async function main() { + let lastArgument = process.argv.pop() as string; + let taskNumber = 1; + let isTest = false; + + if (lastArgument === "test") { + isTest = true; + taskNumber = parseInt(process.argv.pop() as string); + } else { + taskNumber = parseInt(lastArgument) + } + + const fileToLoad = isTest ? "test.in" : "solve.in"; + const fileContents = await readFile(fileToLoad, "utf-8") + + const lines = fileContents.split("\n"); + + if (taskNumber === 1) { + await taskOne(lines); + } + if (taskNumber === 2) { + await taskTwo(lines); + } +} + +void main(); \ No newline at end of file diff --git a/2020/19/task.ts b/2020/19/task.ts new file mode 100644 index 0000000..ae6545a --- /dev/null +++ b/2020/19/task.ts @@ -0,0 +1,132 @@ +export async function taskOne(input: string[]): Promise { + const ruleString: Record = {} + let i = 0; + while(input[i] != "") { + const p = input[i].split(': ') + ruleString[Number(p[0])] = p[1] + i++ + } + i++ + + const ruleRegex: Record = {} + + const regexp = new RegExp("^" + get(0) + "$") + let count = 0 + while(i < input.length) { + if (input[i].match(regexp)) count++ + i++ + } + console.log(count) + + + function get(n: number) { + if (ruleRegex[n] != undefined) return ruleRegex[n] + const r = ruleString[n] + let re = "" + if (r.startsWith("\"")) { + re = r[1] + } else { + const options = r.split(' | ') + re = "(" + options.map(o => { + return `(${o.split(' ').map(Number).map(get).join('')})` + }).join('|') + ")" + } + ruleRegex[n] = re + return re + } +} + +export async function taskTwo(input: string[]): Promise { + const ruleString: Record = {} + let i = 0; + while(input[i] != "") { + const p = input[i].split(': ') + ruleString[Number(p[0])] = p[1] + i++ + } + i++ + + const ruleRegex: Record = {} + + let count = 0 + while(i < input.length) { + const startMatch = matchAll(input[i], get(42)) + const endMatch = matchAll(input[i], get(31)) + + const startChains = extractChains(startMatch).filter(c => c.start == 0) + const endChains = extractChains(endMatch).filter(c => c.end == input[i].length) + + let foundChain = false + for (let i = 0; i < startChains.length; i++) { + for (let j = 0; j < endChains.length; j++) { + if (startChains[i].end == endChains[j].start && startChains[i].parts > endChains[j].parts) { + foundChain = true + } + } + } + if(foundChain) count++ + i++ + } + console.log(count) + + function extractChains(parts: Match[]): Chain[] { + const chains = parts.map(p => {return {...p, parts: 1}}) + let hadChange = false + let lastChainEndLen = 0 + do { + hadChange = false + let len = chains.length + for (let i = lastChainEndLen; i < len; i++) { + for (let j = 0; j < parts.length; j++) { + if (chains[i].end == parts[j].start) { + chains.push({ + start: chains[i].start, + end: parts[j].end, + parts: chains[i].parts + 1 + }) + hadChange = true + } + } + } + lastChainEndLen = len + } while(hadChange); + return chains + } + + function matchAll(s: string, re: string) { + const reg = new RegExp("^" + re + "$") + const matches: Match[] = [] + for (let i = 0; i < s.length; i++) { + for (let j = i+1; j <= s.length; j++) { + if (s.substring(i,j).match(reg)) matches.push({start:i, end:j}) + } + } + return matches + } + + function get(n: number): string { + if (ruleRegex[n] != undefined) return ruleRegex[n] + const r = ruleString[n] + let re = "" + if (r.startsWith("\"")) { + re = r[1] + } else { + const options = r.split(' | ') + re = "(?:" + options.map(o => { + return `(?:${o.split(' ').map(Number).map(get).join('')})` + }).join('|') + ")" + } + ruleRegex[n] = re + return re + } + + interface Chain { + start: number // inc + end: number // exc + parts: number + } + interface Match { + start: number //inc + end: number // exc + } +} \ No newline at end of file diff --git a/2020/20/runner.ts b/2020/20/runner.ts new file mode 100644 index 0000000..b72c86b --- /dev/null +++ b/2020/20/runner.ts @@ -0,0 +1,29 @@ +import { readFile } from "fs/promises"; +import { taskOne, taskTwo } from "./task"; + +async function main() { + let lastArgument = process.argv.pop() as string; + let taskNumber = 1; + let isTest = false; + + if (lastArgument === "test") { + isTest = true; + taskNumber = parseInt(process.argv.pop() as string); + } else { + taskNumber = parseInt(lastArgument) + } + + const fileToLoad = isTest ? "test.in" : "solve.in"; + const fileContents = await readFile(fileToLoad, "utf-8") + + const lines = fileContents.split("\n"); + + if (taskNumber === 1) { + await taskOne(lines); + } + if (taskNumber === 2) { + await taskTwo(lines); + } +} + +void main(); \ No newline at end of file diff --git a/2020/20/task.ts b/2020/20/task.ts new file mode 100644 index 0000000..90de069 --- /dev/null +++ b/2020/20/task.ts @@ -0,0 +1,216 @@ +export async function taskOne(input: string[]): Promise { + const sideUses = new Map + const idSingleUses: Record = {} + const allIds: number[] = [] + let i = 0 + input.push('') + while(i < input.length) { + const _s = input[i].split(' ')[1] + const id = Number(_s.substring(0, _s.length-1)) + const lines: string[] = [] + i++ + while(input[i] != '') { + lines.push(input[i]) + i++ + } + const edges: string[] = [] + edges.push(lines[0]) + edges.push(lines[0].split('').reverse().join('')) + edges.push(lines[lines.length-1]) + edges.push(lines[lines.length-1].split('').reverse().join('')) + + edges.push(lines.map(i => i[0]).join('')) + edges.push(lines.map(i => i[0]).reverse().join('')) + edges.push(lines.map(i => i[i.length-1]).join('')) + edges.push(lines.map(i => i[i.length-1]).reverse().join('')) + + edges.forEach(e => { + if (!sideUses.has(e)) sideUses.set(e, []) + sideUses.get(e)!.push(id) + }) + idSingleUses[id] = 0 + allIds.push(id) + + i++ + } + + for (const [e, ids] of sideUses) { + if (ids.length == 1) { + idSingleUses[ids[0]]++ + } + } + + let r = 1 + for (const id of allIds) { + if (idSingleUses[id] == 4) r *= id + } + console.log(r) +} + +export async function taskTwo(input: string[]): Promise { + const sideUses = new Map + const idSingleUses: Record = {} + const allIds = new Set() + const tilesMap: Record = {} + let i = 0 + input.push('') + while(i < input.length) { + const _s = input[i].split(' ')[1] + const id = Number(_s.substring(0, _s.length-1)) + const lines: string[] = [] + i++ + while(input[i] != '') { + lines.push(input[i]) + i++ + } + const edges: string[] = [] + edges.push(lines[0]) + edges.push(lines[0].split('').reverse().join('')) + edges.push(lines[lines.length-1]) + edges.push(lines[lines.length-1].split('').reverse().join('')) + + edges.push(lines.map(i => i[0]).join('')) + edges.push(lines.map(i => i[0]).reverse().join('')) + edges.push(lines.map(i => i[i.length-1]).join('')) + edges.push(lines.map(i => i[i.length-1]).reverse().join('')) + + edges.forEach(e => { + if (!sideUses.has(e)) sideUses.set(e, []) + sideUses.get(e)!.push(id) + }) + idSingleUses[id] = 0 + allIds.add(id) + tilesMap[id] = lines + + i++ + } + + + const size = Math.sqrt(allIds.size) + const bigGrid: Tile[][] = Array.from({length: size}, () => Array.from({length: size}, () => {return {} as Tile})) + + for (const [e, ids] of sideUses) { + if (ids.length == 1) idSingleUses[ids[0]]++ + } + + for (const id of allIds) { + if (idSingleUses[id] == 4) { + // find orientation, so it is top left corner + const orientation = orientate(tilesMap[id]).filter(o => { + const bottomHasNeighbour = sideUses.get(o[o.length-1])!.length == 2 + const rightSide = o.map(i => i[i.length-1]).join('') + const rightHasNeightbour = sideUses.get(rightSide)!.length == 2 + return bottomHasNeighbour && rightHasNeightbour + })[0] + bigGrid[0][0] = { id: id, tile: orientation} + } + } + + // fill top row + for (let i = 1; i < size; i++) { + const tileToMatch = bigGrid[0][i-1].tile.map(i => i[i.length-1]).join('') + const neighbourID = sideUses.get(tileToMatch)!.filter(j => j != bigGrid[0][i-1].id)[0] + const wantedOrientation = orientate(tilesMap[neighbourID]).filter(o => o.map(i => i[0]).join('') == tileToMatch)[0] + bigGrid[0][i] = {id: neighbourID, tile: wantedOrientation} + } + + // fill each row top to bottom + for (let row = 1; row < size; row++) { + for (let col = 0; col < size; col++) { + const tileToMatch = bigGrid[row-1][col].tile + const bottomRow = tileToMatch[tileToMatch.length-1] + const neighbourID = sideUses.get(bottomRow)!.filter(j => j != bigGrid[row-1][col].id)[0] + const wantedOrientation = orientate(tilesMap[neighbourID]).filter(o => o[0] == bottomRow)[0] + bigGrid[row][col] = {id: neighbourID, tile: wantedOrientation} + } + } + + const tileSize = bigGrid[0][0].tile.length - 2 + const grid: string[] = Array.from({length: (tileSize)*size}, () => "") + // create real grid + for (let row = 0; row < size; row++) { + for (let col = 0; col < size; col++) { + const curCell = bigGrid[row][col].tile + for (let r = 0; r < tileSize; r++) { + grid[row * tileSize + r] += curCell[r+1].substring(1, tileSize+1) + } + } + } + + const monster = [" # ", "# ## ## ###", " # # # # # # "] + let monsterPos: number[][] = [] + for (let y = 0; y < monster.length; y++) { + for (let x = 0; x < monster[y].length; x++) { + if (monster[y][x] == '#') monsterPos.push([y,x]) + } + } + const allGrids = orientate(grid) + + // find which grid has monsters + const finalGrid = allGrids.filter(grid => { + for (let row = 0; row < grid.length- monster.length; row++) { + for (let col = 0; col < grid[row].length- monster[0].length; col++) { + let canBeMonster = true + for (const p of monsterPos) { + if (grid[row+p[0]][col+p[1]] != '#') canBeMonster = false + } + if (canBeMonster) return true + } + } + return false + })[0] + + // mark fields witch monsters + const hasMonster = Array.from({length: finalGrid.length}, () => Array.from({length: finalGrid.length}, () => false)) + for (let row = 0; row < finalGrid.length- monster.length; row++) { + for (let col = 0; col < finalGrid[row].length- monster[0].length; col++) { + let canBeMonster = true + for (const p of monsterPos) { + if (finalGrid[row+p[0]][col+p[1]] != '#') canBeMonster = false + } + if (canBeMonster) { + for (const p of monsterPos) { + hasMonster[row+p[0]][col+p[1]] = true + } + } + } + } + + // count non monster # + let count = 0 + for (let row = 0; row < finalGrid.length; row++) { + for (let col = 0; col < finalGrid[row].length; col++) { + if (!hasMonster[row][col] && finalGrid[row][col] == '#') count++ + } + } + console.log(count) + + function orientate(tile: string[]) { + const orientations: string[][] = [] + let lastRot = Array.from(tile) + orientations.push(lastRot) + for (let i = 0; i < 3; i++) { + lastRot = turn(lastRot) + orientations.push(lastRot) + } + + for (let i = 0; i < 4; i++) { + orientations.push(flip(orientations[i])) + } + + return orientations + + function flip(org: string[]) { + return org.map(l => l.split('').reverse().join('')) + } + + function turn(org: string[]) { + return org[0].split('').map((val, index) => org.map(row => row[index]).reverse()).map(i=>i.join('')) + } + } + + interface Tile { + id: number + tile: string[] + } +} \ No newline at end of file diff --git a/2020/21/runner.ts b/2020/21/runner.ts new file mode 100644 index 0000000..b72c86b --- /dev/null +++ b/2020/21/runner.ts @@ -0,0 +1,29 @@ +import { readFile } from "fs/promises"; +import { taskOne, taskTwo } from "./task"; + +async function main() { + let lastArgument = process.argv.pop() as string; + let taskNumber = 1; + let isTest = false; + + if (lastArgument === "test") { + isTest = true; + taskNumber = parseInt(process.argv.pop() as string); + } else { + taskNumber = parseInt(lastArgument) + } + + const fileToLoad = isTest ? "test.in" : "solve.in"; + const fileContents = await readFile(fileToLoad, "utf-8") + + const lines = fileContents.split("\n"); + + if (taskNumber === 1) { + await taskOne(lines); + } + if (taskNumber === 2) { + await taskTwo(lines); + } +} + +void main(); \ No newline at end of file diff --git a/2020/21/task.ts b/2020/21/task.ts new file mode 100644 index 0000000..8240e3d --- /dev/null +++ b/2020/21/task.ts @@ -0,0 +1,88 @@ +export async function taskOne(input: string[]): Promise { + const allIng = new Set() + const possibleMatches = new Map() + const finishedIng: string[] = [] + const recipeIng: string[][] = [] + input.forEach(i => { + const r = /([^(]+) \(contains ([^)]+)\)/.exec(i)! + const ing = r[1].split(' ').filter(j => !finishedIng.includes(j)) + ing.forEach(j => allIng.add(j)) + const all = r[2].split(', ') + recipeIng.push(ing) + all.forEach(a => { + if (!possibleMatches.has(a)) { + possibleMatches.set(a, ing) + checkSingle(a) + } else if(possibleMatches.get(a)!.length != 1) { + possibleMatches.set(a, union(possibleMatches.get(a)!, ing)) + checkSingle(a) + } + }) + }) + + finishedIng.forEach(i => allIng.delete(i)) + + let c = 0 + recipeIng.forEach(i => { + allIng.forEach(j => { + if (i.includes(j)) c++ + }) + }) + console.log(c) + + function union(a: string[], b: string[]) { + return a.filter(c => b.includes(c)) + } + function checkSingle(a: string) { + if (possibleMatches.get(a)!.length == 1) { + const ing = possibleMatches.get(a)![0] + finishedIng.push(ing) + for (const k of possibleMatches.keys()) { + if (k == a) continue + if (possibleMatches.get(k)!.length == 1) continue + possibleMatches.set(k, possibleMatches.get(k)!.filter(i => i != ing)) + checkSingle(k) + } + } + } +} + +export async function taskTwo(input: string[]): Promise { + const allIng = new Set() + const possibleMatches = new Map() + const finishedIng: string[] = [] + input.forEach(i => { + const r = /([^(]+) \(contains ([^)]+)\)/.exec(i)! + const ing = r[1].split(' ').filter(j => !finishedIng.includes(j)) + ing.forEach(j => allIng.add(j)) + const all = r[2].split(', ') + all.forEach(a => { + if (!possibleMatches.has(a)) { + possibleMatches.set(a, ing) + checkSingle(a) + } else if(possibleMatches.get(a)!.length != 1) { + possibleMatches.set(a, union(possibleMatches.get(a)!, ing)) + checkSingle(a) + } + }) + }) + + console.log(Array.from(possibleMatches).map(i => [i[0], i[1][0]]).sort((a,b) => a[0].localeCompare(b[0])).map(a => a[1]).join(',')) + + + function union(a: string[], b: string[]) { + return a.filter(c => b.includes(c)) + } + function checkSingle(a: string) { + if (possibleMatches.get(a)!.length == 1) { + const ing = possibleMatches.get(a)![0] + finishedIng.push(ing) + for (const k of possibleMatches.keys()) { + if (k == a) continue + if (possibleMatches.get(k)!.length == 1) continue + possibleMatches.set(k, possibleMatches.get(k)!.filter(i => i != ing)) + checkSingle(k) + } + } + } +} \ No newline at end of file diff --git a/2020/22/runner.ts b/2020/22/runner.ts new file mode 100644 index 0000000..b72c86b --- /dev/null +++ b/2020/22/runner.ts @@ -0,0 +1,29 @@ +import { readFile } from "fs/promises"; +import { taskOne, taskTwo } from "./task"; + +async function main() { + let lastArgument = process.argv.pop() as string; + let taskNumber = 1; + let isTest = false; + + if (lastArgument === "test") { + isTest = true; + taskNumber = parseInt(process.argv.pop() as string); + } else { + taskNumber = parseInt(lastArgument) + } + + const fileToLoad = isTest ? "test.in" : "solve.in"; + const fileContents = await readFile(fileToLoad, "utf-8") + + const lines = fileContents.split("\n"); + + if (taskNumber === 1) { + await taskOne(lines); + } + if (taskNumber === 2) { + await taskTwo(lines); + } +} + +void main(); \ No newline at end of file diff --git a/2020/22/task.ts b/2020/22/task.ts new file mode 100644 index 0000000..a645689 --- /dev/null +++ b/2020/22/task.ts @@ -0,0 +1,133 @@ +import { Queue } from "../../base/simpleStructure"; + +export async function taskOne(input: string[]): Promise { + const p1 = new Queue() + const p2 = new Queue() + + let i = 1 + while(input[i] != '') { + p1.push(Number(input[i])) + i++ + } + i+=2 + while(i < input.length) { + p2.push(Number(input[i])) + i++ + } + + while(!(p1.isEmpty() || p2.isEmpty())) { + const c1 = p1.pop() + const c2 = p2.pop() + if (c1 > c2) { + p1.push(c1) + p1.push(c2) + } else { + p2.push(c2) + p2.push(c1) + } + } + const winner = p1.isEmpty() ? p2.asArray() : p1.asArray() + let c = 0 + for (let i = 0; i < winner.length; i++) { + c += (winner.length - i) * winner[i] + } + console.log(c) +} + +export async function taskTwo(input: string[]): Promise { + const p1: number[] = [] + const p2: number[] = [] + + let i = 1 + while(input[i] != '') { + p1.push(Number(input[i])) + i++ + } + i+=2 + while(i < input.length) { + p2.push(Number(input[i])) + i++ + } + console.log(play(new ExtendedQueue(p1), new ExtendedQueue(p2)).s); + + function play(p1: ExtendedQueue, p2: ExtendedQueue): { w: 1|2, s: number } { + const seenHands = new Set + while(!(p1.isEmpty() || p2.isEmpty())) { + const s = stringifyHand(p1) + '|' + stringifyHand(p2) + if (seenHands.has(s)) { + return { w: 1, s: calcScore(p1.asArray()) } + } + seenHands.add(s) + + const c1 = p1.pop() + const c2 = p2.pop() + if (p1.length >= c1 && p2.length >= c2) { + const r = play(new ExtendedQueue(p1.getFirstN(c1)), new ExtendedQueue(p2.getFirstN(c2))) + if (r.w == 1) { + p1.push(c1) + p1.push(c2) + } else { + p2.push(c2) + p2.push(c1) + } + } else { + if (c1 > c2) { + p1.push(c1) + p1.push(c2) + } else { + p2.push(c2) + p2.push(c1) + } + } + } + return { + w: p1.isEmpty() ? 2:1, + s: calcScore(p1.isEmpty() ? p2.asArray() : p1.asArray()) + } + } + + function calcScore(w: number[]) { + let c = 0 + for (let i = 0; i < w.length; i++) { + c += (w.length - i) * w[i] + } + return c + } + + function stringifyHand(h: ExtendedQueue) { + return h.asArray().join(',') + } + + +} + +class ExtendedQueue extends Queue { + + public length = 0 + + constructor(vs: T[]) { + super() + for (const v of vs) this.push(v) + } + + + public getFirstN(n: number) { + const r: T[] = [] + let e = this._head + for (let i = 0; i < n; i++) { + r.push(e?.val!) + e = e?.next + } + return r + } + + public pop() { + this.length-- + return super.pop() + } + + public push(v: T) { + this.length++ + super.push(v) + } +} \ No newline at end of file diff --git a/2020/23/runner.ts b/2020/23/runner.ts new file mode 100644 index 0000000..b72c86b --- /dev/null +++ b/2020/23/runner.ts @@ -0,0 +1,29 @@ +import { readFile } from "fs/promises"; +import { taskOne, taskTwo } from "./task"; + +async function main() { + let lastArgument = process.argv.pop() as string; + let taskNumber = 1; + let isTest = false; + + if (lastArgument === "test") { + isTest = true; + taskNumber = parseInt(process.argv.pop() as string); + } else { + taskNumber = parseInt(lastArgument) + } + + const fileToLoad = isTest ? "test.in" : "solve.in"; + const fileContents = await readFile(fileToLoad, "utf-8") + + const lines = fileContents.split("\n"); + + if (taskNumber === 1) { + await taskOne(lines); + } + if (taskNumber === 2) { + await taskTwo(lines); + } +} + +void main(); \ No newline at end of file diff --git a/2020/23/task.ts b/2020/23/task.ts new file mode 100644 index 0000000..18d56cc --- /dev/null +++ b/2020/23/task.ts @@ -0,0 +1,114 @@ +export async function taskOne(input: string[]): Promise { + const start = input[0].split('').map(i => {return {val: Number(i)} as Node}) + const l = start.length + for (let i = 0; i < start.length; i++) { + start[i].next = start[(i+1)%l] + } + let cur = start[0] + //print(cur) + + for (let i = 0; i < 100; i++) { + //console.log('i:', i) + let removed = cur.next + const pickedUpValues = [removed.val, removed.next.val, removed.next.next.val] + //console.log('removed:',pickedUpValues) + cur.next = removed.next.next.next + + let goal = cur.val - 1 + if (goal < 1) goal = 9 + while(pickedUpValues.includes(goal)) { + goal-- + if (goal < 1) goal = 9 + } + //console.log('goal:', goal) + let goalCup = cur + while(goalCup.val != goal) goalCup = goalCup.next + + let oldNext = goalCup.next + goalCup.next = removed + removed.next.next.next = oldNext + + cur = cur.next + //print(cur) + } + + while(cur.val != 1) cur = cur.next + let r = '' + cur = cur.next + while(cur.val != 1) { + r += cur.val + cur = cur.next + } + + console.log(r) + + + function print(n: Node) { + let r = '' + let c = n + do { + r += c.val + " " + c = c.next + } while(c.val != n.val) + console.log(r) + } + + + interface Node { + val: number + next: Node + } +} + +export async function taskTwo(input: string[]): Promise { + const circle = new Map() + const start = input[0].split('').map(Number) + + for (let i = 0; i < start.length-1; i++) { + circle.set(start[i], start[i+1]) + } + circle.set(start[start.length-1], start.length + 1) + for (let i = start.length+1; i < 1000000; i++) { + circle.set(i, i+1) + } + circle.set(1000000, start[0]) + //circle.set(start[start.length-1], start[0]) + + let cur = start[0] + + for (let i = 0; i < 10000000; i++) { + let removed = get(cur) + let pickedUpValues = [removed, get(removed), get(get(removed))] + circle.set(cur, get(pickedUpValues[2])) + + let goal = cur - 1 + if (goal < 1) goal = 1000000 + while(pickedUpValues.includes(goal)) { + goal-- + if (goal < 1) goal = 1000000 + } + + let oldNext = get(goal) + circle.set(goal, removed) + circle.set(pickedUpValues[2], oldNext) + + cur = get(cur) + } + + console.log(get(1) * get(get(1))) + + function get(n: number) { + return circle.get(n)! + } + + function print() { + let c = cur + let r = '' + do { + r += c + c = get(c) + } while(c != cur) + console.log(r) + } + +} \ No newline at end of file diff --git a/2020/24/runner.ts b/2020/24/runner.ts new file mode 100644 index 0000000..b72c86b --- /dev/null +++ b/2020/24/runner.ts @@ -0,0 +1,29 @@ +import { readFile } from "fs/promises"; +import { taskOne, taskTwo } from "./task"; + +async function main() { + let lastArgument = process.argv.pop() as string; + let taskNumber = 1; + let isTest = false; + + if (lastArgument === "test") { + isTest = true; + taskNumber = parseInt(process.argv.pop() as string); + } else { + taskNumber = parseInt(lastArgument) + } + + const fileToLoad = isTest ? "test.in" : "solve.in"; + const fileContents = await readFile(fileToLoad, "utf-8") + + const lines = fileContents.split("\n"); + + if (taskNumber === 1) { + await taskOne(lines); + } + if (taskNumber === 2) { + await taskTwo(lines); + } +} + +void main(); \ No newline at end of file diff --git a/2020/24/task.ts b/2020/24/task.ts new file mode 100644 index 0000000..2556bc1 --- /dev/null +++ b/2020/24/task.ts @@ -0,0 +1,68 @@ +export async function taskOne(input: string[]): Promise { + console.log(buildFloor(input).size) +} + +export async function taskTwo(input: string[]): Promise { + let blackPieces = buildFloor(input) + + const neighbours = [ + [2,0],[-2,0], + [1,1],[1,-1],[-1,1],[-1,-1] + ] + for (let d = 0; d < 100; d++) { + let newBlackPieces = new Set() + for (const p of blackPieces) { + const [x,y] = p.split('|').map(Number) + + // this is a black piece, handle its neighbour check + let blackNeighbours = 0 + for (const [dX, dY] of neighbours) { + if (blackPieces.has(stringify(x+dX,y+dY))) blackNeighbours++ + } + if (blackNeighbours == 1 || blackNeighbours == 2) newBlackPieces.add(p) + + // since white tiles need to have a black neighbour next to them to change, we just need to check neighbours of black tiles + for (const [wX, wY] of neighbours) { + // skip black neighbours + const k = stringify(x+wX,y+wY) + if (blackPieces.has(k)) continue + blackNeighbours = 0 + for (const [dX, dY] of neighbours) { + if (blackPieces.has(stringify(x+wX+dX,y+wY+dY))) blackNeighbours++ + } + if (blackNeighbours == 2) newBlackPieces.add(k) + } + } + blackPieces = newBlackPieces + } + console.log(blackPieces.size) +} + +function buildFloor(input: string[]) { + const blackPieces = new Set + for (const i of input) { + let x = 0 + let y = 0 + let p = 0 + while(p < i.length) { + if (i[p] == "e") x += 2 + else if (i[p] == "w") x -= 2 + else { + if (i[p] == "n") y += 1 + else if (i[p] == "s") y -= 1 + p++ + if (i[p] == "e") x += 1 + else if (i[p] == "w") x -= 1 + } + p++ + } + const k = stringify(x,y) + if (blackPieces.has(k)) blackPieces.delete(k) + else blackPieces.add(k) + } + return blackPieces +} + +function stringify(x: number, y: number) { + return x + '|' + y +} \ No newline at end of file diff --git a/2020/25/runner.ts b/2020/25/runner.ts new file mode 100644 index 0000000..b72c86b --- /dev/null +++ b/2020/25/runner.ts @@ -0,0 +1,29 @@ +import { readFile } from "fs/promises"; +import { taskOne, taskTwo } from "./task"; + +async function main() { + let lastArgument = process.argv.pop() as string; + let taskNumber = 1; + let isTest = false; + + if (lastArgument === "test") { + isTest = true; + taskNumber = parseInt(process.argv.pop() as string); + } else { + taskNumber = parseInt(lastArgument) + } + + const fileToLoad = isTest ? "test.in" : "solve.in"; + const fileContents = await readFile(fileToLoad, "utf-8") + + const lines = fileContents.split("\n"); + + if (taskNumber === 1) { + await taskOne(lines); + } + if (taskNumber === 2) { + await taskTwo(lines); + } +} + +void main(); \ No newline at end of file diff --git a/2020/25/task.ts b/2020/25/task.ts new file mode 100644 index 0000000..175b14e --- /dev/null +++ b/2020/25/task.ts @@ -0,0 +1,21 @@ +export async function taskOne(input: string[]): Promise { + const cardKey = Number(input[0]) + const doorKey = Number(input[1]) + let cardLoop = 0 + let v = 1 + while(v != cardKey) { + v *= 7 + v %= 20201227 + cardLoop++ + } + v = 1 + for (let i = 0; i < cardLoop; i++) { + v *= doorKey + v %= 20201227 + } + console.log(v) +} + +export async function taskTwo(input: string[]): Promise { + console.log("Unimplemented"); +} \ No newline at end of file diff --git a/base/simpleStructure.ts b/base/simpleStructure.ts index d2fcf8e..f08edda 100644 --- a/base/simpleStructure.ts +++ b/base/simpleStructure.ts @@ -39,8 +39,8 @@ class Stack { } class Queue { - private _head: StructureNode|undefined - private _tail: StructureNode|undefined + protected _head: StructureNode|undefined + protected _tail: StructureNode|undefined public push(v: T) { if (!this._tail) {