Skip to content

Commit

Permalink
Year 2016: Day 23
Browse files Browse the repository at this point in the history
  • Loading branch information
joshleaves committed Mar 14, 2024
1 parent f4e6a61 commit d79660d
Show file tree
Hide file tree
Showing 5 changed files with 171 additions and 1 deletion.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ I'm also adding notes that may be useful if you're learning Ruby.

Notes for solving:
* [2015, complete](year_2015.md)
* [2016, up to day 22](year_2016.md)
* [2016, up to day 23](year_2016.md)
* [2023, up to day 04](year_2023.md)

# How to use
Expand Down
26 changes: 26 additions & 0 deletions spec/year_2016/day_23_input
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
cpy a b
dec b
cpy a d
cpy 0 a
cpy b c
inc a
dec c
jnz c -2
dec d
jnz d -5
dec b
cpy b c
cpy c d
dec d
inc c
jnz d -2
tgl c
cpy -16 c
jnz 1 c
cpy 96 c
jnz 91 d
inc a
inc d
jnz d -2
inc c
jnz c -5
37 changes: 37 additions & 0 deletions spec/year_2016/day_23_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
require 'year_2016/day_23'

describe Year2016::Day23 do
context 'when Part 1' do
subject(:sample_one) do
sample_data = <<~HEREDOC
cpy 2 a
tgl a
tgl a
tgl a
cpy 1 a
dec a
dec a
HEREDOC
described_class.new(sample_data).program
end

it 'gives a final result' do
sample_one.execute
expect(sample_one.registers['a']).to eq(3)
end
end

context 'when Results' do
subject(:input_data) do
File.read('spec/year_2016/day_23_input')
end

it 'correctly answers part 1' do
expect(described_class.new(input_data).part_one).to eq(13_776)
end

it 'correctly answers part 2', skip: 'Test is too slow for CI' do
expect(described_class.new(input_data).part_two).to eq(479_010_336)
end
end
end
14 changes: 14 additions & 0 deletions year_2016.md
Original file line number Diff line number Diff line change
Expand Up @@ -320,3 +320,17 @@ Year2016::Day22
There is something about re-using [Breadth-first search](https://en.wikipedia.org/wiki/Breadth-first_search) all the time that is just very annoying.

In that case, the algorithm is about getting our payload to the empty spot, and then moving the data around it until we reach the goal.


## Day 23: Safe Cracking

```
Year2016::Day21
when Part 1
gives a final result
when Results
correctly answers part 1
correctly answers part 2 (PENDING: Test is too slow for CI)
```

Nothing to say, I'm just a sucker for virtual machines. That said, the test almost takes as long as an episode of Dragon Ball.
93 changes: 93 additions & 0 deletions year_2016/day_23.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
class Year2016
class Day23
attr_accessor :program

class Program
attr_accessor :instructions, :pc, :registers

def initialize(input_instructions)
@instructions = input_instructions.map do |instruction|
[instruction, compile(instruction)]
end
end

def inc(register)
@pc += 1
@registers[register] += 1
end

def dec(register)
@pc += 1
@registers[register] -= 1
end

def cpy(from, to)
@pc += 1
return unless @registers[to]

@registers[to] = @registers[from] || from.to_i
end

def jnz(value, jmp)
return @pc += 1 if (@registers[value] || value.to_i).zero?

@pc += @registers[jmp] || jmp.to_i
end

# rubocop:disable Metrics/MethodLength
def tgl(register)
jump = @registers[register] || jump.to_i
code, tgl_instruction = @instructions[@pc + jump]
return @pc += 1 unless tgl_instruction

case tgl_instruction.length
when 2
tgl_instruction[0] = tgl_instruction[0] == :inc ? :dec : :inc
when 3
tgl_instruction[0] = tgl_instruction[0] == :jnz ? :cpy : :jnz
end
@instructions[@pc + jump] = [code, tgl_instruction]

@pc += 1
end

def compile(instruction)
case instruction
when /^cpy (-?\d+|[abcd]) ([abcd])$/
[:cpy, $1, $2]
when /^inc ([abcd])$/
[:inc, $1]
when /^dec ([abcd])$/
[:dec, $1]
when /^jnz (-?\d+|[abcd]) (-?\d+|[abcd])$/
[:jnz, $1, $2]
when /^tgl ([abcd])$/
[:tgl, $1]
else
raise "Invalid code: #{instruction}"
end
end
# rubocop:enable Metrics/MethodLength

def execute(init_registers = { 'a' => 0, 'b' => 0, 'c' => 0, 'd' => 0 })
@pc = 0
@registers = init_registers
send(*instructions[@pc].last) while instructions[@pc]
end
end

def initialize(input_data)
@program = Program.new(input_data.chomp.split("\n"))
end

def part_one
@program.execute('a' => 7, 'b' => 0, 'c' => 0, 'd' => 0)
@program.registers['a']
end

def part_two
@program.execute('a' => 12, 'b' => 0, 'c' => 0, 'd' => 0)
@program.registers['a']
end
end
end

0 comments on commit d79660d

Please sign in to comment.