|
@@ -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
|