From 3cb015b23073aea3b8613e6c46102b9492b437eb Mon Sep 17 00:00:00 2001 From: Pascal Syma Date: Wed, 27 Nov 2024 10:10:41 +0100 Subject: [PATCH] Initial Commit --- .gitattributes | 1 + .gitignore | 179 +++++++++++++++++++++++++++++++++++++++ .prettierignore | 4 + .prettierrc.json | 5 ++ 2023/01/2023-01.run.xml | 7 ++ 2023/01/index.test.ts | 22 +++++ 2023/01/index.ts | 55 ++++++++++++ 2023/01/run.ts | 12 +++ 2023/02/2023-02.run.xml | 7 ++ 2023/02/index.test.ts | 16 ++++ 2023/02/index.ts | 45 ++++++++++ 2023/02/run.ts | 12 +++ README.md | 15 ++++ bun.lockb | Bin 0 -> 3997 bytes package.json | 19 +++++ template/20xx-xx.run.xml | 7 ++ template/index.test.ts | 17 ++++ template/index.ts | 11 +++ template/input.txt | 0 template/run.ts | 12 +++ tsconfig.json | 27 ++++++ utils/array.ts | 46 ++++++++++ 22 files changed, 519 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 .prettierignore create mode 100644 .prettierrc.json create mode 100644 2023/01/2023-01.run.xml create mode 100644 2023/01/index.test.ts create mode 100644 2023/01/index.ts create mode 100644 2023/01/run.ts create mode 100644 2023/02/2023-02.run.xml create mode 100644 2023/02/index.test.ts create mode 100644 2023/02/index.ts create mode 100644 2023/02/run.ts create mode 100644 README.md create mode 100755 bun.lockb create mode 100644 package.json create mode 100644 template/20xx-xx.run.xml create mode 100644 template/index.test.ts create mode 100644 template/index.ts create mode 100644 template/input.txt create mode 100644 template/run.ts create mode 100644 tsconfig.json create mode 100644 utils/array.ts diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..81c05ed --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.lockb binary diff=lockb diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2930746 --- /dev/null +++ b/.gitignore @@ -0,0 +1,179 @@ +# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore + +# Logs + +logs +_.log +npm-debug.log_ +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Caches + +.cache + +# Diagnostic reports (https://nodejs.org/api/report.html) + +report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json + +# Runtime data + +pids +_.pid +_.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover + +lib-cov + +# Coverage directory used by tools like istanbul + +coverage +*.lcov + +# nyc test coverage + +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) + +.grunt + +# Bower dependency directory (https://bower.io/) + +bower_components + +# node-waf configuration + +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) + +build/Release + +# Dependency directories + +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) + +web_modules/ + +# TypeScript cache + +*.tsbuildinfo + +# Optional npm cache directory + +.npm + +# Optional eslint cache + +.eslintcache + +# Optional stylelint cache + +.stylelintcache + +# Microbundle cache + +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history + +.node_repl_history + +# Output of 'npm pack' + +*.tgz + +# Yarn Integrity file + +.yarn-integrity + +# dotenv environment variable files + +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) + +.parcel-cache + +# Next.js build output + +.next +out + +# Nuxt.js build / generate output + +.nuxt +dist + +# Gatsby files + +# Comment in the public line in if your project uses Gatsby and not Next.js + +# https://nextjs.org/blog/next-9-1#public-directory-support + +# public + +# vuepress build output + +.vuepress/dist + +# vuepress v2.x temp and cache directory + +.temp + +# Docusaurus cache and generated files + +.docusaurus + +# Serverless directories + +.serverless/ + +# FuseBox cache + +.fusebox/ + +# DynamoDB Local files + +.dynamodb/ + +# TernJS port file + +.tern-port + +# Stores VSCode versions used for testing VSCode extensions + +.vscode-test + +# yarn v2 + +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* + +# IntelliJ based IDEs +.idea + +# Finder (MacOS) folder config +.DS_Store + + +input.txt +!template/input.txt \ No newline at end of file diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..834d85f --- /dev/null +++ b/.prettierignore @@ -0,0 +1,4 @@ +.output +.nuxt +node_modules +prisma/migrations \ No newline at end of file diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000..a72d6ab --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,5 @@ +{ + "trailingComma": "none", + "singleQuote": true, + "plugins": ["prettier-plugin-organize-imports"] +} diff --git a/2023/01/2023-01.run.xml b/2023/01/2023-01.run.xml new file mode 100644 index 0000000..2027f8d --- /dev/null +++ b/2023/01/2023-01.run.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/2023/01/index.test.ts b/2023/01/index.test.ts new file mode 100644 index 0000000..1f4aed1 --- /dev/null +++ b/2023/01/index.test.ts @@ -0,0 +1,22 @@ +import { describe, expect, it } from 'bun:test'; +import { solveFirst, solveSecond } from './index.ts'; + +describe('2023-01', () => { + it('first', () => { + const testInput = `1abc2 +pqr3stu8vwx +a1b2c3d4e5f +treb7uchet`; + expect(solveFirst(testInput)).toBe(142); + }); + it('second', () => { + const testInput = `two1nine +eightwothree +abcone2threexyz +xtwone3four +4nineeightseven2 +zoneight234 +7pqrstsixteen`; + expect(solveSecond(testInput)).toBe(281); + }); +}); diff --git a/2023/01/index.ts b/2023/01/index.ts new file mode 100644 index 0000000..93e8bc3 --- /dev/null +++ b/2023/01/index.ts @@ -0,0 +1,55 @@ +import { sumArray } from '../../utils/array.ts'; + +export function solveFirst(input: string): number { + const regex = /^.*?(\d).*(\d).*?$|^.*(\d).*$/gm; + const match = input.matchAll(regex); + + if (!match) { + return 0; + } + + const numbers = Array.from(match, (m) => + Number(m[3] ? `${m[3]}${m[3]}` : `${m[1]}${m[2]}`) + ); + return numbers.reduce((sum, number) => sum + number, 0); +} + +export function solveSecond(input: string): number { + const lookup: Record = { + one: '1', + two: '2', + three: '3', + four: '4', + five: '5', + six: '6', + seven: '7', + eight: '8', + nine: '9', + '1': '1', + '2': '2', + '3': '3', + '4': '4', + '5': '5', + '6': '6', + '7': '7', + '8': '8', + '9': '9', + '0': '0' + } as const; + + const regex = + /^.*?(one|two|three|four|five|six|seven|eight|nine|\d).*(one|two|three|four|five|six|seven|eight|nine|\d).*?$|^.*(one|two|three|four|five|six|seven|eight|nine|\d).*$/gm; + const match = input.matchAll(regex); + + if (!match) { + return 0; + } + + const numbers = Array.from(match, (m) => + Number( + m[3] ? `${lookup[m[3]]}${lookup[m[3]]}` : `${lookup[m[1]]}${lookup[m[2]]}` + ) + ); + + return sumArray(numbers); +} diff --git a/2023/01/run.ts b/2023/01/run.ts new file mode 100644 index 0000000..88783cd --- /dev/null +++ b/2023/01/run.ts @@ -0,0 +1,12 @@ +import { join } from 'path'; +import { solveFirst, solveSecond } from './index.ts'; + +const input = await Bun.file(join(__dirname, 'input.txt')).text(); + +const firstAnswer = solveFirst(input); + +console.log(firstAnswer); + +const secondAnswer = solveSecond(input); + +console.log(secondAnswer); diff --git a/2023/02/2023-02.run.xml b/2023/02/2023-02.run.xml new file mode 100644 index 0000000..dafb22a --- /dev/null +++ b/2023/02/2023-02.run.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/2023/02/index.test.ts b/2023/02/index.test.ts new file mode 100644 index 0000000..4897621 --- /dev/null +++ b/2023/02/index.test.ts @@ -0,0 +1,16 @@ +import { describe, expect, it } from 'bun:test'; +import { solveFirst, solveSecond } from './index.ts'; + +describe('2023-02', () => { + const testInput = `Game 1: 3 blue, 4 red; 1 red, 2 green, 6 blue; 2 green +Game 2: 1 blue, 2 green; 3 green, 4 blue, 1 red; 1 green, 1 blue +Game 3: 8 green, 6 blue, 20 red; 5 blue, 4 red, 13 green; 5 green, 1 red +Game 4: 1 green, 3 red, 6 blue; 3 green, 6 red; 3 green, 15 blue, 14 red +Game 5: 6 red, 1 blue, 3 green; 2 blue, 1 red, 2 green`; + it('first', () => { + expect(solveFirst(testInput, { red: 12, green: 13, blue: 14 })).toBe(8); + }); + it('second', () => { + expect(solveSecond(testInput)).toBe(2286); + }); +}); diff --git a/2023/02/index.ts b/2023/02/index.ts new file mode 100644 index 0000000..2ad4332 --- /dev/null +++ b/2023/02/index.ts @@ -0,0 +1,45 @@ +import { groupBy, multBy, sumArray, sumBy } from '../../utils/array.ts'; + +export type AllowedCubes = Record; + +function parseInput(input: string) { + const matchLine = input.matchAll(/^Game (\d*): (.*)$/gm); + + return Array.from(matchLine, (m) => ({ + id: Number(m[1]), + rounds: m[2].split('; ').map((r) => + r.split(', ').map((g) => { + const [amount, color] = g.split(' '); + return { color, amount: Number(amount) }; + }) + ) + })); +} + +export function solveFirst(input: string, allowed: AllowedCubes): number { + const games = parseInput(input); + + const possible = games.filter( + (g) => + !g.rounds.some((r) => + r.some((s) => !(s.color in allowed) || s.amount > allowed[s.color]) + ) + ); + + return sumBy(possible, (a) => a.id); +} + +export function solveSecond(input: string): number { + const games = parseInput(input); + + const leastCubes = games.map((g) => + groupBy(g.rounds.flat(), (e) => e.color).map(({ key, elements }) => ({ + key, + amount: elements.toSorted((a, b) => b.amount - a.amount)[0].amount + })) + ); + + const powers = leastCubes.map((cubes) => multBy(cubes, (c) => c.amount)); + + return sumArray(powers); +} diff --git a/2023/02/run.ts b/2023/02/run.ts new file mode 100644 index 0000000..66de654 --- /dev/null +++ b/2023/02/run.ts @@ -0,0 +1,12 @@ +import { join } from 'path'; +import { solveFirst, solveSecond } from './index.ts'; + +const input = await Bun.file(join(__dirname, 'input.txt')).text(); + +const firstAnswer = solveFirst(input, { red: 12, green: 13, blue: 14 }); + +console.log(firstAnswer); + +const secondAnswer = solveSecond(input); + +console.log(secondAnswer); diff --git a/README.md b/README.md new file mode 100644 index 0000000..e725b33 --- /dev/null +++ b/README.md @@ -0,0 +1,15 @@ +# aoc + +To install dependencies: + +```bash +bun install +``` + +To run: + +```bash +bun run src/index.ts +``` + +This project was created using `bun init` in bun v1.1.36. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime. diff --git a/bun.lockb b/bun.lockb new file mode 100755 index 0000000000000000000000000000000000000000..867e20c7d8f267324027a94b17ad33d43313c95f GIT binary patch literal 3997 zcmd^C4Nz276n=|~A_St6mf*065Q+QthviQY)S5Ky$1rRETcK7 zm{209Opb_vC@PLji8-1AhUkQ5DuyzcBtl@3PE?AWySrDGrudm0ruw2BhOYM4YhCrlArnh^x?<(y|$q9=_} z7fv-_c^p~N(RI_ITz<5Dtamu=R`m9EYwK|^2xP255f*>ZI%A!}0|>cBp>MN;r+^@I zT882{nqp9+CDftlbu>@Us;e~W63|xA?*?YQ0y@N%m1b*ny$?gem5Vk!B$^||VaMH1 zZrkgko9X@`6@78^o2M6uGar5MW8CGe37ymSHx#7pjlW9giXyhTR?YSutMRYv2;F@O zX#bTUFCmdZQG#83&?Di*_``tn0sJV?h-0{d@jn5;AMoa&$3VgDL-F8oGr?#tz$4pH zu^9?z?8o>70Qs5VT}Ftn20Zvshaw2A!Fq)FZotn1Jc=ubj}hB1gN4imJeqq76r_hM zXunWFdxw0F#8iW6`jdfth2k64A(r(T*^1@G@br!ALleA60X`mK;5DV@w;jmk+(exp zCDBLLuC5Qh;HAvcx^Sb;ZCcj(q~;M*^{sDA({Ju=cPC8B4=mlh@qk}h@x;8zIk(@b zu>UGBp`y`*7snAYoByQkGIg#eVt)ILbVpzH!meqpzX#KWTV>tZlid>{C+%ucwmQ_; zUu~#ttP78Lf8FxHzQ&#nRjGbC)0^#!VrI0N@S;7z!r!_l{lWO3Z63e({oEGo+abq- zT3>5w6FX15<6&2wweDHat%Gq#y*78z4W%obxtqskKkcy}Pp_PsFIZUebl#?|>rHq~ z&nUkrZ&_Aog!)kPP80T@aeDjn9Y3rfd#uKqC6kC?H^du?jR%P@C zolV%I{;%yKqVs{7QH%Y{ z#)Q}23x04voquIoLv2U4Yer#!Yonu|jbGEP#FWITI}&H0hHf$E7;ErAm*k zTE9zyt&dZ{A|fp@rq;t=0S zh45|*-vqqZSPz%$Wse)dGGDf7|F8MVjOor7Ms4ZOG76Gbvz%O|B5|%oE@3DtKp+(h zSUR23#Lg7R1acJ}r`E)xTY@0^o*4waqw~;iq_Z$|6PEtT9?}3n{R1Aw1Bz#SFCh*@ zf$kn3BZqRBTsSX5e25oWhT2daeY4Pa0DWVSM)MRHc^lDWAeR0sq+Y9%ePF#_&+U~A zTrWU$IDfO{MS7BAQf#;}Q4h}OEX-7Lj$*m~bBc363tprLDMJ{P1qc9xvqR{SkrLFC zl1vFXRzbXeqPzHpgIl&8FH&mg(OWsdf`Hjl(ifWX_W;jh%R@atM&K+JXPIU^36Obs z69mpzalUEBTQ3!p5-I6}Gg_RHLXQvWNlL_jgPDPh0>N1?&RPNENlLv)86hwx5K%@w zFw|HoF@<8tw^BKZQOi|}Ifhop1qdYlTi`Qr3kc*JBxnDyJHYJ7u|q!!sBPSx{r=rk zld3tEr5NB`^^G7iEOtTfJs1m9>o)p$UgD+N^yL`sFgN}gK#ankOa5ug2`)`bu?mLP za&z>rBKRA@{uXLg$#Jw=sA1ydYB(Z7I#H`(I9ADVT6UI5#87cG%Q0!BTALWpk}ym( z6jUS}a)?kLDI^z{j@FI|Nk#l{<~8Nl$0FvzejCL0epdiXe?{m?dXrMbGYGcdd4NSf zbSMrbGX3mO)3Xf%M+k%a4QTzlp2Nc%aTw{)`6hXIXg75oS%#uJ&LkMRHC<4?Cm7JUE! literal 0 HcmV?d00001 diff --git a/package.json b/package.json new file mode 100644 index 0000000..10cbb7d --- /dev/null +++ b/package.json @@ -0,0 +1,19 @@ +{ + "name": "aoc", + "type": "module", + "author": "Pascal Syma (https://syma.dev/)", + "scripts": { + "format": "prettier --write .", + "check": "prettier --check .", + "test": "bun test", + "test:dev": "bun test --watch" + }, + "devDependencies": { + "@types/bun": "latest", + "prettier": "^3.4.0", + "prettier-plugin-organize-imports": "^4.1.0" + }, + "peerDependencies": { + "typescript": "^5.0.0" + } +} diff --git a/template/20xx-xx.run.xml b/template/20xx-xx.run.xml new file mode 100644 index 0000000..ceca224 --- /dev/null +++ b/template/20xx-xx.run.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/template/index.test.ts b/template/index.test.ts new file mode 100644 index 0000000..0ed9234 --- /dev/null +++ b/template/index.test.ts @@ -0,0 +1,17 @@ +import { describe, expect, it } from 'bun:test'; +import { solveFirst, solveSecond } from './index.ts'; + +describe('20xx-xx', () => { + it('first', () => { + // TODO: add first input + const testInput = ``; + // TODO: add first solution + expect(solveFirst(testInput)).toBe(0); + }); + it('second', () => { + // TODO: add second input + const testInput = ``; + // TODO: add second solution + expect(solveSecond(testInput)).toBe(0); + }); +}); diff --git a/template/index.ts b/template/index.ts new file mode 100644 index 0000000..b1ce7ff --- /dev/null +++ b/template/index.ts @@ -0,0 +1,11 @@ +export function solveFirst(input: string): number { + // TODO: add code + + return 0; +} + +export function solveSecond(input: string): number { + // TODO: add code + + return 0; +} diff --git a/template/input.txt b/template/input.txt new file mode 100644 index 0000000..e69de29 diff --git a/template/run.ts b/template/run.ts new file mode 100644 index 0000000..88783cd --- /dev/null +++ b/template/run.ts @@ -0,0 +1,12 @@ +import { join } from 'path'; +import { solveFirst, solveSecond } from './index.ts'; + +const input = await Bun.file(join(__dirname, 'input.txt')).text(); + +const firstAnswer = solveFirst(input); + +console.log(firstAnswer); + +const secondAnswer = solveSecond(input); + +console.log(secondAnswer); diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..238655f --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + // Enable latest features + "lib": ["ESNext", "DOM"], + "target": "ESNext", + "module": "ESNext", + "moduleDetection": "force", + "jsx": "react-jsx", + "allowJs": true, + + // Bundler mode + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "noEmit": true, + + // Best practices + "strict": true, + "skipLibCheck": true, + "noFallthroughCasesInSwitch": true, + + // Some stricter flags (disabled by default) + "noUnusedLocals": false, + "noUnusedParameters": false, + "noPropertyAccessFromIndexSignature": false + } +} diff --git a/utils/array.ts b/utils/array.ts new file mode 100644 index 0000000..6f8928f --- /dev/null +++ b/utils/array.ts @@ -0,0 +1,46 @@ +export function sumArray(arr: Array): number { + return sumBy(arr, (a) => a); +} + +export function sumBy( + arr: Array, + by: (array: T) => number | string +): number { + return arr.reduce((sum, element) => sum + Number(by(element)), 0); +} + +export function multArray(arr: Array): number { + return multBy(arr, (a) => a); +} + +export function multBy( + arr: Array, + by: (array: T) => number | string +): number { + if (arr.length <= 0) { + return 0; + } + return arr.reduce((sum, element) => sum * Number(by(element)), 1); +} + +export function groupBy( + arr: Array, + by: (element: E) => K +): { key: K; elements: Array }[] { + return arr.reduce( + (groups, element) => { + const key = by(element); + const index = groups.findIndex((e) => e.key === key); + + if (index < 0) { + groups.push({ key, elements: [element] }); + return groups; + } + const existing = groups[index]; + existing.elements.push(element); + + return groups; + }, + [] as { key: K; elements: Array }[] + ); +}