|
@@ -0,0 +1,195 @@
|
|
|
+use "collections"
|
|
|
+use "files"
|
|
|
+use "format"
|
|
|
+
|
|
|
+interface Value
|
|
|
+ fun value(): I64
|
|
|
+
|
|
|
+
|
|
|
+class Position
|
|
|
+ let _addr: I64
|
|
|
+ let _value: I64
|
|
|
+
|
|
|
+ new create(__addr: I64, __value: I64) =>
|
|
|
+ _addr = __addr
|
|
|
+ _value = __value
|
|
|
+
|
|
|
+ fun addr(): I64 => _addr
|
|
|
+ fun value(): I64 => _value
|
|
|
+
|
|
|
+class Immediate
|
|
|
+ let _value: I64
|
|
|
+
|
|
|
+ new create(__value: I64) =>
|
|
|
+ _value = __value
|
|
|
+
|
|
|
+ fun value(): I64 => _value
|
|
|
+
|
|
|
+class Operands
|
|
|
+ let _lhs: Value
|
|
|
+ let _rhs: Value
|
|
|
+ let _tgt: I64
|
|
|
+
|
|
|
+ new create(__lhs: Value, __rhs: Value, __tgt: I64) =>
|
|
|
+ _lhs = __lhs
|
|
|
+ _rhs = __rhs
|
|
|
+ _tgt = __tgt
|
|
|
+
|
|
|
+ fun val1(): I64 => _lhs.value()
|
|
|
+ fun val2(): I64 => _rhs.value()
|
|
|
+ fun tgt(): USize => _tgt.usize()
|
|
|
+
|
|
|
+trait Error
|
|
|
+ fun message(): String
|
|
|
+
|
|
|
+class val OutOfBounds is Error
|
|
|
+ let _loc: USize
|
|
|
+ new val create(loc: USize) => _loc = loc
|
|
|
+ fun message(): String =>
|
|
|
+ "Memory access out of bounds: " + Format.int[USize](_loc)
|
|
|
+
|
|
|
+class val UnknownOperand is Error
|
|
|
+ let _op: I64
|
|
|
+ new val create(op: I64) => _op = op
|
|
|
+ fun message(): String =>
|
|
|
+ "Unknown operand: " + Format.int[I64](_op)
|
|
|
+
|
|
|
+
|
|
|
+primitive Handler
|
|
|
+ fun run(env: Env, result: (None | Error)) =>
|
|
|
+ match result
|
|
|
+ | None => None
|
|
|
+ | let e: Error => env.err.print(e.message())
|
|
|
+ end
|
|
|
+
|
|
|
+
|
|
|
+class Program
|
|
|
+ var storage: Array[I64]
|
|
|
+ var pc: USize = 0
|
|
|
+ var errors: Array[Error val]
|
|
|
+
|
|
|
+ new create(s: Array[I64]) =>
|
|
|
+ storage = s
|
|
|
+ errors = Array[Error val]()
|
|
|
+
|
|
|
+ new from_file(file: File) =>
|
|
|
+ storage = Array[I64](0)
|
|
|
+ for line in file.lines() do
|
|
|
+ for chunk in line.split(",").values() do
|
|
|
+ try
|
|
|
+ storage.push(chunk.i64()?)
|
|
|
+ end
|
|
|
+ end
|
|
|
+ end
|
|
|
+ errors = Array[Error val]()
|
|
|
+
|
|
|
+
|
|
|
+ fun print(env: Env) =>
|
|
|
+ env.out.write("[")
|
|
|
+ for x in storage.values() do
|
|
|
+ env.out.write(Format.int[I64](x))
|
|
|
+ env.out.write(" ")
|
|
|
+ end
|
|
|
+ env.out.print("]")
|
|
|
+
|
|
|
+ fun ref read_storage(addr: USize): I64 ? =>
|
|
|
+ try
|
|
|
+ storage(addr)?
|
|
|
+ else
|
|
|
+ errors.push(OutOfBounds(addr))
|
|
|
+ error
|
|
|
+ end
|
|
|
+
|
|
|
+ fun ref write_storage(addr: USize, value: I64) ? =>
|
|
|
+ try
|
|
|
+ storage(addr)? = value
|
|
|
+ else
|
|
|
+ errors.push(OutOfBounds(addr))
|
|
|
+ error
|
|
|
+ end
|
|
|
+
|
|
|
+
|
|
|
+ fun ref get_immediate(addr_loc: USize): Immediate ? =>
|
|
|
+ let value = read_storage(addr_loc)?
|
|
|
+ Immediate(value)
|
|
|
+
|
|
|
+ fun ref get_position(addr_loc: USize): Position ? =>
|
|
|
+ let addr = read_storage(addr_loc)?
|
|
|
+ let value = read_storage(addr.usize())?
|
|
|
+ Position(addr, value)
|
|
|
+
|
|
|
+
|
|
|
+ fun ref get_op_data(): Operands ? =>
|
|
|
+ let lhs = get_position(pc+1)?
|
|
|
+ let rhs = get_position(pc+2)?
|
|
|
+ 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 do_mul() ? =>
|
|
|
+ let data = get_op_data()?
|
|
|
+ write_storage(data.tgt(), 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
|
|
|
+ end
|
|
|
+ run()?
|
|
|
+
|
|
|
+ fun make_trial(a: I64, b: I64): Program ? =>
|
|
|
+ var arr = storage.clone()
|
|
|
+ arr(1)? = a
|
|
|
+ arr(2)? = b
|
|
|
+ Program(arr)
|
|
|
+
|
|
|
+ fun ref run_trial(env: Env): Bool =>
|
|
|
+ try
|
|
|
+ run()?
|
|
|
+ else
|
|
|
+ for err in errors.values() do
|
|
|
+ env.out.print(err.message())
|
|
|
+ end
|
|
|
+ end
|
|
|
+ try
|
|
|
+ storage(0)? == 19690720
|
|
|
+ else
|
|
|
+ false
|
|
|
+ end
|
|
|
+
|
|
|
+actor Main
|
|
|
+ new create(env: Env) =>
|
|
|
+ let caps = recover val FileCaps.>set(FileRead).>set(FileStat) end
|
|
|
+
|
|
|
+ try
|
|
|
+ with
|
|
|
+ file = OpenFile(FilePath(env.root as AmbientAuth, "input.txt", caps)?) as File
|
|
|
+ do
|
|
|
+ let program = Program.from_file(file)
|
|
|
+ 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
|
|
|
+ env.err.print("Couldn't read expected file `input.txt'")
|
|
|
+ env.exitcode(99)
|
|
|
+ end
|