add 2024 day 17
This commit is contained in:
parent
1e77d59ed1
commit
9b9b00ed61
2 changed files with 107 additions and 91 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
.DS_Store
|
|
@ -46,6 +46,32 @@ If register B contains 29, the program 1,7 would set register B to 26.
|
|||
If register B contains 2024 and register C contains 43690, the program 4,0 would set register B to 44354.
|
||||
```
|
||||
|
||||
```elixir
|
||||
e1 = """
|
||||
Register A: 729
|
||||
Register B: 0
|
||||
Register C: 0
|
||||
|
||||
Program: 0,1,5,4,3,0
|
||||
"""
|
||||
s1 = "4,6,3,5,6,3,5,2,1,0"
|
||||
|
||||
e2 = """
|
||||
Register A: 2024
|
||||
Register B: 0
|
||||
Register C: 0
|
||||
|
||||
Program: 0,3,5,4,3,0
|
||||
"""
|
||||
input = """
|
||||
Register A: 17323786
|
||||
Register B: 0
|
||||
Register C: 0
|
||||
|
||||
Program: 2,4,1,1,7,5,1,5,4,1,5,5,0,3,3,0
|
||||
"""
|
||||
```
|
||||
|
||||
```elixir
|
||||
defmodule ChronospatialComputer do
|
||||
defstruct a: nil, b: nil, c: nil, program: nil, pc: nil, output: <<>>
|
||||
|
@ -55,7 +81,12 @@ defmodule ChronospatialComputer do
|
|||
[a,b,c] = for register <- registers |> String.split("\n") do
|
||||
register |> String.split(": ") |> Enum.at(1) |> String.to_integer
|
||||
end
|
||||
pc = program |> String.split(": ") |> Enum.at(1) |> String.split(",", trim: true) |> Enum.map(&(String.to_integer/1)) |> :binary.list_to_bin()
|
||||
pc = program
|
||||
|> String.split(": ")
|
||||
|> Enum.at(1)
|
||||
|> String.split(",", trim: true)
|
||||
|> Enum.map(&(String.to_integer/1))
|
||||
|> :binary.list_to_bin()
|
||||
|
||||
init(a,b,c,pc)
|
||||
end
|
||||
|
@ -151,106 +182,90 @@ defmodule ChronospatialComputer do
|
|||
7 -> throw "received combo op 7 at #{computer.pc + 1}"
|
||||
end
|
||||
end
|
||||
|
||||
# Runs my AOC input written as Elixir with `a` in register A.
|
||||
# I could use the code that solves p1, but this runs 10x faster.
|
||||
def run_with_register_a(a), do: run_with_register_a(a, <<>>)
|
||||
def run_with_register_a(0, o), do: o
|
||||
def run_with_register_a(a, o) do
|
||||
import Bitwise
|
||||
# 0 to 7
|
||||
# 0 <= len(b) <= 3
|
||||
b = (a &&& 7)|> Bitwise.bxor(1)
|
||||
# a - 7 <= len(c) <= a
|
||||
c = a >>> b
|
||||
# 0 <= len(b) <= 3
|
||||
b = b |> Bitwise.bxor(5) |> Bitwise.bxor(c)
|
||||
o = o <> <<b &&& 7>>
|
||||
run_with_register_a(a >>> 3, o)
|
||||
end
|
||||
|
||||
# finds valid values of the `A` register that will cause `run_with_register_a` to return
|
||||
# an output equal to the program
|
||||
def quine(program) do
|
||||
quine(program, 0, 10, 0)
|
||||
|> Enum.sort()
|
||||
end
|
||||
|
||||
def quine(<<>>, bits, _, _), do: [bits]
|
||||
# bits is the integer so far
|
||||
# len is the number of bits to generate
|
||||
# z is the number of bits in `bits` expressed as 7 + 3*z
|
||||
def quine(<< first, rest::binary >>, bits, len, z) do
|
||||
import Bitwise
|
||||
|
||||
for i <- 0..((2**len)-1), # first iter - generate 10-bit sequences, do 3-bits on all subsequent loops
|
||||
# noop on first iter - after, shifts over 7 bits
|
||||
i = i <<< (10 - len),
|
||||
# `bits` is always 7+3z bits long, so this will return 7 bits from `bits` and
|
||||
# adds the three bits from `i` at the beginning
|
||||
# so j is << i_0, i_1, i_2, b_0, b_1, b_2, b_3, b_4, b_5, b_6 >>
|
||||
j = (bits >>> 3*z) + i,
|
||||
# run the program with `j` as input
|
||||
o = ChronospatialComputer.run_with_register_a(j),
|
||||
o |> byte_size() > 0,
|
||||
# take only the sequences that generate the next output we're looking for
|
||||
# if we're on the last iteration we want sequences that don't generate
|
||||
# more outputs than we need.
|
||||
# if we're on any other iteration, we take those outputs because they
|
||||
# will be combined with more bits on the next loop.
|
||||
(rest != <<>> and o |> :binary.at(0) == first) or o == << first >> do
|
||||
# takes the `len` (either 3 or 10 - if it's the first loop) new bits from
|
||||
# `i` and prepends them to `bits`
|
||||
(i <<< 3*z) + bits
|
||||
end |> Enum.flat_map(
|
||||
fn b ->
|
||||
# generate the next three bits in the sequence
|
||||
# we do 3 at a time because the program always shifts a 3 bits after writing
|
||||
# to the output.
|
||||
quine(rest, b, 3, z+1)
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
end
|
||||
```
|
||||
|
||||
```elixir
|
||||
<<12>> <> <<12>>
|
||||
Digging deeper in the device's manual, you discover the problem: this program is supposed to output another copy of the program! Unfortunately, the value in register A seems to have been corrupted. You'll need to find a new value to which you can initialize register A so that the program's output instructions produce an exact copy of the program itself.
|
||||
|
||||
For example:
|
||||
|
||||
```
|
||||
|
||||
```elixir
|
||||
e1 = """
|
||||
Register A: 729
|
||||
Register B: 0
|
||||
Register C: 0
|
||||
|
||||
Program: 0,1,5,4,3,0
|
||||
"""
|
||||
s1 = "4,6,3,5,6,3,5,2,1,0"
|
||||
|
||||
e2 = """
|
||||
Register A: 2024
|
||||
Register B: 0
|
||||
Register C: 0
|
||||
|
||||
Program: 0,3,5,4,3,0
|
||||
"""
|
||||
input = """
|
||||
"""
|
||||
```
|
||||
|
||||
This program outputs a copy of itself if register A is instead initialized to 117440. (The original initial value of register A, 2024, is ignored.)
|
||||
|
||||
What is the lowest positive initial value for register A that causes the program to output a copy of itself?
|
||||
|
||||
```elixir
|
||||
[p2answer, _] = ChronospatialComputer.quine(<<2,4,1,1,7,5,1,5,4,1,5,5,0,3,3,0>>)
|
||||
```
|
||||
|
||||
```elixir
|
||||
comp = input |> ChronospatialComputer.parse()
|
||||
```
|
||||
|
||||
```elixir
|
||||
Stream.iterate(0, &(&1 + 1))
|
||||
|> Enum.reduce_while(
|
||||
nil,
|
||||
fn i, _ ->
|
||||
case (%ChronospatialComputer{comp | a: i}
|
||||
|> ChronospatialComputer.run_while(fn c ->
|
||||
o = c.output
|
||||
match?(^o <> _, c.program)
|
||||
end)) do
|
||||
{:halt, %ChronospatialComputer{program: p, output: p}} -> {:halt, i}
|
||||
_ -> {:cont, nil}
|
||||
end
|
||||
end
|
||||
)
|
||||
```
|
||||
|
||||
```elixir
|
||||
"""
|
||||
Register A: 0
|
||||
Register B: 0
|
||||
Register C: 9
|
||||
|
||||
Program: 2,6
|
||||
"""
|
||||
|> ChronospatialComputer.parse() |> ChronospatialComputer.run()
|
||||
```
|
||||
|
||||
```elixir
|
||||
"""
|
||||
Register A: 10
|
||||
Register B: 0
|
||||
Register C: 0
|
||||
|
||||
Program: 5,0,5,1,5,4
|
||||
"""
|
||||
|> ChronospatialComputer.parse() |> ChronospatialComputer.run()
|
||||
```
|
||||
|
||||
```elixir
|
||||
"""
|
||||
Register A: 2024
|
||||
Register B: 0
|
||||
Register C: 0
|
||||
|
||||
Program: 0,1,5,4,3,0
|
||||
"""
|
||||
|> ChronospatialComputer.parse() |> ChronospatialComputer.run()
|
||||
```
|
||||
|
||||
```elixir
|
||||
"""
|
||||
Register A: 0
|
||||
Register B: 29
|
||||
Register C: 0
|
||||
|
||||
Program: 1,7
|
||||
"""
|
||||
|> ChronospatialComputer.parse() |> ChronospatialComputer.run()
|
||||
```
|
||||
|
||||
```elixir
|
||||
"""
|
||||
Register A: 0
|
||||
Register B: 2024
|
||||
Register C: 43690
|
||||
|
||||
Program: 4,0
|
||||
"""
|
||||
|> ChronospatialComputer.parse() |> ChronospatialComputer.run()
|
||||
ChronospatialComputer.run_with_register_a(p2answer)
|
||||
```
|
||||
|
|
Loading…
Add table
Reference in a new issue