package pl.edu.pw.mini.game.flipit.deterministic.noinfo

import pl.edu.pw.mini.sg.rng.RandomGenerator
import pl.edu.pw.mini.sg.game.deterministic.AdvanceablePlayerVisibleState
import pl.edu.pw.mini.game.flipit.deterministic.{Flip, FlipItMove, NoOp}

sealed trait NoInfoFlipItAttackerState
    extends AdvanceablePlayerVisibleState[FlipItMove, NoInfoFlipItAttackerState] {
  def nextState(move: FlipItMove) : NoInfoFlipItAttackerState

  override def possibleContinuations(move: FlipItMove) : List[NoInfoFlipItAttackerState] =
    List(nextState(move))
  override def sampleContinuations(move: FlipItMove)(implicit rng: RandomGenerator) =
    nextState(move)
}

object NoInfoFlipItAttackerStateTerminal extends NoInfoFlipItAttackerState {
  override def nextState(move: FlipItMove) : NoInfoFlipItAttackerState =
    throw new IllegalStateException("terminal state")
  override def possibleMoves: List[FlipItMove] = Nil
}

final class NoInfoFlipItAttackerStateInner(
  cache: NoInfoFlipItCache,
  val moves: SortedList[Flip, Flip.ord.type],
  val round: Int
)extends NoInfoFlipItAttackerState {
  override def possibleMoves : List[FlipItMove] = NoOp :: moves.innerList
  override def equals(other: Any) : Boolean = other match {
    case as: NoInfoFlipItAttackerStateInner => moves == as.moves && round == as.round
    case _ => false
  }
  override def hashCode: Int = (round, moves).##

  override def nextState(m: FlipItMove) : NoInfoFlipItAttackerState =
    if(round == cache.flipitConfig.rounds) NoInfoFlipItAttackerStateTerminal
    else
      new NoInfoFlipItAttackerStateInner(cache, 
      m match {
        case NoOp => moves
        case f: Flip => moves.merge(cache.neighbours(f.vertex))(Flip.ord)
    }, round+1)
}
