-
Notifications
You must be signed in to change notification settings - Fork 2
/
16_chronal_classification.rb
75 lines (61 loc) · 2.33 KB
/
16_chronal_classification.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
instructions = {
addr: ->(a, b, c, r) { r[c] = r[a] + r[b] },
addi: ->(a, b, c, r) { r[c] = r[a] + b },
mulr: ->(a, b, c, r) { r[c] = r[a] * r[b] },
muli: ->(a, b, c, r) { r[c] = r[a] * b },
banr: ->(a, b, c, r) { r[c] = r[a] & r[b] },
bani: ->(a, b, c, r) { r[c] = r[a] & b },
borr: ->(a, b, c, r) { r[c] = r[a] | r[b] },
bori: ->(a, b, c, r) { r[c] = r[a] | b },
setr: ->(a, _, c, r) { r[c] = r[a] },
seti: ->(a, _, c, r) { r[c] = a },
gtir: ->(a, b, c, r) { r[c] = a > r[b] ? 1 : 0 },
gtri: ->(a, b, c, r) { r[c] = r[a] > b ? 1 : 0 },
gtrr: ->(a, b, c, r) { r[c] = r[a] > r[b] ? 1 : 0 },
eqir: ->(a, b, c, r) { r[c] = a == r[b] ? 1 : 0 },
eqri: ->(a, b, c, r) { r[c] = r[a] == b ? 1 : 0 },
eqrr: ->(a, b, c, r) { r[c] = r[a] == r[b] ? 1 : 0 },
}.freeze
raise 'You forgot an instruction...' if instructions.size != 16
could_be = Array.new(instructions.size) { instructions.keys }
broken = ARGV.delete('--broken')
verbose = ARGV.delete('-v')
input = ARGF.each_line.map(&:chomp)
last_after = input.rindex { |l| l.start_with?('After: ') }
puts input[0..last_after].each_slice(4).count { |before, op, after, _|
before = before.scan(/\d+/).map(&:to_i).freeze
after = after.scan(/\d+/).map(&:to_i).freeze
opcode, a, b, c = op.split.map(&method(:Integer))
regs = before.dup
alike = instructions.select { |_, v|
# If broken, we let mutations leak out from one inst to the other.
regs = before.dup unless broken
begin
v[a, b, c, regs]
rescue
# Actually this line isn't necessary...
# I did it to defend against registers >= 4
# but it never happens in input?
next false
end
regs == after
}
could_be[opcode] &= alike.keys
alike.size >= 3
}
could_be.each_with_index { |c, i| puts "#{i} (#{c.size}) -> #{c}" } if verbose
assignments = [nil] * instructions.size
until assignments.all?
only_one = could_be.index { |a| a.size == 1 }
raise "I'm not smart enough to do this one: #{could_be}" unless only_one
assigned = could_be[only_one][0]
puts "Assign #{only_one} #{assigned}" if verbose
assignments[only_one] = instructions[assigned]
could_be.each { |e| e.delete(assigned) }
end
regs = [0, 0, 0, 0]
input.drop(last_after + 1).drop_while(&:empty?).each { |l|
opcode, a, b, c = l.split.map(&method(:Integer))
assignments[opcode][a, b, c, regs]
}
p verbose ? regs : regs[0]