A Nix-friendly SQLite-enhanced fork of Flitter, a speedrunning split timer for Unix-style terminals
Révision | 8aa997f0c15b38ce52569a1387afea104f4bcdb5 |
---|---|
Taille | 4,000 octets |
l'heure | 2023-07-07 12:19:42 |
Auteur | Corbin |
Message de Log | Make Gold.to_image foldable.
Okay! This was the missing piece. Now to restore the big patch...
|
open Core
open Timer_types
let split_time timer ~now split_num =
if split_num < 0 then Some 0
else
match timer.state with
| Idle -> None
| Paused (splits, start_time, pause_time, _) ->
if split_num > Array.length splits then None
else if split_num = Array.length splits then
Some (Duration.between start_time pause_time)
else splits.(split_num)
| Timing (splits, start_time, _) | Done (splits, start_time, _) ->
if split_num > Array.length splits then None
else if split_num = Array.length splits then
Some (Duration.between start_time now)
else splits.(split_num)
let duration timer =
match timer.state with
| Idle -> 0
| Timing (splits, _, now) | Paused (splits, _, _, now) | Done (splits, _, now)
->
Option.value_exn (split_time ~now timer (Array.length splits))
(* Difference between two optional times. *)
let option_diff t0 t1 =
match (t0, t1) with Some t0', Some t1' -> Some (t1' - t0') | _ -> None
let ahead_by timer ~now split_num =
if split_num < 0 then None
else
let split_time = split_time timer ~now split_num in
let comp_time =
Option.bind timer.comparison ~f:(fun comp -> comp.splits.(split_num).time)
in
option_diff comp_time split_time
let segment_time timer ~now split_num =
let t0 = split_time timer ~now (split_num - 1) in
let t1 = split_time timer ~now split_num in
option_diff t0 t1
let current_split timer = Option.map (opt_splits timer.state) ~f:Array.length
let is_gold timer ~now split_num =
match (current_split timer, segment_time ~now timer split_num) with
| Some n, Some seg_time -> (
if split_num >= n then false
else
match timer.golds.(split_num).duration with
| Some duration -> seg_time < duration
| None -> true)
| _ -> false
let updated_golds timer =
match timer.state with
| Idle -> timer.golds
| Timing (splits, _, now) | Paused (splits, _, _, now) | Done (splits, _, now)
->
let seg_durations =
Array.mapi splits ~f:(fun i _ -> segment_time ~now timer i)
in
let old_durations = Array.map timer.golds ~f:(fun g -> g.duration) in
let new_durations =
Array.mapi timer.split_names ~f:(fun i _ ->
if i >= Array.length splits then old_durations.(i)
else
match (seg_durations.(i), old_durations.(i)) with
| Some n, Some o -> if n < o then Some n else Some o
| Some n, None -> Some n
| None, Some o -> Some o
| None, None -> None)
in
Array.map2_exn timer.split_names new_durations ~f:(fun name dur ->
{ title = name; duration = dur })
let gold_sum timer start bound =
let gold_array = Array.slice (updated_golds timer) start bound in
Array.fold gold_array ~init:(Some 0) ~f:(fun sum gold ->
match (sum, gold.duration) with
| Some x, Some y -> Some (x + y)
| _ -> None)
let archived_split_time run split_num =
if split_num < 0 then Some 0
else Option.bind run.comparison ~f:(fun comp -> comp.splits.(split_num).time)
let archived_segment_time run split_num =
let t0 = archived_split_time run (split_num - 1) in
let t1 = archived_split_time run split_num in
option_diff t0 t1
let archive_done_run timer ~now splits =
let run_splits =
Array.mapi timer.split_names ~f:(fun i name ->
{ title = name; time = splits.(i); is_gold = is_gold timer i ~now })
in
{ attempt = timer.attempts; splits = run_splits }
let updated_pb timer =
match timer.state with
| Idle | Timing _ | Paused _ -> timer.pb
| Done (splits, _, now) ->
Option.bind timer.pb ~f:(fun pb_run ->
let last_idx = Array.length splits - 1 in
match (splits.(last_idx), pb_run.splits.(last_idx).time) with
| Some new_t, Some old_t ->
if new_t < old_t then Some (archive_done_run timer splits ~now)
else timer.pb
| _ -> None)