package game.cash;
import game.*;
import game.deck.DeckFactory;
import game.stats.BankrollObserver;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import util.Utils;
import com.biotools.meerkat.GameObserver;
/**
* GameRunner running a CashGame<br>
* Runs the given count of CashGames. In this implementation 'Doyles Game' is played,
* i.e. after each game the players always start again with their initial bankroll
*/
public class CashGameRunner implements GameRunner {
private CashGameDescription cashGameDescription;
private List<BankrollObserver> bankrollObservers = new ArrayList<BankrollObserver>();
public CashGameRunner(CashGameDescription cashGameDescription) {
super();
this.cashGameDescription = cashGameDescription;
}
@Override
public void runGame(DeckFactory deckFactory, TableSeater tableSeater, GameIDGenerator gameIDGenerator, List<? extends GameObserver> gameObservers) {
PublicGameInfo gameInfos[] = tableSeater.createTables(cashGameDescription);
notifyBankRollObserversGameStarted(gameInfos[0], gameInfos.length, cashGameDescription.getNumGames());
for (int seatpermutation = 0; seatpermutation < gameInfos.length; seatpermutation++) {
PublicGameInfo gameInfo = gameInfos[seatpermutation];
for (GameObserver gameObserver : gameObservers) {
gameInfo.addGameObserver(gameObserver);
}
gameInfo.setBlinds(cashGameDescription.getSmallBlind(), cashGameDescription.getBigBlind());
gameInfo.setLimit(cashGameDescription.isNolimit() ? PublicGameInfo.NO_LIMIT : PublicGameInfo.FIXED_LIMIT);
Dealer dealer = new Dealer(deckFactory.createDeck(), gameInfo);
runGames(gameIDGenerator, gameInfo, seatpermutation, dealer);
}
}
@Override
public PublicGameInfo asyncRunGame(DeckFactory deckFactory, TableSeater tableSeater, final GameIDGenerator gameIDGenerator,
List<? extends GameObserver> gameObservers) {
PublicGameInfo gameInfos[] = tableSeater.createTables(cashGameDescription);
if (gameInfos.length != 1) {
throw new IllegalArgumentException("No permutations supported.");
}
final PublicGameInfo gameInfo = gameInfos[0];
notifyBankRollObserversGameStarted(gameInfo, gameInfos.length, cashGameDescription.getNumGames());
for (GameObserver gameObserver : gameObservers) {
gameInfo.addGameObserver(gameObserver);
}
gameInfo.setBlinds(cashGameDescription.getSmallBlind(), cashGameDescription.getBigBlind());
gameInfo.setLimit(cashGameDescription.isNolimit() ? PublicGameInfo.NO_LIMIT : PublicGameInfo.FIXED_LIMIT);
final Dealer dealer = new Dealer(deckFactory.createDeck(), gameInfo);
Runnable gamesRunner = new Runnable() {
public void run() {
runGames(gameIDGenerator, gameInfo, 0, dealer);
}
};
(new Thread(gamesRunner, "AsyncRunGame")).start();
return gameInfo;
}
private void runGames(GameIDGenerator gameIDGenerator, PublicGameInfo gameInfo, int seatpermutation, Dealer dealer) {
for (int i = 0; i < cashGameDescription.getNumGames(); i++) {
Map<String, Double> playerBeforeBankroll = rememberPlayerBankrolls(gameInfo);
gameInfo.setGameID(gameIDGenerator.getNextGameID());
dealer.playHand();
notifyBankRollObserversBankrollDelta(gameInfo, seatpermutation, playerBeforeBankroll);
cashGameDescription.getRebuyStrategy().checkPlayerRebuy(gameInfo);
if (gameIsOver(gameInfo)) {
return;
}
dealer.moveButton();
}
}
private boolean gameIsOver(PublicGameInfo gameInfo) {
int numActivePlayers = 0;
for (int seat = 0; seat < gameInfo.getNumSeats(); seat++) {
PublicPlayerInfo player = gameInfo.getPlayer(seat);
if (player != null && !player.isSittingOut()) {
numActivePlayers++;
}
}
return numActivePlayers <= 1;
}
/**
* notifies Bankroll-Observers that the game has started
*
* @param gameInfo
* @param numSeatPermutations
* @param numGames
*/
private void notifyBankRollObserversGameStarted(PublicGameInfo gameInfo, int numSeatPermutations, int numGames) {
Set<String> playerNames = new HashSet<String>();
for (int seat = 0; seat < gameInfo.getNumPlayers(); seat++) {
PublicPlayerInfo player = gameInfo.getPlayer(seat);
if (player != null) {
playerNames.add(player.getName());
}
}
for (BankrollObserver bankrollObserver : bankrollObservers) {
bankrollObserver.gameStarted(numSeatPermutations, numGames, playerNames);
}
}
/**
* calculates the delta of all bankrolls and notifies all observers
*
* @param gameInfo
* @param seatpermutation
* @param playersBeforeBankroll
*/
private void notifyBankRollObserversBankrollDelta(PublicGameInfo gameInfo, int seatpermutation, Map<String, Double> playersBeforeBankroll) {
Map<String, Double> playerBankrollDelta = new HashMap<String, Double>();
for (Map.Entry<String, Double> playerBeforeBankroll : playersBeforeBankroll.entrySet()) {
String playerName = playerBeforeBankroll.getKey();
double beforeBankroll = playerBeforeBankroll.getValue();
double bankrollNow = gameInfo.getPlayer(playerName).getBankRoll();
playerBankrollDelta.put(playerName, Utils.roundToCents(bankrollNow - beforeBankroll));
}
for (BankrollObserver bankrollObserver : bankrollObservers) {
bankrollObserver.updateBankroll(seatpermutation, playerBankrollDelta);
}
}
/**
* saves the bankrolls of all players to a map
*
* @param gameInfo
* @return
*/
private Map<String, Double> rememberPlayerBankrolls(PublicGameInfo gameInfo) {
Map<String, Double> playerToBankRoll = new HashMap<String, Double>();
for (int seat = 0; seat < gameInfo.getNumPlayers(); seat++) {
PublicPlayerInfo player = gameInfo.getPlayer(seat);
if (player != null) {
playerToBankRoll.put(player.getName(), Double.valueOf(player.getBankRoll()));
}
}
return playerToBankRoll;
}
@Override
public void addBankrollObserver(BankrollObserver bankrollgraph) {
this.bankrollObservers.add(bankrollgraph);
}
}