• R/O
  • HTTP
  • SSH
  • HTTPS

Tags
Aucun tag

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

A Nix-friendly SQLite-enhanced fork of Flitter, a speedrunning split timer for Unix-style terminals


File Info

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...

Content

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)