Ejemplo n.º 1
0
        /// <summary>
        /// Validates the AI action.
        /// Prevents raises when only calls are possible.
        /// Prevents raising more than allowed.
        /// Prevent raising less than allowed.
        /// </summary>
        /// <param name="aiAction">The AI action to be validated.</param>
        /// <returns>The validated decision.</returns>
        public static Play ValidatePlayerDecision(Play oldAiAction, databaseCache cache)
        {
            //PlayerId passed through because "cache.getCurrentActiveTablePosition()" is a slow method.
            //long playerId = cache.getPlayerId(cache.getCurrentActiveTablePosition());

            long    playerId              = oldAiAction.PlayerId;
            decimal minCallAmount         = cache.getMinimumPlayAmount();
            decimal currentRoundBetAmount = cache.getPlayerCurrentRoundBetAmount(playerId);
            decimal playerRemaningStack   = cache.getPlayerStack(playerId);

            //if (oldAiAction.PlayerId != playerId)
            //    throw new Exception("Current active table position does not correspond with bot player position.");

            //Copy the action here so that we can still see the old one for debugging reasons.
            //Once we know this is stable we can get rid of this line.
            Play aiAction = new Play(oldAiAction.Serialise());

            //We need to make sure a raise is possible
            byte[] activePositions = cache.getActivePositions();
            byte   numPlayersAllIn = (byte)cache.getAllInPositions().Length;

            //We need to ensure the bot is not calling dead, i.e. if the winPercentage is less than 5% we should not be calling after the river
            if (aiAction.Action == PokerAction.Fold)
            {
                //Check for the free check
                if (minCallAmount - currentRoundBetAmount == 0)
                {
                    aiAction.Action = PokerAction.Check;
                }
            }
            else if (aiAction.Action == PokerAction.Call)
            {
                //We must call atleast the minimum amount
                if (minCallAmount - currentRoundBetAmount > aiAction.Amount)
                {
                    aiAction.Amount = minCallAmount;
                }

                //We cannot call 0, it should be a check
                if (minCallAmount - currentRoundBetAmount == 0)
                {
                    aiAction.Action = PokerAction.Check;
                    aiAction.Amount = 0;
                }
                else if (minCallAmount - currentRoundBetAmount > playerRemaningStack)
                {
                    //We cannot call more than the stack amount
                    aiAction.Amount = playerRemaningStack;
                }

                //Never call a 0 amount!!!
                if (aiAction.Amount == 0 && aiAction.Action == PokerAction.Call)
                {
                    aiAction.Action = PokerAction.Check;
                }
            }
            else if (aiAction.Action == PokerAction.Raise)
            {
                //If the raiseToAmount is less than the minimum allowable raise then raise the minimum.
                decimal lastAdditionalRaiseAmount = cache.getCurrentRoundLastRaiseAmount();
                decimal minimumRaiseToAmount      = (minCallAmount - lastAdditionalRaiseAmount) + (lastAdditionalRaiseAmount * 2);

                if (aiAction.Amount < minimumRaiseToAmount)
                {
                    aiAction.Amount = minimumRaiseToAmount;
                }

                //if (aiAction.Amount > (cache.getCurrentHandDetails().potValue * 2))
                //    aiAction.Amount = cache.getCurrentHandDetails().potValue * 2;

                //If the raiseToAmount is more than we are able to raise then raise the maximum amount possible.
                if (aiAction.Amount > currentRoundBetAmount + playerRemaningStack)
                {
                    aiAction.Amount = currentRoundBetAmount + playerRemaningStack;
                }

                if (minCallAmount - currentRoundBetAmount >= playerRemaningStack)
                {
                    //If we are trying to raise but we cannot even meet the minimum call then call stack
                    aiAction.Action = PokerAction.Call;
                    aiAction.Amount = playerRemaningStack;
                }
                else if (numPlayersAllIn + 1 == activePositions.Length)
                {
                    //If everyone else is all in then calling is our only option
                    aiAction.Action = PokerAction.Call;
                    aiAction.Amount = minCallAmount - currentRoundBetAmount;

                    //If we already have the right amount in the pot we can only check
                    if (aiAction.Amount == 0)
                    {
                        aiAction.Action = PokerAction.Check;
                    }
                }
            }

            //If we are still trying to call a 0 amounts somthing else has gone very wrong
            if (aiAction.Amount == 0 && aiAction.Action == PokerAction.Call)
            {
                throw new Exception("Critical validation error - trying to call 0 amount.");
            }

            /*
             * if (oldAiAction.Amount != aiAction.Amount || oldAiAction.Action != aiAction.Action)
             *  throw new Exception("Validation Error");
             */

            return(aiAction);
        }
