package pl.edu.pw.mini.sg.game.boundedrationality

import org.scalacheck.{ Gen, Prop, Properties }
import pl.edu.pw.mini.sg.game.deterministic.PureStrategy
import pl.edu.pw.mini.sg.game.deterministic.single.{ DefenderGameView, LinearizedAdvanceableGame, NaiveAdvanceableState, NaiveDefenderState, NaiveRandomGame, SinglePlayerGame }
import pl.edu.pw.mini.sg.game.util.attacker.OptimalAttacker
import pl.edu.pw.mini.sg.mixed.expansion.DummyExpander
import pl.edu.pw.mini.sg.mixed.tree.{ CalculateResults, GameResultNode, InnerResultNode, MixedStrategyNode }


abstract class PayoffCoherenceCheck(br : Gen[BoundedRationality], name: String) extends Properties(s"Payoff coherence: $name") {
  implicit val gameWithStrategyGen : Gen[(NaiveRandomGame,
    PureStrategy[Int, NaiveAdvanceableState], 
    MixedStrategyNode[Int, NaiveDefenderState, Unit])] =
    for {
      game <- NaiveRandomGame.gameGeneratorStart
      attackerStrategy <- PureStrategyGen.genPureStrategy[Int, Int, NaiveDefenderState, NaiveAdvanceableState, NaiveRandomGame](game)
      strategy <- MixedStrategyGen.strategyForGame[Int, Int, NaiveDefenderState, NaiveAdvanceableState, NaiveRandomGame](game, attackerStrategy)
    } yield (game, attackerStrategy, strategy)

  property("should give the same payoff in GameResultNode and OptimalAttacker.payoff") = Prop.forAll(
    gameWithStrategyGen, br
  ){case ((game, attackerStrategy, strategy), boundedRationality) => {
    val payoff1 = OptimalAttacker.payoff[Int, Int, NaiveDefenderState, NaiveAdvanceableState, NaiveRandomGame](game, strategy, attackerStrategy)(boundedRationality)
    val resultNode = new InnerResultNode[Int, NaiveDefenderState](strategy, game.defenderState)(boundedRationality)
    CalculateResults.calculate(game, strategy, attackerStrategy, resultNode, DummyExpander, true)(null, boundedRationality)

    import Prop.BooleanOperators

    (s"evidence P1(oa): ${payoff1} P2(cp): ${resultNode.payoff}") |:  Math.abs(payoff1.real.defender - resultNode.payoff.real.defender) < 1e-5
  }}
}
