Created
December 5, 2019 19:19
-
-
Save zindel/217ee026044bd7d7fc0089773234a99d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
let solve lines = | |
let program = | |
lines | |
|> List.hd | |
|> CCString.split_on_char ',' | |
|> List.map int_of_string | |
in | |
let access () = | |
let program = Array.of_list program in | |
let get = Array.get program in | |
let set ~pos = Array.set program pos in | |
(get, set) | |
in | |
let exec inputs = | |
let inputs = ref inputs in | |
let read () = | |
match !inputs with | |
| hd :: tl -> | |
inputs := tl; | |
hd | |
| _ -> failwith "no input :(" | |
in | |
let outputs = ref [] in | |
let write output = | |
outputs := output :: !outputs | |
in | |
let (get, set) = access () in | |
let rec exec pos = | |
let op = get pos |> string_of_int |> CCString.to_list |> List.rev in | |
let with_modes modes = | |
let modes = | |
modes | |
|> CCString.of_list | |
|> CCString.pad ~side:`Right ~c:'0' 4 | |
|> CCString.to_list | |
in | |
let mode param = | |
match CCList.drop param modes with | |
| [] | '0' :: _ -> `Pos | |
| '1' :: _ -> `Value | |
| _ -> assert false | |
in | |
fun param -> | |
let value = get (pos + param) in | |
match mode param with | |
| `Value -> value | |
| `Pos -> get value | |
in | |
match op with | |
(* halt *) | |
| ['9'; '9'] -> () | |
(* read *) | |
| ['3'] -> | |
let input_pos = get (pos + 1) in | |
let value = read () in | |
set ~pos:input_pos value; | |
exec (pos + 2) | |
(* write *) | |
| '4' :: modes -> | |
let get_param = with_modes modes in | |
write (get_param 1); | |
exec (pos + 2) | |
(* jump-if-true / jump-if-false *) | |
| op :: modes when op = '5' || op = '6' -> | |
let get_param = with_modes modes in | |
let f = if op = '5' then ( <> ) 0 else ( = ) 0 in | |
let next = match get_param 1 |> f with | |
| true -> get_param 2 | |
| false -> pos + 3 | |
in | |
exec next | |
(* less-than / equals *) | |
| op :: modes when op = '7' || op = '8' -> | |
let get_param = with_modes modes in | |
let f = if op = '7' then ( < ) else ( = ) in | |
let value = match f (get_param 1) (get_param 2) with | |
| true -> 1 | |
| false -> 0 | |
in | |
set ~pos:(get (pos + 3)) value; | |
exec (pos + 4) | |
(* add / mul *) | |
| op :: modes when op = '1' || op = '2' -> | |
let get_param = with_modes modes in | |
let f = if op = '1' then ( + ) else ( * ) in | |
let res = f (get_param 1) (get_param 2) in | |
let res_pos = get (pos + 3) in | |
set ~pos:res_pos res; | |
exec (pos + 4) | |
| op -> | |
CCString.of_list op |> print_endline; | |
assert false | |
in | |
exec 0; | |
!outputs | |
in | |
Printf.printf "Part1 = %d\n" (exec [1] |> List.hd); | |
Printf.printf "Part2 = %d\n" (exec [5] |> List.hd); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment