;; ported-from: src/games/host/valley-blocks-protocol.ts @ v1.3.0
;; (itself: game2/client/src/game/protocol.ts + config.ts MAX_PLAYERS /
;; STATE_INTERVAL_MS / PING_INTERVAL_MS @ 25e6d79)
;;
;; Flow: everyone → host: "hi", "lv" · host → everyone: "ro", "st", "ov", "lo" ·
;; host → one late joiner: "sn" · everyone → everyone: "bs" (own board only).
;; Unlike every other suite game the host holds no boards — each seat simulates
;; its own from the shared "st" seed.
(ns ardegazu.peer.games.host.valley-blocks-protocol
(:require [ardegazu.peer.games.host.valley-blocks-core :as core]))
(def MAX-PLAYERS 16)
(def STATE-INTERVAL-MS 150)
(def PING-INTERVAL-MS 2000)
(defn serialize-grid
"The visible field, row-major, '.' for empty — the string every rival sees."
[grid]
(let [n (.-length ^js grid)]
(loop [y core/HIDDEN-ROWS out ""]
(if (>= y n)
out
(let [row (aget grid y)
w (.-length row)]
(recur (inc y)
(loop [x 0 s out]
(if (>= x w)
s
(let [c (aget row x)]
(recur (inc x) (str s (if (identical? c 0) "." c))))))))))))
(defn board-state-of
"A player's own board as everyone else sees it. Six keys, literal order safe."
[game]
(let [snake (unchecked-get game "snake")]
(js-obj "grid" (serialize-grid (unchecked-get (unchecked-get game "board") "grid"))
"score" (unchecked-get game "score")
"lines" (unchecked-get game "lines")
"level" (unchecked-get game "level")
"snake" (if ^boolean (js* "!!(~{})" snake)
(.map (unchecked-get snake "segments")
(fn [s] #js [(aget s 0) (- (aget s 1) core/HIDDEN-ROWS)]))
nil)
"over" (unchecked-get game "over"))))