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.
|
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
|
```elixir
|
||||||
defmodule ChronospatialComputer do
|
defmodule ChronospatialComputer do
|
||||||
defstruct a: nil, b: nil, c: nil, program: nil, pc: nil, output: <<>>
|
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
|
[a,b,c] = for register <- registers |> String.split("\n") do
|
||||||
register |> String.split(": ") |> Enum.at(1) |> String.to_integer
|
register |> String.split(": ") |> Enum.at(1) |> String.to_integer
|
||||||
end
|
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)
|
init(a,b,c,pc)
|
||||||
end
|
end
|
||||||
|
@ -151,106 +182,90 @@ defmodule ChronospatialComputer do
|
||||||
7 -> throw "received combo op 7 at #{computer.pc + 1}"
|
7 -> throw "received combo op 7 at #{computer.pc + 1}"
|
||||||
end
|
end
|
||||||
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
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
```elixir
|
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.
|
||||||
<<12>> <> <<12>>
|
|
||||||
|
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 A: 2024
|
||||||
Register B: 0
|
Register B: 0
|
||||||
Register C: 0
|
Register C: 0
|
||||||
|
|
||||||
Program: 0,3,5,4,3,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
|
```elixir
|
||||||
comp = input |> ChronospatialComputer.parse()
|
ChronospatialComputer.run_with_register_a(p2answer)
|
||||||
```
|
|
||||||
|
|
||||||
```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()
|
|
||||||
```
|
```
|
||||||
|
|
Loading…
Add table
Reference in a new issue