Setup Scala
This commit is contained in:
parent
8dec7591dd
commit
13a8e74189
37 changed files with 290 additions and 187 deletions
142
ocaml/lib/problem_runner.ml
Normal file
142
ocaml/lib/problem_runner.ml
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
open Import
|
||||
|
||||
module Credentials = struct
|
||||
type t = string
|
||||
|
||||
let of_auth_token (x : string) : t = x
|
||||
|
||||
let to_headers (t : t) : (string * string) list =
|
||||
[ ("Cookie", "session=" ^ t) ]
|
||||
end
|
||||
|
||||
module Run_mode = struct
|
||||
type t =
|
||||
| Test_from_puzzle_input of { credentials : Credentials.t option }
|
||||
| Submit of { credentials : Credentials.t }
|
||||
|
||||
let read_file (filename : string) : string =
|
||||
let ch = open_in_bin filename in
|
||||
let s = really_input_string ch (in_channel_length ch) in
|
||||
close_in ch;
|
||||
s
|
||||
|
||||
let write_file (filename : string) (contents : string) : unit =
|
||||
let ch = open_out_bin filename in
|
||||
let () = output_string ch contents in
|
||||
close_out ch
|
||||
|
||||
let get_puzzle_input (year : int) (day : int)
|
||||
(credentials : Credentials.t option) : (string, string) result =
|
||||
(* Create cache directory structure *)
|
||||
let () =
|
||||
if not (Sys.file_exists "inputs") then Sys.mkdir "inputs" 0o777 else ()
|
||||
in
|
||||
let year_dir = Filename.concat "inputs" @@ string_of_int year in
|
||||
let () =
|
||||
if not (Sys.file_exists year_dir) then Sys.mkdir year_dir 0o777 else ()
|
||||
in
|
||||
|
||||
(* Check if cached input exists *)
|
||||
let filename =
|
||||
Filename.concat year_dir @@ Format.sprintf "%02d.txt" day
|
||||
in
|
||||
if Sys.file_exists filename then Ok (read_file filename)
|
||||
(* If not, fetch it from adventofcode.com *)
|
||||
else
|
||||
match credentials with
|
||||
| None ->
|
||||
Error "Cannot fetch input from adventofcode.com: missing credentials."
|
||||
| Some credentials ->
|
||||
Result.map_error Piaf.Error.to_string
|
||||
@@ Lwt_main.run
|
||||
@@
|
||||
let uri =
|
||||
Uri.of_string
|
||||
@@ String.concat "/"
|
||||
[
|
||||
"https://adventofcode.com";
|
||||
string_of_int year;
|
||||
"day";
|
||||
string_of_int day;
|
||||
"input";
|
||||
]
|
||||
in
|
||||
let headers = Credentials.to_headers credentials in
|
||||
let* response = Piaf.Client.Oneshot.get ~headers uri in
|
||||
let* body = Piaf.Body.to_string response.body in
|
||||
write_file filename body;
|
||||
Lwt_result.return body
|
||||
|
||||
let get_input (year : int) (day : int) : t -> (string, string) result =
|
||||
function
|
||||
| Test_from_puzzle_input { credentials } ->
|
||||
get_puzzle_input year day credentials
|
||||
| Submit { credentials } -> get_puzzle_input year day (Some credentials)
|
||||
|
||||
let cleanup (year : int) (day : int) (part : int) (output : string)
|
||||
(run_mode : t) : (string option, string) result =
|
||||
match run_mode with
|
||||
| Test_from_puzzle_input _ -> Ok None
|
||||
| Submit { credentials } ->
|
||||
Result.map_error Piaf.Error.to_string
|
||||
@@ Lwt_main.run
|
||||
@@
|
||||
let uri =
|
||||
Uri.of_string
|
||||
@@ String.concat "/"
|
||||
[
|
||||
"https://adventofcode.com";
|
||||
string_of_int year;
|
||||
"day";
|
||||
string_of_int day;
|
||||
"answer";
|
||||
]
|
||||
in
|
||||
let headers = Credentials.to_headers credentials in
|
||||
let headers =
|
||||
headers @ [ ("Content-Type", "application/x-www-form-urlencoded") ]
|
||||
in
|
||||
let body =
|
||||
Piaf.Body.of_string @@ Fmt.(str "level=%d&answer=%s" part output)
|
||||
in
|
||||
let* response = Piaf.Client.Oneshot.post ~headers ~body uri in
|
||||
let* body = Piaf.Body.to_string response.body in
|
||||
Lwt_result.return (Some body)
|
||||
end
|
||||
|
||||
module Options = struct
|
||||
type t = { year : int; day : int; part : int; run_mode : Run_mode.t }
|
||||
end
|
||||
|
||||
let run_problem (module Problem : Problem.T) (run_mode : Run_mode.t)
|
||||
(year : int) (day : int) (part : int) : (string, string) result =
|
||||
let@ input = Run_mode.get_input year day run_mode in
|
||||
let@ result =
|
||||
match part with
|
||||
| 1 -> Problem.Part_1.run input
|
||||
| 2 -> Problem.Part_2.run input
|
||||
| p -> Error (Format.sprintf {|Invalid part "%d". Expected "1" or "2".|} p)
|
||||
in
|
||||
let@ cleanup_result = Run_mode.cleanup year day part result run_mode in
|
||||
let () =
|
||||
match cleanup_result with None -> () | Some result -> print_endline result
|
||||
in
|
||||
Ok result
|
||||
|
||||
let find_problem (year : int) (day : int) :
|
||||
((module Problem.T), string) result =
|
||||
match
|
||||
List.find_opt
|
||||
(fun (module Problem : Problem.T) ->
|
||||
Problem.year = year && Problem.day = day)
|
||||
Problems.All.all
|
||||
with
|
||||
| Some p -> Ok p
|
||||
| None ->
|
||||
Error
|
||||
(Format.sprintf "Problem (year = %d, day = %d) not implemented."
|
||||
year day)
|
||||
|
||||
let run (options : Options.t) : (string, string) result =
|
||||
let@ problem = find_problem options.year options.day in
|
||||
run_problem problem options.run_mode options.year options.day options.part
|
||||
Loading…
Add table
Add a link
Reference in a new issue