Ejemplo n.º 2
0
            public void GetRaiseCallStealAmounts(databaseCache cache, long playerId, out decimal call, out decimal steel, out double probStealSuccess, out double probCallSuccess)
            {
                var playersInHand = cache.getActivePlayerIds();

                call  = decimal.MinValue;
                steel = decimal.MinValue;
                decimal callTemp, stealTemp;
                double  stealProbTemp, callProbTemp;

                probStealSuccess = 0;
                probCallSuccess  = 0;

                HandState stage;
                var       details = cache.getCurrentHandDetails();

                if (details.tableCard1 == 0)
                {
                    stage = HandState.PreFlop;
                }
                else if (details.tableCard4 == 0)
                {
                    stage = HandState.Flop;
                }
                else if (details.tableCard5 == 0)
                {
                    stage = HandState.Turn;
                }
                else
                {
                    stage = HandState.River;
                }

                var     playerCards   = cache.getPlayerHoleCards(playerId);
                decimal minExtraRaise = (cache.getCurrentRoundLastRaiseAmount() == 0 ? cache.BigBlind : cache.getCurrentRoundLastRaiseAmount());
                decimal maxExtraRaise = cache.getPlayerStack(playerId) - cache.getMinimumPlayAmount() + cache.getPlayerCurrentRoundBetAmount(playerId);

                double numberOpponents = cache.getActivePositions().Length - cache.getAllInPositions().Length - 1;

                if (playersInHand.Length > cache.getAllInPositions().Length + 1 && maxExtraRaise > 0)
                {
                    foreach (var player in playersNew)
                    {
                        if (player.Key != playerId && playersInHand.Contains(player.Key))
                        {
                            if (cache.getAllInPositions().Contains(cache.getPlayerPosition(player.Key)))
                            {
                                continue;
                            }

                            var dd = (cache.getActivePlayerDistanceToDealer(player.Key) - 1.0) / (cache.getActivePositions().Length - 1.0);

                            player.Value.GetRaiseCallSteal(stage, (Card)playerCards.holeCard1, (Card)playerCards.holeCard2, dd < 0.5,
                                                           details.potValue, minExtraRaise, maxExtraRaise, Math.Pow(0.5, 1.0 / numberOpponents), Math.Pow(0.75, 1.0 / numberOpponents), out callTemp, out stealTemp, out stealProbTemp, out callProbTemp);

                            if (callTemp > call)
                            {
                                call            = callTemp;
                                probCallSuccess = callProbTemp;
                            }

                            if (stealTemp > steel)
                            {
                                steel            = stealTemp;
                                probStealSuccess = stealProbTemp;
                            }
                        }
                    }

                    probStealSuccess = Math.Pow(probStealSuccess, numberOpponents);
                    probCallSuccess  = Math.Pow(probCallSuccess, numberOpponents);
                }
                else
                {
                    call             = minExtraRaise;
                    steel            = minExtraRaise;
                    probStealSuccess = 0;
                    probCallSuccess  = 0;
                }

                decimal currentMinPlayAmount = cache.getMinimumPlayAmount();
                decimal minRaise             = minExtraRaise + currentMinPlayAmount;
                decimal maxRaise             = maxExtraRaise + currentMinPlayAmount;

                call  += currentMinPlayAmount;
                steel += currentMinPlayAmount;

                decimal callChange  = call * 0.2m * (decimal)(wrProv.randomGen.NextDouble() - 0.5);
                decimal stealChange = steel * 0.2m * (decimal)(wrProv.randomGen.NextDouble() - 0.5);

                if (Math.Abs(callChange) < cache.LittleBlind)
                {
                    callChange = cache.LittleBlind * callChange / Math.Abs(callChange);
                }

                if (Math.Abs(stealChange) < cache.LittleBlind)
                {
                    stealChange = cache.LittleBlind * stealChange / Math.Abs(stealChange);
                }

                call += callChange;
                call  = Math.Round(call / cache.LittleBlind, 0, MidpointRounding.AwayFromZero) * cache.LittleBlind;

                if (call < minRaise)
                {
                    call = minRaise;
                }
                if (call > maxRaise)
                {
                    call = maxRaise;
                }

                steel += stealChange;
                steel  = Math.Round(steel / cache.LittleBlind, 0, MidpointRounding.AwayFromZero) * cache.LittleBlind;

                if (steel < minRaise)
                {
                    steel = minRaise;
                }
                if (steel > maxRaise)
                {
                    steel = maxRaise;
                }
            }