├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .github ├── badges │ └── completion.json └── workflows │ └── nodejs.yml ├── .gitignore ├── LICENSE ├── README.md ├── day-01-the-tyranny-of-the-rocket-equation ├── README.md ├── rocket.js ├── rocket2.js └── test.js ├── day-02-1202-program-alarm ├── README.md ├── alarm.js ├── alarm2.js └── test.js ├── day-03-crossed-wires ├── README.md ├── test.js ├── wires.js └── wires2.js ├── day-04-secure-container ├── README.md ├── secure.js ├── secure2.js └── test.js ├── day-05-sunny-with-a-chance-of-asteroids ├── README.md ├── asteroids.js ├── asteroids2.js └── test.js ├── day-06-universal-orbit-map ├── README.md ├── orbits.js ├── orbits2.js └── test.js ├── day-07-amplification-circuit ├── README.md ├── amplifier-controller.js ├── circuit.js ├── circuit2.js └── test.js ├── day-08-space-image-format ├── README.md ├── image.js ├── image2.js └── test.js ├── day-09-sensor-boost ├── README.md ├── intcode.js ├── sensor.js └── test.js ├── day-10-monitoring-station ├── README.md ├── station.js ├── station2.js └── test.js ├── day-11-space-police ├── README.md ├── intcode.js ├── robot.js └── robot2.js ├── day-12-the-n-body-problem ├── README.md ├── body.js ├── body2.js └── test.js ├── day-13-care-package ├── README.md ├── breakout.js ├── care.js ├── care2.js └── intcode.js ├── day-14-space-stoichiometry ├── README.md ├── fuel.js ├── fuel2.js └── test.js ├── day-15-oxygen-system ├── README.md ├── oxygen.js ├── oxygen2.js └── repairDroid.js ├── day-16-flawed-frequency-transmission ├── README.md ├── fft.js ├── fft2.js └── test.js ├── day-17-set-and-forget ├── README.md ├── ascii.js └── intcode.js ├── day-24-planet-of-discord ├── README.md ├── biodiversity.js └── test.js ├── package-lock.json └── package.json /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true; 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | input.js 2 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'env': { 3 | 'es6': true, 4 | 'node': true, 5 | 'mocha': true, 6 | }, 7 | 'extends': 'eslint:recommended', 8 | 'parserOptions': { 9 | 'sourceType': 'module', 10 | }, 11 | 'rules': { 12 | 'indent': ['error', 2, { 'SwitchCase': 1 }], 13 | 'quotes': [2, 'single'], 14 | 'semi': 2, 15 | }, 16 | }; 17 | -------------------------------------------------------------------------------- /.github/badges/completion.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": 1, 3 | "label": "completion", 4 | "message": "35/50", 5 | "color": "yellow" 6 | } 7 | -------------------------------------------------------------------------------- /.github/workflows/nodejs.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | strategy: 11 | matrix: 12 | node-version: [18.x] 13 | 14 | steps: 15 | - uses: actions/checkout@v1 16 | - name: Use Node.js ${{ matrix.node-version }} 17 | uses: actions/setup-node@v1 18 | with: 19 | node-version: ${{ matrix.node-version }} 20 | - name: npm install, lint, and test 21 | run: | 22 | npm ci 23 | npm run lint 24 | npm test 25 | env: 26 | CI: true 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | 3 | input.js 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Mario Tacke 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Advent of Code 2019 - My Solutions 2 | [![Build Status](https://github.com/mariotacke/advent-of-code-2019/workflows/build/badge.svg)](https://github.com/mariotacke/advent-of-code-2019/actions) 3 | [![Completion Status](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/mariotacke/advent-of-code-2019/master/.github/badges/completion.json)](https://github.com/mariotacke/advent-of-code-2019) 4 | ![Libraries.io dependency status for GitHub repo](https://img.shields.io/librariesio/github/mariotacke/advent-of-code-2019) 5 | [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/mariotacke/advent-of-code-2019/master/LICENSE) 6 | 7 | Santa has become stranded at the edge of the Solar System while delivering presents to other planets! To accurately calculate his position in space, safely align his warp drive, and return to Earth in time to save Christmas, he needs you to bring him measurements from **fifty stars**. 8 | 9 | Collect stars by solving puzzles. Two puzzles will be made available on each day in the Advent calendar; the second puzzle is unlocked when you complete the first. Each puzzle grants **one star**. Good luck! 10 | 11 | ## Days 12 | 13 | - [Day 1: The Tyranny of the Rocket Equation](day-01-the-tyranny-of-the-rocket-equation/) 14 | - [Day 2: 1202 Program Alarm](day-02-1202-program-alarm/) 15 | - [Day 3: Crossed Wires](day-03-crossed-wires/) 16 | - [Day 4: Secure Container](day-04-secure-container/) 17 | - [Day 5: Sunny with a Chance of Asteroids](day-05-sunny-with-a-chance-of-asteroids/) 18 | - [Day 6: Universal Orbit Map](day-06-universal-orbit-map/) 19 | - [Day 7: Amplification Circuit](day-07-amplification-circuit/) 20 | - [Day 8: Space Image Format](day-08-space-image-format/) 21 | - [Day 9: Sensor Boost](day-09-sensor-boost/) 22 | - [Day 10: Monitoring Station](day-10-monitoring-station/) 23 | - [Day 11: Space Police](day-11-space-police/) 24 | - [Day 12: The N-Body Problem](day-12-the-n-body-problem/) 25 | - [Day 13: Care Package](day-13-care-package/) 26 | - [Day 14: Space Stoichiometry](day-14-space-stoichiometry/) 27 | - [Day 15: Oxygen System](day-15-oxygen-system/) 28 | - [Day 16: Flawed Frequency Transmission](day-16-flawed-frequency-transmission/) 29 | - [Day 17: Set and Forget](day-17-set-and-forget/) 30 | - [Day 24: Planet of Discord](day-24-planet-of-discord/) 31 | 32 | ## Running Tests 33 | 34 | Each day contains its own set of tests. To run them type `npm test`. 35 | 36 | ## Previous Years 37 | - [![Completion Status](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/mariotacke/advent-of-code-2018/master/.github/badges/completion.json&label=2018)](https://github.com/mariotacke/advent-of-code-2018) 38 | - [![Completion Status](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/mariotacke/advent-of-code-2017/master/.github/badges/completion.json&label=2017)](https://github.com/mariotacke/advent-of-code-2017) 39 | - [![Completion Status](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/mariotacke/advent-of-code-2016/master/.github/badges/completion.json&label=2016)](https://github.com/mariotacke/advent-of-code-2016) 40 | - [![Completion Status](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/mariotacke/advent-of-code-2015/master/.github/badges/completion.json&label=2015)](https://github.com/mariotacke/advent-of-code-2015) 41 | 42 | ## Visit 43 | - http://adventofcode.com/2019 44 | -------------------------------------------------------------------------------- /day-01-the-tyranny-of-the-rocket-equation/README.md: -------------------------------------------------------------------------------- 1 | # Day 1: The Tyranny of the Rocket Equation 2 | 3 | The Elves quickly load you into a spacecraft and prepare to launch. 4 | 5 | At the first Go / No Go poll, every Elf is Go until the Fuel Counter-Upper. They haven't determined the amount of fuel required yet. 6 | 7 | Fuel required to launch a given **module** is based on its **mass**. Specifically, to find the fuel required for a module, take its mass, divide by three, round down, and subtract 2. 8 | 9 | For example: 10 | 11 | - For a mass of `12`, divide by 3 and round down to get `4`, then subtract 2 to get `2`. 12 | - For a mass of `14`, dividing by 3 and rounding down still yields `4`, so the fuel required is also `2`. 13 | - For a mass of `1969`, the fuel required is `654`. 14 | - For a mass of `100756`, the fuel required is `33583`. 15 | 16 | The Fuel Counter-Upper needs to know the total fuel requirement. To find it, individually calculate the fuel needed for the mass of each module (your puzzle input), then add together all the fuel values. 17 | 18 | **What is the sum of the fuel requirements** for all of the modules on your spacecraft? 19 | 20 | ## Part Two 21 | 22 | During the second Go / No Go poll, the Elf in charge of the Rocket Equation Double-Checker stops the launch sequence. Apparently, you forgot to include additional fuel for the fuel you just added. 23 | 24 | Fuel itself requires fuel just like a module - take its mass, divide by three, round down, and subtract 2. However, that fuel **also** requires fuel, and **that** fuel requires fuel, and so on. Any mass that would require **negative fuel** should instead be treated as if it requires **zero fuel**; the remaining mass, if any, is instead handled by **wishing really hard**, which has no mass and is outside the scope of this calculation. 25 | 26 | So, for each module mass, calculate its fuel and add it to the total. Then, treat the fuel amount you just calculated as the input mass and repeat the process, continuing until a fuel requirement is zero or negative. For example: 27 | 28 | - A module of mass `14` requires `2` fuel. This fuel requires no further fuel (2 divided by 3 and rounded down is `0`, which would call for a negative fuel), so the total fuel required is still just `2`. 29 | - At first, a module of mass `1969` requires `654` fuel. Then, this fuel requires `216` more fuel (`654 / 3 - 2`). `216` then requires `70` more fuel, which requires `21` fuel, which requires `5` fuel, which requires no further fuel. So, the total fuel required for a module of mass `1969` is `654 + 216 + 70 + 21 + 5 = 966`. 30 | - The fuel required by a module of mass `100756` and its fuel is: `33583 + 11192 + 3728 + 1240 + 411 + 135 + 43 + 12 + 2 = 50346`. 31 | 32 | **What is the sum of the fuel requirements** for all of the modules on your spacecraft when also taking into account the mass of the added fuel? (Calculate the fuel requirements for each module separately, then add them all up at the end.) 33 | 34 | ## References 35 | - https://adventofcode.com/2019/day/1 36 | -------------------------------------------------------------------------------- /day-01-the-tyranny-of-the-rocket-equation/rocket.js: -------------------------------------------------------------------------------- 1 | module.exports = (input) => { 2 | return input 3 | .split('\n') 4 | .map((line) => parseInt(line)) 5 | .reduce((a, b) => Math.floor(b / 3) - 2 + a, 0); 6 | }; 7 | -------------------------------------------------------------------------------- /day-01-the-tyranny-of-the-rocket-equation/rocket2.js: -------------------------------------------------------------------------------- 1 | module.exports = (input) => { 2 | return input 3 | .split('\n') 4 | .map((line) => parseInt(line)) 5 | .map((initialMass) => { 6 | let totalFuel = 0; 7 | let remainingMass = initialMass; 8 | 9 | while (remainingMass > 0) { 10 | const fuel = Math.floor(remainingMass / 3) - 2; 11 | 12 | if (fuel <= 0) { 13 | break; 14 | } 15 | 16 | totalFuel += fuel; 17 | remainingMass = fuel; 18 | } 19 | 20 | return totalFuel; 21 | }) 22 | .reduce((a, b) => a + b, 0); 23 | }; 24 | -------------------------------------------------------------------------------- /day-01-the-tyranny-of-the-rocket-equation/test.js: -------------------------------------------------------------------------------- 1 | const assert = require('assert'); 2 | 3 | const rocket = require('./rocket'); 4 | const rocket2 = require('./rocket2'); 5 | 6 | describe('Day 1: The Tyranny of the Rocket Equation', () => { 7 | it('should calculate fuel requirements for module mass 12', () => { 8 | assert.strictEqual(rocket('12'), 2); 9 | }); 10 | 11 | it('should calculate fuel requirements for module mass 14', () => { 12 | assert.strictEqual(rocket('14'), 2); 13 | }); 14 | 15 | it('should calculate fuel requirements for module mass 1969', () => { 16 | assert.strictEqual(rocket('1969'), 654); 17 | }); 18 | 19 | it('should calculate fuel requirements for module mass 100756', () => { 20 | assert.strictEqual(rocket('100756'), 33583); 21 | }); 22 | 23 | describe('Part Two', () => { 24 | it('should calculate fuel requirements for module mass 14', () => { 25 | assert.strictEqual(rocket2('14'), 2); 26 | }); 27 | 28 | it('should calculate fuel requirements for module mass 1969', () => { 29 | assert.strictEqual(rocket2('1969'), 966); 30 | }); 31 | 32 | it('should calculate fuel requirements for module mass 100756', () => { 33 | assert.strictEqual(rocket2('100756'), 50346); 34 | }); 35 | }); 36 | }); 37 | -------------------------------------------------------------------------------- /day-02-1202-program-alarm/README.md: -------------------------------------------------------------------------------- 1 | # Day 2: 1202 Program Alarm 2 | 3 | On the way to your [gravity assist](https://en.wikipedia.org/wiki/Gravity_assist) around the Moon, your ship computer beeps angrily about a "[1202 program alarm](https://www.hq.nasa.gov/alsj/a11/a11.landing.html#1023832)". On the radio, an Elf is already explaining how to handle the situation: "Don't worry, that's perfectly norma--" The ship computer [bursts into flames](https://en.wikipedia.org/wiki/Halt_and_Catch_Fire). 4 | 5 | You notify the Elves that the computer's [magic smoke](https://en.wikipedia.org/wiki/Magic_smoke) seems to have escaped. "That computer ran **Intcode** programs like the gravity assist program it was working on; surely there are enough spare parts up there to build a new Intcode computer!" 6 | 7 | An Intcode program is a list of [integers](https://en.wikipedia.org/wiki/Integer) separated by commas (like `1,0,0,3,99`). To run one, start by looking at the first integer (called position `0`). Here, you will find an **opcode** - either `1`, `2`, or `99`. The opcode indicates what to do; for example, `99` means that the program is finished and should immediately halt. Encountering an unknown opcode means something went wrong. 8 | 9 | Opcode `1` **adds** together numbers read from two positions and stores the result in a third position. The three integers **immediately after** the opcode tell you these three positions - the first two indicate the **positions** from which you should read the input values, and the third indicates the **position** at which the output should be stored. 10 | 11 | For example, if your Intcode computer encounters `1,10,20,30`, it should read the values at positions `10` and `20`, add those values, and then overwrite the value at position `30` with their sum. 12 | 13 | Opcode `2` works exactly like opcode `1`, except it **multiplies** the two inputs instead of adding them. Again, the three integers after the opcode indicate **where** the inputs and outputs are, not their values. 14 | 15 | Once you're done processing an opcode, **move to the next one** by stepping forward `4` positions. 16 | 17 | For example, suppose you have the following program: 18 | ``` 19 | 1,9,10,3,2,3,11,0,99,30,40,50` 20 | ``` 21 | 22 | For the purposes of illustration, here is the same program split into multiple lines: 23 | ``` 24 | 1,9,10,3, 25 | 2,3,11,0, 26 | 99, 27 | 30,40,50 28 | ``` 29 | 30 | The first four integers, `1,9,10,3`, are at positions `0`, `1`, `2`, and `3`. Together, they represent the first opcode (`1`, addition), the positions of the two inputs (`9` and `10`), and the position of the output (`3`). To handle this opcode, you first need to get the values at the input positions: position `9` contains `30`, and position `10` contains `40`. Add these numbers together to get `70`. Then, store this value at the output position; here, the output position `(3`) is **at** position `3`, so it overwrites itself. Afterward, the program looks like this: 31 | ``` 32 | 1,9,10,70, 33 | 2,3,11,0, 34 | 99, 35 | 30,40,50 36 | ``` 37 | 38 | Step forward `4` positions to reach the next opcode, `2`. This opcode works just like the previous, but it multiplies instead of adding. The inputs are at positions `3` and `11`; these positions contain `70` and `50` respectively. Multiplying these produces `3500`; this is stored at position `0`: 39 | 40 | ``` 41 | 3500,9,10,70, 42 | 2,3,11,0, 43 | 99, 44 | 30,40,50 45 | ``` 46 | 47 | Stepping forward `4` more positions arrives at opcode `99`, halting the program. 48 | 49 | Here are the initial and final states of a few more small programs: 50 | 51 | - `1,0,0,0,99` becomes `2,0,0,0,99` (`1 + 1 = 2`). 52 | - `2,3,0,3,99` becomes `2,3,0,6,99` (`3 * 2 = 6`). 53 | - `2,4,4,5,99,0` becomes `2,4,4,5,99,9801` (`99 * 99 = 9801`). 54 | - `1,1,1,4,99,5,6,0,99` becomes `30,1,1,4,2,5,6,0,99`. 55 | 56 | Once you have a working computer, the first step is to restore the gravity assist program (your puzzle input) to the "1202 program alarm" state it had just before the last computer caught fire. To do this, **before running the program**, replace position `1` with the value `12` and replace position `2` with the value `2`. **What value is left at position `0`** after the program halts? 57 | 58 | ## Part Two 59 | 60 | "Good, the new computer seems to be working correctly! **Keep it nearby** during this mission - you'll probably use it again. Real Intcode computers support many more features than your new one, but we'll let you know what they are as you need them." 61 | 62 | "However, your current priority should be to complete your gravity assist around the Moon. For this mission to succeed, we should settle on some terminology for the parts you've already built." 63 | 64 | Intcode programs are given as a list of integers; these values are used as the initial state for the computer's **memory**. When you run an Intcode program, make sure to start by initializing memory to the program's values. A position in memory is called an **address** (for example, the first value in memory is at "address 0"). 65 | 66 | Opcodes (like `1`, `2`, or `99`) mark the beginning of an **instruction**. The values used immediately after an opcode, if any, are called the instruction's **parameters**. For example, in the instruction `1,2,3,4`, `1` is the opcode; `2`, `3`, and `4` are the parameters. The instruction `99` contains only an opcode and has no parameters. 67 | 68 | The address of the current instruction is called the **instruction pointer**; it starts at `0`. After an instruction finishes, the instruction pointer increases by **the number of values in the instruction**; until you add more instructions to the computer, this is always `4` (`1` opcode + `3` parameters) for the add and multiply instructions. (The halt instruction would increase the instruction pointer by `1`, but it halts the program instead.) 69 | 70 | "With terminology out of the way, we're ready to proceed. To complete the gravity assist, you need to **determine what pair of inputs produces the output `19690720`**." 71 | 72 | The inputs should still be provided to the program by replacing the values at addresses `1` and `2`, just like before. In this program, the value placed in address `1` is called the **noun**, and the value placed in address `2` is called the **verb**. Each of the two input values will be between 0 and 99, inclusive. 73 | 74 | Once the program has halted, its output is available at address `0`, also just like before. Each time you try a pair of inputs, make sure you first **reset the computer's memory to the values in the program** (your puzzle input) - in other words, don't reuse memory from a previous attempt. 75 | 76 | Find the input **noun** and **verb** that cause the program to produce the output `19690720`. **What is `100 * noun + verb`?** (For example, if `noun=12` and `verb=2`, the answer would be `1202`.) 77 | 78 | ## References 79 | - https://adventofcode.com/2019/day/2 80 | -------------------------------------------------------------------------------- /day-02-1202-program-alarm/alarm.js: -------------------------------------------------------------------------------- 1 | module.exports = (input, overrides = []) => { 2 | const intcodes = input 3 | .split(',') 4 | .map(Number); 5 | 6 | let position = 0; 7 | 8 | if (overrides.length) { 9 | intcodes[1] = overrides[0]; 10 | intcodes[2] = overrides[1]; 11 | } 12 | 13 | while (intcodes[position] !== 99) { 14 | const opcode = intcodes[position]; 15 | const input1 = intcodes[intcodes[position + 1]]; 16 | const input2 = intcodes[intcodes[position + 2]]; 17 | const output = intcodes[position + 3]; 18 | 19 | if (opcode === 1) { 20 | intcodes[output] = input1 + input2; 21 | } else if (opcode === 2) { 22 | intcodes[output] = input1 * input2; 23 | } 24 | 25 | position += 4; 26 | } 27 | 28 | return intcodes; 29 | }; 30 | -------------------------------------------------------------------------------- /day-02-1202-program-alarm/alarm2.js: -------------------------------------------------------------------------------- 1 | module.exports = (input, output = 19690720) => { 2 | const initialMemoryState = input 3 | .split(',') 4 | .map(Number); 5 | 6 | for (let noun = 0; noun < 100; noun++) { 7 | for (let verb = 0; verb < 100; verb++) { 8 | const memory = [...initialMemoryState]; 9 | 10 | let instructionPointer = 0; 11 | 12 | memory[1] = noun; 13 | memory[2] = verb; 14 | 15 | while (memory[instructionPointer] !== 99) { 16 | const opcode = memory[instructionPointer]; 17 | const parameter1 = memory[memory[instructionPointer + 1]]; 18 | const parameter2 = memory[memory[instructionPointer + 2]]; 19 | const parameter3 = memory[instructionPointer + 3]; 20 | 21 | if (opcode === 1) { 22 | memory[parameter3] = parameter1 + parameter2; 23 | } else if (opcode === 2) { 24 | memory[parameter3] = parameter1 * parameter2; 25 | } 26 | 27 | instructionPointer += 4; 28 | } 29 | 30 | if (memory[0] === output) { 31 | return 100 * noun + verb; 32 | } 33 | } 34 | } 35 | }; 36 | -------------------------------------------------------------------------------- /day-02-1202-program-alarm/test.js: -------------------------------------------------------------------------------- 1 | const assert = require('assert'); 2 | 3 | const alarm = require('./alarm'); 4 | 5 | describe('Day 2: 1202 Program Alarm', () => { 6 | it('should interpret Intcode 1,9,10,3,2,3,11,0,99,30,40,50', () => { 7 | assert.strictEqual(alarm('1,9,10,3,2,3,11,0,99,30,40,50')[0], 3500); 8 | }); 9 | 10 | it('should interpret Intcode 1,0,0,0,99', () => { 11 | assert.strictEqual(alarm('1,0,0,0,99')[0], 2); 12 | }); 13 | 14 | it('should interpret Intcode 2,3,0,3,99', () => { 15 | assert.strictEqual(alarm('2,3,0,3,99')[3], 6); 16 | }); 17 | 18 | it('should interpret Intcode 2,4,4,5,99,0', () => { 19 | assert.strictEqual(alarm('2,4,4,5,99,0')[5], 9801); 20 | }); 21 | 22 | it('should interpret Intcode 1,1,1,4,99,5,6,0,99', () => { 23 | assert.deepStrictEqual(alarm('1,1,1,4,99,5,6,0,99'), [30, 1, 1, 4, 2, 5, 6, 0, 99]); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /day-03-crossed-wires/README.md: -------------------------------------------------------------------------------- 1 | # Day 3: Crossed Wires 2 | 3 | The gravity assist was successful, and you're well on your way to the Venus refuelling station. During the rush back on Earth, the fuel management system wasn't completely installed, so that's next on the priority list. 4 | 5 | Opening the front panel reveals a jumble of wires. Specifically, **two wires** are connected to a central port and extend outward on a grid. You trace the path each wire takes as it leaves the central port, one wire per line of text (your puzzle input). 6 | 7 | The wires twist and turn, but the two wires occasionally cross paths. To fix the circuit, you need to **find the intersection point closest to the central port**. Because the wires are on a grid, use the [Manhattan distance](https://en.wikipedia.org/wiki/Taxicab_geometry) for this measurement. While the wires do technically cross right at the central port where they both start, this point does not count, nor does a wire count as crossing with itself. 8 | 9 | For example, if the first wire's path is `R8,U5,L5,D3`, then starting from the central port (`o`), it goes right `8`, up `5`, left `5`, and finally down `3`: 10 | ``` 11 | ........... 12 | ........... 13 | ........... 14 | ....+----+. 15 | ....|....|. 16 | ....|....|. 17 | ....|....|. 18 | .........|. 19 | .o-------+. 20 | ........... 21 | ``` 22 | 23 | Then, if the second wire's path is `U7,R6,D4,L4`, it goes up `7`, right `6`, down `4`, and left `4`: 24 | ``` 25 | ........... 26 | .+-----+... 27 | .|.....|... 28 | .|..+--X-+. 29 | .|..|..|.|. 30 | .|.-X--+.|. 31 | .|..|....|. 32 | .|.......|. 33 | .o-------+. 34 | ........... 35 | ``` 36 | 37 | These wires cross at two locations (marked `X`), but the lower-left one is closer to the central port: its distance is `3 + 3 = 6`. 38 | 39 | Here are a few more examples: 40 | 41 | - ``` 42 | R75,D30,R83,U83,L12,D49,R71,U7,L72 43 | U62,R66,U55,R34,D71,R55,D58,R83 = distance 159 44 | ``` 45 | - ``` 46 | R98,U47,R26,D63,R33,U87,L62,D20,R33,U53,R51 47 | U98,R91,D20,R16,D67,R40,U7,R15,U6,R7 = distance 135 48 | ``` 49 | 50 | **What is the Manhattan distance** from the central port to the closest intersection? 51 | 52 | ## Part Two 53 | 54 | It turns out that this circuit is very timing-sensitive; you actually need to **minimize the signal delay**. 55 | 56 | To do this, calculate the **number of steps** each wire takes to reach each intersection; choose the intersection where the **sum of both wires' steps** is lowest. If a wire visits a position on the grid multiple times, use the steps value from the **first** time it visits that position when calculating the total value of a specific intersection. 57 | 58 | The number of steps a wire takes is the total number of grid squares the wire has entered to get to that location, including the intersection being considered. Again consider the example from above: 59 | ``` 60 | ........... 61 | .+-----+... 62 | .|.....|... 63 | .|..+--X-+. 64 | .|..|..|.|. 65 | .|.-X--+.|. 66 | .|..|....|. 67 | .|.......|. 68 | .o-------+. 69 | ........... 70 | ``` 71 | 72 | In the above example, the intersection closest to the central port is reached after `8+5+5+2 = 20` steps by the first wire and `7+6+4+3 = 20` steps by the second wire for a total of `20+20 = 40` steps. 73 | 74 | However, the top-right intersection is better: the first wire takes only `8+5+2 = 15` and the second wire takes only `7+6+2 = 15`, a total of `15+15 = 30` steps. 75 | 76 | Here are the best steps for the extra examples from above: 77 | 78 | - ``` 79 | R75,D30,R83,U83,L12,D49,R71,U7,L72 80 | U62,R66,U55,R34,D71,R55,D58,R83 = 610 steps 81 | ``` 82 | - ``` 83 | R98,U47,R26,D63,R33,U87,L62,D20,R33,U53,R51 84 | U98,R91,D20,R16,D67,R40,U7,R15,U6,R7 = 410 steps 85 | ``` 86 | 87 | **What is the fewest combined steps the wires must take to reach an intersection?** 88 | 89 | ## References 90 | - https://adventofcode.com/2019/day/3 91 | -------------------------------------------------------------------------------- /day-03-crossed-wires/test.js: -------------------------------------------------------------------------------- 1 | const assert = require('assert'); 2 | 3 | const wires = require('./wires'); 4 | const wires2 = require('./wires2'); 5 | 6 | describe('Day 3: Crossed Wires', () => { 7 | it('should find closest intersection of wires', () => { 8 | let input = 9 | `R8,U5,L5,D3 10 | U7,R6,D4,L4`; 11 | 12 | assert.strictEqual(wires(input), 6); 13 | 14 | input = 15 | `R75,D30,R83,U83,L12,D49,R71,U7,L72 16 | U62,R66,U55,R34,D71,R55,D58,R83`; 17 | 18 | assert.strictEqual(wires(input), 159); 19 | 20 | input = 21 | `R98,U47,R26,D63,R33,U87,L62,D20,R33,U53,R51 22 | U98,R91,D20,R16,D67,R40,U7,R15,U6,R7`; 23 | 24 | assert.strictEqual(wires(input), 135); 25 | }); 26 | 27 | describe('Part Two', () => { 28 | it('should find fewest combined steps to reach intersection', () => { 29 | let input = 30 | `R8,U5,L5,D3 31 | U7,R6,D4,L4`; 32 | 33 | assert.strictEqual(wires2(input), 30); 34 | 35 | input = 36 | `R75,D30,R83,U83,L12,D49,R71,U7,L72 37 | U62,R66,U55,R34,D71,R55,D58,R83`; 38 | 39 | assert.strictEqual(wires2(input), 610); 40 | 41 | input = 42 | `R98,U47,R26,D63,R33,U87,L62,D20,R33,U53,R51 43 | U98,R91,D20,R16,D67,R40,U7,R15,U6,R7`; 44 | 45 | assert.strictEqual(wires2(input), 410); 46 | }); 47 | }); 48 | }); 49 | -------------------------------------------------------------------------------- /day-03-crossed-wires/wires.js: -------------------------------------------------------------------------------- 1 | const getWirePositions = (wire) => { 2 | const positions = new Set(); 3 | const position = { x: 0, y: 0 }; 4 | 5 | for (let i = 0; i < wire.length; i++) { 6 | const { direction, distance } = wire[i]; 7 | 8 | for (let step = 1; step <= distance; step++) { 9 | position.x += direction === 'L' ? -1 : direction === 'R' ? 1 : 0; 10 | position.y += direction === 'U' ? -1 : direction === 'D' ? 1 : 0; 11 | 12 | positions.add(`${position.x},${position.y}`); 13 | } 14 | } 15 | 16 | return positions; 17 | }; 18 | 19 | module.exports = (input) => { 20 | const wires = input 21 | .split('\n') 22 | .map((wire) => { 23 | return wire 24 | .trim() 25 | .split(',') 26 | .map((instruction) => { 27 | return { 28 | direction: instruction[0], 29 | distance: Number(instruction.slice(1)), 30 | }; 31 | }); 32 | }); 33 | 34 | const wire1Positions = getWirePositions(wires[0]); 35 | const wire2Positions = [...getWirePositions(wires[1])]; 36 | 37 | return wire2Positions 38 | .filter((position) => wire1Positions.has(position)) 39 | .map((position) => position.split(',').map(Number)) 40 | .map(([x, y]) => Math.abs(x) + Math.abs(y)) 41 | .sort((a, b) => a - b)[0]; 42 | }; 43 | -------------------------------------------------------------------------------- /day-03-crossed-wires/wires2.js: -------------------------------------------------------------------------------- 1 | const getWirePositions = (wire) => { 2 | const positions = new Map(); 3 | const position = { x: 0, y: 0 }; 4 | 5 | let length = 0; 6 | 7 | for (let i = 0; i < wire.length; i++) { 8 | const { direction, distance } = wire[i]; 9 | 10 | for (let step = 1; step <= distance; step++) { 11 | position.x += direction === 'L' ? -1 : direction === 'R' ? 1 : 0; 12 | position.y += direction === 'U' ? -1 : direction === 'D' ? 1 : 0; 13 | 14 | positions.set(`${position.x},${position.y}`, ++length); 15 | } 16 | } 17 | 18 | return positions; 19 | }; 20 | 21 | module.exports = (input) => { 22 | const wires = input 23 | .split('\n') 24 | .map((wire) => { 25 | return wire 26 | .trim() 27 | .split(',') 28 | .map((instruction) => { 29 | return { 30 | direction: instruction[0], 31 | distance: Number(instruction.slice(1)), 32 | }; 33 | }); 34 | }); 35 | 36 | const wire1Positions = getWirePositions(wires[0]); 37 | const wire2Positions = [...getWirePositions(wires[1]).entries()]; 38 | 39 | return wire2Positions 40 | .filter(([position]) => wire1Positions.has(position)) 41 | .map(([position, steps]) => wire1Positions.get(position) + steps) 42 | .sort((a, b) => a - b)[0]; 43 | }; 44 | -------------------------------------------------------------------------------- /day-04-secure-container/README.md: -------------------------------------------------------------------------------- 1 | # Day 4: Secure Container 2 | 3 | You arrive at the Venus fuel depot only to discover it's protected by a password. The Elves had written the password on a sticky note, but someone threw it out. 4 | 5 | However, they do remember a few key facts about the password: 6 | 7 | - It is a six-digit number. 8 | - The value is within the range given in your puzzle input. 9 | - Two adjacent digits are the same (like `22` in `122345`). 10 | - Going from left to right, the digits **never decrease**; they only ever increase or stay the same (like `111123` or `135679`). 11 | 12 | Other than the range rule, the following are true: 13 | 14 | - `111111` meets these criteria (double `11`, never decreases). 15 | - `223450` does not meet these criteria (decreasing pair of digits `50`). 16 | - `123789` does not meet these criteria (no double). 17 | 18 | **How many different passwords** within the range given in your puzzle input meet these criteria? 19 | 20 | ## Part Two 21 | 22 | An Elf just remembered one more important detail: the two adjacent matching digits **are not part of a larger group of matching digits**. 23 | 24 | Given this additional criterion, but still ignoring the range rule, the following are now true: 25 | 26 | - `112233` meets these criteria because the digits never decrease and all repeated digits are exactly two digits long. 27 | - `123444` no longer meets the criteria (the repeated `44` is part of a larger group of `444`). 28 | - `111122` meets the criteria (even though `1` is repeated more than twice, it still contains a double `22`). 29 | 30 | **How many different passwords** within the range given in your puzzle input meet all of the criteria? 31 | 32 | ## References 33 | - https://adventofcode.com/2019/day/4 34 | -------------------------------------------------------------------------------- /day-04-secure-container/secure.js: -------------------------------------------------------------------------------- 1 | const isValid = (password) => { 2 | let twoAdjacent = false; 3 | let onlyIncreasing = true; 4 | 5 | for (let i = 0; i < password.length; i++) { 6 | if (password[i] === password[i + 1]) { 7 | twoAdjacent = true; 8 | } 9 | 10 | if (Number(password[i]) > Number(password[i + 1])) { 11 | onlyIncreasing = false; 12 | } 13 | } 14 | 15 | return twoAdjacent && onlyIncreasing; 16 | }; 17 | 18 | module.exports = (input) => { 19 | const range = input.split('-').map(Number); 20 | 21 | let counter = 0; 22 | 23 | for (let i = range[0]; i <= range[1]; i++) { 24 | if (isValid(`${i}`)) { 25 | counter++; 26 | } 27 | } 28 | 29 | return counter; 30 | }; 31 | -------------------------------------------------------------------------------- /day-04-secure-container/secure2.js: -------------------------------------------------------------------------------- 1 | const isValid = (password) => { 2 | let twoAdjacent = false; 3 | let onlyIncreasing = true; 4 | 5 | for (let i = 0; i < password.length; i++) { 6 | const previousDigit = password[i - 1]; 7 | const digit = password[i]; 8 | const nextDigit = password[i + 1]; 9 | const digitAfterNext = password[i + 2]; 10 | 11 | if (previousDigit !== digit && digit === nextDigit && digit !== digitAfterNext) { 12 | twoAdjacent = true; 13 | } 14 | 15 | if (Number(digit) > Number(nextDigit)) { 16 | onlyIncreasing = false; 17 | } 18 | } 19 | 20 | return twoAdjacent && onlyIncreasing; 21 | }; 22 | 23 | module.exports = (input) => { 24 | const range = input.split('-').map(Number); 25 | 26 | let counter = 0; 27 | 28 | for (let i = range[0]; i <= range[1]; i++) { 29 | if (isValid(`${i}`)) { 30 | counter++; 31 | } 32 | } 33 | 34 | return counter; 35 | }; 36 | -------------------------------------------------------------------------------- /day-04-secure-container/test.js: -------------------------------------------------------------------------------- 1 | const assert = require('assert'); 2 | 3 | const secure = require('./secure'); 4 | const secure2 = require('./secure2'); 5 | 6 | describe('Day 4: Secure Container', () => { 7 | it('should find number of valid passwords in range', () => { 8 | assert.strictEqual(secure('122345-122345'), 1); 9 | assert.strictEqual(secure('111123-111123'), 1); 10 | assert.strictEqual(secure('111111-111111'), 1); 11 | assert.strictEqual(secure('223450-223450'), 0); 12 | assert.strictEqual(secure('123789-123789'), 0); 13 | }); 14 | 15 | describe('Part Two', () => { 16 | it('should find number of valid passwords in range', () => { 17 | assert.strictEqual(secure2('112233-112233'), 1); 18 | assert.strictEqual(secure2('123444-123444'), 0); 19 | assert.strictEqual(secure2('111122-111122'), 1); 20 | }); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /day-05-sunny-with-a-chance-of-asteroids/README.md: -------------------------------------------------------------------------------- 1 | # Day 5: Sunny with a Chance of Asteroids 2 | 3 | You're starting to sweat as the ship makes its way toward Mercury. The Elves suggest that you get the air conditioner working by upgrading your ship computer to support the Thermal Environment Supervision Terminal. 4 | 5 | The Thermal Environment Supervision Terminal (TEST) starts by running a **diagnostic program** (your puzzle input). The TEST diagnostic program will run on [your existing Intcode computer](https://adventofcode.com/2019/day/2) after a few modifications: 6 | 7 | **First**, you'll need to add **two new instructions**: 8 | 9 | - Opcode `3` takes a single integer as **input** and saves it to the address given by its only parameter. For example, the instruction `3,50` would take an input value and store it at address `50`. 10 | - Opcode `4` **outputs** the value of its only parameter. For example, the instruction `4,50` would output the value at address `50`. 11 | 12 | Programs that use these instructions will come with documentation that explains what should be connected to the input and output. The program `3,0,4,0,99` outputs whatever it gets as input, then halts. 13 | 14 | **Second**, you'll need to add support for **parameter modes**: 15 | 16 | Each parameter of an instruction is handled based on its parameter mode. Right now, your ship computer already understands parameter mode `0`, **position mode**, which causes the parameter to be interpreted as a **position** - if the parameter is `50`, its value is **the value stored at address `50` in memory**. Until now, all parameters have been in position mode. 17 | 18 | Now, your ship computer will also need to handle parameters in mode `1`, **immediate mode**. In immediate mode, a parameter is interpreted as a **value** - if the parameter is `50`, its value is simply **`50`**. 19 | 20 | Parameter modes are stored in the same value as the instruction's opcode. The opcode is a two-digit number based only on the ones and tens digit of the value, that is, the opcode is the rightmost two digits of the first value in an instruction. Parameter modes are single digits, one per parameter, read right-to-left from the opcode: the first parameter's mode is in the hundreds digit, the second parameter's mode is in the thousands digit, the third parameter's mode is in the ten-thousands digit, and so on. Any missing modes are `0`. 21 | 22 | For example, consider the program `1002,4,3,4,33`. 23 | 24 | The first instruction, `1002,4,3,4`, is a **multiply** instruction - the rightmost two digits of the first value, `02`, indicate opcode `2`, multiplication. Then, going right to left, the parameter modes are `0` (hundreds digit), `1` (thousands digit), and `0` (ten-thousands digit, not present and therefore zero): 25 | ``` 26 | ABCDE 27 | 1002 28 | 29 | DE - two-digit opcode, 02 == opcode 2 30 | C - mode of 1st parameter, 0 == position mode 31 | B - mode of 2nd parameter, 1 == immediate mode 32 | A - mode of 3rd parameter, 0 == position mode, 33 | omitted due to being a leading zero 34 | ``` 35 | 36 | This instruction multiplies its first two parameters. The first parameter, `4` in position mode, works like it did before - its value is the value stored at address `4` (`33`). The second parameter, `3` in immediate mode, simply has value `3`. The result of this operation, `33 * 3 = 99`, is written according to the third parameter, `4` in position mode, which also works like it did before - `99` is written to address `4`. 37 | 38 | Parameters that an instruction writes to will **never be in immediate mode**. 39 | 40 | **Finally**, some notes: 41 | 42 | - It is important to remember that the instruction pointer should increase **by the number of values in the instruction** after the instruction finishes. Because of the new instructions, this amount is no longer always `4`. 43 | - Integers can be negative: `1101,100,-1,4,0` is a valid program (find` 100 + -1`, store the result in position `4`). 44 | 45 | The TEST diagnostic program will start by requesting from the user the ID of the system to test by running an **input** instruction - provide it `1`, the ID for the ship's air conditioner unit. 46 | 47 | It will then perform a series of diagnostic tests confirming that various parts of the Intcode computer, like parameter modes, function correctly. For each test, it will run an **output** instruction indicating how far the result of the test was from the expected value, where `0` means the test was successful. Non-zero outputs mean that a function is not working correctly; check the instructions that were run before the output instruction to see which one failed. 48 | 49 | Finally, the program will output a **diagnostic code** and immediately halt. This final output isn't an error; an output followed immediately by a halt means the program finished. If all outputs were zero except the diagnostic code, the diagnostic program ran successfully. 50 | 51 | After providing `1` to the only input instruction and passing all the tests, **what diagnostic code does the program produce?** 52 | 53 | ## Part Two 54 | 55 | The air conditioner comes online! Its cold air feels good for a while, but then the TEST alarms start to go off. Since the air conditioner can't vent its heat anywhere but back into the spacecraft, it's actually making the air inside the ship **warmer**. 56 | 57 | Instead, you'll need to use the TEST to extend the [thermal radiators](https://en.wikipedia.org/wiki/Spacecraft_thermal_control). Fortunately, the diagnostic program (your puzzle input) is already equipped for this. Unfortunately, your Intcode computer is not. 58 | 59 | Your computer is only missing a few opcodes: 60 | 61 | - Opcode `5` is **jump-if-true**: if the first parameter is **non-zero**, it sets the instruction pointer to the value from the second parameter. Otherwise, it does nothing. 62 | - Opcode `6` is **jump-if-false**: if the first parameter **is zero**, it sets the instruction pointer to the value from the second parameter. Otherwise, it does nothing. 63 | - Opcode `7` is **less than**: if the first parameter is **less than** the second parameter, it stores `1` in the position given by the third parameter. Otherwise, it stores `0`. 64 | - Opcode `8` is **equals**: if the first parameter is **equal to** the second parameter, it stores `1` in the position given by the third parameter. Otherwise, it stores `0`. 65 | 66 | Like all instructions, these instructions need to support **parameter modes** as described above. 67 | 68 | Normally, after an instruction is finished, the instruction pointer increases by the number of values in that instruction. **However**, if the instruction modifies the instruction pointer, that value is used and the instruction pointer is **not automatically increased**. 69 | 70 | For example, here are several programs that take one input, compare it to the value `8`, and then produce one output: 71 | 72 | - `3,9,8,9,10,9,4,9,99,-1,8` - Using **position mode**, consider whether the input is **equal to** `8`; output `1` (if it is) or `0` (if it is not). 73 | - `3,9,7,9,10,9,4,9,99,-1,8` - Using **position mode**, consider whether the input is **less than** `8`; output `1` (if it is) or `0` (if it is not). 74 | - `3,3,1108,-1,8,3,4,3,99` - Using **immediate mode**, consider whether the input is **equal to** `8`; output `1` (if it is) or `0` (if it is not). 75 | - `3,3,1107,-1,8,3,4,3,99` - Using **immediate mode**, consider whether the input is **less than** `8`; output `1` (if it is) or `0` (if it is not). 76 | 77 | Here are some jump tests that take an input, then output `0` if the input was zero or `1` if the input was non-zero: 78 | 79 | - `3,12,6,12,15,1,13,14,13,4,13,99,-1,0,1,9` (using **position mode**) 80 | - `3,3,1105,-1,9,1101,0,0,12,4,12,99,1` (using **immediate mode**) 81 | 82 | Here's a larger example: 83 | 84 | ``` 85 | 3,21,1008,21,8,20,1005,20,22,107,8,21,20,1006,20,31, 86 | 1106,0,36,98,0,0,1002,21,125,20,4,20,1105,1,46,104, 87 | 999,1105,1,46,1101,1000,1,20,4,20,1105,1,46,98,99 88 | ``` 89 | 90 | The above example program uses an input instruction to ask for a single number. The program will then output `999` if the input value is below `8`, output `1000` if the input value is equal to `8`, or output `1001` if the input value is greater than `8`. 91 | 92 | This time, when the TEST diagnostic program runs its input instruction to get the ID of the system to test, **provide it `5`**, the ID for the ship's thermal radiator controller. This diagnostic test suite only outputs one number, the **diagnostic code**. 93 | 94 | **What is the diagnostic code for system ID `5`?** 95 | 96 | ## References 97 | - https://adventofcode.com/2019/day/5 98 | -------------------------------------------------------------------------------- /day-05-sunny-with-a-chance-of-asteroids/asteroids.js: -------------------------------------------------------------------------------- 1 | module.exports = (instructions, input = 1) => { 2 | const initialMemoryState = instructions.split(','); 3 | 4 | const memory = [...initialMemoryState]; 5 | 6 | let instructionPointer = 0; 7 | let output = '0'; 8 | 9 | const getParameter = (parameterMode, position) => { 10 | return parameterMode === 0 ? memory[memory[position]] : memory[position]; 11 | }; 12 | 13 | while (Number(memory[instructionPointer]) !== 99) { 14 | const instruction = memory[instructionPointer].padStart(5, '0'); 15 | 16 | const opcode = Number(instruction.slice(3)); 17 | const parameter1Mode = Number(instruction[2]); 18 | const parameter2Mode = Number(instruction[1]); 19 | const parameter3Mode = Number(instruction[0]); // eslint-disable-line no-unused-vars 20 | 21 | if (opcode === 1) { 22 | const parameter1 = getParameter(parameter1Mode, instructionPointer + 1); 23 | const parameter2 = getParameter(parameter2Mode, instructionPointer + 2); 24 | const parameter3 = memory[instructionPointer + 3]; 25 | 26 | memory[parameter3] = `${Number(parameter1) + Number(parameter2)}`; 27 | 28 | instructionPointer += 4; 29 | } else if (opcode === 2) { 30 | const parameter1 = getParameter(parameter1Mode, instructionPointer + 1); 31 | const parameter2 = getParameter(parameter2Mode, instructionPointer + 2); 32 | const parameter3 = memory[instructionPointer + 3]; 33 | 34 | memory[parameter3] = `${Number(parameter1) * Number(parameter2)}`; 35 | 36 | instructionPointer += 4; 37 | } else if (opcode === 3) { 38 | const parameter1 = memory[instructionPointer + 1]; 39 | 40 | memory[parameter1] = `${input}`; 41 | 42 | instructionPointer += 2; 43 | } else if (opcode === 4) { 44 | output = getParameter(parameter1Mode, instructionPointer + 1); 45 | 46 | instructionPointer += 2; 47 | } 48 | } 49 | 50 | return output; 51 | }; 52 | -------------------------------------------------------------------------------- /day-05-sunny-with-a-chance-of-asteroids/asteroids2.js: -------------------------------------------------------------------------------- 1 | module.exports = (instructions, input = [5]) => { 2 | const initialMemoryState = instructions.split(','); 3 | 4 | const memory = [...initialMemoryState]; 5 | 6 | let instructionPointer = 0; 7 | let output = '0'; 8 | 9 | const getParameter = (parameterMode, position) => { 10 | return parameterMode === 0 ? memory[memory[position]] : memory[position]; 11 | }; 12 | 13 | while (Number(memory[instructionPointer]) !== 99) { 14 | const instruction = memory[instructionPointer].padStart(5, '0'); 15 | 16 | const opcode = Number(instruction.slice(3)); 17 | const parameter1Mode = Number(instruction[2]); 18 | const parameter2Mode = Number(instruction[1]); 19 | const parameter3Mode = Number(instruction[0]); // eslint-disable-line no-unused-vars 20 | 21 | if (opcode === 1) { 22 | const parameter1 = getParameter(parameter1Mode, instructionPointer + 1); 23 | const parameter2 = getParameter(parameter2Mode, instructionPointer + 2); 24 | const parameter3 = memory[instructionPointer + 3]; 25 | 26 | memory[parameter3] = `${Number(parameter1) + Number(parameter2)}`; 27 | 28 | instructionPointer += 4; 29 | } else if (opcode === 2) { 30 | const parameter1 = getParameter(parameter1Mode, instructionPointer + 1); 31 | const parameter2 = getParameter(parameter2Mode, instructionPointer + 2); 32 | const parameter3 = memory[instructionPointer + 3]; 33 | 34 | memory[parameter3] = `${Number(parameter1) * Number(parameter2)}`; 35 | 36 | instructionPointer += 4; 37 | } else if (opcode === 3) { 38 | const parameter1 = memory[instructionPointer + 1]; 39 | 40 | memory[parameter1] = `${input.shift()}`; 41 | 42 | instructionPointer += 2; 43 | } else if (opcode === 4) { 44 | output = getParameter(parameter1Mode, instructionPointer + 1); 45 | 46 | instructionPointer += 2; 47 | } else if (opcode === 5) { 48 | const parameter1 = getParameter(parameter1Mode, instructionPointer + 1); 49 | const parameter2 = getParameter(parameter2Mode, instructionPointer + 2); 50 | 51 | if (Number(parameter1) !== 0) { 52 | instructionPointer = Number(parameter2); 53 | } else { 54 | instructionPointer += 3; 55 | } 56 | } else if (opcode === 6) { 57 | const parameter1 = getParameter(parameter1Mode, instructionPointer + 1); 58 | const parameter2 = getParameter(parameter2Mode, instructionPointer + 2); 59 | 60 | if (Number(parameter1) === 0) { 61 | instructionPointer = Number(parameter2); 62 | } else { 63 | instructionPointer += 3; 64 | } 65 | } else if (opcode === 7) { 66 | const parameter1 = getParameter(parameter1Mode, instructionPointer + 1); 67 | const parameter2 = getParameter(parameter2Mode, instructionPointer + 2); 68 | const parameter3 = memory[instructionPointer + 3]; 69 | 70 | memory[parameter3] = Number(parameter1) < Number(parameter2) ? '1' : '0'; 71 | 72 | instructionPointer += 4; 73 | } else if (opcode === 8) { 74 | const parameter1 = getParameter(parameter1Mode, instructionPointer + 1); 75 | const parameter2 = getParameter(parameter2Mode, instructionPointer + 2); 76 | const parameter3 = memory[instructionPointer + 3]; 77 | 78 | memory[parameter3] = Number(parameter1) === Number(parameter2) ? '1' : '0'; 79 | 80 | instructionPointer += 4; 81 | } 82 | } 83 | 84 | return output; 85 | }; 86 | -------------------------------------------------------------------------------- /day-05-sunny-with-a-chance-of-asteroids/test.js: -------------------------------------------------------------------------------- 1 | const assert = require('assert'); 2 | 3 | const asteroids = require('./asteroids'); 4 | const asteroids2 = require('./asteroids2'); 5 | 6 | describe('Day 5: Sunny with a Chance of Asteroids', () => { 7 | it('should run diagnostics', () => { 8 | assert.strictEqual(asteroids('3,0,4,0,99', [9]), '9'); 9 | assert.strictEqual(asteroids('3,0,4,0,99', [10]), '10'); 10 | 11 | assert.strictEqual(asteroids('1002,4,3,4,33', [0]), '0'); 12 | 13 | assert.strictEqual(asteroids('1101,100,-1,4,0', [0]), '0'); 14 | }); 15 | 16 | describe('Part Two', () => { 17 | it('should perform jump tests', () => { 18 | assert.strictEqual(asteroids2('3,9,8,9,10,9,4,9,99,-1,8', [7]), '0'); 19 | assert.strictEqual(asteroids2('3,9,8,9,10,9,4,9,99,-1,8', [8]), '1'); 20 | assert.strictEqual(asteroids2('3,9,8,9,10,9,4,9,99,-1,8', [9]), '0'); 21 | 22 | assert.strictEqual(asteroids2('3,9,7,9,10,9,4,9,99,-1,8', [7]), '1'); 23 | assert.strictEqual(asteroids2('3,9,7,9,10,9,4,9,99,-1,8', [8]), '0'); 24 | 25 | assert.strictEqual(asteroids2('3,3,1108,-1,8,3,4,3,99', [7]), '0'); 26 | assert.strictEqual(asteroids2('3,3,1108,-1,8,3,4,3,99', [8]), '1'); 27 | assert.strictEqual(asteroids2('3,3,1108,-1,8,3,4,3,99', [9]), '0'); 28 | 29 | assert.strictEqual(asteroids2('3,3,1107,-1,8,3,4,3,99', [7]), '1'); 30 | assert.strictEqual(asteroids2('3,3,1107,-1,8,3,4,3,99', [8]), '0'); 31 | 32 | assert.strictEqual(asteroids2('3,12,6,12,15,1,13,14,13,4,13,99,-1,0,1,9', [0]), '0'); 33 | assert.strictEqual(asteroids2('3,12,6,12,15,1,13,14,13,4,13,99,-1,0,1,9', [1]), '1'); 34 | 35 | assert.strictEqual(asteroids2('3,3,1105,-1,9,1101,0,0,12,4,12,99,1', [0]), '0'); 36 | assert.strictEqual(asteroids2('3,3,1105,-1,9,1101,0,0,12,4,12,99,1', [1]), '1'); 37 | 38 | const largeExample = '3,21,1008,21,8,20,1005,20,22,107,8,21,20,1006,20,31,1106,0,36,98,0,0,1002,21,125,20,4,20,1105,1,46,104,999,1105,1,46,1101,1000,1,20,4,20,1105,1,46,98,99'; 39 | 40 | assert.strictEqual(asteroids2(largeExample, [7]), '999'); 41 | assert.strictEqual(asteroids2(largeExample, [8]), '1000'); 42 | assert.strictEqual(asteroids2(largeExample, [9]), '1001'); 43 | }); 44 | }); 45 | }); 46 | -------------------------------------------------------------------------------- /day-06-universal-orbit-map/README.md: -------------------------------------------------------------------------------- 1 | # Day 6: Universal Orbit Map 2 | 3 | You've landed at the Universal Orbit Map facility on Mercury. Because navigation in space often involves transferring between orbits, the orbit maps here are useful for finding efficient routes between, for example, you and Santa. You download a map of the local orbits (your puzzle input). 4 | 5 | Except for the universal Center of Mass (`COM`), every object in space is in orbit around exactly one other object. An [orbit](https://en.wikipedia.org/wiki/Orbit) looks roughly like this: 6 | 7 | ``` 8 | \ 9 | \ 10 | | 11 | | 12 | AAA--> o o <--BBB 13 | | 14 | | 15 | / 16 | / 17 | ``` 18 | 19 | In this diagram, the object `BBB` is in orbit around `AAA`. The path that `BBB` takes around `AAA` (drawn with lines) is only partly shown. In the map data, this orbital relationship is written `AAA)BBB`, which means "`BBB` is in orbit around `AAA`". 20 | 21 | Before you use your map data to plot a course, you need to make sure it wasn't corrupted during the download. To verify maps, the Universal Orbit Map facility uses **orbit count checksums** - the total number of **direct orbits** (like the one shown above) and **indirect orbits**. 22 | 23 | Whenever `A` orbits `B` and `B` orbits `C`, then `A` **indirectly orbits** `C`. This chain can be any number of objects long: if `A` orbits `B`, `B` orbits `C`, and `C` orbits `D`, then `A` indirectly orbits `D`. 24 | 25 | For example, suppose you have the following map: 26 | 27 | ``` 28 | COM)B 29 | B)C 30 | C)D 31 | D)E 32 | E)F 33 | B)G 34 | G)H 35 | D)I 36 | E)J 37 | J)K 38 | K)L 39 | ``` 40 | 41 | Visually, the above map of orbits looks like this: 42 | 43 | ``` 44 | G - H J - K - L 45 | / / 46 | COM - B - C - D - E - F 47 | \ 48 | I 49 | ``` 50 | 51 | In this visual representation, when two objects are connected by a line, the one on the right directly orbits the one on the left. 52 | 53 | Here, we can count the total number of orbits as follows: 54 | 55 | - `D` directly orbits `C` and indirectly orbits `B` and `COM`, a total of `3` orbits. 56 | - `L` directly orbits `K` and indirectly orbits `J`, `E`, `D`, `C`, `B`, and `COM`, a total of `7` orbits. 57 | - `COM` orbits nothing. 58 | 59 | The total number of direct and indirect orbits in this example is **`42`**. 60 | 61 | **What is the total number of direct and indirect orbits** in your map data? 62 | 63 | ## Part Two 64 | 65 | Now, you just need to figure out how many **orbital transfers** you (`YOU`) need to take to get to Santa (`SAN`). 66 | 67 | You start at the object `YOU` are orbiting; your destination is the object `SAN` is orbiting. An orbital transfer lets you move from any object to an object orbiting or orbited by that object. 68 | 69 | For example, suppose you have the following map: 70 | 71 | ``` 72 | COM)B 73 | B)C 74 | C)D 75 | D)E 76 | E)F 77 | B)G 78 | G)H 79 | D)I 80 | E)J 81 | J)K 82 | K)L 83 | K)YOU 84 | I)SAN 85 | ``` 86 | 87 | Visually, the above map of orbits looks like this: 88 | 89 | ``` 90 | YOU 91 | / 92 | G - H J - K - L 93 | / / 94 | COM - B - C - D - E - F 95 | \ 96 | I - SAN 97 | ``` 98 | 99 | In this example, `YOU` are in orbit around `K`, and `SAN` is in orbit around `I`. To move from `K` to `I`, a minimum of `4` orbital transfers are required: 100 | 101 | - `K` to `J` 102 | - `J` to `E` 103 | - `E` to `D` 104 | - `D` to `I` 105 | 106 | Afterward, the map of orbits looks like this: 107 | 108 | ``` 109 | G - H J - K - L 110 | / / 111 | COM - B - C - D - E - F 112 | \ 113 | I - SAN 114 | \ 115 | YOU 116 | ``` 117 | 118 | **What is the minimum number of orbital transfers required** to move from the object `YOU` are orbiting to the object `SAN` is orbiting? (Between the objects they are orbiting - **not** between `YOU` and `SAN`.) 119 | 120 | ## References 121 | - https://adventofcode.com/2019/day/6 122 | -------------------------------------------------------------------------------- /day-06-universal-orbit-map/orbits.js: -------------------------------------------------------------------------------- 1 | module.exports = (input) => { 2 | const orbits = input 3 | .split('\n') 4 | .reduce((orbits, line) => { 5 | const [object1, object2] = line.trim().split(')'); 6 | 7 | orbits[object2] = object1; 8 | 9 | return orbits; 10 | }, {}); 11 | 12 | let totalNumberOfOrbits = 0; 13 | let objectsOrbitingAnother = Object.keys(orbits); 14 | 15 | for (let i = 0; i < objectsOrbitingAnother.length; i++) { 16 | const currentObject = objectsOrbitingAnother[i]; 17 | 18 | let nextObject = orbits[currentObject]; 19 | 20 | while (nextObject) { 21 | nextObject = orbits[nextObject]; 22 | totalNumberOfOrbits += 1; 23 | } 24 | } 25 | 26 | return totalNumberOfOrbits; 27 | }; 28 | -------------------------------------------------------------------------------- /day-06-universal-orbit-map/orbits2.js: -------------------------------------------------------------------------------- 1 | module.exports = (input) => { 2 | const orbits = input 3 | .split('\n') 4 | .reduce((orbits, line) => { 5 | const [object1, object2] = line.trim().split(')'); 6 | 7 | orbits[object2] = object1; 8 | 9 | return orbits; 10 | }, {}); 11 | 12 | const distances = {}; 13 | 14 | let objectsOrbitingAnother = Object.keys(orbits); 15 | 16 | for (let i = 0; i < objectsOrbitingAnother.length; i++) { 17 | const currentObject = objectsOrbitingAnother[i]; 18 | const visited = []; 19 | 20 | let nextObject = orbits[currentObject]; 21 | let distanceToObject = 0; 22 | 23 | while (nextObject) { 24 | nextObject = orbits[nextObject]; 25 | distanceToObject += 1; 26 | 27 | visited.push([ nextObject, distanceToObject ]); 28 | } 29 | 30 | distances[currentObject] = visited; 31 | } 32 | 33 | const closestCommonObject1 = distances['YOU'] 34 | .filter(([ object ]) => distances['SAN'].find(([ otherObject ]) => object === otherObject)) 35 | .sort((a, b) => a[1] - b[1])[0]; 36 | 37 | const closestCommonObject2 = distances['SAN'] 38 | .find(([object]) => object === closestCommonObject1[0]); 39 | 40 | return closestCommonObject1[1] + closestCommonObject2[1]; 41 | }; 42 | -------------------------------------------------------------------------------- /day-06-universal-orbit-map/test.js: -------------------------------------------------------------------------------- 1 | const assert = require('assert'); 2 | 3 | const orbits = require('./orbits'); 4 | const orbits2 = require('./orbits2'); 5 | 6 | describe('Day 6: Universal Orbit Map', () => { 7 | it('should calculate the number of direct and indirect orbits', () => { 8 | const input = 9 | `COM)B 10 | B)C 11 | C)D 12 | D)E 13 | E)F 14 | B)G 15 | G)H 16 | D)I 17 | E)J 18 | J)K 19 | K)L`; 20 | 21 | assert.strictEqual(orbits(input), 42); 22 | }); 23 | 24 | describe('Part Two', () => { 25 | it('should calculate the minimum number of orbital transfers required', () => { 26 | const input = 27 | `COM)B 28 | B)C 29 | C)D 30 | D)E 31 | E)F 32 | B)G 33 | G)H 34 | D)I 35 | E)J 36 | J)K 37 | K)L 38 | K)YOU 39 | I)SAN`; 40 | 41 | assert.strictEqual(orbits2(input), 4); 42 | }); 43 | }); 44 | }); 45 | -------------------------------------------------------------------------------- /day-07-amplification-circuit/README.md: -------------------------------------------------------------------------------- 1 | # Day 7: Amplification Circuit 2 | 3 | Based on the navigational maps, you're going to need to send more power to your ship's thrusters to reach Santa in time. To do this, you'll need to configure a series of [amplifiers](https://en.wikipedia.org/wiki/Amplifier) already installed on the ship. 4 | 5 | There are five amplifiers connected in series; each one receives an input signal and produces an output signal. They are connected such that the first amplifier's output leads to the second amplifier's input, the second amplifier's output leads to the third amplifier's input, and so on. The first amplifier's input value is `0`, and the last amplifier's output leads to your ship's thrusters. 6 | 7 | ``` 8 | O-------O O-------O O-------O O-------O O-------O 9 | 0 ->| Amp A |->| Amp B |->| Amp C |->| Amp D |->| Amp E |-> (to thrusters) 10 | O-------O O-------O O-------O O-------O O-------O 11 | ``` 12 | 13 | The Elves have sent you some **Amplifier Controller Software** (your puzzle input), a program that should run on your [existing Intcode computer](https://adventofcode.com/2019/day/5). Each amplifier will need to run a copy of the program. 14 | 15 | When a copy of the program starts running on an amplifier, it will first use an input instruction to ask the amplifier for its current **phase setting** (an integer from `0` to `4`). Each phase setting is used **exactly once**, but the Elves can't remember which amplifier needs which phase setting. 16 | 17 | The program will then call another input instruction to get the amplifier's input signal, compute the correct output signal, and supply it back to the amplifier with an output instruction. (If the amplifier has not yet received an input signal, it waits until one arrives.) 18 | 19 | Your job is to **find the largest output signal that can be sent to the thrusters** by trying every possible combination of phase settings on the amplifiers. Make sure that memory is not shared or reused between copies of the program. 20 | 21 | For example, suppose you want to try the phase setting sequence `3,1,2,4,0`, which would mean setting amplifier `A` to phase setting `3`, amplifier `B` to setting `1`, `C` to `2`, `D` to `4`, and `E` to `0`. Then, you could determine the output signal that gets sent from amplifier `E` to the thrusters with the following steps: 22 | 23 | - Start the copy of the amplifier controller software that will run on amplifier `A`. At its first input instruction, provide it the amplifier's phase setting, `3`. At its second input instruction, provide it the input signal, `0`. After some calculations, it will use an output instruction to indicate the amplifier's output signal. 24 | - Start the software for amplifier `B`. Provide it the phase setting (`1`) and then whatever output signal was produced from amplifier `A`. It will then produce a new output signal destined for amplifier `C`. 25 | - Start the software for amplifier `C`, provide the phase setting (`2`) and the value from amplifier `B`, then collect its output signal. 26 | - Run amplifier `D`'s software, provide the phase setting (`4`) and input value, and collect its output signal. 27 | - Run amplifier `E`'s software, provide the phase setting (`0`) and input value, and collect its output signal. 28 | 29 | The final output signal from amplifier `E` would be sent to the thrusters. However, this phase setting sequence may not have been the best one; another sequence might have sent a higher signal to the thrusters. 30 | 31 | Here are some example programs: 32 | 33 | - Max thruster signal **`43210`** (from phase setting sequence `4,3,2,1,0`): 34 | ``` 35 | 3,15,3,16,1002,16,10,16,1,16,15,15,4,15,99,0,0 36 | ``` 37 | - Max thruster signal **`54321`** (from phase setting sequence `0,1,2,3,4`): 38 | ``` 39 | 3,23,3,24,1002,24,10,24,1002,23,-1,23, 40 | 101,5,23,23,1,24,23,23,4,23,99,0,0 41 | ``` 42 | - Max thruster signal **`65210`** (from phase setting sequence `1,0,4,3,2`): 43 | ``` 44 | 3,31,3,32,1002,32,10,32,1001,31,-2,31,1007,31,0,33, 45 | 1002,33,7,33,1,33,31,31,1,32,31,31,4,31,99,0,0,0 46 | ``` 47 | 48 | Try every combination of phase settings on the amplifiers. **What is the highest signal that can be sent to the thrusters?** 49 | 50 | ## Part Two 51 | 52 | It's no good - in this configuration, the amplifiers can't generate a large enough output signal to produce the thrust you'll need. The Elves quickly talk you through rewiring the amplifiers into a **feedback loop**: 53 | 54 | ``` 55 | O-------O O-------O O-------O O-------O O-------O 56 | 0 -+->| Amp A |->| Amp B |->| Amp C |->| Amp D |->| Amp E |-. 57 | | O-------O O-------O O-------O O-------O O-------O | 58 | | | 59 | '--------------------------------------------------------+ 60 | | 61 | v 62 | (to thrusters) 63 | ``` 64 | 65 | Most of the amplifiers are connected as they were before; amplifier `A`'s output is connected to amplifier `B`'s input, and so on. **However**, the output from amplifier `E` is now connected into amplifier `A`'s input. This creates the feedback loop: the signal will be sent through the amplifiers **many times**. 66 | 67 | In feedback loop mode, the amplifiers need **totally different phase settings:** integers from `5` to `9`, again each used exactly once. These settings will cause the Amplifier Controller Software to repeatedly take input and produce output many times before halting. Provide each amplifier its phase setting at its first input instruction; all further input/output instructions are for signals. 68 | 69 | Don't restart the Amplifier Controller Software on any amplifier during this process. Each one should continue receiving and sending signals until it halts. 70 | 71 | All signals sent or received in this process will be between pairs of amplifiers except the very first signal and the very last signal. To start the process, a `0` signal is sent to amplifier `A`'s input **exactly once**. 72 | 73 | Eventually, the software on the amplifiers will halt after they have processed the final loop. When this happens, the last output signal from amplifier `E` is sent to the thrusters. Your job is to **find the largest output signal that can be sent to the thrusters** using the new phase settings and feedback loop arrangement. 74 | 75 | Here are some example programs: 76 | 77 | - Max thruster signal **`139629729`** (from phase setting sequence `9,8,7,6,5`): 78 | ``` 79 | 3,26,1001,26,-4,26,3,27,1002,27,2,27,1,27,26, 80 | 27,4,27,1001,28,-1,28,1005,28,6,99,0,0,5 81 | ``` 82 | - Max thruster signal **`18216`** (from phase setting sequence `9,7,8,5,6`): 83 | ``` 84 | 3,52,1001,52,-5,52,3,53,1,52,56,54,1007,54,5,55,1005,55,26,1001,54, 85 | -5,54,1105,1,12,1,53,54,53,1008,54,0,55,1001,55,1,55,2,53,55,53,4, 86 | 53,1001,56,-1,56,1005,56,6,99,0,0,0,0,10 87 | ``` 88 | 89 | Try every combination of the new phase settings on the amplifier feedback loop. **What is the highest signal that can be sent to the thrusters?** 90 | 91 | ## References 92 | - https://adventofcode.com/2019/day/7 93 | -------------------------------------------------------------------------------- /day-07-amplification-circuit/amplifier-controller.js: -------------------------------------------------------------------------------- 1 | class AmplifierController { 2 | constructor (instructions, phase) { 3 | this.memory = instructions.split(','); 4 | this.inputs = [phase]; 5 | this.instructionPointer = 0; 6 | this.terminated = false; 7 | } 8 | 9 | getParameter (parameterMode, position) { 10 | return parameterMode === 0 11 | ? this.memory[this.memory[position]] 12 | : this.memory[position]; 13 | } 14 | 15 | run (input) { 16 | const { memory, inputs } = this; 17 | 18 | inputs.push(input); 19 | 20 | let output = null; 21 | 22 | while (!this.terminated) { 23 | const instruction = memory[this.instructionPointer].padStart(5, '0'); 24 | 25 | const opcode = Number(instruction.slice(3)); 26 | const parameter1Mode = Number(instruction[2]); 27 | const parameter2Mode = Number(instruction[1]); 28 | const parameter3Mode = Number(instruction[0]); // eslint-disable-line no-unused-vars 29 | 30 | if (opcode === 1) { 31 | const parameter1 = this.getParameter(parameter1Mode, this.instructionPointer + 1); 32 | const parameter2 = this.getParameter(parameter2Mode, this.instructionPointer + 2); 33 | const parameter3 = memory[this.instructionPointer + 3]; 34 | 35 | memory[parameter3] = `${Number(parameter1) + Number(parameter2)}`; 36 | 37 | this.instructionPointer += 4; 38 | } else if (opcode === 2) { 39 | const parameter1 = this.getParameter(parameter1Mode, this.instructionPointer + 1); 40 | const parameter2 = this.getParameter(parameter2Mode, this.instructionPointer + 2); 41 | const parameter3 = memory[this.instructionPointer + 3]; 42 | 43 | memory[parameter3] = `${Number(parameter1) * Number(parameter2)}`; 44 | 45 | this.instructionPointer += 4; 46 | } else if (opcode === 3) { 47 | const parameter1 = memory[this.instructionPointer + 1]; 48 | 49 | memory[parameter1] = `${inputs.shift()}`; 50 | 51 | this.instructionPointer += 2; 52 | } else if (opcode === 4) { 53 | output = this.getParameter(parameter1Mode, this.instructionPointer + 1); 54 | 55 | this.instructionPointer += 2; 56 | 57 | break; 58 | } else if (opcode === 5) { 59 | const parameter1 = this.getParameter(parameter1Mode, this.instructionPointer + 1); 60 | const parameter2 = this.getParameter(parameter2Mode, this.instructionPointer + 2); 61 | 62 | if (Number(parameter1) !== 0) { 63 | this.instructionPointer = Number(parameter2); 64 | } else { 65 | this.instructionPointer += 3; 66 | } 67 | } else if (opcode === 6) { 68 | const parameter1 = this.getParameter(parameter1Mode, this.instructionPointer + 1); 69 | const parameter2 = this.getParameter(parameter2Mode, this.instructionPointer + 2); 70 | 71 | if (Number(parameter1) === 0) { 72 | this.instructionPointer = Number(parameter2); 73 | } else { 74 | this.instructionPointer += 3; 75 | } 76 | } else if (opcode === 7) { 77 | const parameter1 = this.getParameter(parameter1Mode, this.instructionPointer + 1); 78 | const parameter2 = this.getParameter(parameter2Mode, this.instructionPointer + 2); 79 | const parameter3 = memory[this.instructionPointer + 3]; 80 | 81 | memory[parameter3] = Number(parameter1) < Number(parameter2) ? '1' : '0'; 82 | 83 | this.instructionPointer += 4; 84 | } else if (opcode === 8) { 85 | const parameter1 = this.getParameter(parameter1Mode, this.instructionPointer + 1); 86 | const parameter2 = this.getParameter(parameter2Mode, this.instructionPointer + 2); 87 | const parameter3 = memory[this.instructionPointer + 3]; 88 | 89 | memory[parameter3] = Number(parameter1) === Number(parameter2) ? '1' : '0'; 90 | 91 | this.instructionPointer += 4; 92 | } else if (opcode === 99) { 93 | this.terminated = true; 94 | } 95 | } 96 | 97 | return output; 98 | } 99 | } 100 | 101 | module.exports = AmplifierController; 102 | -------------------------------------------------------------------------------- /day-07-amplification-circuit/circuit.js: -------------------------------------------------------------------------------- 1 | const intcode = require('../day-05-sunny-with-a-chance-of-asteroids/asteroids2'); 2 | 3 | const getPermutations = (set = []) => { 4 | const permutations = []; 5 | 6 | const permute = (candidates = [], sequence = []) => { 7 | if (!candidates.length) { 8 | permutations.push(sequence); 9 | 10 | return; 11 | } 12 | 13 | for (let i = 0; i < candidates.length; i++) { 14 | const candidate = candidates[i]; 15 | permute( 16 | [...candidates.filter((x) => x !== candidate)], 17 | [...sequence, candidate] 18 | ); 19 | } 20 | }; 21 | 22 | permute(set); 23 | 24 | return permutations; 25 | }; 26 | 27 | module.exports = (input) => { 28 | const phases = getPermutations([0, 1, 2, 3, 4]); 29 | const thrusterSignals = []; 30 | 31 | for (let i = 0; i < phases.length; i++) { 32 | const a = intcode(input, [phases[i][0], 0]); 33 | const b = intcode(input, [phases[i][1], a]); 34 | const c = intcode(input, [phases[i][2], b]); 35 | const d = intcode(input, [phases[i][3], c]); 36 | const e = intcode(input, [phases[i][4], d]); 37 | 38 | thrusterSignals.push(Number(`${e}`)); 39 | } 40 | 41 | return thrusterSignals.sort((a, b) => b - a)[0]; 42 | }; 43 | -------------------------------------------------------------------------------- /day-07-amplification-circuit/circuit2.js: -------------------------------------------------------------------------------- 1 | const AmplifierController = require('./amplifier-controller'); 2 | 3 | const getPermutations = (set = []) => { 4 | const permutations = []; 5 | 6 | const permute = (candidates = [], sequence = []) => { 7 | if (!candidates.length) { 8 | permutations.push(sequence); 9 | 10 | return; 11 | } 12 | 13 | for (let i = 0; i < candidates.length; i++) { 14 | const candidate = candidates[i]; 15 | 16 | permute( 17 | [...candidates.filter((x) => x !== candidate)], 18 | [...sequence, candidate] 19 | ); 20 | } 21 | }; 22 | 23 | permute(set); 24 | 25 | return permutations; 26 | }; 27 | 28 | module.exports = (input) => { 29 | const phases = getPermutations([5, 6, 7, 8, 9]); 30 | const thrusterSignals = []; 31 | 32 | for (let i = 0; i < phases.length; i++) { 33 | const amplifiers = phases[i] 34 | .map((phase) => new AmplifierController(input, phase)); 35 | 36 | let index = 0; 37 | let lastOutput = 0; 38 | 39 | while (!amplifiers[4].terminated) { 40 | const output = amplifiers[index].run(lastOutput); 41 | 42 | if (output !== null) { 43 | lastOutput = output; 44 | } 45 | 46 | index = index + 1 === amplifiers.length ? 0 : index + 1; 47 | } 48 | 49 | thrusterSignals.push(Number(lastOutput)); 50 | } 51 | 52 | return thrusterSignals.sort((a, b) => b - a)[0]; 53 | }; 54 | -------------------------------------------------------------------------------- /day-07-amplification-circuit/test.js: -------------------------------------------------------------------------------- 1 | const assert = require('assert'); 2 | 3 | const circuit = require('./circuit'); 4 | const circuit2 = require('./circuit2'); 5 | 6 | describe('Day 7: Amplification Circuit', () => { 7 | it('should find highest thruster signals', () => { 8 | assert.strictEqual(circuit([ 9 | '3,15,3,16,1002,16,10,16,1,16,15,15,4,15,99,0,0' 10 | ].join('')), 43210); 11 | 12 | assert.strictEqual(circuit([ 13 | '3,23,3,24,1002,24,10,24,1002,23,-1,23,101,5,23,23,1,24,23,23,4,23,99,', 14 | '0,0' 15 | ].join('')), 54321); 16 | 17 | assert.strictEqual(circuit([ 18 | '3,31,3,32,1002,32,10,32,1001,31,-2,31,1007,31,0,33,1002,33,7,33,1,33,', 19 | '31,31,1,32,31,31,4,31,99,0,0,0', 20 | ].join('')), 65210); 21 | }); 22 | 23 | describe('Part Two', () => { 24 | it('should find highest thruster signals via feedback loop', () => { 25 | assert.strictEqual(circuit2([ 26 | '3,26,1001,26,-4,26,3,27,1002,27,2,27,1,27,26,27,4,27,1001,28,-1,28,', 27 | '1005,28,6,99,0,0,5', 28 | ].join('')), 139629729); 29 | 30 | assert.strictEqual(circuit2([ 31 | '3,52,1001,52,-5,52,3,53,1,52,56,54,1007,54,5,55,1005,55,26,1001,54,', 32 | '-5,54,1105,1,12,1,53,54,53,1008,54,0,55,1001,55,1,55,2,53,55,53,4,', 33 | '53,1001,56,-1,56,1005,56,6,99,0,0,0,0,10', 34 | ].join('')), 18216); 35 | }); 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /day-08-space-image-format/README.md: -------------------------------------------------------------------------------- 1 | # Day 8: Space Image Format 2 | 3 | The Elves' spirits are lifted when they realize you have an opportunity to reboot one of their Mars rovers, and so they are curious if you would spend a brief sojourn on Mars. You land your ship near the rover. 4 | 5 | When you reach the rover, you discover that it's already in the process of rebooting! It's just waiting for someone to enter a [BIOS](https://en.wikipedia.org/wiki/BIOS) password. The Elf responsible for the rover takes a picture of the password (your puzzle input) and sends it to you via the Digital Sending Network. 6 | 7 | Unfortunately, images sent via the Digital Sending Network aren't encoded with any normal encoding; instead, they're encoded in a special Space Image Format. None of the Elves seem to remember why this is the case. They send you the instructions to decode it. 8 | 9 | Images are sent as a series of digits that each represent the color of a single pixel. The digits fill each row of the image left-to-right, then move downward to the next row, filling rows top-to-bottom until every pixel of the image is filled. 10 | 11 | Each image actually consists of a series of identically-sized **layers** that are filled in this way. So, the first digit corresponds to the top-left pixel of the first layer, the second digit corresponds to the pixel to the right of that on the same layer, and so on until the last digit, which corresponds to the bottom-right pixel of the last layer. 12 | 13 | For example, given an image `3` pixels wide and `2` pixels tall, the image data `123456789012` corresponds to the following image layers: 14 | 15 | ``` 16 | Layer 1: 123 17 | 456 18 | 19 | Layer 2: 789 20 | 012 21 | ``` 22 | 23 | The image you received is **`25` pixels wide and `6` pixels tall**. 24 | 25 | To make sure the image wasn't corrupted during transmission, the Elves would like you to find the layer that contains the **fewest `0` digits**. On that layer, what is **the number of `1` digits multiplied by the number of `2` digits?** 26 | 27 | ## Part Two 28 | 29 | Now you're ready to decode the image. The image is rendered by stacking the layers and aligning the pixels with the same positions in each layer. The digits indicate the color of the corresponding pixel: `0` is black, `1` is white, and `2` is transparent. 30 | 31 | The layers are rendered with the first layer in front and the last layer in back. So, if a given position has a transparent pixel in the first and second layers, a black pixel in the third layer, and a white pixel in the fourth layer, the final image would have a **black** pixel at that position. 32 | 33 | For example, given an image `2` pixels wide and `2` pixels tall, the image data `0222112222120000` corresponds to the following image layers: 34 | 35 | ``` 36 | Layer 1: 02 37 | 22 38 | 39 | Layer 2: 11 40 | 22 41 | 42 | Layer 3: 22 43 | 12 44 | 45 | Layer 4: 00 46 | 00 47 | ``` 48 | 49 | Then, the full image can be found by determining the top visible pixel in each position: 50 | 51 | - The top-left pixel is **black** because the top layer is `0`. 52 | - The top-right pixel is **white** because the top layer is `2` (transparent), but the second layer is `1`. 53 | - The bottom-left pixel is **white** because the top two layers are `2`, but the third layer is `1`. 54 | - The bottom-right pixel is **black** because the only visible pixel in that position is `0` (from layer 4). 55 | 56 | So, the final image looks like this: 57 | 58 | ``` 59 | 01 60 | 10 61 | ``` 62 | 63 | **What message is produced after decoding your image?** 64 | 65 | ## References 66 | - https://adventofcode.com/2019/day/8 67 | -------------------------------------------------------------------------------- /day-08-space-image-format/image.js: -------------------------------------------------------------------------------- 1 | module.exports = (input, width = 25, height = 6) => { 2 | const bits = input.split('').map(Number); 3 | const layers = []; 4 | 5 | for (let x = 0; x < input.length; x += width * height) { 6 | layers.push(bits.slice(x, x + width * height)); 7 | } 8 | 9 | const fewestZeros = layers 10 | .map((layer) => { 11 | return { 12 | zeros: layer.filter((bit) => bit === 0).length, 13 | ones: layer.filter((bit) => bit === 1).length, 14 | twos: layer.filter((bit) => bit === 2).length, 15 | }; 16 | }) 17 | .sort((a, b) => a.zeros - b.zeros); 18 | 19 | return fewestZeros[0].ones * fewestZeros[0].twos; 20 | }; 21 | -------------------------------------------------------------------------------- /day-08-space-image-format/image2.js: -------------------------------------------------------------------------------- 1 | module.exports = (input, width = 25, height = 6) => { 2 | const bits = input.split('').map(Number); 3 | const layers = []; 4 | 5 | for (let i = 0; i < input.length; i += width * height) { 6 | layers.push(bits.slice(i, i + width * height)); 7 | } 8 | 9 | const pixels = []; 10 | 11 | for (let i = 0; i < width * height; i++) { 12 | const layeredPixels = layers.map((layer) => layer[i]); 13 | 14 | for (let p = 0; p < layeredPixels.length; p++) { 15 | if (layeredPixels[p] !== 2) { 16 | pixels.push(layeredPixels[p]); 17 | 18 | break; 19 | } 20 | } 21 | } 22 | 23 | const image = []; 24 | 25 | for (let i = 0; i < width * height; i += width) { 26 | image.push(pixels.slice(i, i + width)); 27 | } 28 | 29 | return image 30 | .map((row) => row 31 | .map((c) => c === 0 ? ' ' : 'X') 32 | .join('')) 33 | .join('\n'); 34 | }; 35 | -------------------------------------------------------------------------------- /day-08-space-image-format/test.js: -------------------------------------------------------------------------------- 1 | const assert = require('assert'); 2 | 3 | const image = require('./image'); 4 | const image2 = require('./image2'); 5 | 6 | describe('Day 8: Space Image Format', () => { 7 | it('should calculate image checksum', () => { 8 | assert.strictEqual(image('123456789012', 3, 2), 1); 9 | }); 10 | 11 | describe('Part Two', () => { 12 | it('should decode image', () => { 13 | assert.strictEqual(image2('0222112222120000', 2, 2), ' X\nX '); 14 | }); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /day-09-sensor-boost/README.md: -------------------------------------------------------------------------------- 1 | # Day 9: Sensor Boost 2 | 3 | You've just said goodbye to the rebooted rover and left Mars when you receive a faint distress signal coming from the asteroid belt. It must be the Ceres monitoring station! 4 | 5 | In order to lock on to the signal, you'll need to boost your sensors. The Elves send up the latest **BOOST** program - Basic Operation Of System Test. 6 | 7 | While BOOST (your puzzle input) is capable of boosting your sensors, for tenuous safety reasons, it refuses to do so until the computer it runs on passes some checks to demonstrate it is a **complete Intcode computer**. 8 | 9 | [Your existing Intcode computer](https://adventofcode.com/2019/day/5) is missing one key feature: it needs support for parameters in **relative mode**. 10 | 11 | Parameters in mode `2`, **relative mode**, behave very similarly to parameters in **position mode**: the parameter is interpreted as a position. Like position mode, parameters in relative mode can be read from or written to. 12 | 13 | The important difference is that relative mode parameters don't count from address 0. Instead, they count from a value called the **relative base**. The relative base starts at `0`. 14 | 15 | The address a relative mode parameter refers to is itself **plus** the current **relative base**. When the relative base is `0`, relative mode parameters and position mode parameters with the same value refer to the same address. 16 | 17 | For example, given a relative base of `50`, a relative mode parameter of `-7` refers to memory address `50 + -7 = 43`. 18 | 19 | The relative base is modified with the **relative base offset** instruction: 20 | 21 | - Opcode `9` **adjusts the relative base** by the value of its only parameter. The relative base increases (or decreases, if the value is negative) by the value of the parameter. 22 | 23 | For example, if the relative base is `2000`, then after the instruction `109,19`, the relative base would be `2019`. If the next instruction were `204,-34`, then the value at address `1985` would be output. 24 | 25 | Your Intcode computer will also need a few other capabilities: 26 | 27 | - The computer's available memory should be much larger than the initial program. Memory beyond the initial program starts with the value `0` and can be read or written like any other memory. (It is invalid to try to access memory at a negative address, though.) 28 | - The computer should have support for large numbers. Some instructions near the beginning of the BOOST program will verify this capability. 29 | 30 | Here are some example programs that use these features: 31 | 32 | - `109,1,204,-1,1001,100,1,100,1008,100,16,101,1006,101,0,99` takes no input and produces a [copy of itself](https://en.wikipedia.org/wiki/Quine_(computing)) as output. 33 | - `1102,34915192,34915192,7,4,7,99,0` should output a 16-digit number. 34 | - `104,1125899906842624,99` should output the large number in the middle. 35 | 36 | The BOOST program will ask for a single input; run it in test mode by providing it the value `1`. It will perform a series of checks on each opcode, output any opcodes (and the associated parameter modes) that seem to be functioning incorrectly, and finally output a BOOST keycode. 37 | 38 | Once your Intcode computer is fully functional, the BOOST program should report no malfunctioning opcodes when run in test mode; it should only output a single value, the BOOST keycode. **What BOOST keycode does it produce?** 39 | 40 | ## Part Two 41 | 42 | **You now have a complete Intcode computer.** 43 | 44 | Finally, you can lock on to the Ceres distress signal! You just need to boost your sensors using the BOOST program. 45 | 46 | The program runs in sensor boost mode by providing the input instruction the value `2`. Once run, it will boost the sensors automatically, but it might take a few seconds to complete the operation on slower hardware. In sensor boost mode, the program will output a single value: **the coordinates of the distress signal**. 47 | 48 | Run the BOOST program in sensor boost mode. **What are the coordinates of the distress signal?** 49 | 50 | ## References 51 | - https://adventofcode.com/2019/day/9 52 | -------------------------------------------------------------------------------- /day-09-sensor-boost/intcode.js: -------------------------------------------------------------------------------- 1 | const POSITION_MODE = 0; 2 | const IMMEDIATE_MODE = 1; 3 | const RELATIVE_MODE = 2; 4 | 5 | const ADD = 1; 6 | const MULTIPLY = 2; 7 | const RECEIVE = 3; 8 | const SEND = 4; 9 | const JUMP_IF_NOT_ZERO = 5; 10 | const JUMP_IF_ZERO = 6; 11 | const LESS_THAN = 7; 12 | const EQUALS = 8; 13 | const ADJUST_RELATIVE_BASE = 9; 14 | 15 | module.exports = (instructions, input = []) => { 16 | const initialMemoryState = instructions.split(',').map(Number); 17 | 18 | const memory = [...initialMemoryState] 19 | // expand memory space 20 | .concat(Array.from({ length: 1024 }).map(() => 0)); 21 | 22 | let instructionPointer = 0; 23 | let relativeBase = 0; 24 | let output = []; 25 | 26 | const getValue = (parameterMode, position) => { 27 | switch (parameterMode) { 28 | case POSITION_MODE: 29 | return memory[memory[position]]; 30 | case IMMEDIATE_MODE: 31 | return memory[position]; 32 | case RELATIVE_MODE: 33 | return memory[memory[position] + relativeBase]; 34 | } 35 | }; 36 | 37 | const getAddress = (parameterMode, position) => { 38 | if (parameterMode === POSITION_MODE) { 39 | return memory[position]; 40 | } else if (parameterMode === RELATIVE_MODE) { 41 | return memory[position] + relativeBase; 42 | } 43 | }; 44 | 45 | while (memory[instructionPointer] !== 99) { 46 | const instruction = `${memory[instructionPointer]}`.padStart(5, '0'); 47 | 48 | const opcode = Number(instruction.slice(3)); 49 | const parameter1Mode = Number(instruction[2]); 50 | const parameter2Mode = Number(instruction[1]); 51 | const parameter3Mode = Number(instruction[0]); 52 | 53 | if (opcode === ADD) { 54 | const parameter1 = getValue(parameter1Mode, instructionPointer + 1); 55 | const parameter2 = getValue(parameter2Mode, instructionPointer + 2); 56 | const parameter3 = getAddress(parameter3Mode, instructionPointer + 3); 57 | 58 | memory[parameter3] = parameter1 + parameter2; 59 | 60 | instructionPointer += 4; 61 | } else if (opcode === MULTIPLY) { 62 | const parameter1 = getValue(parameter1Mode, instructionPointer + 1); 63 | const parameter2 = getValue(parameter2Mode, instructionPointer + 2); 64 | const parameter3 = getAddress(parameter3Mode, instructionPointer + 3); 65 | 66 | memory[parameter3] = parameter1 * parameter2; 67 | 68 | instructionPointer += 4; 69 | } else if (opcode === RECEIVE) { 70 | const parameter1 = getAddress(parameter1Mode, instructionPointer + 1); 71 | 72 | memory[parameter1] = input.shift(); 73 | 74 | instructionPointer += 2; 75 | } else if (opcode === SEND) { 76 | output.push(getValue(parameter1Mode, instructionPointer + 1)); 77 | 78 | instructionPointer += 2; 79 | } else if (opcode === JUMP_IF_NOT_ZERO) { 80 | const parameter1 = getValue(parameter1Mode, instructionPointer + 1); 81 | const parameter2 = getValue(parameter2Mode, instructionPointer + 2); 82 | 83 | if (parameter1 !== 0) { 84 | instructionPointer = parameter2; 85 | } else { 86 | instructionPointer += 3; 87 | } 88 | } else if (opcode === JUMP_IF_ZERO) { 89 | const parameter1 = getValue(parameter1Mode, instructionPointer + 1); 90 | const parameter2 = getValue(parameter2Mode, instructionPointer + 2); 91 | 92 | if (parameter1 === 0) { 93 | instructionPointer = parameter2; 94 | } else { 95 | instructionPointer += 3; 96 | } 97 | } else if (opcode === LESS_THAN) { 98 | const parameter1 = getValue(parameter1Mode, instructionPointer + 1); 99 | const parameter2 = getValue(parameter2Mode, instructionPointer + 2); 100 | const parameter3 = getAddress(parameter3Mode, instructionPointer + 3); 101 | 102 | memory[parameter3] = parameter1 < parameter2 ? 1 : 0; 103 | 104 | instructionPointer += 4; 105 | } else if (opcode === EQUALS) { 106 | const parameter1 = getValue(parameter1Mode, instructionPointer + 1); 107 | const parameter2 = getValue(parameter2Mode, instructionPointer + 2); 108 | const parameter3 = getAddress(parameter3Mode, instructionPointer + 3); 109 | 110 | memory[parameter3] = parameter1 === parameter2 ? 1 : 0; 111 | 112 | instructionPointer += 4; 113 | } else if (opcode === ADJUST_RELATIVE_BASE) { 114 | const parameter1 = getValue(parameter1Mode, instructionPointer + 1); 115 | 116 | relativeBase += parameter1; 117 | 118 | instructionPointer += 2; 119 | } 120 | } 121 | 122 | return output.join(','); 123 | }; 124 | -------------------------------------------------------------------------------- /day-09-sensor-boost/sensor.js: -------------------------------------------------------------------------------- 1 | const intcode = require('./intcode'); 2 | 3 | module.exports = (instructions, inputs = [1]) => { 4 | return intcode(instructions, inputs); 5 | }; 6 | -------------------------------------------------------------------------------- /day-09-sensor-boost/test.js: -------------------------------------------------------------------------------- 1 | const assert = require('assert'); 2 | 3 | const sensor = require('./sensor'); 4 | 5 | describe('Day 9: Sensor Boost', () => { 6 | it('should output a copy of itself', () => { 7 | assert.strictEqual( 8 | sensor('109,1,204,-1,1001,100,1,100,1008,100,16,101,1006,101,0,99', []), 9 | '109,1,204,-1,1001,100,1,100,1008,100,16,101,1006,101,0,99' 10 | ); 11 | }); 12 | 13 | it('should output a 16-digit number', () => { 14 | assert.strictEqual( 15 | sensor('1102,34915192,34915192,7,4,7,99,0', []), 16 | '1219070632396864' 17 | ); 18 | }); 19 | 20 | it('should output the large number in the middle', () => { 21 | assert.strictEqual( 22 | sensor('104,1125899906842624,99', []), 23 | '1125899906842624' 24 | ); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /day-10-monitoring-station/README.md: -------------------------------------------------------------------------------- 1 | # Day 10: Monitoring Station 2 | 3 | You fly into the asteroid belt and reach the Ceres monitoring station. The Elves here have an emergency: they're having trouble tracking all of the asteroids and can't be sure they're safe. 4 | 5 | The Elves would like to build a new monitoring station in a nearby area of space; they hand you a map of all of the asteroids in that region (your puzzle input). 6 | 7 | The map indicates whether each position is empty (`.`) or contains an asteroid (`#`). The asteroids are much smaller than they appear on the map, and every asteroid is exactly in the center of its marked position. The asteroids can be described with `X,Y` coordinates where `X` is the distance from the left edge and `Y` is the distance from the top edge (so the top-left corner is 0,0 and the position immediately to its right is `1,0`). 8 | 9 | Your job is to figure out which asteroid would be the best place to build a **new monitoring station**. A monitoring station can **detect** any asteroid to which it has **direct line of sight** - that is, there cannot be another asteroid **exactly** between them. This line of sight can be at any angle, not just lines aligned to the grid or diagonally. The **best** location is the asteroid that can **detect** the largest number of other asteroids. 10 | 11 | For example, consider the following map: 12 | 13 | ``` 14 | .#..# 15 | ..... 16 | ##### 17 | ....# 18 | ...## 19 | ``` 20 | 21 | The best location for a new monitoring station on this map is the highlighted asteroid at `3,4` because it can detect `8` asteroids, more than any other location. (The only asteroid it cannot detect is the one at `1,0`; its view of this asteroid is blocked by the asteroid at `2,2`.) All other asteroids are worse locations; they can detect `7` or fewer other asteroids. Here is the number of other asteroids a monitoring station on each asteroid could detect: 22 | 23 | ``` 24 | .7..7 25 | ..... 26 | 67775 27 | ....7 28 | ...87 29 | ``` 30 | 31 | Here is an asteroid (`#`) and some examples of the ways its line of sight might be blocked. If there were another asteroid at the location of a capital letter, the locations marked with the corresponding lowercase letter would be blocked and could not be detected: 32 | 33 | ``` 34 | #......... 35 | ...A...... 36 | ...B..a... 37 | .EDCG....a 38 | ..F.c.b... 39 | .....c.... 40 | ..efd.c.gb 41 | .......c.. 42 | ....f...c. 43 | ...e..d..c 44 | ``` 45 | 46 | Here are some larger examples: 47 | - Best is `5,8` with `33` other asteroids detected: 48 | ``` 49 | ......#.#. 50 | #..#.#.... 51 | ..#######. 52 | .#.#.###.. 53 | .#..#..... 54 | ..#....#.# 55 | #..#....#. 56 | .##.#..### 57 | ##...#..#. 58 | .#....#### 59 | ``` 60 | - Best is `1,2` with `35` other asteroids detected: 61 | ``` 62 | #.#...#.#. 63 | .###....#. 64 | .#....#... 65 | ##.#.#.#.# 66 | ....#.#.#. 67 | .##..###.# 68 | ..#...##.. 69 | ..##....## 70 | ......#... 71 | .####.###. 72 | ``` 73 | - Best is `6,3` with `41` other asteroids detected: 74 | ``` 75 | .#..#..### 76 | ####.###.# 77 | ....###.#. 78 | ..###.##.# 79 | ##.##.#.#. 80 | ....###..# 81 | ..#.#..#.# 82 | #..#.#.### 83 | .##...##.# 84 | .....#.#.. 85 | ``` 86 | - Best is `11,13` with `210` other asteroids detected: 87 | ``` 88 | .#..##.###...####### 89 | ##.############..##. 90 | .#.######.########.# 91 | .###.#######.####.#. 92 | #####.##.#.##.###.## 93 | ..#####..#.######### 94 | #################### 95 | #.####....###.#.#.## 96 | ##.################# 97 | #####.##.###..####.. 98 | ..######..##.####### 99 | ####.##.####...##..# 100 | .#####..#.######.### 101 | ##...#.##########... 102 | #.##########.####### 103 | .####.#.###.###.#.## 104 | ....##.##.###..##### 105 | .#.#.###########.### 106 | #.#.#.#####.####.### 107 | ###.##.####.##.#..## 108 | ``` 109 | 110 | Find the best location for a new monitoring station. **How many other asteroids can be detected from that location?** 111 | 112 | ## Part Two 113 | 114 | Once you give them the coordinates, the Elves quickly deploy an Instant Monitoring Station to the location and discover the worst: there are simply too many asteroids. 115 | 116 | The only solution is **complete vaporization by giant laser**. 117 | 118 | Fortunately, in addition to an asteroid scanner, the new monitoring station also comes equipped with a giant rotating laser perfect for vaporizing asteroids. The laser starts by pointing **up** and always rotates **clockwise**, vaporizing any asteroid it hits. 119 | 120 | If multiple asteroids are **exactly** in line with the station, the laser only has enough power to vaporize **one** of them before continuing its rotation. In other words, the same asteroids that can be **detected** can be vaporized, but if vaporizing one asteroid makes another one detectable, the newly-detected asteroid won't be vaporized until the laser has returned to the same position by rotating a full 360 degrees. 121 | 122 | For example, consider the following map, where the asteroid with the new monitoring station (and laser) is marked `X`: 123 | 124 | ``` 125 | .#....#####...#.. 126 | ##...##.#####..## 127 | ##...#...#.#####. 128 | ..#.....X...###.. 129 | ..#.#.....#....## 130 | ``` 131 | 132 | The first nine asteroids to get vaporized, in order, would be: 133 | 134 | ``` 135 | .#....###24...#.. 136 | ##...##.13#67..9# 137 | ##...#...5.8####. 138 | ..#.....X...###.. 139 | ..#.#.....#....## 140 | ``` 141 | 142 | Note that some asteroids (the ones behind the asteroids marked `1`, `5`, and `7`) won't have a chance to be vaporized until the next full rotation. The laser continues rotating; the next nine to be vaporized are: 143 | 144 | ``` 145 | .#....###.....#.. 146 | ##...##...#.....# 147 | ##...#......1234. 148 | ..#.....X...5##.. 149 | ..#.9.....8....76 150 | ``` 151 | 152 | The next nine to be vaporized are then: 153 | 154 | ``` 155 | .8....###.....#.. 156 | 56...9#...#.....# 157 | 34...7........... 158 | ..2.....X....##.. 159 | ..1.............. 160 | ``` 161 | 162 | Finally, the laser completes its first full rotation (`1` through `3`), a second rotation (`4` through `8`), and vaporizes the last asteroid (`9`) partway through its third rotation: 163 | 164 | ``` 165 | ......234.....6.. 166 | ......1...5.....7 167 | ................. 168 | ........X....89.. 169 | ................. 170 | ``` 171 | 172 | In the large example above (the one with the best monitoring station location at `11,13`): 173 | 174 | - The 1st asteroid to be vaporized is at `11,12`. 175 | - The 2nd asteroid to be vaporized is at `12,1`. 176 | - The 3rd asteroid to be vaporized is at `12,2`. 177 | - The 10th asteroid to be vaporized is at `12,8`. 178 | - The 20th asteroid to be vaporized is at `16,0`. 179 | - The 50th asteroid to be vaporized is at `16,9`. 180 | - The 100th asteroid to be vaporized is at `10,16`. 181 | - The 199th asteroid to be vaporized is at `9,6`. 182 | - **The 200th asteroid to be vaporized is at `8,2`.** 183 | - The 201st asteroid to be vaporized is at `10,9`. 184 | - The 299th and final asteroid to be vaporized is at `11,1`. 185 | 186 | The Elves are placing bets on which will be the **200th** asteroid to be vaporized. Win the bet by determining which asteroid that will be; **what do you get if you multiply its X coordinate by `100` and then add its Y coordinate?** (For example, `8,2` becomes **`802`**.) 187 | 188 | ## References 189 | - https://adventofcode.com/2019/day/10 190 | -------------------------------------------------------------------------------- /day-10-monitoring-station/station.js: -------------------------------------------------------------------------------- 1 | module.exports = (input) => { 2 | const asteroids = input 3 | .split('\n') 4 | .reduce((objects, line, y) => { 5 | line.trim().split('').forEach((space, x) => { 6 | if (space === '#') { 7 | objects.push({ x, y }); 8 | } 9 | }); 10 | 11 | return objects; 12 | }, []); 13 | 14 | return asteroids 15 | .map(({ x: x1, y: y1 }) => { 16 | const angles = new Set(); 17 | 18 | asteroids.forEach(({ x: x2, y: y2 }) => { 19 | if (!(x1 === x2 && y1 === y2)) { 20 | angles.add(Math.atan2(y2 - y1, x2 - x1)); 21 | } 22 | }); 23 | 24 | return { 25 | asteroids: angles.size, 26 | x: x1, 27 | y: y1, 28 | }; 29 | }) 30 | .sort((a, b) => b.asteroids - a.asteroids)[0]; 31 | }; 32 | -------------------------------------------------------------------------------- /day-10-monitoring-station/station2.js: -------------------------------------------------------------------------------- 1 | module.exports = (input, stationCoordinates = { x: 0, y: 0}) => { 2 | const { x: x1, y: y1 } = stationCoordinates; 3 | 4 | let targets = input 5 | .split('\n') 6 | .reduce((objects, line, y2) => { 7 | line.trim().split('').forEach((space, x2) => { 8 | if (space === '#' && !(x1 === x2 && y1 === y2)) { 9 | objects.push({ 10 | x: x2, 11 | y: y2, 12 | degrees: Math.atan2(y2 - y1, x2 - x1) * (180 / Math.PI), 13 | distance: Math.hypot(x1 - x2, y1 - y2), 14 | }); 15 | } 16 | }); 17 | 18 | return objects; 19 | }, []) 20 | .sort((a, b) => a.degrees - b.degrees); 21 | 22 | const targetDegrees = [...new Set(targets.map(({ degrees }) => degrees))]; 23 | 24 | let currentDegrees = targetDegrees.findIndex((degrees) => degrees === -90); 25 | let counter = 0; 26 | 27 | while (targets.length) { 28 | const target = targets 29 | .filter(({ degrees }) => degrees === targetDegrees[currentDegrees]) 30 | .sort((a, b) => a.distance - b.distance)[0]; 31 | 32 | if (target) { 33 | targets = targets.filter(({ x, y }) => !(x === target.x && y === target.y)); 34 | 35 | if (++counter === 200) { 36 | return target.x * 100 + target.y; 37 | } 38 | } 39 | 40 | currentDegrees = currentDegrees < targetDegrees.length ? currentDegrees + 1 : 0; 41 | } 42 | }; 43 | -------------------------------------------------------------------------------- /day-10-monitoring-station/test.js: -------------------------------------------------------------------------------- 1 | const assert = require('assert'); 2 | 3 | const station = require('./station'); 4 | const station2 = require('./station2'); 5 | 6 | describe('Day 10: Monitoring Station', () => { 7 | it('should determine best location in sample map 1 (small)', () => { 8 | const map = 9 | `.#..# 10 | ..... 11 | ##### 12 | ....# 13 | ...##`; 14 | 15 | assert.deepStrictEqual(station(map), { x: 3, y: 4, asteroids: 8 }); 16 | }); 17 | 18 | it('should determine best location in sample map 2 (medium)', () => { 19 | const map = 20 | `......#.#. 21 | #..#.#.... 22 | ..#######. 23 | .#.#.###.. 24 | .#..#..... 25 | ..#....#.# 26 | #..#....#. 27 | .##.#..### 28 | ##...#..#. 29 | .#....####`; 30 | 31 | assert.deepStrictEqual(station(map), { x: 5, y: 8, asteroids: 33 }); 32 | }); 33 | 34 | it('should determine best location in sample map 3 (medium)', () => { 35 | const map = 36 | `#.#...#.#. 37 | .###....#. 38 | .#....#... 39 | ##.#.#.#.# 40 | ....#.#.#. 41 | .##..###.# 42 | ..#...##.. 43 | ..##....## 44 | ......#... 45 | .####.###.`; 46 | 47 | assert.deepStrictEqual(station(map), { x: 1, y: 2, asteroids: 35 }); 48 | }); 49 | 50 | it('should determine best location in sample map 4 (medium)', () => { 51 | const map = 52 | `.#..#..### 53 | ####.###.# 54 | ....###.#. 55 | ..###.##.# 56 | ##.##.#.#. 57 | ....###..# 58 | ..#.#..#.# 59 | #..#.#.### 60 | .##...##.# 61 | .....#.#..`; 62 | 63 | assert.deepStrictEqual(station(map), { x: 6, y: 3, asteroids: 41 }); 64 | }); 65 | 66 | it('should determine best location in sample map 5 (large)', () => { 67 | const map = 68 | `.#..##.###...####### 69 | ##.############..##. 70 | .#.######.########.# 71 | .###.#######.####.#. 72 | #####.##.#.##.###.## 73 | ..#####..#.######### 74 | #################### 75 | #.####....###.#.#.## 76 | ##.################# 77 | #####.##.###..####.. 78 | ..######..##.####### 79 | ####.##.####...##..# 80 | .#####..#.######.### 81 | ##...#.##########... 82 | #.##########.####### 83 | .####.#.###.###.#.## 84 | ....##.##.###..##### 85 | .#.#.###########.### 86 | #.#.#.#####.####.### 87 | ###.##.####.##.#..##`; 88 | 89 | assert.deepStrictEqual(station(map), { x: 11, y: 13, asteroids: 210 }); 90 | }); 91 | 92 | describe('Part Two', () => { 93 | it('should find the 200th asteroid to be vaporized', () => { 94 | const map = 95 | `.#..##.###...####### 96 | ##.############..##. 97 | .#.######.########.# 98 | .###.#######.####.#. 99 | #####.##.#.##.###.## 100 | ..#####..#.######### 101 | #################### 102 | #.####....###.#.#.## 103 | ##.################# 104 | #####.##.###..####.. 105 | ..######..##.####### 106 | ####.##.####...##..# 107 | .#####..#.######.### 108 | ##...#.##########... 109 | #.##########.####### 110 | .####.#.###.###.#.## 111 | ....##.##.###..##### 112 | .#.#.###########.### 113 | #.#.#.#####.####.### 114 | ###.##.####.##.#..##`; 115 | 116 | assert.deepStrictEqual(station2(map, { x: 11, y: 13 }), 802); 117 | }); 118 | }); 119 | }); 120 | -------------------------------------------------------------------------------- /day-11-space-police/README.md: -------------------------------------------------------------------------------- 1 | # Day 11: Space Police 2 | 3 | On the way to Jupiter, you're [pulled over](https://www.youtube.com/watch?v=KwY28rpyKDE) by the **Space Police**. 4 | 5 | "Attention, unmarked spacecraft! You are in violation of Space Law! All spacecraft must have a clearly visible **registration identifier**! You have 24 hours to comply or be sent to [Space Jail](https://www.youtube.com/watch?v=BVn1oQL9sWg&t=5)!" 6 | 7 | Not wanting to be sent to Space Jail, you radio back to the Elves on Earth for help. Although it takes almost three hours for their reply signal to reach you, they send instructions for how to power up the **emergency hull painting robot** and even provide a small [Intcode program](https://adventofcode.com/2019/day/9) (your puzzle input) that will cause it to paint your ship appropriately. 8 | 9 | There's just one problem: you don't have an emergency hull painting robot. 10 | 11 | You'll need to build a new emergency hull painting robot. The robot needs to be able to move around on the grid of square panels on the side of your ship, detect the color of its current panel, and paint its current panel **black** or **white**. (All of the panels are currently **black**.) 12 | 13 | The Intcode program will serve as the brain of the robot. The program uses input instructions to access the robot's camera: provide `0` if the robot is over a **black** panel or `1` if the robot is over a **white** panel. Then, the program will output two values: 14 | 15 | - First, it will output a value indicating the **color to paint the panel** the robot is over: `0` means to paint the panel **black**, and `1` means to paint the panel **white**. 16 | - Second, it will output a value indicating the **direction the robot should turn**: `0` means it should turn **left 90 degrees**, and `1` means it should turn **right 90 degrees**. 17 | 18 | After the robot turns, it should always move **forward exactly one panel**. The robot starts facing **up**. 19 | 20 | The robot will continue running for a while like this and halt when it is finished drawing. Do not restart the Intcode computer inside the robot during this process. 21 | 22 | For example, suppose the robot is about to start running. Drawing black panels as `.`, white panels as `#`, and the robot pointing the direction it is facing (`< ^ > v`), the initial state and region near the robot looks like this: 23 | 24 | ``` 25 | ..... 26 | ..... 27 | ..^.. 28 | ..... 29 | ..... 30 | ``` 31 | 32 | The panel under the robot (not visible here because a `^` is shown instead) is also black, and so any input instructions at this point should be provided `0`. Suppose the robot eventually outputs `1` (paint white) and then `0` (turn left). After taking these actions and moving forward one panel, the region now looks like this: 33 | 34 | ``` 35 | ..... 36 | ..... 37 | .<#.. 38 | ..... 39 | ..... 40 | ``` 41 | 42 | Input instructions should still be provided `0`. Next, the robot might output `0` (paint black) and then `0` (turn left): 43 | 44 | ``` 45 | ..... 46 | ..... 47 | ..#.. 48 | .v... 49 | ..... 50 | ``` 51 | 52 | After more outputs (`1,0,` `1,0`): 53 | 54 | ``` 55 | ..... 56 | ..... 57 | ..^.. 58 | .##.. 59 | ..... 60 | ``` 61 | 62 | The robot is now back where it started, but because it is now on a white panel, input instructions should be provided `1`. After several more outputs (`0,1`, `1,0`, `1,0`), the area looks like this: 63 | 64 | ``` 65 | ..... 66 | ..<#. 67 | ...#. 68 | .##.. 69 | ..... 70 | ``` 71 | 72 | Before you deploy the robot, you should probably have an estimate of the area it will cover: specifically, you need to know the **number of panels it paints at least once**, regardless of color. In the example above, the robot painted **`6` panels** at least once. (It painted its starting panel twice, but that panel is [still only counted once](https://www.youtube.com/watch?v=KjsSvjA5TuE); it also never painted the panel it ended on.) 73 | 74 | Build a new emergency hull painting robot and run the Intcode program on it. **How many panels does it paint at least once?** 75 | 76 | ## Part Two 77 | 78 | You're not sure what it's trying to paint, but it's definitely not a **registration identifier**. The Space Police are getting impatient. 79 | 80 | Checking your external ship cameras again, you notice a white panel marked "emergency hull painting robot starting panel". The rest of the panels are **still black**, but it looks like the robot was expecting to **start on a white panel**, not a black one. 81 | 82 | Based on the Space Law Space Brochure that the Space Police attached to one of your windows, a valid registration identifier is always **eight capital letters**. After starting the robot on a single **white panel** instead, **what registration identifier does it paint** on your hull? 83 | 84 | ## References 85 | - https://adventofcode.com/2019/day/11 86 | -------------------------------------------------------------------------------- /day-11-space-police/intcode.js: -------------------------------------------------------------------------------- 1 | const POSITION_MODE = 0; 2 | const IMMEDIATE_MODE = 1; 3 | const RELATIVE_MODE = 2; 4 | 5 | const ADD = 1; 6 | const MULTIPLY = 2; 7 | const RECEIVE = 3; 8 | const SEND = 4; 9 | const JUMP_IF_NOT_ZERO = 5; 10 | const JUMP_IF_ZERO = 6; 11 | const LESS_THAN = 7; 12 | const EQUALS = 8; 13 | const ADJUST_RELATIVE_BASE = 9; 14 | 15 | module.exports = (memory, instructionPointer, relativeBase, input = []) => { 16 | let output = []; 17 | 18 | const getValue = (parameterMode, position) => { 19 | switch (parameterMode) { 20 | case POSITION_MODE: 21 | return memory[memory[position]]; 22 | case IMMEDIATE_MODE: 23 | return memory[position]; 24 | case RELATIVE_MODE: 25 | return memory[memory[position] + relativeBase]; 26 | } 27 | }; 28 | 29 | const getAddress = (parameterMode, position) => { 30 | if (parameterMode === POSITION_MODE) { 31 | return memory[position]; 32 | } else if (parameterMode === RELATIVE_MODE) { 33 | return memory[position] + relativeBase; 34 | } 35 | }; 36 | 37 | while (memory[instructionPointer] !== 99) { 38 | const instruction = `${memory[instructionPointer]}`.padStart(5, '0'); 39 | 40 | const opcode = Number(instruction.slice(3)); 41 | const parameter1Mode = Number(instruction[2]); 42 | const parameter2Mode = Number(instruction[1]); 43 | const parameter3Mode = Number(instruction[0]); 44 | 45 | if (opcode === ADD) { 46 | const parameter1 = getValue(parameter1Mode, instructionPointer + 1); 47 | const parameter2 = getValue(parameter2Mode, instructionPointer + 2); 48 | const parameter3 = getAddress(parameter3Mode, instructionPointer + 3); 49 | 50 | memory[parameter3] = parameter1 + parameter2; 51 | 52 | instructionPointer += 4; 53 | } else if (opcode === MULTIPLY) { 54 | const parameter1 = getValue(parameter1Mode, instructionPointer + 1); 55 | const parameter2 = getValue(parameter2Mode, instructionPointer + 2); 56 | const parameter3 = getAddress(parameter3Mode, instructionPointer + 3); 57 | 58 | memory[parameter3] = parameter1 * parameter2; 59 | 60 | instructionPointer += 4; 61 | } else if (opcode === RECEIVE) { 62 | const parameter1 = getAddress(parameter1Mode, instructionPointer + 1); 63 | 64 | memory[parameter1] = input.shift(); 65 | 66 | instructionPointer += 2; 67 | } else if (opcode === SEND) { 68 | output.push(getValue(parameter1Mode, instructionPointer + 1)); 69 | 70 | instructionPointer += 2; 71 | 72 | if (output.length === 2) { 73 | return [memory, instructionPointer, relativeBase, output]; 74 | } 75 | } else if (opcode === JUMP_IF_NOT_ZERO) { 76 | const parameter1 = getValue(parameter1Mode, instructionPointer + 1); 77 | const parameter2 = getValue(parameter2Mode, instructionPointer + 2); 78 | 79 | if (parameter1 !== 0) { 80 | instructionPointer = parameter2; 81 | } else { 82 | instructionPointer += 3; 83 | } 84 | } else if (opcode === JUMP_IF_ZERO) { 85 | const parameter1 = getValue(parameter1Mode, instructionPointer + 1); 86 | const parameter2 = getValue(parameter2Mode, instructionPointer + 2); 87 | 88 | if (parameter1 === 0) { 89 | instructionPointer = parameter2; 90 | } else { 91 | instructionPointer += 3; 92 | } 93 | } else if (opcode === LESS_THAN) { 94 | const parameter1 = getValue(parameter1Mode, instructionPointer + 1); 95 | const parameter2 = getValue(parameter2Mode, instructionPointer + 2); 96 | const parameter3 = getAddress(parameter3Mode, instructionPointer + 3); 97 | 98 | memory[parameter3] = parameter1 < parameter2 ? 1 : 0; 99 | 100 | instructionPointer += 4; 101 | } else if (opcode === EQUALS) { 102 | const parameter1 = getValue(parameter1Mode, instructionPointer + 1); 103 | const parameter2 = getValue(parameter2Mode, instructionPointer + 2); 104 | const parameter3 = getAddress(parameter3Mode, instructionPointer + 3); 105 | 106 | memory[parameter3] = parameter1 === parameter2 ? 1 : 0; 107 | 108 | instructionPointer += 4; 109 | } else if (opcode === ADJUST_RELATIVE_BASE) { 110 | const parameter1 = getValue(parameter1Mode, instructionPointer + 1); 111 | 112 | relativeBase += parameter1; 113 | 114 | instructionPointer += 2; 115 | } 116 | } 117 | 118 | return null; 119 | }; 120 | -------------------------------------------------------------------------------- /day-11-space-police/robot.js: -------------------------------------------------------------------------------- 1 | const intcode = require('./intcode'); 2 | 3 | module.exports = (instructions) => { 4 | const initialMemory = instructions 5 | .split(',') 6 | .map(Number); 7 | 8 | const panels = new Map(); 9 | 10 | let memory = [...initialMemory]; 11 | let instructionPointer = 0; 12 | let relativeBase = 0; 13 | 14 | let result = intcode(memory, instructionPointer, relativeBase, [0]); 15 | 16 | const position = { x: 0, y: 0, dx: 0, dy: -1 }; 17 | 18 | while (result) { 19 | let [memory, instructionPointer, relativeBase, output] = result; 20 | 21 | const turn = output[1] === 0 ? 'left' : 'right'; 22 | 23 | if ((panels.get(`${position.x},${position.y}`) || 0) !== output[0]) { 24 | panels.set(`${position.x},${position.y}`, output[0]); 25 | } 26 | 27 | const dx = position.dx === 0 ? turn === 'left' ? position.dy : position.dy * -1 : 0; 28 | const dy = position.dy === 0 ? turn === 'left' ? position.dx * -1 : position.dx : 0; 29 | 30 | position.dx = dx; 31 | position.dy = dy; 32 | position.x += position.dx; 33 | position.y += position.dy; 34 | 35 | const panel = panels.get(`${position.x},${position.y}`) || 0; 36 | 37 | result = intcode(memory, instructionPointer, relativeBase, [panel]); 38 | } 39 | 40 | return panels.size; 41 | }; 42 | -------------------------------------------------------------------------------- /day-11-space-police/robot2.js: -------------------------------------------------------------------------------- 1 | const intcode = require('./intcode'); 2 | 3 | const print = (panels) => { 4 | const keys = [...panels.keys()]; 5 | const [width, height] = keys 6 | .reduce(([maxWidth, maxHeight], xy) => { 7 | const [x, y] = xy.split(',').map(Number); 8 | 9 | return [Math.max(maxWidth, x), Math.max(maxHeight, y)]; 10 | }, [0, 0]); 11 | 12 | const canvas = Array 13 | .from({ length: height + 1 }) 14 | .map(() => Array 15 | .from({ length: width + 1 }) 16 | .map(() => ' ')); 17 | 18 | for (let i = 0; i < keys.length; i++) { 19 | const [x, y] = keys[i].split(',').map(Number); 20 | 21 | canvas[y][x] = panels.get(`${x},${y}`) === 1 ? '█' : ' '; 22 | } 23 | 24 | return canvas.map((row) => row.join('')).join('\n'); 25 | }; 26 | 27 | module.exports = (instructions) => { 28 | const initialMemory = instructions 29 | .split(',') 30 | .map(Number); 31 | 32 | const panels = new Map(); 33 | 34 | let memory = [...initialMemory]; 35 | let instructionPointer = 0; 36 | let relativeBase = 0; 37 | 38 | const getPanel = () => panels.get(`${position.x},${position.y}`) || 0; 39 | 40 | const position = { x: 0, y: 0, dx: 0, dy: -1 }; 41 | 42 | panels.set(`${position.x},${position.y}`, 1); 43 | 44 | let result = intcode(memory, instructionPointer, relativeBase, [getPanel()]); 45 | 46 | while (result) { 47 | let [memory, instructionPointer, relativeBase, output] = result; 48 | 49 | const turn = output[1] === 0 ? 'left' : 'right'; 50 | 51 | panels.set(`${position.x},${position.y}`, output[0]); 52 | 53 | const dx = position.dx === 0 ? turn === 'left' ? position.dy : position.dy * -1 : 0; 54 | const dy = position.dy === 0 ? turn === 'left' ? position.dx * -1 : position.dx : 0; 55 | 56 | position.dx = dx; 57 | position.dy = dy; 58 | position.x += position.dx; 59 | position.y += position.dy; 60 | 61 | result = intcode(memory, instructionPointer, relativeBase, [getPanel()]); 62 | } 63 | 64 | return print(panels); 65 | }; 66 | -------------------------------------------------------------------------------- /day-12-the-n-body-problem/README.md: -------------------------------------------------------------------------------- 1 | # Day 12: The N-Body Problem 2 | 3 | The space near Jupiter is not a very safe place; you need to be careful of a [big distracting red spot](https://en.wikipedia.org/wiki/Great_Red_Spot), extreme [radiation](https://en.wikipedia.org/wiki/Magnetosphere_of_Jupiter), and a [whole lot of moons](https://en.wikipedia.org/wiki/Moons_of_Jupiter#List) swirling around. You decide to start by tracking the four largest moons: **Io**, **Europa**, **Ganymede**, and **Callisto**. 4 | 5 | After a brief scan, you calculate the **position of each moon** (your puzzle input). You just need to **simulate their motion** so you can avoid them. 6 | 7 | Each moon has a 3-dimensional position (`x`, `y`, and `z`) and a 3-dimensional velocity. The position of each moon is given in your scan; the `x`, `y`, and `z` velocity of each moon starts at `0`. 8 | 9 | Simulate the motion of the moons in **time steps**. Within each time step, first update the velocity of every moon by applying **gravity**. Then, once all moons' velocities have been updated, update the position of every moon by applying **velocity**. Time progresses by one step once all of the positions are updated. 10 | 11 | To apply **gravity**, consider every **pair** of moons. On each axis (`x`, `y`, and `z`), the velocity of each moon changes by **exactly +1 or -1** to pull the moons together. For example, if Ganymede has an `x` position of `3`, and Callisto has a `x` position of `5`, then Ganymede's `x` velocity **changes by +1** (because `5 > 3`) and Callisto's `x` velocity **changes by -1** (because `3 < 5`). However, if the positions on a given axis are the same, the velocity on that axis **does not change** for that pair of moons. 12 | 13 | Once all gravity has been applied, apply **velocity**: simply add the velocity of each moon to its own position. For example, if Europa has a position of `x=1, y=2, z=3` and a velocity of `x=-2, y=0,z=3`, then its new position would be `x=-1, y=2, z=6`. This process does not modify the velocity of any moon. 14 | 15 | For example, suppose your scan reveals the following positions: 16 | 17 | ``` 18 | 19 | 20 | 21 | 22 | ``` 23 | 24 | Simulating the motion of these moons would produce the following: 25 | 26 | ``` 27 | After 0 steps: 28 | pos=, vel= 29 | pos=, vel= 30 | pos=, vel= 31 | pos=, vel= 32 | 33 | After 1 step: 34 | pos=, vel= 35 | pos=, vel= 36 | pos=, vel= 37 | pos=, vel= 38 | 39 | After 2 steps: 40 | pos=, vel= 41 | pos=, vel= 42 | pos=, vel= 43 | pos=, vel= 44 | 45 | After 3 steps: 46 | pos=, vel= 47 | pos=, vel= 48 | pos=, vel= 49 | pos=, vel= 50 | 51 | After 4 steps: 52 | pos=, vel= 53 | pos=, vel= 54 | pos=, vel= 55 | pos=, vel= 56 | 57 | After 5 steps: 58 | pos=, vel= 59 | pos=, vel= 60 | pos=, vel= 61 | pos=, vel= 62 | 63 | After 6 steps: 64 | pos=, vel= 65 | pos=, vel= 66 | pos=, vel= 67 | pos=, vel= 68 | 69 | After 7 steps: 70 | pos=, vel= 71 | pos=, vel= 72 | pos=, vel= 73 | pos=, vel= 74 | 75 | After 8 steps: 76 | pos=, vel= 77 | pos=, vel= 78 | pos=, vel= 79 | pos=, vel= 80 | 81 | After 9 steps: 82 | pos=, vel= 83 | pos=, vel= 84 | pos=, vel= 85 | pos=, vel= 86 | 87 | After 10 steps: 88 | pos=, vel= 89 | pos=, vel= 90 | pos=, vel= 91 | pos=, vel= 92 | ``` 93 | 94 | Then, it might help to calculate the **total energy in the system**. The total energy for a single moon is its **potential energy** multiplied by its **kinetic energy**. A moon's **potential energy** is the sum of the [absolute values](https://en.wikipedia.org/wiki/Absolute_value) of its `x`, `y`, and `z` position coordinates. A moon's **kinetic energy** is the sum of the absolute values of its velocity coordinates. Below, each line shows the calculations for a moon's potential energy (`pot`), kinetic energy (`kin`), and total energy: 95 | 96 | ``` 97 | Energy after 10 steps: 98 | pot: 2 + 1 + 3 = 6; kin: 3 + 2 + 1 = 6; total: 6 * 6 = 36 99 | pot: 1 + 8 + 0 = 9; kin: 1 + 1 + 3 = 5; total: 9 * 5 = 45 100 | pot: 3 + 6 + 1 = 10; kin: 3 + 2 + 3 = 8; total: 10 * 8 = 80 101 | pot: 2 + 0 + 4 = 6; kin: 1 + 1 + 1 = 3; total: 6 * 3 = 18 102 | Sum of total energy: 36 + 45 + 80 + 18 = 179 103 | ``` 104 | 105 | In the above example, adding together the total energy for all moons after 10 steps produces the total energy in the system, **`179`**. 106 | 107 | Here's a second example: 108 | 109 | ``` 110 | 111 | 112 | 113 | 114 | ``` 115 | 116 | Every ten steps of simulation for 100 steps produces: 117 | 118 | ``` 119 | After 0 steps: 120 | pos=, vel= 121 | pos=, vel= 122 | pos=, vel= 123 | pos=, vel= 124 | 125 | After 10 steps: 126 | pos=, vel= 127 | pos=, vel= 128 | pos=, vel= 129 | pos=, vel= 130 | 131 | After 20 steps: 132 | pos=, vel= 133 | pos=, vel= 134 | pos=, vel= 135 | pos=, vel= 136 | 137 | After 30 steps: 138 | pos=, vel= 139 | pos=, vel= 140 | pos=, vel= 141 | pos=, vel= 142 | 143 | After 40 steps: 144 | pos=, vel= 145 | pos=, vel= 146 | pos=, vel= 147 | pos=, vel= 148 | 149 | After 50 steps: 150 | pos=, vel= 151 | pos=, vel= 152 | pos=, vel= 153 | pos=, vel= 154 | 155 | After 60 steps: 156 | pos=, vel= 157 | pos=, vel= 158 | pos=, vel= 159 | pos=, vel= 160 | 161 | After 70 steps: 162 | pos=, vel= 163 | pos=, vel= 164 | pos=, vel= 165 | pos=, vel= 166 | 167 | After 80 steps: 168 | pos=, vel= 169 | pos=, vel= 170 | pos=, vel= 171 | pos=, vel= 172 | 173 | After 90 steps: 174 | pos=, vel= 175 | pos=, vel= 176 | pos=, vel= 177 | pos=, vel= 178 | 179 | After 100 steps: 180 | pos=, vel= 181 | pos=, vel= 182 | pos=, vel= 183 | pos=, vel= 184 | 185 | Energy after 100 steps: 186 | pot: 8 + 12 + 9 = 29; kin: 7 + 3 + 0 = 10; total: 29 * 10 = 290 187 | pot: 13 + 16 + 3 = 32; kin: 3 + 11 + 5 = 19; total: 32 * 19 = 608 188 | pot: 29 + 11 + 1 = 41; kin: 3 + 7 + 4 = 14; total: 41 * 14 = 574 189 | pot: 16 + 13 + 23 = 52; kin: 7 + 1 + 1 = 9; total: 52 * 9 = 468 190 | Sum of total energy: 290 + 608 + 574 + 468 = 1940 191 | ``` 192 | 193 | **What is the total energy in the system** after simulating the moons given in your scan for `1000` steps? 194 | 195 | ## Part Two 196 | 197 | All this drifting around in space makes you wonder about the nature of the universe. Does history really repeat itself? You're curious whether the moons will ever return to a previous state. 198 | 199 | Determine the **number of steps** that must occur before all of the moons' **positions and velocities** exactly match a previous point in time. 200 | 201 | For example, the first example above takes `2772` steps before they exactly match a previous point in time; it eventually returns to the initial state: 202 | 203 | ``` 204 | After 0 steps: 205 | pos=, vel= 206 | pos=, vel= 207 | pos=, vel= 208 | pos=, vel= 209 | 210 | After 2770 steps: 211 | pos=, vel= 212 | pos=, vel= 213 | pos=, vel= 214 | pos=, vel= 215 | 216 | After 2771 steps: 217 | pos=, vel= 218 | pos=, vel= 219 | pos=, vel= 220 | pos=, vel= 221 | 222 | After 2772 steps: 223 | pos=, vel= 224 | pos=, vel= 225 | pos=, vel= 226 | pos=, vel= 227 | ``` 228 | 229 | Of course, the universe might last for a **very long time** before repeating. Here's a copy of the second example from above: 230 | 231 | ``` 232 | 233 | 234 | 235 | 236 | ``` 237 | 238 | This set of initial positions takes `4686774924` steps before it repeats a previous state! Clearly, you might need to **find a more efficient way to simulate the universe**. 239 | 240 | **How many steps does it take** to reach the first state that exactly matches a previous state? 241 | 242 | ## References 243 | - https://adventofcode.com/2019/day/12 244 | -------------------------------------------------------------------------------- /day-12-the-n-body-problem/body.js: -------------------------------------------------------------------------------- 1 | const names = ['Io', 'Europa', 'Ganymede', 'Callisto']; 2 | 3 | const calculateEnergy = (moons) => { 4 | return moons 5 | .reduce((total, { x, y, z, vx, vy, vz }) => { 6 | const potentialEnergy = Math.abs(x) + Math.abs(y) + Math.abs(z); 7 | const kineticEnergy = Math.abs(vx) + Math.abs(vy) + Math.abs(vz); 8 | 9 | return total + potentialEnergy * kineticEnergy; 10 | }, 0); 11 | }; 12 | 13 | module.exports = (input, iterations = 1000) => { 14 | const moons = input 15 | .split('\n') 16 | .map((line, i) => { 17 | const [x, y, z] = line.match(/(-?\d+)/g).map(Number); 18 | 19 | return { x, y, z, vx: 0, vy: 0, vz: 0, name: names[i] }; 20 | }); 21 | 22 | for (let i = 0; i < iterations; i++) { 23 | moons.forEach((moon) => { 24 | const { x: x1, y: y1, z: z1 } = moon; 25 | 26 | moons 27 | .filter(({ name }) => name !== moon.name) 28 | .forEach(({ x: x2, y: y2, z: z2 }) => { 29 | moon.vx += x1 > x2 ? -1 : x1 < x2 ? 1 : 0; 30 | moon.vy += y1 > y2 ? -1 : y1 < y2 ? 1 : 0; 31 | moon.vz += z1 > z2 ? -1 : z1 < z2 ? 1 : 0; 32 | }); 33 | }); 34 | 35 | moons.forEach((moon) => { 36 | moon.x += moon.vx; 37 | moon.y += moon.vy; 38 | moon.z += moon.vz; 39 | }); 40 | } 41 | 42 | return calculateEnergy(moons); 43 | }; 44 | -------------------------------------------------------------------------------- /day-12-the-n-body-problem/body2.js: -------------------------------------------------------------------------------- 1 | const names = ['Io', 'Europa', 'Ganymede', 'Callisto']; 2 | const axes = ['x', 'y', 'z']; 3 | 4 | const getState = (moons, axis) => moons.map((moon) => moon[axis]).join(','); 5 | 6 | // greatest common divisor 7 | const gcd = (a, b) => !b ? a : gcd(b, a % b); 8 | 9 | // least common multiple 10 | const lcm = (a, b) => a * (b / gcd(a, b)); 11 | 12 | module.exports = (input) => { 13 | const moons = input 14 | .split('\n') 15 | .map((line, i) => { 16 | const [x, y, z] = line.match(/(-?\d+)/g).map(Number); 17 | 18 | return { x, y, z, vx: 0, vy: 0, vz: 0, name: names[i] }; 19 | }); 20 | 21 | const states = { 22 | x: [1, getState(moons, 'x'), false], 23 | y: [1, getState(moons, 'y'), false], 24 | z: [1, getState(moons, 'z'), false], 25 | }; 26 | 27 | while (!axes.every((axis) => states[axis][2])) { 28 | moons.forEach((moon) => { 29 | const { x: x1, y: y1, z: z1 } = moon; 30 | 31 | moons 32 | .filter(({ name }) => name !== moon.name) 33 | .forEach(({ x: x2, y: y2, z: z2 }) => { 34 | moon.vx += x1 > x2 ? -1 : x1 < x2 ? 1 : 0; 35 | moon.vy += y1 > y2 ? -1 : y1 < y2 ? 1 : 0; 36 | moon.vz += z1 > z2 ? -1 : z1 < z2 ? 1 : 0; 37 | }); 38 | }); 39 | 40 | moons.forEach((moon) => { 41 | moon.x += moon.vx; 42 | moon.y += moon.vy; 43 | moon.z += moon.vz; 44 | }); 45 | 46 | for (let a = 0; a < axes.length; a++) { 47 | const state = getState(moons, axes[a]); 48 | 49 | if (!states[axes[a]][2] && state === states[axes[a]][1]) { 50 | states[axes[a]][0] += 1; 51 | states[axes[a]][2] = true; 52 | } else if (!states[axes[a]][2]) { 53 | states[axes[a]][0] += 1; 54 | } 55 | } 56 | } 57 | 58 | return lcm(lcm(states.x[0], states.y[0]), states.z[0]); 59 | }; 60 | -------------------------------------------------------------------------------- /day-12-the-n-body-problem/test.js: -------------------------------------------------------------------------------- 1 | const assert = require('assert'); 2 | 3 | const body = require('./body'); 4 | const body2 = require('./body2'); 5 | 6 | describe('Day 12: The N-Body Problem', () => { 7 | it('should compute the total energy in system 1', () => { 8 | const system = 9 | ` 10 | 11 | 12 | `; 13 | 14 | assert.strictEqual(body(system, 10), 179); 15 | }); 16 | 17 | it('should compute the total energy in system 2', () => { 18 | const system = 19 | ` 20 | 21 | 22 | `; 23 | 24 | assert.strictEqual(body(system, 100), 1940); 25 | }); 26 | 27 | describe('Part Two', () => { 28 | it('should compute the steps in system 1', () => { 29 | const system = 30 | ` 31 | 32 | 33 | `; 34 | 35 | assert.strictEqual(body2(system), 2772); 36 | }); 37 | 38 | it('should compute the steps in system 2', () => { 39 | const system = 40 | ` 41 | 42 | 43 | `; 44 | 45 | assert.strictEqual(body2(system), 4686774924); 46 | }); 47 | }); 48 | }); 49 | -------------------------------------------------------------------------------- /day-13-care-package/README.md: -------------------------------------------------------------------------------- 1 | # Day 13: Care Package 2 | 3 | As you ponder the solitude of space and the ever-increasing three-hour roundtrip for messages between you and Earth, you notice that the Space Mail Indicator Light is blinking. To help keep you sane, the Elves have sent you a care package. 4 | 5 | It's a new game for the ship's [arcade cabinet](https://en.wikipedia.org/wiki/Arcade_cabinet)! Unfortunately, the arcade is **all the way** on the other end of the ship. Surely, it won't be hard to build your own - the care package even comes with schematics. 6 | 7 | The arcade cabinet runs [Intcode](https://adventofcode.com/2019/day/9) software like the game the Elves sent (your puzzle input). It has a primitive screen capable of drawing square **tiles** on a grid. The software draws tiles to the screen with output instructions: every three output instructions specify the `x` position (distance from the left), `y` position (distance from the top), and `tile id`. The `tile id` is interpreted as follows: 8 | 9 | - 0 is an **empty** tile. No game object appears in this tile. 10 | - 1 is a **wall** tile. Walls are indestructible barriers. 11 | - 2 is a **block** tile. Blocks can be broken by the ball. 12 | - 3 is a **horizontal paddle** tile. The paddle is indestructible. 13 | - 4 is a **ball** tile. The ball moves diagonally and bounces off objects. 14 | 15 | For example, a sequence of output values like `1,2,3,6,5,4` would draw a **horizontal paddle** tile (`1` tile from the left and `2` tiles from the top) and a **ball** tile (`6` tiles from the left and `5` tiles from the top). 16 | 17 | Start the game. **How many block tiles are on the screen when the game exits?** 18 | 19 | ## Part Two 20 | 21 | The game didn't run because you didn't put in any quarters. Unfortunately, you did not bring any quarters. Memory address `0` represents the number of quarters that have been inserted; set it to `2` to play for free. 22 | 23 | The arcade cabinet has a [joystick](https://en.wikipedia.org/wiki/Joystick) that can move left and right. The software reads the position of the joystick with input instructions: 24 | 25 | - If the joystick is in the **neutral position**, provide `0`. 26 | - If the joystick is **tilted to the left**, provide `-1`. 27 | - If the joystick is **tilted to the right**, provide `1`. 28 | 29 | The arcade cabinet also has a [segment display](https://en.wikipedia.org/wiki/Display_device#Segment_displays) capable of showing a single number that represents the player's current score. When three output instructions specify `X=-1, Y=0`, the third output instruction is not a tile; the value instead specifies the new score to show in the segment display. For example, a sequence of output values like `-1,0,12345` would show `12345` as the player's current score. 30 | 31 | Beat the game by breaking all the blocks. **What is your score after the last block is broken?** 32 | 33 | ## References 34 | - https://adventofcode.com/2019/day/13 35 | -------------------------------------------------------------------------------- /day-13-care-package/breakout.js: -------------------------------------------------------------------------------- 1 | const { EventEmitter } = require('events'); 2 | 3 | const POSITION_MODE = 0; 4 | const IMMEDIATE_MODE = 1; 5 | const RELATIVE_MODE = 2; 6 | 7 | const ADD = 1; 8 | const MULTIPLY = 2; 9 | const RECEIVE = 3; 10 | const SEND = 4; 11 | const JUMP_IF_NOT_ZERO = 5; 12 | const JUMP_IF_ZERO = 6; 13 | const LESS_THAN = 7; 14 | const EQUALS = 8; 15 | const ADJUST_RELATIVE_BASE = 9; 16 | const HALT = 99; 17 | 18 | const PADDLE = 3; 19 | const BALL = 4; 20 | 21 | class Breakout extends EventEmitter { 22 | constructor (program) { 23 | super(); 24 | 25 | this.memory = [...program]; 26 | this.instructionPointer = 0; 27 | this.relativeBase = 0; 28 | this.input = []; 29 | this.output = []; 30 | this.score; 31 | this.paused = false; 32 | this.paddlePositionX = 0; 33 | this.ballPositionX = 0; 34 | 35 | this.resolution = { 36 | width: 42, 37 | height: 20, 38 | }; 39 | 40 | this._tilemap = { 41 | 0: ' ', 42 | 1: '█', 43 | 2: '#', 44 | 3: '-', 45 | 4: 'o', 46 | }; 47 | 48 | this.frame = Array 49 | .from({ length: this.resolution.height }) 50 | .map(() => Array 51 | .from({ length: this.resolution.width }) 52 | .map(() => 0)); 53 | } 54 | 55 | _getValue(parameterMode, position) { 56 | switch (parameterMode) { 57 | case POSITION_MODE: 58 | return this.memory[this.memory[position]]; 59 | case IMMEDIATE_MODE: 60 | return this.memory[position]; 61 | case RELATIVE_MODE: 62 | return this.memory[this.memory[position] + this.relativeBase]; 63 | } 64 | } 65 | 66 | _getAddress(parameterMode, position) { 67 | if (parameterMode === POSITION_MODE) { 68 | return this.memory[position]; 69 | } else if (parameterMode === RELATIVE_MODE) { 70 | return this.memory[position] + this.relativeBase; 71 | } 72 | } 73 | 74 | paint() { 75 | return this.frame 76 | .map((row) => row 77 | .map((tile) => this._tilemap[tile]) 78 | .join('')) 79 | .join('\n'); 80 | } 81 | 82 | joystick(key) { 83 | this.input = [key === 'left' ? -1 : key === 'right' ? 1 : 0]; 84 | } 85 | 86 | run() { 87 | this.paused = false; 88 | 89 | while (!this.paused) { 90 | const instruction = `${this.memory[this.instructionPointer]}`.padStart(5, '0'); 91 | 92 | const opcode = Number(instruction.slice(3)); 93 | const parameter1Mode = Number(instruction[2]); 94 | const parameter2Mode = Number(instruction[1]); 95 | const parameter3Mode = Number(instruction[0]); 96 | 97 | if (opcode === ADD) { 98 | const parameter1 = this._getValue(parameter1Mode, this.instructionPointer + 1); 99 | const parameter2 = this._getValue(parameter2Mode, this.instructionPointer + 2); 100 | const parameter3 = this._getAddress(parameter3Mode, this.instructionPointer + 3); 101 | 102 | this.memory[parameter3] = parameter1 + parameter2; 103 | 104 | this.instructionPointer += 4; 105 | } else if (opcode === MULTIPLY) { 106 | const parameter1 = this._getValue(parameter1Mode, this.instructionPointer + 1); 107 | const parameter2 = this._getValue(parameter2Mode, this.instructionPointer + 2); 108 | const parameter3 = this._getAddress(parameter3Mode, this.instructionPointer + 3); 109 | 110 | this.memory[parameter3] = parameter1 * parameter2; 111 | 112 | this.instructionPointer += 4; 113 | } else if (opcode === RECEIVE) { 114 | const parameter1 = this._getAddress(parameter1Mode, this.instructionPointer + 1); 115 | 116 | if (this.paddlePositionX < this.ballPositionX) { 117 | this.joystick('right'); 118 | } else if (this.paddlePositionX > this.ballPositionX) { 119 | this.joystick('left'); 120 | } else { 121 | this.joystick('up'); 122 | } 123 | 124 | this.memory[parameter1] = this.input.shift(); 125 | 126 | this.instructionPointer += 2; 127 | } else if (opcode === SEND) { 128 | this.output.push(this._getValue(parameter1Mode, this.instructionPointer + 1)); 129 | 130 | if (this.output.length === 3) { 131 | if (this.output[0] === -1) { 132 | this.score = this.output[2]; 133 | 134 | this.emit('score', this.score); 135 | 136 | const frame = this.paint(); 137 | 138 | this.emit('frame', frame); 139 | } else { 140 | const [x, y, type] = this.output; 141 | 142 | this.frame[y][x] = type; 143 | 144 | if (type === BALL) { 145 | this.ballPositionX = x; 146 | } else if (type === PADDLE) { 147 | this.paddlePositionX = x; 148 | } 149 | } 150 | 151 | this.output = []; 152 | } 153 | 154 | this.instructionPointer += 2; 155 | } else if (opcode === JUMP_IF_NOT_ZERO) { 156 | const parameter1 = this._getValue(parameter1Mode, this.instructionPointer + 1); 157 | const parameter2 = this._getValue(parameter2Mode, this.instructionPointer + 2); 158 | 159 | if (parameter1 !== 0) { 160 | this.instructionPointer = parameter2; 161 | } else { 162 | this.instructionPointer += 3; 163 | } 164 | } else if (opcode === JUMP_IF_ZERO) { 165 | const parameter1 = this._getValue(parameter1Mode, this.instructionPointer + 1); 166 | const parameter2 = this._getValue(parameter2Mode, this.instructionPointer + 2); 167 | 168 | if (parameter1 === 0) { 169 | this.instructionPointer = parameter2; 170 | } else { 171 | this.instructionPointer += 3; 172 | } 173 | } else if (opcode === LESS_THAN) { 174 | const parameter1 = this._getValue(parameter1Mode, this.instructionPointer + 1); 175 | const parameter2 = this._getValue(parameter2Mode, this.instructionPointer + 2); 176 | const parameter3 = this._getAddress(parameter3Mode, this.instructionPointer + 3); 177 | 178 | this.memory[parameter3] = parameter1 < parameter2 ? 1 : 0; 179 | 180 | this.instructionPointer += 4; 181 | } else if (opcode === EQUALS) { 182 | const parameter1 = this._getValue(parameter1Mode, this.instructionPointer + 1); 183 | const parameter2 = this._getValue(parameter2Mode, this.instructionPointer + 2); 184 | const parameter3 = this._getAddress(parameter3Mode, this.instructionPointer + 3); 185 | 186 | this.memory[parameter3] = parameter1 === parameter2 ? 1 : 0; 187 | 188 | this.instructionPointer += 4; 189 | } else if (opcode === ADJUST_RELATIVE_BASE) { 190 | const parameter1 = this._getValue(parameter1Mode, this.instructionPointer + 1); 191 | 192 | this.relativeBase += parameter1; 193 | 194 | this.instructionPointer += 2; 195 | } else if (opcode === HALT) { 196 | this.emit('game-over'); 197 | 198 | this.paused = true; 199 | 200 | break; 201 | } 202 | } 203 | } 204 | } 205 | 206 | module.exports = Breakout; 207 | -------------------------------------------------------------------------------- /day-13-care-package/care.js: -------------------------------------------------------------------------------- 1 | const intcode = require('./intcode'); 2 | 3 | module.exports = (input) => { 4 | const program = input.split(',').map(Number); 5 | const output = intcode(program, []); 6 | 7 | let blocks = 0; 8 | 9 | for (let i = 0; i < output.length; i += 3) { 10 | if (output[i + 2] === 2) { 11 | blocks++; 12 | } 13 | } 14 | 15 | return blocks; 16 | }; 17 | -------------------------------------------------------------------------------- /day-13-care-package/care2.js: -------------------------------------------------------------------------------- 1 | const Breakout = require('./breakout'); 2 | 3 | const patchFreeGames = (memory) => { 4 | memory[0] = 2; 5 | 6 | return memory; 7 | }; 8 | 9 | module.exports = (input, display = false) => { 10 | const program = input.split(',').map(Number); 11 | const patchedProgram = patchFreeGames(program); 12 | const game = new Breakout(patchedProgram); 13 | 14 | let highscore = 0; 15 | 16 | game.on('frame', (frame) => { 17 | if (display) { 18 | console.log(frame, '\n'); // eslint-disable-line no-console 19 | } 20 | }); 21 | 22 | game.on('score', (score) => { 23 | highscore = score; 24 | }); 25 | 26 | game.on('game-over', () => { 27 | if (display) { 28 | // eslint-disable-next-line no-console 29 | console.log(`You win. Highscore: ${highscore}`); 30 | } 31 | }); 32 | 33 | game.run(); 34 | 35 | return highscore; 36 | }; 37 | -------------------------------------------------------------------------------- /day-13-care-package/intcode.js: -------------------------------------------------------------------------------- 1 | const POSITION_MODE = 0; 2 | const IMMEDIATE_MODE = 1; 3 | const RELATIVE_MODE = 2; 4 | 5 | const ADD = 1; 6 | const MULTIPLY = 2; 7 | const RECEIVE = 3; 8 | const SEND = 4; 9 | const JUMP_IF_NOT_ZERO = 5; 10 | const JUMP_IF_ZERO = 6; 11 | const LESS_THAN = 7; 12 | const EQUALS = 8; 13 | const ADJUST_RELATIVE_BASE = 9; 14 | 15 | module.exports = (initialMemoryState, input = []) => { 16 | const memory = [...initialMemoryState] 17 | // expand memory space 18 | .concat(Array.from({ length: 1024 }).map(() => 0)); 19 | 20 | let instructionPointer = 0; 21 | let relativeBase = 0; 22 | let output = []; 23 | 24 | const getValue = (parameterMode, position) => { 25 | switch (parameterMode) { 26 | case POSITION_MODE: 27 | return memory[memory[position]]; 28 | case IMMEDIATE_MODE: 29 | return memory[position]; 30 | case RELATIVE_MODE: 31 | return memory[memory[position] + relativeBase]; 32 | } 33 | }; 34 | 35 | const getAddress = (parameterMode, position) => { 36 | if (parameterMode === POSITION_MODE) { 37 | return memory[position]; 38 | } else if (parameterMode === RELATIVE_MODE) { 39 | return memory[position] + relativeBase; 40 | } 41 | }; 42 | 43 | while (memory[instructionPointer] !== 99) { 44 | const instruction = `${memory[instructionPointer]}`.padStart(5, '0'); 45 | 46 | const opcode = Number(instruction.slice(3)); 47 | const parameter1Mode = Number(instruction[2]); 48 | const parameter2Mode = Number(instruction[1]); 49 | const parameter3Mode = Number(instruction[0]); 50 | 51 | if (opcode === ADD) { 52 | const parameter1 = getValue(parameter1Mode, instructionPointer + 1); 53 | const parameter2 = getValue(parameter2Mode, instructionPointer + 2); 54 | const parameter3 = getAddress(parameter3Mode, instructionPointer + 3); 55 | 56 | memory[parameter3] = parameter1 + parameter2; 57 | 58 | instructionPointer += 4; 59 | } else if (opcode === MULTIPLY) { 60 | const parameter1 = getValue(parameter1Mode, instructionPointer + 1); 61 | const parameter2 = getValue(parameter2Mode, instructionPointer + 2); 62 | const parameter3 = getAddress(parameter3Mode, instructionPointer + 3); 63 | 64 | memory[parameter3] = parameter1 * parameter2; 65 | 66 | instructionPointer += 4; 67 | } else if (opcode === RECEIVE) { 68 | const parameter1 = getAddress(parameter1Mode, instructionPointer + 1); 69 | 70 | memory[parameter1] = input.shift(); 71 | console.log('RECEIVE', memory[parameter1]); 72 | 73 | instructionPointer += 2; 74 | } else if (opcode === SEND) { 75 | output.push(getValue(parameter1Mode, instructionPointer + 1)); 76 | console.log(getValue(parameter1Mode, instructionPointer + 1)); 77 | instructionPointer += 2; 78 | } else if (opcode === JUMP_IF_NOT_ZERO) { 79 | const parameter1 = getValue(parameter1Mode, instructionPointer + 1); 80 | const parameter2 = getValue(parameter2Mode, instructionPointer + 2); 81 | 82 | if (parameter1 !== 0) { 83 | instructionPointer = parameter2; 84 | } else { 85 | instructionPointer += 3; 86 | } 87 | } else if (opcode === JUMP_IF_ZERO) { 88 | const parameter1 = getValue(parameter1Mode, instructionPointer + 1); 89 | const parameter2 = getValue(parameter2Mode, instructionPointer + 2); 90 | 91 | if (parameter1 === 0) { 92 | instructionPointer = parameter2; 93 | } else { 94 | instructionPointer += 3; 95 | } 96 | } else if (opcode === LESS_THAN) { 97 | const parameter1 = getValue(parameter1Mode, instructionPointer + 1); 98 | const parameter2 = getValue(parameter2Mode, instructionPointer + 2); 99 | const parameter3 = getAddress(parameter3Mode, instructionPointer + 3); 100 | 101 | memory[parameter3] = parameter1 < parameter2 ? 1 : 0; 102 | 103 | instructionPointer += 4; 104 | } else if (opcode === EQUALS) { 105 | const parameter1 = getValue(parameter1Mode, instructionPointer + 1); 106 | const parameter2 = getValue(parameter2Mode, instructionPointer + 2); 107 | const parameter3 = getAddress(parameter3Mode, instructionPointer + 3); 108 | 109 | memory[parameter3] = parameter1 === parameter2 ? 1 : 0; 110 | 111 | instructionPointer += 4; 112 | } else if (opcode === ADJUST_RELATIVE_BASE) { 113 | const parameter1 = getValue(parameter1Mode, instructionPointer + 1); 114 | 115 | relativeBase += parameter1; 116 | 117 | instructionPointer += 2; 118 | } 119 | } 120 | 121 | return output; 122 | }; 123 | -------------------------------------------------------------------------------- /day-14-space-stoichiometry/README.md: -------------------------------------------------------------------------------- 1 | # Day 14: Space Stoichiometry 2 | 3 | As you approach the rings of Saturn, your ship's **low fuel** indicator turns on. There isn't any fuel here, but the rings have plenty of raw material. Perhaps your ship's Inter-Stellar Refinery Union brand **nanofactory** can turn these raw materials into fuel. 4 | 5 | You ask the nanofactory to produce a list of the **reactions** it can perform that are relevant to this process (your puzzle input). Every reaction turns some quantities of specific **input chemicals** into some quantity of an **output chemical**. Almost every **chemical** is produced by exactly one reaction; the only exception, **ORE**, is the raw material input to the entire process and is not produced by a reaction. 6 | 7 | You just need to know how much **`ORE`** you'll need to collect before you can produce one unit of **`FUEL`**. 8 | 9 | Each reaction gives specific quantities for its inputs and output; reactions cannot be partially run, so only whole integer multiples of these quantities can be used. (It's okay to have leftover chemicals when you're done, though.) For example, the reaction `1 A, 2 B, 3 C => 2 D` means that exactly 2 units of chemical `D` can be produced by consuming exactly 1 `A`, 2 `B` and 3 `C`. You can run the full reaction as many times as necessary; for example, you could produce 10 `D` by consuming 5 `A`, 10 `B`, and 15 `C`. 10 | 11 | Suppose your nanofactory produces the following list of reactions: 12 | 13 | ``` 14 | 10 ORE => 10 A 15 | 1 ORE => 1 B 16 | 7 A, 1 B => 1 C 17 | 7 A, 1 C => 1 D 18 | 7 A, 1 D => 1 E 19 | 7 A, 1 E => 1 FUEL 20 | ``` 21 | 22 | The first two reactions use only `ORE` as inputs; they indicate that you can produce as much of chemical `A` as you want (in increments of 10 units, each 10 costing 10 `ORE`) and as much of chemical `B` as you want (each costing 1 `ORE`). To produce 1 `FUEL`, a total of **31** `ORE` is required: 1 `ORE` to produce 1 `B`, then 30 more `ORE` to produce the 7 + 7 + 7 + 7 = 28 `A` (with 2 extra `A` wasted) required in the reactions to convert the `B` into `C`, `C` into `D`, `D` into `E`, and finally `E` into `FUEL`. (30 `A` is produced because its reaction requires that it is created in increments of 10.) 23 | 24 | Or, suppose you have the following list of reactions: 25 | 26 | ``` 27 | 9 ORE => 2 A 28 | 8 ORE => 3 B 29 | 7 ORE => 5 C 30 | 3 A, 4 B => 1 AB 31 | 5 B, 7 C => 1 BC 32 | 4 C, 1 A => 1 CA 33 | 2 AB, 3 BC, 4 CA => 1 FUEL 34 | ``` 35 | 36 | The above list of reactions requires **165** `ORE` to produce 1 `FUEL`: 37 | 38 | - Consume 45 `ORE` to produce 10 `A`. 39 | - Consume 64 `ORE` to produce 24 `B`. 40 | - Consume 56 `ORE` to produce 40 `C`. 41 | - Consume 6 `A`, 8 `B` to produce 2 `AB`. 42 | - Consume 15 `B`, 21 `C` to produce 3 `BC`. 43 | - Consume 16 `C`, 4 `A` to produce 4 `CA`. 44 | - Consume 2 `AB`, 3 `BC`, 4 `CA` to produce 1 `FUEL`. 45 | 46 | Here are some larger examples: 47 | 48 | - **13312** `ORE` for 1 `FUEL`: 49 | ``` 50 | 157 ORE => 5 NZVS 51 | 165 ORE => 6 DCFZ 52 | 44 XJWVT, 5 KHKGT, 1 QDVJ, 29 NZVS, 9 GPVTF, 48 HKGWZ => 1 FUEL 53 | 12 HKGWZ, 1 GPVTF, 8 PSHF => 9 QDVJ 54 | 179 ORE => 7 PSHF 55 | 177 ORE => 5 HKGWZ 56 | 7 DCFZ, 7 PSHF => 2 XJWVT 57 | 165 ORE => 2 GPVTF 58 | 3 DCFZ, 7 NZVS, 5 HKGWZ, 10 PSHF => 8 KHKGT 59 | ``` 60 | - **180697** `ORE` for 1 `FUEL`: 61 | ``` 62 | 2 VPVL, 7 FWMGM, 2 CXFTF, 11 MNCFX => 1 STKFG 63 | 17 NVRVD, 3 JNWZP => 8 VPVL 64 | 53 STKFG, 6 MNCFX, 46 VJHF, 81 HVMC, 68 CXFTF, 25 GNMV => 1 FUEL 65 | 22 VJHF, 37 MNCFX => 5 FWMGM 66 | 139 ORE => 4 NVRVD 67 | 144 ORE => 7 JNWZP 68 | 5 MNCFX, 7 RFSQX, 2 FWMGM, 2 VPVL, 19 CXFTF => 3 HVMC 69 | 5 VJHF, 7 MNCFX, 9 VPVL, 37 CXFTF => 6 GNMV 70 | 145 ORE => 6 MNCFX 71 | 1 NVRVD => 8 CXFTF 72 | 1 VJHF, 6 MNCFX => 4 RFSQX 73 | 176 ORE => 6 VJHF 74 | ``` 75 | - **2210736** `ORE` for 1 `FUEL`: 76 | ``` 77 | 171 ORE => 8 CNZTR 78 | 7 ZLQW, 3 BMBT, 9 XCVML, 26 XMNCP, 1 WPTQ, 2 MZWV, 1 RJRHP => 4 PLWSL 79 | 114 ORE => 4 BHXH 80 | 14 VRPVC => 6 BMBT 81 | 6 BHXH, 18 KTJDG, 12 WPTQ, 7 PLWSL, 31 FHTLT, 37 ZDVW => 1 FUEL 82 | 6 WPTQ, 2 BMBT, 8 ZLQW, 18 KTJDG, 1 XMNCP, 6 MZWV, 1 RJRHP => 6 FHTLT 83 | 15 XDBXC, 2 LTCX, 1 VRPVC => 6 ZLQW 84 | 13 WPTQ, 10 LTCX, 3 RJRHP, 14 XMNCP, 2 MZWV, 1 ZLQW => 1 ZDVW 85 | 5 BMBT => 4 WPTQ 86 | 189 ORE => 9 KTJDG 87 | 1 MZWV, 17 XDBXC, 3 XCVML => 2 XMNCP 88 | 12 VRPVC, 27 CNZTR => 2 XDBXC 89 | 15 KTJDG, 12 BHXH => 5 XCVML 90 | 3 BHXH, 2 VRPVC => 7 MZWV 91 | 121 ORE => 7 VRPVC 92 | 7 XCVML => 6 RJRHP 93 | 5 BHXH, 4 VRPVC => 5 LTCX 94 | ``` 95 | 96 | Given the list of reactions in your puzzle input, **what is the minimum amount of `ORE` required to produce exactly 1 `FUEL`?** 97 | 98 | ## Part Two 99 | 100 | After collecting `ORE` for a while, you check your cargo hold: **1 trillion** (**1000000000000**) units of `ORE`. 101 | 102 | **With that much ore**, given the examples above: 103 | 104 | - The 13312 `ORE`-per-`FUEL` example could produce **82892753** `FUEL`. 105 | - The 180697 `ORE`-per-`FUEL` example could produce **5586022** `FUEL`. 106 | - The 2210736 `ORE`-per-`FUEL` example could produce **460664** `FUEL`. 107 | 108 | Given 1 trillion `ORE`, **what is the maximum amount of `FUEL` you can produce?** 109 | 110 | ## References 111 | - https://adventofcode.com/2019/day/14 112 | -------------------------------------------------------------------------------- /day-14-space-stoichiometry/fuel.js: -------------------------------------------------------------------------------- 1 | module.exports = (input) => { 2 | const reactions = input 3 | .split('\n') 4 | .reduce((mixtures, line) => { 5 | const chemicals = line.split('=>'); 6 | const outputChemical = chemicals[1].match(/(\d+) (\w+)/g)[0]; 7 | 8 | mixtures[outputChemical.split(' ')[1]] = { 9 | amount: Number(outputChemical.split(' ')[0]), 10 | ingredients: chemicals[0].split(',').map((ingredient) => { 11 | const inputChemical = ingredient.match(/(\d+) (\w+)/g)[0]; 12 | 13 | return { 14 | amount: Number(inputChemical.split(' ')[0]), 15 | chemical: inputChemical.split(' ')[1], 16 | }; 17 | }), 18 | }; 19 | 20 | return mixtures; 21 | }, {}); 22 | 23 | const isBaseMaterial = (chemical) => 24 | reactions[chemical].ingredients[0].chemical === 'ORE'; 25 | 26 | const materials = Object 27 | .keys(reactions) 28 | .reduce((all, key) => { 29 | all[key] = 0; 30 | 31 | return all; 32 | }, {}); 33 | 34 | let totalOreRequired = 0; 35 | 36 | const buyBasics = (chemical, amount) => { 37 | if (materials[chemical] > 0) { 38 | const existing = materials[chemical]; 39 | const leftOver = Math.max(0, existing - amount); 40 | 41 | amount -= existing - leftOver; 42 | materials[chemical] = leftOver; 43 | } 44 | 45 | const reaction = reactions[chemical]; 46 | const multiplier = Math.ceil(amount / reaction.amount); 47 | 48 | materials[chemical] += multiplier * reaction.amount; 49 | 50 | if (isBaseMaterial(chemical)) { 51 | const oreRequiredForReaction = reactions[chemical].ingredients[0].amount; 52 | 53 | totalOreRequired += multiplier * oreRequiredForReaction; 54 | } else { 55 | reactions[chemical].ingredients.forEach((ingredient) => { 56 | buyBasics(ingredient.chemical, ingredient.amount * multiplier); 57 | }); 58 | } 59 | 60 | materials[chemical] -= amount; 61 | }; 62 | 63 | buyBasics('FUEL', 1); 64 | 65 | return totalOreRequired; 66 | }; 67 | -------------------------------------------------------------------------------- /day-14-space-stoichiometry/fuel2.js: -------------------------------------------------------------------------------- 1 | const calculateOreUsage = (reactions, fuel) => { 2 | let totalOreRequired = 0; 3 | 4 | const baseMaterials = new Set( 5 | Object 6 | .keys(reactions) 7 | .filter((key) => reactions[key].ingredients[0].chemical === 'ORE') 8 | ); 9 | 10 | const materials = Object 11 | .keys(reactions) 12 | .reduce((all, key) => { 13 | all[key] = 0; 14 | 15 | return all; 16 | }, {}); 17 | 18 | const buyBasics = (chemical, amount) => { 19 | if (materials[chemical] > 0) { 20 | const existing = materials[chemical]; 21 | const leftOver = Math.max(0, existing - amount); 22 | 23 | amount -= existing - leftOver; 24 | materials[chemical] = leftOver; 25 | } 26 | 27 | const reaction = reactions[chemical]; 28 | const multiplier = Math.ceil(amount / reaction.amount); 29 | 30 | materials[chemical] += multiplier * reaction.amount - amount; 31 | 32 | if (baseMaterials.has(chemical)) { 33 | const oreRequiredForReaction = reactions[chemical].ingredients[0].amount; 34 | 35 | totalOreRequired += multiplier * oreRequiredForReaction; 36 | } else { 37 | for (let i = 0; i < reactions[chemical].ingredients.length; i++) { 38 | const ingredient = reactions[chemical].ingredients[i]; 39 | 40 | buyBasics(ingredient.chemical, ingredient.amount * multiplier); 41 | } 42 | } 43 | }; 44 | 45 | buyBasics('FUEL', fuel); 46 | 47 | return totalOreRequired; 48 | }; 49 | 50 | module.exports = (input) => { 51 | const cargo = 1000000000000; 52 | const reactions = input 53 | .split('\n') 54 | .reduce((mixtures, line) => { 55 | const chemicals = line.split('=>'); 56 | const outputChemical = chemicals[1].match(/(\d+) (\w+)/g)[0]; 57 | 58 | mixtures[outputChemical.split(' ')[1]] = { 59 | amount: Number(outputChemical.split(' ')[0]), 60 | ingredients: chemicals[0].split(',').map((ingredient) => { 61 | const inputChemical = ingredient.match(/(\d+) (\w+)/g)[0]; 62 | 63 | return { 64 | amount: Number(inputChemical.split(' ')[0]), 65 | chemical: inputChemical.split(' ')[1], 66 | }; 67 | }), 68 | }; 69 | 70 | return mixtures; 71 | }, {}); 72 | 73 | let fuel = cargo / 2; 74 | let low = 0; 75 | let high = cargo; 76 | 77 | const estimations = new Set(); 78 | 79 | do { 80 | const totalOreRequired = calculateOreUsage(reactions, fuel); 81 | 82 | if (totalOreRequired < cargo && estimations.has(fuel)) { 83 | return fuel; 84 | } 85 | 86 | estimations.add(fuel); 87 | 88 | if (totalOreRequired < cargo) { 89 | low = fuel; 90 | fuel += Math.ceil((high - low) / 2); 91 | } else { 92 | high = fuel; 93 | fuel -= Math.ceil((high - low) / 2); 94 | } 95 | } while (true); // eslint-disable-line no-constant-condition 96 | }; 97 | -------------------------------------------------------------------------------- /day-14-space-stoichiometry/test.js: -------------------------------------------------------------------------------- 1 | const assert = require('assert'); 2 | 3 | const fuel = require('./fuel'); 4 | const fuel2 = require('./fuel2'); 5 | 6 | describe('Day 14: Space Stoichiometry', () => { 7 | it('should calculate the number of ORE required per FUEL (sample 1)', () => { 8 | const input = 9 | `9 ORE => 2 A 10 | 8 ORE => 3 B 11 | 7 ORE => 5 C 12 | 3 A, 4 B => 1 AB 13 | 5 B, 7 C => 1 BC 14 | 4 C, 1 A => 1 CA 15 | 2 AB, 3 BC, 4 CA => 1 FUEL`; 16 | 17 | assert.strictEqual(fuel(input), 165); 18 | }); 19 | 20 | it('should calculate the number of ORE required per FUEL (sample 2)', () => { 21 | const input = 22 | `157 ORE => 5 NZVS 23 | 165 ORE => 6 DCFZ 24 | 44 XJWVT, 5 KHKGT, 1 QDVJ, 29 NZVS, 9 GPVTF, 48 HKGWZ => 1 FUEL 25 | 12 HKGWZ, 1 GPVTF, 8 PSHF => 9 QDVJ 26 | 179 ORE => 7 PSHF 27 | 177 ORE => 5 HKGWZ 28 | 7 DCFZ, 7 PSHF => 2 XJWVT 29 | 165 ORE => 2 GPVTF 30 | 3 DCFZ, 7 NZVS, 5 HKGWZ, 10 PSHF => 8 KHKGT`; 31 | 32 | assert.strictEqual(fuel(input), 13312); 33 | }); 34 | 35 | it('should calculate the number of ORE required per FUEL (sample 3)', () => { 36 | const input = 37 | `2 VPVL, 7 FWMGM, 2 CXFTF, 11 MNCFX => 1 STKFG 38 | 17 NVRVD, 3 JNWZP => 8 VPVL 39 | 53 STKFG, 6 MNCFX, 46 VJHF, 81 HVMC, 68 CXFTF, 25 GNMV => 1 FUEL 40 | 22 VJHF, 37 MNCFX => 5 FWMGM 41 | 139 ORE => 4 NVRVD 42 | 144 ORE => 7 JNWZP 43 | 5 MNCFX, 7 RFSQX, 2 FWMGM, 2 VPVL, 19 CXFTF => 3 HVMC 44 | 5 VJHF, 7 MNCFX, 9 VPVL, 37 CXFTF => 6 GNMV 45 | 145 ORE => 6 MNCFX 46 | 1 NVRVD => 8 CXFTF 47 | 1 VJHF, 6 MNCFX => 4 RFSQX 48 | 176 ORE => 6 VJHF`; 49 | 50 | assert.strictEqual(fuel(input), 180697); 51 | }); 52 | 53 | it('should calculate the number of ORE required per FUEL (sample 4)', () => { 54 | const input = 55 | `171 ORE => 8 CNZTR 56 | 7 ZLQW, 3 BMBT, 9 XCVML, 26 XMNCP, 1 WPTQ, 2 MZWV, 1 RJRHP => 4 PLWSL 57 | 114 ORE => 4 BHXH 58 | 14 VRPVC => 6 BMBT 59 | 6 BHXH, 18 KTJDG, 12 WPTQ, 7 PLWSL, 31 FHTLT, 37 ZDVW => 1 FUEL 60 | 6 WPTQ, 2 BMBT, 8 ZLQW, 18 KTJDG, 1 XMNCP, 6 MZWV, 1 RJRHP => 6 FHTLT 61 | 15 XDBXC, 2 LTCX, 1 VRPVC => 6 ZLQW 62 | 13 WPTQ, 10 LTCX, 3 RJRHP, 14 XMNCP, 2 MZWV, 1 ZLQW => 1 ZDVW 63 | 5 BMBT => 4 WPTQ 64 | 189 ORE => 9 KTJDG 65 | 1 MZWV, 17 XDBXC, 3 XCVML => 2 XMNCP 66 | 12 VRPVC, 27 CNZTR => 2 XDBXC 67 | 15 KTJDG, 12 BHXH => 5 XCVML 68 | 3 BHXH, 2 VRPVC => 7 MZWV 69 | 121 ORE => 7 VRPVC 70 | 7 XCVML => 6 RJRHP 71 | 5 BHXH, 4 VRPVC => 5 LTCX`; 72 | 73 | assert.strictEqual(fuel(input), 2210736); 74 | }); 75 | 76 | describe('Part Two', () => { 77 | it('should calculate the maximum amount of fuel per trillion ORE (sample 1)', () => { 78 | const input = 79 | `157 ORE => 5 NZVS 80 | 165 ORE => 6 DCFZ 81 | 44 XJWVT, 5 KHKGT, 1 QDVJ, 29 NZVS, 9 GPVTF, 48 HKGWZ => 1 FUEL 82 | 12 HKGWZ, 1 GPVTF, 8 PSHF => 9 QDVJ 83 | 179 ORE => 7 PSHF 84 | 177 ORE => 5 HKGWZ 85 | 7 DCFZ, 7 PSHF => 2 XJWVT 86 | 165 ORE => 2 GPVTF 87 | 3 DCFZ, 7 NZVS, 5 HKGWZ, 10 PSHF => 8 KHKGT`; 88 | 89 | assert.strictEqual(fuel2(input), 82892753); 90 | }); 91 | 92 | it('should calculate the maximum amount of fuel per trillion ORE (sample 2)', () => { 93 | const input = 94 | `2 VPVL, 7 FWMGM, 2 CXFTF, 11 MNCFX => 1 STKFG 95 | 17 NVRVD, 3 JNWZP => 8 VPVL 96 | 53 STKFG, 6 MNCFX, 46 VJHF, 81 HVMC, 68 CXFTF, 25 GNMV => 1 FUEL 97 | 22 VJHF, 37 MNCFX => 5 FWMGM 98 | 139 ORE => 4 NVRVD 99 | 144 ORE => 7 JNWZP 100 | 5 MNCFX, 7 RFSQX, 2 FWMGM, 2 VPVL, 19 CXFTF => 3 HVMC 101 | 5 VJHF, 7 MNCFX, 9 VPVL, 37 CXFTF => 6 GNMV 102 | 145 ORE => 6 MNCFX 103 | 1 NVRVD => 8 CXFTF 104 | 1 VJHF, 6 MNCFX => 4 RFSQX 105 | 176 ORE => 6 VJHF`; 106 | 107 | assert.strictEqual(fuel2(input), 5586022); 108 | }); 109 | 110 | it('should calculate the maximum amount of fuel per trillion ORE (sample 3)', () => { 111 | const input = 112 | `171 ORE => 8 CNZTR 113 | 7 ZLQW, 3 BMBT, 9 XCVML, 26 XMNCP, 1 WPTQ, 2 MZWV, 1 RJRHP => 4 PLWSL 114 | 114 ORE => 4 BHXH 115 | 14 VRPVC => 6 BMBT 116 | 6 BHXH, 18 KTJDG, 12 WPTQ, 7 PLWSL, 31 FHTLT, 37 ZDVW => 1 FUEL 117 | 6 WPTQ, 2 BMBT, 8 ZLQW, 18 KTJDG, 1 XMNCP, 6 MZWV, 1 RJRHP => 6 FHTLT 118 | 15 XDBXC, 2 LTCX, 1 VRPVC => 6 ZLQW 119 | 13 WPTQ, 10 LTCX, 3 RJRHP, 14 XMNCP, 2 MZWV, 1 ZLQW => 1 ZDVW 120 | 5 BMBT => 4 WPTQ 121 | 189 ORE => 9 KTJDG 122 | 1 MZWV, 17 XDBXC, 3 XCVML => 2 XMNCP 123 | 12 VRPVC, 27 CNZTR => 2 XDBXC 124 | 15 KTJDG, 12 BHXH => 5 XCVML 125 | 3 BHXH, 2 VRPVC => 7 MZWV 126 | 121 ORE => 7 VRPVC 127 | 7 XCVML => 6 RJRHP 128 | 5 BHXH, 4 VRPVC => 5 LTCX`; 129 | 130 | assert.strictEqual(fuel2(input), 460664); 131 | }); 132 | }); 133 | }); 134 | -------------------------------------------------------------------------------- /day-15-oxygen-system/README.md: -------------------------------------------------------------------------------- 1 | # Day 15: Oxygen System 2 | 3 | Out here in deep space, many things can go wrong. Fortunately, many of those things have indicator lights. Unfortunately, one of those lights is lit: the oxygen system for part of the ship has failed! 4 | 5 | According to the readouts, the oxygen system must have failed days ago after a rupture in oxygen tank two; that section of the ship was automatically sealed once oxygen levels went dangerously low. A single remotely-operated **repair droid** is your only option for fixing the oxygen system. 6 | 7 | The Elves' care package included an [Intcode](https://adventofcode.com/2019/day/9) program (your puzzle input) that you can use to remotely control the repair droid. By running that program, you can direct the repair droid to the oxygen system and fix the problem. 8 | 9 | The remote control program executes the following steps in a loop forever: 10 | 11 | - Accept a **movement command** via an input instruction. 12 | - Send the movement command to the repair droid. 13 | - Wait for the repair droid to finish the movement operation. 14 | - Report on the **status** of the repair droid via an output instruction. 15 | 16 | Only four **movement commands** are understood: north (`1`), south (`2`), west (`3`), and east (`4`). Any other command is invalid. The movements differ in direction, but not in distance: in a long enough east-west hallway, a series of commands like `4,4,4,4,3,3,3,3` would leave the repair droid back where it started. 17 | 18 | The repair droid can reply with any of the following **status** codes: 19 | 20 | - `0`: The repair droid hit a wall. Its position has not changed. 21 | - `1`: The repair droid has moved one step in the requested direction. 22 | - `2`: The repair droid has moved one step in the requested direction; its new position is the location of the oxygen system. 23 | 24 | You don't know anything about the area around the repair droid, but you can figure it out by watching the status codes. 25 | 26 | For example, we can draw the area using `D` for the droid, `#` for walls, `.` for locations the droid can traverse, and empty space for unexplored locations. Then, the initial state looks like this: 27 | 28 | ``` 29 | 30 | 31 | D 32 | 33 | 34 | ``` 35 | To make the droid go north, send it `1`. If it replies with `0`, you know that location is a wall and that the droid didn't move: 36 | 37 | ``` 38 | 39 | # 40 | D 41 | 42 | 43 | ``` 44 | 45 | To move east, send `4`; a reply of `1` means the movement was successful: 46 | 47 | ``` 48 | 49 | # 50 | .D 51 | 52 | 53 | ``` 54 | 55 | Then, perhaps attempts to move north (`1`), south (`2`), and east (`4`) are all met with replies of `0`: 56 | 57 | ``` 58 | 59 | ## 60 | .D# 61 | # 62 | 63 | ``` 64 | 65 | Now, you know the repair droid is in a dead end. Backtrack with `3` (which you already know will get a reply of `1` because you already know that location is open): 66 | 67 | ``` 68 | 69 | ## 70 | D.# 71 | # 72 | 73 | ``` 74 | 75 | Then, perhaps west (`3`) gets a reply of `0`, south (`2`) gets a reply of `1`, south again (`2`) gets a reply of `0`, and then west (`3`) gets a reply of `2`: 76 | 77 | ``` 78 | 79 | ## 80 | #..# 81 | D.# 82 | # 83 | ``` 84 | 85 | Now, because of the reply of `2`, you know you've found the **oxygen system**! In this example, it was only **`2`** moves away from the repair droid's starting position. 86 | 87 | **What is the fewest number of movement commands** required to move the repair droid from its starting position to the location of the oxygen system? 88 | 89 | ## Part Two 90 | 91 | You quickly repair the oxygen system; oxygen gradually fills the area. 92 | 93 | Oxygen starts in the location containing the repaired oxygen system. It takes **one minute** for oxygen to spread to all open locations that are adjacent to a location that already contains oxygen. Diagonal locations are **not** adjacent. 94 | 95 | In the example above, suppose you've used the droid to explore the area fully and have the following map (where locations that currently contain oxygen are marked `O`): 96 | 97 | ``` 98 | ## 99 | #..## 100 | #.#..# 101 | #.O.# 102 | ### 103 | ``` 104 | 105 | Initially, the only location which contains oxygen is the location of the repaired oxygen system. However, after one minute, the oxygen spreads to all open (`.`) locations that are adjacent to a location containing oxygen: 106 | 107 | ``` 108 | ## 109 | #..## 110 | #.#..# 111 | #OOO# 112 | ### 113 | ``` 114 | After a total of two minutes, the map looks like this: 115 | 116 | ``` 117 | ## 118 | #..## 119 | #O#O.# 120 | #OOO# 121 | ### 122 | ``` 123 | 124 | After a total of three minutes: 125 | 126 | ``` 127 | ## 128 | #O.## 129 | #O#OO# 130 | #OOO# 131 | ### 132 | ``` 133 | 134 | And finally, the whole region is full of oxygen after a total of four minutes: 135 | 136 | ``` 137 | ## 138 | #OO## 139 | #O#OO# 140 | #OOO# 141 | ### 142 | ``` 143 | 144 | So, in this example, all locations contain oxygen after **`4`** minutes. 145 | 146 | Use the repair droid to get a complete map of the area. **How many minutes will it take to fill with oxygen?** 147 | 148 | ## References 149 | - https://adventofcode.com/2019/day/15 150 | -------------------------------------------------------------------------------- /day-15-oxygen-system/oxygen.js: -------------------------------------------------------------------------------- 1 | const RepairDroid = require('./repairDroid'); 2 | 3 | const getOpposite = (direction) => 4 | direction === 'west' 5 | ? 'east' 6 | : direction === 'east' 7 | ? 'west' 8 | : direction === 'north' 9 | ? 'south' 10 | : 'north'; 11 | 12 | module.exports = (input) => { 13 | const program = input.split(',').map(Number); 14 | const droid = new RepairDroid(program); 15 | 16 | const undoAll = (movements) => { 17 | while (movements.length) { 18 | const movement = getOpposite(movements.shift()); 19 | 20 | droid.move([movement]); 21 | } 22 | }; 23 | 24 | let stack = []; 25 | let stepsRequired = 0; 26 | 27 | const branches = [[]]; 28 | 29 | do { 30 | const branch = branches.pop(); 31 | 32 | stack = [...branch]; 33 | 34 | if (stack.length) { 35 | droid.move([...stack]); 36 | } 37 | 38 | do { 39 | const possibleMoves = droid.lookAround(stack[0]); 40 | 41 | if (possibleMoves.length === 0) { 42 | undoAll([...stack]); 43 | 44 | break; 45 | } else if (possibleMoves.length === 1) { 46 | stack.unshift(possibleMoves[0]); 47 | 48 | const status = droid.move([possibleMoves[0]]); 49 | 50 | if (status === 2) { 51 | stepsRequired = stack.length; 52 | } 53 | } else { 54 | possibleMoves.forEach((move) => branches.push([move, ...stack])); 55 | 56 | undoAll([...stack]); 57 | break; 58 | } 59 | } while (true); // eslint-disable-line no-constant-condition 60 | } while (branches.length); 61 | 62 | // eslint-disable-next-line no-console 63 | console.log(droid.print()); 64 | 65 | return stepsRequired; 66 | }; 67 | -------------------------------------------------------------------------------- /day-15-oxygen-system/oxygen2.js: -------------------------------------------------------------------------------- 1 | const RepairDroid = require('./repairDroid'); 2 | 3 | const getOpposite = (direction) => 4 | direction === 'west' 5 | ? 'east' 6 | : direction === 'east' 7 | ? 'west' 8 | : direction === 'north' 9 | ? 'south' 10 | : 'north'; 11 | 12 | module.exports = (input) => { 13 | const program = input.split(',').map(Number); 14 | const droid = new RepairDroid(program); 15 | 16 | const undoAll = (movements) => { 17 | while (movements.length) { 18 | const movement = getOpposite(movements.shift()); 19 | 20 | droid.move([movement]); 21 | } 22 | }; 23 | 24 | let stack = []; 25 | let shortestPath = []; 26 | 27 | const branches = [[]]; 28 | 29 | do { 30 | const branch = branches.pop(); 31 | 32 | stack = [...branch]; 33 | 34 | if (stack.length) { 35 | droid.move([...stack]); 36 | } 37 | 38 | do { 39 | const possibleMoves = droid.lookAround(stack[0]); 40 | 41 | if (possibleMoves.length === 0) { 42 | undoAll([...stack]); 43 | 44 | break; 45 | } else if (possibleMoves.length === 1) { 46 | stack.unshift(possibleMoves[0]); 47 | 48 | const status = droid.move([possibleMoves[0]]); 49 | 50 | if (status === 2) { 51 | shortestPath = [...stack]; 52 | } 53 | } else { 54 | possibleMoves.forEach((move) => branches.push([move, ...stack])); 55 | 56 | undoAll([...stack]); 57 | break; 58 | } 59 | } while (true); // eslint-disable-line no-constant-condition 60 | } while (branches.length); 61 | 62 | droid.move(shortestPath); 63 | branches.push([]); 64 | 65 | const pathLengths = []; 66 | 67 | do { 68 | const branch = branches.pop(); 69 | 70 | stack = [...branch]; 71 | 72 | if (stack.length) { 73 | droid.move([...stack]); 74 | } 75 | 76 | do { 77 | const possibleMoves = droid.lookAround(stack[0]); 78 | 79 | if (possibleMoves.length === 0) { 80 | undoAll([...stack]); 81 | pathLengths.push(stack.length); 82 | break; 83 | } else if (possibleMoves.length === 1) { 84 | stack.unshift(possibleMoves[0]); 85 | droid.move([possibleMoves[0]]); 86 | } else { 87 | possibleMoves.forEach((move) => branches.push([move, ...stack])); 88 | 89 | undoAll([...stack]); 90 | break; 91 | } 92 | } while (true); // eslint-disable-line no-constant-condition 93 | } while (branches.length); 94 | 95 | return pathLengths.sort((a, b) => b - a)[0]; 96 | }; 97 | -------------------------------------------------------------------------------- /day-15-oxygen-system/repairDroid.js: -------------------------------------------------------------------------------- 1 | const POSITION_MODE = 0; 2 | const IMMEDIATE_MODE = 1; 3 | const RELATIVE_MODE = 2; 4 | 5 | const ADD = 1; 6 | const MULTIPLY = 2; 7 | const RECEIVE = 3; 8 | const SEND = 4; 9 | const JUMP_IF_NOT_ZERO = 5; 10 | const JUMP_IF_ZERO = 6; 11 | const LESS_THAN = 7; 12 | const EQUALS = 8; 13 | const ADJUST_RELATIVE_BASE = 9; 14 | const HALT = 99; 15 | 16 | const directions = { 17 | 1: 'north', 18 | north: 1, 19 | 2: 'south', 20 | south: 2, 21 | 3: 'west', 22 | west: 3, 23 | 4: 'east', 24 | east: 4, 25 | }; 26 | 27 | const statuses = ['█', '.', 'o']; 28 | 29 | const getOpposite = (direction) => 30 | direction === 'west' 31 | ? 'east' 32 | : direction === 'east' 33 | ? 'west' 34 | : direction === 'north' 35 | ? 'south' 36 | : 'north'; 37 | 38 | class RepairDroid { 39 | constructor (program) { 40 | this.memory = [...program]; 41 | this.instructionPointer = 0; 42 | this.relativeBase = 0; 43 | this.input = []; 44 | this.output = []; 45 | this.paused = false; 46 | this.lastMoveCommand = null; 47 | 48 | this.position = { 49 | x: 0, 50 | y: 0, 51 | }; 52 | 53 | this._map = new Map(); 54 | } 55 | 56 | _getValue(parameterMode, position) { 57 | switch (parameterMode) { 58 | case POSITION_MODE: 59 | return this.memory[this.memory[position]]; 60 | case IMMEDIATE_MODE: 61 | return this.memory[position]; 62 | case RELATIVE_MODE: 63 | return this.memory[this.memory[position] + this.relativeBase]; 64 | } 65 | } 66 | 67 | _getAddress(parameterMode, position) { 68 | if (parameterMode === POSITION_MODE) { 69 | return this.memory[position]; 70 | } else if (parameterMode === RELATIVE_MODE) { 71 | return this.memory[position] + this.relativeBase; 72 | } 73 | } 74 | 75 | move(commands = []) { 76 | this.input = commands.map((direction) => directions[direction]); 77 | 78 | return this._run(); 79 | } 80 | 81 | lookAround(lastDirection) { 82 | const directions = ['north', 'east', 'south', 'west']; 83 | const possibleDirections = []; 84 | 85 | directions.forEach((direction) => { 86 | const opposite = getOpposite(direction); 87 | const status = this.move([direction]); 88 | 89 | if (status !== 0) { 90 | if (!lastDirection || direction !== getOpposite(lastDirection)) { 91 | possibleDirections.push(direction); 92 | } 93 | 94 | this.move([opposite]); 95 | } 96 | }); 97 | 98 | return possibleDirections; 99 | } 100 | 101 | print() { 102 | const dimensions = [...this._map.keys()].reduce((points, key) => { 103 | const [x, y] = key.split(',').map(Number); 104 | 105 | if (x < points.minX) points.minX = x; 106 | if (x > points.maxX) points.maxX = x; 107 | if (y < points.minY) points.minY = y; 108 | if (y > points.maxY) points.maxY = y; 109 | 110 | return points; 111 | }, { minX: 0, maxX: 0, minY: 0, maxY: 0 }); 112 | 113 | const dx = Math.abs(dimensions.minX); 114 | const dy = Math.abs(dimensions.minY); 115 | const width = Math.abs(dimensions.minX - dimensions.maxX) + 1; 116 | const height = Math.abs(dimensions.minY - dimensions.maxY) + 1; 117 | 118 | const maze = Array 119 | .from({ length: height }) 120 | .map(() => Array 121 | .from({ length: width }).map(() => '+')); 122 | 123 | [...this._map.entries()].forEach(([key, value]) => { 124 | const [x, y] = key.split(',').map(Number); 125 | const status = statuses[value]; 126 | 127 | maze[y + dy][x + dx] = status; 128 | }); 129 | 130 | maze[this.position.y + dy][this.position.x + dx] = 'X'; 131 | 132 | return maze 133 | .map((row) => row.join('')) 134 | .join('\n'); 135 | } 136 | 137 | _getRelativeCoordinate(direction) { 138 | switch (directions[direction]) { 139 | case ('north'): 140 | return { x: this.position.x, y: this.position.y - 1 }; 141 | case ('south'): 142 | return { x: this.position.x, y: this.position.y + 1 }; 143 | case ('west'): 144 | return { x: this.position.x - 1, y: this.position.y }; 145 | case ('east'): 146 | return { x: this.position.x + 1, y: this.position.y }; 147 | } 148 | } 149 | 150 | _run() { 151 | this.paused = false; 152 | 153 | while (!this.paused) { 154 | const instruction = `${this.memory[this.instructionPointer]}`.padStart(5, '0'); 155 | 156 | const opcode = Number(instruction.slice(3)); 157 | const parameter1Mode = Number(instruction[2]); 158 | const parameter2Mode = Number(instruction[1]); 159 | const parameter3Mode = Number(instruction[0]); 160 | 161 | if (opcode === ADD) { 162 | const parameter1 = this._getValue(parameter1Mode, this.instructionPointer + 1); 163 | const parameter2 = this._getValue(parameter2Mode, this.instructionPointer + 2); 164 | const parameter3 = this._getAddress(parameter3Mode, this.instructionPointer + 3); 165 | 166 | this.memory[parameter3] = parameter1 + parameter2; 167 | 168 | this.instructionPointer += 4; 169 | } else if (opcode === MULTIPLY) { 170 | const parameter1 = this._getValue(parameter1Mode, this.instructionPointer + 1); 171 | const parameter2 = this._getValue(parameter2Mode, this.instructionPointer + 2); 172 | const parameter3 = this._getAddress(parameter3Mode, this.instructionPointer + 3); 173 | 174 | this.memory[parameter3] = parameter1 * parameter2; 175 | 176 | this.instructionPointer += 4; 177 | } else if (opcode === RECEIVE) { 178 | const parameter1 = this._getAddress(parameter1Mode, this.instructionPointer + 1); 179 | 180 | this.memory[parameter1] = this.input.pop(); 181 | this.lastMoveCommand = this.memory[parameter1]; 182 | 183 | this.instructionPointer += 2; 184 | } else if (opcode === SEND) { 185 | const status = this._getValue(parameter1Mode, this.instructionPointer + 1); 186 | const position = this._getRelativeCoordinate(this.lastMoveCommand); 187 | 188 | this.instructionPointer += 2; 189 | 190 | this._map.set(`${position.x},${position.y}`, status); 191 | 192 | if (status !== 0) { 193 | this.position = position; 194 | } 195 | 196 | if (!this.input.length) { 197 | this.paused = true; 198 | 199 | return status; 200 | } 201 | } else if (opcode === JUMP_IF_NOT_ZERO) { 202 | const parameter1 = this._getValue(parameter1Mode, this.instructionPointer + 1); 203 | const parameter2 = this._getValue(parameter2Mode, this.instructionPointer + 2); 204 | 205 | if (parameter1 !== 0) { 206 | this.instructionPointer = parameter2; 207 | } else { 208 | this.instructionPointer += 3; 209 | } 210 | } else if (opcode === JUMP_IF_ZERO) { 211 | const parameter1 = this._getValue(parameter1Mode, this.instructionPointer + 1); 212 | const parameter2 = this._getValue(parameter2Mode, this.instructionPointer + 2); 213 | 214 | if (parameter1 === 0) { 215 | this.instructionPointer = parameter2; 216 | } else { 217 | this.instructionPointer += 3; 218 | } 219 | } else if (opcode === LESS_THAN) { 220 | const parameter1 = this._getValue(parameter1Mode, this.instructionPointer + 1); 221 | const parameter2 = this._getValue(parameter2Mode, this.instructionPointer + 2); 222 | const parameter3 = this._getAddress(parameter3Mode, this.instructionPointer + 3); 223 | 224 | this.memory[parameter3] = parameter1 < parameter2 ? 1 : 0; 225 | 226 | this.instructionPointer += 4; 227 | } else if (opcode === EQUALS) { 228 | const parameter1 = this._getValue(parameter1Mode, this.instructionPointer + 1); 229 | const parameter2 = this._getValue(parameter2Mode, this.instructionPointer + 2); 230 | const parameter3 = this._getAddress(parameter3Mode, this.instructionPointer + 3); 231 | 232 | this.memory[parameter3] = parameter1 === parameter2 ? 1 : 0; 233 | 234 | this.instructionPointer += 4; 235 | } else if (opcode === ADJUST_RELATIVE_BASE) { 236 | const parameter1 = this._getValue(parameter1Mode, this.instructionPointer + 1); 237 | 238 | this.relativeBase += parameter1; 239 | 240 | this.instructionPointer += 2; 241 | } else if (opcode === HALT) { 242 | this.paused = true; 243 | 244 | return null; 245 | } 246 | } 247 | } 248 | } 249 | 250 | module.exports = RepairDroid; 251 | -------------------------------------------------------------------------------- /day-16-flawed-frequency-transmission/README.md: -------------------------------------------------------------------------------- 1 | # Day 16: Flawed Frequency Transmission 2 | 3 | You're 3/4ths of the way through the [gas giants](https://en.wikipedia.org/wiki/Gas_giant). Not only do roundtrip signals to Earth take five hours, but the signal quality is quite bad as well. You can clean up the signal with the Flawed Frequency Transmission algorithm, or **FFT**. 4 | 5 | As input, FFT takes a list of numbers. In the signal you received (your puzzle input), each number is a single digit: data like `15243` represents the sequence `1`, `5`, `2`, `4`, `3`. 6 | 7 | FFT operates in repeated **phases**. In each phase, a new list is constructed with the same length as the input list. This new list is also used as the input for the next phase. 8 | 9 | Each element in the new list is built by multiplying every value in the input list by a value in a repeating **pattern** and then adding up the results. So, if the input list were `9, 8, 7, 6, 5` and the pattern for a given element were `1, 2, 3`, the result would be `9*1 + 8*2 + 7*3 + 6*1 + 5*2` (with each input element on the left and each value in the repeating pattern on the right of each multiplication). Then, only the ones digit is kept: `38` becomes `8`, `-17` becomes `7`, and so on. 10 | 11 | While each element in the output array uses all of the same input array elements, the actual repeating pattern to use depends on **which output element** is being calculated. The base pattern is `0, 1, 0, -1`. Then, repeat each value in the pattern a number of times equal to the **position in the output list** being considered. Repeat once for the first element, twice for the second element, three times for the third element, and so on. So, if the third element of the output list is being calculated, repeating the values would produce: `0, 0, 0, 1, 1, 1, 0, 0, 0, -1, -1, -1`. 12 | 13 | When applying the pattern, skip the very first value exactly once. (In other words, offset the whole pattern left by one.) So, for the second element of the output list, the actual pattern used would be: `0, 1, 1, 0, 0, -1, -1, 0, 0, 1, 1, 0, 0, -1, -1, ...`. 14 | 15 | After using this process to calculate each element of the output list, the phase is complete, and the output list of this phase is used as the new input list for the next phase, if any. 16 | 17 | Given the input signal `12345678`, below are four phases of FFT. Within each phase, each output digit is calculated on a single line with the result at the far right; each multiplication operation shows the input digit on the left and the pattern value on the right: 18 | 19 | ``` 20 | Input signal: 12345678 21 | 22 | 1*1 + 2*0 + 3*-1 + 4*0 + 5*1 + 6*0 + 7*-1 + 8*0 = 4 23 | 1*0 + 2*1 + 3*1 + 4*0 + 5*0 + 6*-1 + 7*-1 + 8*0 = 8 24 | 1*0 + 2*0 + 3*1 + 4*1 + 5*1 + 6*0 + 7*0 + 8*0 = 2 25 | 1*0 + 2*0 + 3*0 + 4*1 + 5*1 + 6*1 + 7*1 + 8*0 = 2 26 | 1*0 + 2*0 + 3*0 + 4*0 + 5*1 + 6*1 + 7*1 + 8*1 = 6 27 | 1*0 + 2*0 + 3*0 + 4*0 + 5*0 + 6*1 + 7*1 + 8*1 = 1 28 | 1*0 + 2*0 + 3*0 + 4*0 + 5*0 + 6*0 + 7*1 + 8*1 = 5 29 | 1*0 + 2*0 + 3*0 + 4*0 + 5*0 + 6*0 + 7*0 + 8*1 = 8 30 | 31 | After 1 phase: 48226158 32 | 33 | 4*1 + 8*0 + 2*-1 + 2*0 + 6*1 + 1*0 + 5*-1 + 8*0 = 3 34 | 4*0 + 8*1 + 2*1 + 2*0 + 6*0 + 1*-1 + 5*-1 + 8*0 = 4 35 | 4*0 + 8*0 + 2*1 + 2*1 + 6*1 + 1*0 + 5*0 + 8*0 = 0 36 | 4*0 + 8*0 + 2*0 + 2*1 + 6*1 + 1*1 + 5*1 + 8*0 = 4 37 | 4*0 + 8*0 + 2*0 + 2*0 + 6*1 + 1*1 + 5*1 + 8*1 = 0 38 | 4*0 + 8*0 + 2*0 + 2*0 + 6*0 + 1*1 + 5*1 + 8*1 = 4 39 | 4*0 + 8*0 + 2*0 + 2*0 + 6*0 + 1*0 + 5*1 + 8*1 = 3 40 | 4*0 + 8*0 + 2*0 + 2*0 + 6*0 + 1*0 + 5*0 + 8*1 = 8 41 | 42 | After 2 phases: 34040438 43 | 44 | 3*1 + 4*0 + 0*-1 + 4*0 + 0*1 + 4*0 + 3*-1 + 8*0 = 0 45 | 3*0 + 4*1 + 0*1 + 4*0 + 0*0 + 4*-1 + 3*-1 + 8*0 = 3 46 | 3*0 + 4*0 + 0*1 + 4*1 + 0*1 + 4*0 + 3*0 + 8*0 = 4 47 | 3*0 + 4*0 + 0*0 + 4*1 + 0*1 + 4*1 + 3*1 + 8*0 = 1 48 | 3*0 + 4*0 + 0*0 + 4*0 + 0*1 + 4*1 + 3*1 + 8*1 = 5 49 | 3*0 + 4*0 + 0*0 + 4*0 + 0*0 + 4*1 + 3*1 + 8*1 = 5 50 | 3*0 + 4*0 + 0*0 + 4*0 + 0*0 + 4*0 + 3*1 + 8*1 = 1 51 | 3*0 + 4*0 + 0*0 + 4*0 + 0*0 + 4*0 + 3*0 + 8*1 = 8 52 | 53 | After 3 phases: 03415518 54 | 55 | 0*1 + 3*0 + 4*-1 + 1*0 + 5*1 + 5*0 + 1*-1 + 8*0 = 0 56 | 0*0 + 3*1 + 4*1 + 1*0 + 5*0 + 5*-1 + 1*-1 + 8*0 = 1 57 | 0*0 + 3*0 + 4*1 + 1*1 + 5*1 + 5*0 + 1*0 + 8*0 = 0 58 | 0*0 + 3*0 + 4*0 + 1*1 + 5*1 + 5*1 + 1*1 + 8*0 = 2 59 | 0*0 + 3*0 + 4*0 + 1*0 + 5*1 + 5*1 + 1*1 + 8*1 = 9 60 | 0*0 + 3*0 + 4*0 + 1*0 + 5*0 + 5*1 + 1*1 + 8*1 = 4 61 | 0*0 + 3*0 + 4*0 + 1*0 + 5*0 + 5*0 + 1*1 + 8*1 = 9 62 | 0*0 + 3*0 + 4*0 + 1*0 + 5*0 + 5*0 + 1*0 + 8*1 = 8 63 | 64 | After 4 phases: 01029498 65 | ``` 66 | 67 | Here are the first eight digits of the final output list after 100 phases for some larger inputs: 68 | 69 | - `80871224585914546619083218645595` becomes `24176176`. 70 | - `19617804207202209144916044189917` becomes `73745418`. 71 | - `69317163492948606335995924319873` becomes `52432133`. 72 | 73 | After **100** phases of FFT, **what are the first eight digits in the final output list?** 74 | 75 | ## Part Two 76 | 77 | Now that your FFT is working, you can decode the **real signal**. 78 | 79 | The real signal is your puzzle input **repeated 10000 times**. Treat this new signal as a single input list. Patterns are still calculated as before, and 100 phases of FFT are still applied. 80 | 81 | The **first seven digits** of your initial input signal also represent the **message offset**. The message offset is the location of the eight-digit message in the final output list. Specifically, the message offset indicates **the number of digits to skip** before reading the eight-digit message. For example, if the first seven digits of your initial input signal were `1234567`, the eight-digit message would be the eight digits after skipping 1,234,567 digits of the final output list. Or, if the message offset were `7` and your final output list were `98765432109876543210`, the eight-digit message would be `21098765`. (Of course, your real message offset will be a seven-digit number, not a one-digit number like `7`.) 82 | 83 | Here is the eight-digit message in the final output list after 100 phases. The message offset given in each input has been highlighted. (Note that the inputs given below are repeated 10000 times to find the actual starting input lists.) 84 | 85 | - `03036732577212944063491565474664` becomes `84462026`. 86 | - `02935109699940807407585447034323` becomes `78725270`. 87 | - `03081770884921959731165446850517` becomes `53553731`. 88 | 89 | After repeating your input signal 10000 times and running 100 phases of FFT, **what is the eight-digit message embedded in the final output list?** 90 | 91 | ## References 92 | - https://adventofcode.com/2019/day/16 93 | -------------------------------------------------------------------------------- /day-16-flawed-frequency-transmission/fft.js: -------------------------------------------------------------------------------- 1 | const basePattern = [0, 1, 0, -1]; 2 | 3 | const getPattern = (position) => { 4 | let repeatedBasePattern = []; 5 | 6 | for (let i = 0; i < basePattern.length; i++) { 7 | const segment = Array.from({ length: position }, () => basePattern[i]); 8 | 9 | repeatedBasePattern = repeatedBasePattern.concat(segment); 10 | } 11 | 12 | repeatedBasePattern.push(repeatedBasePattern.shift()); 13 | 14 | return repeatedBasePattern; 15 | }; 16 | 17 | module.exports = (input, phases = 100) => { 18 | let signal = input.split('').map(Number); 19 | 20 | const patterns = Array 21 | .from({ length: signal.length }) 22 | .map((_, i) => getPattern(i + 1)); 23 | 24 | for (let p = 0; p < phases; p++) { 25 | signal = Array.from({ length: signal.length }).map((_, position) => { 26 | const pattern = patterns[position]; 27 | const product = signal.reduce((total, element, i) => { 28 | return total + (element * pattern[i % pattern.length]); 29 | }, 0); 30 | 31 | return Number(`${product}`.split('').reverse()[0]); 32 | }); 33 | } 34 | 35 | return signal.join('').slice(0, 8); 36 | }; 37 | -------------------------------------------------------------------------------- /day-16-flawed-frequency-transmission/fft2.js: -------------------------------------------------------------------------------- 1 | module.exports = (input, phases = 100) => { 2 | const messageOffset = Number(input.slice(0, 7)); 3 | const signal = input 4 | .repeat(10000) 5 | .split('') 6 | .map(Number) 7 | .slice(messageOffset); 8 | 9 | for (let p = 0; p < phases; p++) { 10 | for (let i = signal.length - 1; i >= 0; i--) { 11 | signal[i] = ((signal[i + 1] || 0) + signal[i]) % 10; 12 | } 13 | } 14 | 15 | return signal.slice(0, 8).join(''); 16 | }; 17 | -------------------------------------------------------------------------------- /day-16-flawed-frequency-transmission/test.js: -------------------------------------------------------------------------------- 1 | const assert = require('assert'); 2 | 3 | const fft = require('./fft'); 4 | const fft2 = require('./fft2'); 5 | 6 | describe('Day 16: Flawed Frequency Transmission', () => { 7 | it('should determine first eight digits (sample 1)', () => { 8 | assert.strictEqual(fft('12345678', 1), '48226158'); 9 | assert.strictEqual(fft('12345678', 2), '34040438'); 10 | assert.strictEqual(fft('12345678', 3), '03415518'); 11 | assert.strictEqual(fft('12345678', 4), '01029498'); 12 | }); 13 | 14 | it('should determine first eight digits (sample 2)', () => { 15 | assert.strictEqual(fft('80871224585914546619083218645595'), '24176176'); 16 | }); 17 | 18 | it('should determine first eight digits (sample 3)', () => { 19 | assert.strictEqual(fft('19617804207202209144916044189917'), '73745418'); 20 | }); 21 | 22 | it('should determine first eight digits (sample 4)', () => { 23 | assert.strictEqual(fft('69317163492948606335995924319873'), '52432133'); 24 | }); 25 | 26 | describe('Part Two', () => { 27 | it('should determine embedded eight-digit message (sample 1)', () => { 28 | assert.strictEqual(fft2('03036732577212944063491565474664'), '84462026'); 29 | }); 30 | 31 | it('should determine embedded eight-digit message (sample 2)', () => { 32 | assert.strictEqual(fft2('02935109699940807407585447034323'), '78725270'); 33 | }); 34 | 35 | it('should determine embedded eight-digit message (sample 3)', () => { 36 | assert.strictEqual(fft2('03081770884921959731165446850517'), '53553731'); 37 | }); 38 | }); 39 | }); 40 | -------------------------------------------------------------------------------- /day-17-set-and-forget/README.md: -------------------------------------------------------------------------------- 1 | # Day 17: Set and Forget 2 | 3 | An early warning system detects an incoming [solar flare](https://en.wikipedia.org/wiki/Solar_flare) and automatically activates the ship's electromagnetic shield. Unfortunately, this has cut off the Wi-Fi for many small robots that, unaware of the impending danger, are now trapped on exterior scaffolding on the unsafe side of the shield. To rescue them, you'll have to act quickly! 4 | 5 | The only tools at your disposal are some wired cameras and a small vacuum robot currently asleep at its charging station. The video quality is poor, but the vacuum robot has a needlessly bright LED that makes it easy to spot no matter where it is. 6 | 7 | An [Intcode](https://adventofcode.com/2019/day/9) program, the **Aft Scaffolding Control and Information Interface** (ASCII, your puzzle input), provides access to the cameras and the vacuum robot. Currently, because the vacuum robot is asleep, you can only access the cameras. 8 | 9 | Running the ASCII program on your Intcode computer will provide the current view of the scaffolds. This is output, purely coincidentally, as [ASCII code](https://simple.wikipedia.org/wiki/ASCII): `35` means `#`, `46` means `.`, `10` starts a [new line](https://en.wikipedia.org/wiki/Newline#In_programming_languages) of output below the current one, and so on. (Within a line, characters are drawn left-to-right.) 10 | 11 | In the camera output, `#` represents a scaffold and `.` represents open space. The vacuum robot is visible as `^`, `v`, `<`, or `>` depending on whether it is facing up, down, left, or right respectively. When drawn like this, the vacuum robot is **always on a scaffold**; if the vacuum robot ever walks off of a scaffold and begins **tumbling through space uncontrollably**, it will instead be visible as `X`. 12 | 13 | In general, the scaffold forms a path, but it sometimes loops back onto itself. For example, suppose you can see the following view from the cameras: 14 | 15 | ``` 16 | ..#.......... 17 | ..#.......... 18 | #######...### 19 | #.#...#...#.# 20 | ############# 21 | ..#...#...#.. 22 | ..#####...^.. 23 | ``` 24 | 25 | Here, the vacuum robot, `^` is facing up and sitting at one end of the scaffold near the bottom-right of the image. The scaffold continues up, loops across itself several times, and ends at the top-left of the image. 26 | 27 | The first step is to calibrate the cameras by getting the **alignment parameters** of some well-defined points. Locate all **scaffold intersections**; for each, its alignment parameter is the distance between its left edge and the left edge of the view multiplied by the distance between its top edge and the top edge of the view. Here, the intersections from the above image are marked `O`: 28 | 29 | ``` 30 | ..#.......... 31 | ..#.......... 32 | ##O####...### 33 | #.#...#...#.# 34 | ##O###O###O## 35 | ..#...#...#.. 36 | ..#####...^.. 37 | ``` 38 | 39 | For these intersections: 40 | 41 | - The top-left intersection is `2` units from the left of the image and `2` units from the top of the image, so its alignment parameter is `2 * 2 = 4`. 42 | - The bottom-left intersection is `2` units from the left and `4` units from the top, so its alignment parameter is `2 * 4 = 8`. 43 | - The bottom-middle intersection is `6` from the left and `4` from the top, so its alignment parameter is **`24`**. 44 | - The bottom-right intersection's alignment parameter is **`40`**. 45 | 46 | To calibrate the cameras, you need the **sum of the alignment parameters**. In the above example, this is **`76`**. 47 | 48 | Run your ASCII program. **What is the sum of the alignment parameters** for the scaffold intersections? 49 | 50 | ## References 51 | - https://adventofcode.com/2019/day/17 52 | -------------------------------------------------------------------------------- /day-17-set-and-forget/ascii.js: -------------------------------------------------------------------------------- 1 | const intcode = require('./intcode'); 2 | 3 | module.exports = (input) => { 4 | const program = input.split(',').map(Number); 5 | const view = intcode(program); 6 | const frame = String.fromCodePoint(...view); 7 | 8 | return frame 9 | .split('\n') 10 | .reduce((sum, row, y, all) => { 11 | for (let x = 0; x < row.length; x++) { 12 | const positions = [ 13 | row[x], 14 | row[x - 1], 15 | row[x + 1], 16 | (all[y - 1] || [])[x], 17 | (all[y + 1] || [])[x] 18 | ]; 19 | 20 | if (positions.every((position) => position === '#')) { 21 | sum += x * y; 22 | } 23 | } 24 | 25 | return sum; 26 | }, 0); 27 | }; 28 | -------------------------------------------------------------------------------- /day-17-set-and-forget/intcode.js: -------------------------------------------------------------------------------- 1 | const POSITION_MODE = 0; 2 | const IMMEDIATE_MODE = 1; 3 | const RELATIVE_MODE = 2; 4 | 5 | const ADD = 1; 6 | const MULTIPLY = 2; 7 | const RECEIVE = 3; 8 | const SEND = 4; 9 | const JUMP_IF_NOT_ZERO = 5; 10 | const JUMP_IF_ZERO = 6; 11 | const LESS_THAN = 7; 12 | const EQUALS = 8; 13 | const ADJUST_RELATIVE_BASE = 9; 14 | 15 | module.exports = (program, input = []) => { 16 | const memory = [...program]; 17 | 18 | let instructionPointer = 0; 19 | let relativeBase = 0; 20 | let output = []; 21 | 22 | const getValue = (parameterMode, position) => { 23 | switch (parameterMode) { 24 | case POSITION_MODE: 25 | return memory[memory[position]]; 26 | case IMMEDIATE_MODE: 27 | return memory[position]; 28 | case RELATIVE_MODE: 29 | return memory[memory[position] + relativeBase]; 30 | } 31 | }; 32 | 33 | const getAddress = (parameterMode, position) => { 34 | if (parameterMode === POSITION_MODE) { 35 | return memory[position]; 36 | } else if (parameterMode === RELATIVE_MODE) { 37 | return memory[position] + relativeBase; 38 | } 39 | }; 40 | 41 | while (memory[instructionPointer] !== 99) { 42 | const instruction = `${memory[instructionPointer]}`.padStart(5, '0'); 43 | 44 | const opcode = Number(instruction.slice(3)); 45 | const parameter1Mode = Number(instruction[2]); 46 | const parameter2Mode = Number(instruction[1]); 47 | const parameter3Mode = Number(instruction[0]); 48 | 49 | if (opcode === ADD) { 50 | const parameter1 = getValue(parameter1Mode, instructionPointer + 1); 51 | const parameter2 = getValue(parameter2Mode, instructionPointer + 2); 52 | const parameter3 = getAddress(parameter3Mode, instructionPointer + 3); 53 | 54 | memory[parameter3] = parameter1 + parameter2; 55 | 56 | instructionPointer += 4; 57 | } else if (opcode === MULTIPLY) { 58 | const parameter1 = getValue(parameter1Mode, instructionPointer + 1); 59 | const parameter2 = getValue(parameter2Mode, instructionPointer + 2); 60 | const parameter3 = getAddress(parameter3Mode, instructionPointer + 3); 61 | 62 | memory[parameter3] = parameter1 * parameter2; 63 | 64 | instructionPointer += 4; 65 | } else if (opcode === RECEIVE) { 66 | const parameter1 = getAddress(parameter1Mode, instructionPointer + 1); 67 | 68 | memory[parameter1] = input.shift(); 69 | 70 | instructionPointer += 2; 71 | } else if (opcode === SEND) { 72 | output.push(getValue(parameter1Mode, instructionPointer + 1)); 73 | 74 | instructionPointer += 2; 75 | } else if (opcode === JUMP_IF_NOT_ZERO) { 76 | const parameter1 = getValue(parameter1Mode, instructionPointer + 1); 77 | const parameter2 = getValue(parameter2Mode, instructionPointer + 2); 78 | 79 | if (parameter1 !== 0) { 80 | instructionPointer = parameter2; 81 | } else { 82 | instructionPointer += 3; 83 | } 84 | } else if (opcode === JUMP_IF_ZERO) { 85 | const parameter1 = getValue(parameter1Mode, instructionPointer + 1); 86 | const parameter2 = getValue(parameter2Mode, instructionPointer + 2); 87 | 88 | if (parameter1 === 0) { 89 | instructionPointer = parameter2; 90 | } else { 91 | instructionPointer += 3; 92 | } 93 | } else if (opcode === LESS_THAN) { 94 | const parameter1 = getValue(parameter1Mode, instructionPointer + 1); 95 | const parameter2 = getValue(parameter2Mode, instructionPointer + 2); 96 | const parameter3 = getAddress(parameter3Mode, instructionPointer + 3); 97 | 98 | memory[parameter3] = parameter1 < parameter2 ? 1 : 0; 99 | 100 | instructionPointer += 4; 101 | } else if (opcode === EQUALS) { 102 | const parameter1 = getValue(parameter1Mode, instructionPointer + 1); 103 | const parameter2 = getValue(parameter2Mode, instructionPointer + 2); 104 | const parameter3 = getAddress(parameter3Mode, instructionPointer + 3); 105 | 106 | memory[parameter3] = parameter1 === parameter2 ? 1 : 0; 107 | 108 | instructionPointer += 4; 109 | } else if (opcode === ADJUST_RELATIVE_BASE) { 110 | const parameter1 = getValue(parameter1Mode, instructionPointer + 1); 111 | 112 | relativeBase += parameter1; 113 | 114 | instructionPointer += 2; 115 | } 116 | } 117 | 118 | return output; 119 | }; 120 | -------------------------------------------------------------------------------- /day-24-planet-of-discord/README.md: -------------------------------------------------------------------------------- 1 | # Day 24: Planet of Discord 2 | 3 | You land on [Eris](https://en.wikipedia.org/wiki/Eris_(dwarf_planet)), your last stop before reaching Santa. As soon as you do, your sensors start picking up strange life forms moving around: Eris is infested with [bugs](https://www.nationalgeographic.org/thisday/sep9/worlds-first-computer-bug/)! With an over 24-hour roundtrip for messages between you and Earth, you'll have to deal with this problem on your own. 4 | 5 | Eris isn't a very large place; a scan of the entire area fits into a 5x5 grid (your puzzle input). The scan shows **bugs** (`#`) and **empty spaces** (`.`). 6 | 7 | Each **minute**, The bugs live and die based on the number of bugs in the **four adjacent tiles**: 8 | 9 | - A bug **dies** (becoming an empty space) unless there is **exactly one** bug adjacent to it. 10 | - An empty space **becomes infested** with a bug if **exactly one or two** bugs are adjacent to it. 11 | 12 | Otherwise, a bug or empty space remains the same. (Tiles on the edges of the grid have fewer than four adjacent tiles; the missing tiles count as empty space.) This process happens in every location **simultaneously**; that is, within the same minute, the number of adjacent bugs is counted for every tile first, and then the tiles are updated. 13 | 14 | Here are the first few minutes of an example scenario: 15 | 16 | ``` 17 | Initial state: 18 | ....# 19 | #..#. 20 | #..## 21 | ..#.. 22 | #.... 23 | 24 | After 1 minute: 25 | #..#. 26 | ####. 27 | ###.# 28 | ##.## 29 | .##.. 30 | 31 | After 2 minutes: 32 | ##### 33 | ....# 34 | ....# 35 | ...#. 36 | #.### 37 | 38 | After 3 minutes: 39 | #.... 40 | ####. 41 | ...## 42 | #.##. 43 | .##.# 44 | 45 | After 4 minutes: 46 | ####. 47 | ....# 48 | ##..# 49 | ..... 50 | ##... 51 | ``` 52 | 53 | To understand the nature of the bugs, watch for the first time a layout of bugs and empty spaces **matches any previous layout**. In the example above, the first layout to appear twice is: 54 | 55 | ``` 56 | ..... 57 | ..... 58 | ..... 59 | #.... 60 | .#... 61 | ``` 62 | 63 | To calculate the **biodiversity rating** for this layout, consider each tile left-to-right in the top row, then left-to-right in the second row, and so on. Each of these tiles is worth biodiversity points equal to **increasing powers of two**: 1, 2, 4, 8, 16, 32, and so on. Add up the biodiversity points for tiles with bugs; in this example, the 16th tile (`32768` points) and 22nd tile (`2097152` points) have bugs, a total biodiversity rating of **`2129920`**. 64 | 65 | **What is the biodiversity rating for the first layout that appears twice?** 66 | 67 | ## References 68 | - https://adventofcode.com/2019/day/24 69 | -------------------------------------------------------------------------------- /day-24-planet-of-discord/biodiversity.js: -------------------------------------------------------------------------------- 1 | const print = (state) => state 2 | .map((row) => row.map((column) => column ? '#' : '.').join('')).join('\n'); 3 | 4 | const rate = (state) => state 5 | .flat() 6 | .reduce((sum, field, i) => sum + (field ? Math.pow(2, i) : 0), 0); 7 | 8 | function step(state) { 9 | return state.map((row, y) => row.map((column, x) => { 10 | const neighbors = [ 11 | (state[y - 1] || [])[x], 12 | (state[y + 1] || [])[x], 13 | state[y][x - 1], 14 | state[y][x + 1], 15 | ].filter((a) => a).length; 16 | 17 | return column ? neighbors === 1 : neighbors === 1 || neighbors === 2; 18 | })); 19 | } 20 | 21 | module.exports = (input) => { 22 | const initialState = input 23 | .split('\n') 24 | .map((line) => line.trim().split('').map((field) => field === '#')); 25 | 26 | const states = new Set(); 27 | 28 | let nextState = initialState; 29 | 30 | while (!states.has(print(nextState))) { 31 | states.add(print(nextState)); 32 | 33 | nextState = step(nextState); 34 | } 35 | 36 | return rate(nextState); 37 | }; 38 | -------------------------------------------------------------------------------- /day-24-planet-of-discord/test.js: -------------------------------------------------------------------------------- 1 | const assert = require('assert'); 2 | 3 | const biodiversity = require('./biodiversity'); 4 | 5 | describe('Day 24: Planet of Discord', () => { 6 | it('should compute biodiversity rating', () => { 7 | const input = 8 | `....# 9 | #..#. 10 | #..## 11 | ..#.. 12 | #....`; 13 | 14 | assert.strictEqual(biodiversity(input), 2129920); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "advent-of-code-2019", 3 | "version": "1.0.0", 4 | "description": "Advent of Code 2019", 5 | "main": "index.js", 6 | "author": "Mario Tacke (https://www.mariotacke.io)", 7 | "license": "MIT", 8 | "scripts": { 9 | "test": "mocha day-*/**/test.js", 10 | "lint": "eslint ." 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "https://github.com/mariotacke/advent-of-code-2019.git" 15 | }, 16 | "devDependencies": { 17 | "eslint": "^8.29.0", 18 | "mocha": "^10.1.0" 19 | } 20 | } 21 | --------------------------------------------------------------------------------