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

import org.scalacheck.Gen
import pl.edu.pw.mini.sg.game.deterministic.{ AdvanceablePlayerVisibleState, DeterministicGame, PlayerVisibleState, PureStrategy }
import pl.edu.pw.mini.sg.mixed.IterationInfo
import pl.edu.pw.mini.sg.mixed.tree.{ MixedStrategyNode}
import scala.collection.mutable.{ArrayBuffer, Map => MMap}


object MixedStrategyGen {
  def sequence[T](l: List[Gen[T]]) : Gen[List[T]] = l match {
    case Nil => Gen.const(Nil)
    case x::xx => x.flatMap(e => sequence(xx).map(ee => e::ee))
  }


  def strategyForGame[DM, AM,
    DS <: PlayerVisibleState[DM],
    AS <: AdvanceablePlayerVisibleState[AM, AS],
    G <: DeterministicGame[DM, AM, DS, AS, G]
  ](game : G, pureStrategyX: PureStrategy[AM, AS]) : Gen[MixedStrategyNode[DM, DS, Unit]] = {
    import MixedStrategyNode.unitST
    def generateNode(defenderState: DS, realState: G, pureStrategy: PureStrategy[AM, AS]) : Gen[MixedStrategyNode[DM, DS, Unit]] = {
      if(defenderState.possibleMoves.isEmpty) {
        Gen.const(new MixedStrategyNode(defenderState, ArrayBuffer(), MMap()))
      } else {
        for {
          moves <- Gen.atLeastOne(defenderState.possibleMoves)
          probabilities1 <- Gen.containerOfN[Vector, Double](moves.size, Gen.choose(0.1, 0.9))
          sum = probabilities1.sum
          prob2 = probabilities1.map(_/sum)
          successors <- sequence(moves.map(m => {
            val succ = realState.makeMove(m, pureStrategy.move)
            generateNode(succ.defenderState, succ, pureStrategy.nextState(succ.attackerState)).map(n =>
              (m, MMap(succ.defenderState -> n)))
          }).toList)
        } yield new MixedStrategyNode(defenderState, ArrayBuffer(moves.zip(prob2).map{case (m,p) => (m,p, IterationInfo.dummyIterationInfo)}:_*), MMap(successors : _*))
      }
    }
    generateNode(game.defenderState, game, pureStrategyX)
  }
}
