type Memory = string array type Instruction = int type Modes = (int * int * int) type State = (Memory * Instruction) type Operation = (State * Modes) -> State let program = "3,225,1,225,6,6,1100,1,238,225,104,0,1102,88,66,225,101,8,125,224,101,-88,224,224,4,224,1002,223,8,223,101,2,224,224,1,224,223,223,1101,87,23,225,1102,17,10,224,101,-170,224,224,4,224,102,8,223,223,101,3,224,224,1,223,224,223,1101,9,65,225,1101,57,74,225,1101,66,73,225,1101,22,37,224,101,-59,224,224,4,224,102,8,223,223,1001,224,1,224,1,223,224,223,1102,79,64,225,1001,130,82,224,101,-113,224,224,4,224,102,8,223,223,1001,224,7,224,1,223,224,223,1102,80,17,225,1101,32,31,225,1,65,40,224,1001,224,-32,224,4,224,102,8,223,223,1001,224,4,224,1,224,223,223,2,99,69,224,1001,224,-4503,224,4,224,102,8,223,223,101,6,224,224,1,223,224,223,1002,14,92,224,1001,224,-6072,224,4,224,102,8,223,223,101,5,224,224,1,223,224,223,102,33,74,224,1001,224,-2409,224,4,224,1002,223,8,223,101,7,224,224,1,223,224,223,4,223,99,0,0,0,677,0,0,0,0,0,0,0,0,0,0,0,1105,0,99999,1105,227,247,1105,1,99999,1005,227,99999,1005,0,256,1105,1,99999,1106,227,99999,1106,0,265,1105,1,99999,1006,0,99999,1006,227,274,1105,1,99999,1105,1,280,1105,1,99999,1,225,225,225,1101,294,0,0,105,1,0,1105,1,99999,1106,0,300,1105,1,99999,1,225,225,225,1101,314,0,0,106,0,0,1105,1,99999,107,677,677,224,1002,223,2,223,1006,224,329,101,1,223,223,108,677,677,224,1002,223,2,223,1005,224,344,101,1,223,223,1007,677,677,224,1002,223,2,223,1006,224,359,101,1,223,223,1107,226,677,224,1002,223,2,223,1006,224,374,1001,223,1,223,8,677,226,224,1002,223,2,223,1006,224,389,101,1,223,223,1108,677,677,224,1002,223,2,223,1005,224,404,1001,223,1,223,7,226,226,224,1002,223,2,223,1006,224,419,101,1,223,223,1107,677,677,224,1002,223,2,223,1005,224,434,101,1,223,223,107,226,226,224,102,2,223,223,1005,224,449,101,1,223,223,107,677,226,224,1002,223,2,223,1006,224,464,1001,223,1,223,8,226,677,224,102,2,223,223,1006,224,479,1001,223,1,223,108,677,226,224,102,2,223,223,1005,224,494,1001,223,1,223,1108,677,226,224,1002,223,2,223,1005,224,509,1001,223,1,223,1107,677,226,224,1002,223,2,223,1005,224,524,101,1,223,223,1008,226,226,224,1002,223,2,223,1006,224,539,101,1,223,223,1008,226,677,224,1002,223,2,223,1005,224,554,1001,223,1,223,7,226,677,224,1002,223,2,223,1005,224,569,101,1,223,223,1007,677,226,224,1002,223,2,223,1006,224,584,1001,223,1,223,7,677,226,224,102,2,223,223,1006,224,599,101,1,223,223,1007,226,226,224,102,2,223,223,1006,224,614,101,1,223,223,1008,677,677,224,1002,223,2,223,1006,224,629,101,1,223,223,108,226,226,224,102,2,223,223,1006,224,644,101,1,223,223,1108,226,677,224,1002,223,2,223,1005,224,659,101,1,223,223,8,226,226,224,1002,223,2,223,1005,224,674,101,1,223,223,4,223,99,226" // let program = "1002,4,3,4,33".Split [| ',' |] let dereference (mem: Memory) pointer mode = let value = mem.[pointer] if mode = 1 then value else mem.[int value] let add ((mem, ip): State) ((m1, m2, _): Modes): State = let op1 = dereference mem (ip + 1) m1 let op2 = dereference mem (ip + 2) m2 let addr = dereference mem (ip + 3) 1 mem.[int addr] <- string ((int op1) + (int op2)) (mem, ip + 4) let mul ((mem, ip): State) ((m1, m2, _): Modes): State = let op1 = dereference mem (ip + 1) m1 let op2 = dereference mem (ip + 2) m2 let addr = dereference mem (ip + 3) 1 mem.[int addr] <- string ((int op1) * (int op2)) (mem, ip + 4) let inp ((mem, ip): State) (_): State = let address = dereference mem (ip + 1) 1 printf "input: " mem.[int address] <- System.Console.ReadLine () (mem, ip + 2) let out ((mem, ip): State) (_): State = let address = dereference mem (ip + 1) 1 printfn "%s" mem.[int address] (mem, ip + 2) let getModes (opcode: string array) length: Modes = let toMode index = Array.tryItem (length - index) opcode |> Option.defaultValue "0" |> int (toMode 3, toMode 4, toMode 5) let eval ((mem, ip) as state: State): State option = let opcode = mem.[ip].ToCharArray () |> Array.map string let modes = getModes opcode opcode.Length let code = Array.last opcode |> int match code with | 1 -> Some (add state modes) | 2 -> Some (mul state modes) | 3 -> Some (inp state modes) | 4 -> Some (out state modes) | _ -> None let rec run (state: State): State = match eval state with | Some newState -> run newState | None -> state [] let main (_: string[]) = run (program.Split [| ',' |], 0) |> ignore 0