package pl.edu.pw.mini.sg.mixed.stchooser

import pl.edu.pw.mini.sg.rng.RandomGenerator
import org.log4s._
import pl.edu.pw.mini.sg.mixed.tree.{InnerResultNode, MixedStrategyNode}
import pl.edu.pw.mini.sg.game.deterministic.PlayerVisibleState

case class ValueSubtreeChooser(
  probBoost: Double 
)extends SubtreeChooser {
  private val logger = getLogger

  override def chooseInSubtrees[M, S <: PlayerVisibleState[M]](
    desiredAttacker: InnerResultNode[M, S],
    optimalAttacker: InnerResultNode[M, S],
    strategy: MixedStrategyNode[M, S, _]
  )(
    implicit rng: RandomGenerator
  ) : List[M] = {
    strategy.probabilities.view.map{case (move, pr) => {
      (optimalAttacker.successors.get(move), desiredAttacker.successors.get(move)) match {
        case (Some(oa), Some(da)) => {
          val prob = pr + Math.abs(oa.payoff.distortedAttacker.attacker - da.payoff.distortedAttacker.attacker)
          if(prob+probBoost > rng.nextDouble()) Some(move)
      else None

        }
        case _ => None
      }
    }}.foldLeft(List[M]())((list, el) => el match {
      case Some(x) => x :: list
      case None => list
    })
  }
  
  override def chooseOutSubtrees[M, S <: PlayerVisibleState[M]](
    optimalAttacker: InnerResultNode[M, S],
    strategy: MixedStrategyNode[M, S, _]
  )(
    implicit rng: RandomGenerator
  ) : List[M] = {
    strategy.probabilities.view.map{case (move, pr) => {
      if((optimalAttacker.successors(move).payoff.distortedAttacker.attacker) + probBoost >= rng.nextDouble())
        Some(move)
      else
        None
    }}.foldLeft(List[M]())((list, el) => el match {
      case Some(x) => x :: list
      case None => list
    })
  }

  override
  def choosePositivePhaseSubtrees[M, S <: PlayerVisibleState[M]](
    gameResult: InnerResultNode[M, S],
    strategy: MixedStrategyNode[M, S, _]
  )(
    implicit rng: RandomGenerator
  ) : List[M] = {
    strategy.probabilities.view.map{case (move, pr) => {
      if(((1-gameResult.successors(move).payoff.real.defender)) + probBoost >= rng.nextDouble())
        Some(move)
      else
        None
    }}.foldLeft(List[M]())((list, el) => el match {
      case Some(x) => x :: list
      case None => list
    })

  }

}
