package 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 boolean running = true; private int nbGamesPlayed = 0; private CashGameDescription cashGameDescription; private List<BankrollObserver> bankrollObservers = new ArrayList<BankrollObserver>(); //Info needed for resuming game private GameIDGenerator gameIDGenerator; private PublicGameInfo gameInfo; private int seatpermutation; private Dealer dealer; public CashGameRunner(CashGameDescription cashGameDescription) { super(); this.cashGameDescription = cashGameDescription; } public boolean isRunning(){ return this.running; } @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; } /**Stops the simulation of the game. Only works for Asynchronous runs! * */ public synchronized void stopGame(){ running = false; notifyBankRollObserversGamePaused(); } public synchronized void terminateGame(){ notifyBankRollObserversGameTerminated(); } /**Resumes execution of the game. Only works for Asynchronous runs! * If the game is already running, nothing happens. */ public synchronized void resumeGame(){ if(running) { return; } else { running = true; Runnable gamesRunner = new Runnable() { public void run() { runGames(gameIDGenerator, gameInfo, seatpermutation, dealer); } }; (new Thread(gamesRunner, "AsyncRunGame")).start(); notifyBankRollObserversGameResumed(); } } private void runGames(GameIDGenerator gameIDGen, PublicGameInfo gameIn, int seatperm, Dealer deal) { this.gameIDGenerator = gameIDGen; this.gameInfo = gameIn; this.seatpermutation = seatperm; this.dealer = deal; for (int i = nbGamesPlayed; i < cashGameDescription.getNumGames(); i++) { if(!running) { //Stop simulation of table nbGamesPlayed = i; break; } Map<String, Double> playerBeforeBankroll = rememberPlayerBankrolls(gameInfo); gameInfo.setGameID(gameIDGenerator.getNextGameID()); dealer.playHand(); notifyBankRollObserversBankrollDelta(gameInfo, seatpermutation, playerBeforeBankroll); checkPlayerRebuy(gameInfo); dealer.moveButton(); } } /** * 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); } } private void notifyBankRollObserversGamePaused(){ for(BankrollObserver bankrollObserver : bankrollObservers){ bankrollObserver.gamePaused(); } } private void notifyBankRollObserversGameResumed(){ for(BankrollObserver bankrollObserver : bankrollObservers){ bankrollObserver.gameResumed(); } } private void notifyBankRollObserversGameTerminated(){ for(BankrollObserver bankrollObserver : bankrollObservers){ bankrollObserver.gameTerminated(); } } /** * 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; } private void checkPlayerRebuy(PublicGameInfo gameInfo) { for (int seat = 0; seat < gameInfo.getNumSeats(); seat++) { PublicPlayerInfo player = gameInfo.getPlayer(seat); if (player != null) { player.setBankroll(cashGameDescription.getInitialBankRoll()); } if (player != null && player.isSittingOut()) { player.setSittingOut(false); } } } @Override public void addBankrollObserver(BankrollObserver bankrollgraph) { this.bankrollObservers.add(bankrollgraph); } }