; SPDX-FileCopyrightText: 2023 Jummit
;
; SPDX-License-Identifier: GPL-3.0-or-later

(local {: is-online} (require :match.info))
(local {: view} (require :fennel))

(fn make-state [world player]
  "Analyses the world and returns a view of the game state for the
given player. The structure contains the terminal, online and captured
cards, and some information about the cells:

{:online [{:kind :virus :x 1 :y 2 :mine true :boosted true}]
 :terminals {:line-boost true true :404 true}]
 :captured [{:kind :virus :mine true}
 :cells [{:x 1 :y 1 :fire-wall :enemies :exit :mine}]]}

This function exists so AIs or players don't accidentally access
information that they shouldn't have, and to structure the data
so it is easier to use."
  {:terminals (collect [_ entity (ipairs world)]
                (case entity
                  (where {:card {: owner : kind}}
                         (and (not (is-online entity.card)) (= owner player)))
                  (values kind true)))
   :captured (icollect [_ entity (ipairs world)]
               (case entity
                 {:card {: owner : kind} :captured true}
                 {:mine (= player owner) :kind (when (= player owner) kind)}))
   :online (icollect [_ entity (ipairs world)]
             (case entity
               {:card {: owner : kind} :circuit-x x :circuit-y y :captured nil}
               {: x : y :mine (= player owner) : kind :boosted entity.boosted}))
   :cells (icollect [_ entity (ipairs world)]
            (case entity
              (where {:circuit-x x :circuit-y y} entity.cell)
              {: x
               : y
               :fire-wall (match entity.cell.fire-walled player :mine nil nil _ :enemies)
               :exit (match entity.cell.exit-for player :mine nil nil _ :enemies)}))})

(fn enemies [mine]
  (case mine
    :mine
    :enemies
    :enemies
    :mine))

(fn invert-state [state]
  "Returns the board state flipped, as the opponent sees it."
  {:cells (icollect [_ {: x : y : fire-wall : exit} (ipairs state.cells)]
            {: x : y :fire-wall (enemies fire-wall) :exit (enemies exit)})
   :online (icollect [_ {: x : y : mine : boosted} (ipairs state.online)]
             {: x : y :mine (not mine) : boosted})
   :captured (icollect [_ {: mine : kind} (ipairs state.captured)]
               {:mine (not mine) : kind})
   :terminals {}})

{: make-state : invert-state}