Skip to content

Commit e55c404

Browse files
committed
Day 17 Part 1
1 parent a080d72 commit e55c404

File tree

9 files changed

+191
-0
lines changed

9 files changed

+191
-0
lines changed

Day_17/README.md

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
## \--- Day 17: Chronospatial Computer ---
2+
3+
The Historians push the button on their strange device, but this time, you all just feel like you're [falling](https://adventofcode.com/2018/day/6).
4+
5+
"Situation critical", the device announces in a familiar voice. "Bootstrapping process failed. Initializing debugger...."
6+
7+
The small handheld device suddenly unfolds into an entire computer! The Historians look around nervously before one of them tosses it to you.
8+
9+
This seems to be a 3-bit computer: its program is a list of 3-bit numbers (0 through 7), like `0,1,2,3`. The computer also has three _registers_ named `A`, `B`, and `C`, but these registers aren't limited to 3 bits and can instead hold any integer.
10+
11+
The computer knows _eight instructions_, each identified by a 3-bit number (called the instruction's _opcode_). Each instruction also reads the 3-bit number after it as an input; this is called its _operand_.
12+
13+
A number called the _instruction pointer_ identifies the position in the program from which the next opcode will be read; it starts at `0`, pointing at the first 3-bit number in the program. Except for jump instructions, the instruction pointer increases by `2` after each instruction is processed (to move past the instruction's opcode and its operand). If the computer tries to read an opcode past the end of the program, it instead _halts_.
14+
15+
So, the program `0,1,2,3` would run the instruction whose opcode is `0` and pass it the operand `1`, then run the instruction having opcode `2` and pass it the operand `3`, then halt.
16+
17+
There are two types of operands; each instruction specifies the type of its operand. The value of a _literal operand_ is the operand itself. For example, the value of the literal operand `7` is the number `7`. The value of a _combo operand_ can be found as follows:
18+
19+
- Combo operands `0` through `3` represent literal values `0` through `3`.
20+
- Combo operand `4` represents the value of register `A`.
21+
- Combo operand `5` represents the value of register `B`.
22+
- Combo operand `6` represents the value of register `C`.
23+
- Combo operand `7` is reserved and will not appear in valid programs.
24+
25+
The eight instructions are as follows:
26+
27+
The `adv` instruction (opcode `0`) performs _division_. The numerator is the value in the `A` register. The denominator is found by raising 2 to the power of the instruction's _combo_ operand. (So, an operand of `2` would divide `A` by `4` (`2^2`); an operand of `5` would divide `A` by `2^B`.) The result of the division operation is _truncated_ to an integer and then written to the `A` register.
28+
29+
The `bxl` instruction (opcode `1`) calculates the [bitwise XOR](https://en.wikipedia.org/wiki/Bitwise_operation#XOR) of register `B` and the instruction's _literal_ operand, then stores the result in register `B`.
30+
31+
The `bst` instruction (opcode `2`) calculates the value of its _combo_ operand [modulo](https://en.wikipedia.org/wiki/Modulo) 8 (thereby keeping only its lowest 3 bits), then writes that value to the `B` register.
32+
33+
The `jnz` instruction (opcode `3`) does _nothing_ if the `A` register is `0`. However, if the `A` register is _not zero_, it _jumps_ by setting the instruction pointer to the value of its _literal_ operand; if this instruction jumps, the instruction pointer is _not_ increased by `2` after this instruction.
34+
35+
The `bxc` instruction (opcode `4`) calculates the _bitwise XOR_ of register `B` and register `C`, then stores the result in register `B`. (For legacy reasons, this instruction reads an operand but _ignores_ it.)
36+
37+
The `out` instruction (opcode `5`) calculates the value of its _combo_ operand modulo 8, then _outputs_ that value. (If a program outputs multiple values, they are separated by commas.)
38+
39+
The `bdv` instruction (opcode `6`) works exactly like the `adv` instruction except that the result is stored in the `B` register_. (The numerator is still read from the `A` register.)
40+
41+
The `cdv` instruction (opcode `7`) works exactly like the `adv` instruction except that the result is stored in the `C` register_. (The numerator is still read from the `A` register.)
42+
43+
Here are some examples of instruction operation:
44+
45+
- If register `C` contains `9`, the program `2,6` would set register `B` to `1`.
46+
- If register `A` contains `10`, the program `5,0,5,1,5,4` would output `0,1,2`.
47+
- If register `A` contains `2024`, the program `0,1,5,4,3,0` would output `4,2,5,6,7,7,7,7,3,1,0` and leave `0` in register `A`.
48+
- If register `B` contains `29`, the program `1,7` would set register `B` to `26`.
49+
- If register `B` contains `2024` and register `C` contains `43690`, the program `4,0` would set register `B` to `44354`.
50+
51+
The Historians' strange device has finished initializing its debugger and is displaying some _information about the program it is trying to run_ (your puzzle input). For example:
52+
53+
```
54+
Register A: 729
55+
Register B: 0
56+
Register C: 0
57+
58+
Program: 0,1,5,4,3,0
59+
```
60+
61+
Your first task is to _determine what the program is trying to output_. To do this, initialize the registers to the given values, then run the given program, collecting any output produced by `out` instructions. (Always join the values produced by `out` instructions with commas.) After the above program halts, its final output will be `4,6,3,5,6,3,5,2,1,0`.
62+
63+
Using the information provided by the debugger, initialize the registers to the given values, then run the program. Once it halts, _what do you get if you use commas to join the values it output into a single string?_
64+
65+
66+
Your puzzle answer was `[REDACTED]`.
67+
68+
The first half of this puzzle is complete! It provides one gold star: ⭐

Day_17/example_17a.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Register A: 729
2+
Register B: 0
3+
Register C: 0
4+
5+
Program: 0,1,5,4,3,0

Day_17/example_17b.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Register A: 10
2+
Register B: 0
3+
Register C: 9
4+
5+
Program: 2,6

Day_17/example_17c.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Register A: 10
2+
Register B: 0
3+
Register C: 0
4+
5+
Program: 5,0,5,1,5,4

Day_17/example_17d.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Register A: 2024
2+
Register B: 0
3+
Register C: 0
4+
5+
Program: 0,1,5,4,3,0

Day_17/example_17e.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Register A: 2024
2+
Register B: 29
3+
Register C: 0
4+
5+
Program: 1,7

Day_17/example_17f.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Register A: 2024
2+
Register B: 2024
3+
Register C: 43690
4+
5+
Program: 4,0

Day_17/task_17a.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import math
2+
3+
4+
def load_data(filename):
5+
with open(filename, "r") as file:
6+
registers, program = file.read().split("\n\n")
7+
8+
registers = [int(register.split(": ")[1]) for register in registers.split("\n")]
9+
program = program.strip().split(": ")[1].split(",")
10+
return registers, list(map(int, program))
11+
12+
13+
def run_program(program, registers):
14+
15+
def combo(operand):
16+
if operand <= 3:
17+
return operand
18+
if operand == 4:
19+
return a
20+
if operand == 5:
21+
return b
22+
if operand == 6:
23+
return c
24+
raise ValueError(f"Invalid operand: {operand}")
25+
26+
a, b, c = registers
27+
28+
output = []
29+
pointer = 0
30+
while pointer < len(program) - 1:
31+
jumped = False
32+
instruction = program[pointer]
33+
operand = program[pointer + 1]
34+
35+
if instruction == 0: # adv
36+
a = math.floor(a / pow(2, combo(operand)))
37+
elif instruction == 1: # bxl
38+
b = b ^ operand
39+
elif instruction == 2: # bst
40+
b = combo(operand) % 8
41+
elif instruction == 3: # jnz
42+
if a != 0:
43+
pointer = operand
44+
jumped = True
45+
elif instruction == 4: # bxc
46+
b = b ^ c
47+
elif instruction == 5: # out
48+
output.append(combo(operand) % 8)
49+
elif instruction == 6: # bdv
50+
b = math.floor(a / pow(2, combo(operand)))
51+
elif instruction == 7: # cdv
52+
c = math.floor(a / pow(2, combo(operand)))
53+
54+
if not jumped:
55+
pointer += 2
56+
57+
return output, a, b, c
58+
59+
60+
if __name__ == "__main__":
61+
registers, program = load_data("Day_17/puzzle_input.txt")
62+
output, a, b, c = run_program(program, registers)
63+
print(",".join(map(str, output)))

Day_17/test_task_17a.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
from task_17a import load_data, run_program
2+
import pytest
3+
4+
5+
@pytest.mark.parametrize(
6+
"file_path, exp_a, exp_b, exp_c, exp_output",
7+
[
8+
("Day_17/example_17a.txt", "X", "X", "X", "4,6,3,5,6,3,5,2,1,0"),
9+
("Day_17/example_17b.txt", "X", 1, "X", "X"),
10+
("Day_17/example_17c.txt", "X", "X", "X", "0,1,2"),
11+
("Day_17/example_17d.txt", 0, "X", "X", "4,2,5,6,7,7,7,7,3,1,0"),
12+
("Day_17/example_17e.txt", "X", 26, "X", "X"),
13+
("Day_17/example_17f.txt", "X", 44354, "X", "X"),
14+
],
15+
)
16+
def test_run_programe(file_path, exp_a, exp_b, exp_c, exp_output):
17+
registers, program = load_data(file_path)
18+
output, a, b, c = run_program(program, registers)
19+
20+
if exp_a != "X":
21+
assert a == exp_a
22+
23+
if exp_b != "X":
24+
assert b == exp_b
25+
26+
if exp_c != "X":
27+
assert c == exp_c
28+
29+
if exp_output != "X":
30+
assert ",".join(map(str, output)) == exp_output

0 commit comments

Comments
 (0)