Skip to content

Commit d969bb9

Browse files
committed
Day 24 Ruby solutions
1 parent fababab commit d969bb9

File tree

2 files changed

+197
-0
lines changed

2 files changed

+197
-0
lines changed

24-1.rb

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
#!/usr/bin/env ruby
2+
3+
require 'memoist' # https://github.com/matthewrudy/memoist
4+
5+
class ALU
6+
attr_accessor :w, :x, :y, :z
7+
8+
def initialize(input)
9+
@input = input.split('').map(&:to_i)
10+
@w = 0
11+
@x = 0
12+
@y = 0
13+
@z = 0
14+
end
15+
16+
def to_s
17+
"<#{self.class}: input=#{@input}, w=#{@w}, x=#{@x}, y=#{@y}, z=#{@z}>"
18+
end
19+
20+
def inspect
21+
to_s
22+
end
23+
24+
def inp(reg, _)
25+
instance_variable_set('@' + reg, @input.shift.to_i)
26+
end
27+
28+
def get_operand(oper)
29+
case oper
30+
when 'w'..'z'
31+
instance_variable_get('@' + oper)
32+
else
33+
oper.to_i
34+
end
35+
end
36+
37+
def add(reg, oper)
38+
op1 = instance_variable_get('@' + reg)
39+
op2 = get_operand oper
40+
instance_variable_set('@' + reg, op1 + op2)
41+
end
42+
43+
def mul(reg, oper)
44+
op1 = instance_variable_get('@' + reg)
45+
op2 = get_operand oper
46+
instance_variable_set('@' + reg, op1 * op2)
47+
end
48+
49+
def div(reg, oper)
50+
op1 = instance_variable_get('@' + reg)
51+
op2 = get_operand oper
52+
instance_variable_set('@' + reg, (op1.to_f / op2).truncate)
53+
end
54+
55+
def mod(reg, oper)
56+
op1 = instance_variable_get('@' + reg)
57+
op2 = get_operand oper
58+
instance_variable_set('@' + reg, op1 % op2)
59+
end
60+
61+
def eql(reg, oper)
62+
op1 = instance_variable_get('@' + reg)
63+
op2 = get_operand oper
64+
instance_variable_set('@' + reg, op1 == op2 ? 1 : 0)
65+
end
66+
67+
def valid?
68+
@z == 0
69+
end
70+
end
71+
72+
class MONAD
73+
extend Memoist
74+
75+
@@instruction_format = /^(?<inst>inp|add|mul|div|mod|eql) (?<reg>[w-z])($| (?<oper>([w-z]|[[:digit:]\-]+)))/
76+
77+
def initialize(program)
78+
@blocks = []
79+
collect = []
80+
program.each do |line|
81+
if line.start_with? 'inp' and not collect.empty?
82+
@blocks.append collect
83+
collect = []
84+
end
85+
collect.append line
86+
end
87+
@blocks.append collect
88+
end
89+
90+
def run_block(step, w, z)
91+
alu = ALU.new w.to_s
92+
alu.z = z
93+
@blocks[step].each do |insn|
94+
@@instruction_format.match(insn) do |m|
95+
alu.send m['inst'].to_sym, m['reg'], m['oper']
96+
end
97+
end
98+
alu.z
99+
end
100+
101+
def find_solution(step, input, last_output)
102+
return '' if step == 14 and last_output.zero?
103+
return nil if step == 14
104+
105+
this_block = step >= 0 ? run_block(step, input, last_output) : 0
106+
107+
9.downto(1) do |next_input|
108+
solution = find_solution(step + 1, next_input, this_block)
109+
return input.to_s + solution if solution
110+
end
111+
nil
112+
end
113+
114+
memoize :find_solution
115+
116+
def find_max
117+
find_solution(-1, 0, 0)[1..]
118+
end
119+
end
120+
121+
instructions = File.read('24.input').lines.map(&:strip)
122+
123+
monad = MONAD.new(instructions)
124+
125+
print monad.find_max, "\n"

24-2.rb

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
#!/usr/bin/env ruby
2+
3+
require 'memoist' # https://github.com/matthewrudy/memoist
4+
5+
class MONAD
6+
extend Memoist
7+
8+
@@instruction_format = /^(?<inst>inp|add|mul|div|mod|eql) (?<reg>[w-z])($| (?<oper>([w-z]|[[:digit:]\-]+)))/
9+
10+
def initialize(program)
11+
# A program is 14 blocks of almost the same 18 instructions, with
12+
# three operands changing between them, on line 4 (div z), 5 (add
13+
# x), and 15 (add y).
14+
@divz = []
15+
@addx = []
16+
@addy = []
17+
program.each_with_index do |insn, number|
18+
@@instruction_format.match(insn) do |m|
19+
if number % 18 == 4
20+
@divz.append m['oper'].to_i
21+
elsif number % 18 == 5
22+
@addx.append m['oper'].to_i
23+
elsif number % 18 == 15
24+
@addy.append m['oper'].to_i
25+
end
26+
end
27+
end
28+
end
29+
30+
def run_block(step, w, z)
31+
x = z % 26 + @addx[step]
32+
z = (z / @divz[step].to_f).truncate
33+
if x != w
34+
z *= 26
35+
z += w + @addy[step]
36+
end
37+
z
38+
end
39+
40+
def find_solution(step, input, last_output)
41+
return '' if step == 14 and last_output.zero?
42+
return nil if step == 14
43+
44+
this_block = step >= 0 ? run_block(step, input, last_output) : 0
45+
46+
1.upto(9) do |next_input|
47+
solution = find_solution(step + 1, next_input, this_block)
48+
return input.to_s + solution if solution
49+
end
50+
nil
51+
end
52+
53+
memoize :find_solution
54+
55+
def find_max
56+
find_solution(-1, 0, 0)[1..]
57+
end
58+
59+
def to_s
60+
"<#{self.class}:\ndiv z: #{@divz}\nadd x: #{@addx}\nadd y: #{@addy}\n>"
61+
end
62+
63+
def inspect
64+
to_s
65+
end
66+
end
67+
68+
instructions = File.read('24.input').lines.map(&:strip)
69+
70+
monad = MONAD.new(instructions)
71+
72+
print monad.find_max, "\n"

0 commit comments

Comments
 (0)