package pl.edu.pw.mini.sg.game.graph.sud

import pl.edu.pw.mini.sg.rng.RandomGenerator
import pl.edu.pw.mini.sg.game.deterministic.AdvanceablePlayerVisibleState
import pl.edu.pw.mini.sg.game.graph.DeterministicGraphGameConfig
import pl.edu.pw.mini.sg.util.CachedHashPair
import scala.runtime.ScalaRunTime


final case class SingleUnitDefenderState(
  graphGameConfig: DeterministicGraphGameConfig,
  unitPositions: FastArrayWrapper,
  currentUnit: Int,
  timeStep: Int
) extends AdvanceablePlayerVisibleState[Int, SingleUnitDefenderState] {
  def continuation(move: Int) : SingleUnitDefenderState = {
    assert(timeStep < graphGameConfig.rounds)
    assert(possibleMoves.contains(move))
    graphGameConfig.defenderCache.get(CachedHashPair(move, this), (p: CachedHashPair[Int, SingleUnitDefenderState]) => {
      val s = p.second
      val m = p.first
      val (cuNext, tsNext) =
        if(s.currentUnit == graphGameConfig.defenderUnitCount -1)
          (0, s.timeStep + 1)
        else
          (s.currentUnit + 1, s.timeStep)
      s.copy(currentUnit = cuNext, timeStep = tsNext, unitPositions = s.unitPositions.updated(s.currentUnit, m))
    })
    
  }

  override def possibleContinuations(move: Int): List[SingleUnitDefenderState] = List(continuation(move))
  override def sampleContinuations(move: Int)(implicit rng: RandomGenerator): SingleUnitDefenderState = continuation(move)
  override def possibleMoves: List[Int] =
    if(timeStep < graphGameConfig.rounds) graphGameConfig.possibleMovesFromVertex(unitPositions(currentUnit))
    else Nil

  override lazy val hashCode : Int = ScalaRunTime._hashCode((unitPositions, currentUnit, timeStep))
  override def equals(other: Any) : Boolean = other match {
    case suds : SingleUnitDefenderState => suds.unitPositions == unitPositions && currentUnit == suds.currentUnit && timeStep == suds.timeStep
    case _ => false
  }

  override def toString: String = s"SUDS(pos = ${unitPositions}, curr=${currentUnit}, ts=${timeStep}"
}
