Browse Source

Add completed day 5 program

Getty Ritter 4 years ago
parent
commit
0bfa4f83e5
1 changed files with 92 additions and 53 deletions
  1. 92 53
      05/main.pony

+ 92 - 53
05/main.pony

@@ -52,27 +52,33 @@ class val UnknownOperand is Error
   let _op: I64
   new val create(op: I64) => _op = op
   fun message(): String =>
-    "Unknown operand: " + Format.int[I64](_op)
+    "Unknown operation: " + Format.int[I64](_op)
 
+class val NotEnoughInput is Error
+  let _pc: USize
+  new val create(pc: USize) => _pc = pc
+  fun message(): String =>
+    "Not enough input when running instruction at " + Format.int[USize](_pc)
 
-primitive Handler
-  fun run(env: Env, result: (None | Error)) =>
-    match result
-      | None => None
-      | let e: Error => env.err.print(e.message())
-    end
+
+type Opcode is I64
+type Modes is (Bool, Bool, Bool)
 
 
 class Program
   var storage: Array[I64]
   var pc: USize = 0
-  var errors: Array[Error val]
+  var errors: Array[Error val] = Array[Error val]()
+
+  var input: Array[I64]
+  var output: Array[I64] = Array[I64]()
+  var debug: Array[String] = Array[String]()
 
-  new create(s: Array[I64]) =>
+  new create(s: Array[I64], i: Array[I64]) =>
     storage = s
-    errors = Array[Error val]()
+    input = i
 
-  new from_file(file: File) =>
+  new from_file(file: File, i: Array[I64]) =>
     storage = Array[I64](0)
     for line in file.lines() do
       for chunk in line.split(",").values() do
@@ -81,7 +87,7 @@ class Program
         end
       end
     end
-    errors = Array[Error val]()
+    input = i
 
 
   fun print(env: Env) =>
@@ -92,6 +98,10 @@ class Program
     end
     env.out.print("]")
 
+  fun ref dbg(msg: String) =>
+    debug.push(msg)
+
+
   fun ref read_storage(addr: USize): I64 ? =>
     try
       storage(addr)?
@@ -118,54 +128,91 @@ class Program
     let value = read_storage(addr.usize())?
     Position(addr, value)
 
+  fun ref get_value(addr_loc: USize, mode: Bool): Value ? =>
+    if mode then
+      get_immediate(addr_loc)?
+    else
+      get_position(addr_loc)?
+    end
+
 
-  fun ref get_op_data(): Operands ? =>
-    let lhs = get_position(pc+1)?
-    let rhs = get_position(pc+2)?
+  fun ref get_op_data(modes: Modes): Operands ? =>
+    (let lm, let rm, _) = modes
+    let lhs = get_value(pc+1, lm)?
+    let rhs = get_value(pc+2, rm)?
     let tgt = read_storage(pc+3)?
     Operands(lhs, rhs, tgt)
 
-  fun ref do_add() ? =>
-    let data = get_op_data()?
-    write_storage(data.tgt(), data.val1() + data.val2())?
-    pc = pc + 4
-    None
+  fun ref parse_op(n: I64): (Opcode, Modes) =>
+    let opcode = n % 100
+    let mode1 =   (n / 100) % 10
+    let mode2 =  (n / 1000) % 10
+    let mode3 = (n / 10000) % 10
+    (opcode, (mode1 == 1, mode2 == 1, mode3 == 1))
 
-  fun ref do_mul() ? =>
-    let data = get_op_data()?
-    write_storage(data.tgt(), data.val1() * data.val2())?
+
+  fun ref do_binop(modes: Modes, op: {(I64, I64): I64}) ? =>
+    let data = get_op_data(modes)?
+    write_storage(data.tgt(), op(data.val1(), data.val2()))?
     pc = pc + 4
-    None
 
-  fun ref run() ? =>
-    match read_storage(pc)?
-      | 1 => do_add()?
-      | 2 => do_mul()?
-      | 99 => return None
-      | let x: I64 =>
-        errors.push(UnknownOperand(x))
-        error
+  fun ref do_jump(modes: Modes, jump_cond: {(I64): Bool}) ? =>
+    (let cond, let tgt, _) = modes
+    if jump_cond(get_value(pc+1, cond)?.value()) then
+      pc = get_value(pc+2, tgt)?.value().usize()
+    else
+      pc = pc + 3
     end
-    run()?
 
-  fun make_trial(a: I64, b: I64): Program ? =>
-    var arr = storage.clone()
-    arr(1)? = a
-    arr(2)? = b
-    Program(arr)
+  fun ref do_input(modes: Modes) ? =>
+    let i = try
+      input.shift()?
+    else
+      errors.push(NotEnoughInput(pc))
+      error
+    end
+    write_storage(read_storage(pc+1)?.usize(), i)?
+    pc = pc + 2
+
+  fun ref do_output(modes: Modes) ? =>
+    (let m, _, _) = modes
+    output.push(get_value(pc+1, m)?.value())
+    pc = pc + 2
 
-  fun ref run_trial(env: Env): Bool =>
+
+  fun ref run() ? =>
+    while true do
+      (let opcode, let modes) = parse_op(read_storage(pc)?)
+      dbg("running op " + Format.int[I64](opcode))
+      match opcode
+        | 1 => do_binop(modes, {(x, y) => x + y})?
+        | 2 => do_binop(modes, {(x, y) => x * y})?
+        | 3 => do_input(modes)?
+        | 4 => do_output(modes)?
+        | 5 => do_jump(modes, {(x) => x != 0})?
+        | 6 => do_jump(modes, {(x) => x == 0})?
+        | 7 => do_binop(modes, {(x, y) => if x < y then 1 else 0 end})?
+        | 8 => do_binop(modes, {(x, y) => if x == y then 1 else 0 end})?
+        | 99 => return None
+        | let x: I64 =>
+          errors.push(UnknownOperand(x))
+          error
+      end
+    end
+
+  fun ref run_trial(env: Env) =>
     try
       run()?
     else
       for err in errors.values() do
         env.out.print(err.message())
       end
+      for n in debug.values() do
+        env.out.print("[debug] " + n)
+      end
     end
-    try
-      storage(0)? == 19690720
-    else
-      false
+    for n in output.values() do
+      env.out.print("> " + Format.int[I64](n))
     end
 
 actor Main
@@ -176,17 +223,9 @@ actor Main
       with
         file = OpenFile(FilePath(env.root as AmbientAuth, "input.txt", caps)?) as File
       do
-        let program = Program.from_file(file)
+        let program = Program.from_file(file, [5])
+        program.run_trial(env)
         program.print(env)
-        for a in Range[I64](0, 100) do
-          for b in Range[I64](0, 100) do
-            let trial = program.make_trial(a, b)?
-            if trial.run_trial(env) then
-              env.out.print("noun=" + Format.int[I64](a) + ", verb=" + Format.int[I64](b))
-              env.out.print("result=" + Format.int[I64]((a * 100) + b))
-            end
-          end
-        end
       end
     else
       // if something failed, then print an error message of some kind and exit