-
Notifications
You must be signed in to change notification settings - Fork 3
/
19.rb
executable file
·195 lines (158 loc) · 3.43 KB
/
19.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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
#!/usr/bin/env ruby
require 'pp'
require 'io/console'
class Time
def to_ms
(self.to_f * 1000.0).to_i
end
end
class Compute
def addr(r, a, b, c)
r[c] = r[a] + r[b]
end
def addi(r, a, b, c)
r[c] = r[a] + b
end
def mulr(r, a, b, c)
r[c] = r[a] * r[b]
end
def muli(r, a, b, c)
r[c] = r[a] * b
end
def banr(r, a, b, c)
r[c] = r[a] & r[b]
end
def bani(r, a, b, c)
r[c] = r[a] & b
end
def borr(r, a, b, c)
r[c] = r[a] | r[b]
end
def bori(r, a, b, c)
r[c] = r[a] | b
end
def setr(r, a, _b, c)
r[c] = r[a]
end
def seti(r, a, _b, c)
r[c] = a
end
def gtir(r, a, b, c)
r[c] = a > r[b] ? 1 : 0
end
def gtri(r, a, b, c)
r[c] = r[a] > b ? 1 : 0
end
def gtrr(r, a, b, c)
r[c] = r[a] > r[b] ? 1 : 0
end
def eqir(r, a, b, c)
r[c] = a == r[b] ? 1 : 0
end
def eqri(r, a, b, c)
r[c] = r[a] == b ? 1 : 0
end
def eqrr(r, a, b, c)
r[c] = r[a] == r[b] ? 1 : 0
end
def all_instructions
%w[
addr
addi
mulr
muli
banr
bani
borr
bori
setr
seti
gtir
gtri
gtrr
eqir
eqri
eqrr
]
end
end
$cpu = Compute.new
def tests
#p1_tests
#opcode_tests
end
def p1_tests
raise 'fail p1 small' unless part1('input_small.txt') == 7
# Too slow:
#raise 'fail p1 medium' unless 912 == part1('input.txt')
end
def opcode_tests
# A = 3 Value A = 3 Register A = 0
# B = 2 Value B = 2 Register B = 3
# C = 3
# Something that sets register 3.
# Before: [0, 0, 3, 0]
# 14 3 2 3
# After: [0, 0, 3, 1]
cpu = Compute.new
regs_before = [0, 0, 3, 0, 98, 99]
regs_after = cpu.public_send('eqir', regs_before, 3, 2, 3)
regs_expect = [0, 0, 3, 1, 98, 99]
raise 'fail3' unless regs_after == regs_expect
end
def parse_file(filename)
program = []
ip_index = -1
File.readlines(filename).each do |line|
if line =~ /^#ip/
ip_index, _ = line.strip.match(/#ip (\d+)/).captures.map(&:to_i)
next
end
op, a, b, c = line.strip.match(/(\w+) (\d+) (\d+) (\d+)/).captures
instruction = { op: op, a: a.to_i, b: b.to_i, c: c.to_i }
program.push instruction
end
{ program: program, ip_index: ip_index, regs: [0, 0, 0, 0, 0, 0] }
end
def tick(data)
exe = data[:program][data[:regs][data[:ip_index]]]
#print "ip=#{data[:regs][data[:ip_index]]} #{data[:regs]} "
$cpu.send(exe[:op], data[:regs], exe[:a], exe[:b], exe[:c])
#print "-> #{exe[:op]} #{exe[:a]} #{exe[:b]} #{exe[:c]} -> #{data[:regs]} -> "
data[:regs][data[:ip_index]] += 1
#puts "#{data[:regs]}"
data
end
def invalid_ip(data)
data[:program][data[:regs][data[:ip_index]]].nil?
end
def part1(filename)
data = parse_file(filename)
loop do
data = tick(data)
#pp data[:regs]
break if invalid_ip(data)
end
#pp data[:regs]
#puts "Left in reg 0: "
#puts data[:regs][0]
data[:regs][0]
end
############## MAIN #####################
begin_tests = Time.now
tests
end_tests = Time.now
puts "All tests passed - #{end_tests.to_ms - begin_tests.to_ms}ms"
filename = 'input.txt'
data = parse_file(filename)
loop do
tick(data)
#puts data
break if invalid_ip(data)
#STDIN.getch
end
puts data
puts data[:regs][0]
# That's not the right answer; your answer is too low. If you're stuck, there
# are some general tips on the about page, or you can ask for hints on the
# subreddit. Please wait one minute before trying again. (You guessed 10551312.)