package pl.edu.pw.mini.sg.game.deterministic.single

import org.scalacheck.{ Prop, Properties }
import scala.annotation.tailrec
import Prop.BooleanOperators



abstract class LinearizedGameCheck(gameName: String, lgp: LinearizedGameProvider)
    extends Properties(gameName) {

  @tailrec
  private final def playMoveSequence(currentState: lgp.Game[Int, NaiveAdvanceableState],
    moves: List[(Int, NaiveAdvanceableState)]) : lgp.Game[Int, NaiveAdvanceableState] = moves match {
    case Nil => currentState
    case (m, s)::xs => {
      require(currentState.possibleMoves.contains(m), s"Illegal move $s in state $currentState")
      val succ = currentState.makeMove(m)
      require(succ.playerState == s)
      playMoveSequence(succ, xs)
    }
  }

  property("Should correctly reconstruct moves from pure strategy") =
    Prop.forAll(NaiveRandomGame.generateGameWithMoveSequence(lgp)){
      case GMS(game, moves) => {
        val lingame = lgp.create[Int, NaiveAdvanceableState](game.attackerState)
        require(lingame.possibleMoves == game.attackerState.possibleMoves)
        require(game.attackerState.possibleMoves.isEmpty == moves.isEmpty, s"Game attacker state possible moves is ${game.attackerState.possibleMoves}, but moves list is empty: ${moves}")
        require(game.attackerState.possibleMoves.isEmpty || moves.last._2.possibleMoves.isEmpty)

        val leaf = playMoveSequence(lingame, moves)
        require(leaf.possibleMoves.isEmpty, s"the last state should be game leaf, but has moves: ${leaf.possibleMoves}")
        val res = lgp.pureStrategyToLinearizedGameMoveSequence(game.attackerState, leaf.pureStrategy)
        s"evidence =  $res,\n original = ${moves.map(_._1)}" |: res  == moves.map(_._1)
      }
    }

}
