[2019][ruby][9.x]
change xmywlsrprzoozspvkxwnpkupxpvswzwz
commit 4def46a01f2327971eeebc21c251c02b3ee31751
author Alpha Chen <alpha@kejadlen.dev>
date
parent lrksyxus
diff --git a/2019/ruby/computer.rb b/2019/ruby/computer.rb
index 6c5b953..c691582 100644
--- a/2019/ruby/computer.rb
+++ b/2019/ruby/computer.rb
@@ -11,20 +11,22 @@ class Mode < T::Enum
   enums do
     Position = new
     Immediate = new
+    Relative = new
   end
 end
 
 OPCODES = T.let({
-  1  => ->(m, _, _, a, b, c) { m[c] = m[a] + m[b]           ; nil }, # add
-  2  => ->(m, _, _, a, b, c) { m[c] = m[a] * m[b]           ; nil }, # multiply
-  3  => ->(m, i, _, a)       { m[a] = i.gets.to_i           ; nil }, # input
-  4  => ->(m, _, o, a)       {        o.puts(m[a])          ; nil }, # output
-  5  => ->(m, _, _, a, b)    {        m[a].nonzero? ? m[b]  : nil }, # jump-if-true
-  6  => ->(m, _, _, a, b)    {        m[a].zero?    ? m[b]  : nil }, # jump-if-false
-  7  => ->(m, _, _, a, b, c) { m[c] = (m[a] < m[b])  ? 1 : 0; nil }, # less than
-  8  => ->(m, _, _, a, b, c) { m[c] = (m[a] == m[b]) ? 1 : 0; nil }, # equals
-  99 => ->(*)                {        throw :halt                 }, # halt
-}, T::Hash[T.untyped, T.untyped])
+  1  => ->(m, _, _, a, b, c) { m[c] = m[a] + m[b]           ; [nil, nil]  }, # add
+  2  => ->(m, _, _, a, b, c) { m[c] = m[a] * m[b]           ; [nil, nil]  }, # multiply
+  3  => ->(m, i, _, a)       { m[a] = i.gets.to_i           ; [nil, nil]  }, # input
+  4  => ->(m, _, o, a)       {        o.puts(m[a])          ; [nil, nil]  }, # output
+  5  => ->(m, _, _, a, b)    {        [m[a].nonzero? ? m[b] :  nil, nil]  }, # jump-if-true
+  6  => ->(m, _, _, a, b)    {        [m[a].zero?    ? m[b] :  nil, nil]  }, # jump-if-false
+  7  => ->(m, _, _, a, b, c) { m[c] = (m[a] < m[b])  ? 1 : 0; [nil, nil]  }, # less than
+  8  => ->(m, _, _, a, b, c) { m[c] = (m[a] == m[b]) ? 1 : 0; [nil, nil]  }, # equals
+  9  => ->(m, _, _, a)       {                                [nil, m[a]] }, # adjust relative base
+  99 => ->(*)                {        throw :halt                         }, # halt
+}, T::Hash[Integer, T.untyped])
 
 class Parameter
   extend T::Sig
@@ -71,6 +73,7 @@ class Computer
     @input = T.let(input, AnyIO)
     @output = T.let(output, AnyIO)
     @pc = T.let(0, Integer)
+    @relative_base = T.let(0, Integer)
   end
 
   sig {params(input: AnyIO, output: AnyIO).returns(Memory)}
@@ -101,13 +104,16 @@ class Computer
           mode = case mode
                  when ?0 then Mode::Position
                  when ?1 then Mode::Immediate
+                 when ?2 then Mode::Relative
                  else fail "unexpected mode: #{mode}"
                  end
           Parameter.new(mode, value)
         }
         @pc += n
 
-        @pc = opcode.call(self, input, output, *args) || @pc
+        pc, rb = opcode.call(self, input, output, *args)
+        @pc = pc if pc
+        @relative_base += rb if rb
 
         yield @memory
       end
@@ -123,8 +129,9 @@ class Computer
     parameter = Parameter.from(parameter)
     mode = parameter.mode
     case mode
-    when Mode::Position  then @memory.fetch(parameter.value) || 0
+    when Mode::Position  then @memory[parameter.value] || 0
     when Mode::Immediate then parameter.value
+    when Mode::Relative then @memory[@relative_base + parameter.value] || 0
     else T.absurd(mode)
     end
   end
@@ -132,8 +139,13 @@ class Computer
 
   sig {params(parameter: Parameter, value: Integer).void}
   def []=(parameter, value)
-    raise "writes should never be in immediate mode" if parameter.mode == Mode::Immediate
 
-    @memory[parameter.value] = value
+    mode = parameter.mode
+    case mode
+    when Mode::Position  then @memory[parameter.value] = value
+    when Mode::Immediate then raise "writes should never be in immediate mode"
+    when Mode::Relative then @memory[@relative_base + parameter.value] = value
+    else T.absurd(mode)
+    end
   end
 end
diff --git a/2019/ruby/day_09.rb b/2019/ruby/day_09.rb
new file mode 100644
index 0000000..64508ea
--- /dev/null
+++ b/2019/ruby/day_09.rb
@@ -0,0 +1,6 @@
+require_relative "computer"
+
+program = ARGF.read
+c = Computer.from(program)
+
+c.run(StringIO.new("2"))