;; ported-from: src/games/host/sim.ts @ v1.3.0
;;
;; Shared shape of a pure host simulation. A sim owns the authoritative game
;; state and nothing else: no timers, no networking, no ambient randomness or
;; clock — every transition returns the frames to deliver plus a descriptor of
;; the single next scheduled step. The live driver turns `next` into a real
;; timer and broadcasts the frames (looping them back through the local client,
;; exactly like the browsers' hostEmit); the gym ignores `inMs` and steps
;; synchronously, which is what makes offline RL training fast.
;;
;; SimEmit = #js {:frames [#js {:f frame :to peerId?} …]
;; :next #js {:step name :inMs ms} | nil | undefined
;; :matchEnd [[id nick score] …]?}
;;
;; `next` has THREE states and the driver distinguishes all three: an object
;; replaces any pending step, null cancels it, and *absent* leaves the pending
;; schedule untouched. The port keeps that distinction by simply not setting
;; the key — `undefined` on read, exactly as in TS.
(ns ardegazu.peer.games.host.sim)
(def NO-EMIT (js-obj "frames" #js []))
(defn frames
"An emit carrying just frames (no `next` key at all)."
[& fs]
(js-obj "frames" (into-array fs)))
(defn frame
"One SimFrame: `to` absent ⇒ broadcast."
([f] (js-obj "f" f))
([to f] (js-obj "to" to "f" f)))
(defn next-step [step in-ms]
(js-obj "step" step "inMs" in-ms))