├── .editorconfig ├── .github └── workflows │ └── main.yml ├── .gitignore ├── README.md ├── angular.json ├── docs ├── editor.png ├── menu.png ├── plot1.png ├── plot2.png ├── plot3.png └── plot_animated.gif ├── karma.conf.js ├── package-lock.json ├── package.json ├── src ├── app │ ├── app-routing.module.ts │ ├── app.component.html │ ├── app.component.scss │ ├── app.component.ts │ ├── app.module.ts │ ├── helper │ │ ├── activate-route-guards │ │ │ ├── can-activate-day.ts │ │ │ └── can-activate-year.ts │ │ ├── components │ │ │ ├── animator │ │ │ │ ├── animator.component.html │ │ │ │ ├── animator.component.scss │ │ │ │ └── animator.component.ts │ │ │ ├── base-result.component.ts │ │ │ ├── day-selection │ │ │ │ ├── day-selection.component.html │ │ │ │ ├── day-selection.component.scss │ │ │ │ └── day-selection.component.ts │ │ │ ├── plotly-graph │ │ │ │ ├── plotly-graph.component.html │ │ │ │ ├── plotly-graph.component.scss │ │ │ │ └── plotly-graph.component.ts │ │ │ ├── solution │ │ │ │ ├── solution.component.html │ │ │ │ ├── solution.component.scss │ │ │ │ └── solution.component.ts │ │ │ └── year-selection │ │ │ │ ├── year-selection.component.html │ │ │ │ ├── year-selection.component.scss │ │ │ │ └── year-selection.component.ts │ │ ├── helper.module.ts │ │ ├── services │ │ │ ├── base-solution.service.ts │ │ │ ├── isolution.service.ts │ │ │ ├── scripts-loader.service.ts │ │ │ └── solutions-collector.service.ts │ │ └── util-functions │ │ │ ├── astar.ts │ │ │ ├── big-number.ts │ │ │ ├── chunk.ts │ │ │ ├── color-interpolate.ts │ │ │ ├── deque.ts │ │ │ ├── distances.ts │ │ │ ├── extensions.ts │ │ │ ├── gcd.ts │ │ │ ├── global-counter.ts │ │ │ ├── is-number.ts │ │ │ ├── lcm.ts │ │ │ ├── linked-list.ts │ │ │ ├── mod.ts │ │ │ ├── normalize.ts │ │ │ ├── ocr.ts │ │ │ ├── parse-first-line-into-numbers.ts │ │ │ ├── parse-into-2d-numbers-array.ts │ │ │ ├── parse-into-numbers.ts │ │ │ ├── point.ts │ │ │ ├── product.ts │ │ │ ├── queue.ts │ │ │ ├── split-into-lines.ts │ │ │ ├── stack.ts │ │ │ ├── sum.ts │ │ │ └── two-way-map.ts │ ├── solutions2021 │ │ ├── components │ │ │ ├── amphipods-room-visualizer │ │ │ │ ├── amphipods-room-visualizer.component.html │ │ │ │ ├── amphipods-room-visualizer.component.scss │ │ │ │ └── amphipods-room-visualizer.component.ts │ │ │ ├── arithmetic-logic-unit-visualizer │ │ │ │ ├── arithmetic-logic-unit-visualizer.component.html │ │ │ │ ├── arithmetic-logic-unit-visualizer.component.scss │ │ │ │ └── arithmetic-logic-unit-visualizer.component.ts │ │ │ ├── bingo-visualizer │ │ │ │ ├── bingo-visualizer.component.html │ │ │ │ ├── bingo-visualizer.component.scss │ │ │ │ └── bingo-visualizer.component.ts │ │ │ ├── bits-visualizer │ │ │ │ ├── bits-visualizer.component.html │ │ │ │ ├── bits-visualizer.component.scss │ │ │ │ └── bits-visualizer.component.ts │ │ │ ├── caves-visualizer │ │ │ │ ├── caves-visualizer.component.html │ │ │ │ ├── caves-visualizer.component.scss │ │ │ │ └── caves-visualizer.component.ts │ │ │ ├── ocean-trench-visualizer │ │ │ │ ├── ocean-trench-visualizer.component.html │ │ │ │ ├── ocean-trench-visualizer.component.scss │ │ │ │ └── ocean-trench-visualizer.component.ts │ │ │ ├── octopus-flashes-visualizer │ │ │ │ ├── octopus-flashes-visualizer.component.html │ │ │ │ ├── octopus-flashes-visualizer.component.scss │ │ │ │ └── octopus-flashes-visualizer.component.ts │ │ │ ├── sea-cucumbers-visualizer │ │ │ │ ├── sea-cucumbers-visualizer.component.html │ │ │ │ ├── sea-cucumbers-visualizer.component.scss │ │ │ │ └── sea-cucumbers-visualizer.component.ts │ │ │ ├── seven-segments-display-visualizer │ │ │ │ ├── seven-segments-display-visualizer.component.html │ │ │ │ ├── seven-segments-display-visualizer.component.scss │ │ │ │ └── seven-segments-display-visualizer.component.ts │ │ │ ├── snailfish-number-visualizer │ │ │ │ ├── snailfish-number-visualizer.component.html │ │ │ │ ├── snailfish-number-visualizer.component.scss │ │ │ │ └── snailfish-number-visualizer.component.ts │ │ │ └── syntax-error-lines-visualizer │ │ │ │ ├── syntax-error-lines-visualizer.component.html │ │ │ │ ├── syntax-error-lines-visualizer.component.scss │ │ │ │ └── syntax-error-lines-visualizer.component.ts │ │ ├── day1.service.ts │ │ ├── day10.service.ts │ │ ├── day11.service.ts │ │ ├── day12.service.ts │ │ ├── day13.service.ts │ │ ├── day14.service.ts │ │ ├── day15.service.ts │ │ ├── day16.service.ts │ │ ├── day17.service.ts │ │ ├── day18.service.ts │ │ ├── day19.service.ts │ │ ├── day2.service.ts │ │ ├── day20.service.ts │ │ ├── day21.service.ts │ │ ├── day22.service.ts │ │ ├── day23.service.ts │ │ ├── day24.service.ts │ │ ├── day25.service.ts │ │ ├── day3.service.ts │ │ ├── day4.service.ts │ │ ├── day5.service.ts │ │ ├── day6.service.ts │ │ ├── day7.service.ts │ │ ├── day8.service.ts │ │ ├── day9.service.ts │ │ └── solutions2021.module.ts │ ├── solutions2022 │ │ ├── components │ │ │ ├── blizzard-visualizer │ │ │ │ ├── blizzard-visualizer.component.html │ │ │ │ ├── blizzard-visualizer.component.scss │ │ │ │ └── blizzard-visualizer.component.ts │ │ │ ├── camp-sections-visualizer │ │ │ │ ├── camp-sections-visualizer.component.html │ │ │ │ ├── camp-sections-visualizer.component.scss │ │ │ │ └── camp-sections-visualizer.component.ts │ │ │ ├── cargo-visualizer │ │ │ │ ├── cargo-step-visualizer │ │ │ │ │ ├── cargo-step-visualizer.component.html │ │ │ │ │ ├── cargo-step-visualizer.component.scss │ │ │ │ │ └── cargo-step-visualizer.component.ts │ │ │ │ ├── cargo-visualizer.component.html │ │ │ │ ├── cargo-visualizer.component.scss │ │ │ │ └── cargo-visualizer.component.ts │ │ │ ├── datastream-buffer-visualizer │ │ │ │ ├── datastream-buffer-visualizer.component.html │ │ │ │ ├── datastream-buffer-visualizer.component.scss │ │ │ │ └── datastream-buffer-visualizer.component.ts │ │ │ ├── device-file-visualizer │ │ │ │ ├── device-file-visualizer.component.html │ │ │ │ ├── device-file-visualizer.component.scss │ │ │ │ └── device-file-visualizer.component.ts │ │ │ ├── elves-moves-visualizer │ │ │ │ ├── elves-moves-visualizer.component.html │ │ │ │ ├── elves-moves-visualizer.component.scss │ │ │ │ └── elves-moves-visualizer.component.ts │ │ │ ├── falling-rocks-visualizer │ │ │ │ ├── falling-rocks-visualizer.component.html │ │ │ │ ├── falling-rocks-visualizer.component.scss │ │ │ │ └── falling-rocks-visualizer.component.ts │ │ │ ├── falling-sand-visualizer │ │ │ │ ├── falling-sand-visualizer.component.html │ │ │ │ ├── falling-sand-visualizer.component.scss │ │ │ │ └── falling-sand-visualizer.component.ts │ │ │ ├── monkey-map-cube-visualizer │ │ │ │ ├── monkey-map-cube-visualizer.component.html │ │ │ │ ├── monkey-map-cube-visualizer.component.scss │ │ │ │ ├── monkey-map-cube-visualizer.component.ts │ │ │ │ └── orbit-controls.ts │ │ │ ├── monkey-math-equations-visualizer │ │ │ │ ├── monkey-math-equations-visualizer.component.html │ │ │ │ ├── monkey-math-equations-visualizer.component.scss │ │ │ │ └── monkey-math-equations-visualizer.component.ts │ │ │ ├── monkeys-inspections-visualizer │ │ │ │ ├── monkey-inspection-visualizer │ │ │ │ │ ├── monkey-inspection-visualizer.component.html │ │ │ │ │ ├── monkey-inspection-visualizer.component.scss │ │ │ │ │ └── monkey-inspection-visualizer.component.ts │ │ │ │ ├── monkeys-inspections-visualizer.component.html │ │ │ │ ├── monkeys-inspections-visualizer.component.scss │ │ │ │ └── monkeys-inspections-visualizer.component.ts │ │ │ ├── packet-numbers-visualizer │ │ │ │ ├── packet-numbers-visualizer.component.html │ │ │ │ ├── packet-numbers-visualizer.component.scss │ │ │ │ └── packet-numbers-visualizer.component.ts │ │ │ ├── pressure-valves-visualizer │ │ │ │ ├── pressure-valves-visualizer.component.html │ │ │ │ ├── pressure-valves-visualizer.component.scss │ │ │ │ └── pressure-valves-visualizer.component.ts │ │ │ ├── rope-bridge-visualizer │ │ │ │ ├── rope-bridge-visualizer.component.html │ │ │ │ ├── rope-bridge-visualizer.component.scss │ │ │ │ └── rope-bridge-visualizer.component.ts │ │ │ └── snafu-numbers-visualizer │ │ │ │ ├── snafu-numbers-visualizer.component.html │ │ │ │ ├── snafu-numbers-visualizer.component.scss │ │ │ │ └── snafu-numbers-visualizer.component.ts │ │ ├── day1.service.ts │ │ ├── day10.service.ts │ │ ├── day11.service.ts │ │ ├── day12.service.ts │ │ ├── day13.service.ts │ │ ├── day14.service.ts │ │ ├── day15.service.ts │ │ ├── day16.service.ts │ │ ├── day17.service.ts │ │ ├── day18.service.ts │ │ ├── day19.service.ts │ │ ├── day2.service.ts │ │ ├── day20.service.ts │ │ ├── day21.service.ts │ │ ├── day22.service.ts │ │ ├── day23.service.ts │ │ ├── day24.service.ts │ │ ├── day25.service.ts │ │ ├── day3.service.ts │ │ ├── day4.service.ts │ │ ├── day5.service.ts │ │ ├── day6.service.ts │ │ ├── day7.service.ts │ │ ├── day8.service.ts │ │ ├── day9.service.ts │ │ ├── helper │ │ │ ├── day16.ts │ │ │ └── day19.ts │ │ ├── solutions2022.module.ts │ │ └── web-workers │ │ │ ├── day16.worker.ts │ │ │ └── day19.worker.ts │ └── template │ │ └── solution-template.service.ts ├── assets │ ├── .gitkeep │ └── inputs │ │ ├── 2021 │ │ ├── 1.txt │ │ ├── 10.txt │ │ ├── 11.txt │ │ ├── 12.txt │ │ ├── 13.txt │ │ ├── 14.txt │ │ ├── 15.txt │ │ ├── 16.txt │ │ ├── 17.txt │ │ ├── 18.txt │ │ ├── 19.txt │ │ ├── 2.txt │ │ ├── 20.txt │ │ ├── 21.txt │ │ ├── 22.txt │ │ ├── 23.txt │ │ ├── 24.txt │ │ ├── 25.txt │ │ ├── 3.txt │ │ ├── 4.txt │ │ ├── 5.txt │ │ ├── 6.txt │ │ ├── 7.txt │ │ ├── 8.txt │ │ └── 9.txt │ │ └── 2022 │ │ ├── 1.txt │ │ ├── 10.txt │ │ ├── 11.txt │ │ ├── 12.txt │ │ ├── 13.txt │ │ ├── 14.txt │ │ ├── 15.txt │ │ ├── 16.txt │ │ ├── 17.txt │ │ ├── 18.txt │ │ ├── 19.txt │ │ ├── 2.txt │ │ ├── 20.txt │ │ ├── 21.txt │ │ ├── 22.txt │ │ ├── 23.txt │ │ ├── 24.txt │ │ ├── 25.txt │ │ ├── 3.txt │ │ ├── 4.txt │ │ ├── 5.txt │ │ ├── 6.txt │ │ ├── 7.txt │ │ ├── 8.txt │ │ └── 9.txt ├── environments │ ├── environment.prod.ts │ └── environment.ts ├── favicon.ico ├── index.html ├── main.ts ├── polyfills.ts ├── styles.scss └── test.ts ├── tsconfig.app.json ├── tsconfig.json ├── tsconfig.spec.json └── tsconfig.worker.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.ts] 12 | quote_type = single 13 | 14 | [*.md] 15 | max_line_length = off 16 | trim_trailing_whitespace = false 17 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Build and Deploy 2 | on: 3 | push: 4 | branches: 5 | - main 6 | pull_request: 7 | branches: 8 | - main 9 | jobs: 10 | build-and-deploy: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout 🛎️ 14 | uses: actions/checkout@v2.3.1 15 | 16 | - name: Download required Node version ⬇️ 17 | uses: actions/setup-node@v3 18 | with: 19 | node-version: '16' 20 | cache: 'npm' 21 | 22 | - name: Install and Build 🔧 # This example project is built using npm and outputs the result to the 'build' folder. Replace with the commands required to build your project, or remove this step entirely if your site is pre-built. 23 | run: | 24 | npm ci 25 | npm run build-gh 26 | 27 | - name: Deploy 🚀 28 | uses: JamesIves/github-pages-deploy-action@4.1.7 29 | with: 30 | branch: page # The branch the action should deploy to. 31 | folder: dist/AdventOfCode # The folder the action should deploy. 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | # Only exists if Bazel was run 8 | /bazel-out 9 | 10 | # dependencies 11 | /node_modules 12 | 13 | # profiling files 14 | chrome-profiler-events*.json 15 | 16 | # IDEs and editors 17 | /.idea 18 | .project 19 | .classpath 20 | .c9/ 21 | *.launch 22 | .settings/ 23 | *.sublime-workspace 24 | 25 | # IDE - VSCode 26 | .vscode/* 27 | !.vscode/settings.json 28 | !.vscode/tasks.json 29 | !.vscode/launch.json 30 | !.vscode/extensions.json 31 | .history/* 32 | 33 | # misc 34 | /.angular/cache 35 | /.sass-cache 36 | /connect.lock 37 | /coverage 38 | /libpeerconnection.log 39 | npm-debug.log 40 | yarn-error.log 41 | testem.log 42 | /typings 43 | 44 | # System Files 45 | .DS_Store 46 | Thumbs.db 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [AdventOfCode Angular](https://raczeq.github.io/AdventOfCodeAngular/) 2 | 3 | An interactive page with solutions written in the TypeScript language with Angular framework. 4 | 5 | https://raczeq.github.io/AdventOfCodeAngular/ 6 | 7 | ![Menu](/docs/menu.png "Menu") 8 | 9 | Page loads base input automatically, but allows you to paste your own into a provided form. Input link opens up your input page from Advent Of Code website. 10 | 11 | ![Editor](/docs/editor.png "Editor") 12 | 13 | After clicking run, solution and visualizations are generated on your browser. Clicking on results will automatically copy it to your clipboard. 14 | 15 | ![Plot animated](/docs/plot_animated.gif "Plot animated") 16 | 17 | ![Plot1](/docs/plot1.png "Plot1") 18 | 19 | ![Plot2](/docs/plot2.png "Plot2") 20 | 21 | ![Plot3](/docs/plot3.png "Plot3") -------------------------------------------------------------------------------- /angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "version": 1, 4 | "newProjectRoot": "projects", 5 | "projects": { 6 | "AdventOfCode": { 7 | "projectType": "application", 8 | "schematics": { 9 | "@schematics/angular:component": { 10 | "style": "scss", 11 | "skipTests": true 12 | }, 13 | "@schematics/angular:class": { 14 | "skipTests": true 15 | }, 16 | "@schematics/angular:directive": { 17 | "skipTests": true 18 | }, 19 | "@schematics/angular:guard": { 20 | "skipTests": true 21 | }, 22 | "@schematics/angular:interceptor": { 23 | "skipTests": true 24 | }, 25 | "@schematics/angular:pipe": { 26 | "skipTests": true 27 | }, 28 | "@schematics/angular:service": { 29 | "skipTests": true 30 | }, 31 | "@schematics/angular:application": { 32 | "strict": true 33 | } 34 | }, 35 | "root": "", 36 | "sourceRoot": "src", 37 | "prefix": "aoc", 38 | "architect": { 39 | "build": { 40 | "builder": "@angular-devkit/build-angular:browser", 41 | "options": { 42 | "outputPath": "dist/AdventOfCode", 43 | "index": "src/index.html", 44 | "main": "src/main.ts", 45 | "polyfills": "src/polyfills.ts", 46 | "tsConfig": "tsconfig.app.json", 47 | "inlineStyleLanguage": "scss", 48 | "assets": ["src/favicon.ico", "src/assets"], 49 | "styles": ["src/styles.scss"], 50 | "scripts": [], 51 | "webWorkerTsConfig": "tsconfig.worker.json" 52 | }, 53 | "configurations": { 54 | "production": { 55 | "budgets": [], 56 | "fileReplacements": [ 57 | { 58 | "replace": "src/environments/environment.ts", 59 | "with": "src/environments/environment.prod.ts" 60 | } 61 | ], 62 | "outputHashing": "all" 63 | }, 64 | "development": { 65 | "buildOptimizer": false, 66 | "optimization": false, 67 | "vendorChunk": true, 68 | "extractLicenses": false, 69 | "sourceMap": true, 70 | "namedChunks": true 71 | } 72 | }, 73 | "defaultConfiguration": "production" 74 | }, 75 | "serve": { 76 | "builder": "@angular-devkit/build-angular:dev-server", 77 | "configurations": { 78 | "production": { 79 | "browserTarget": "AdventOfCode:build:production" 80 | }, 81 | "development": { 82 | "browserTarget": "AdventOfCode:build:development" 83 | } 84 | }, 85 | "defaultConfiguration": "development" 86 | }, 87 | "extract-i18n": { 88 | "builder": "@angular-devkit/build-angular:extract-i18n", 89 | "options": { 90 | "browserTarget": "AdventOfCode:build" 91 | } 92 | }, 93 | "test": { 94 | "builder": "@angular-devkit/build-angular:karma", 95 | "options": { 96 | "main": "src/test.ts", 97 | "polyfills": "src/polyfills.ts", 98 | "tsConfig": "tsconfig.spec.json", 99 | "karmaConfig": "karma.conf.js", 100 | "inlineStyleLanguage": "scss", 101 | "assets": ["src/favicon.ico", "src/assets"], 102 | "styles": ["src/styles.scss"], 103 | "scripts": [], 104 | "webWorkerTsConfig": "tsconfig.worker.json" 105 | } 106 | } 107 | } 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /docs/editor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaczeQ/AdventOfCodeAngular/d0a64b2f29a94ea0818e8873aecfb1827f1cfb5a/docs/editor.png -------------------------------------------------------------------------------- /docs/menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaczeQ/AdventOfCodeAngular/d0a64b2f29a94ea0818e8873aecfb1827f1cfb5a/docs/menu.png -------------------------------------------------------------------------------- /docs/plot1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaczeQ/AdventOfCodeAngular/d0a64b2f29a94ea0818e8873aecfb1827f1cfb5a/docs/plot1.png -------------------------------------------------------------------------------- /docs/plot2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaczeQ/AdventOfCodeAngular/d0a64b2f29a94ea0818e8873aecfb1827f1cfb5a/docs/plot2.png -------------------------------------------------------------------------------- /docs/plot3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaczeQ/AdventOfCodeAngular/d0a64b2f29a94ea0818e8873aecfb1827f1cfb5a/docs/plot3.png -------------------------------------------------------------------------------- /docs/plot_animated.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaczeQ/AdventOfCodeAngular/d0a64b2f29a94ea0818e8873aecfb1827f1cfb5a/docs/plot_animated.gif -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client: { 16 | jasmine: { 17 | // you can add configuration options for Jasmine here 18 | // the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html 19 | // for example, you can disable the random execution with `random: false` 20 | // or set a specific seed with `seed: 4321` 21 | }, 22 | clearContext: false // leave Jasmine Spec Runner output visible in browser 23 | }, 24 | jasmineHtmlReporter: { 25 | suppressAll: true // removes the duplicated traces 26 | }, 27 | coverageReporter: { 28 | dir: require('path').join(__dirname, './coverage/AdventOfCode'), 29 | subdir: '.', 30 | reporters: [ 31 | { type: 'html' }, 32 | { type: 'text-summary' } 33 | ] 34 | }, 35 | reporters: ['progress', 'kjhtml'], 36 | port: 9876, 37 | colors: true, 38 | logLevel: config.LOG_INFO, 39 | autoWatch: true, 40 | browsers: ['Chrome'], 41 | singleRun: false, 42 | restartOnFileChange: true 43 | }); 44 | }; 45 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "advent-of-code", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "ng": "ng", 6 | "start": "ng serve", 7 | "build": "ng build", 8 | "build-gh": "ng build --base-href https://raczeq.github.io/AdventOfCodeAngular/", 9 | "watch": "ng build --watch --configuration development", 10 | "test": "ng test" 11 | }, 12 | "private": true, 13 | "dependencies": { 14 | "@angular/animations": "^15.0.1", 15 | "@angular/cdk": "^15.0.0", 16 | "@angular/common": "^15.0.1", 17 | "@angular/compiler": "^15.0.1", 18 | "@angular/core": "^15.0.1", 19 | "@angular/forms": "^15.0.1", 20 | "@angular/material": "^15.0.0", 21 | "@angular/platform-browser": "^15.0.1", 22 | "@angular/platform-browser-dynamic": "^15.0.1", 23 | "@angular/router": "^15.0.1", 24 | "angular-plotly.js": "^4.0.4", 25 | "plotly.js-dist-min": "^2.7.0", 26 | "rxjs": "~7.4.0", 27 | "tslib": "^2.3.0", 28 | "zone.js": "~0.11.4" 29 | }, 30 | "devDependencies": { 31 | "@angular-devkit/build-angular": "^15.0.1", 32 | "@angular/cli": "^15.0.1", 33 | "@angular/compiler-cli": "^15.0.1", 34 | "@types/jasmine": "~3.10.0", 35 | "@types/node": "^12.11.1", 36 | "@types/plotly.js-dist-min": "^2.3.0", 37 | "jasmine-core": "~3.10.0", 38 | "karma": "~6.3.0", 39 | "karma-chrome-launcher": "~3.1.0", 40 | "karma-coverage": "~2.0.3", 41 | "karma-jasmine": "~4.0.0", 42 | "karma-jasmine-html-reporter": "~1.7.0", 43 | "typescript": "~4.8.4" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/app/app-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { RouterModule, Routes } from '@angular/router'; 3 | import { CanActivateDay } from './helper/activate-route-guards/can-activate-day'; 4 | import { CanActivateYear } from './helper/activate-route-guards/can-activate-year'; 5 | import { DaySelectionComponent } from './helper/components/day-selection/day-selection.component'; 6 | import { SolutionComponent } from './helper/components/solution/solution.component'; 7 | import { YearSelectionComponent } from './helper/components/year-selection/year-selection.component'; 8 | 9 | const routes: Routes = [ 10 | { 11 | path: ':year/:day', 12 | canActivate: [CanActivateDay], 13 | component: SolutionComponent, 14 | }, 15 | { 16 | path: ':year', 17 | canActivate: [CanActivateYear], 18 | component: DaySelectionComponent, 19 | }, 20 | { 21 | path: '', 22 | component: YearSelectionComponent, 23 | pathMatch: 'full', 24 | }, 25 | { path: '**', redirectTo: '/' }, 26 | ]; 27 | 28 | @NgModule({ 29 | imports: [ 30 | RouterModule.forRoot(routes, { 31 | useHash: true, 32 | }), 33 | ], 34 | exports: [RouterModule], 35 | }) 36 | export class AppRoutingModule {} 37 | -------------------------------------------------------------------------------- /src/app/app.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 10 | Advent Of Code 11 | {{ selectedYear }} 18 | {{ actionName }} 24 | 30 | Previous day 31 | 32 | 37 | Previous day 38 | 39 | 45 | Next day 46 | 47 | 52 | Next day 53 | 54 |
55 | 56 | code 57 | Github repository 58 | 59 |
60 |
61 | 62 |
63 | -------------------------------------------------------------------------------- /src/app/app.component.scss: -------------------------------------------------------------------------------- 1 | @use "@angular/material" as mat; 2 | @use "sass:math"; 3 | 4 | @function random_range($min, $max) { 5 | $rand: random(); 6 | $random_range: $min + floor($rand * (($max - $min) + 1)); 7 | @return $random_range; 8 | } 9 | 10 | :host { 11 | z-index: 1; 12 | height: 100vh; 13 | width: 100vw; 14 | display: flex; 15 | flex-direction: column; 16 | background: linear-gradient(#000428, #0f0f23); 17 | 18 | .router-container { 19 | padding-top: 64px; 20 | flex: 1; 21 | overflow: auto; 22 | z-index: 1; 23 | } 24 | 25 | .navigator { 26 | cursor: pointer; 27 | @media screen and (max-width: 600px) { 28 | display: none; 29 | } 30 | } 31 | 32 | .disabled-navigator { 33 | color: rgba(255, 255, 255, 0.2); 34 | } 35 | 36 | .code-icon { 37 | vertical-align: middle; 38 | padding-bottom: 2px; 39 | } 40 | 41 | .snow-background { 42 | z-index: 0; 43 | position: absolute; 44 | height: 100vh; 45 | width: 100vw; 46 | top: 0; 47 | left: 0; 48 | overflow: hidden; 49 | filter: drop-shadow(0 0 5px white); 50 | 51 | .snow { 52 | $total: 200; 53 | position: absolute; 54 | width: 10px; 55 | height: 10px; 56 | background: white; 57 | border-radius: 50%; 58 | 59 | @for $i from 1 through $total { 60 | $random-x: random(1000000) * 0.0001vw; 61 | $random-offset: random_range(-100000, 100000) * 0.0001vw; 62 | $random-x-end: $random-x + $random-offset; 63 | $random-x-end-yoyo: $random-x + math.div($random-offset, 2); 64 | $random-yoyo-time: math.div(random_range(30000, 80000), 100000); 65 | $random-yoyo-y: $random-yoyo-time * 100vh; 66 | $random-scale: random(10000) * 0.0001; 67 | $fall-duration: random_range(10, 30) * 1s; 68 | $fall-delay: random(30) * -1s; 69 | 70 | &:nth-child(#{$i}) { 71 | opacity: random(10000) * 0.0001; 72 | transform: translate($random-x, -10px) scale($random-scale); 73 | animation: fall-#{$i} $fall-duration $fall-delay linear infinite; 74 | } 75 | 76 | @keyframes fall-#{$i} { 77 | #{percentage($random-yoyo-time)} { 78 | transform: translate($random-x-end, $random-yoyo-y) 79 | scale($random-scale); 80 | } 81 | 82 | to { 83 | transform: translate($random-x-end-yoyo, 100vh) scale($random-scale); 84 | } 85 | } 86 | } 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { ActivationEnd, Router } from '@angular/router'; 3 | import { 4 | AvailableSolutions, 5 | SolutionsCollectorService, 6 | } from './helper/services/solutions-collector.service'; 7 | 8 | @Component({ 9 | selector: 'aoc-root', 10 | templateUrl: './app.component.html', 11 | styleUrls: ['./app.component.scss'], 12 | }) 13 | export class AppComponent { 14 | title = 'AdventOfCode'; 15 | selectedYear: number = 0; 16 | selectedDay: number = 0; 17 | actionName: string = ''; 18 | availableSolutions: AvailableSolutions = {}; 19 | constructor( 20 | private router: Router, 21 | private solutionsCollectorService: SolutionsCollectorService 22 | ) { 23 | router.events.subscribe((event) => { 24 | if (event instanceof ActivationEnd) { 25 | this.selectedYear = Number(event.snapshot.params['year']); 26 | this.selectedDay = Number(event.snapshot.params['day']); 27 | if (this.selectedDay) { 28 | this.actionName = 'Go back'; 29 | } else if (this.selectedYear) { 30 | this.actionName = 'Select day'; 31 | } else { 32 | this.actionName = 'Select year'; 33 | } 34 | } 35 | }); 36 | 37 | solutionsCollectorService 38 | .getAvailableSolutionsObservable() 39 | .subscribe((solutions) => (this.availableSolutions = solutions)); 40 | } 41 | 42 | get canGoToPreviousDay(): boolean { 43 | return this.selectedDay - 1 in this.availableSolutions[this.selectedYear]; 44 | } 45 | 46 | get canGoToNextDay(): boolean { 47 | return this.selectedDay + 1 in this.availableSolutions[this.selectedYear]; 48 | } 49 | 50 | goToRepo(): void { 51 | window.open('https://github.com/RaczeQ/AdventOfCodeAngular', '_blank'); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { BrowserModule } from '@angular/platform-browser'; 3 | 4 | import { AppRoutingModule } from './app-routing.module'; 5 | import { AppComponent } from './app.component'; 6 | import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; 7 | import { RouterModule } from '@angular/router'; 8 | 9 | import { MatToolbarModule } from '@angular/material/toolbar'; 10 | import { MatIconModule } from '@angular/material/icon'; 11 | 12 | import { Solutions2021Module } from './solutions2021/solutions2021.module'; 13 | import { Solutions2022Module } from './solutions2022/solutions2022.module'; 14 | 15 | @NgModule({ 16 | declarations: [AppComponent], 17 | imports: [ 18 | BrowserModule, 19 | AppRoutingModule, 20 | BrowserAnimationsModule, 21 | RouterModule, 22 | MatToolbarModule, 23 | MatIconModule, 24 | Solutions2021Module, 25 | Solutions2022Module, 26 | ], 27 | providers: [], 28 | bootstrap: [AppComponent], 29 | }) 30 | export class AppModule {} 31 | -------------------------------------------------------------------------------- /src/app/helper/activate-route-guards/can-activate-day.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { 3 | ActivatedRouteSnapshot, 4 | CanActivate, 5 | Router, 6 | RouterStateSnapshot, 7 | UrlTree, 8 | } from '@angular/router'; 9 | import { Observable } from 'rxjs'; 10 | import { 11 | AvailableSolutions, 12 | SolutionsCollectorService, 13 | } from '../services/solutions-collector.service'; 14 | 15 | @Injectable() 16 | export class CanActivateDay implements CanActivate { 17 | availableSolutions: AvailableSolutions = {}; 18 | constructor( 19 | private solutionsCollectorService: SolutionsCollectorService, 20 | private router: Router 21 | ) { 22 | solutionsCollectorService 23 | .getAvailableSolutionsObservable() 24 | .subscribe((solutions) => (this.availableSolutions = solutions)); 25 | } 26 | 27 | canActivate( 28 | route: ActivatedRouteSnapshot, 29 | state: RouterStateSnapshot 30 | ): 31 | | Observable 32 | | Promise 33 | | boolean 34 | | UrlTree { 35 | var year = route.params['year']; 36 | var yearNumber = Number(year); 37 | var day = route.params['day']; 38 | var dayNumber = Number(day); 39 | var result = 40 | day && 41 | this.isInt(day) && 42 | yearNumber in this.availableSolutions && 43 | dayNumber in this.availableSolutions[yearNumber]; 44 | if (!result) { 45 | this.router.navigate(['/', yearNumber]); 46 | } 47 | return result; 48 | } 49 | 50 | isInt(value: any) { 51 | return ( 52 | !isNaN(value) && 53 | parseInt(Number(value).toString()) == value && 54 | !isNaN(parseInt(value, 10)) 55 | ); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/app/helper/activate-route-guards/can-activate-year.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { 3 | ActivatedRouteSnapshot, 4 | CanActivate, 5 | Router, 6 | RouterStateSnapshot, 7 | UrlTree, 8 | } from '@angular/router'; 9 | import { Observable } from 'rxjs'; 10 | import { SolutionsCollectorService } from '../services/solutions-collector.service'; 11 | 12 | @Injectable() 13 | export class CanActivateYear implements CanActivate { 14 | availableYears: number[] = []; 15 | constructor( 16 | private solutionsCollectorService: SolutionsCollectorService, 17 | private router: Router 18 | ) { 19 | solutionsCollectorService 20 | .getAvailableYearsObservable() 21 | .subscribe((years) => (this.availableYears = years)); 22 | } 23 | 24 | canActivate( 25 | route: ActivatedRouteSnapshot, 26 | state: RouterStateSnapshot 27 | ): 28 | | Observable 29 | | Promise 30 | | boolean 31 | | UrlTree { 32 | var year = route.params['year']; 33 | var yearNumber = Number(year); 34 | var result = 35 | year && this.isInt(year) && this.availableYears.includes(yearNumber); 36 | if (!result) { 37 | this.router.navigate(['/']); 38 | } 39 | return result; 40 | } 41 | 42 | isInt(value: any) { 43 | return ( 44 | !isNaN(value) && 45 | parseInt(Number(value).toString()) == value && 46 | !isNaN(parseInt(value, 10)) 47 | ); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/app/helper/components/animator/animator.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 12 | 21 | 30 | 39 | 48 | 57 |
58 |
59 | Animation speed: {{ interval }}ms 60 | 61 | 68 | 69 |
70 |
71 | Iterations: {{ currentIdx + 1 }} / {{ iterations }} ({{ 72 | (100 * currentIdx) / (iterations - 1) | number : "1.0-2" 73 | }}%) 74 |
75 |
76 | -------------------------------------------------------------------------------- /src/app/helper/components/animator/animator.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: block; 3 | width: 100%; 4 | } 5 | -------------------------------------------------------------------------------- /src/app/helper/components/animator/animator.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, EventEmitter, Input, Output } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'aoc-animator', 5 | templateUrl: './animator.component.html', 6 | styleUrls: ['./animator.component.scss'], 7 | }) 8 | export class AnimatorComponent { 9 | currentIdx: number = 0; 10 | visualizing: boolean = false; 11 | interval = 100; 12 | @Input() iterations: number = 0; 13 | @Output() currentIdxEvent = new EventEmitter(); 14 | 15 | resetVisualization() { 16 | this.currentIdx = 0; 17 | this.currentIdxEvent.emit(this.currentIdx); 18 | } 19 | 20 | goToEnd() { 21 | this.currentIdx = this.iterations - 1; 22 | this.currentIdxEvent.emit(this.currentIdx); 23 | } 24 | 25 | pauseVisualization() { 26 | this.visualizing = false; 27 | } 28 | 29 | startVisualization() { 30 | this.visualizing = true; 31 | if (this.currentIdx == this.iterations - 1) { 32 | this.resetVisualization(); 33 | } 34 | this.loop(); 35 | } 36 | 37 | nextStep() { 38 | this.currentIdx++; 39 | this.currentIdxEvent.emit(this.currentIdx); 40 | } 41 | 42 | prevStep() { 43 | this.currentIdx--; 44 | this.currentIdxEvent.emit(this.currentIdx); 45 | } 46 | 47 | private loop() { 48 | if (this.visualizing) { 49 | setTimeout(() => { 50 | this.nextStep(); 51 | if (this.currentIdx < this.iterations - 1) { 52 | this.loop(); 53 | } else { 54 | this.visualizing = false; 55 | } 56 | }, this.interval); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/app/helper/components/base-result.component.ts: -------------------------------------------------------------------------------- 1 | import { Directive, Input } from "@angular/core"; 2 | 3 | @Directive() 4 | export abstract class BaseResultComponent { 5 | @Input() data: any; 6 | } 7 | -------------------------------------------------------------------------------- /src/app/helper/components/day-selection/day-selection.component.html: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | Day 9 | {{ 10 | day[0] 11 | }} 12 | 13 | {{ day[1] }} 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/app/helper/components/day-selection/day-selection.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: flex; 3 | flex-flow: row wrap; 4 | mat-card { 5 | margin: 2em; 6 | cursor: pointer; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/app/helper/components/day-selection/day-selection.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { ActivatedRoute } from '@angular/router'; 3 | import { SolutionsCollectorService } from '../../services/solutions-collector.service'; 4 | 5 | @Component({ 6 | selector: 'aoc-day-selection', 7 | templateUrl: './day-selection.component.html', 8 | styleUrls: ['./day-selection.component.scss'], 9 | }) 10 | export class DaySelectionComponent { 11 | availableDays: [number, string][] = []; 12 | constructor( 13 | private solutionsCollectorService: SolutionsCollectorService, 14 | private route: ActivatedRoute 15 | ) { 16 | var year = route.snapshot.params["year"]; 17 | this.solutionsCollectorService 18 | .getAvailableDaysObservable(year) 19 | .subscribe((days) => (this.availableDays = days)); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/app/helper/components/plotly-graph/plotly-graph.component.html: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /src/app/helper/components/plotly-graph/plotly-graph.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaczeQ/AdventOfCodeAngular/d0a64b2f29a94ea0818e8873aecfb1827f1cfb5a/src/app/helper/components/plotly-graph/plotly-graph.component.scss -------------------------------------------------------------------------------- /src/app/helper/components/plotly-graph/plotly-graph.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { BaseResultComponent } from '../base-result.component'; 3 | 4 | @Component({ 5 | selector: 'aoc-plotly-graph', 6 | templateUrl: './plotly-graph.component.html', 7 | styleUrls: ['./plotly-graph.component.scss'], 8 | }) 9 | export class PlotlyGraphComponent 10 | extends BaseResultComponent 11 | implements OnInit 12 | { 13 | // graphData: Plotly.Data[] = []; 14 | // graphLayout: Partial = {}; 15 | // graphConfig: Partial = {}; 16 | 17 | graphData: any[] = []; 18 | graphLayout: any = {}; 19 | graphConfig: any = {}; 20 | 21 | ngOnInit(): void { 22 | this.graphData = this.data.graphData ?? []; 23 | this.graphLayout = this.data.graphLayout ?? {}; 24 | this.graphLayout.margin = { 25 | l: 64, 26 | r: 64, 27 | b: 32, 28 | t: 32, 29 | // pad: 0 30 | }; 31 | this.graphLayout.paper_bgcolor = 'rgba(0,0,0,0)'; 32 | this.graphLayout.plot_bgcolor = 'rgba(0,0,0,0)'; 33 | this.graphLayout.legend = { 34 | font: { 35 | color: '#ffffff', 36 | }, 37 | }; 38 | if (!this.graphLayout.xaxis) { 39 | this.graphLayout.xaxis = {}; 40 | } 41 | this.graphLayout.xaxis.showgrid = false; 42 | this.graphLayout.xaxis.zeroline = false; 43 | this.graphLayout.xaxis.showline = true; 44 | this.graphLayout.xaxis.color = '#ffffff'; 45 | this.graphLayout.xaxis.tickfont = { 46 | color: '#ffffff', 47 | }; 48 | if (!this.graphLayout.yaxis) { 49 | this.graphLayout.yaxis = {}; 50 | } 51 | this.graphLayout.yaxis.showgrid = false; 52 | this.graphLayout.yaxis.showline = true; 53 | this.graphLayout.yaxis.zeroline = false; 54 | this.graphLayout.yaxis.color = '#ffffff'; 55 | this.graphLayout.yaxis.tickfont = { 56 | color: '#ffffff', 57 | }; 58 | if (!this.graphLayout.yaxis2) { 59 | this.graphLayout.yaxis2 = {}; 60 | } 61 | this.graphLayout.yaxis2.showgrid = false; 62 | this.graphLayout.yaxis2.showline = true; 63 | this.graphLayout.yaxis2.zeroline = false; 64 | this.graphLayout.yaxis2.color = '#ffffff'; 65 | this.graphLayout.yaxis2.tickfont = { 66 | color: '#ffffff', 67 | }; 68 | if (!this.graphLayout.scene) { 69 | this.graphLayout.scene = {}; 70 | (['xaxis', 'yaxis', 'zaxis'] as ('xaxis' | 'yaxis' | 'zaxis')[]).forEach( 71 | (ax) => { 72 | this.graphLayout.scene![ax] = { 73 | showgrid: true, 74 | zeroline: true, 75 | showline: true, 76 | color: '#ffffff', 77 | tickfont: { 78 | color: '#ffffff', 79 | }, 80 | }; 81 | } 82 | ); 83 | } 84 | 85 | this.graphConfig = this.data.graphConfig ?? { 86 | displayModeBar: false, 87 | staticPlot: true, 88 | }; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/app/helper/components/solution/solution.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | margin: 2rem; 3 | display: block; 4 | } 5 | 6 | .flex-row { 7 | display: flex; 8 | margin-bottom: 2em; 9 | } 10 | 11 | .input-link { 12 | margin-right: 2em; 13 | display: flex; 14 | justify-content: center; 15 | 16 | mat-card-title { 17 | margin: auto; 18 | } 19 | 20 | .link { 21 | text-decoration: none; 22 | background-color: none; 23 | &:hover { 24 | text-decoration: none; 25 | } 26 | } 27 | 28 | @media screen and (max-width: 600px) { 29 | display: none; 30 | } 31 | } 32 | 33 | .day-name { 34 | cursor: pointer; 35 | } 36 | 37 | .run-button { 38 | display: flex; 39 | justify-content: center; 40 | button { 41 | margin: auto; 42 | } 43 | } 44 | 45 | .input-card { 46 | width: auto; 47 | margin-bottom: 2em; 48 | } 49 | 50 | .textarea-full-width { 51 | width: 100%; 52 | textarea { 53 | height: 20vh; 54 | } 55 | } 56 | 57 | ::ng-deep { 58 | .mdc-text-field--filled { 59 | background-color: transparent !important; 60 | } 61 | .mat-mdc-form-field-focus-overlay { 62 | background-color: transparent !important; 63 | } 64 | /* TODO(mdc-migration): The following rule targets internal classes of form-field that may no longer apply for the MDC version. */ 65 | .mat-mdc-text-field-wrapper { 66 | margin-bottom: -1.25em; 67 | } 68 | /* TODO(mdc-migration): The following rule targets internal classes of form-field that may no longer apply for the MDC version. */ 69 | .mdc-floating-label { 70 | color: rgba(#fad02c, 0.8) !important; 71 | } 72 | /* TODO(mdc-migration): The following rule targets internal classes of form-field that may no longer apply for the MDC version. */ 73 | .mat-focused .mdc-floating-label { 74 | color: #fad02c !important; 75 | } 76 | /* TODO(mdc-migration): The following rule targets internal classes of form-field that may no longer apply for the MDC version. */ 77 | .mdc-line-ripple { 78 | background-color: #fad02c !important; 79 | } 80 | 81 | .mat-mdc-form-field.mat-accent .mat-mdc-input-element { 82 | caret-color: #fad02c; 83 | } 84 | 85 | .mdc-text-field:not(.mdc-text-field--disabled) .mdc-text-field__input { 86 | color: currentcolor; 87 | } 88 | } 89 | 90 | .results-card { 91 | margin-right: 2em; 92 | cursor: pointer; 93 | } 94 | -------------------------------------------------------------------------------- /src/app/helper/components/year-selection/year-selection.component.html: -------------------------------------------------------------------------------- 1 | 7 | 8 | {{ year }} 9 | Days: {{ getDays(year) }} / 25 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/app/helper/components/year-selection/year-selection.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: flex; 3 | flex-flow: row wrap; 4 | mat-card { 5 | margin: 2em; 6 | cursor: pointer; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/app/helper/components/year-selection/year-selection.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { 3 | AvailableSolutions, 4 | SolutionsCollectorService, 5 | } from '../../services/solutions-collector.service'; 6 | 7 | @Component({ 8 | selector: 'aoc-year-selection', 9 | templateUrl: './year-selection.component.html', 10 | styleUrls: ['./year-selection.component.scss'], 11 | }) 12 | export class YearSelectionComponent implements OnInit { 13 | availableYears: number[] = []; 14 | availableSolutions: AvailableSolutions = {}; 15 | constructor(private solutionsCollectorService: SolutionsCollectorService) {} 16 | 17 | ngOnInit() { 18 | this.solutionsCollectorService 19 | .getAvailableYearsObservable() 20 | .subscribe((years) => (this.availableYears = years)); 21 | this.solutionsCollectorService 22 | .getAvailableSolutionsObservable() 23 | .subscribe((solutions) => (this.availableSolutions = solutions)); 24 | } 25 | 26 | getDays(year: number): number { 27 | return Object.keys(this.availableSolutions[year]).length; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/app/helper/helper.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { HttpClientModule } from '@angular/common/http'; 4 | import { ClipboardModule } from '@angular/cdk/clipboard'; 5 | import { MatButtonModule } from '@angular/material/button'; 6 | import { MatCardModule } from '@angular/material/card'; 7 | import { MatInputModule } from '@angular/material/input'; 8 | import { MatFormFieldModule } from '@angular/material/form-field'; 9 | import { MatSnackBarModule } from '@angular/material/snack-bar'; 10 | import { MatProgressBarModule } from '@angular/material/progress-bar'; 11 | 12 | import { CanActivateDay } from './activate-route-guards/can-activate-day'; 13 | import { DaySelectionComponent } from './components/day-selection/day-selection.component'; 14 | import { YearSelectionComponent } from './components/year-selection/year-selection.component'; 15 | import { SolutionComponent } from './components/solution/solution.component'; 16 | import { RouterModule } from '@angular/router'; 17 | import { SolutionsCollectorService } from './services/solutions-collector.service'; 18 | import { FormsModule, ReactiveFormsModule } from '@angular/forms'; 19 | import { CanActivateYear } from './activate-route-guards/can-activate-year'; 20 | import { PlotlyGraphComponent } from './components/plotly-graph/plotly-graph.component'; 21 | import { ScriptsLoaderService } from './services/scripts-loader.service'; 22 | 23 | import { PlotlyViaCDNModule } from 'angular-plotly.js'; 24 | import { AnimatorComponent } from './components/animator/animator.component'; 25 | import { MatSliderModule } from '@angular/material/slider'; 26 | 27 | PlotlyViaCDNModule.setPlotlyVersion('2.16.1'); 28 | PlotlyViaCDNModule.setPlotlyBundle(null); 29 | 30 | @NgModule({ 31 | declarations: [ 32 | SolutionComponent, 33 | DaySelectionComponent, 34 | YearSelectionComponent, 35 | PlotlyGraphComponent, 36 | AnimatorComponent, 37 | ], 38 | imports: [ 39 | CommonModule, 40 | RouterModule, 41 | FormsModule, 42 | ReactiveFormsModule, 43 | HttpClientModule, 44 | PlotlyViaCDNModule, 45 | ClipboardModule, 46 | MatButtonModule, 47 | MatCardModule, 48 | MatInputModule, 49 | MatFormFieldModule, 50 | MatSnackBarModule, 51 | MatProgressBarModule, 52 | MatSliderModule, 53 | ], 54 | providers: [ 55 | CanActivateYear, 56 | CanActivateDay, 57 | ScriptsLoaderService, 58 | SolutionsCollectorService, 59 | ], 60 | exports: [AnimatorComponent], 61 | }) 62 | export class HelperModule {} 63 | -------------------------------------------------------------------------------- /src/app/helper/services/base-solution.service.ts: -------------------------------------------------------------------------------- 1 | import { ISolutionService, PuzzleResult } from './isolution.service'; 2 | import { SolutionsCollectorService } from './solutions-collector.service'; 3 | 4 | export abstract class BaseSolutionService implements ISolutionService { 5 | protected constructor( 6 | protected solutionsCollectorService: SolutionsCollectorService, 7 | protected year: number, 8 | protected day: number, 9 | protected dayName: string, 10 | protected additionalInfo: string = '' 11 | ) { 12 | solutionsCollectorService.registerSolution(year, day, dayName, this, additionalInfo); 13 | } 14 | solvePart1( 15 | input: string 16 | ): 17 | | string 18 | | number 19 | | PuzzleResult 20 | | Promise 21 | | Promise 22 | | Promise { 23 | throw new Error('Method not implemented.'); 24 | } 25 | solvePart2( 26 | input: string 27 | ): 28 | | string 29 | | number 30 | | PuzzleResult 31 | | Promise 32 | | Promise 33 | | Promise { 34 | throw new Error('Method not implemented.'); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/app/helper/services/isolution.service.ts: -------------------------------------------------------------------------------- 1 | import { Type } from '@angular/core'; 2 | import { BaseResultComponent } from '../components/base-result.component'; 3 | 4 | export interface PuzzleResult { 5 | result: string | number; 6 | component: Type; 7 | componentData: any; 8 | } 9 | export interface ISolutionService { 10 | solvePart1( 11 | input: string 12 | ): 13 | | number 14 | | string 15 | | PuzzleResult 16 | | Promise 17 | | Promise 18 | | Promise; 19 | solvePart2( 20 | input: string 21 | ): 22 | | number 23 | | string 24 | | PuzzleResult 25 | | Promise 26 | | Promise 27 | | Promise; 28 | } 29 | -------------------------------------------------------------------------------- /src/app/helper/services/scripts-loader.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | 3 | @Injectable({ 4 | providedIn: 'root', 5 | }) 6 | export class ScriptsLoaderService { 7 | private loadedScripts: string[] = []; 8 | constructor() {} 9 | 10 | loadScript(name: string, srcUrl: string) { 11 | return new Promise((resolve, reject) => { 12 | var script = document.getElementById(name); 13 | if (this.loadedScripts.includes(name) && script) { 14 | resolve({ script: name, loaded: true, status: 'Loaded' }); 15 | } else { 16 | const script = document.createElement('script'); 17 | script.type = 'text/javascript'; 18 | script.id = name; 19 | script.src = srcUrl; 20 | script.onload = () => { 21 | this.loadedScripts.push(name); 22 | resolve({ script: name, loaded: true, status: 'Loaded' }); 23 | }; 24 | script.onerror = (error: any) => 25 | resolve({ script: name, loaded: false, status: 'Loaded' }); 26 | document.getElementsByTagName('head')[0].appendChild(script); 27 | } 28 | }); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/app/helper/services/solutions-collector.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { BehaviorSubject, map, Observable } from 'rxjs'; 3 | import { ISolutionService } from './isolution.service'; 4 | 5 | export interface SolutionObject { 6 | dayName: string; 7 | additionalInfo: string; 8 | service: ISolutionService; 9 | } 10 | 11 | export interface AvailableSolutions { 12 | [year: number]: { 13 | [day: number]: SolutionObject; 14 | }; 15 | } 16 | 17 | @Injectable({ 18 | providedIn: 'root', 19 | }) 20 | export class SolutionsCollectorService { 21 | static readonly startYear: number = 2015; 22 | private availableSolutions = new BehaviorSubject({}); 23 | 24 | getAvailableSolutionsObservable(): Observable { 25 | return this.availableSolutions.asObservable(); 26 | } 27 | 28 | getAvailableYearsObservable(): Observable { 29 | return this.availableSolutions 30 | .asObservable() 31 | .pipe(map((solutions) => Object.keys(solutions).map((k) => Number(k)))); 32 | } 33 | 34 | getAvailableDaysObservable(year: number): Observable<[number, string][]> { 35 | return this.availableSolutions 36 | .asObservable() 37 | .pipe( 38 | map((solutions) => 39 | year in solutions 40 | ? Object.keys(solutions[year]).map((k) => [ 41 | Number(k), 42 | solutions[year][Number(k)].dayName, 43 | ]) 44 | : [] 45 | ) 46 | ); 47 | } 48 | 49 | constructor() {} 50 | 51 | registerSolution( 52 | year: number, 53 | day: number, 54 | dayName: string, 55 | service: ISolutionService, 56 | additionalInfo: string = '' 57 | ) { 58 | if (day < 1 || day > 25) { 59 | throw new Error(`Cannot register solution for day ${day}!`); 60 | } 61 | var solutionsObj = this.availableSolutions.value; 62 | if (!(year in solutionsObj)) { 63 | solutionsObj[year] = {}; 64 | } 65 | if (day in solutionsObj) { 66 | throw new Error( 67 | `Solutions for Year ${year}, Day ${day} has already been registered!` 68 | ); 69 | } 70 | solutionsObj[year][day] = { dayName, additionalInfo, service }; 71 | this.availableSolutions.next(solutionsObj); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/app/helper/util-functions/chunk.ts: -------------------------------------------------------------------------------- 1 | export function chunk(input: any[], n: number): any[][] { 2 | return Array.from(Array(Math.ceil(input.length / n)), (_, i) => 3 | input.slice(i * n, i * n + n) 4 | ); 5 | } 6 | -------------------------------------------------------------------------------- /src/app/helper/util-functions/color-interpolate.ts: -------------------------------------------------------------------------------- 1 | export interface RgbColor { 2 | r: number; 3 | g: number; 4 | b: number; 5 | } 6 | 7 | export function getRgb(color: string): RgbColor { 8 | let [r, g, b] = color 9 | .replace('rgb(', '') 10 | .replace(')', '') 11 | .split(',') 12 | .map((str) => Number(str)); 13 | return { 14 | r, 15 | g, 16 | b, 17 | }; 18 | } 19 | 20 | export function colorInterpolate( 21 | colorA: string, 22 | colorB: string, 23 | intval: number 24 | ): string { 25 | const rgbA = getRgb(colorA), 26 | rgbB = getRgb(colorB); 27 | const interpolatedColor: RgbColor = { 28 | r: rgbA.r * (1 - intval) + rgbB.r * intval, 29 | g: rgbA.g * (1 - intval) + rgbB.g * intval, 30 | b: rgbA.b * (1 - intval) + rgbB.b * intval, 31 | }; 32 | return `rgb( ${interpolatedColor.r}, ${interpolatedColor.g}, ${interpolatedColor.b})`; 33 | } 34 | -------------------------------------------------------------------------------- /src/app/helper/util-functions/deque.ts: -------------------------------------------------------------------------------- 1 | //Modified https://gist.github.com/Youka/e28beeb31f585ac9b9532636cadbdb8d 2 | 3 | // Linked data structure part 4 | interface DequeNode { 5 | previous?: DequeNode; 6 | value: T; 7 | next?: DequeNode; 8 | } 9 | // Double-ended queue structure 10 | export class Deque { 11 | private first?: DequeNode = undefined; 12 | private last?: DequeNode = undefined; 13 | private size: number = 0; 14 | 15 | public get length(): number { 16 | return this.size; 17 | } 18 | public get array(): T[] { 19 | var result: T[] = []; 20 | var current = this.first; 21 | while (current !== undefined) { 22 | result.push(current.value); 23 | current = current.next; 24 | } 25 | return result; 26 | } 27 | public pushBack(value: T) { 28 | // Update last 29 | const last = this.last; 30 | this.last = { previous: last, value: value, next: undefined }; 31 | if (last !== undefined) last.next = this.last; 32 | // Update first 33 | if (this.first === undefined) this.first = this.last; 34 | // Update size 35 | this.size++; 36 | // Return new size 37 | return this.size; 38 | } 39 | public pushFront(value: T) { 40 | // Update first 41 | const first = this.first; 42 | this.first = { previous: undefined, value: value, next: first }; 43 | if (first !== undefined) first.previous = this.first; 44 | // Update last 45 | if (this.last === undefined) this.last = this.first; 46 | // Update size 47 | this.size++; 48 | // Return new size 49 | return this.size; 50 | } 51 | 52 | public popBack() { 53 | // Check possibility 54 | if (this.size === 0) return undefined; 55 | // Update last 56 | const entry = this.last; 57 | this.last = entry!.previous; 58 | if (this.last !== undefined) this.last.next = undefined; 59 | // Update first 60 | if (this.first === entry) this.first = undefined; 61 | // Update size 62 | this.size--; 63 | // Return value of removed entry 64 | return entry!.value; 65 | } 66 | public popFront() { 67 | // Check possibility 68 | if (this.size === 0) return undefined; 69 | // Update first 70 | const entry = this.first; 71 | this.first = entry!.next; 72 | if (this.first !== undefined) this.first.previous = undefined; 73 | // Update last 74 | if (this.last === entry) this.last = undefined; 75 | // Update size 76 | this.size--; 77 | // Return value of removed entry 78 | return entry!.value; 79 | } 80 | public rotate(n: number) { 81 | if (this.size > 0) { 82 | var rotateForward = Math.sign(n) > 0; 83 | for (let i = 0; i < Math.abs(n); i++) { 84 | if (rotateForward) { 85 | this.pushBack(this.popFront()!); 86 | } else { 87 | this.pushFront(this.popBack()!); 88 | } 89 | } 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/app/helper/util-functions/distances.ts: -------------------------------------------------------------------------------- 1 | import { Point2D, Point3D } from './point'; 2 | 3 | export function euclidean2D(a: Point2D, b: Point2D): number { 4 | return Math.sqrt(Math.pow(b.x - a.x, 2) + Math.pow(b.y - a.y, 2)); 5 | } 6 | 7 | export function euclidean3D(a: Point3D, b: Point3D): number { 8 | return Math.sqrt( 9 | Math.pow(b.x - a.x, 2) + Math.pow(b.y - a.y, 2) + Math.pow(b.z - a.z, 2) 10 | ); 11 | } 12 | 13 | export function manhattan2D(a: Point2D, b: Point2D): number { 14 | return Math.abs(b.x - a.x) + Math.abs(b.y - a.y); 15 | } 16 | 17 | export function manhattan3D(a: Point3D, b: Point3D): number { 18 | return Math.abs(b.x - a.x) + Math.abs(b.y - a.y) + Math.abs(b.z - a.z); 19 | } 20 | -------------------------------------------------------------------------------- /src/app/helper/util-functions/extensions.ts: -------------------------------------------------------------------------------- 1 | import { chunk } from './chunk'; 2 | import { multiplyNumbers } from './product'; 3 | import { sumNumbers } from './sum'; 4 | 5 | declare global { 6 | interface Array { 7 | sum(): number; 8 | product(): number; 9 | } 10 | } 11 | 12 | Array.prototype.sum = function (): number { 13 | return sumNumbers(this); 14 | }; 15 | 16 | Array.prototype.product = function (): number { 17 | return multiplyNumbers(this); 18 | }; 19 | 20 | declare global { 21 | interface Array { 22 | chunk(n: number): Array>; 23 | } 24 | } 25 | 26 | Array.prototype.chunk = function (n: number): Array> { 27 | return chunk(this, n); 28 | }; 29 | 30 | declare global { 31 | interface ArrayConstructor { 32 | range(start: number, end: number): number[]; 33 | } 34 | } 35 | 36 | Array.range = (start, end) => 37 | Array.from({ length: end - start }, (v, k) => k + start); 38 | 39 | declare global { 40 | interface Array { 41 | findLast( 42 | predicate: (value: T, index: number, obj: T[]) => unknown, 43 | thisArg?: any 44 | ): T | undefined; 45 | findLastIndex( 46 | predicate: (value: T, index: number, obj: T[]) => unknown, 47 | thisArg?: any 48 | ): number; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/app/helper/util-functions/gcd.ts: -------------------------------------------------------------------------------- 1 | export function gcd(a: number, b: number): number { 2 | while (b != 0) { 3 | var x = b; 4 | b = a % b; 5 | a = x; 6 | } 7 | return a; 8 | } 9 | -------------------------------------------------------------------------------- /src/app/helper/util-functions/global-counter.ts: -------------------------------------------------------------------------------- 1 | export interface GlobalCounter { 2 | value: number; 3 | higherValue: number; 4 | } 5 | -------------------------------------------------------------------------------- /src/app/helper/util-functions/is-number.ts: -------------------------------------------------------------------------------- 1 | export function isNumber(value: string | number): boolean { 2 | return value != null && value !== '' && !isNaN(Number(value.toString())); 3 | } 4 | -------------------------------------------------------------------------------- /src/app/helper/util-functions/lcm.ts: -------------------------------------------------------------------------------- 1 | export function lcm(a: number, b: number): number { 2 | var greater = a > b ? a : b; 3 | 4 | while (true) { 5 | if (greater % a == 0 && greater % b == 0) { 6 | return greater; 7 | } 8 | greater += 1; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/app/helper/util-functions/linked-list.ts: -------------------------------------------------------------------------------- 1 | export interface LinkedListNode { 2 | previous?: LinkedListNode; 3 | value: T; 4 | next?: LinkedListNode; 5 | } 6 | 7 | export function insertNode(value: T, last?: LinkedListNode) { 8 | let p: LinkedListNode = { value }; 9 | 10 | if (last === undefined) { 11 | p.previous = p; 12 | p.next = p; 13 | } else { 14 | p.next = last.next; 15 | p.previous = last; 16 | last.next!.previous = p; 17 | last.next = p; 18 | } 19 | return p; 20 | } 21 | 22 | export function removeNode(p: LinkedListNode) { 23 | p.next!.previous = p.previous; 24 | p.previous!.next = p.next; 25 | } 26 | 27 | export function findNode( 28 | p: LinkedListNode, 29 | value: T 30 | ): LinkedListNode | undefined { 31 | var currentNode = p; 32 | do { 33 | if (currentNode.value === value) { 34 | return currentNode; 35 | } 36 | currentNode = currentNode.next!; 37 | } while (currentNode !== p); 38 | return; 39 | } 40 | 41 | export function swapWithNext(p: LinkedListNode) { 42 | var previous = p.previous!; 43 | var neighbour = p.next!; 44 | var next = neighbour.next!; 45 | 46 | previous.next = neighbour; 47 | 48 | neighbour.previous = previous; 49 | neighbour.next = p; 50 | 51 | p.previous = neighbour; 52 | p.next = next; 53 | 54 | next.previous = p; 55 | 56 | return p; 57 | } 58 | 59 | export function swapWithPrevious(p: LinkedListNode) { 60 | var next = p.next!; 61 | var neighbour = p.previous!; 62 | var previous = neighbour.previous!; 63 | 64 | next.previous = neighbour; 65 | 66 | neighbour.next = next; 67 | neighbour.previous = p; 68 | 69 | p.next = neighbour; 70 | p.previous = previous; 71 | 72 | previous.next = p; 73 | 74 | return p; 75 | } 76 | -------------------------------------------------------------------------------- /src/app/helper/util-functions/mod.ts: -------------------------------------------------------------------------------- 1 | export function mod(n: number, m: number) { 2 | return ((n % m) + m) % m; 3 | } 4 | -------------------------------------------------------------------------------- /src/app/helper/util-functions/normalize.ts: -------------------------------------------------------------------------------- 1 | export function normalize( 2 | val: number, 3 | in_min: number, 4 | in_max: number, 5 | out_min: number, 6 | out_max: number 7 | ) { 8 | return ((val - in_min) * (out_max - out_min)) / (in_max - in_min) + out_min; 9 | } 10 | -------------------------------------------------------------------------------- /src/app/helper/util-functions/ocr.ts: -------------------------------------------------------------------------------- 1 | import { ScriptsLoaderService } from '../services/scripts-loader.service'; 2 | 3 | declare let Tesseract: any; 4 | 5 | export async function OCR( 6 | x: number[], 7 | y: number[], 8 | z: number[], 9 | scriptsLoaderService: ScriptsLoaderService 10 | ): Promise { 11 | var maxX = Math.max(...x); 12 | var maxY = Math.max(...y); 13 | 14 | var canvas = document.createElement('canvas'); 15 | let ctx = canvas.getContext('2d'); 16 | let image = document.getElementById('source'); 17 | const magnifier = 5; 18 | canvas.width = magnifier * (maxX + 3); 19 | canvas.height = magnifier * (maxY + 3); 20 | for (let i = 0; i < x.length; i++) { 21 | if (z[i] > 0) { 22 | ctx?.fillRect( 23 | (x[i] + 1) * magnifier, 24 | (y[i] + 1) * magnifier, 25 | magnifier, 26 | magnifier 27 | ); 28 | } 29 | } 30 | const data = canvas.toDataURL(); 31 | return scriptsLoaderService 32 | .loadScript( 33 | 'Tesseract', 34 | 'https://unpkg.com/tesseract.js@v2.1.0/dist/tesseract.min.js' 35 | ) 36 | .then((res) => { 37 | return Tesseract.recognize(data, 'eng', {}).then((data: any) => { 38 | return data.data.text; 39 | }); 40 | }); 41 | } 42 | -------------------------------------------------------------------------------- /src/app/helper/util-functions/parse-first-line-into-numbers.ts: -------------------------------------------------------------------------------- 1 | import { splitIntoLines } from './split-into-lines'; 2 | 3 | export function parseFirstLineIntoNumbers(input: string): number[] { 4 | return splitIntoLines(input)[0].split(',').map(Number); 5 | } 6 | -------------------------------------------------------------------------------- /src/app/helper/util-functions/parse-into-2d-numbers-array.ts: -------------------------------------------------------------------------------- 1 | import { splitIntoLines } from './split-into-lines'; 2 | 3 | export function parseInto2DNumbersArray(input: string): number[][] { 4 | return splitIntoLines(input).map((line) => line.split('').map(Number)); 5 | } 6 | -------------------------------------------------------------------------------- /src/app/helper/util-functions/parse-into-numbers.ts: -------------------------------------------------------------------------------- 1 | import { splitIntoLines } from './split-into-lines'; 2 | 3 | export function parseIntoNumbers(input: string): number[] { 4 | return splitIntoLines(input) 5 | .filter((line) => line.trim().length > 0) 6 | .map((line) => Number(line.trim())) 7 | .filter((num) => !isNaN(num)); 8 | } 9 | -------------------------------------------------------------------------------- /src/app/helper/util-functions/point.ts: -------------------------------------------------------------------------------- 1 | export interface Point2D { 2 | x: number; 3 | y: number; 4 | } 5 | 6 | export interface Point3D extends Point2D { 7 | z: number; 8 | } 9 | 10 | export function points2DEqual(a: Point2D, b: Point2D): boolean { 11 | return a.x == b.x && a.y == b.y; 12 | } 13 | 14 | export function points3DEqual(a: Point3D, b: Point3D): boolean { 15 | return a.x == b.x && a.y == b.y && a.z == b.z; 16 | } 17 | -------------------------------------------------------------------------------- /src/app/helper/util-functions/product.ts: -------------------------------------------------------------------------------- 1 | export function multiplyNumbers(input: number[]): number { 2 | if (input.length == 0) { 3 | return 0; 4 | } 5 | return input.reduce((a, b) => a * b); 6 | } 7 | -------------------------------------------------------------------------------- /src/app/helper/util-functions/queue.ts: -------------------------------------------------------------------------------- 1 | export class Queue { 2 | protected _store: T[] = []; 3 | get store(): T[] { 4 | return this._store; 5 | } 6 | isEmpty(): boolean { 7 | return this._store.length == 0; 8 | } 9 | enqueue(val: T) { 10 | this._store.push(val); 11 | } 12 | dequeue(): T | undefined { 13 | return this._store.shift(); 14 | } 15 | clear(): void { 16 | this._store = []; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/app/helper/util-functions/split-into-lines.ts: -------------------------------------------------------------------------------- 1 | export function splitIntoLines(input: string, trim: boolean = false): string[] { 2 | var lines = input.split('\n'); 3 | if (trim) { 4 | lines = lines.map((l) => l.trim()); 5 | } 6 | if (lines[lines.length - 1].trim().length == 0) { 7 | lines = lines.slice(0, lines.length - 1); 8 | } 9 | return lines; 10 | } 11 | -------------------------------------------------------------------------------- /src/app/helper/util-functions/stack.ts: -------------------------------------------------------------------------------- 1 | export class Stack { 2 | constructor( 3 | private capacity: number = Infinity, 4 | protected _store: T[] = [] 5 | ) {} 6 | 7 | get store(): T[] { 8 | return this._store; 9 | } 10 | 11 | push(item: T): void { 12 | if (this.size() === this.capacity) { 13 | throw Error('Stack has reached max capacity, you cannot add more items'); 14 | } 15 | this._store.push(item); 16 | } 17 | 18 | pop(): T | undefined { 19 | return this._store.pop(); 20 | } 21 | 22 | peek(): T | undefined { 23 | return this._store[this.size() - 1]; 24 | } 25 | 26 | size(): number { 27 | return this._store.length; 28 | } 29 | 30 | copy(): Stack { 31 | return new Stack(this.capacity, Object.assign([], this._store)); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/app/helper/util-functions/sum.ts: -------------------------------------------------------------------------------- 1 | export function sumNumbers(input: number[]): number { 2 | if (input.length == 0) { 3 | return 0; 4 | } 5 | return input.reduce((a, b) => a + b); 6 | } 7 | -------------------------------------------------------------------------------- /src/app/helper/util-functions/two-way-map.ts: -------------------------------------------------------------------------------- 1 | export class TwoWayMap { 2 | map: Map; 3 | reverseMap: Map; 4 | constructor() { 5 | this.map = new Map(); 6 | this.reverseMap = new Map(); 7 | } 8 | get(key: K) { 9 | return this.map.get(key); 10 | } 11 | set(key: K, value: V) { 12 | this.map.set(key, value); 13 | this.reverseMap.set(value, key); 14 | } 15 | delete(key: K) { 16 | var value = this.map.get(key)!; 17 | this.map.delete(key); 18 | this.reverseMap.delete(value); 19 | } 20 | revGet(key: V) { 21 | return this.reverseMap.get(key); 22 | } 23 | values() { 24 | return [...this.reverseMap.keys()]; 25 | } 26 | } 27 | 28 | export class TwoWayNumberMap extends TwoWayMap { 29 | private static eps: number = 0.00005; 30 | override set(key: number, value: number) { 31 | var alteredValue = value; 32 | while (this.reverseMap.has(alteredValue)) { 33 | alteredValue -= TwoWayNumberMap.eps; 34 | } 35 | this.map.set(key, alteredValue); 36 | this.reverseMap.set(alteredValue, key); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/app/solutions2021/components/amphipods-room-visualizer/amphipods-room-visualizer.component.html: -------------------------------------------------------------------------------- 1 |
2 | 11 | 20 |
21 | 22 |
Current step: {{ currentStateIdx }}
23 |
Total cost: {{ currentCost }}
24 | 25 |
26 |
32 |
39 | {{ room.occupant }} 40 |
41 |
42 | -------------------------------------------------------------------------------- /src/app/solutions2021/components/amphipods-room-visualizer/amphipods-room-visualizer.component.scss: -------------------------------------------------------------------------------- 1 | .room-grid { 2 | margin-top: 0.5em; 3 | display: grid; 4 | grid-template-columns: repeat(var(--col), 1.5em); 5 | grid-template-rows: repeat(var(--row), 1.5em); 6 | 7 | .cell { 8 | grid-column-end: span 1; 9 | grid-row-end: span 1; 10 | height: 1.5em; 11 | width: 1.5em; 12 | display: flex; 13 | justify-content: center; 14 | 15 | &.border-cell { 16 | background-color: rgba(#fad02c, 0.5); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/app/solutions2021/components/amphipods-room-visualizer/amphipods-room-visualizer.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, HostBinding, OnInit } from '@angular/core'; 2 | import { BaseResultComponent } from 'src/app/helper/components/base-result.component'; 3 | import { Point2D } from 'src/app/helper/util-functions/point'; 4 | import { AmphipodRoomField } from '../../day23.service'; 5 | 6 | @Component({ 7 | selector: 'aoc-amphipods-room-visualizer', 8 | templateUrl: './amphipods-room-visualizer.component.html', 9 | styleUrls: ['./amphipods-room-visualizer.component.scss'], 10 | }) 11 | export class AmphipodsRoomVisualizerComponent 12 | extends BaseResultComponent 13 | implements OnInit 14 | { 15 | states: AmphipodRoomField[][] = []; 16 | border: Point2D[] = []; 17 | costs: number[] = []; 18 | currentStateIdx: number = 0; 19 | minX: number = 0; 20 | maxX: number = 0; 21 | minY: number = 0; 22 | maxY: number = 0; 23 | 24 | @HostBinding('style.--col') 25 | get col(): number { 26 | return this.maxX - this.minX; 27 | } 28 | 29 | @HostBinding('style.--row') 30 | get row(): number { 31 | return this.maxY - this.minY; 32 | } 33 | 34 | ngOnInit(): void { 35 | this.states = this.data.states as AmphipodRoomField[][]; 36 | this.border = this.data.border as Point2D[]; 37 | this.costs = this.data.costs as number[]; 38 | this.currentStateIdx = 0; 39 | this.minX = Math.min(...this.border.map((p) => p.x)); 40 | this.maxX = Math.max(...this.border.map((p) => p.x)); 41 | this.minY = Math.min(...this.border.map((p) => p.y)); 42 | this.maxY = Math.max(...this.border.map((p) => p.y)); 43 | } 44 | 45 | nextStep() { 46 | this.currentStateIdx++; 47 | } 48 | 49 | prevStep() { 50 | this.currentStateIdx--; 51 | } 52 | 53 | get currentState(): AmphipodRoomField[] { 54 | return this.states[this.currentStateIdx]; 55 | } 56 | 57 | get currentCost(): number { 58 | return this.costs[this.currentStateIdx]; 59 | } 60 | 61 | get currentMoving(): number | undefined { 62 | if (this.currentStateIdx == this.states.length - 1) { 63 | return undefined; 64 | } 65 | var currentState = this.states[this.currentStateIdx]; 66 | var nextState = this.states[this.currentStateIdx + 1]; 67 | var result = 0; 68 | currentState.forEach((f, idx) => { 69 | if (currentState[idx].occupant && !nextState[idx].occupant) { 70 | result = idx; 71 | } 72 | }); 73 | return result; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/app/solutions2021/components/arithmetic-logic-unit-visualizer/arithmetic-logic-unit-visualizer.component.html: -------------------------------------------------------------------------------- 1 |
2 | 11 | 20 |
21 | 22 |
23 | NOMAD version: 24 | {{ digit }} 29 |
30 |
31 | 32 |
{{ instruction[0] }}
33 |
34 | [w: {{ instruction[1].get("w") }}, x: {{ instruction[1].get("x") }}, y: 35 | {{ instruction[1].get("y") }}, z: {{ instruction[1].get("z") }}] 36 |
37 |
38 |
39 | -------------------------------------------------------------------------------- /src/app/solutions2021/components/arithmetic-logic-unit-visualizer/arithmetic-logic-unit-visualizer.component.scss: -------------------------------------------------------------------------------- 1 | .nomad-number { 2 | font-size: 1.5rem; 3 | margin-bottom: 0.5em; 4 | } 5 | 6 | .nomad-instructions { 7 | display: grid; 8 | width: fit-content; 9 | grid-template-columns: auto auto; 10 | grid-column-gap: 0.5em; 11 | } 12 | -------------------------------------------------------------------------------- /src/app/solutions2021/components/arithmetic-logic-unit-visualizer/arithmetic-logic-unit-visualizer.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { BaseResultComponent } from 'src/app/helper/components/base-result.component'; 3 | 4 | @Component({ 5 | selector: 'aoc-arithmetic-logic-unit-visualizer', 6 | templateUrl: './arithmetic-logic-unit-visualizer.component.html', 7 | styleUrls: ['./arithmetic-logic-unit-visualizer.component.scss'], 8 | }) 9 | export class ArithmeticLogicUnitVisualizerComponent 10 | extends BaseResultComponent 11 | implements OnInit 12 | { 13 | currentDigitIdx: number = 0; 14 | instructions: [string, Map][][] = []; 15 | number!: string; 16 | ngOnInit(): void { 17 | this.number = this.data.number as string; 18 | this.instructions = this.data.instructions as [ 19 | string, 20 | Map 21 | ][][]; 22 | } 23 | 24 | nextStep() { 25 | this.currentDigitIdx++; 26 | } 27 | 28 | prevStep() { 29 | this.currentDigitIdx--; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/app/solutions2021/components/bingo-visualizer/bingo-visualizer.component.html: -------------------------------------------------------------------------------- 1 | 10 | 11 |
12 | Numbers: 13 |
18 | {{ number }} 19 |
20 |
21 | 22 |
23 |
28 |
36 | {{ number }} 37 |
38 |
39 |
40 | -------------------------------------------------------------------------------- /src/app/solutions2021/components/bingo-visualizer/bingo-visualizer.component.scss: -------------------------------------------------------------------------------- 1 | .flex-row { 2 | display: flex; 3 | flex-flow: row wrap; 4 | } 5 | 6 | .number-cell { 7 | height: 1.5em; 8 | width: 1.5em; 9 | display: flex; 10 | justify-content: center; 11 | border-radius: 0.25em; 12 | margin: 0.1em; 13 | } 14 | 15 | .board { 16 | margin: 0.75em; 17 | display: grid; 18 | grid-template-columns: repeat(5, auto); 19 | border: rgba(#fff, 0.1) solid 2px; 20 | 21 | &.won { 22 | border: #fad02c solid 2px; 23 | box-shadow: 0 0 1em #fad02c; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/app/solutions2021/components/bingo-visualizer/bingo-visualizer.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { BaseResultComponent } from 'src/app/helper/components/base-result.component'; 3 | import { normalize } from 'src/app/helper/util-functions/normalize'; 4 | 5 | @Component({ 6 | selector: 'aoc-bingo-visualizer', 7 | templateUrl: './bingo-visualizer.component.html', 8 | styleUrls: ['./bingo-visualizer.component.scss'], 9 | }) 10 | export class BingoVisualizerComponent 11 | extends BaseResultComponent 12 | implements OnInit 13 | { 14 | boards!: number[][][]; 15 | numbers!: number[]; 16 | visualizeCounter: number = 0; 17 | wonBoards!: number[]; 18 | visualizing: boolean = false; 19 | ngOnInit(): void { 20 | var fullBoards = this.data.boards as [number, boolean][][][]; 21 | this.boards = fullBoards.map((board) => 22 | board.map((row) => row.map((tuple) => tuple[0])) 23 | ); 24 | this.numbers = this.data.numbers as number[]; 25 | this.visualizeCounter = this.numbers.length; 26 | this.wonBoards = this.data.wonBoards; 27 | } 28 | 29 | getNumberStyle(n: number): string { 30 | var idx = this.numbers 31 | .slice(0, this.visualizeCounter) 32 | .findIndex((num) => num == n); 33 | if (idx >= 0) { 34 | var value = normalize(idx, 0, this.numbers.length, 0.25, 1); 35 | return `rgba(250, 208, 44, ${value})`; 36 | } 37 | return 'transparent'; 38 | } 39 | startVisualization() { 40 | this.visualizing = true; 41 | this.visualizeCounter = 0; 42 | this.loop(); 43 | } 44 | 45 | private loop() { 46 | setTimeout(() => { 47 | this.visualizeCounter++; 48 | if (this.visualizeCounter < this.numbers.length) { 49 | this.loop(); 50 | } else { 51 | this.visualizing = false; 52 | } 53 | }, 100); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/app/solutions2021/components/bits-visualizer/bits-visualizer.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | {{ 5 | separator == 0 ? "⠀⠀" : "│⠀" 6 | }} 7 | 8 | 9 | 10 | 11 | 12 | Version: 14 | {{ 15 | packet.packetBits?.slice(0, 3) 16 | }} 17 | ({{ packet.version }}) 20 | Type ID: {{ packet.packetBits?.slice(3, 6) }} ({{ 22 | packet.typeId 23 | }}) 25 | 26 | Length type ID: {{ packet.lengthId }} 29 | 30 | Subpackets total length: 32 | {{ packet.packetBits?.slice(7, 23) }} ({{ 33 | packet.lengthNumber 34 | }}) 36 | 37 | 38 | Number of subpackets: 40 | {{ packet.packetBits?.slice(7, 18) }} ({{ 41 | packet.lengthNumber 42 | }}) 44 | 45 | 46 | 47 | 48 | 49 | Operator: {{ packet.packetBits?.slice(3, 6) }} ({{ getOperator(packet.typeId) }}) 55 | Final value: 57 | {{ packet.value }} 59 | 60 | 61 | Literal value: 63 | {{ c }} 71 | ({{ packet.value }}) 74 | 75 | 76 | 77 | 78 | 79 | 87 | 88 |
89 | -------------------------------------------------------------------------------- /src/app/solutions2021/components/bits-visualizer/bits-visualizer.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | width: 100%; 3 | display: block; 4 | margin-top: -0.4em; 5 | 6 | span { 7 | display: inline-block; 8 | line-height: 1em; 9 | } 10 | 11 | .bits-row { 12 | margin-right: 0.5em; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/app/solutions2021/components/bits-visualizer/bits-visualizer.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input, OnInit } from '@angular/core'; 2 | import { BaseResultComponent } from 'src/app/helper/components/base-result.component'; 3 | import { Packet } from '../../day16.service'; 4 | 5 | @Component({ 6 | selector: 'aoc-bits-visualizer', 7 | templateUrl: './bits-visualizer.component.html', 8 | styleUrls: ['./bits-visualizer.component.scss'], 9 | }) 10 | export class BitsVisualizerComponent 11 | extends BaseResultComponent 12 | implements OnInit 13 | { 14 | @Input() packet!: Packet; 15 | @Input() depth: number = 0; 16 | @Input() separators: number[] = []; 17 | @Input() isChild: boolean = false; 18 | @Input() isLast: boolean = true; 19 | @Input() showValues: boolean = false; 20 | 21 | ngOnInit(): void { 22 | if (this.data) { 23 | this.packet = this.data.packet as Packet; 24 | this.showValues = this.data.showValues as boolean; 25 | } 26 | } 27 | 28 | getOperator(typeId: number): string { 29 | switch (typeId) { 30 | case 0: 31 | return '+'; 32 | case 1: 33 | return '×'; 34 | case 2: 35 | return 'Min'; 36 | case 3: 37 | return 'Max'; 38 | case 5: 39 | return '>'; 40 | case 6: 41 | return '<'; 42 | case 7: 43 | return '='; 44 | default: 45 | return ''; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/app/solutions2021/components/caves-visualizer/caves-visualizer.component.html: -------------------------------------------------------------------------------- 1 |
2 | -------------------------------------------------------------------------------- /src/app/solutions2021/components/caves-visualizer/caves-visualizer.component.scss: -------------------------------------------------------------------------------- 1 | .network { 2 | height: 800px; 3 | } 4 | -------------------------------------------------------------------------------- /src/app/solutions2021/components/caves-visualizer/caves-visualizer.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { BaseResultComponent } from 'src/app/helper/components/base-result.component'; 3 | import { ScriptsLoaderService } from 'src/app/helper/services/scripts-loader.service'; 4 | 5 | declare let vis: any; 6 | 7 | @Component({ 8 | selector: 'aoc-caves-visualizer', 9 | templateUrl: './caves-visualizer.component.html', 10 | styleUrls: ['./caves-visualizer.component.scss'], 11 | }) 12 | export class CavesVisualizerComponent 13 | extends BaseResultComponent 14 | implements OnInit 15 | { 16 | networkId!: string; 17 | visLoaded: boolean = false; 18 | constructor(private scripts: ScriptsLoaderService) { 19 | super(); 20 | this.networkId = (Math.random() + 1).toString(36).substring(2); 21 | } 22 | 23 | ngOnInit(): void { 24 | var sources: number[] = this.data.sources as number[]; 25 | var targets: number[] = this.data.targets as number[]; 26 | var values: number[] = this.data.values as number[]; 27 | var labels: string[] = this.data.labels as string[]; 28 | var maxValue = Math.max(...values); 29 | this.scripts 30 | .loadScript( 31 | 'VisNetwork', 32 | 'https://unpkg.com/vis-network/standalone/umd/vis-network.min.js' 33 | ) 34 | .then(() => { 35 | var nodes = new vis.DataSet( 36 | labels.map((l, idx) => { 37 | return { id: idx, label: l }; 38 | }) 39 | ); 40 | var edges = new vis.DataSet( 41 | sources.map((s, idx) => { 42 | return { 43 | from: s, 44 | to: targets[idx], 45 | value: values[idx] / maxValue, 46 | arrows: 'to', 47 | color: '#fad02c', 48 | }; 49 | }) 50 | ); 51 | 52 | var container = document.getElementById(this.networkId); 53 | 54 | // provide the data in the vis format 55 | var data = { 56 | nodes: nodes, 57 | edges: edges, 58 | }; 59 | var options = { 60 | physics: { 61 | barnesHut: { 62 | springConstant: 0, 63 | avoidOverlap: 0.2, 64 | }, 65 | }, 66 | }; 67 | 68 | // initialize your network! 69 | var network = new vis.Network(container, data, options); 70 | // network.stabilize(); 71 | }); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/app/solutions2021/components/ocean-trench-visualizer/ocean-trench-visualizer.component.html: -------------------------------------------------------------------------------- 1 | 10 | 11 |
Current step: {{ currentIdx }}
12 |
Lit pixels: {{ litPixels }}
13 | 14 |
15 | 16 |
17 | -------------------------------------------------------------------------------- /src/app/solutions2021/components/ocean-trench-visualizer/ocean-trench-visualizer.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: block; 3 | width: 100%; 4 | } 5 | .flex-row { 6 | display: flex; 7 | flex-flow: row wrap; 8 | } 9 | .grid-wrapper { 10 | display: flex; 11 | justify-content: center; 12 | align-items: center; 13 | } 14 | -------------------------------------------------------------------------------- /src/app/solutions2021/components/ocean-trench-visualizer/ocean-trench-visualizer.component.ts: -------------------------------------------------------------------------------- 1 | import { AfterViewInit, Component, ElementRef, OnInit } from '@angular/core'; 2 | import { BaseResultComponent } from 'src/app/helper/components/base-result.component'; 3 | 4 | @Component({ 5 | selector: 'aoc-ocean-trench-visualizer', 6 | templateUrl: './ocean-trench-visualizer.component.html', 7 | styleUrls: ['./ocean-trench-visualizer.component.scss'], 8 | }) 9 | export class OceanTrenchVisualizerComponent 10 | extends BaseResultComponent 11 | implements OnInit, AfterViewInit 12 | { 13 | images: number[][][] = []; 14 | currentIdx: number = 0; 15 | visualizing: boolean = false; 16 | squareWidth: number = 5; 17 | 18 | constructor(private el: ElementRef) { 19 | super(); 20 | } 21 | 22 | get image(): number[][] { 23 | return this.images[this.currentIdx]; 24 | } 25 | 26 | get litPixels(): number { 27 | return this.image.flat().filter((d) => d == 1).length; 28 | } 29 | 30 | get imageWidth(): number { 31 | return this.image.length; 32 | } 33 | 34 | get finalWidth(): number { 35 | return this.images.slice(-1)[0].length; 36 | } 37 | 38 | get imageCanvas(): string { 39 | var imageArray = this.image; 40 | 41 | var canvas = document.createElement('canvas'); 42 | let ctx = canvas.getContext('2d'); 43 | const magnifier = this.squareWidth; 44 | canvas.width = magnifier * this.imageWidth; 45 | canvas.height = magnifier * this.imageWidth; 46 | ctx!.fillStyle = '#fad02c'; 47 | imageArray.forEach((row, y) => { 48 | row.forEach((val, x) => { 49 | if (val) { 50 | ctx!.fillRect(x * magnifier, y * magnifier, magnifier, magnifier); 51 | } 52 | }); 53 | }); 54 | const data = canvas.toDataURL(); 55 | return data; 56 | } 57 | 58 | ngOnInit(): void { 59 | this.images = this.data.images as number[][][]; 60 | this.currentIdx = this.images.length - 1; 61 | this.currentIdx = 0; 62 | } 63 | 64 | ngAfterViewInit(): void { 65 | this.squareWidth = 66 | this.el.nativeElement.offsetWidth / (3 * this.finalWidth); 67 | } 68 | 69 | startVisualization() { 70 | this.visualizing = true; 71 | this.currentIdx = 0; 72 | this.loop(); 73 | } 74 | 75 | private loop() { 76 | setTimeout(() => { 77 | this.currentIdx++; 78 | if (this.currentIdx < this.images.length - 1) { 79 | this.loop(); 80 | } else { 81 | this.visualizing = false; 82 | } 83 | }, 100); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/app/solutions2021/components/octopus-flashes-visualizer/octopus-flashes-visualizer.component.html: -------------------------------------------------------------------------------- 1 | 10 | 11 |
Current step: {{ currentIdx }}
12 |
Flashes sum: {{ flashedAmount }}
13 | 14 |
15 |
20 | {{ number }} 21 |
22 |
23 | -------------------------------------------------------------------------------- /src/app/solutions2021/components/octopus-flashes-visualizer/octopus-flashes-visualizer.component.scss: -------------------------------------------------------------------------------- 1 | .number-cell { 2 | height: 1.5em; 3 | width: 1.5em; 4 | display: flex; 5 | justify-content: center; 6 | border-radius: 0.25em; 7 | margin: 0.1em; 8 | } 9 | 10 | .flex-row { 11 | display: flex; 12 | flex-flow: row wrap; 13 | } 14 | 15 | .grid { 16 | margin: 0.75em; 17 | display: grid; 18 | grid-template-columns: repeat(10, auto); 19 | width: fit-content; 20 | } 21 | -------------------------------------------------------------------------------- /src/app/solutions2021/components/octopus-flashes-visualizer/octopus-flashes-visualizer.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { BaseResultComponent } from 'src/app/helper/components/base-result.component'; 3 | 4 | @Component({ 5 | selector: 'aoc-octopus-flashes-visualizer', 6 | templateUrl: './octopus-flashes-visualizer.component.html', 7 | styleUrls: ['./octopus-flashes-visualizer.component.scss'], 8 | }) 9 | export class OctopusFlashesVisualizerComponent 10 | extends BaseResultComponent 11 | implements OnInit 12 | { 13 | snapshots: number[][][] = []; 14 | flashes: number[] = []; 15 | currentIdx: number = 0; 16 | visualizing: boolean = false; 17 | 18 | get snapshot(): number[][] { 19 | return this.snapshots[this.currentIdx]; 20 | } 21 | 22 | get flashedAmount(): number { 23 | return this.currentIdx > 0 24 | ? this.flashes.slice(0, this.currentIdx).reduce((a, b) => a + b) 25 | : this.flashes[0]; 26 | } 27 | 28 | ngOnInit(): void { 29 | this.snapshots = this.data.snapshots as number[][][]; 30 | this.flashes = this.data.flashes as number[]; 31 | this.currentIdx = this.snapshots.length - 1; 32 | } 33 | 34 | startVisualization() { 35 | this.visualizing = true; 36 | this.currentIdx = 0; 37 | this.loop(); 38 | } 39 | 40 | private loop() { 41 | setTimeout(() => { 42 | this.currentIdx++; 43 | if (this.currentIdx < this.snapshots.length - 1) { 44 | this.loop(); 45 | } else { 46 | this.visualizing = false; 47 | } 48 | }, 100); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/app/solutions2021/components/sea-cucumbers-visualizer/sea-cucumbers-visualizer.component.html: -------------------------------------------------------------------------------- 1 | 10 | 11 |
Current step: {{ currentIdx }}
12 | 13 |
14 | 15 |
16 | -------------------------------------------------------------------------------- /src/app/solutions2021/components/sea-cucumbers-visualizer/sea-cucumbers-visualizer.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: block; 3 | width: 100%; 4 | } 5 | .flex-row { 6 | display: flex; 7 | flex-flow: row wrap; 8 | } 9 | .grid-wrapper { 10 | display: flex; 11 | justify-content: center; 12 | align-items: center; 13 | } 14 | -------------------------------------------------------------------------------- /src/app/solutions2021/components/sea-cucumbers-visualizer/sea-cucumbers-visualizer.component.ts: -------------------------------------------------------------------------------- 1 | import { AfterViewInit, Component, ElementRef, OnInit } from '@angular/core'; 2 | import { BaseResultComponent } from 'src/app/helper/components/base-result.component'; 3 | 4 | @Component({ 5 | selector: 'aoc-sea-cucumbers-visualizer', 6 | templateUrl: './sea-cucumbers-visualizer.component.html', 7 | styleUrls: ['./sea-cucumbers-visualizer.component.scss'], 8 | }) 9 | export class SeaCucumbersVisualizerComponent 10 | extends BaseResultComponent 11 | implements OnInit, AfterViewInit 12 | { 13 | areas: string[][][] = []; 14 | currentIdx: number = 0; 15 | visualizing: boolean = false; 16 | squareWidth: number = 5; 17 | 18 | constructor(private el: ElementRef) { 19 | super(); 20 | } 21 | 22 | get area(): string[][] { 23 | return this.areas[this.currentIdx]; 24 | } 25 | 26 | get imageWidth(): number { 27 | return this.area.length; 28 | } 29 | 30 | get imageCanvas(): string { 31 | var imageArray = this.area; 32 | 33 | var canvas = document.createElement('canvas'); 34 | let ctx = canvas.getContext('2d'); 35 | const magnifier = this.squareWidth; 36 | canvas.width = magnifier * this.imageWidth; 37 | canvas.height = magnifier * this.imageWidth; 38 | ctx!.fillStyle = '#fad02c'; 39 | imageArray.forEach((row, y) => { 40 | row.forEach((val, x) => { 41 | if (val == '>' || val == 'v') { 42 | ctx!.fillStyle = val == '>' ? '#fad02c' : '#ffffff'; 43 | ctx!.fillRect(x * magnifier, y * magnifier, magnifier, magnifier); 44 | } 45 | }); 46 | }); 47 | const data = canvas.toDataURL(); 48 | return data; 49 | } 50 | 51 | ngOnInit(): void { 52 | this.areas = this.data.areas as string[][][]; 53 | this.currentIdx = 0; 54 | } 55 | 56 | ngAfterViewInit(): void { 57 | this.squareWidth = 58 | this.el.nativeElement.offsetWidth / (3 * this.imageWidth); 59 | } 60 | 61 | startVisualization() { 62 | this.visualizing = true; 63 | this.currentIdx = 0; 64 | this.loop(); 65 | } 66 | 67 | private loop() { 68 | setTimeout(() => { 69 | this.currentIdx++; 70 | if (this.currentIdx < this.areas.length - 1) { 71 | this.loop(); 72 | } else { 73 | this.visualizing = false; 74 | } 75 | }, 100); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/app/solutions2021/components/seven-segments-display-visualizer/seven-segments-display-visualizer.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
8 |
9 |
10 |
>
11 |
12 |
17 |
18 |
19 | 20 |
21 |
25 |
30 |
31 |
32 |
>
33 |
34 |
39 |
40 |
41 |
42 |
43 | -------------------------------------------------------------------------------- /src/app/solutions2021/components/seven-segments-display-visualizer/seven-segments-display-visualizer.component.scss: -------------------------------------------------------------------------------- 1 | .display-row { 2 | display: flex; 3 | flex-flow: row; 4 | 5 | .divider { 6 | display: flex; 7 | align-items: center; 8 | margin-left: 0.5em; 9 | margin-right: 0.5em; 10 | font-size: 2em; 11 | line-height: 1em; 12 | } 13 | 14 | .display-block { 15 | display: flex; 16 | flex-flow: column; 17 | width: fit-content; 18 | height: fit-content; 19 | margin: 0.25em; 20 | 21 | &.accented { 22 | filter: drop-shadow(0 0 2px #fad02c) drop-shadow(0 0 5px #fad02c); 23 | } 24 | 25 | .display-block-part { 26 | height: 1em; 27 | width: 1em; 28 | box-sizing: border-box; 29 | border-color: #fad02c; 30 | border-style: solid; 31 | border-width: 0; 32 | 33 | &:nth-child(1) { 34 | border-top-left-radius: 2px; 35 | border-top-right-radius: 2px; 36 | } 37 | 38 | &:nth-child(2) { 39 | border-bottom-left-radius: 2px; 40 | border-bottom-right-radius: 2px; 41 | } 42 | 43 | &.a:nth-child(1) { 44 | border-top-width: 2px; 45 | } 46 | 47 | &.b:nth-child(1), 48 | &.e:nth-child(2) { 49 | border-left-width: 2px; 50 | } 51 | 52 | &.c:nth-child(1), 53 | &.f:nth-child(2) { 54 | border-right-width: 2px; 55 | } 56 | 57 | &.d:nth-child(1) { 58 | border-bottom-width: 2px; 59 | } 60 | 61 | &.g:nth-child(2) { 62 | border-bottom-width: 2px; 63 | } 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/app/solutions2021/components/seven-segments-display-visualizer/seven-segments-display-visualizer.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { BaseResultComponent } from 'src/app/helper/components/base-result.component'; 3 | import { Display } from '../../day8.service'; 4 | 5 | @Component({ 6 | selector: 'aoc-seven-segments-display-visualizer', 7 | templateUrl: './seven-segments-display-visualizer.component.html', 8 | styleUrls: ['./seven-segments-display-visualizer.component.scss'], 9 | }) 10 | export class SevenSegmentsDisplayVisualizerComponent 11 | extends BaseResultComponent 12 | implements OnInit 13 | { 14 | inputDisplays!: Display[]; 15 | decodedDisplays!: Display[]; 16 | accentUniqueLengths: boolean = false; 17 | uniqueLenghts = [2, 3, 4, 7]; 18 | ngOnInit(): void { 19 | this.inputDisplays = this.data.inputDisplays as Display[]; 20 | this.decodedDisplays = (this.data.decodedDisplays ?? []) as Display[]; 21 | this.accentUniqueLengths = this.data.accentUniqueLengths as boolean ?? false; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/app/solutions2021/components/snailfish-number-visualizer/snailfish-number-visualizer.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 12 | 21 | 30 | 43 |
44 |
45 | Animation speed: {{ interval }}ms 46 | 47 | 54 | 55 |
56 | 57 |
58 | Adding numbers: 59 | 63 | + 64 |
69 | Iterations: {{ iterations }} ({{ currentSnapshotIdx + 1 }}: 70 | {{ currentSnailfishIdx + 1 }}) 71 |
72 | 73 |
74 | 79 |
80 |
81 | 82 | 83 |
89 | [ 90 | {{ currentSnailfish.x }} 93 | 99 | , 100 | {{ currentSnailfish.y }} 109 | ] 110 |
111 |
112 | -------------------------------------------------------------------------------- /src/app/solutions2021/components/snailfish-number-visualizer/snailfish-number-visualizer.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: inline-block; 3 | vertical-align: top; 4 | } 5 | 6 | .non-glow { 7 | text-shadow: none; 8 | } 9 | -------------------------------------------------------------------------------- /src/app/solutions2021/components/syntax-error-lines-visualizer/syntax-error-lines-visualizer.component.html: -------------------------------------------------------------------------------- 1 | 2 |
{{ lines[i] }}
3 |
{{ result }}
4 |
8 | {{ scores[i] }} 9 |
10 |
11 | -------------------------------------------------------------------------------- /src/app/solutions2021/components/syntax-error-lines-visualizer/syntax-error-lines-visualizer.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: grid; 3 | grid-template-columns: repeat(3, auto); 4 | width: fit-content; 5 | column-gap: 1em; 6 | } 7 | .flex-row { 8 | display: flex; 9 | flex-flow: row; 10 | } 11 | 12 | .monospace { 13 | font-family: monospace; 14 | display: flex; 15 | width: fit-content; 16 | align-items: center; 17 | } 18 | -------------------------------------------------------------------------------- /src/app/solutions2021/components/syntax-error-lines-visualizer/syntax-error-lines-visualizer.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { BaseResultComponent } from 'src/app/helper/components/base-result.component'; 3 | 4 | @Component({ 5 | selector: 'aoc-syntax-error-lines-visualizer', 6 | templateUrl: './syntax-error-lines-visualizer.component.html', 7 | styleUrls: ['./syntax-error-lines-visualizer.component.scss'], 8 | }) 9 | export class SyntaxErrorLinesVisualizerComponent 10 | extends BaseResultComponent 11 | implements OnInit 12 | { 13 | lines!: string[]; 14 | results!: string[]; 15 | scores!: number[]; 16 | medianScore: number | undefined; 17 | 18 | ngOnInit(): void { 19 | this.lines = this.data.lines as string[]; 20 | this.results = this.data.results as string[]; 21 | this.scores = this.data.scores as number[]; 22 | this.medianScore = this.data.medianScore as number; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/app/solutions2021/day1.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { PlotlyGraphComponent } from '../helper/components/plotly-graph/plotly-graph.component'; 3 | import { BaseSolutionService } from '../helper/services/base-solution.service'; 4 | import { 5 | ISolutionService, 6 | PuzzleResult, 7 | } from '../helper/services/isolution.service'; 8 | import { SolutionsCollectorService } from '../helper/services/solutions-collector.service'; 9 | import { parseIntoNumbers } from '../helper/util-functions/parse-into-numbers'; 10 | 11 | @Injectable({ 12 | providedIn: 'root', 13 | }) 14 | export class Day1Service 15 | extends BaseSolutionService 16 | implements ISolutionService 17 | { 18 | constructor(solutionsCollectorService: SolutionsCollectorService) { 19 | super(solutionsCollectorService, 2021, 1, 'Sonar Sweep'); 20 | } 21 | override solvePart1(input: string): PuzzleResult { 22 | var measurements = parseIntoNumbers(input); 23 | var increases = []; 24 | for (let i = 1; i < measurements.length; i++) { 25 | if (measurements[i - 1] < measurements[i]) { 26 | increases.push([i, measurements[i]]); 27 | } 28 | } 29 | return { 30 | result: increases.length, 31 | component: PlotlyGraphComponent, 32 | componentData: { 33 | graphData: [ 34 | { 35 | x: measurements.map((val, idx) => idx), 36 | y: measurements, 37 | mode: 'lines', 38 | name: 'Measurements', 39 | line: { 40 | color: 'rgba(#ffffff, 0.8)', 41 | }, 42 | }, 43 | { 44 | x: increases.map((t) => t[0]), 45 | y: increases.map((t) => t[1]), 46 | mode: 'markers', 47 | name: 'Increases', 48 | marker: { 49 | color: '#fad02c', 50 | size: 2, 51 | }, 52 | }, 53 | ], 54 | graphLayout: { 55 | yaxis: { title: 'Depth', autorange: 'reversed' }, 56 | xaxis: { title: 'Time' }, 57 | }, 58 | }, 59 | }; 60 | } 61 | override solvePart2(input: string): PuzzleResult { 62 | var measurements = parseIntoNumbers(input); 63 | var measurementsWindows = []; 64 | var increases = []; 65 | measurementsWindows.push([ 66 | 2, 67 | measurements[0] + measurements[1] + measurements[2], 68 | ]); 69 | for (let i = 3; i < measurements.length; i++) { 70 | const window1 = 71 | measurements[i - 3] + measurements[i - 2] + measurements[i - 1]; 72 | const window2 = 73 | measurements[i - 2] + measurements[i - 1] + measurements[i]; 74 | measurementsWindows.push([i, window2]); 75 | if (window1 < window2) { 76 | increases.push([i, window2]); 77 | } 78 | } 79 | return { 80 | result: increases.length, 81 | component: PlotlyGraphComponent, 82 | componentData: { 83 | graphData: [ 84 | { 85 | x: measurementsWindows.map((t) => t[0]), 86 | y: measurementsWindows.map((t) => t[1]), 87 | mode: 'lines', 88 | name: 'Measurements', 89 | line: { 90 | color: 'rgba(#ffffff, 0.8)', 91 | }, 92 | }, 93 | { 94 | x: increases.map((t) => t[0]), 95 | y: increases.map((t) => t[1]), 96 | mode: 'markers', 97 | name: 'Increases', 98 | marker: { 99 | color: 'rgb(#fad02c)', 100 | size: 2, 101 | }, 102 | }, 103 | ], 104 | graphLayout: { yaxis: { title: 'Depth', autorange: 'reversed' } }, 105 | }, 106 | }; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/app/solutions2021/day2.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { PlotlyGraphComponent } from '../helper/components/plotly-graph/plotly-graph.component'; 3 | import { BaseSolutionService } from '../helper/services/base-solution.service'; 4 | import { 5 | ISolutionService, 6 | PuzzleResult, 7 | } from '../helper/services/isolution.service'; 8 | import { SolutionsCollectorService } from '../helper/services/solutions-collector.service'; 9 | import { splitIntoLines } from '../helper/util-functions/split-into-lines'; 10 | 11 | @Injectable({ 12 | providedIn: 'root', 13 | }) 14 | export class Day2Service 15 | extends BaseSolutionService 16 | implements ISolutionService 17 | { 18 | constructor(solutionsCollectorService: SolutionsCollectorService) { 19 | super(solutionsCollectorService, 2021, 2, 'Dive!'); 20 | } 21 | private parseCommands(input: string): [string, number][] { 22 | var commands = splitIntoLines(input); 23 | return commands.map((command) => { 24 | var parts = command.split(' '); 25 | return [parts[0], Number(parts[1])]; 26 | }); 27 | } 28 | override solvePart1(input: string): PuzzleResult { 29 | var commands = this.parseCommands(input); 30 | var depth = 0; 31 | var position = 0; 32 | var depths = [depth]; 33 | var positions = [position]; 34 | commands.forEach((command) => { 35 | switch (command[0]) { 36 | case 'forward': 37 | position += command[1]; 38 | break; 39 | case 'up': 40 | depth -= command[1]; 41 | break; 42 | case 'down': 43 | depth += command[1]; 44 | break; 45 | } 46 | depths.push(depth); 47 | positions.push(position); 48 | }); 49 | return { 50 | result: depth * position, 51 | component: PlotlyGraphComponent, 52 | componentData: { 53 | graphData: [ 54 | { 55 | x: positions, 56 | y: depths, 57 | mode: 'lines', 58 | name: 'Measurements', 59 | line: { 60 | color: 'rgba(#ffffff, 0.8)', 61 | }, 62 | }, 63 | ], 64 | graphLayout: { 65 | yaxis: { title: 'Depth', autorange: 'reversed' }, 66 | xaxis: { title: 'Position' }, 67 | }, 68 | }, 69 | }; 70 | } 71 | override solvePart2(input: string): PuzzleResult { 72 | var commands = this.parseCommands(input); 73 | var depth = 0; 74 | var position = 0; 75 | var aim = 0; 76 | var depths = [depth]; 77 | var positions = [position]; 78 | commands.forEach((command) => { 79 | switch (command[0]) { 80 | case 'forward': 81 | position += command[1]; 82 | depth += command[1] * aim; 83 | break; 84 | case 'up': 85 | aim -= command[1]; 86 | break; 87 | case 'down': 88 | aim += command[1]; 89 | break; 90 | } 91 | depths.push(depth); 92 | positions.push(position); 93 | }); 94 | return { 95 | result: depth * position, 96 | component: PlotlyGraphComponent, 97 | componentData: { 98 | graphData: [ 99 | { 100 | x: positions, 101 | y: depths, 102 | mode: 'lines', 103 | name: 'Measurements', 104 | line: { 105 | color: 'rgba(#ffffff, 0.8)', 106 | }, 107 | }, 108 | ], 109 | graphLayout: { 110 | yaxis: { title: 'Depth', autorange: 'reversed' }, 111 | xaxis: { title: 'Position' }, 112 | }, 113 | }, 114 | }; 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/app/solutions2021/day20.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { BaseSolutionService } from '../helper/services/base-solution.service'; 3 | import { 4 | ISolutionService, 5 | PuzzleResult, 6 | } from '../helper/services/isolution.service'; 7 | import { SolutionsCollectorService } from '../helper/services/solutions-collector.service'; 8 | import { splitIntoLines } from '../helper/util-functions/split-into-lines'; 9 | import { OceanTrenchVisualizerComponent } from './components/ocean-trench-visualizer/ocean-trench-visualizer.component'; 10 | 11 | @Injectable({ 12 | providedIn: 'root', 13 | }) 14 | export class Day20Service 15 | extends BaseSolutionService 16 | implements ISolutionService 17 | { 18 | constructor(solutionsCollectorService: SolutionsCollectorService) { 19 | super(solutionsCollectorService, 2021, 20, 'Trench Map'); 20 | } 21 | 22 | private enhance( 23 | algorithm: number[], 24 | startImage: number[][], 25 | steps: number = 2 26 | ): number[][][] { 27 | var result: number[][][] = [startImage]; 28 | var padding = 2; 29 | for (let s = 0; s < steps; s++) { 30 | var enhancedImage: number[][] = []; 31 | var lastImage = result.slice(-1)[0]; 32 | var height = lastImage.length; 33 | var width = lastImage[0].length; 34 | for (let y = -padding; y < height + padding - 2; y++) { 35 | var currentRow: number[] = []; 36 | for (let x = -padding; x < width + padding - 2; x++) { 37 | var numbersString = ''; 38 | [0, 1, 2].forEach((yIdx) => { 39 | [0, 1, 2].forEach((xIdx) => { 40 | var yPos = y + yIdx; 41 | var xPos = x + xIdx; 42 | if (yPos >= 0 && yPos < height && xPos >= 0 && xPos < width) { 43 | numbersString += lastImage[yPos][xPos].toString(); 44 | } else if (algorithm[0] == 1) { 45 | numbersString += (s % 2).toString(); 46 | } else { 47 | numbersString += '0'; 48 | } 49 | }); 50 | }); 51 | var kernelValue = Number.parseInt(numbersString, 2); 52 | currentRow.push(algorithm[kernelValue]); 53 | } 54 | enhancedImage.push(currentRow); 55 | } 56 | result.push(enhancedImage); 57 | } 58 | 59 | return result; 60 | } 61 | 62 | override solvePart1(input: string): PuzzleResult { 63 | var lines = splitIntoLines(input); 64 | var algorithm: number[] = lines[0].split('').map((c) => (c == '#' ? 1 : 0)); 65 | var image: number[][] = lines 66 | .slice(2) 67 | .map((l) => l.split('').map((c) => (c == '#' ? 1 : 0))); 68 | var images = this.enhance(algorithm, image, 2); 69 | return { 70 | result: images 71 | .slice(-1)[0] 72 | .flat() 73 | .filter((d) => d == 1).length, 74 | component: OceanTrenchVisualizerComponent, 75 | componentData: { 76 | images: images, 77 | }, 78 | }; 79 | } 80 | override solvePart2(input: string): PuzzleResult { 81 | var lines = splitIntoLines(input); 82 | var algorithm: number[] = lines[0].split('').map((c) => (c == '#' ? 1 : 0)); 83 | var image: number[][] = lines 84 | .slice(2) 85 | .map((l) => l.split('').map((c) => (c == '#' ? 1 : 0))); 86 | var images = this.enhance(algorithm, image, 50); 87 | return { 88 | result: images 89 | .slice(-1)[0] 90 | .flat() 91 | .filter((d) => d == 1).length, 92 | component: OceanTrenchVisualizerComponent, 93 | componentData: { 94 | images: images, 95 | }, 96 | }; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/app/solutions2021/day25.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { BaseSolutionService } from '../helper/services/base-solution.service'; 3 | import { 4 | ISolutionService, 5 | PuzzleResult, 6 | } from '../helper/services/isolution.service'; 7 | import { SolutionsCollectorService } from '../helper/services/solutions-collector.service'; 8 | import { Point2D } from '../helper/util-functions/point'; 9 | import { splitIntoLines } from '../helper/util-functions/split-into-lines'; 10 | import { SeaCucumbersVisualizerComponent } from './components/sea-cucumbers-visualizer/sea-cucumbers-visualizer.component'; 11 | 12 | @Injectable({ 13 | providedIn: 'root', 14 | }) 15 | export class Day25Service 16 | extends BaseSolutionService 17 | implements ISolutionService 18 | { 19 | constructor(solutionsCollectorService: SolutionsCollectorService) { 20 | super(solutionsCollectorService, 2021, 25, 'Sea Cucumber'); 21 | } 22 | 23 | private parseArea(input: string): string[][] { 24 | return splitIntoLines(input).map((l) => l.split('')); 25 | } 26 | 27 | private moveCucumbers(area: string[][]): string[][][] { 28 | var result: string[][][] = [JSON.parse(JSON.stringify(area))]; 29 | var moved = true; 30 | var height = area.length; 31 | var width = area[0].length; 32 | while (moved) { 33 | moved = false; 34 | var horizontalCucumbersToMove: Point2D[] = []; 35 | for (let y = 0; y < height; y++) { 36 | for (let x = 0; x < width; x++) { 37 | if (area[y][x] == '>' && area[y][(x + 1) % width] == '.') { 38 | horizontalCucumbersToMove.push({ x, y }); 39 | moved = true; 40 | } 41 | } 42 | } 43 | horizontalCucumbersToMove.forEach(({ x, y }) => { 44 | area[y][x] = '.'; 45 | area[y][(x + 1) % width] = '>'; 46 | }); 47 | 48 | var verticalCucumbersToMove: Point2D[] = []; 49 | for (let y = 0; y < height; y++) { 50 | for (let x = 0; x < width; x++) { 51 | if (area[y][x] == 'v' && area[(y + 1) % height][x] == '.') { 52 | verticalCucumbersToMove.push({ x, y }); 53 | moved = true; 54 | } 55 | } 56 | } 57 | verticalCucumbersToMove.forEach(({ x, y }) => { 58 | area[y][x] = '.'; 59 | area[(y + 1) % height][x] = 'v'; 60 | }); 61 | result.push(JSON.parse(JSON.stringify(area))); 62 | } 63 | return result; 64 | } 65 | 66 | override solvePart1(input: string): PuzzleResult { 67 | var startArea = this.parseArea(input); 68 | var result = this.moveCucumbers(startArea); 69 | return { 70 | result: result.length - 1, 71 | component: SeaCucumbersVisualizerComponent, 72 | componentData: { 73 | areas: result, 74 | }, 75 | }; 76 | } 77 | override solvePart2(input: string): number { 78 | return 0; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/app/solutions2021/day6.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { PlotlyGraphComponent } from '../helper/components/plotly-graph/plotly-graph.component'; 3 | import { BaseSolutionService } from '../helper/services/base-solution.service'; 4 | import { 5 | ISolutionService, 6 | PuzzleResult, 7 | } from '../helper/services/isolution.service'; 8 | import { SolutionsCollectorService } from '../helper/services/solutions-collector.service'; 9 | import { parseFirstLineIntoNumbers } from '../helper/util-functions/parse-first-line-into-numbers'; 10 | 11 | @Injectable({ 12 | providedIn: 'root', 13 | }) 14 | export class Day6Service 15 | extends BaseSolutionService 16 | implements ISolutionService 17 | { 18 | constructor(solutionsCollectorService: SolutionsCollectorService) { 19 | super(solutionsCollectorService, 2021, 6, 'Lanternfish'); 20 | } 21 | private getInitialState(input: string): { [day: number]: number } { 22 | var result: { [day: number]: number } = {}; 23 | parseFirstLineIntoNumbers(input).forEach((n) => { 24 | if (!(n in result)) { 25 | result[n] = 0; 26 | } 27 | result[n]++; 28 | }); 29 | return result; 30 | } 31 | private solve(input: string, days: number): PuzzleResult { 32 | var currentState = this.getInitialState(input); 33 | var y = [ 34 | Object.values(currentState) 35 | .map(Number) 36 | .reduce((a, b) => a + b), 37 | ]; 38 | var x = [0]; 39 | for (let d = 0; d < days; d++) { 40 | var newState: { [day: number]: number } = {}; 41 | Object.keys(currentState) 42 | .map(Number) 43 | .sort() 44 | .forEach((day) => { 45 | if (day > 0) { 46 | if (!(day - 1 in newState)) { 47 | newState[day - 1] = 0; 48 | } 49 | newState[day - 1] += currentState[day]; 50 | } else { 51 | newState[6] = currentState[day]; 52 | newState[8] = currentState[day]; 53 | } 54 | }); 55 | currentState = newState; 56 | y.push( 57 | Object.values(currentState) 58 | .map(Number) 59 | .reduce((a, b) => a + b) 60 | ); 61 | x.push(d + 1); 62 | } 63 | return { 64 | result: y[y.length - 1], 65 | component: PlotlyGraphComponent, 66 | componentData: { 67 | graphData: [ 68 | { 69 | x: x, 70 | y: y, 71 | mode: 'lines', 72 | name: 'Measurements', 73 | line: { 74 | color: '#fad02c', 75 | }, 76 | }, 77 | ], 78 | graphLayout: { 79 | yaxis: { title: 'Fishes' }, 80 | xaxis: { title: 'Days' }, 81 | }, 82 | }, 83 | }; 84 | } 85 | override solvePart1(input: string): PuzzleResult { 86 | return this.solve(input, 80); 87 | } 88 | override solvePart2(input: string): PuzzleResult { 89 | return this.solve(input, 256); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/app/solutions2021/day7.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { PlotlyGraphComponent } from '../helper/components/plotly-graph/plotly-graph.component'; 3 | import { BaseSolutionService } from '../helper/services/base-solution.service'; 4 | import { 5 | ISolutionService, 6 | PuzzleResult, 7 | } from '../helper/services/isolution.service'; 8 | import { SolutionsCollectorService } from '../helper/services/solutions-collector.service'; 9 | import { parseFirstLineIntoNumbers } from '../helper/util-functions/parse-first-line-into-numbers'; 10 | 11 | function sumNumber(num: number) { 12 | var rval = 1; 13 | for (var i = 2; i <= num; i++) rval = rval + i; 14 | return rval; 15 | } 16 | 17 | @Injectable({ 18 | providedIn: 'root', 19 | }) 20 | export class Day7Service 21 | extends BaseSolutionService 22 | implements ISolutionService 23 | { 24 | constructor(solutionsCollectorService: SolutionsCollectorService) { 25 | super(solutionsCollectorService, 2021, 7, 'The Treachery of Whales'); 26 | } 27 | override solvePart1(input: string): PuzzleResult { 28 | var positions = parseFirstLineIntoNumbers(input); 29 | var bestPos = -1; 30 | var bestCost = -1; 31 | for (let i = Math.min(...positions); i <= Math.max(...positions); i++) { 32 | var cost = positions 33 | .map((pos) => Math.abs(pos - i)) 34 | .reduce((a, b) => a + b); 35 | if (bestPos < 0 || cost < bestCost) { 36 | bestPos = i; 37 | bestCost = cost; 38 | } 39 | } 40 | return { 41 | result: bestCost, 42 | component: PlotlyGraphComponent, 43 | componentData: { 44 | graphData: positions.map((pos, idx) => { 45 | return { 46 | x: [pos, bestPos], 47 | y: [idx, idx], 48 | mode: 'markers', 49 | type: 'scattergl', 50 | showlegend: false, 51 | legendgroup: 'crab', 52 | }; 53 | }), 54 | graphLayout: { 55 | yaxis: { title: 'Crabs', visible: false }, 56 | xaxis: { title: 'Positions' }, 57 | }, 58 | }, 59 | }; 60 | } 61 | override solvePart2(input: string): PuzzleResult { 62 | var positions = parseFirstLineIntoNumbers(input); 63 | var bestPos = -1; 64 | var bestCost = -1; 65 | for (let i = Math.min(...positions); i <= Math.max(...positions); i++) { 66 | var cost = positions 67 | .map((pos) => sumNumber(Math.abs(pos - i))) 68 | .reduce((a, b) => a + b); 69 | if (bestPos < 0 || cost < bestCost) { 70 | bestPos = i; 71 | bestCost = cost; 72 | } 73 | } 74 | return { 75 | result: bestCost, 76 | component: PlotlyGraphComponent, 77 | componentData: { 78 | graphData: positions.map((pos, idx) => { 79 | return { 80 | x: [pos, bestPos], 81 | y: [idx, idx], 82 | mode: 'markers', 83 | type: 'scattergl', 84 | showlegend: false, 85 | legendgroup: 'crab', 86 | }; 87 | }), 88 | graphLayout: { 89 | yaxis: { title: 'Crabs', visible: false }, 90 | xaxis: { title: 'Positions' }, 91 | }, 92 | }, 93 | }; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/app/solutions2022/components/blizzard-visualizer/blizzard-visualizer.component.html: -------------------------------------------------------------------------------- 1 | 5 | 6 |
7 | 8 | 9 |
10 | -------------------------------------------------------------------------------- /src/app/solutions2022/components/blizzard-visualizer/blizzard-visualizer.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: block; 3 | width: 100%; 4 | } 5 | .grid-wrapper { 6 | display: flex; 7 | justify-content: center; 8 | align-items: center; 9 | 10 | img { 11 | position: absolute; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/app/solutions2022/components/blizzard-visualizer/blizzard-visualizer.component.ts: -------------------------------------------------------------------------------- 1 | import { AfterViewInit, Component, ElementRef, OnInit } from '@angular/core'; 2 | import { BaseResultComponent } from 'src/app/helper/components/base-result.component'; 3 | import { Point2D } from 'src/app/helper/util-functions/point'; 4 | import { Blizzard, getCurrentBlizzardsPositions } from '../../day24.service'; 5 | 6 | @Component({ 7 | selector: 'aoc-blizzard-visualizer', 8 | templateUrl: './blizzard-visualizer.component.html', 9 | styleUrls: ['./blizzard-visualizer.component.scss'], 10 | }) 11 | export class BlizzardVisualizerComponent 12 | extends BaseResultComponent 13 | implements OnInit, AfterViewInit 14 | { 15 | blizzards!: Blizzard[]; 16 | moves!: Point2D[]; 17 | walls!: Point2D[]; 18 | minX!: number; 19 | maxX!: number; 20 | minY!: number; 21 | maxY!: number; 22 | currentIdx: number = 0; 23 | visualizing: boolean = false; 24 | squareWidth: number = 5; 25 | blizzardsCache = {}; 26 | 27 | constructor(private el: ElementRef) { 28 | super(); 29 | } 30 | 31 | get imageHeight(): number { 32 | return this.maxY - this.minY + 1; 33 | } 34 | 35 | get imageWidth(): number { 36 | return this.maxX - this.minX + 1; 37 | } 38 | 39 | get wallsCanvas(): string { 40 | var canvas = document.createElement('canvas'); 41 | let ctx = canvas.getContext('2d'); 42 | const magnifier = this.squareWidth; 43 | canvas.width = magnifier * this.imageWidth; 44 | canvas.height = magnifier * this.imageHeight; 45 | ctx!.fillStyle = '#ccc'; 46 | this.walls.forEach((wall) => { 47 | ctx!.fillRect( 48 | (wall.x - this.minX) * magnifier, 49 | (wall.y - this.minY) * magnifier, 50 | magnifier, 51 | magnifier 52 | ); 53 | }); 54 | const data = canvas.toDataURL(); 55 | return data; 56 | } 57 | 58 | get imageCanvas(): string { 59 | var canvas = document.createElement('canvas'); 60 | let ctx = canvas.getContext('2d'); 61 | const magnifier = this.squareWidth; 62 | canvas.width = magnifier * this.imageWidth; 63 | canvas.height = magnifier * this.imageHeight; 64 | 65 | ctx!.fillStyle = 'rgb(250, 208, 44)'; 66 | ctx!.fillRect( 67 | (this.moves[this.currentIdx].x - this.minX) * magnifier, 68 | (this.moves[this.currentIdx].y - this.minY) * magnifier, 69 | magnifier, 70 | magnifier 71 | ); 72 | ctx!.fillStyle = 'rgba(115,155,208,0.25)'; 73 | var currentBlizzard = getCurrentBlizzardsPositions( 74 | this.blizzards, 75 | this.currentIdx, 76 | this.maxX - 1, 77 | this.maxY - 1, 78 | this.blizzardsCache 79 | ); 80 | currentBlizzard.forEach((blizzard) => { 81 | ctx!.fillRect( 82 | (blizzard.x - this.minX) * magnifier, 83 | (blizzard.y - this.minY) * magnifier, 84 | magnifier, 85 | magnifier 86 | ); 87 | }); 88 | const data = canvas.toDataURL(); 89 | return data; 90 | } 91 | 92 | ngOnInit(): void { 93 | this.blizzards = this.data.blizzards as Blizzard[]; 94 | this.walls = this.data.walls as Point2D[]; 95 | this.moves = this.data.moves as Point2D[]; 96 | this.currentIdx = 0; 97 | this.minX = Math.min(...this.walls.map((p) => p.x)); 98 | this.maxX = Math.max(...this.walls.map((p) => p.x)); 99 | this.minY = Math.min(...this.walls.map((p) => p.y)); 100 | this.maxY = Math.max(...this.walls.map((p) => p.y)); 101 | } 102 | 103 | ngAfterViewInit(): void { 104 | this.blizzardsCache = {}; 105 | this.squareWidth = this.el.nativeElement.offsetHeight / this.imageHeight; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/app/solutions2022/components/camp-sections-visualizer/camp-sections-visualizer.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
Elf 1 4 |
5 |
6 |
Elf 2 7 |
8 |
9 |
Overlap 10 |
11 |
12 | 13 |
14 | 15 |
16 | -------------------------------------------------------------------------------- /src/app/solutions2022/components/camp-sections-visualizer/camp-sections-visualizer.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: block; 3 | width: 100%; 4 | } 5 | 6 | .flex-row { 7 | display: flex; 8 | flex-flow: row wrap; 9 | 10 | &>div { 11 | margin-right: 8px; 12 | } 13 | } 14 | 15 | .block { 16 | width: 32px; 17 | height: 32px; 18 | } 19 | 20 | .block-1 { 21 | background-color: #fad02c; 22 | opacity: 0.6; 23 | } 24 | 25 | .block-2 { 26 | background-color: #fff; 27 | opacity: 0.6; 28 | } 29 | 30 | .block-3 { 31 | background-color: #fad02c; 32 | opacity: 1.0; 33 | } 34 | 35 | .grid-wrapper { 36 | display: flex; 37 | justify-content: center; 38 | align-items: center; 39 | } 40 | -------------------------------------------------------------------------------- /src/app/solutions2022/components/camp-sections-visualizer/camp-sections-visualizer.component.ts: -------------------------------------------------------------------------------- 1 | import { AfterViewInit, Component, ElementRef, OnInit } from '@angular/core'; 2 | import { min } from 'rxjs'; 3 | import { BaseResultComponent } from 'src/app/helper/components/base-result.component'; 4 | 5 | @Component({ 6 | selector: 'aoc-camp-sections-visualizer', 7 | templateUrl: './camp-sections-visualizer.component.html', 8 | styleUrls: ['./camp-sections-visualizer.component.scss'], 9 | }) 10 | export class CampSectionsVisualizerComponent 11 | extends BaseResultComponent 12 | implements OnInit, AfterViewInit 13 | { 14 | sections: [number[], number[]][] = []; 15 | squareWidth: number = 5; 16 | minSection: number = 0; 17 | maxSection: number = 0; 18 | 19 | constructor(private el: ElementRef) { 20 | super(); 21 | } 22 | 23 | get imageWidth(): number { 24 | return this.maxSection - this.minSection + 1; 25 | } 26 | 27 | get imageCanvas(): string { 28 | var sections = this.sections; 29 | 30 | var canvas = document.createElement('canvas'); 31 | let ctx = canvas.getContext('2d'); 32 | const magnifier = this.squareWidth; 33 | canvas.width = magnifier * this.imageWidth; 34 | canvas.height = magnifier * this.sections.length; 35 | sections.forEach((ranges, y) => { 36 | Array.range(this.minSection, this.maxSection + 1).forEach( 37 | (sectionId, x) => { 38 | var fillStyle = null; 39 | if (ranges.every((range) => range.includes(sectionId))) { 40 | fillStyle = '#fad02c'; 41 | ctx!.globalAlpha = 1.0; 42 | } else if (ranges[0].includes(sectionId)) { 43 | fillStyle = '#fad02c'; 44 | ctx!.globalAlpha = 0.6; 45 | } else if (ranges[1].includes(sectionId)) { 46 | fillStyle = '#ffffff'; 47 | ctx!.globalAlpha = 0.6; 48 | } 49 | 50 | if (fillStyle != null) { 51 | ctx!.fillStyle = fillStyle; 52 | ctx!.fillRect(x * magnifier, y * magnifier, magnifier, magnifier); 53 | } 54 | } 55 | ); 56 | }); 57 | const data = canvas.toDataURL(); 58 | return data; 59 | } 60 | 61 | ngOnInit(): void { 62 | this.sections = this.data.sections as [number[], number[]][]; 63 | var allNumbers: number[] = []; 64 | this.sections.forEach((ranges) => { 65 | allNumbers = allNumbers.concat(ranges.flat()); 66 | }); 67 | this.minSection = Math.min(...allNumbers); 68 | this.maxSection = Math.max(...allNumbers); 69 | } 70 | 71 | ngAfterViewInit(): void { 72 | this.squareWidth = 73 | this.el.nativeElement.offsetWidth / (2 * this.imageWidth); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/app/solutions2022/components/cargo-visualizer/cargo-step-visualizer/cargo-step-visualizer.component.html: -------------------------------------------------------------------------------- 1 |
2 |
8 | [{{ element.value }}] 9 |
10 | 11 | 12 |
20 | {{ column + 1 }} 21 |
22 |
23 |
24 | -------------------------------------------------------------------------------- /src/app/solutions2022/components/cargo-visualizer/cargo-step-visualizer/cargo-step-visualizer.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: block; 3 | width: fit-content; 4 | } 5 | 6 | .grid { 7 | margin: 0.75em; 8 | display: grid; 9 | width: fit-content; 10 | column-gap: 8px; 11 | } 12 | 13 | .cargo-cell { 14 | justify-self: center; 15 | min-width: 3ch; 16 | text-align: center; 17 | } 18 | -------------------------------------------------------------------------------- /src/app/solutions2022/components/cargo-visualizer/cargo-step-visualizer/cargo-step-visualizer.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input } from '@angular/core'; 2 | import { Stack } from '../../../../helper/util-functions/stack'; 3 | 4 | interface CargoElement { 5 | value: string; 6 | row: number; 7 | col: number; 8 | } 9 | 10 | @Component({ 11 | selector: 'aoc-cargo-step-visualizer', 12 | templateUrl: './cargo-step-visualizer.component.html', 13 | styleUrls: ['./cargo-step-visualizer.component.scss'], 14 | }) 15 | export class CargoStepVisualizerComponent { 16 | @Input() stacks: Stack[] = []; 17 | @Input() showColumns: boolean = true; 18 | @Input() glowColumn?: number; 19 | 20 | get cargoElements(): CargoElement[] { 21 | return this.stacks.flatMap((stack, col) => 22 | stack.store.map((element, row) => { 23 | return { value: element, row, col }; 24 | }) 25 | ); 26 | } 27 | 28 | get columns(): number[] { 29 | return this.stacks.map((s, idx) => idx); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/app/solutions2022/components/cargo-visualizer/cargo-visualizer.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 12 | 21 | 35 | 49 |
50 |
51 | Animation speed: {{ interval }}ms 52 | 53 | 60 | 61 |
62 |
63 |
64 | 65 | move {{ move.amount }} from 66 | {{ move.from }} to 67 | {{ move.to }}
69 | Iterations: {{ iterations }} / {{ totalIterations }} ({{ 70 | (100 * iterations) / totalIterations | number : "1.0-2" 71 | }}%) 72 |
73 |
74 |
75 | 76 | 80 | 81 | 82 | 83 | 86 | 87 | 88 | 89 | 93 | 94 |
95 |
96 | 97 | 101 | 102 |
103 |
104 |
105 |
106 | -------------------------------------------------------------------------------- /src/app/solutions2022/components/cargo-visualizer/cargo-visualizer.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: block; 3 | width: 100%; 4 | } 5 | 6 | .flex-box { 7 | margin: 0.75em; 8 | display: flex; 9 | flex-direction: column; 10 | width: fit-content; 11 | 12 | .cargo { 13 | justify-content: center; 14 | display: flex; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/app/solutions2022/components/cargo-visualizer/cargo-visualizer.component.ts: -------------------------------------------------------------------------------- 1 | import { AfterViewInit, Component, OnInit } from '@angular/core'; 2 | import { BaseResultComponent } from 'src/app/helper/components/base-result.component'; 3 | import { CargoMove, CargoSnapshot, CargoStep } from '../../day5.service'; 4 | 5 | @Component({ 6 | selector: 'aoc-cargo-visualizer', 7 | templateUrl: './cargo-visualizer.component.html', 8 | styleUrls: ['./cargo-visualizer.component.scss'], 9 | }) 10 | export class CargoVisualizerComponent 11 | extends BaseResultComponent 12 | implements OnInit 13 | { 14 | snapshots: CargoSnapshot[] = []; 15 | 16 | currentSnapshotIdx: number = 0; 17 | currentStepIdx: number = 0; 18 | currentStepStateIdx: number = 0; 19 | visualizing: boolean = false; 20 | iterations: number = 0; 21 | totalIterations: number = 0; 22 | interval = 100; 23 | 24 | get snapshot(): CargoSnapshot { 25 | return this.snapshots[this.currentSnapshotIdx]; 26 | } 27 | 28 | get move(): CargoMove { 29 | return this.snapshot.move; 30 | } 31 | 32 | get step(): CargoStep { 33 | return this.snapshot.steps[this.currentStepIdx]; 34 | } 35 | 36 | ngOnInit(): void { 37 | this.snapshots = this.data.snapshots as CargoSnapshot[]; 38 | this.totalIterations = 39 | this.snapshots.flatMap((s) => s.steps.map((x) => 3)).sum() - 1; 40 | } 41 | 42 | pauseVisualization() { 43 | this.visualizing = false; 44 | } 45 | 46 | startVisualization() { 47 | this.visualizing = true; 48 | if ( 49 | this.currentStepIdx == this.snapshot.steps.length - 1 && 50 | this.currentSnapshotIdx == this.snapshots.length - 1 && 51 | this.currentStepStateIdx == 2 52 | ) { 53 | this.currentStepIdx = 0; 54 | this.currentSnapshotIdx = 0; 55 | this.currentStepStateIdx = 0; 56 | this.iterations = 0; 57 | } 58 | this.loop(); 59 | } 60 | 61 | nextStep() { 62 | this.iterations++; 63 | var isLastStepState = this.currentStepStateIdx == 2; 64 | var isLastStep = this.currentStepIdx == this.snapshot.steps.length - 1; 65 | 66 | this.currentStepStateIdx++; 67 | 68 | if (isLastStepState) { 69 | this.currentStepStateIdx = 0; 70 | this.currentStepIdx++; 71 | } 72 | 73 | if (isLastStep && isLastStepState) { 74 | this.currentStepIdx = 0; 75 | this.currentSnapshotIdx++; 76 | } 77 | } 78 | 79 | prevStep() { 80 | this.iterations--; 81 | var isFirstStepState = this.currentStepStateIdx == 0; 82 | var isFirstStep = this.currentStepIdx == 0; 83 | 84 | this.currentStepStateIdx--; 85 | 86 | if (isFirstStepState) { 87 | this.currentStepIdx--; 88 | this.currentStepStateIdx = 2; 89 | } 90 | 91 | if (isFirstStep && isFirstStepState) { 92 | this.currentSnapshotIdx--; 93 | this.currentStepIdx = this.snapshot.steps.length - 1; 94 | } 95 | } 96 | 97 | private loop() { 98 | if (this.visualizing) { 99 | setTimeout(() => { 100 | this.nextStep(); 101 | if ( 102 | this.currentStepStateIdx < 2 || 103 | this.currentStepIdx < this.snapshot.steps.length - 1 || 104 | this.currentSnapshotIdx < this.snapshots.length - 1 105 | ) { 106 | this.loop(); 107 | } else { 108 | this.visualizing = false; 109 | } 110 | }, this.interval); 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/app/solutions2022/components/datastream-buffer-visualizer/datastream-buffer-visualizer.component.html: -------------------------------------------------------------------------------- 1 | {{ char }} 7 | -------------------------------------------------------------------------------- /src/app/solutions2022/components/datastream-buffer-visualizer/datastream-buffer-visualizer.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: block; 3 | width: 100%; 4 | word-break: break-all; 5 | 6 | .packet-character { 7 | padding: 0 4px; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/app/solutions2022/components/datastream-buffer-visualizer/datastream-buffer-visualizer.component.ts: -------------------------------------------------------------------------------- 1 | import { AfterViewInit, Component, OnInit } from '@angular/core'; 2 | import { BaseResultComponent } from 'src/app/helper/components/base-result.component'; 3 | 4 | @Component({ 5 | selector: 'aoc-datastream-buffer-visualizer', 6 | templateUrl: './datastream-buffer-visualizer.component.html', 7 | styleUrls: ['./datastream-buffer-visualizer.component.scss'], 8 | }) 9 | export class DatastreamBufferVisualizerComponent 10 | extends BaseResultComponent 11 | implements OnInit 12 | { 13 | message: string[] = []; 14 | index: number = 0; 15 | packetLength: number = 0; 16 | ngOnInit(): void { 17 | this.message = (this.data.message as string).split(''); 18 | this.index = this.data.index as number; 19 | this.packetLength = this.data.packetLength as number; 20 | } 21 | 22 | isInPacket(idx: number): boolean { 23 | return idx > this.index - this.packetLength && idx <= this.index; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/app/solutions2022/components/device-file-visualizer/device-file-visualizer.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | {{ 5 | separator == 0 ? "⠀⠀" : "│⠀" 6 | }} 7 | 8 | 9 | 10 | 11 | 12 | {{ file.fileName }} 17 | ({{ file.isDirectory ? "dir, " : "file, " }}size={{ file.fileSize }}) 23 | 24 | 25 | 26 | 27 | 35 | 36 |
37 | -------------------------------------------------------------------------------- /src/app/solutions2022/components/device-file-visualizer/device-file-visualizer.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | width: 100%; 3 | display: block; 4 | margin-top: -0.4em; 5 | 6 | span { 7 | display: inline-block; 8 | line-height: 1em; 9 | } 10 | 11 | .file-row { 12 | margin-right: 0.5em; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/app/solutions2022/components/device-file-visualizer/device-file-visualizer.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input, OnInit } from '@angular/core'; 2 | import { BaseResultComponent } from '../../../helper/components/base-result.component'; 3 | import { DeviceFile } from '../../day7.service'; 4 | 5 | @Component({ 6 | selector: 'aoc-device-file-visualizer', 7 | templateUrl: './device-file-visualizer.component.html', 8 | styleUrls: ['./device-file-visualizer.component.scss'], 9 | }) 10 | export class DeviceFileVisualizerComponent 11 | extends BaseResultComponent 12 | implements OnInit 13 | { 14 | @Input() file!: DeviceFile; 15 | @Input() selectedDirectories!: DeviceFile[]; 16 | @Input() depth: number = 0; 17 | @Input() separators: number[] = []; 18 | @Input() isChild: boolean = false; 19 | @Input() isLast: boolean = true; 20 | 21 | ngOnInit(): void { 22 | if (this.data) { 23 | this.file = this.data.file as DeviceFile; 24 | this.selectedDirectories = this.data.selectedDirectories as DeviceFile[]; 25 | } 26 | } 27 | 28 | matchDeviceFile(file: DeviceFile): boolean { 29 | return this.selectedDirectories.some((dir) => { 30 | return ( 31 | file.isDirectory && 32 | file.fileName === dir.fileName && 33 | file.fileSize === dir.fileSize 34 | ); 35 | }); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/app/solutions2022/components/elves-moves-visualizer/elves-moves-visualizer.component.html: -------------------------------------------------------------------------------- 1 | 5 | 6 |
7 | 8 |
9 | -------------------------------------------------------------------------------- /src/app/solutions2022/components/elves-moves-visualizer/elves-moves-visualizer.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: block; 3 | width: 100%; 4 | } 5 | .grid-wrapper { 6 | display: flex; 7 | justify-content: center; 8 | align-items: center; 9 | } 10 | -------------------------------------------------------------------------------- /src/app/solutions2022/components/elves-moves-visualizer/elves-moves-visualizer.component.ts: -------------------------------------------------------------------------------- 1 | import { AfterViewInit, Component, ElementRef, OnInit } from '@angular/core'; 2 | import { colorInterpolate } from 'src/app/helper/util-functions/color-interpolate'; 3 | import { normalize } from 'src/app/helper/util-functions/normalize'; 4 | import { BaseResultComponent } from '../../../helper/components/base-result.component'; 5 | import { MovingElf } from '../../day23.service'; 6 | 7 | @Component({ 8 | selector: 'aoc-elves-moves-visualizer', 9 | templateUrl: './elves-moves-visualizer.component.html', 10 | styleUrls: ['./elves-moves-visualizer.component.scss'], 11 | }) 12 | export class ElvesMovesVisualizerComponent 13 | extends BaseResultComponent 14 | implements OnInit, AfterViewInit 15 | { 16 | elves!: MovingElf[]; 17 | minX!: number; 18 | maxX!: number; 19 | minY!: number; 20 | maxY!: number; 21 | currentIdx: number = 0; 22 | visualizing: boolean = false; 23 | squareWidth: number = 5; 24 | 25 | constructor(private el: ElementRef) { 26 | super(); 27 | } 28 | 29 | get imageHeight(): number { 30 | return this.maxY - this.minY + 1; 31 | } 32 | 33 | get imageWidth(): number { 34 | return this.maxX - this.minX + 1; 35 | } 36 | 37 | get imageCanvas(): string { 38 | var canvas = document.createElement('canvas'); 39 | let ctx = canvas.getContext('2d'); 40 | const magnifier = this.squareWidth; 41 | canvas.width = magnifier * this.imageWidth; 42 | canvas.height = magnifier * this.imageHeight; 43 | 44 | ctx!.fillStyle = 'rgb(250, 208, 44)'; 45 | this.elves.forEach((elf) => { 46 | ctx!.fillStyle = colorInterpolate( 47 | 'rgb(250, 208, 44)', 48 | 'rgb(255, 255, 255)', 49 | normalize( 50 | this.currentIdx - 51 | 1 - 52 | elf.moveChanges.findLast((change) => change < this.currentIdx)!, 53 | 0, 54 | 10, 55 | 0, 56 | 1 57 | ) 58 | ); 59 | ctx!.fillRect( 60 | (elf.positionsList[this.currentIdx].x - this.minX) * magnifier, 61 | (elf.positionsList[this.currentIdx].y - this.minY) * magnifier, 62 | magnifier, 63 | magnifier 64 | ); 65 | }); 66 | const data = canvas.toDataURL(); 67 | return data; 68 | } 69 | 70 | ngOnInit(): void { 71 | this.elves = this.data.elves as MovingElf[]; 72 | this.currentIdx = 0; 73 | this.minX = Math.min( 74 | ...this.elves.map((elf) => Math.min(...elf.positionsList.map((p) => p.x))) 75 | ); 76 | this.maxX = Math.max( 77 | ...this.elves.map((elf) => Math.max(...elf.positionsList.map((p) => p.x))) 78 | ); 79 | this.minY = Math.min( 80 | ...this.elves.map((elf) => Math.min(...elf.positionsList.map((p) => p.y))) 81 | ); 82 | this.maxY = Math.max( 83 | ...this.elves.map((elf) => Math.max(...elf.positionsList.map((p) => p.y))) 84 | ); 85 | } 86 | 87 | ngAfterViewInit(): void { 88 | this.squareWidth = 89 | this.el.nativeElement.offsetWidth / (3 * this.imageWidth); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/app/solutions2022/components/falling-rocks-visualizer/falling-rocks-visualizer.component.html: -------------------------------------------------------------------------------- 1 | 5 |
Current rock: {{ currentRock + 1 }}
6 |
7 | Current move: 8 | {{ 9 | jets[rocksPositions[currentRock][currentMove].jetIdx] === -1 ? "<" : ">" 10 | }} 11 |
12 |
13 | 14 |
15 | -------------------------------------------------------------------------------- /src/app/solutions2022/components/falling-rocks-visualizer/falling-rocks-visualizer.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: block; 3 | width: 100%; 4 | } 5 | .flex-row { 6 | display: flex; 7 | flex-flow: row wrap; 8 | } 9 | .grid-wrapper { 10 | display: flex; 11 | justify-content: center; 12 | align-items: center; 13 | } 14 | -------------------------------------------------------------------------------- /src/app/solutions2022/components/falling-sand-visualizer/falling-sand-visualizer.component.html: -------------------------------------------------------------------------------- 1 | 5 | 6 |
7 | 8 | 9 |
10 | -------------------------------------------------------------------------------- /src/app/solutions2022/components/falling-sand-visualizer/falling-sand-visualizer.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: block; 3 | width: 100%; 4 | } 5 | .flex-row { 6 | display: flex; 7 | flex-flow: row wrap; 8 | } 9 | .grid-wrapper { 10 | display: flex; 11 | justify-content: center; 12 | align-items: center; 13 | 14 | img { 15 | position: absolute; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/app/solutions2022/components/falling-sand-visualizer/falling-sand-visualizer.component.ts: -------------------------------------------------------------------------------- 1 | import { AfterViewInit, Component, ElementRef, OnInit } from '@angular/core'; 2 | import { Point2D } from 'src/app/helper/util-functions/point'; 3 | import { BaseResultComponent } from '../../../helper/components/base-result.component'; 4 | 5 | @Component({ 6 | selector: 'aoc-falling-sand-visualizer', 7 | templateUrl: './falling-sand-visualizer.component.html', 8 | styleUrls: ['./falling-sand-visualizer.component.scss'], 9 | }) 10 | export class FallingSandVisualizerComponent 11 | extends BaseResultComponent 12 | implements OnInit, AfterViewInit 13 | { 14 | rocks!: Point2D[]; 15 | sands!: Point2D[][]; 16 | minX!: number; 17 | maxX!: number; 18 | minY!: number; 19 | maxY!: number; 20 | currentIdx: number = 0; 21 | visualizing: boolean = false; 22 | squareWidth: number = 5; 23 | 24 | constructor(private el: ElementRef) { 25 | super(); 26 | } 27 | 28 | get sand(): Point2D[] { 29 | return this.sands[this.currentIdx]; 30 | } 31 | 32 | get imageHeight(): number { 33 | return this.maxY - this.minY + 1; 34 | } 35 | 36 | get imageWidth(): number { 37 | return this.maxX - this.minX + 1; 38 | } 39 | 40 | get rockCanvas(): string { 41 | var canvas = document.createElement('canvas'); 42 | let ctx = canvas.getContext('2d'); 43 | const magnifier = this.squareWidth; 44 | canvas.width = magnifier * this.imageWidth; 45 | canvas.height = magnifier * this.imageHeight; 46 | ctx!.fillStyle = '#ffffff'; 47 | this.rocks.forEach((rock) => { 48 | ctx!.fillRect( 49 | (rock.x - this.minX) * magnifier, 50 | (rock.y - this.minY) * magnifier, 51 | magnifier, 52 | magnifier 53 | ); 54 | }); 55 | const data = canvas.toDataURL(); 56 | return data; 57 | } 58 | 59 | get imageCanvas(): string { 60 | var canvas = document.createElement('canvas'); 61 | let ctx = canvas.getContext('2d'); 62 | const magnifier = this.squareWidth; 63 | canvas.width = magnifier * this.imageWidth; 64 | canvas.height = magnifier * this.imageHeight; 65 | ctx!.fillStyle = '#fad02c'; 66 | this.sand.forEach((grain) => { 67 | ctx!.fillRect( 68 | (grain.x - this.minX) * magnifier, 69 | (grain.y - this.minY) * magnifier, 70 | magnifier, 71 | magnifier 72 | ); 73 | }); 74 | const data = canvas.toDataURL(); 75 | return data; 76 | } 77 | 78 | ngOnInit(): void { 79 | this.rocks = this.data.rocks as Point2D[]; 80 | this.sands = this.data.sands as Point2D[][]; 81 | this.currentIdx = 0; 82 | this.minX = Math.min( 83 | ...this.rocks.concat(this.sands[this.sands.length - 1]).map((p) => p.x) 84 | ); 85 | this.maxX = Math.max( 86 | ...this.rocks.concat(this.sands[this.sands.length - 1]).map((p) => p.x) 87 | ); 88 | this.minY = 0; 89 | this.maxY = Math.max( 90 | ...this.rocks.concat(this.sands[this.sands.length - 1]).map((p) => p.y) 91 | ); 92 | } 93 | 94 | ngAfterViewInit(): void { 95 | this.squareWidth = 96 | this.el.nativeElement.offsetWidth / (3 * this.imageWidth); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/app/solutions2022/components/monkey-map-cube-visualizer/monkey-map-cube-visualizer.component.html: -------------------------------------------------------------------------------- 1 |
2 | -------------------------------------------------------------------------------- /src/app/solutions2022/components/monkey-map-cube-visualizer/monkey-map-cube-visualizer.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: block; 3 | width: 100%; 4 | } 5 | 6 | .scene { 7 | height: 800px; 8 | } 9 | -------------------------------------------------------------------------------- /src/app/solutions2022/components/monkey-math-equations-visualizer/monkey-math-equations-visualizer.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | -------------------------------------------------------------------------------- /src/app/solutions2022/components/monkey-math-equations-visualizer/monkey-math-equations-visualizer.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: block; 3 | width: 100%; 4 | } 5 | 6 | .network { 7 | height: 800px; 8 | } 9 | 10 | .equations-container { 11 | display: flex; 12 | flex-direction: column; 13 | 14 | ::ng-deep { 15 | .eq-smaller-margin { 16 | margin: 0.25em 0; 17 | } 18 | } 19 | .equation { 20 | margin: 1em 0; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/app/solutions2022/components/monkeys-inspections-visualizer/monkey-inspection-visualizer/monkey-inspection-visualizer.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 🐒 #{{ monkeyId }}
5 | 6 | Inspections: 7 | {{ monkeyInspection.inspections }}
9 | Items: {{ items }}
11 | Condition: x % {{ monkeyInspection.divisibleBy }} == 0 ? 13 | {{ monkeyInspection.trueMonkeyIndex }} : 14 | {{ monkeyInspection.falseMonkeyIndex }}
16 |
17 | -------------------------------------------------------------------------------- /src/app/solutions2022/components/monkeys-inspections-visualizer/monkey-inspection-visualizer/monkey-inspection-visualizer.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: block; 3 | width: fit-content; 4 | justify-self: center; 5 | } 6 | -------------------------------------------------------------------------------- /src/app/solutions2022/components/monkeys-inspections-visualizer/monkey-inspection-visualizer/monkey-inspection-visualizer.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input } from '@angular/core'; 2 | import { Monkey } from 'src/app/solutions2022/day11.service'; 3 | 4 | @Component({ 5 | selector: 'aoc-monkey-inspection-visualizer', 6 | templateUrl: './monkey-inspection-visualizer.component.html', 7 | styleUrls: ['./monkey-inspection-visualizer.component.scss'], 8 | }) 9 | export class MonkeyInspectionVisualizerComponent { 10 | @Input() monkeyId!: number; 11 | @Input() monkeyInspection!: Monkey; 12 | 13 | get items(): string { 14 | return this.monkeyInspection.items.map((item) => item.value).join(', '); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/app/solutions2022/components/monkeys-inspections-visualizer/monkeys-inspections-visualizer.component.html: -------------------------------------------------------------------------------- 1 |
2 | 6 | 7 |
8 | 13 |
14 |
15 | -------------------------------------------------------------------------------- /src/app/solutions2022/components/monkeys-inspections-visualizer/monkeys-inspections-visualizer.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: block; 3 | width: 100%; 4 | } 5 | 6 | .grid { 7 | display: grid; 8 | grid-template-columns: repeat(4, 1fr); 9 | column-gap: 0.5em; 10 | row-gap: 0.5em; 11 | } 12 | -------------------------------------------------------------------------------- /src/app/solutions2022/components/monkeys-inspections-visualizer/monkeys-inspections-visualizer.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { BaseResultComponent } from '../../../helper/components/base-result.component'; 3 | import { Monkey } from '../../day11.service'; 4 | 5 | @Component({ 6 | selector: 'aoc-monkeys-inspections-visualizer', 7 | templateUrl: './monkeys-inspections-visualizer.component.html', 8 | styleUrls: ['./monkeys-inspections-visualizer.component.scss'], 9 | }) 10 | export class MonkeysInspectionsVisualizerComponent 11 | extends BaseResultComponent 12 | implements OnInit 13 | { 14 | currentIdx: number = 0; 15 | iterations!: number; 16 | 17 | monkeysSnapshots: Monkey[][] = []; 18 | 19 | get monkeys(): Monkey[] { 20 | return this.monkeysSnapshots[this.currentIdx]; 21 | } 22 | 23 | ngOnInit(): void { 24 | this.monkeysSnapshots = this.data.monkeysSnapshots as Monkey[][]; 25 | this.iterations = this.monkeysSnapshots.length; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/app/solutions2022/components/packet-numbers-visualizer/packet-numbers-visualizer.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
7 | {{ packetNumber | json }} 8 |
9 |
10 |
11 |
12 | -------------------------------------------------------------------------------- /src/app/solutions2022/components/packet-numbers-visualizer/packet-numbers-visualizer.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: block; 3 | width: 100%; 4 | } 5 | -------------------------------------------------------------------------------- /src/app/solutions2022/components/packet-numbers-visualizer/packet-numbers-visualizer.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input, OnInit } from '@angular/core'; 2 | import { BaseResultComponent } from 'src/app/helper/components/base-result.component'; 3 | import { PacketNumber } from '../../day13.service'; 4 | 5 | @Component({ 6 | selector: 'aoc-packet-numbers-visualizer', 7 | templateUrl: './packet-numbers-visualizer.component.html', 8 | styleUrls: ['./packet-numbers-visualizer.component.scss'], 9 | }) 10 | export class PacketNumbersVisualizerComponent 11 | extends BaseResultComponent 12 | implements OnInit 13 | { 14 | packetNumbersGroups!: PacketNumber[][]; 15 | highlightIndexes!: number[][]; 16 | 17 | isHighlighted(i: number, j: number): boolean { 18 | return this.highlightIndexes.some((pair) => pair[0] === i && pair[1] === j); 19 | } 20 | 21 | ngOnInit(): void { 22 | this.packetNumbersGroups = this.data.packetNumbers as PacketNumber[][]; 23 | this.highlightIndexes = this.data.highlightIndexes as number[][]; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/app/solutions2022/components/pressure-valves-visualizer/pressure-valves-visualizer.component.html: -------------------------------------------------------------------------------- 1 |
2 | -------------------------------------------------------------------------------- /src/app/solutions2022/components/pressure-valves-visualizer/pressure-valves-visualizer.component.scss: -------------------------------------------------------------------------------- 1 | .network { 2 | height: 800px; 3 | } 4 | -------------------------------------------------------------------------------- /src/app/solutions2022/components/rope-bridge-visualizer/rope-bridge-visualizer.component.html: -------------------------------------------------------------------------------- 1 |
2 | 6 |
7 | 8 | Direction {{ move.direction }}
9 | Steps {{ move.distance }}
11 |
12 |
13 |
14 |
19 | H 20 |
21 |
26 | 27 | T 28 | 29 |
30 |
36 | 42 | . 43 | 44 |
45 |
51 | s 52 |
53 |
60 |
61 |
62 |
63 | -------------------------------------------------------------------------------- /src/app/solutions2022/components/rope-bridge-visualizer/rope-bridge-visualizer.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: block; 3 | width: 100%; 4 | } 5 | 6 | .grid-wrapper { 7 | display: flex; 8 | justify-content: center; 9 | align-items: center; 10 | } 11 | 12 | .grid { 13 | margin: 0.75em; 14 | display: grid; 15 | width: fit-content; 16 | } 17 | 18 | .rope-cell { 19 | height: 100%; 20 | width: 100%; 21 | display: flex; 22 | & > span { 23 | margin: auto; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/app/solutions2022/components/rope-bridge-visualizer/rope-bridge-visualizer.component.ts: -------------------------------------------------------------------------------- 1 | import { AfterViewInit, Component, ElementRef, OnInit } from '@angular/core'; 2 | import { BaseResultComponent } from 'src/app/helper/components/base-result.component'; 3 | import { Point2D } from 'src/app/helper/util-functions/point'; 4 | import { RopeMove } from '../../day9.service'; 5 | 6 | @Component({ 7 | selector: 'aoc-rope-bridge-visualizer', 8 | templateUrl: './rope-bridge-visualizer.component.html', 9 | styleUrls: ['./rope-bridge-visualizer.component.scss'], 10 | }) 11 | export class RopeBridgeVisualizerComponent 12 | extends BaseResultComponent 13 | implements OnInit, AfterViewInit 14 | { 15 | currentIdx: number = 0; 16 | 17 | headMoves!: { move: RopeMove; position: Point2D }[]; 18 | knotsMoves!: Point2D[][]; 19 | minX!: number; 20 | maxX!: number; 21 | minY!: number; 22 | maxY!: number; 23 | 24 | squareWidth: number = 5; 25 | 26 | get move(): RopeMove { 27 | return this.headMoves[this.currentIdx].move; 28 | } 29 | 30 | get head(): Point2D { 31 | return this.headMoves[this.currentIdx].position; 32 | } 33 | 34 | get tail(): Point2D { 35 | return this.knotsMoves.slice(-1)[0][this.currentIdx]; 36 | } 37 | 38 | get tailTrail(): Point2D[] { 39 | return this.knotsMoves.slice(-1)[0].slice(0, this.currentIdx + 1); 40 | } 41 | 42 | get body(): Point2D[] { 43 | return this.knotsMoves 44 | .slice(0, -1) 45 | .map((knotMoves) => knotMoves[this.currentIdx]); 46 | } 47 | 48 | get gridRepeatStyle(): object { 49 | return { 50 | 'grid-template-columns': `repeat(${this.minX + this.maxX + 1}, ${ 51 | this.squareWidth 52 | }px)`, 53 | 'grid-template-rows': `repeat(${this.minY + this.maxY + 1}, ${ 54 | this.squareWidth 55 | }px)`, 56 | }; 57 | } 58 | 59 | constructor(private el: ElementRef) { 60 | super(); 61 | } 62 | 63 | ngOnInit(): void { 64 | this.headMoves = this.data.headMoves as { 65 | move: RopeMove; 66 | position: Point2D; 67 | }[]; 68 | this.knotsMoves = this.data.knotsMoves as Point2D[][]; 69 | 70 | this.minX = -1 * Math.min(...this.headMoves.map((m) => m.position.x)); 71 | this.maxX = Math.max(...this.headMoves.map((m) => m.position.x)); 72 | this.minY = -1 * Math.min(...this.headMoves.map((m) => m.position.y)); 73 | this.maxY = Math.max(...this.headMoves.map((m) => m.position.y)); 74 | } 75 | 76 | ngAfterViewInit(): void { 77 | this.squareWidth = 78 | this.el.nativeElement.offsetWidth / ((this.minX + this.maxX + 1) * 2); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/app/solutions2022/components/snafu-numbers-visualizer/snafu-numbers-visualizer.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
7 | {{ snafuNumber }} => 8 | {{ parsedNumbers[i] }} 9 |
10 |
11 | 12 |
13 | {{ finalNumber }} = {{ factoredSnafuNumber }} = 14 | {{ finalSnafuNumber }} 15 |
16 |
17 | -------------------------------------------------------------------------------- /src/app/solutions2022/components/snafu-numbers-visualizer/snafu-numbers-visualizer.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: block; 3 | width: 100%; 4 | } 5 | 6 | .grid-wrapper { 7 | display: flex; 8 | flex-direction: column; 9 | justify-content: center; 10 | align-items: center; 11 | } 12 | 13 | .grid { 14 | display: grid; 15 | grid-template-columns: repeat(8, 1fr); 16 | column-gap: 0.5em; 17 | row-gap: 0.5em; 18 | } 19 | 20 | .grid-cell { 21 | justify-self: center; 22 | } 23 | -------------------------------------------------------------------------------- /src/app/solutions2022/components/snafu-numbers-visualizer/snafu-numbers-visualizer.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { BaseResultComponent } from '../../../helper/components/base-result.component'; 3 | 4 | @Component({ 5 | selector: 'aoc-snafu-numbers-visualizer', 6 | templateUrl: './snafu-numbers-visualizer.component.html', 7 | styleUrls: ['./snafu-numbers-visualizer.component.scss'], 8 | }) 9 | export class SnafuNumbersVisualizerComponent 10 | extends BaseResultComponent 11 | implements OnInit 12 | { 13 | snafuNumbers!: string[]; 14 | parsedNumbers!: number[]; 15 | finalNumber!: number; 16 | finalSnafuNumber!: string; 17 | 18 | get factoredSnafuNumber(): string { 19 | return this.finalSnafuNumber 20 | .split('') 21 | .reverse() 22 | .map( 23 | (char, idx) => 24 | `${char.replace('-', '-1').replace('=', '-2')} * 5^${idx}` 25 | ) 26 | .reverse() 27 | .join(' + '); 28 | } 29 | 30 | ngOnInit(): void { 31 | this.snafuNumbers = this.data.snafuNumbers as string[]; 32 | this.parsedNumbers = this.data.parsedNumbers as number[]; 33 | this.finalNumber = this.data.finalNumber as number; 34 | this.finalSnafuNumber = this.data.finalSnafuNumber as string; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/app/solutions2022/day1.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { PlotlyGraphComponent } from '../helper/components/plotly-graph/plotly-graph.component'; 3 | import { BaseSolutionService } from '../helper/services/base-solution.service'; 4 | import { 5 | ISolutionService, 6 | PuzzleResult, 7 | } from '../helper/services/isolution.service'; 8 | import { SolutionsCollectorService } from '../helper/services/solutions-collector.service'; 9 | import { parseIntoNumbers } from '../helper/util-functions/parse-into-numbers'; 10 | import { sumNumbers } from '../helper/util-functions/sum'; 11 | 12 | @Injectable({ 13 | providedIn: 'root', 14 | }) 15 | export class Day1Service 16 | extends BaseSolutionService 17 | implements ISolutionService 18 | { 19 | constructor(solutionsCollectorService: SolutionsCollectorService) { 20 | super(solutionsCollectorService, 2022, 1, 'Calorie Counting'); 21 | } 22 | override solvePart1(input: string): PuzzleResult { 23 | var groups = input.split('\n\n').map(parseIntoNumbers); 24 | var intakes = groups.map(sumNumbers); 25 | var result = Math.max(...intakes); 26 | return { 27 | result: result, 28 | component: PlotlyGraphComponent, 29 | componentData: { 30 | graphData: [ 31 | { 32 | x: intakes.map((val, idx) => idx + 1), 33 | y: intakes, 34 | type: 'bar', 35 | marker: { color: '#fad02c' }, 36 | }, 37 | ], 38 | graphLayout: { 39 | yaxis: { title: 'Calories sum' }, 40 | xaxis: { title: 'Elf', automargin: true }, 41 | }, 42 | }, 43 | }; 44 | } 45 | override solvePart2(input: string): PuzzleResult { 46 | var groups = input.split('\n\n').map(parseIntoNumbers); 47 | var intakes = groups 48 | .map(sumNumbers) 49 | .map((val, idx) => [val, idx + 1]) 50 | .sort((a, b) => (a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0)); 51 | 52 | var triple_intakes = intakes.slice(0, -2).map((val, idx) => { 53 | var sub_arr = intakes.slice(idx, idx + 3); 54 | return [ 55 | sub_arr.reduce((acc, cur) => { 56 | return acc + cur[0]; 57 | }, 0), 58 | sub_arr.map((x) => x[1]).join(' + '), 59 | ]; 60 | }); 61 | 62 | return { 63 | result: triple_intakes.slice(-1)[0][0], 64 | component: PlotlyGraphComponent, 65 | componentData: { 66 | graphData: [ 67 | { 68 | x: triple_intakes.map((val) => val[1]), 69 | y: triple_intakes.map((val) => val[0]), 70 | type: 'bar', 71 | marker: { color: '#fad02c' }, 72 | }, 73 | ], 74 | graphLayout: { 75 | yaxis: { title: 'Calories sum' }, 76 | xaxis: { title: 'Elf', type: 'category', automargin: true }, 77 | }, 78 | }, 79 | }; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/app/solutions2022/day25.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { PlotlyGraphComponent } from '../helper/components/plotly-graph/plotly-graph.component'; 3 | import { BaseSolutionService } from '../helper/services/base-solution.service'; 4 | import { 5 | ISolutionService, 6 | PuzzleResult, 7 | } from '../helper/services/isolution.service'; 8 | import { SolutionsCollectorService } from '../helper/services/solutions-collector.service'; 9 | import { splitIntoLines } from '../helper/util-functions/split-into-lines'; 10 | import { SnafuNumbersVisualizerComponent } from './components/snafu-numbers-visualizer/snafu-numbers-visualizer.component'; 11 | 12 | function fromSNAFU(value: string): number { 13 | return value 14 | .split('') 15 | .reverse() 16 | .map((char, idx) => { 17 | var base = Math.pow(5, idx); 18 | switch (char) { 19 | case '=': 20 | return base * -2; 21 | case '-': 22 | return base * -1; 23 | default: 24 | return base * Number(char); 25 | } 26 | }) 27 | .sum(); 28 | } 29 | 30 | // Inspired by u/ai_prof 31 | // https://www.reddit.com/r/adventofcode/comments/zur1an/comment/j1qmqf1/ 32 | function toSNAFU(value: number): string { 33 | if (value == 0) return ''; 34 | 35 | var quotient = Math.floor(value / 5); 36 | switch (value % 5) { 37 | case 3: 38 | return toSNAFU(1 + quotient) + '='; 39 | case 4: 40 | return toSNAFU(1 + quotient) + '-'; 41 | default: 42 | return toSNAFU(quotient) + (value % 5).toString(); 43 | } 44 | } 45 | 46 | @Injectable({ 47 | providedIn: 'root', 48 | }) 49 | export class Day25Service 50 | extends BaseSolutionService 51 | implements ISolutionService 52 | { 53 | constructor(solutionsCollectorService: SolutionsCollectorService) { 54 | super(solutionsCollectorService, 2022, 25, 'Full of Hot Air'); 55 | } 56 | override solvePart1(input: string): PuzzleResult { 57 | var lines = splitIntoLines(input, true); 58 | var numbers = lines.map(fromSNAFU); 59 | var numbersSum = numbers.sum(); 60 | var snafuNumber = toSNAFU(numbersSum); 61 | return { 62 | result: snafuNumber, 63 | component: SnafuNumbersVisualizerComponent, 64 | componentData: { 65 | snafuNumbers: lines, 66 | parsedNumbers: numbers, 67 | finalNumber: numbersSum, 68 | finalSnafuNumber: snafuNumber, 69 | }, 70 | }; 71 | } 72 | override solvePart2(input: string): number { 73 | return 0; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/app/solutions2022/day4.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { PlotlyGraphComponent } from '../helper/components/plotly-graph/plotly-graph.component'; 3 | import { BaseSolutionService } from '../helper/services/base-solution.service'; 4 | import { 5 | ISolutionService, 6 | PuzzleResult, 7 | } from '../helper/services/isolution.service'; 8 | import { SolutionsCollectorService } from '../helper/services/solutions-collector.service'; 9 | import { splitIntoLines } from '../helper/util-functions/split-into-lines'; 10 | import { CampSectionsVisualizerComponent } from './components/camp-sections-visualizer/camp-sections-visualizer.component'; 11 | 12 | export class Sections { 13 | protected elf1Start: number; 14 | protected elf1End: number; 15 | protected elf2Start: number; 16 | protected elf2End: number; 17 | 18 | constructor(inputLine: string) { 19 | var parts = inputLine.split(','); 20 | var elf1Range = parts[0].split('-').map(Number); 21 | var elf2Range = parts[1].split('-').map(Number); 22 | 23 | this.elf1Start = elf1Range[0]; 24 | this.elf1End = elf1Range[1]; 25 | 26 | this.elf2Start = elf2Range[0]; 27 | this.elf2End = elf2Range[1]; 28 | } 29 | 30 | get ranges(): [number[], number[]] { 31 | return [ 32 | Array.range(this.elf1Start, this.elf1End + 1), 33 | Array.range(this.elf2Start, this.elf2End + 1), 34 | ]; 35 | } 36 | 37 | get isTotalOverlap(): boolean { 38 | return ( 39 | (this.elf1Start <= this.elf2Start && this.elf1End >= this.elf2End) || 40 | (this.elf2Start <= this.elf1Start && this.elf2End >= this.elf1End) 41 | ); 42 | } 43 | 44 | get overlapLength(): number { 45 | var ranges = this.ranges; 46 | var frequency = ranges[0] 47 | .concat(ranges[1]) 48 | .reduce(function (acc: { [item: number]: number }, curr: number) { 49 | return acc[curr] ? ++acc[curr] : (acc[curr] = 1), acc; 50 | }, {}); 51 | return Object.entries(frequency).filter(([key, value]) => value > 1).length; 52 | } 53 | } 54 | 55 | @Injectable({ 56 | providedIn: 'root', 57 | }) 58 | export class Day4Service 59 | extends BaseSolutionService 60 | implements ISolutionService 61 | { 62 | constructor(solutionsCollectorService: SolutionsCollectorService) { 63 | super(solutionsCollectorService, 2022, 4, 'Camp Cleanup'); 64 | } 65 | override solvePart1(input: string): PuzzleResult { 66 | var sections = splitIntoLines(input).map((line) => new Sections(line)); 67 | return { 68 | result: sections.filter((x) => x.isTotalOverlap).length, 69 | component: CampSectionsVisualizerComponent, 70 | componentData: { 71 | sections: sections.map((section) => section.ranges), 72 | }, 73 | }; 74 | } 75 | override solvePart2(input: string): PuzzleResult { 76 | var sections = splitIntoLines(input).map((line) => new Sections(line)); 77 | var overlaps = sections.map((x) => x.overlapLength); 78 | var overlapsFrequency = overlaps.reduce(function ( 79 | acc: { [item: number]: number }, 80 | curr: number 81 | ) { 82 | return acc[curr] ? ++acc[curr] : (acc[curr] = 1), acc; 83 | }, 84 | {}); 85 | return { 86 | result: overlaps.filter((x) => x > 0).length, 87 | component: PlotlyGraphComponent, 88 | componentData: { 89 | graphData: [ 90 | { 91 | x: Object.entries(overlapsFrequency).map(([key, value]) => key), 92 | y: Object.entries(overlapsFrequency).map(([key, value]) => value), 93 | type: 'bar', 94 | marker: { color: '#fad02c' }, 95 | }, 96 | ], 97 | graphLayout: { 98 | yaxis: { title: 'Count' }, 99 | xaxis: { title: 'Overlap size', automargin: true }, 100 | }, 101 | }, 102 | }; 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/app/solutions2022/day6.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { PlotlyGraphComponent } from '../helper/components/plotly-graph/plotly-graph.component'; 3 | import { BaseSolutionService } from '../helper/services/base-solution.service'; 4 | import { 5 | ISolutionService, 6 | PuzzleResult, 7 | } from '../helper/services/isolution.service'; 8 | import { SolutionsCollectorService } from '../helper/services/solutions-collector.service'; 9 | import { splitIntoLines } from '../helper/util-functions/split-into-lines'; 10 | import { DatastreamBufferVisualizerComponent } from './components/datastream-buffer-visualizer/datastream-buffer-visualizer.component'; 11 | 12 | function findStartOfPacket(message: string, markerLength: number): number { 13 | return ( 14 | message 15 | .split('') 16 | .findIndex( 17 | (buffer, idx) => 18 | new Set(message.slice(idx, idx + markerLength)).size === markerLength 19 | ) + markerLength 20 | ); 21 | } 22 | 23 | @Injectable({ 24 | providedIn: 'root', 25 | }) 26 | export class Day6Service 27 | extends BaseSolutionService 28 | implements ISolutionService 29 | { 30 | constructor(solutionsCollectorService: SolutionsCollectorService) { 31 | super(solutionsCollectorService, 2022, 6, 'Tuning Trouble'); 32 | } 33 | override solvePart1(input: string): PuzzleResult { 34 | var datastreamBuffer = splitIntoLines(input)[0]; 35 | var result = findStartOfPacket(datastreamBuffer, 4); 36 | return { 37 | result: result, 38 | component: DatastreamBufferVisualizerComponent, 39 | componentData: { 40 | index: result, 41 | message: datastreamBuffer, 42 | packetLength: 4, 43 | }, 44 | }; 45 | } 46 | override solvePart2(input: string): PuzzleResult { 47 | var datastreamBuffer = splitIntoLines(input)[0]; 48 | var result = findStartOfPacket(datastreamBuffer, 14); 49 | return { 50 | result: result, 51 | component: DatastreamBufferVisualizerComponent, 52 | componentData: { 53 | index: result, 54 | message: datastreamBuffer, 55 | packetLength: 14, 56 | }, 57 | }; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/app/solutions2022/web-workers/day16.worker.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import '../../helper/util-functions/extensions'; 3 | import { findBestValveOpeningMoves } from '../helper/day16'; 4 | 5 | addEventListener('message', async ({ data }) => { 6 | var idx = data[0]; 7 | var move = data[1]; 8 | console.log('Worker start', idx); 9 | var bestPotentialMoves = findBestValveOpeningMoves( 10 | data[2], 11 | data[3], 12 | data[4], 13 | data[5], 14 | undefined, 15 | { value: -1, higherValue: idx } 16 | ); 17 | postMessage({ move, bestPotentialMoves }); 18 | }); 19 | -------------------------------------------------------------------------------- /src/app/solutions2022/web-workers/day19.worker.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import '../../helper/util-functions/extensions'; 3 | import { evaluateBlueprint } from '../helper/day19'; 4 | 5 | addEventListener('message', async ({ data }) => { 6 | console.log('Worker start', data[0].id); 7 | var { materials, robots } = evaluateBlueprint(data[0], data[1], data[2]); 8 | postMessage({ blueprint: data[0], materials, robots }); 9 | }); 10 | -------------------------------------------------------------------------------- /src/app/template/solution-template.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { PlotlyGraphComponent } from '../helper/components/plotly-graph/plotly-graph.component'; 3 | import { BaseSolutionService } from '../helper/services/base-solution.service'; 4 | import { 5 | ISolutionService, 6 | PuzzleResult, 7 | } from '../helper/services/isolution.service'; 8 | import { SolutionsCollectorService } from '../helper/services/solutions-collector.service'; 9 | 10 | @Injectable({ 11 | providedIn: 'root', 12 | }) 13 | export class Day0Service 14 | extends BaseSolutionService 15 | implements ISolutionService 16 | { 17 | constructor(solutionsCollectorService: SolutionsCollectorService) { 18 | super(solutionsCollectorService, 2020, 0, 'template'); 19 | } 20 | override solvePart1( 21 | input: string 22 | ): 23 | | string 24 | | number 25 | | PuzzleResult 26 | | Promise 27 | | Promise 28 | | Promise { 29 | return { 30 | result: 0, 31 | component: PlotlyGraphComponent, 32 | componentData: { 33 | graphData: [], 34 | graphLayout: {}, 35 | }, 36 | }; 37 | } 38 | override solvePart2( 39 | input: string 40 | ): 41 | | string 42 | | number 43 | | PuzzleResult 44 | | Promise 45 | | Promise 46 | | Promise { 47 | return { 48 | result: 0, 49 | component: PlotlyGraphComponent, 50 | componentData: { 51 | graphData: [], 52 | graphLayout: {}, 53 | }, 54 | }; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaczeQ/AdventOfCodeAngular/d0a64b2f29a94ea0818e8873aecfb1827f1cfb5a/src/assets/.gitkeep -------------------------------------------------------------------------------- /src/assets/inputs/2021/1.txt: -------------------------------------------------------------------------------- 1 | 199 2 | 200 3 | 208 4 | 210 5 | 200 6 | 207 7 | 240 8 | 269 9 | 260 10 | 263 11 | -------------------------------------------------------------------------------- /src/assets/inputs/2021/10.txt: -------------------------------------------------------------------------------- 1 | [({(<(())[]>[[{[]{<()<>> 2 | [(()[<>])]({[<{<<[]>>( 3 | {([(<{}[<>[]}>{[]{[(<()> 4 | (((({<>}<{<{<>}{[]{[]{} 5 | [[<[([]))<([[{}[[()]]] 6 | [{[{({}]{}}([{[{{{}}([] 7 | {<[[]]>}<{[{[{[]{()[[[] 8 | [<(<(<(<{}))><([]([]() 9 | <{([([[(<>()){}]>(<<{{ 10 | <{([{{}}[<[[[<>{}]]]>[]] 11 | -------------------------------------------------------------------------------- /src/assets/inputs/2021/11.txt: -------------------------------------------------------------------------------- 1 | 5483143223 2 | 2745854711 3 | 5264556173 4 | 6141336146 5 | 6357385478 6 | 4167524645 7 | 2176841721 8 | 6882881134 9 | 4846848554 10 | 5283751526 11 | -------------------------------------------------------------------------------- /src/assets/inputs/2021/12.txt: -------------------------------------------------------------------------------- 1 | start-A 2 | start-b 3 | A-c 4 | A-b 5 | b-d 6 | A-end 7 | b-end 8 | -------------------------------------------------------------------------------- /src/assets/inputs/2021/13.txt: -------------------------------------------------------------------------------- 1 | 6,10 2 | 0,14 3 | 9,10 4 | 0,3 5 | 10,4 6 | 4,11 7 | 6,0 8 | 6,12 9 | 4,1 10 | 0,13 11 | 10,12 12 | 3,4 13 | 3,0 14 | 8,4 15 | 1,10 16 | 2,14 17 | 8,10 18 | 9,0 19 | 20 | fold along y=7 21 | fold along x=5 22 | -------------------------------------------------------------------------------- /src/assets/inputs/2021/14.txt: -------------------------------------------------------------------------------- 1 | NNCB 2 | 3 | CH -> B 4 | HH -> N 5 | CB -> H 6 | NH -> C 7 | HB -> C 8 | HC -> B 9 | HN -> C 10 | NN -> C 11 | BH -> H 12 | NC -> B 13 | NB -> B 14 | BN -> B 15 | BB -> N 16 | BC -> B 17 | CC -> N 18 | CN -> C 19 | -------------------------------------------------------------------------------- /src/assets/inputs/2021/15.txt: -------------------------------------------------------------------------------- 1 | 1163751742 2 | 1381373672 3 | 2136511328 4 | 3694931569 5 | 7463417111 6 | 1319128137 7 | 1359912421 8 | 3125421639 9 | 1293138521 10 | 2311944581 11 | -------------------------------------------------------------------------------- /src/assets/inputs/2021/16.txt: -------------------------------------------------------------------------------- 1 | 9C0141080250320F1802104A08 2 | -------------------------------------------------------------------------------- /src/assets/inputs/2021/17.txt: -------------------------------------------------------------------------------- 1 | target area: x=20..30, y=-10..-5 2 | -------------------------------------------------------------------------------- /src/assets/inputs/2021/18.txt: -------------------------------------------------------------------------------- 1 | [[[0,[5,8]],[[1,7],[9,6]]],[[4,[1,2]],[[1,4],2]]] 2 | [[[5,[2,8]],4],[5,[[9,9],0]]] 3 | [6,[[[6,2],[5,6]],[[7,6],[4,7]]]] 4 | [[[6,[0,7]],[0,9]],[4,[9,[9,0]]]] 5 | [[[7,[6,4]],[3,[1,3]]],[[[5,5],1],9]] 6 | [[6,[[7,3],[3,2]]],[[[3,8],[5,7]],4]] 7 | [[[[5,4],[7,7]],8],[[8,3],8]] 8 | [[9,3],[[9,9],[6,[4,9]]]] 9 | [[2,[[7,7],7]],[[5,8],[[9,3],[0,2]]]] 10 | [[[[5,2],5],[8,[3,7]]],[[5,[7,5]],[4,4]]] 11 | -------------------------------------------------------------------------------- /src/assets/inputs/2021/19.txt: -------------------------------------------------------------------------------- 1 | --- scanner 0 --- 2 | 404,-588,-901 3 | 528,-643,409 4 | -838,591,734 5 | 390,-675,-793 6 | -537,-823,-458 7 | -485,-357,347 8 | -345,-311,381 9 | -661,-816,-575 10 | -876,649,763 11 | -618,-824,-621 12 | 553,345,-567 13 | 474,580,667 14 | -447,-329,318 15 | -584,868,-557 16 | 544,-627,-890 17 | 564,392,-477 18 | 455,729,728 19 | -892,524,684 20 | -689,845,-530 21 | 423,-701,434 22 | 7,-33,-71 23 | 630,319,-379 24 | 443,580,662 25 | -789,900,-551 26 | 459,-707,401 27 | 28 | --- scanner 1 --- 29 | 686,422,578 30 | 605,423,415 31 | 515,917,-361 32 | -336,658,858 33 | 95,138,22 34 | -476,619,847 35 | -340,-569,-846 36 | 567,-361,727 37 | -460,603,-452 38 | 669,-402,600 39 | 729,430,532 40 | -500,-761,534 41 | -322,571,750 42 | -466,-666,-811 43 | -429,-592,574 44 | -355,545,-477 45 | 703,-491,-529 46 | -328,-685,520 47 | 413,935,-424 48 | -391,539,-444 49 | 586,-435,557 50 | -364,-763,-893 51 | 807,-499,-711 52 | 755,-354,-619 53 | 553,889,-390 54 | 55 | --- scanner 2 --- 56 | 649,640,665 57 | 682,-795,504 58 | -784,533,-524 59 | -644,584,-595 60 | -588,-843,648 61 | -30,6,44 62 | -674,560,763 63 | 500,723,-460 64 | 609,671,-379 65 | -555,-800,653 66 | -675,-892,-343 67 | 697,-426,-610 68 | 578,704,681 69 | 493,664,-388 70 | -671,-858,530 71 | -667,343,800 72 | 571,-461,-707 73 | -138,-166,112 74 | -889,563,-600 75 | 646,-828,498 76 | 640,759,510 77 | -630,509,768 78 | -681,-892,-333 79 | 673,-379,-804 80 | -742,-814,-386 81 | 577,-820,562 82 | 83 | --- scanner 3 --- 84 | -589,542,597 85 | 605,-692,669 86 | -500,565,-823 87 | -660,373,557 88 | -458,-679,-417 89 | -488,449,543 90 | -626,468,-788 91 | 338,-750,-386 92 | 528,-832,-391 93 | 562,-778,733 94 | -938,-730,414 95 | 543,643,-506 96 | -524,371,-870 97 | 407,773,750 98 | -104,29,83 99 | 378,-903,-323 100 | -778,-728,485 101 | 426,699,580 102 | -438,-605,-362 103 | -469,-447,-387 104 | 509,732,623 105 | 647,635,-688 106 | -868,-804,481 107 | 614,-800,639 108 | 595,780,-596 109 | 110 | --- scanner 4 --- 111 | 727,592,562 112 | -293,-554,779 113 | 441,611,-461 114 | -714,465,-776 115 | -743,427,-804 116 | -660,-479,-426 117 | 832,-632,460 118 | 927,-485,-438 119 | 408,393,-506 120 | 466,436,-512 121 | 110,16,151 122 | -258,-428,682 123 | -393,719,612 124 | -211,-452,876 125 | 808,-476,-593 126 | -575,615,604 127 | -485,667,467 128 | -680,325,-822 129 | -627,-443,-432 130 | 872,-547,-609 131 | 833,512,582 132 | 807,604,487 133 | 839,-516,451 134 | 891,-625,532 135 | -652,-548,-490 136 | 30,-46,-14 137 | -------------------------------------------------------------------------------- /src/assets/inputs/2021/2.txt: -------------------------------------------------------------------------------- 1 | forward 5 2 | down 5 3 | forward 8 4 | up 3 5 | down 8 6 | forward 2 7 | -------------------------------------------------------------------------------- /src/assets/inputs/2021/20.txt: -------------------------------------------------------------------------------- 1 | ..#.#..#####.#.#.#.###.##.....###.##.#..###.####..#####..#....#..#..##..###..######.###...####..#..#####..##..#.#####...##.#.#..#.##..#.#......#.###.######.###.####...#.##.##..#..#..#####.....#.#....###..#.##......#.....#..#..#..##..#...##.######.####.####.#.#...#.......#..#.#.#...####.##.#......#..#...##.#.##..#...##.#.##..###.#......#.#.......#.#.#.####.###.##...#.....####.#..#..#.##.#....##..#.####....##...##..#...#......#.#.......#.......##..####..#...#.#.#...##..#.#..###..#####........#..####......#..# 2 | 3 | #..#. 4 | #.... 5 | ##..# 6 | ..#.. 7 | ..### 8 | -------------------------------------------------------------------------------- /src/assets/inputs/2021/21.txt: -------------------------------------------------------------------------------- 1 | Player 1 starting position: 4 2 | Player 2 starting position: 8 3 | -------------------------------------------------------------------------------- /src/assets/inputs/2021/22.txt: -------------------------------------------------------------------------------- 1 | on x=-5..47,y=-31..22,z=-19..33 2 | on x=-44..5,y=-27..21,z=-14..35 3 | on x=-49..-1,y=-11..42,z=-10..38 4 | on x=-20..34,y=-40..6,z=-44..1 5 | off x=26..39,y=40..50,z=-2..11 6 | on x=-41..5,y=-41..6,z=-36..8 7 | off x=-43..-33,y=-45..-28,z=7..25 8 | on x=-33..15,y=-32..19,z=-34..11 9 | off x=35..47,y=-46..-34,z=-11..5 10 | on x=-14..36,y=-6..44,z=-16..29 11 | on x=-57795..-6158,y=29564..72030,z=20435..90618 12 | on x=36731..105352,y=-21140..28532,z=16094..90401 13 | on x=30999..107136,y=-53464..15513,z=8553..71215 14 | on x=13528..83982,y=-99403..-27377,z=-24141..23996 15 | on x=-72682..-12347,y=18159..111354,z=7391..80950 16 | on x=-1060..80757,y=-65301..-20884,z=-103788..-16709 17 | on x=-83015..-9461,y=-72160..-8347,z=-81239..-26856 18 | on x=-52752..22273,y=-49450..9096,z=54442..119054 19 | on x=-29982..40483,y=-108474..-28371,z=-24328..38471 20 | on x=-4958..62750,y=40422..118853,z=-7672..65583 21 | on x=55694..108686,y=-43367..46958,z=-26781..48729 22 | on x=-98497..-18186,y=-63569..3412,z=1232..88485 23 | on x=-726..56291,y=-62629..13224,z=18033..85226 24 | on x=-110886..-34664,y=-81338..-8658,z=8914..63723 25 | on x=-55829..24974,y=-16897..54165,z=-121762..-28058 26 | on x=-65152..-11147,y=22489..91432,z=-58782..1780 27 | on x=-120100..-32970,y=-46592..27473,z=-11695..61039 28 | on x=-18631..37533,y=-124565..-50804,z=-35667..28308 29 | on x=-57817..18248,y=49321..117703,z=5745..55881 30 | on x=14781..98692,y=-1341..70827,z=15753..70151 31 | on x=-34419..55919,y=-19626..40991,z=39015..114138 32 | on x=-60785..11593,y=-56135..2999,z=-95368..-26915 33 | on x=-32178..58085,y=17647..101866,z=-91405..-8878 34 | on x=-53655..12091,y=50097..105568,z=-75335..-4862 35 | on x=-111166..-40997,y=-71714..2688,z=5609..50954 36 | on x=-16602..70118,y=-98693..-44401,z=5197..76897 37 | on x=16383..101554,y=4615..83635,z=-44907..18747 38 | off x=-95822..-15171,y=-19987..48940,z=10804..104439 39 | on x=-89813..-14614,y=16069..88491,z=-3297..45228 40 | on x=41075..99376,y=-20427..49978,z=-52012..13762 41 | on x=-21330..50085,y=-17944..62733,z=-112280..-30197 42 | on x=-16478..35915,y=36008..118594,z=-7885..47086 43 | off x=-98156..-27851,y=-49952..43171,z=-99005..-8456 44 | off x=2032..69770,y=-71013..4824,z=7471..94418 45 | on x=43670..120875,y=-42068..12382,z=-24787..38892 46 | off x=37514..111226,y=-45862..25743,z=-16714..54663 47 | off x=25699..97951,y=-30668..59918,z=-15349..69697 48 | off x=-44271..17935,y=-9516..60759,z=49131..112598 49 | on x=-61695..-5813,y=40978..94975,z=8655..80240 50 | off x=-101086..-9439,y=-7088..67543,z=33935..83858 51 | off x=18020..114017,y=-48931..32606,z=21474..89843 52 | off x=-77139..10506,y=-89994..-18797,z=-80..59318 53 | off x=8476..79288,y=-75520..11602,z=-96624..-24783 54 | on x=-47488..-1262,y=24338..100707,z=16292..72967 55 | off x=-84341..13987,y=2429..92914,z=-90671..-1318 56 | off x=-37810..49457,y=-71013..-7894,z=-105357..-13188 57 | off x=-27365..46395,y=31009..98017,z=15428..76570 58 | off x=-70369..-16548,y=22648..78696,z=-1892..86821 59 | on x=-53470..21291,y=-120233..-33476,z=-44150..38147 60 | off x=-93533..-4276,y=-16170..68771,z=-104985..-24507 61 | -------------------------------------------------------------------------------- /src/assets/inputs/2021/23.txt: -------------------------------------------------------------------------------- 1 | ############# 2 | #...........# 3 | ###B#C#B#D### 4 | #A#D#C#A# 5 | ######### 6 | -------------------------------------------------------------------------------- /src/assets/inputs/2021/24.txt: -------------------------------------------------------------------------------- 1 | inp w 2 | mul x 0 3 | add x z 4 | mod x 26 5 | div z 1 6 | add x 10 7 | eql x w 8 | eql x 0 9 | mul y 0 10 | add y 25 11 | mul y x 12 | add y 1 13 | mul z y 14 | mul y 0 15 | add y w 16 | add y 2 17 | mul y x 18 | add z y 19 | inp w 20 | mul x 0 21 | add x z 22 | mod x 26 23 | div z 1 24 | add x 14 25 | eql x w 26 | eql x 0 27 | mul y 0 28 | add y 25 29 | mul y x 30 | add y 1 31 | mul z y 32 | mul y 0 33 | add y w 34 | add y 13 35 | mul y x 36 | add z y 37 | inp w 38 | mul x 0 39 | add x z 40 | mod x 26 41 | div z 1 42 | add x 14 43 | eql x w 44 | eql x 0 45 | mul y 0 46 | add y 25 47 | mul y x 48 | add y 1 49 | mul z y 50 | mul y 0 51 | add y w 52 | add y 13 53 | mul y x 54 | add z y 55 | inp w 56 | mul x 0 57 | add x z 58 | mod x 26 59 | div z 26 60 | add x -13 61 | eql x w 62 | eql x 0 63 | mul y 0 64 | add y 25 65 | mul y x 66 | add y 1 67 | mul z y 68 | mul y 0 69 | add y w 70 | add y 9 71 | mul y x 72 | add z y 73 | inp w 74 | mul x 0 75 | add x z 76 | mod x 26 77 | div z 1 78 | add x 10 79 | eql x w 80 | eql x 0 81 | mul y 0 82 | add y 25 83 | mul y x 84 | add y 1 85 | mul z y 86 | mul y 0 87 | add y w 88 | add y 15 89 | mul y x 90 | add z y 91 | inp w 92 | mul x 0 93 | add x z 94 | mod x 26 95 | div z 26 96 | add x -13 97 | eql x w 98 | eql x 0 99 | mul y 0 100 | add y 25 101 | mul y x 102 | add y 1 103 | mul z y 104 | mul y 0 105 | add y w 106 | add y 3 107 | mul y x 108 | add z y 109 | inp w 110 | mul x 0 111 | add x z 112 | mod x 26 113 | div z 26 114 | add x -7 115 | eql x w 116 | eql x 0 117 | mul y 0 118 | add y 25 119 | mul y x 120 | add y 1 121 | mul z y 122 | mul y 0 123 | add y w 124 | add y 6 125 | mul y x 126 | add z y 127 | inp w 128 | mul x 0 129 | add x z 130 | mod x 26 131 | div z 1 132 | add x 11 133 | eql x w 134 | eql x 0 135 | mul y 0 136 | add y 25 137 | mul y x 138 | add y 1 139 | mul z y 140 | mul y 0 141 | add y w 142 | add y 5 143 | mul y x 144 | add z y 145 | inp w 146 | mul x 0 147 | add x z 148 | mod x 26 149 | div z 1 150 | add x 10 151 | eql x w 152 | eql x 0 153 | mul y 0 154 | add y 25 155 | mul y x 156 | add y 1 157 | mul z y 158 | mul y 0 159 | add y w 160 | add y 16 161 | mul y x 162 | add z y 163 | inp w 164 | mul x 0 165 | add x z 166 | mod x 26 167 | div z 1 168 | add x 13 169 | eql x w 170 | eql x 0 171 | mul y 0 172 | add y 25 173 | mul y x 174 | add y 1 175 | mul z y 176 | mul y 0 177 | add y w 178 | add y 1 179 | mul y x 180 | add z y 181 | inp w 182 | mul x 0 183 | add x z 184 | mod x 26 185 | div z 26 186 | add x -4 187 | eql x w 188 | eql x 0 189 | mul y 0 190 | add y 25 191 | mul y x 192 | add y 1 193 | mul z y 194 | mul y 0 195 | add y w 196 | add y 6 197 | mul y x 198 | add z y 199 | inp w 200 | mul x 0 201 | add x z 202 | mod x 26 203 | div z 26 204 | add x -9 205 | eql x w 206 | eql x 0 207 | mul y 0 208 | add y 25 209 | mul y x 210 | add y 1 211 | mul z y 212 | mul y 0 213 | add y w 214 | add y 3 215 | mul y x 216 | add z y 217 | inp w 218 | mul x 0 219 | add x z 220 | mod x 26 221 | div z 26 222 | add x -13 223 | eql x w 224 | eql x 0 225 | mul y 0 226 | add y 25 227 | mul y x 228 | add y 1 229 | mul z y 230 | mul y 0 231 | add y w 232 | add y 7 233 | mul y x 234 | add z y 235 | inp w 236 | mul x 0 237 | add x z 238 | mod x 26 239 | div z 26 240 | add x -9 241 | eql x w 242 | eql x 0 243 | mul y 0 244 | add y 25 245 | mul y x 246 | add y 1 247 | mul z y 248 | mul y 0 249 | add y w 250 | add y 9 251 | mul y x 252 | add z y 253 | -------------------------------------------------------------------------------- /src/assets/inputs/2021/25.txt: -------------------------------------------------------------------------------- 1 | v...>>.vv> 2 | .vv>>.vv.. 3 | >>.>v>...v 4 | >>v>>.>.v. 5 | v>v.vv.v.. 6 | >.>>..v... 7 | .vv..>.>v. 8 | v.v..>>v.v 9 | ....v..v.> 10 | -------------------------------------------------------------------------------- /src/assets/inputs/2021/3.txt: -------------------------------------------------------------------------------- 1 | 00100 2 | 11110 3 | 10110 4 | 10111 5 | 10101 6 | 01111 7 | 00111 8 | 11100 9 | 10000 10 | 11001 11 | 00010 12 | 01010 13 | -------------------------------------------------------------------------------- /src/assets/inputs/2021/4.txt: -------------------------------------------------------------------------------- 1 | 7,4,9,5,11,17,23,2,0,14,21,24,10,16,13,6,15,25,12,22,18,20,8,19,3,26,1 2 | 3 | 22 13 17 11 0 4 | 8 2 23 4 24 5 | 21 9 14 16 7 6 | 6 10 3 18 5 7 | 1 12 20 15 19 8 | 9 | 3 15 0 2 22 10 | 9 18 13 17 5 11 | 19 8 7 25 23 12 | 20 11 10 24 4 13 | 14 21 16 12 6 14 | 15 | 14 21 17 24 4 16 | 10 16 15 9 19 17 | 18 8 23 26 20 18 | 22 11 13 6 5 19 | 2 0 12 3 7 20 | -------------------------------------------------------------------------------- /src/assets/inputs/2021/5.txt: -------------------------------------------------------------------------------- 1 | 0,9 -> 5,9 2 | 8,0 -> 0,8 3 | 9,4 -> 3,4 4 | 2,2 -> 2,1 5 | 7,0 -> 7,4 6 | 6,4 -> 2,0 7 | 0,9 -> 2,9 8 | 3,4 -> 1,4 9 | 0,0 -> 8,8 10 | 5,5 -> 8,2 11 | -------------------------------------------------------------------------------- /src/assets/inputs/2021/6.txt: -------------------------------------------------------------------------------- 1 | 3,4,3,1,2 2 | -------------------------------------------------------------------------------- /src/assets/inputs/2021/7.txt: -------------------------------------------------------------------------------- 1 | 16,1,2,0,4,2,7,1,2,14 2 | -------------------------------------------------------------------------------- /src/assets/inputs/2021/8.txt: -------------------------------------------------------------------------------- 1 | be cfbegad cbdgef fgaecd cgeb fdcge agebfd fecdb fabcd edb | fdgacbe cefdb cefbgd gcbe 2 | edbfga begcd cbg gc gcadebf fbgde acbgfd abcde gfcbed gfec | fcgedb cgb dgebacf gc 3 | fgaebd cg bdaec gdafb agbcfd gdcbef bgcad gfac gcb cdgabef | cg cg fdcagb cbg 4 | fbegcd cbd adcefb dageb afcb bc aefdc ecdab fgdeca fcdbega | efabcd cedba gadfec cb 5 | aecbfdg fbg gf bafeg dbefa fcge gcbea fcaegb dgceab fcbdga | gecf egdcabf bgf bfgea 6 | fgeab ca afcebg bdacfeg cfaedg gcfdb baec bfadeg bafgc acf | gebdcfa ecba ca fadegcb 7 | dbcfg fgd bdegcaf fgec aegbdf ecdfab fbedc dacgb gdcebf gf | cefg dcbef fcge gbcadfe 8 | bdfegc cbegaf gecbf dfcage bdacg ed bedf ced adcbefg gebcd | ed bcgafe cdgba cbgef 9 | egadfb cdbfeg cegd fecab cgb gbdefca cg fgcdab egfdb bfceg | gbdfcae bgc cg cgb 10 | gcafb gcf dcaebfg ecagb gf abcdeg gaef cafbge fdbac fegbdc | fgae cfgab fg bagce 11 | -------------------------------------------------------------------------------- /src/assets/inputs/2021/9.txt: -------------------------------------------------------------------------------- 1 | 2199943210 2 | 3987894921 3 | 9856789892 4 | 8767896789 5 | 9899965678 6 | -------------------------------------------------------------------------------- /src/assets/inputs/2022/1.txt: -------------------------------------------------------------------------------- 1 | 1000 2 | 2000 3 | 3000 4 | 5 | 4000 6 | 7 | 5000 8 | 6000 9 | 10 | 7000 11 | 8000 12 | 9000 13 | 14 | 10000 15 | -------------------------------------------------------------------------------- /src/assets/inputs/2022/10.txt: -------------------------------------------------------------------------------- 1 | addx 15 2 | addx -11 3 | addx 6 4 | addx -3 5 | addx 5 6 | addx -1 7 | addx -8 8 | addx 13 9 | addx 4 10 | noop 11 | addx -1 12 | addx 5 13 | addx -1 14 | addx 5 15 | addx -1 16 | addx 5 17 | addx -1 18 | addx 5 19 | addx -1 20 | addx -35 21 | addx 1 22 | addx 24 23 | addx -19 24 | addx 1 25 | addx 16 26 | addx -11 27 | noop 28 | noop 29 | addx 21 30 | addx -15 31 | noop 32 | noop 33 | addx -3 34 | addx 9 35 | addx 1 36 | addx -3 37 | addx 8 38 | addx 1 39 | addx 5 40 | noop 41 | noop 42 | noop 43 | noop 44 | noop 45 | addx -36 46 | noop 47 | addx 1 48 | addx 7 49 | noop 50 | noop 51 | noop 52 | addx 2 53 | addx 6 54 | noop 55 | noop 56 | noop 57 | noop 58 | noop 59 | addx 1 60 | noop 61 | noop 62 | addx 7 63 | addx 1 64 | noop 65 | addx -13 66 | addx 13 67 | addx 7 68 | noop 69 | addx 1 70 | addx -33 71 | noop 72 | noop 73 | noop 74 | addx 2 75 | noop 76 | noop 77 | noop 78 | addx 8 79 | noop 80 | addx -1 81 | addx 2 82 | addx 1 83 | noop 84 | addx 17 85 | addx -9 86 | addx 1 87 | addx 1 88 | addx -3 89 | addx 11 90 | noop 91 | noop 92 | addx 1 93 | noop 94 | addx 1 95 | noop 96 | noop 97 | addx -13 98 | addx -19 99 | addx 1 100 | addx 3 101 | addx 26 102 | addx -30 103 | addx 12 104 | addx -1 105 | addx 3 106 | addx 1 107 | noop 108 | noop 109 | noop 110 | addx -9 111 | addx 18 112 | addx 1 113 | addx 2 114 | noop 115 | noop 116 | addx 9 117 | noop 118 | noop 119 | noop 120 | addx -1 121 | addx 2 122 | addx -37 123 | addx 1 124 | addx 3 125 | noop 126 | addx 15 127 | addx -21 128 | addx 22 129 | addx -6 130 | addx 1 131 | noop 132 | addx 2 133 | addx 1 134 | noop 135 | addx -10 136 | noop 137 | noop 138 | addx 20 139 | addx 1 140 | addx 2 141 | addx 2 142 | addx -6 143 | addx -11 144 | noop 145 | noop 146 | noop 147 | -------------------------------------------------------------------------------- /src/assets/inputs/2022/11.txt: -------------------------------------------------------------------------------- 1 | Monkey 0: 2 | Starting items: 79, 98 3 | Operation: new = old * 19 4 | Test: divisible by 23 5 | If true: throw to monkey 2 6 | If false: throw to monkey 3 7 | 8 | Monkey 1: 9 | Starting items: 54, 65, 75, 74 10 | Operation: new = old + 6 11 | Test: divisible by 19 12 | If true: throw to monkey 2 13 | If false: throw to monkey 0 14 | 15 | Monkey 2: 16 | Starting items: 79, 60, 97 17 | Operation: new = old * old 18 | Test: divisible by 13 19 | If true: throw to monkey 1 20 | If false: throw to monkey 3 21 | 22 | Monkey 3: 23 | Starting items: 74 24 | Operation: new = old + 3 25 | Test: divisible by 17 26 | If true: throw to monkey 0 27 | If false: throw to monkey 1 28 | -------------------------------------------------------------------------------- /src/assets/inputs/2022/12.txt: -------------------------------------------------------------------------------- 1 | Sabqponm 2 | abcryxxl 3 | accszExk 4 | acctuvwj 5 | abdefghi 6 | -------------------------------------------------------------------------------- /src/assets/inputs/2022/13.txt: -------------------------------------------------------------------------------- 1 | [1,1,3,1,1] 2 | [1,1,5,1,1] 3 | 4 | [[1],[2,3,4]] 5 | [[1],4] 6 | 7 | [9] 8 | [[8,7,6]] 9 | 10 | [[4,4],4,4] 11 | [[4,4],4,4,4] 12 | 13 | [7,7,7,7] 14 | [7,7,7] 15 | 16 | [] 17 | [3] 18 | 19 | [[[]]] 20 | [[]] 21 | 22 | [1,[2,[3,[4,[5,6,7]]]],8,9] 23 | [1,[2,[3,[4,[5,6,0]]]],8,9] 24 | -------------------------------------------------------------------------------- /src/assets/inputs/2022/14.txt: -------------------------------------------------------------------------------- 1 | 498,4 -> 498,6 -> 496,6 2 | 503,4 -> 502,4 -> 502,9 -> 494,9 3 | -------------------------------------------------------------------------------- /src/assets/inputs/2022/15.txt: -------------------------------------------------------------------------------- 1 | Sensor at x=2, y=18: closest beacon is at x=-2, y=15 2 | Sensor at x=9, y=16: closest beacon is at x=10, y=16 3 | Sensor at x=13, y=2: closest beacon is at x=15, y=3 4 | Sensor at x=12, y=14: closest beacon is at x=10, y=16 5 | Sensor at x=10, y=20: closest beacon is at x=10, y=16 6 | Sensor at x=14, y=17: closest beacon is at x=10, y=16 7 | Sensor at x=8, y=7: closest beacon is at x=2, y=10 8 | Sensor at x=2, y=0: closest beacon is at x=2, y=10 9 | Sensor at x=0, y=11: closest beacon is at x=2, y=10 10 | Sensor at x=20, y=14: closest beacon is at x=25, y=17 11 | Sensor at x=17, y=20: closest beacon is at x=21, y=22 12 | Sensor at x=16, y=7: closest beacon is at x=15, y=3 13 | Sensor at x=14, y=3: closest beacon is at x=15, y=3 14 | Sensor at x=20, y=1: closest beacon is at x=15, y=3 15 | -------------------------------------------------------------------------------- /src/assets/inputs/2022/16.txt: -------------------------------------------------------------------------------- 1 | Valve AA has flow rate=0; tunnels lead to valves DD, II, BB 2 | Valve BB has flow rate=13; tunnels lead to valves CC, AA 3 | Valve CC has flow rate=2; tunnels lead to valves DD, BB 4 | Valve DD has flow rate=20; tunnels lead to valves CC, AA, EE 5 | Valve EE has flow rate=3; tunnels lead to valves FF, DD 6 | Valve FF has flow rate=0; tunnels lead to valves EE, GG 7 | Valve GG has flow rate=0; tunnels lead to valves FF, HH 8 | Valve HH has flow rate=22; tunnel leads to valve GG 9 | Valve II has flow rate=0; tunnels lead to valves AA, JJ 10 | Valve JJ has flow rate=21; tunnel leads to valve II 11 | -------------------------------------------------------------------------------- /src/assets/inputs/2022/17.txt: -------------------------------------------------------------------------------- 1 | >>><<><>><<<>><>>><<<>>><<<><<<>><>><<>> 2 | -------------------------------------------------------------------------------- /src/assets/inputs/2022/18.txt: -------------------------------------------------------------------------------- 1 | 2,2,2 2 | 1,2,2 3 | 3,2,2 4 | 2,1,2 5 | 2,3,2 6 | 2,2,1 7 | 2,2,3 8 | 2,2,4 9 | 2,2,6 10 | 1,2,5 11 | 3,2,5 12 | 2,1,5 13 | 2,3,5 14 | -------------------------------------------------------------------------------- /src/assets/inputs/2022/19.txt: -------------------------------------------------------------------------------- 1 | Blueprint 1: Each ore robot costs 4 ore. Each clay robot costs 2 ore. Each obsidian robot costs 3 ore and 14 clay. Each geode robot costs 2 ore and 7 obsidian. 2 | Blueprint 2: Each ore robot costs 2 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 8 clay. Each geode robot costs 3 ore and 12 obsidian. 3 | -------------------------------------------------------------------------------- /src/assets/inputs/2022/2.txt: -------------------------------------------------------------------------------- 1 | A Y 2 | B X 3 | C Z 4 | -------------------------------------------------------------------------------- /src/assets/inputs/2022/20.txt: -------------------------------------------------------------------------------- 1 | 1 2 | 2 3 | -3 4 | 3 5 | -2 6 | 0 7 | 4 8 | -------------------------------------------------------------------------------- /src/assets/inputs/2022/21.txt: -------------------------------------------------------------------------------- 1 | root: pppw + sjmn 2 | dbpl: 5 3 | cczh: sllz + lgvd 4 | zczc: 2 5 | ptdq: humn - dvpt 6 | dvpt: 3 7 | lfqf: 4 8 | humn: 5 9 | ljgn: 2 10 | sjmn: drzm * dbpl 11 | sllz: 4 12 | pppw: cczh / lfqf 13 | lgvd: ljgn * ptdq 14 | drzm: hmdt - zczc 15 | hmdt: 32 16 | -------------------------------------------------------------------------------- /src/assets/inputs/2022/22.txt: -------------------------------------------------------------------------------- 1 | ...# 2 | .#.. 3 | #... 4 | .... 5 | ...#.......# 6 | ........#... 7 | ..#....#.... 8 | ..........#. 9 | ...#.... 10 | .....#.. 11 | .#...... 12 | ......#. 13 | 14 | 10R5L5R10L4R5L5 15 | -------------------------------------------------------------------------------- /src/assets/inputs/2022/23.txt: -------------------------------------------------------------------------------- 1 | ....#.. 2 | ..###.# 3 | #...#.# 4 | .#...## 5 | #.###.. 6 | ##.#.## 7 | .#..#.. 8 | -------------------------------------------------------------------------------- /src/assets/inputs/2022/24.txt: -------------------------------------------------------------------------------- 1 | #.###### 2 | #>>.<^<# 3 | #.<..<<# 4 | #>v.><># 5 | #<^v^^># 6 | ######.# 7 | -------------------------------------------------------------------------------- /src/assets/inputs/2022/25.txt: -------------------------------------------------------------------------------- 1 | 1=-0-2 2 | 12111 3 | 2=0= 4 | 21 5 | 2=01 6 | 111 7 | 20012 8 | 112 9 | 1=-1= 10 | 1-12 11 | 12 12 | 1= 13 | 122 14 | -------------------------------------------------------------------------------- /src/assets/inputs/2022/3.txt: -------------------------------------------------------------------------------- 1 | vJrwpWtwJgWrhcsFMMfFFhFp 2 | jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL 3 | PmmdzqPrVvPwwTWBwg 4 | wMqvLMZHhHMvwLHjbvcjnnSBnvTQFn 5 | ttgJtRGJQctTZtZT 6 | CrZsJsPPZsGzwwsLwLmpwMDw 7 | -------------------------------------------------------------------------------- /src/assets/inputs/2022/4.txt: -------------------------------------------------------------------------------- 1 | 2-4,6-8 2 | 2-3,4-5 3 | 5-7,7-9 4 | 2-8,3-7 5 | 6-6,4-6 6 | 2-6,4-8 7 | -------------------------------------------------------------------------------- /src/assets/inputs/2022/5.txt: -------------------------------------------------------------------------------- 1 | [D] 2 | [N] [C] 3 | [Z] [M] [P] 4 | 1 2 3 5 | 6 | move 1 from 2 to 1 7 | move 3 from 1 to 3 8 | move 2 from 2 to 1 9 | move 1 from 1 to 2 10 | -------------------------------------------------------------------------------- /src/assets/inputs/2022/6.txt: -------------------------------------------------------------------------------- 1 | mjqjpqmgbljsphdztnvjfqwrcgsmlb 2 | -------------------------------------------------------------------------------- /src/assets/inputs/2022/7.txt: -------------------------------------------------------------------------------- 1 | $ cd / 2 | $ ls 3 | dir a 4 | 14848514 b.txt 5 | 8504156 c.dat 6 | dir d 7 | $ cd a 8 | $ ls 9 | dir e 10 | 29116 f 11 | 2557 g 12 | 62596 h.lst 13 | $ cd e 14 | $ ls 15 | 584 i 16 | $ cd .. 17 | $ cd .. 18 | $ cd d 19 | $ ls 20 | 4060174 j 21 | 8033020 d.log 22 | 5626152 d.ext 23 | 7214296 k 24 | -------------------------------------------------------------------------------- /src/assets/inputs/2022/8.txt: -------------------------------------------------------------------------------- 1 | 30373 2 | 25512 3 | 65332 4 | 33549 5 | 35390 6 | -------------------------------------------------------------------------------- /src/assets/inputs/2022/9.txt: -------------------------------------------------------------------------------- 1 | R 5 2 | U 8 3 | L 8 4 | D 3 5 | R 17 6 | D 10 7 | L 25 8 | U 20 9 | -------------------------------------------------------------------------------- /src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false 7 | }; 8 | 9 | /* 10 | * For easier debugging in development mode, you can import the following file 11 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. 12 | * 13 | * This import should be commented out in production mode because it will have a negative impact 14 | * on performance if an error is thrown. 15 | */ 16 | // import 'zone.js/plugins/zone-error'; // Included with Angular CLI. 17 | -------------------------------------------------------------------------------- /src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaczeQ/AdventOfCodeAngular/d0a64b2f29a94ea0818e8873aecfb1827f1cfb5a/src/favicon.ico -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AdventOfCode 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | import './app/helper/util-functions/extensions'; 7 | 8 | if (environment.production) { 9 | enableProdMode(); 10 | } 11 | 12 | platformBrowserDynamic() 13 | .bootstrapModule(AppModule) 14 | .catch((err) => console.error(err)); 15 | -------------------------------------------------------------------------------- /src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file includes polyfills needed by Angular and is loaded before the app. 3 | * You can add your own extra polyfills to this file. 4 | * 5 | * This file is divided into 2 sections: 6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. 7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main 8 | * file. 9 | * 10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that 11 | * automatically update themselves. This includes recent versions of Safari, Chrome (including 12 | * Opera), Edge on the desktop, and iOS and Chrome on mobile. 13 | * 14 | * Learn more in https://angular.io/guide/browser-support 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** 22 | * By default, zone.js will patch all possible macroTask and DomEvents 23 | * user can disable parts of macroTask/DomEvents patch by setting following flags 24 | * because those flags need to be set before `zone.js` being loaded, and webpack 25 | * will put import in the top of bundle, so user need to create a separate file 26 | * in this directory (for example: zone-flags.ts), and put the following flags 27 | * into that file, and then add the following code before importing zone.js. 28 | * import './zone-flags'; 29 | * 30 | * The flags allowed in zone-flags.ts are listed here. 31 | * 32 | * The following flags will work for all browsers. 33 | * 34 | * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame 35 | * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick 36 | * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames 37 | * 38 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js 39 | * with the following flag, it will bypass `zone.js` patch for IE/Edge 40 | * 41 | * (window as any).__Zone_enable_cross_context_check = true; 42 | * 43 | */ 44 | 45 | /*************************************************************************************************** 46 | * Zone JS is required by default for Angular itself. 47 | */ 48 | import 'zone.js'; // Included with Angular CLI. 49 | 50 | 51 | /*************************************************************************************************** 52 | * APPLICATION IMPORTS 53 | */ 54 | -------------------------------------------------------------------------------- /src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | // First, initialize the Angular testing environment. 11 | getTestBed().initTestEnvironment( 12 | BrowserDynamicTestingModule, 13 | platformBrowserDynamicTesting(), 14 | ); 15 | -------------------------------------------------------------------------------- /tsconfig.app.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "./tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "./out-tsc/app", 6 | "types": [] 7 | }, 8 | "files": [ 9 | "src/main.ts", 10 | "src/polyfills.ts" 11 | ], 12 | "include": [ 13 | "src/**/*.d.ts" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "compileOnSave": false, 4 | "compilerOptions": { 5 | "baseUrl": "./", 6 | "outDir": "./dist/out-tsc", 7 | "forceConsistentCasingInFileNames": true, 8 | "strict": true, 9 | "noImplicitOverride": true, 10 | "noPropertyAccessFromIndexSignature": true, 11 | "noImplicitReturns": true, 12 | "noFallthroughCasesInSwitch": true, 13 | "sourceMap": true, 14 | "declaration": false, 15 | "downlevelIteration": true, 16 | "experimentalDecorators": true, 17 | "moduleResolution": "node", 18 | "importHelpers": true, 19 | "target": "ES2022", 20 | "module": "es2020", 21 | "lib": ["es2020", "dom"], 22 | "useDefineForClassFields": false, 23 | "allowJs": true 24 | }, 25 | "angularCompilerOptions": { 26 | "enableI18nLegacyMessageIdFormat": false, 27 | "strictInjectionParameters": true, 28 | "strictInputAccessModifiers": true, 29 | "strictTemplates": true 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "./tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "./out-tsc/spec", 6 | "types": [ 7 | "jasmine" 8 | ] 9 | }, 10 | "files": [ 11 | "src/test.ts", 12 | "src/polyfills.ts" 13 | ], 14 | "include": [ 15 | "src/**/*.spec.ts", 16 | "src/**/*.d.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /tsconfig.worker.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "./tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "./out-tsc/worker", 6 | "lib": [ 7 | "es2020", 8 | "webworker" 9 | ], 10 | "types": [] 11 | }, 12 | "include": [ 13 | "src/**/*.worker.ts" 14 | ] 15 | } 16 | --------------------------------------------------------------------------------