From d30e3f9600a7d20e5899e02de93bfdf45c476b51 Mon Sep 17 00:00:00 2001 From: Bill Rossi Date: Sat, 6 Dec 2025 10:19:08 -0500 Subject: [PATCH] More intcode --- ruby/2019/2/lib/intcode.rb | 79 ------------------- ruby/2019/5/bin/problem | 16 ++++ ruby/2019/lib/intcode.rb | 155 +++++++++++++++++++++++++++++++++++++ ruby/bin/run | 2 +- 4 files changed, 172 insertions(+), 80 deletions(-) delete mode 100644 ruby/2019/2/lib/intcode.rb create mode 100644 ruby/2019/5/bin/problem create mode 100644 ruby/2019/lib/intcode.rb diff --git a/ruby/2019/2/lib/intcode.rb b/ruby/2019/2/lib/intcode.rb deleted file mode 100644 index 4c5e1b4..0000000 --- a/ruby/2019/2/lib/intcode.rb +++ /dev/null @@ -1,79 +0,0 @@ -class Intcode - attr_reader :memory, :pc, :stopped - def initialize(memory) - @initial_memory = memory - @memory = memory.clone - @pc = 0 - @stopped = true - end - - def self.for(string) - new string.split(",").map(&:to_i) - end - - def run! - @stopped = false - @pc = 0 - step! until stopped - end - - def reset! - @memory = @initial_memory.clone - @pc = 0 - end - - def step! - case instruction - when 1 - add! - when 2 - multiply! - when 99 - halt! - else - raise "invalid instuction #{instruction} at #{pc}" - end - end - - def add! - v1 = peek(peek(pc + 1)) - v2 = peek(peek(pc + 2)) - log "adding #{v1} and #{v2}" - poke(peek(pc + 3), v1 + v2) - @pc += 4 - end - - def multiply! - v1 = peek(peek(pc + 1)) - v2 = peek(peek(pc + 2)) - log "multiplying #{v1} and #{v2}" - poke(peek(pc + 3), v1 * v2) - @pc += 4 - end - - def halt! - log "halting!" - @stopped = true - end - - def instruction - peek pc - end - - def peek(address) - memory[address] - end - - def poke(address, value) - log "poking #{value} into #{address}" - memory[address] = value - end - - def log(message) - puts message if logging? - end - - def logging? - false - end -end diff --git a/ruby/2019/5/bin/problem b/ruby/2019/5/bin/problem new file mode 100644 index 0000000..7cb2c1c --- /dev/null +++ b/ruby/2019/5/bin/problem @@ -0,0 +1,16 @@ +#!/usr/bin/env ruby + +require "intcode" + +intcode = Intcode.for STDIN.read.chomp +intcode.input.push 1 +intcode.run! + +puts "Part 1: #{intcode.output.last}" + +intcode.reset! +intcode.input.push 5 +intcode.run! + +puts "Part 2: #{intcode.output.first}" + diff --git a/ruby/2019/lib/intcode.rb b/ruby/2019/lib/intcode.rb new file mode 100644 index 0000000..642fb28 --- /dev/null +++ b/ruby/2019/lib/intcode.rb @@ -0,0 +1,155 @@ +class Intcode + attr_reader :memory, :pc, :stopped, :input, :output + def initialize(memory) + @initial_memory = memory + @memory = memory.clone + @pc = 0 + @stopped = true + @input = [] + @output = [] + end + + def self.for(string) + new string.split(",").map(&:to_i) + end + + def run! + @stopped = false + @pc = 0 + step! until stopped + end + + def reset! + @memory = @initial_memory.clone + @pc = 0 + @output = [] + @input = [] + end + + def step! + log "pc: #{pc}, instruction: #{instruction}" + case opcode + when 1 + add! + when 2 + multiply! + when 3 + read_input! + when 4 + write_output! + when 5 + jump_if_true! + when 6 + jump_if_false! + when 7 + less_than! + when 8 + equals! + when 99 + halt! + else + raise "invalid opcode #{opcode} at #{pc}" + end + end + + def parameters + parameter_modes.each_with_index.map do |mode, index| + case mode + when 0 + peek(pc + 1 + index) + when 1 + pc + 1 + index + else + raise "Invalid parameter mode #{mode}" + end + end + end + + def add! + log "adding #{peek(parameters[0])} and #{(parameters[1])}" + poke(parameters[2], peek(parameters[0]) + peek(parameters[1])) + @pc += 4 + end + + def multiply! + log "multiplying #{peek(parameters[0])} and #{peek(parameters[1])}" + poke(parameters[2], peek(parameters[0]) * peek(parameters[1])) + @pc += 4 + end + + def read_input! + i = input.shift + log "reading input #{i} into #{parameters[0]}" + poke(parameters[0], i) + @pc += 2 + end + + def write_output! + o = peek(parameters[0]) + log "outputting #{o} from #{parameters[0]}" + output.push o + @pc += 2 + end + + def jump_if_true! + predicate = peek(parameters[0]) + log "jumping to #{peek(parameters[1])} if #{predicate}" + @pc = predicate > 0 ? peek(parameters[1]) : @pc + 3 + end + + def jump_if_false! + predicate = peek(parameters[0]) + log "jumping to #{peek(parameters[1])} unless #{predicate}" + @pc = predicate == 0 ? peek(parameters[1]) : @pc + 3 + end + + def less_than! + lt = peek(parameters[0]) < peek(parameters[1]) + poke(parameters[2], lt ? 1 : 0) + @pc += 4 + end + + def equals! + eq = peek(parameters[0]) == peek(parameters[1]) + poke(parameters[2], eq ? 1 : 0) + @pc += 4 + end + + def halt! + log "halting!" + @stopped = true + end + + def instruction + peek pc + end + + def opcode + instruction % 100 + end + + def parameter_modes + [ + instruction / 100 % 10, + instruction / 1000 % 10, + instruction / 10000 % 10, + ] + end + + def peek(address) + memory[address] + end + + def poke(address, value) + log "poking #{value} into #{address}" + memory[address] = value + end + + def log(message) + puts message if logging? + end + + def logging? + false + end +end diff --git a/ruby/bin/run b/ruby/bin/run index f9c5d56..25df725 100755 --- a/ruby/bin/run +++ b/ruby/bin/run @@ -11,4 +11,4 @@ if [[ -z $source_file ]] ; then exit 1 fi -time (cat ../data/$year/$day/input.txt | ruby -I$year/$day/lib $source_file) +time (cat ../data/$year/$day/input.txt | ruby -I$year/$day/lib -I$year/lib $source_file)