/**
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package bots.mctsbot.ai.bots.bot.gametree.rollout;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import org.apache.log4j.Logger;
import bots.mctsbot.client.common.gamestate.GameState;
import bots.mctsbot.client.common.playerstate.PlayerState;
import bots.mctsbot.common.elements.player.PlayerId;
import bots.mctsbot.common.util.MutableDouble;
import com.biotools.meerkat.Card;
public abstract class AbstractDistributionRollout extends RollOutStrategy {
private final static Logger logger = Logger.getLogger(AbstractDistributionRollout.class);
public final int relPotSize;
AbstractDistributionRollout(GameState gameState, PlayerId botId) {
super(gameState, botId);
this.relPotSize = gamePotSize / ((activeOpponents.size() + 1) * gameState.getTableConfiguration().getBigBlind());
}
public RolloutResult doRollOut(int nbCommunitySamples, int nbOpponentSamples) {
boolean traceEnabled = logger.isTraceEnabled();
double totalProb = 0;
TreeSet<PlayerState> drawers = new TreeSet<PlayerState>(playerComparatorByInvestment);
TreeMap<Integer, MutableDouble> values = new TreeMap<Integer, MutableDouble>();
for (int i = 0; i < nbCommunitySamples; i++) {
int communitySampleRank = fixedRank;
Set<Integer> usedCommunityAndBotCards = new TreeSet<Integer>(usedFixedCommunityAndBotCards);
for (int j = 0; j < nbMissingCommunityCards; j++) {
Integer communityCard = drawNewCard(usedCommunityAndBotCards);
if (traceEnabled) {
logger.trace("Evaluating sampled community card " + new Card(communityCard));
}
communitySampleRank = updateIntermediateRank(communitySampleRank, new Card(communityCard));
}
if (traceEnabled) {
logger.trace("Evaluating bot cards " + botCard1 + " " + botCard2);
}
int botRank = getFinalRank(communitySampleRank, botCard1, botCard2);
for (int j = 0; j < nbOpponentSamples; j++) {
Set<Integer> usedOpponentCards = new TreeSet<Integer>(usedCommunityAndBotCards);
double logProb = 0;
int maxOpponentWin = 0;
drawers.clear();
for (PlayerState opponentThatCanWin : activeOpponents) {
Card opponentCard1 = new Card(drawNewCard(usedOpponentCards));
Card opponentCard2 = new Card(drawNewCard(usedOpponentCards));
int opponentRank = getFinalRank(communitySampleRank, opponentCard1, opponentCard2);
if (traceEnabled) {
logger.trace("Evaluating sampled opponent cards " + opponentCard1 + " " + opponentCard2);
}
if (opponentRank > botRank) {
maxOpponentWin = Math.max(maxOpponentWin, opponentThatCanWin.getTotalInvestment());
} else if (opponentRank == botRank) {
drawers.add(opponentThatCanWin);
}
float opponentRankProb = getRelativeNearestProbability(opponentRank, relPotSize);
logProb += Math.log(opponentRankProb);
}
double prob = Math.exp(logProb);
int won = calcAmountWon(botState, maxOpponentWin, drawers, allPlayers);
MutableDouble value = values.get(won);
if (value == null) {
values.put(won, new MutableDouble(prob));
} else {
value.add(prob);
}
totalProb += prob;
}
}
return new RolloutResult(values, totalProb, (1 - gameState.getTableConfiguration().getRake()));
}
protected float getRelativeNearestProbability(int rank, int relativePotSize) {
float prob = getRelativeProbability(rank, relPotSize);
if (prob == 0) {
prob = getRelativeNearestProbability(rank - 1, relativePotSize);
}
if (Float.isInfinite(prob) || Float.isNaN(prob) || prob == 0) {
throw new IllegalStateException("Bad opponentRankProb: " + prob);
}
return prob;
}
protected abstract float getRelativeProbability(int rank, int relativePotSize);
@Override
public String toString() {
return "Abstract Distribution Rollout";
}
public static interface Factory {
AbstractDistributionRollout create(GameState gameState, PlayerId botId);
}
}