-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path24solution.rb
116 lines (100 loc) · 2.5 KB
/
24solution.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
require 'active_support'
require 'active_support/core_ext/array'
filename = "24input.txt"
# this code doesn't solve the problem by itself, this is done through
# staring at the instructions long enough
# it does provide functions to execute the code on inputs etc., though
# this way I can play around with my assumptions
def parse_arg(arg)
if arg =~ /-?\d+/
arg.to_i
else
arg.to_sym
end
end
def parse_input(filename)
File.read(filename).split("\n").map do |line|
segments = line.split(" ")
{ op: segments[0].to_sym, args: segments.drop(1).map { |a| parse_arg(a) } }
end
end
# split instructions into distinct steps
def split(instructions)
instructions.split do |instruction|
instruction[:op] == :inp
end.map do |is|
[{ op: :inp, args: [:w] }] + is
end.drop(1)
end
def get(state, arg)
if arg.is_a? Integer
arg
elsif [:w, :x, :y, :z].include?(arg)
state[arg]
else
raise "Invalid argument"
end
end
def execute(instructions, inputs, state=nil)
state ||= {
w: 0,
x: 0,
y: 0,
z: 0
}
input_index = 0
instructions.each do |instruction|
store_addr = instruction[:args][0]
state[store_addr] =
case instruction[:op]
when :inp
value = inputs[input_index]
raise "not enough inputs" if value.nil?
input_index += 1
value
when :add
state[store_addr] + get(state, instruction[:args][1])
when :mul
state[store_addr] * get(state, instruction[:args][1])
when :div
state[store_addr] / get(state, instruction[:args][1])
when :mod
state[store_addr] % get(state, instruction[:args][1])
when :eql
state[store_addr] == get(state, instruction[:args][1]) ? 1 : 0
else
raise "Invalid instruction"
end
end
state
end
def valid_model_number?(instructions, num)
inputs = num.to_s.split("").map(&:to_i)
return false if inputs.any?(&:zero?)
result = execute(instructions, inputs)
result[:z] == 0
end
instructions = parse_input(filename)
# from reading the code we extract the following conditions
# (bi is the ith input digit):
# - b5-7 = b6
# - b4+1 = b7
# - b8+2 = b9
# - b10+5 = b11
# - b3-4 = b12
# - b2-8 = b13
# - b1+7 = b14
#
# whence we get the bounds:
# - b5 >= 8
# - b4 <= 8
# - b8 <= 7
# - b10 <= 4
# - b3 >= 5
# - b2 = 9
# - b13 = 1
# - b1 <= 2
#
# the following is the highest number satisfying these conditions
puts valid_model_number?(instructions, 29989297949519)
puts valid_model_number?(instructions, 19518121316118)