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);
}
}