|
| 1 | +require_relative 'lib/intcode' |
| 2 | + |
| 3 | +VERBOSE = ARGV.delete('-v') |
| 4 | + |
| 5 | +def const_input(mem, phase, input) |
| 6 | + ic = Intcode.new(mem, valid_ops: (1..8).to_a + [99]).continue(input: phase) |
| 7 | + ic.continue(input: input) until ic.halted? |
| 8 | + ic.output |
| 9 | +end |
| 10 | + |
| 11 | +# Assume each amplifier performs a linear mx+b transform. |
| 12 | +# Determine m and b by running the amplifiers once, instead of once per permutation. |
| 13 | +# Could take it even farther with dynamic programming: |
| 14 | +# https://www.reddit.com/r/adventofcode/comments/e7q8fp/2019_day_7_part_2_c_feed_it_forward/ |
| 15 | +# But this is fast enough and I don't care. |
| 16 | +def chain(mem, phases) |
| 17 | + amps = phases.to_h { |phase| [phase, { |
| 18 | + b: b = const_input(mem, phase, 0), |
| 19 | + m: const_input(mem, phase, 1).zip(b).map { |y, bb| y - bb }, |
| 20 | + }.freeze] }.freeze |
| 21 | + |
| 22 | + puts amps if VERBOSE |
| 23 | + |
| 24 | + sizes = amps.values.flat_map { |a| [a[:b].size, a[:m].size] }.uniq |
| 25 | + raise "Incompatible sizes #{sizes}" if sizes.size != 1 |
| 26 | + |
| 27 | + phases.permutation.map { |perm| |
| 28 | + ms = perm.map { |phase| amps[phase][:m] }.transpose.flatten |
| 29 | + bs = perm.map { |phase| amps[phase][:b] }.transpose.flatten |
| 30 | + ms.zip(bs).reduce(0) { |signal, (m, b)| m * signal + b } |
| 31 | + }.max |
| 32 | +end |
| 33 | + |
| 34 | +input = (ARGV[0]&.include?(?,) ? ARGV[0] : ARGF.read).split(?,).map(&method(:Integer)).freeze |
| 35 | + |
| 36 | +[0...5, 5...10].each { |range| puts chain(input, range.to_a) } |
0 commit comments