//public override ActionType GetAction(GameState gameState, out int amount) //{ // amount = gameState.CallAmount; // return ActionType.Call; //} // This doesn't try to calc every possible combination of turn and river cards (as too many and too slow) // Instead it looks at turn card and then calcs two chances to get this . It doesn't consider drawing two cards to improve hand as these are unlikely and unlikely to change probs much public override double EstProbWinningShowdown(GameState gameState) { int numUnseen = gameState.UnseenCards.Count; HandAndBoard myHandAndBoard = gameState.MyHandAndBoard; Card[] opponentHoleCards = new Card[2]; Dictionary <string, double> opponentHands = new Dictionary <string, double>(); Dictionary <string, Hand> myBestHandAfterDraw = new Dictionary <string, Hand>(); // Loop through all possible hands for opponent for (int i = 0; i < numUnseen; i++) { opponentHoleCards[0] = gameState.UnseenCards[i]; for (int j = i + 1; j < numUnseen; j++) { // Evaluate opponents hand opponentHoleCards[1] = gameState.UnseenCards[j]; PocketCards opponentPocketCards = new PocketCards(opponentHoleCards[0], opponentHoleCards[1]); HandAndBoard oppHandAndBoard = new HandAndBoard(); oppHandAndBoard.HoleCards = opponentPocketCards; oppHandAndBoard.Board = gameState.Board; oppHandAndBoard.Evaluate(); int[] results = new int[3]; int result; HandAndBoard lowHand, highHand; // Work out who is winning at the moment (before any card is drawn) result = myHandAndBoard.CurrentBestHand.Compare(oppHandAndBoard.CurrentBestHand); if (result < 0) { // opponent is currently winning lowHand = myHandAndBoard; highHand = oppHandAndBoard; } else { // I'm currently winning (or tie) lowHand = oppHandAndBoard; highHand = myHandAndBoard; } // Get a list of cards that could change the result (ie low hand outdraws the high hand). Still need to check this list as high hand could improve as well. List <Card> unseenList = gameState.UnseenCards.Where(p => p.ValueStr() != opponentHoleCards[0].ValueStr() && p.ValueStr() != opponentHoleCards[1].ValueStr()).ToList(); List <Card> drawCardsToCheck = GetCardsThatCouldChangeResult(unseenList, lowHand, highHand); // award wins/tie for all draw cards that don't change result results[result + 1] = unseenList.Count - drawCardsToCheck.Count; // for each possible card that could change the result check what the result would be foreach (Card draw in drawCardsToCheck) { List <Card> drawBoard = new List <Card>(gameState.Board); drawBoard.Add(draw); Hand myBestHand; string drawCardValue = draw.ValueStr(); if (myBestHandAfterDraw.ContainsKey(drawCardValue)) { myBestHand = myBestHandAfterDraw[drawCardValue]; } else { myBestHand = Hand.FindPlayersBestHand(gameState.MyCards.CardList, drawBoard); myBestHandAfterDraw.Add(drawCardValue, myBestHand); } Hand opponentBestHand = Hand.FindPlayersBestHand(opponentHoleCards, drawBoard); results[myBestHand.Compare(opponentBestHand) + 1]++; } double probBeatingOpponentHand = 0; // double probBeatingOpponentHand = (results[2] + results[1] / 2.0) / (results[0] + results[1] + results[2]); if (result < 0) { // opponent currently winning. I need to hit draw card in one of next two cards // or opponent needs to hit two cards that are not ones that win it for me // !!! is this the correct way to handle ties? double winsForOpponent = results[0] + results[1] / 2.0; double cardsRemaining = unseenList.Count; probBeatingOpponentHand = 1 - ((winsForOpponent / cardsRemaining) * ((winsForOpponent - 1) / (cardsRemaining - 1))); } else { // tie or I am currently winning. Opponent needs to hit draw card in one of next two cards // or I need to hit two cards that are not ones that win it for opponent double winsForMe = results[2] + results[1] / 2.0; double cardsRemaining = unseenList.Count; probBeatingOpponentHand = (winsForMe / cardsRemaining) * ((winsForMe - 1) / (cardsRemaining - 1)); } string opponentHandString = opponentHoleCards[0].ValueStr() + opponentHoleCards[1].ValueStr(); opponentHands.Add(opponentHandString, probBeatingOpponentHand); } } // !!! This bit is common to flop/turn/river - should not be duplicated double estimate = 1; foreach (PlayerProfile p in gameState.ActiveOpponents()) { double probBeatingThisOpponent = 0; foreach (KeyValuePair <string, double> kvp in opponentHands) { probBeatingThisOpponent += kvp.Value * p.PointsForPossibleHands.PointsForHand(kvp.Key); } probBeatingThisOpponent /= p.PointsForPossibleHands.TotalPoints; estimate *= probBeatingThisOpponent; } return(estimate); }
public double EstProbWinningShowdownFastMethod(GameState gameState) { int numUnseen = gameState.UnseenCards.Count; HandAndBoard myHandAndBoard = gameState.MyHandAndBoard; Card[] opponentHoleCards = new Card[2]; Dictionary <string, double> opponentHands = new Dictionary <string, double>(); Dictionary <string, Hand> myBestHandForRiver = new Dictionary <string, Hand>(); // Loop through all possible hands for opponent for (int i = 0; i < numUnseen; i++) { opponentHoleCards[0] = gameState.UnseenCards[i]; for (int j = i + 1; j < numUnseen; j++) { // Evaluate opponents hand opponentHoleCards[1] = gameState.UnseenCards[j]; PocketCards opponentPocketCards = new PocketCards(opponentHoleCards[0], opponentHoleCards[1]); HandAndBoard oppHandAndBoard = new HandAndBoard(); oppHandAndBoard.HoleCards = opponentPocketCards; oppHandAndBoard.Board = gameState.Board; oppHandAndBoard.Evaluate(); int[] results = new int[3]; int result; HandAndBoard lowHand, highHand; // Work out who is winning at the moment (before the river card is drawn) result = myHandAndBoard.CurrentBestHand.Compare(oppHandAndBoard.CurrentBestHand); if (result < 0) { // opponent is currently winning lowHand = myHandAndBoard; highHand = oppHandAndBoard; } else { // I'm currently winning (or tie) lowHand = oppHandAndBoard; highHand = myHandAndBoard; } // Get a list of cards that could change the result (ie low hand outdraws the high hand). Still need to check this list as high hand could improve as well. List <Card> unseenList = gameState.UnseenCards.Where(p => p.ValueStr() != opponentHoleCards[0].ValueStr() && p.ValueStr() != opponentHoleCards[1].ValueStr()).ToList(); List <Card> riverCardsToCheck = GetCardsThatCouldChangeResult(unseenList, lowHand, highHand); // award wins/tie for all river cards that don't change result results[result + 1] = unseenList.Count - riverCardsToCheck.Count; // for each possible rivercard that could change the result check what the result would be foreach (Card river in riverCardsToCheck) { List <Card> riverBoard = new List <Card>(gameState.Board); riverBoard.Add(river); Hand myBestHand; string riverCardValue = river.ValueStr(); if (myBestHandForRiver.ContainsKey(riverCardValue)) { myBestHand = myBestHandForRiver[riverCardValue]; } else { myBestHand = Hand.FindPlayersBestHand(gameState.MyCards.CardList, riverBoard); myBestHandForRiver.Add(riverCardValue, myBestHand); } Hand opponentBestHand = Hand.FindPlayersBestHand(opponentHoleCards, riverBoard); results[myBestHand.Compare(opponentBestHand) + 1]++; } double probBeatingOpponentHand = (results[2] + results[1] / 2.0) / (results[0] + results[1] + results[2]); string opponentHandString = opponentHoleCards[0].ValueStr() + opponentHoleCards[1].ValueStr(); opponentHands.Add(opponentHandString, probBeatingOpponentHand); } } // !!! This bit is common to preflop/flop/turn/river - should not be duplicated double estimate = 1; foreach (PlayerProfile p in gameState.ActiveOpponents()) { double probBeatingThisOpponent = 0; foreach (KeyValuePair <string, double> kvp in opponentHands) { probBeatingThisOpponent += kvp.Value * p.PointsForPossibleHands.PointsForHand(kvp.Key); } probBeatingThisOpponent /= p.PointsForPossibleHands.TotalPoints; estimate *= probBeatingThisOpponent; } return(estimate); }
public virtual List <Card> GetCardsThatCouldChangeResult(List <Card> unseenCards, HandAndBoard lowHand, HandAndBoard highHand) { List <Card> cards = new List <Card>(); PocketCards lowPocketCards = lowHand.HoleCards; Hand lowCurrBestHand = lowHand.CurrentBestHand; Hand highCurrBestHand = lowHand.CurrentBestHand; EHandType lowCurrHandType = lowCurrBestHand.HandRank(); EHandType highCurrHandType = highCurrBestHand.HandRank(); // if low hand has a straight draw and high hand <= straight then add cards that would give the low hand a straight if (lowHand.IsStraightDraw && highHand.CurrentBestHand.HandRank() <= EHandType.HandStraight) { foreach (ERankType rank in lowHand.RanksToMakeStraight) { cards.AddRange(unseenCards.Where(p => p.Rank == rank)); } } // if low hand has a flush draw and high hand <= flush then add cards that would give the low hand a flush if (lowHand.IsFlushDraw && highHand.CurrentBestHand.HandRank() <= EHandType.HandFlush) { cards.AddRange(unseenCards.Where(p => p.Suit == lowHand.SuitToMakeFlush)); } /* * // This should be covered by above (!!! unless high hand > flush) * // if low hand has a straight flush draw then add cards that would give the low hand a straight flush * if(lowHand.IsStraightFlushDraw) * { * foreach(Card c in lowHand.CardsToMakeStraightFlush) * { * if(unseenCards.Contains(c)) * { * cards.Add(c); * } * } * } */ // Check for drawing dead if (highCurrHandType == EHandType.HandFours && lowCurrHandType <= EHandType.HandTwoPair) { return(cards); } if (highCurrHandType == EHandType.HandFullHouse && lowCurrHandType <= EHandType.HandPair) { return(cards); } if (highCurrHandType >= EHandType.HandTwoPair && lowCurrHandType == EHandType.HandRunt) { return(cards); } // simple check - add any card of same rank as low hand pocket cards. cards.AddRange(unseenCards.Where(p => p.Rank == lowPocketCards.LowCard.Rank)); if (!lowPocketCards.IsPair) { cards.AddRange(unseenCards.Where(p => p.Rank == lowPocketCards.HighCard.Rank)); } // Also need to consider edge cases where a card pairs with board card and helps low hand but not high hand - eg high hand has flush, river card pairs with board // gives low hand (but not high hand) a full house. // Another edge case is where high hand has two pair (no pocket pair, but two cards paired with cards on board) and low hand has a pocket pair that is higher than highest of two pair // A drawn card that pairs with a board would give you a higher two pair. // Always checking all board cards is too slow! /* * foreach(Card c in lowHand.Board) * { * cards.AddRange(unseenCards.Where(p => p.Rank == c.Rank)); * } */ return(cards.Distinct().ToList()); }
public void SeeBoardCard(EBoardCardType cardType, Card boardCard) { // update unseen card list UnseenCards.Remove(boardCard); Board.Add(boardCard); foreach (PlayerProfile p in ActiveOpponents()) { p.PointsForPossibleHands.RemoveHandsContaining(boardCard); } if (cardType == EBoardCardType.BoardFlop3) { InitStage(Stage.StageFlop); } else if (cardType == EBoardCardType.BoardTurn) { InitStage(Stage.StageTurn); } else if (cardType == EBoardCardType.BoardRiver) { InitStage(Stage.StageRiver); } // !!! eliminate possibilities for opponent hands // if you are not alive then you don't have a hand if (Players[MyPlayerId].IsAlive && (cardType == EBoardCardType.BoardFlop3 || cardType == EBoardCardType.BoardTurn || cardType == EBoardCardType.BoardRiver) ) { //// !!! this probably should be in the PocketCards class //List<Card> myCards = new List<Card>(); //myCards.Add(MyCards.HighCard); //myCards.Add(MyCards.LowCard); // determine your best hand // MyBestHand = Hand.FindPlayersBestHand(MyCards.CardList, Board); // !!! move this bit to SeeBoardCard? MyHandAndBoard = new HandAndBoard(); MyHandAndBoard.HoleCards = MyCards; MyHandAndBoard.Board = Board; MyHandAndBoard.Evaluate(); // !!! determine nuts. Don't bet if your hand is far from nuts (unless bluff)? // !!! determine possible best hands for opponents (also include straight draws and flush draws) // for each possible hand ranks (that beats mine) - highest to lowest // work out which pocket cards could make these (exclude cards already used on higher ranked hands) // for each opponent // what is prob opponent hold them? // How to factor in draws to calc prob of winning showdown? // How to factor in hands of equal rank to mine? // Need to work through examples // !!! work out cards I am concerned opponent holds. // !!! work out good and bad cards for turn /river (cards that help me or cards that hurt me) // !!! calc your prob of winning showdown } }