/**
* 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.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
import java.util.TreeSet;
import org.apache.log4j.Logger;
import util.CardConverter;
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.handeval.spears2p2.StateTableEvaluator;
import com.biotools.meerkat.Card;
import com.biotools.meerkat.Hand;
public abstract class RollOutStrategy {
private final static Logger logger = Logger.getLogger(RollOutStrategy.class);
//cards
static final int[] offsets = new int[] { 0, 1277, 4137, 4995, 5853, 5863, 7140, 7296, 7452 };
static final Random random = new Random();
final static int[] handRanks;
static {
handRanks = StateTableEvaluator.getInstance().handRanks;
}
public final GameState gameState;
public final PlayerState botState;
public final PlayerId botId;
public final Set<PlayerState> allPlayers;
public final Set<PlayerState> activeOpponents;
public final int gamePotSize;
public final Card botCard1;
public final Card botCard2;
protected final Set<Integer> usedFixedCommunityAndBotCards;
public final int fixedRank;
public final int nbMissingCommunityCards;
protected final Hand usedFixedCommunityCards;
public RollOutStrategy(GameState gameState, PlayerId botId) {
this.botId = botId;
this.gameState = gameState;
this.botState = gameState.getPlayer(botId);
this.allPlayers = Collections.unmodifiableSet(gameState.getAllSeatedPlayers());
this.activeOpponents = Collections.unmodifiableSet(getActiveOpponents(allPlayers));
this.gamePotSize = gameState.getGamePotSize();
Hand botHand = botState.getCards();
this.botCard1 = botHand.getFirstCard();
this.botCard2 = botHand.getSecondCard();
this.usedFixedCommunityCards = gameState.getCommunityCards();
this.usedFixedCommunityAndBotCards = getSetOf(botCard1, botCard2, usedFixedCommunityCards);
int fixedRankBuilder = 53;
boolean traceEnabled = logger.isTraceEnabled();
for (int i = 0; i < usedFixedCommunityCards.size(); i++) {
if (traceEnabled) {
logger.trace("Evaluating fixed community card " + usedFixedCommunityCards.getCard(i + 1));
}
fixedRankBuilder = updateIntermediateRank(fixedRankBuilder, usedFixedCommunityCards.getCard(i + 1));
}
this.fixedRank = fixedRankBuilder;
this.nbMissingCommunityCards = 5 - usedFixedCommunityCards.size();
}
protected int getFinalRank(int communityRank, Card handCard1, Card handCard2) {
return extractFinalRank(updateIntermediateRank(updateIntermediateRank(communityRank, handCard1), handCard2));
}
protected int calcAmountWon(PlayerState botState, int maxOpponentWin, Set<PlayerState> drawers, Set<PlayerState> players) {
int botInvestment = botState.getTotalInvestment();
if (maxOpponentWin >= botInvestment) {
// won nothing
return 0;
} else if (drawers.isEmpty()) {
// won something, no draw
if (maxOpponentWin == 0 && !botState.isAllIn()) {
// just win everything
return gamePotSize;
} else {
// Calculate from individual contributions
int totalToDistribute = 0;
for (PlayerState player : players) {
totalToDistribute += Math.max(0, Math.min(botInvestment, player.getTotalInvestment()) - maxOpponentWin);
}
return totalToDistribute;
}
} else {
// won something but must share
int myShare = 0;
int distributed = maxOpponentWin;
int nbDrawers = drawers.size() + 1;
for (PlayerState drawer : drawers) {
int limit = Math.min(botInvestment, drawer.getTotalInvestment());
if (limit > distributed) {
int totalToDistribute = 0;
for (PlayerState player : players) {
totalToDistribute += Math.max(0, Math.min(limit, player.getTotalInvestment()) - distributed);
}
myShare += totalToDistribute / nbDrawers;
distributed = limit;
}
--nbDrawers;
}
return myShare + botInvestment - distributed;
}
}
protected static Comparator<PlayerState> playerComparatorByInvestment = new Comparator<PlayerState>() {
@Override
public int compare(PlayerState o1, PlayerState o2) {
int o1i = o1.getTotalInvestment();
int o2i = o2.getTotalInvestment();
if (o1i == o2i) {
return o1.hashCode() - o2.hashCode();
}
return o1i - o2i;
}
};
protected Integer drawNewCard(Set<Integer> usedCards) {
Integer communityCard;
do {
communityCard = getRandomCard();
} while (usedCards.contains(communityCard));
usedCards.add(communityCard);
return communityCard;
}
protected int extractFinalRank(int rank) {
int type = (rank >>> 12) - 1;
rank = rank & 0xFFF;
return offsets[type] + rank - 1;
}
protected Set<PlayerState> getActiveOpponents(Set<PlayerState> allPlayers) {
Set<PlayerState> opponentsThatCanWin = new HashSet<PlayerState>();
for (PlayerState playerState : allPlayers) {
if (!playerState.hasFolded() && !playerState.getPlayerId().equals(botId)) {
opponentsThatCanWin.add(playerState);
}
}
return opponentsThatCanWin;
}
private Integer getRandomCard() {
return Integer.valueOf(random.nextInt(52));
}
protected Set<Integer> getSetOf(Card botCard1, Card botCard2, Hand usedFixedCommunityCards) {
Set<Integer> usedFixedCommunityAndBotCards = new TreeSet<Integer>();
for (int i = 0; i < usedFixedCommunityCards.size(); i++) {
usedFixedCommunityAndBotCards.add(usedFixedCommunityCards.getCardIndex(i + 1));
}
usedFixedCommunityAndBotCards.add(botCard1.getIndex());
usedFixedCommunityAndBotCards.add(botCard2.getIndex());
return usedFixedCommunityAndBotCards;
}
protected int updateIntermediateRank(int rank, Card card) {
return handRanks[CardConverter.toSpears2p2Index(card) + rank];
}
public double getUpperWinBound() {
PlayerState botState = gameState.getPlayer(botId);
return gameState.getGamePotSize() + botState.getStack();
}
}