| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195 | use "collections"use "files"use "format"interface Value  fun value(): I64class Position  let _addr: I64  let _value: I64  new create(__addr: I64, __value: I64) =>    _addr = __addr    _value = __value  fun addr(): I64 => _addr  fun value(): I64 => _valueclass Immediate  let _value: I64  new create(__value: I64) =>    _value = __value  fun value(): I64 => _valueclass 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(): Stringclass 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())    endclass 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    endactor 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
 |