示例#1
0
        protected override Play GetDecision()
        {
            Dictionary <string, decimal> networkInputs = new Dictionary <string, decimal>();

            //Some values need to be moved the top because they are used in multiple places
            decimal currentRoundMinPlayCallAmount = currentDecision.Cache.getMinimumPlayAmount();
            decimal additionalCallAmount          = currentRoundMinPlayCallAmount - infoStore.GetInfoValue(InfoType.BP_PlayerBetAmountCurrentRound_Decimal);

            //Determine the minimumRaiseToAmount
            decimal lastAdditionalRaiseAmount = currentDecision.Cache.getCurrentRoundLastRaiseAmount();
            decimal minimumRaiseToAmount      = (currentRoundMinPlayCallAmount - lastAdditionalRaiseAmount) + (lastAdditionalRaiseAmount * 2);

            decimal currentPotAmount     = infoStore.GetInfoValue(InfoType.BP_TotalPotAmount_Decimal);
            decimal remainingPlayerStack = currentDecision.Cache.getPlayerStack(currentDecision.PlayerId);

            long[] activePlayerIds = currentDecision.Cache.getActivePlayerIds();

            //Current Round Actions
            List <PokerAction> currentRoundPlayerActions = (from current in currentDecision.Cache.getPlayerCurrentRoundActions(currentDecision.PlayerId)
                                                            where current == PokerAction.Check ||
                                                            current == PokerAction.Call ||
                                                            current == PokerAction.Raise
                                                            select current).ToList();

            #region RaiseAmounts
            decimal raiseToCallAmountNew, raiseToStealAmountNew;

            //If we are preflop we calculate the raise amounts in a slightly more fixed fashion
            if (currentDecision.Cache.getBettingRound() == 0)
            {
                double randomNumber = randomGen.NextDouble();

                //If the pot is unraised
                if (infoStore.GetInfoValue(InfoType.BP_MinimumPlayAmount_Decimal) == currentDecision.Cache.BigBlind)
                {
                    if (randomNumber > 0.8)
                    {
                        raiseToCallAmountNew = 4m * currentDecision.Cache.BigBlind;
                    }
                    else if (randomNumber > 0.4)
                    {
                        raiseToCallAmountNew = 3.5m * currentDecision.Cache.BigBlind;
                    }
                    else
                    {
                        raiseToCallAmountNew = 3.0m * currentDecision.Cache.BigBlind;
                    }
                }
                else
                {
                    //decimal currentRoundLastRaiseAmount = infoStore.GetInfoValue(InfoType.BP_LastAdditionalRaiseAmount);
                    decimal additionalNewRaiseAmount;

                    if (randomNumber > 0.9)
                    {
                        additionalNewRaiseAmount = 2 * lastAdditionalRaiseAmount;
                    }
                    else if (randomNumber > 0.45)
                    {
                        additionalNewRaiseAmount = 1.5m * lastAdditionalRaiseAmount;
                    }
                    else
                    {
                        additionalNewRaiseAmount = 1 * lastAdditionalRaiseAmount;
                    }

                    raiseToCallAmountNew = additionalNewRaiseAmount + infoStore.GetInfoValue(InfoType.BP_MinimumPlayAmount_Decimal);
                }

                raiseToStealAmountNew = 1.5m * raiseToCallAmountNew;

                //We will only scale the raiseToCallAmount if it is not a bigblind multiple
                if (((int)(raiseToCallAmountNew / currentDecision.Cache.BigBlind)) * currentDecision.Cache.BigBlind != raiseToCallAmountNew)
                {
                    //Round the raiseToCallAmount
                    decimal raiseToCallAmountBlindMultiple = raiseToCallAmountNew / currentDecision.Cache.LittleBlind;
                    raiseToCallAmountNew = Math.Round(raiseToCallAmountBlindMultiple, 0, MidpointRounding.AwayFromZero) * currentDecision.Cache.LittleBlind;
                }

                //Round the raiseToStealAmount
                decimal raiseToStealAmountBlindMultiple = raiseToStealAmountNew / currentDecision.Cache.LittleBlind;
                raiseToStealAmountNew = Math.Round(raiseToStealAmountBlindMultiple, 0, MidpointRounding.AwayFromZero) * currentDecision.Cache.LittleBlind;
            }
            else
            {
                raiseToCallAmountNew  = (decimal)infoStore.GetInfoValue(InfoType.WR_RaiseToCallAmount);
                raiseToStealAmountNew = (decimal)infoStore.GetInfoValue(InfoType.WR_RaiseToStealAmount);
            }

            //Some raise validation
            //Validate we can actually raise the selected amounts
            decimal maximumRaiseAmount = remainingPlayerStack + infoStore.GetInfoValue(InfoType.BP_PlayerBetAmountCurrentRound_Decimal);

            //if (raiseToCallAmount > maximumRaiseAmount) raiseToCallAmount = maximumRaiseAmount;
            //if (raiseToStealAmount > maximumRaiseAmount) raiseToStealAmount = maximumRaiseAmount;

            //Check for a big raise amount which would be best as going all in
            if (raiseToCallAmountNew > 0.8m * maximumRaiseAmount)
            {
                raiseToCallAmountNew = maximumRaiseAmount;
            }
            if (raiseToStealAmountNew > 0.8m * maximumRaiseAmount)
            {
                raiseToStealAmountNew = maximumRaiseAmount;
            }

            //If we have already raised twice this round all amounts are set to all in
            bool raisedTwiceOrGreaterCurrentRound = currentRoundPlayerActions.Count(entry => entry == PokerAction.Raise) >= 2;
            if (raisedTwiceOrGreaterCurrentRound)
            {
                raiseToCallAmountNew  = maximumRaiseAmount;
                raiseToStealAmountNew = maximumRaiseAmount;
            }
            #endregion RaiseAmounts

            /////////////////////////////////////////
            ///////////ALL NON BOOLEAN INPUTS BETWEEN 0.9 and 0.1
            /////////////////////////////////////////

            #region neuralInputs

            #region gameStage

            decimal gameStagePreFlop = 0;
            decimal gameStageFlop    = 0;
            decimal gameStageTurn    = 0;
            decimal gameStageRiver   = 0;

            decimal currentGameStage = infoStore.GetInfoValue(InfoType.GP_GameStage_Byte);

            if (currentGameStage == 0)
            {
                gameStagePreFlop = 1;
            }
            else if (currentGameStage == 1)
            {
                gameStageFlop = 1;
            }
            else if (currentGameStage == 2)
            {
                gameStageTurn = 1;
            }
            else if (currentGameStage == 3)
            {
                gameStageRiver = 1;
            }
            else
            {
                throw new Exception("What sort of game stage do you call this??");
            }

            networkInputs.Add("GameStagePreFlop", gameStagePreFlop);
            networkInputs.Add("GameStageFlop", gameStageFlop);
            networkInputs.Add("GameStageTurn", gameStageTurn);
            networkInputs.Add("GameStageRiver", gameStageRiver);

            #endregion gameStage
            //4 inputs

            #region preFlop HoleCards
            if (gameStagePreFlop == 1)
            {
                //Card info types
                networkInputs.Add("HoleCardsAAPair", infoStore.GetInfoValue(InfoType.CP_HoleCardsAAPair_Bool));
                networkInputs.Add("HoleCardsKKPair", infoStore.GetInfoValue(InfoType.CP_HoleCardsKKPair_Bool));
                networkInputs.Add("HoleCardsAKPair", infoStore.GetInfoValue(InfoType.CP_HoleCardsAK_Bool));
                networkInputs.Add("HoleCardsOtherHighPair", infoStore.GetInfoValue(InfoType.CP_HoleCardsOtherHighPair_Bool));
                networkInputs.Add("HoleCardsOtherLowPair", infoStore.GetInfoValue(InfoType.CP_HoleCardsOtherLowPair_Bool));
                networkInputs.Add("HoleCardsTroubleHand", infoStore.GetInfoValue(InfoType.CP_HoleCardsTroubleHand_Bool));
                networkInputs.Add("HoleCardsMidConnector", infoStore.GetInfoValue(InfoType.CP_HoleCardsMidConnector_Bool));
                networkInputs.Add("HoleCardsLowConnector", infoStore.GetInfoValue(InfoType.CP_HoleCardsLowConnector_Bool));
                networkInputs.Add("HoleCardsSuited", infoStore.GetInfoValue(InfoType.CP_HoleCardsSuited_Bool));
            }
            else
            {
                networkInputs.Add("HoleCardsAAPair", 0);
                networkInputs.Add("HoleCardsKKPair", 0);
                networkInputs.Add("HoleCardsAKPair", 0);
                networkInputs.Add("HoleCardsOtherHighPair", 0);
                networkInputs.Add("HoleCardsOtherLowPair", 0);
                networkInputs.Add("HoleCardsTroubleHand", 0);
                networkInputs.Add("HoleCardsMidConnector", 0);
                networkInputs.Add("HoleCardsLowConnector", 0);
                networkInputs.Add("HoleCardsSuited", 0);
            }
            #endregion
            //9 inputs

            #region playerPosition and numPlayers
            decimal dealerDistance     = ((infoStore.GetInfoValue(InfoType.GP_DealerDistance_Byte) - 1) / (infoStore.GetInfoValue(InfoType.GP_NumActivePlayers_Byte) - 1));
            decimal tablePositionEarly = 0;
            decimal tablePositionMid   = 0;
            decimal tablePositionLate  = 0;

            if (dealerDistance < (1.0m / 3.0m) && dealerDistance >= 0)
            {
                tablePositionEarly = 1;
            }
            else if (dealerDistance < (2.0m / 3.0m) && dealerDistance >= 0)
            {
                tablePositionMid = 1;
            }
            else if (dealerDistance <= 1.0m && dealerDistance >= 0)
            {
                tablePositionLate = 1;
            }
            else
            {
                throw new Exception("Dealer distance must be between 0 and 1.");
            }

            networkInputs.Add("TablePositionEarly", tablePositionEarly);
            networkInputs.Add("TablePositionMid", tablePositionMid);
            networkInputs.Add("TablePositionLate", tablePositionLate);

            networkInputs.Add("NumActivePlayers4Plus", (infoStore.GetInfoValue(InfoType.GP_NumActivePlayers_Byte) >= 4 ? 1 : 0));
            networkInputs.Add("NumActivePlayers3", (infoStore.GetInfoValue(InfoType.GP_NumActivePlayers_Byte) == 3 ? 1 : 0));
            networkInputs.Add("NumActivePlayers2", (infoStore.GetInfoValue(InfoType.GP_NumActivePlayers_Byte) == 2 ? 1 : 0));

            networkInputs.Add("LastToAct", (infoStore.GetInfoValue(InfoType.GP_NumUnactedPlayers_Byte) == 1 ? 1 : 0));
            #endregion playerPosition and numPlayers
            //7 inputs

            #region potCommitment and liability
            decimal potCommitted = 0;
            if (infoStore.GetInfoValue(InfoType.BP_PlayerMoneyInPot_Decimal) > infoStore.GetInfoValue(InfoType.BP_PlayerHandStartingStackAmount_Decimal) * 0.75m)
            {
                potCommitted = 1;
            }

            networkInputs.Add("PotCommitted", potCommitted);

            //The maximum liability in our current hand, i.e.
            decimal   maximumLiability = 0;
            decimal[] allPlayerStacks  = new decimal[activePlayerIds.Length];

            //Determine if anyone has a larger stack than us
            bool stackLargerThanOurs = false;
            for (int i = 0; i < activePlayerIds.Length; i++)
            {
                allPlayerStacks[i] = currentDecision.Cache.getPlayerStack(activePlayerIds[i]);

                if (activePlayerIds[i] != currentDecision.PlayerId && allPlayerStacks[i] > remainingPlayerStack)
                {
                    stackLargerThanOurs = true;
                    break;
                }
            }

            if (!stackLargerThanOurs)
            {
                //Find the nearest largest stack
                decimal nearestLargestStack = 0;
                for (int i = 0; i < activePlayerIds.Length; i++)
                {
                    if (activePlayerIds[i] != currentDecision.PlayerId && allPlayerStacks[i] > nearestLargestStack)
                    {
                        nearestLargestStack = allPlayerStacks[i];
                    }
                }

                maximumLiability = ScaleContInput(nearestLargestStack / currentDecision.Cache.MaxStack);
            }
            else
            {
                maximumLiability = ScaleContInput(remainingPlayerStack / currentDecision.Cache.MaxStack);
            }

            networkInputs.Add("MaximumLiability", maximumLiability);
            #endregion
            //2 inputs

            #region Hand and Action History
            List <PokerAction> allPlayerActionsCurrentHand = currentDecision.Cache.getPlayerActionsCurrentHand(currentDecision.PlayerId);
            decimal            callCount  = (decimal)allPlayerActionsCurrentHand.Count(entry => entry == PokerAction.Call);
            decimal            checkCount = (decimal)allPlayerActionsCurrentHand.Count(entry => entry == PokerAction.Check);
            decimal            raiseCount = (decimal)allPlayerActionsCurrentHand.Count(entry => entry == PokerAction.Raise);

            decimal currentHandOurAggression = 0;

            currentHandOurAggression = raiseCount - (callCount + checkCount);
            if (currentHandOurAggression < -6)
            {
                currentHandOurAggression = -6;
            }
            else if (currentHandOurAggression > 6)
            {
                currentHandOurAggression = 6;
            }

            networkInputs.Add("CurrentHandOurAggression", currentHandOurAggression / 6.0m);

            networkInputs.Add("CurrentRoundFirstAction", (currentRoundPlayerActions.Count == 0 ? 1 : 0));
            networkInputs.Add("CurrentRoundSecondAction", (currentRoundPlayerActions.Count == 1 ? 1 : 0));
            networkInputs.Add("CurrentRoundThirdPlusAction", (currentRoundPlayerActions.Count >= 2 ? 1 : 0));
            #endregion Hand and Round Actions
            //4 inputs

            #region WinRatio
            decimal probWin = 1.0m - infoStore.GetInfoValue(InfoType.WR_ProbOpponentHasBetterWRFIXED);
            networkInputs.Add("WRProbWin", ScaleContInput(probWin));
            #endregion
            //1 inputs

            #region EV, RaiseAmounts and CheckPossibilitiy

            decimal bigBlindEVScaleAmount = 20;

            #region CallEV
            //The following EV assumes we can actually call the additionaCallAmount
            //We could cap the additionalCallAmount but we would then also not be able to win the total pot amount ;( again a minor error
            decimal actualCallCheckEV = (currentPotAmount * probWin) - ((1.0m - probWin) * additionalCallAmount);
            decimal scaledCallCheckEV = (actualCallCheckEV / currentDecision.Cache.BigBlind) / bigBlindEVScaleAmount;
            if (scaledCallCheckEV > 1)
            {
                networkInputs.Add("ScaledCallCheckEV", 1);
            }
            else if (scaledCallCheckEV < -1)
            {
                networkInputs.Add("ScaledCallCheckEV", -1);
            }
            else
            {
                networkInputs.Add("ScaledCallCheckEV", scaledCallCheckEV);
            }
            #endregion

            //Current scaled raise amounts
            //Aditional = MaximumRaiseTo - CurrentCallAmount
            decimal maximumAdditionalRaiseAmount = (infoStore.GetInfoValue(InfoType.BP_PlayerBetAmountCurrentRound_Decimal) + remainingPlayerStack) - (currentRoundMinPlayCallAmount);
            bool    raisePossible = false;

            if (maximumAdditionalRaiseAmount > 0)
            {
                raisePossible = true;
                if (lastAdditionalRaiseAmount > maximumAdditionalRaiseAmount)
                {
                    lastAdditionalRaiseAmount = maximumAdditionalRaiseAmount;
                }

                decimal additionalRaiseToCallAmount  = raiseToCallAmountNew - currentRoundMinPlayCallAmount;  // -infoStore.GetInfoValue(InfoType.BP_PlayerBetAmountCurrentRound_Decimal);
                decimal additionalRaiseToStealAmount = raiseToStealAmountNew - currentRoundMinPlayCallAmount; // -infoStore.GetInfoValue(InfoType.BP_PlayerBetAmountCurrentRound_Decimal);

                if (additionalRaiseToCallAmount > maximumAdditionalRaiseAmount)
                {
                    additionalRaiseToCallAmount = maximumAdditionalRaiseAmount;
                }
                else if (additionalRaiseToCallAmount < currentDecision.Cache.BigBlind)
                {
                    additionalRaiseToCallAmount = currentDecision.Cache.BigBlind;
                }

                if (additionalRaiseToStealAmount > maximumAdditionalRaiseAmount)
                {
                    additionalRaiseToStealAmount = maximumAdditionalRaiseAmount;
                }
                else if (additionalRaiseToStealAmount < currentDecision.Cache.BigBlind)
                {
                    additionalRaiseToStealAmount = currentDecision.Cache.BigBlind;
                }

                networkInputs.Add("ScaledAdditionalRaiseToCallAmount", ScaleContInput((decimal)RaiseAmountsHelper.ScaleAdditionalRaiseAmount(currentPotAmount, currentDecision.Cache.BigBlind, lastAdditionalRaiseAmount, maximumAdditionalRaiseAmount, additionalRaiseToCallAmount)));
                networkInputs.Add("ScaledAdditionalRaiseToStealAmount", ScaleContInput((decimal)RaiseAmountsHelper.ScaleAdditionalRaiseAmount(currentPotAmount, currentDecision.Cache.BigBlind, lastAdditionalRaiseAmount, maximumAdditionalRaiseAmount, additionalRaiseToStealAmount)));
            }
            else
            {
                //No raise possible, just use defaults
                networkInputs.Add("ScaledAdditionalRaiseToCallAmount", ScaleContInput(0));
                networkInputs.Add("ScaledAdditionalRaiseToStealAmount", ScaleContInput(0));
            }

            decimal probAllOpponentFoldRaiseToCall  = infoStore.GetInfoValue(InfoType.WR_RaiseToCallStealSuccessProb);
            decimal probAllOpponentFoldRaiseToSteal = (gameStagePreFlop == 1 ? 0 : infoStore.GetInfoValue(InfoType.WR_RaiseToStealSuccessProb));

            #region RaiseToCallEV
            if (raisePossible)
            {
                decimal potAmountAssumingAllCall = currentPotAmount;

                //If we are preflop then it would be unrealistic to expect everyone to call
                //For Call we assume that if there are 8 players to act after the raise we get 2 calls
                //If there are 4 players to act after the raise we get 1 call
                //This is the same as dividing the number of activePlayers by 4
                if (gameStagePreFlop == 1)
                {
                    //We assume anyone who has already called or raised will call again
                    long[] calledRaisedPlayerIds = (from current in currentDecision.Cache.getAllHandActions()
                                                    where current.actionType == PokerAction.Call || current.actionType == PokerAction.Raise
                                                    where current.playerId != currentDecision.PlayerId
                                                    select current.playerId).ToArray();

                    for (int i = 0; i < calledRaisedPlayerIds.Length; i++)
                    {
                        potAmountAssumingAllCall += raiseToCallAmountNew - currentDecision.Cache.getPlayerCurrentRoundBetAmount(calledRaisedPlayerIds[i]);
                    }

                    potAmountAssumingAllCall += ((decimal)(activePlayerIds.Length - 1 - calledRaisedPlayerIds.Length) / 4) * raiseToCallAmountNew;
                }
                else
                {
                    for (int i = 0; i < activePlayerIds.Length; i++)
                    {
                        if (activePlayerIds[i] != currentDecision.PlayerId)
                        {
                            potAmountAssumingAllCall += raiseToCallAmountNew - currentDecision.Cache.getPlayerCurrentRoundBetAmount(activePlayerIds[i]);
                        }
                    }
                }

                decimal extraDollarRiskAmount = raiseToCallAmountNew - infoStore.GetInfoValue(InfoType.BP_PlayerBetAmountCurrentRound_Decimal);

                decimal actualRaiseToCallEV = (currentPotAmount * probAllOpponentFoldRaiseToCall) + (probWin * potAmountAssumingAllCall * (1.0m - probAllOpponentFoldRaiseToCall)) - ((1.0m - probWin) * extraDollarRiskAmount * (1.0m - probAllOpponentFoldRaiseToCall));

                decimal scaledRaiseToCallEV = (actualRaiseToCallEV / currentDecision.Cache.BigBlind) / bigBlindEVScaleAmount;
                if (scaledRaiseToCallEV > 1)
                {
                    networkInputs.Add("ScaledRaiseToCallEV", 1);
                }
                else if (scaledRaiseToCallEV < -1)
                {
                    networkInputs.Add("ScaledRaiseToCallEV", -1);
                }
                else
                {
                    networkInputs.Add("ScaledRaiseToCallEV", scaledRaiseToCallEV);
                }
            }
            else
            {
                networkInputs.Add("ScaledRaiseToCallEV", networkInputs["ScaledCallCheckEV"]);
            }
            #endregion

            #region RaiseToStealEV
            if (raisePossible)
            {
                decimal potAmountAssumingAllCall = currentPotAmount;

                //If we are preflop then it would be unrealistic to expect everyone to call
                //For steal we assume that if there are 8 players to act after the raise we get 1 call
                //If there are 4 players to act after the raise we get 0.5 call
                //This is the same as dividing the number of activePlayers by 8
                if (gameStagePreFlop == 1)
                {
                    //We assume anyone who has already raised will call again
                    long[] raisedPlayerIds = (from current in currentDecision.Cache.getAllHandActions()
                                              where current.actionType == PokerAction.Raise
                                              where current.playerId != currentDecision.PlayerId
                                              select current.playerId).ToArray();

                    for (int i = 0; i < raisedPlayerIds.Length; i++)
                    {
                        potAmountAssumingAllCall += raiseToStealAmountNew - currentDecision.Cache.getPlayerCurrentRoundBetAmount(raisedPlayerIds[i]);
                    }

                    potAmountAssumingAllCall += ((decimal)(activePlayerIds.Length - 1 - raisedPlayerIds.Length) / 8) * raiseToStealAmountNew;
                }
                else
                {
                    for (int i = 0; i < activePlayerIds.Length; i++)
                    {
                        if (activePlayerIds[i] != currentDecision.PlayerId)
                        {
                            potAmountAssumingAllCall += raiseToStealAmountNew - currentDecision.Cache.getPlayerCurrentRoundBetAmount(activePlayerIds[i]);
                        }
                    }
                }

                decimal extraDollarRiskAmount = raiseToStealAmountNew - infoStore.GetInfoValue(InfoType.BP_PlayerBetAmountCurrentRound_Decimal);

                decimal actualRaiseToStealEV = (currentPotAmount * probAllOpponentFoldRaiseToSteal) + (probWin * potAmountAssumingAllCall * (1.0m - probAllOpponentFoldRaiseToSteal)) - ((1.0m - probWin) * extraDollarRiskAmount * (1.0m - probAllOpponentFoldRaiseToSteal));
                decimal scaledRaiseToStealEV = (actualRaiseToStealEV / currentDecision.Cache.BigBlind) / bigBlindEVScaleAmount;
                if (scaledRaiseToStealEV > 1)
                {
                    networkInputs.Add("ScaledRaiseToStealEV", 1);
                }
                else if (scaledRaiseToStealEV < -1)
                {
                    networkInputs.Add("ScaledRaiseToStealEV", -1);
                }
                else
                {
                    networkInputs.Add("ScaledRaiseToStealEV", scaledRaiseToStealEV);
                }
            }
            else
            {
                networkInputs.Add("ScaledRaiseToStealEV", networkInputs["ScaledCallCheckEV"]);
            }
            #endregion

            bool checkPossible = (infoStore.GetInfoValue(InfoType.BP_MinimumPlayAmount_Decimal) == infoStore.GetInfoValue(InfoType.BP_PlayerBetAmountCurrentRound_Decimal));
            networkInputs.Add("CheckPossible", Convert.ToDecimal(checkPossible));

            networkInputs.Add("CallAmount1BBOrLess", !checkPossible && ((decimal)infoStore.GetInfoValue(InfoType.BP_MinimumPlayAmount_Decimal) - (decimal)infoStore.GetInfoValue(InfoType.BP_PlayerBetAmountCurrentRound_Decimal)) <= currentDecision.Cache.BigBlind ? 1 : 0);
            #endregion
            //7 inputs

            #region PAP
            networkInputs.Add("ProbRaiseToStealSuccess", ScaleContInput(probAllOpponentFoldRaiseToSteal));
            #endregion
            //1 inputs

            #region PlayerAggression
            networkInputs.Add("AvgLiveOppPreFlopPlayFreq", ScaleContInput(infoStore.GetInfoValue(InfoType.AP_AvgLiveOppPreFlopPlayFreq_Double)));
            networkInputs.Add("AvgLiveOppPostFlopPlayFreq", ScaleContInput(infoStore.GetInfoValue(InfoType.AP_AvgLiveOppPostFlopPlayFreq_Double)));
            networkInputs.Add("AvgLiveOppCurrentRoundAggr", ScaleContInput(infoStore.GetInfoValue(InfoType.AP_AvgLiveOppCurrentRoundAggr_Double)));
            networkInputs.Add("AvgLiveOppCurrentRoundAggrAcc", ScaleContInput(infoStore.GetInfoValue(InfoType.AP_AvgLiveOppCurrentRoundAggrAcc_Double)));
            #endregion
            //4 inputs

            #region BigOrSmallPot
            byte isBigPot = 0;
            if (currentPotAmount > RaiseAmountsHelper.SmallPotBBMultiplierLimit * currentDecision.Cache.BigBlind)
            {
                isBigPot = 1;
            }
            networkInputs.Add("BigPot", ScaleContInput(isBigPot));
            #endregion
            //1 input

            #region RandomInputs
            //We have 2 random inputs with different periods, per hand and per decision

            //Check the randomNumbers are not -1
            if (currentDecision.Cache.CurrentHandRandomNumber() < 0)
            {
                throw new Exception("currentDecision.Cache.CurrentHandRandomNumber() should not be less than 0");
            }

            //We disable these random numbers for the ailwyn blank network
            if (currentDecision.Cache.PokerClientId == (short)PokerClients.GeneticPokerPlayer_PlaySimpleAI_1a_FixedStart || currentDecision.Cache.PokerClientId == (short)PokerClients.GeneticPokerPlayer_PlayerSimpleAI_1b_RandomInitialisation || currentDecision.Cache.PokerClientId == (short)PokerClients.GeneticPokerPlay_PlaySimpleAI_2a || (currentDecision.AiConfigStr.StartsWith("F") && currentDecision.AiConfigStr == "FixedNeuralPlayers\\neuralV7_Ailwyn_NoRandomInput.eNN"))
            {
                networkInputs.Add("HandRandomNumber", 0);
                networkInputs.Add("DecisionRandomNumber", 0);
            }
            else
            {
                networkInputs.Add("HandRandomNumber", ScaleContInput((decimal)currentDecision.Cache.CurrentHandRandomNumber() / (decimal)int.MaxValue));
                networkInputs.Add("DecisionRandomNumber", ScaleContInput((decimal)randomGen.NextDouble()));
            }
            #endregion
            //2 inputs

            #endregion neuralInputs

            NNDataSource aiDecisionData = new NNDataSource(networkInputs.Values.ToArray(), NeuralAINNModelV7.Input_Neurons, true);

            if (true)
            {
                //Get the network outputs
                double[] networkInputsArray = null;
                aiDecisionData.returnInput(ref networkInputsArray);
                double[] networkOutput = getPlayerNetworkPrediction(currentDecision.AiConfigStr, networkInputsArray);

                //Blank the non possible actions
                if (checkPossible)
                {
                    //Blank fold
                    networkOutput[0] = 0;
                    //Blank call
                    networkOutput[2] = 0;
                }
                else
                {
                    //Blank check
                    networkOutput[1] = 0;
                }

                //Get the bot decision
                NeuralAiDecisionNeuralv7 decision = new NeuralAiDecisionNeuralv7(networkOutput, !Convert.ToBoolean(gameStageRiver), randomGen.NextDouble());

                Debug.Print("Decision");

                //Can now check the fold decision for aces
                //if (decision.BotAction == 0 && networkInputs["HoleCardsAAPair"] == 1 && gameStagePreFlop == 1 && currentDecision.AiConfigStr.StartsWith("GeneticPokerPlayers"))
                //{
                //    currentDecision.Cache.SaveToDisk("", currentDecision.PlayerId + "-" + InfoProviderBase.CurrentJob.JobId + "-" + currentDecision.Cache.getCurrentHandId() + "-" + currentDecision.Cache.getMostRecentLocalIndex()[1]);
                //}

                if (decision.BotAction == 0)
                {
                    return(new Play(PokerAction.Fold, 0, 0, currentDecision.Cache.getCurrentHandId(), currentDecision.PlayerId, decisionLogStr, 0));
                }
                else if (decision.BotAction == 1)
                {
                    return(new Play(PokerAction.Check, 0, 0, currentDecision.Cache.getCurrentHandId(), currentDecision.PlayerId, decisionLogStr, 0));
                }
                else if (decision.BotAction == 2)
                {
                    return(new Play(PokerAction.Call, additionalCallAmount, 0, currentDecision.Cache.getCurrentHandId(), currentDecision.PlayerId, decisionLogStr, 0));
                }
                else if (decision.BotAction == 3)
                {
                    bool isSmallPot = currentPotAmount < RaiseAmountsHelper.SmallPotBBMultiplierLimit * currentDecision.Cache.BigBlind * ((decimal)(randomGen.NextDouble() * 0.2) + 0.80m);

                    //////////////////////////////////////////////////////////
                    ///////////////// START VANAHEIM FIX /////////////////////
                    //////////////////////////////////////////////////////////

                    //We add a temporary fix here for vanaheim which is playing mid pocket pairs a little strongly
                    //If we have pocket pair lower than (not including KK) have already raised and are trying to raise again we fold
                    //if (currentDecision.AiConfigStr.StartsWith("F") && !isSmallPot && gameStagePreFlop == 1 && currentDecision.AiConfigStr == "FixedNeuralPlayers\\neuralV7_Vanaheim.eNN")
                    //{
                    //    bool highPair = infoStore.GetInfoValue(InfoType.CP_HoleCardsOtherHighPair_Bool) == 1.0m;
                    //    bool midPair = infoStore.GetInfoValue(InfoType.CP_HoleCardsOtherLowPair_Bool) == 1.0m;
                    //    if (highPair || midPair)
                    //    {
                    //        if (currentRoundPlayerActions.Count(entry => entry == PokerAction.Raise) >= 1)
                    //        {
                    //            if (actualCallCheckEV > 0 && (tablePositionLate == 1 || tablePositionMid == 1) && currentRoundPlayerActions.Count(entry => entry == PokerAction.Call) == 0)
                    //                return new Play(PokerAction.Call, additionalCallAmount, 0, currentDecision.Cache.getCurrentHandId(), currentDecision.PlayerId, decisionLogStr, 0);
                    //            else
                    //                return new Play(PokerAction.Fold, 0, 0, currentDecision.Cache.getCurrentHandId(), currentDecision.PlayerId, decisionLogStr, 0);
                    //        }
                    //    }
                    //}

                    ////////////////////////////////////////////////////////////////////
                    /////////////////// END VANAHEIM FIX /////////////////////
                    ////////////////////////////////////////////////////////////////////

                    //Make sure raiseAmount is multiple of small blind
                    if (raisePossible)
                    {
                        decimal raiseToAmount, raiseAmountBlindMultiple;
                        /////////////////////
                        //GENETIC OR VANAHEIM 2 PLAYER FIX
                        ////////////////////
                        if (raisedTwiceOrGreaterCurrentRound && gameStagePreFlop == 1 && (currentDecision.AiConfigStr.StartsWith("G") || currentDecision.AiConfigStr == "FixedNeuralPlayers\\neuralV7_Vanaheim.eNN"))
                        {
                            //Genetic players will now go all in on their third raise preflop
                            raiseToAmount = maximumRaiseAmount;
                        }
                        else
                        {
                            decimal additionalRaiseAmount = RaiseAmountsHelper.UnscaleAdditionalRaiseAmount(currentPotAmount, currentDecision.Cache.BigBlind, lastAdditionalRaiseAmount, maximumAdditionalRaiseAmount, decision.ScaledAdditionalRaiseAmount);

                            //If the pot is currently small we raise in increments of big blind instead of little blind
                            //We add a little randomness into this limit so that it's not always exact, random number is between 0.8 and 1.0
                            if (isSmallPot)
                            {
                                ///////////////////////////////////////
                                ///// START VANAHEIM FIX //////////////
                                ///////////////////////////////////////
                                //If we are preflop with a small pot playing as vanaheim
                                //And we do not have AA or KK we can only raise to a set maximum
                                //if (currentDecision.AiConfigStr.StartsWith("F") && gameStagePreFlop == 1 && currentDecision.AiConfigStr == "FixedNeuralPlayers\\neuralV7_Vanaheim.eNN")
                                //{
                                //    bool AAPair = infoStore.GetInfoValue(InfoType.CP_HoleCardsAAPair_Bool) == 1.0m;
                                //    bool KKPair = infoStore.GetInfoValue(InfoType.CP_HoleCardsKKPair_Bool) == 1.0m;

                                //    decimal maxDesiredRaise = RaiseAmountsHelper.SmallPotBBMultiplierLimit * currentDecision.Cache.BigBlind;
                                //    if (!(AAPair || KKPair) && additionalRaiseAmount > maxDesiredRaise)
                                //        additionalRaiseAmount = maxDesiredRaise;
                                //}
                                ///////////////////////////////////////
                                ///// START VANAHEIM FIX //////////////
                                ///////////////////////////////////////

                                raiseAmountBlindMultiple = (currentRoundMinPlayCallAmount + additionalRaiseAmount) / currentDecision.Cache.BigBlind;
                                raiseToAmount            = Math.Round(raiseAmountBlindMultiple, 0, MidpointRounding.AwayFromZero) * currentDecision.Cache.BigBlind;
                            }
                            else
                            {
                                raiseAmountBlindMultiple = (currentRoundMinPlayCallAmount + additionalRaiseAmount) / currentDecision.Cache.LittleBlind;
                                raiseToAmount            = Math.Round(raiseAmountBlindMultiple, 0, MidpointRounding.AwayFromZero) * currentDecision.Cache.LittleBlind;
                            }

                            //If we are going to raise almost maximum then it might as well be max
                            if (raiseToAmount > maximumRaiseAmount * 0.9m)
                            {
                                raiseToAmount = maximumRaiseAmount;
                            }
                        }

                        return(new Play(PokerAction.Raise, raiseToAmount, 0, currentDecision.Cache.getCurrentHandId(), currentDecision.PlayerId, decisionLogStr, 0));
                    }
                    else
                    {
                        return(new Play(PokerAction.Call, additionalCallAmount, 0, currentDecision.Cache.getCurrentHandId(), currentDecision.PlayerId, decisionLogStr, 0));
                    }
                }
                else
                {
                    throw new Exception("Something has gone wery wong!");
                }
            }

            decisionLogStr = aiDecisionData.ToStringAdv(true);
            return(new Play(PokerAction.Fold, 0, 0, currentDecision.Cache.getCurrentHandId(), currentDecision.PlayerId, decisionLogStr, 0));
        }
示例#2
0
        protected override Play GetDecision()
        {
            //If we are on the river then probWin can be 1 or 0
            decimal probWin             = 1.0m - infoStore.GetInfoValue(InfoType.WR_ProbOpponentHasBetterWRFIXED);
            bool    topHand             = false;
            byte    currentBettingRound = currentDecision.Cache.getBettingRound();

            //Some values need to be moved the top because they are used in multiple places
            decimal currentRoundMinPlayCallAmount = infoStore.GetInfoValue(InfoType.BP_MinimumPlayAmount_Decimal);
            decimal additionalCallAmount          = currentRoundMinPlayCallAmount - infoStore.GetInfoValue(InfoType.BP_PlayerBetAmountCurrentRound_Decimal);
            decimal currentPotAmount     = infoStore.GetInfoValue(InfoType.BP_TotalPotAmount_Decimal);
            decimal remainingPlayerStack = currentDecision.Cache.getPlayerStack(currentDecision.PlayerId);

            long[] activePlayerIds = currentDecision.Cache.getActivePlayerIds();

            var ourCards = currentDecision.Cache.getPlayerHoleCards(currentDecision.PlayerId);

            int decision = 0;

            //Current Round Actions
            List <PokerAction> currentRoundPlayerActions = (from current in currentDecision.Cache.getPlayerCurrentRoundActions(currentDecision.PlayerId)
                                                            where current == PokerAction.Check ||
                                                            current == PokerAction.Call ||
                                                            current == PokerAction.Raise
                                                            select current).ToList();

            PokerAction playerLastActionCurrentRound = PokerAction.NoAction;

            if (currentRoundPlayerActions.Count > 0)
            {
                playerLastActionCurrentRound = currentRoundPlayerActions.Last();
            }

            #region RaiseAmounts
            decimal raiseToCallAmountNew, raiseToStealAmountNew;

            decimal maximumRaiseToAmount      = remainingPlayerStack + (decimal)infoStore.GetInfoValue(InfoType.BP_PlayerBetAmountCurrentRound_Decimal);
            decimal lastAdditionalRaiseAmount = currentDecision.Cache.getCurrentRoundLastRaiseAmount();
            if (lastAdditionalRaiseAmount > remainingPlayerStack)
            {
                lastAdditionalRaiseAmount = remainingPlayerStack;
            }

            bool littlePot = (currentPotAmount < RaiseAmountsHelper.SmallPotBBMultiplierLimit * currentDecision.Cache.BigBlind * ((decimal)(randomGen.NextDouble() * 0.2) + 0.80m));

            double randomNumber1            = randomGen.NextDouble();
            double randomNumber2            = randomGen.NextDouble();
            double raiseToCallRandomNumber  = Math.Min(randomNumber1, randomNumber2);
            double raiseToStealRandomNumber = Math.Max(randomNumber1, randomNumber2);

            int raiseToCallIndex = -1, raiseToStealIndex = -1;

            //If we have already raised twice this round all amounts are set to all in
            if (currentRoundPlayerActions.Count(entry => entry == PokerAction.Raise) >= 2)
            {
                raiseToCallAmountNew  = maximumRaiseToAmount;
                raiseToStealAmountNew = maximumRaiseToAmount;
            }
            else
            {
                #region Select RaiseIndex
                if (currentBettingRound == 0)
                {
                    for (byte raiseIndex = 0; raiseIndex < 10; raiseIndex += 1)
                    {
                        if (raiseToCallIndex < 0 && raiseToCallRandomNumber < RaiseAmountsHelper.PreFlopRaiseBinIdealCDF[raiseIndex])
                        {
                            raiseToCallIndex = raiseIndex;
                        }
                        if (raiseToStealRandomNumber < RaiseAmountsHelper.PreFlopRaiseBinIdealCDF[raiseIndex])
                        {
                            raiseToStealIndex = raiseIndex;
                            break;
                        }
                    }
                }
                else if (currentBettingRound == 1)
                {
                    if (littlePot)
                    {
                        for (byte raiseIndex = 0; raiseIndex < 10; raiseIndex += 1)
                        {
                            if (raiseToCallIndex < 0 && raiseToCallRandomNumber < RaiseAmountsHelper.FlopRaiseBinIdealSmallCDF[raiseIndex])
                            {
                                raiseToCallIndex = raiseIndex;
                            }
                            if (raiseToStealRandomNumber < RaiseAmountsHelper.FlopRaiseBinIdealSmallCDF[raiseIndex])
                            {
                                raiseToStealIndex = raiseIndex;
                                break;
                            }
                        }
                    }
                    else
                    {
                        for (byte raiseIndex = 0; raiseIndex < 10; raiseIndex += 1)
                        {
                            if (raiseToCallIndex < 0 && raiseToCallRandomNumber < RaiseAmountsHelper.FlopRaiseBinIdealBigCDF[raiseIndex])
                            {
                                raiseToCallIndex = raiseIndex;
                            }
                            if (raiseToStealRandomNumber < RaiseAmountsHelper.FlopRaiseBinIdealBigCDF[raiseIndex])
                            {
                                raiseToStealIndex = raiseIndex;
                                break;
                            }
                        }
                    }
                }
                else if (currentBettingRound == 2)
                {
                    if (littlePot)
                    {
                        for (byte raiseIndex = 0; raiseIndex < 10; raiseIndex += 1)
                        {
                            if (raiseToCallIndex < 0 && raiseToCallRandomNumber < RaiseAmountsHelper.TurnRaiseBinIdealSmallCDF[raiseIndex])
                            {
                                raiseToCallIndex = raiseIndex;
                            }
                            if (raiseToStealRandomNumber < RaiseAmountsHelper.TurnRaiseBinIdealSmallCDF[raiseIndex])
                            {
                                raiseToStealIndex = raiseIndex;
                                break;
                            }
                        }
                    }
                    else
                    {
                        for (byte raiseIndex = 0; raiseIndex < 10; raiseIndex += 1)
                        {
                            if (raiseToCallIndex < 0 && raiseToCallRandomNumber < RaiseAmountsHelper.TurnRaiseBinIdealBigCDF[raiseIndex])
                            {
                                raiseToCallIndex = raiseIndex;
                            }
                            if (raiseToStealRandomNumber < RaiseAmountsHelper.TurnRaiseBinIdealBigCDF[raiseIndex])
                            {
                                raiseToStealIndex = raiseIndex;
                                break;
                            }
                        }
                    }
                }
                else if (currentBettingRound == 3)
                {
                    if (littlePot)
                    {
                        for (byte raiseIndex = 0; raiseIndex < 10; raiseIndex += 1)
                        {
                            if (raiseToCallIndex < 0 && raiseToCallRandomNumber < RaiseAmountsHelper.RiverRaiseBinIdealSmallCDF[raiseIndex])
                            {
                                raiseToCallIndex = raiseIndex;
                            }
                            if (raiseToStealRandomNumber < RaiseAmountsHelper.RiverRaiseBinIdealSmallCDF[raiseIndex])
                            {
                                raiseToStealIndex = raiseIndex;
                                break;
                            }
                        }
                    }
                    else
                    {
                        for (byte raiseIndex = 0; raiseIndex < 10; raiseIndex += 1)
                        {
                            if (raiseToCallIndex < 0 && raiseToCallRandomNumber < RaiseAmountsHelper.RiverRaiseBinIdealBigCDF[raiseIndex])
                            {
                                raiseToCallIndex = raiseIndex;
                            }
                            if (raiseToStealRandomNumber < RaiseAmountsHelper.RiverRaiseBinIdealBigCDF[raiseIndex])
                            {
                                raiseToStealIndex = raiseIndex;
                                break;
                            }
                        }
                    }
                }
                else
                {
                    throw new Exception("Impossible!");
                }
                #endregion

                decimal additionalRaiseToCallAmountNew  = RaiseAmountsHelper.UnscaleAdditionalRaiseAmount(currentPotAmount, currentDecision.Cache.BigBlind, lastAdditionalRaiseAmount, remainingPlayerStack, raiseToCallIndex / 10.0 + 0.05);
                decimal additionalRaiseToStealAmountNew = RaiseAmountsHelper.UnscaleAdditionalRaiseAmount(currentPotAmount, currentDecision.Cache.BigBlind, lastAdditionalRaiseAmount, remainingPlayerStack, raiseToStealIndex / 10.0 + 0.05);

                if (littlePot)
                {
                    decimal raiseAmountBlindMultipleCall = (currentRoundMinPlayCallAmount + additionalRaiseToCallAmountNew) / currentDecision.Cache.BigBlind;
                    raiseToCallAmountNew = Math.Round(raiseAmountBlindMultipleCall, 0, MidpointRounding.AwayFromZero) * currentDecision.Cache.BigBlind;

                    decimal raiseAmountBlindMultipleSteal = (currentRoundMinPlayCallAmount + additionalRaiseToStealAmountNew) / currentDecision.Cache.BigBlind;
                    raiseToStealAmountNew = Math.Round(raiseAmountBlindMultipleSteal, 0, MidpointRounding.AwayFromZero) * currentDecision.Cache.BigBlind;
                }
                else
                {
                    decimal raiseAmountBlindMultipleCall = (currentRoundMinPlayCallAmount + additionalRaiseToCallAmountNew) / currentDecision.Cache.LittleBlind;
                    raiseToCallAmountNew = Math.Round(raiseAmountBlindMultipleCall, 0, MidpointRounding.AwayFromZero) * currentDecision.Cache.LittleBlind;

                    decimal raiseAmountBlindMultipleSteal = (currentRoundMinPlayCallAmount + additionalRaiseToStealAmountNew) / currentDecision.Cache.LittleBlind;
                    raiseToStealAmountNew = Math.Round(raiseAmountBlindMultipleSteal, 0, MidpointRounding.AwayFromZero) * currentDecision.Cache.LittleBlind;
                }

                //Check for a big raise amount which would be best as going all in
                if (raiseToCallAmountNew > 0.9m * maximumRaiseToAmount)
                {
                    raiseToCallAmountNew = maximumRaiseToAmount;
                }
                if (raiseToStealAmountNew > 0.9m * maximumRaiseToAmount)
                {
                    raiseToStealAmountNew = maximumRaiseToAmount;
                }
            }
            #endregion RaiseAmounts

            #region EV and CheckPossibilitiy

            decimal bigBlindEVScaleAmount = 20;

            #region CallEV
            //The following EV assumes we can actually call the additionaCallAmount
            //We could cap the additionalCallAmount but we would then also not be able to win the total pot amount ;( again a minor error
            decimal actualCallCheckEV = (currentPotAmount * probWin) - ((1.0m - probWin) * additionalCallAmount);
            decimal scaledCallCheckEV = (actualCallCheckEV / currentDecision.Cache.BigBlind) / bigBlindEVScaleAmount;
            #endregion

            //We can raise if we have more stack than the current additional call amount
            //If we can't raise the raiseEV's get set to the callEV (which may be negative)
            bool raisePossible = (remainingPlayerStack > additionalCallAmount);
            bool checkPossible = (infoStore.GetInfoValue(InfoType.BP_MinimumPlayAmount_Decimal) == infoStore.GetInfoValue(InfoType.BP_PlayerBetAmountCurrentRound_Decimal));

            decimal probAllOpponentFoldRaiseToCall  = (currentBettingRound == 0 ? 0 : infoStore.GetInfoValue(InfoType.WR_RaiseToCallStealSuccessProb));
            decimal probAllOpponentFoldRaiseToSteal = (currentBettingRound == 0 ? 0 : infoStore.GetInfoValue(InfoType.WR_RaiseToStealSuccessProb));

            #region RaiseToCallEV
            decimal scaledRaiseToCallEV = scaledCallCheckEV;
            if (raisePossible)
            {
                decimal potAmountAssumingAllCall = currentPotAmount;

                //If we are preflop then it would be unrealistic to expect everyone to call
                //For Call we assume that if there are 8 players to act after the raise we get 2 calls
                //If there are 4 players to act after the raise we get 1 call
                //This is the same as dividing the number of activePlayers by 4
                if (currentBettingRound == 0)
                {
                    //We assume anyone who has already called or raised will call again
                    long[] calledRaisedPlayerIds = (from current in currentDecision.Cache.getAllHandActions()
                                                    where current.actionType == PokerAction.Call || current.actionType == PokerAction.Raise
                                                    where current.playerId != currentDecision.PlayerId
                                                    select current.playerId).ToArray();

                    for (int i = 0; i < calledRaisedPlayerIds.Length; i++)
                    {
                        potAmountAssumingAllCall += raiseToCallAmountNew - currentDecision.Cache.getPlayerCurrentRoundBetAmount(calledRaisedPlayerIds[i]);
                    }

                    potAmountAssumingAllCall += ((decimal)(activePlayerIds.Length - 1 - calledRaisedPlayerIds.Length) / 4) * raiseToCallAmountNew;
                }
                else
                {
                    for (int i = 0; i < activePlayerIds.Length; i++)
                    {
                        if (activePlayerIds[i] != currentDecision.PlayerId)
                        {
                            potAmountAssumingAllCall += raiseToCallAmountNew - currentDecision.Cache.getPlayerCurrentRoundBetAmount(activePlayerIds[i]);
                        }
                    }
                }

                decimal extraDollarRiskAmount = raiseToCallAmountNew - infoStore.GetInfoValue(InfoType.BP_PlayerBetAmountCurrentRound_Decimal);

                decimal actualRaiseToCallEV = (currentPotAmount * probAllOpponentFoldRaiseToCall) + (probWin * potAmountAssumingAllCall * (1.0m - probAllOpponentFoldRaiseToCall)) - ((1.0m - probWin) * extraDollarRiskAmount * (1.0m - probAllOpponentFoldRaiseToCall));

                scaledRaiseToCallEV = (actualRaiseToCallEV / currentDecision.Cache.BigBlind) / bigBlindEVScaleAmount;
            }
            #endregion

            #region RaiseToStealEV
            decimal scaledRaiseToStealEV = scaledCallCheckEV;
            if (raisePossible)
            {
                decimal potAmountAssumingAllCall = currentPotAmount;

                //If we are preflop then it would be unrealistic to expect everyone to call
                //For steal we assume that if there are 8 players to act after the raise we get 1 call
                //If there are 4 players to act after the raise we get 0.5 call
                //This is the same as dividing the number of activePlayers by 8
                if (currentBettingRound == 0)
                {
                    //We assume anyone who has already raised will call again
                    long[] raisedPlayerIds = (from current in currentDecision.Cache.getAllHandActions()
                                              where current.actionType == PokerAction.Raise
                                              where current.playerId != currentDecision.PlayerId
                                              select current.playerId).ToArray();

                    for (int i = 0; i < raisedPlayerIds.Length; i++)
                    {
                        potAmountAssumingAllCall += raiseToStealAmountNew - currentDecision.Cache.getPlayerCurrentRoundBetAmount(raisedPlayerIds[i]);
                    }

                    potAmountAssumingAllCall += ((decimal)(activePlayerIds.Length - 1 - raisedPlayerIds.Length) / 8) * raiseToStealAmountNew;
                }
                else
                {
                    for (int i = 0; i < activePlayerIds.Length; i++)
                    {
                        if (activePlayerIds[i] != currentDecision.PlayerId)
                        {
                            potAmountAssumingAllCall += raiseToStealAmountNew - currentDecision.Cache.getPlayerCurrentRoundBetAmount(activePlayerIds[i]);
                        }
                    }
                }

                decimal extraDollarRiskAmount = raiseToStealAmountNew - infoStore.GetInfoValue(InfoType.BP_PlayerBetAmountCurrentRound_Decimal);

                decimal actualRaiseToStealEV = (currentPotAmount * probAllOpponentFoldRaiseToSteal) + (probWin * potAmountAssumingAllCall * (1.0m - probAllOpponentFoldRaiseToSteal)) - ((1.0m - probWin) * extraDollarRiskAmount * (1.0m - probAllOpponentFoldRaiseToSteal));
                scaledRaiseToStealEV = (actualRaiseToStealEV / currentDecision.Cache.BigBlind) / bigBlindEVScaleAmount;
            }

            #endregion
            #endregion

            #region playerPosition and numPlayers
            decimal dealerDistance     = ((infoStore.GetInfoValue(InfoType.GP_DealerDistance_Byte) - 1) / (infoStore.GetInfoValue(InfoType.GP_NumActivePlayers_Byte) - 1));
            bool    tablePositionEarly = false;
            bool    tablePositionMid   = false;
            bool    tablePositionLate  = false;

            if (dealerDistance < (1.0m / 3.0m) && dealerDistance >= 0)
            {
                tablePositionEarly = true;
            }
            else if (dealerDistance < (2.0m / 3.0m) && dealerDistance >= 0)
            {
                tablePositionMid = true;
            }
            else if (dealerDistance <= 1.0m && dealerDistance >= 0)
            {
                tablePositionLate = true;
            }
            else
            {
                throw new Exception("Dealer distance must be between 0 and 1.");
            }

            bool lastToAct = infoStore.GetInfoValue(InfoType.GP_NumUnactedPlayers_Byte) == 1;
            #endregion playerPosition and numPlayers

            #region Hand and Action History
            List <PokerAction> allPlayerActionsCurrentHand = currentDecision.Cache.getPlayerActionsCurrentHand(currentDecision.PlayerId);
            decimal            callCount  = (decimal)allPlayerActionsCurrentHand.Count(entry => entry == PokerAction.Call);
            decimal            checkCount = (decimal)allPlayerActionsCurrentHand.Count(entry => entry == PokerAction.Check);
            decimal            raiseCount = (decimal)allPlayerActionsCurrentHand.Count(entry => entry == PokerAction.Raise);

            decimal currentHandOurAggression = raiseCount - (callCount + checkCount);
            #endregion

            #region potCommitment
            bool potCommitted = false;
            if (infoStore.GetInfoValue(InfoType.BP_PlayerMoneyInPot_Decimal) > infoStore.GetInfoValue(InfoType.BP_PlayerHandStartingStackAmount_Decimal) * 0.75m)
            {
                potCommitted = true;
            }
            #endregion

            if (currentBettingRound == 0)
            {
                #region Preflop
                decimal holeCardsPlayability = infoStore.GetInfoValue(InfoType.CP_HoleCardsMatchedPlayability);
                byte    numCallers           = (byte)infoStore.GetInfoValue(InfoType.BP_TotalNumCalls_Byte);

                //Used an odd format to allow multiple fall through all statements
                //i.e. we can use break; to go to the end of the loop
                while (true)
                {
                    if (holeCardsPlayability == 1)
                    {
                        if (playerLastActionCurrentRound == PokerAction.Raise && topHand && randomGen.NextDouble() > 0.8)
                        {
                            decision = 4;
                            raiseToStealAmountNew = currentRoundMinPlayCallAmount + remainingPlayerStack;
                            break;
                        }
                        else
                        {
                            decision = 3;
                            break;
                        }
                    }

                    //If we are required to call an amount greater than 10 times the big blind ($2.50) on 0.25 tables and we dont have AA, KK we fold
                    if (additionalCallAmount > currentDecision.Cache.BigBlind * 10 && !topHand)
                    {
                        break;
                    }

                    if (holeCardsPlayability >= 0.9m)
                    {
                        if (playerLastActionCurrentRound == PokerAction.Raise && topHand && randomGen.NextDouble() > 0.9)
                        {
                            decision = 4;
                            raiseToStealAmountNew = currentRoundMinPlayCallAmount + remainingPlayerStack;
                            break;
                        }
                        else if (tablePositionLate &&
                                 currentRoundMinPlayCallAmount > currentDecision.Cache.BigBlind &&
                                 scaledCallCheckEV > 0 && scaledRaiseToCallEV > scaledCallCheckEV)
                        {
                            //Late position, raised pot, 80% reraise
                            if (randomGen.NextDouble() > 0.20 && playerLastActionCurrentRound != PokerAction.Raise)
                            {
                                decision = 3;
                            }
                            else
                            {
                                decision = 2;
                            }

                            break;
                        }
                        else if (currentRoundMinPlayCallAmount > currentDecision.Cache.BigBlind &&
                                 (scaledCallCheckEV > 0 || (additionalCallAmount <= 4 * currentDecision.Cache.BigBlind && scaledCallCheckEV > -0.1m) || topHand))
                        {
                            //Not late, raised pot, call
                            decision = 2;

                            if (scaledRaiseToCallEV > 0 &&
                                playerLastActionCurrentRound != PokerAction.Raise &&
                                randomGen.NextDouble() > 0.50)
                            {
                                decision = 3;
                            }

                            break;
                        }
                        else if (currentRoundMinPlayCallAmount == currentDecision.Cache.BigBlind)
                        {
                            //Unraised, there is 90% prob we will raise
                            if (randomGen.NextDouble() > 0.1)
                            {
                                decision = 3;
                            }
                            else
                            {
                                decision = 2;
                            }

                            break;
                        }
                    }

                    if (holeCardsPlayability >= 0.75m)
                    {
                        //Early position, raised pot
                        if (tablePositionEarly && currentRoundMinPlayCallAmount > currentDecision.Cache.BigBlind &&
                            (scaledCallCheckEV > 0 || (additionalCallAmount <= 4 * currentDecision.Cache.BigBlind && scaledCallCheckEV > -0.2m) || topHand))
                        {
                            decision = 2;
                            break;
                        }
                        //Not early, raised pot
                        if (!tablePositionEarly && currentRoundMinPlayCallAmount > currentDecision.Cache.BigBlind &&
                            (scaledCallCheckEV > 0 || (additionalCallAmount <= 4 * currentDecision.Cache.BigBlind && scaledCallCheckEV > -0.2m) || topHand))
                        {
                            decision = 2;

                            if (raiseToCallAmountNew <= 8 * currentDecision.Cache.BigBlind && randomGen.NextDouble() > 0.5)
                            {
                                decision = 3;
                            }

                            break;
                        }
                        //Unraised pot
                        else if (currentRoundMinPlayCallAmount == currentDecision.Cache.BigBlind)
                        {
                            if (randomGen.NextDouble() > 0.1)
                            {
                                decision = 3;
                            }
                            else
                            {
                                decision = 2;
                            }

                            break;
                        }
                    }

                    if (holeCardsPlayability >= 0.6m)
                    {
                        if (tablePositionEarly &&
                            (scaledCallCheckEV > 0 || (additionalCallAmount <= 4 * currentDecision.Cache.BigBlind && scaledCallCheckEV > -0.1m) || topHand))
                        {
                            decision = 2;
                            break;
                        }
                        else if ((scaledCallCheckEV > 0 || (additionalCallAmount <= 4 * currentDecision.Cache.BigBlind && scaledCallCheckEV > -0.15m) || topHand))
                        {
                            decision = 2;
                            break;
                        }
                    }

                    if (holeCardsPlayability >= 0.5m)
                    {
                        if (tablePositionLate &&
                            (scaledCallCheckEV > 0 || (additionalCallAmount <= 4 * currentDecision.Cache.BigBlind && scaledCallCheckEV > -0.15m) || topHand))
                        {
                            decision = 2;
                            break;
                        }
                        else if ((playerLastActionCurrentRound == PokerAction.Call || playerLastActionCurrentRound == PokerAction.Raise) &&
                                 (scaledCallCheckEV > 0 || (additionalCallAmount <= 4 * currentDecision.Cache.BigBlind && scaledCallCheckEV > -0.15m) || topHand))
                        {
                            decision = 2;
                            break;
                        }
                    }

                    if (holeCardsPlayability >= 0.3m)
                    {
                        if (currentRoundMinPlayCallAmount == currentDecision.Cache.BigBlind)
                        {
                            decision = 2;
                            break;
                        }
                        else if (tablePositionLate && (playerLastActionCurrentRound == PokerAction.Call || playerLastActionCurrentRound == PokerAction.Raise) &&
                                 (scaledCallCheckEV > 0 || (additionalCallAmount <= 4 * currentDecision.Cache.BigBlind && scaledCallCheckEV > -0.1m) || topHand))
                        {
                            decision = 2;
                            break;
                        }
                    }

                    if (holeCardsPlayability >= 0.25m)
                    {
                        if (tablePositionLate && currentRoundMinPlayCallAmount == currentDecision.Cache.BigBlind)
                        {
                            decision = 2;
                            break;
                        }
                    }

                    if (holeCardsPlayability >= 0.1m)
                    {
                        if (tablePositionLate && numCallers >= 2 && currentRoundMinPlayCallAmount == currentDecision.Cache.BigBlind)
                        {
                            decision = 2;
                            break;
                        }
                        else if (topHand)
                        {
                            decision = 2;
                            break;
                        }
                    }

                    //We only fall through once
                    break;
                }

                #endregion
            }
            else
            {
                #region PostFlop Strategy
                //decimal playEVThreshold = 0.05m;
                decimal playEVThreshold = 0;

                //Need some form of opponent aggression factor to use in scaling the slow play
                //Scaled between 0 and 1 for aggression between 0.01 and 10
                //Default value is approx 0.57
                double avgOppAggression = (double)infoStore.GetInfoValue(InfoType.AP_AvgLiveOppCurrentRoundAggr_Double);

                //If we have hit big
                if (probWin > 0.95m)
                {
                    #region BigHit
                    //River only
                    if (currentBettingRound == 3)
                    {
                        #region River BigHit
                        //Has our opponent raised every round? If so we will check again here
                        if (tablePositionEarly && checkPossible && playerLastActionCurrentRound == PokerAction.NoAction)
                        {
                            //What is our opponent aggression this hand?
                            double averageOpponentAggression = 0;
                            for (int i = 0; i < activePlayerIds.Length; i++)
                            {
                                if (activePlayerIds[i] != currentDecision.PlayerId)
                                {
                                    List <PokerAction> allOpponentActions = currentDecision.Cache.getPlayerActionsCurrentHandPostFlop(activePlayerIds[i]);

                                    double currentHandOpponentAggression = allOpponentActions.Count(entry => entry == PokerAction.Raise) -
                                                                           (allOpponentActions.Count(entry => entry == PokerAction.Call) + allOpponentActions.Count(entry => entry == PokerAction.Check));

                                    averageOpponentAggression += currentHandOpponentAggression;
                                }
                            }

                            averageOpponentAggression /= (double)(activePlayerIds.Length - 1);

                            if (averageOpponentAggression >= 2 || randomGen.NextDouble() < (avgOppAggression - 0.8))
                            {
                                decision = 1;
                                Debug.WriteLine("Checking with a whopper on the river hoping you will raise, aggressive SOB!");
                            }
                            else
                            {
                                Debug.WriteLine("Raising with my big one on river as you havn't been very aggressive.");

                                //When we are on the river we play differently with big hits
                                //We will always 'atleast' raise to call with a really good hand
                                decision = 3;

                                //We may occasionaly raiseToSteal on the river with a good hand to keep opponenents guessing
                                if (scaledRaiseToStealEV > scaledRaiseToCallEV && randomGen.NextDouble() > 0.75)
                                {
                                    decision = 4;
                                }
                            }
                        }
                        else
                        {
                            Debug.WriteLine("Raising with big hit on river as it looks like you have nothing. Pay me!");

                            //When we are on the river we play differently with big hits
                            //We will always 'atleast' raise to call with a really good hand
                            decision = 3;

                            //We may occasionaly raiseToSteal on the river with a good hand to keep opponenents guessing
                            if (scaledRaiseToStealEV > scaledRaiseToCallEV && randomGen.NextDouble() > 0.75)
                            {
                                decision = 4;
                            }
                        }
                        #endregion
                    }
                    else
                    {
                        if (currentBettingRound == 1 ||                                                                                              //We will slow play on the flop
                            (playerLastActionCurrentRound == PokerAction.Check && randomGen.NextDouble() < avgOppAggression) ||                      //If we just checked we may continue to slow play this round
                            (scaledCallCheckEV > 0.25m && checkPossible && !tablePositionLate && randomGen.NextDouble() < 0.6 * avgOppAggression) || //Sensible pot (flop/turn) we're early and it's not yet raised
                            scaledCallCheckEV > 0.75m && !checkPossible && additionalCallAmount > 0.25m * currentPotAmount)                          //Big pot (flop/turn) and it's been raised sensibly
                        {
                            Debug.WriteLine("Slow playing with my big hit. Will you take the bait?");

                            if (checkPossible)
                            {
                                decision = 1;
                            }
                            else
                            {
                                decision = 2;
                            }
                        }
                        else
                        {
                            Debug.WriteLine("I'm not going to slow play my hit. Raising so that it gets expensive if you want to continue.");
                            //If we are are not going to slow play then we ofcourse default to raise
                            decision = 3;
                        }
                    }
                    #endregion
                }
                else if (probWin > 0.5m)
                {
                    #region ProbableWin
                    //If both raise EV's are positive and better than just calling/checking
                    if (scaledRaiseToCallEV > playEVThreshold &&
                        scaledRaiseToStealEV > playEVThreshold &&
                        scaledRaiseToCallEV > scaledCallCheckEV &&
                        scaledRaiseToStealEV > scaledCallCheckEV)
                    {
                        //Unraised, we've been aggressive, in an early position, then 40% of the time check
                        if (checkPossible &&
                            currentHandOurAggression > 2 &&
                            scaledCallCheckEV > playEVThreshold &&
                            tablePositionEarly &&
                            randomGen.NextDouble() < avgOppAggression)
                        {
                            Debug.WriteLine("Early position with OK hand, have already been agressive so checking.");
                            decision = 1;
                        }

                        //Unraised, early position, 15% time we will check
                        else if (checkPossible &&
                                 scaledCallCheckEV > playEVThreshold &&
                                 randomGen.NextDouble() < avgOppAggression * (double)(1.0m - (probWin * 0.8m))) //higher prob win, less checks
                        {
                            Debug.WriteLine("Sometimes I want to check with my OK hand.");
                            decision = 1;
                        }

                        //Before river and raised, if we have been aggressive or due to the random number we may call
                        else if (!checkPossible &&
                                 scaledCallCheckEV > playEVThreshold &&
                                 (randomGen.NextDouble() < avgOppAggression * 0.75 || currentHandOurAggression > 2 || additionalCallAmount > 0.25m * currentPotAmount))
                        {
                            Debug.WriteLine("I have a better hand than you but sometimes I will just call to be annoying.");
                            decision = 2;
                        }

                        //If we have not checked or called then we will generally be raising
                        else if ((randomGen.NextDouble() < 0.8 && scaledRaiseToCallEV > scaledRaiseToStealEV) || //If raiseToCall is best 80% of the time we raiseToCall
                                 (randomGen.NextDouble() < 0.2 && scaledRaiseToStealEV > scaledRaiseToCallEV) || //If raiseToSteal is best 20% of the time we raiseToCall
                                 (probAllOpponentFoldRaiseToSteal >= 0.75m) ||                                   //Probability everyone will fold if we try to steal is high enough
                                 currentPotAmount > 40 * currentDecision.Cache.BigBlind)                         //The pot is already large, a steal is probably pointless
                        {
                            //Generally the raise will be to call
                            Debug.WriteLine("Considered checking/calling with an OK hand but TBH i'm going to raise to call.");
                            decision = 3;
                        }
                        else
                        {
                            Debug.WriteLine("Considered checking/calling with an OK hand but TBH i'm going to raise to steal.");
                            //If we made it to raising but for some reason we didnt raise to call then a steal it is
                            decision = 4;
                        }
                    }
                    else if (scaledCallCheckEV > playEVThreshold)
                    {
                        Debug.WriteLine("Raising doesn't really work for me so i'm just going to call/check.");
                        if (checkPossible)
                        {
                            decision = 1;
                        }
                        else
                        {
                            decision = 2;
                        }
                    }
                    #endregion
                }
                else if (probWin > 0.1m)
                {
                    #region DangerArea
                    //We will consider a steal if it looks favourable
                    if (scaledRaiseToStealEV > playEVThreshold &&
                        scaledRaiseToStealEV > scaledCallCheckEV &&
                        scaledRaiseToStealEV > scaledRaiseToCallEV &&
                        probAllOpponentFoldRaiseToSteal > 0.75m &&
                        currentPotAmount <= 40 * currentDecision.Cache.BigBlind)
                    {
                        Debug.WriteLine("My hand is not great but I think I can steal it from you, haha.");
                        decision = 4;
                    }
                    else
                    {
                        //First action on river with a small pot, finite chance of raising anyway
                        if (currentBettingRound == 3 &&
                            playerLastActionCurrentRound == PokerAction.NoAction &&
                            randomGen.NextDouble() < 0.10 &&
                            scaledRaiseToCallEV > playEVThreshold &&
                            currentPotAmount < 12 * currentDecision.Cache.BigBlind)
                        {
                            Debug.WriteLine("My hand is not great but I fancy semi bluffing and faking strength.");
                            if (randomGen.NextDouble() > (double)probAllOpponentFoldRaiseToSteal || scaledRaiseToCallEV > scaledRaiseToStealEV)
                            {
                                decision = 3;
                            }
                            else
                            {
                                decision = 4;
                            }
                        }
                        //Tried to check but got raised a small amount
                        else if (playerLastActionCurrentRound == PokerAction.Check &&
                                 randomGen.NextDouble() < avgOppAggression * 0.2 &&
                                 scaledRaiseToCallEV > playEVThreshold &&
                                 (currentRoundMinPlayCallAmount * 10.0m <= currentPotAmount || currentRoundMinPlayCallAmount <= currentDecision.Cache.BigBlind * 1.2m))
                        {
                            decision = 3;
                            Debug.WriteLine("Hahahaha, if you're going to raise so little can you handle my check-raise bluff??");
                        }
                        else if (scaledCallCheckEV > playEVThreshold)
                        {
                            if (checkPossible)
                            {
                                Debug.WriteLine("MY hand is not great so i'm checking for some free cards.");
                                decision = 1;
                            }
                            else
                            {
                                Debug.WriteLine("I'll call but only because i fancy my draws.");
                                decision = 2;
                            }
                        }
                        else
                        {
                            Debug.WriteLine("I just don't fancy my draws, folding is probably best for me.");
                            decision = 0;
                        }
                    }
                    #endregion
                }
                else
                {
                    #region BigFatMiss Or Big Opponent Hit

                    if (currentBettingRound == 3 &&
                        (playerLastActionCurrentRound == PokerAction.NoAction || playerLastActionCurrentRound == PokerAction.Check) &&
                        currentPotAmount < 12 * currentDecision.Cache.BigBlind &&
                        //Depending on the amount raised and the opponent aggression we may try to bluff
                        randomGen.NextDouble() < 0.02 * avgOppAggression * (double)(additionalCallAmount > 0 ? (currentPotAmount - additionalCallAmount) / additionalCallAmount : 5))
                    {
                        Debug.WriteLine("I have so totally missed, but against my better judgement i'm going to bluff once on the river.");
                        if (randomGen.NextDouble() > (double)probAllOpponentFoldRaiseToSteal)
                        {
                            decision = 3;
                        }
                        else
                        {
                            decision = 4;
                        }
                    }
                    else
                    {
                        //We are not going to attempt to steal if we are beat
                        if (scaledCallCheckEV > playEVThreshold)
                        {
                            Debug.WriteLine("I have so totally missed, but my EV says YES!");
                            if (checkPossible)
                            {
                                decision = 1;
                            }
                            else
                            {
                                decision = 2;
                            }
                        }
                        else
                        {
                            Debug.WriteLine("Fair play, you can have this one, AHOLE!");
                            decision = 0;
                        }
                    }
                    #endregion
                }
                #endregion
            }

            //If we are pot committed we must call anything from here on out
            if (potCommitted && !checkPossible && probWin > 0.01m)
            {
                decision = 2;
            }

            if (decision == 0)
            {
                return(new Play(PokerAction.Fold, 0, 0, currentDecision.Cache.getCurrentHandId(), currentDecision.PlayerId, decisionLogStr, 0));
            }
            else if (decision == 1)
            {
                return(new Play(PokerAction.Check, 0, 0, currentDecision.Cache.getCurrentHandId(), currentDecision.PlayerId, decisionLogStr, 0));
            }
            else if (decision == 2)
            {
                return(new Play(PokerAction.Call, additionalCallAmount, 0, currentDecision.Cache.getCurrentHandId(), currentDecision.PlayerId, decisionLogStr, 0));
            }
            else if (decision == 3)
            {
                return(new Play(PokerAction.Raise, raiseToCallAmountNew, 0, currentDecision.Cache.getCurrentHandId(), currentDecision.PlayerId, decisionLogStr, 0));
            }
            else if (decision == 4)
            {
                return(new Play(PokerAction.Raise, raiseToStealAmountNew, 0, currentDecision.Cache.getCurrentHandId(), currentDecision.PlayerId, decisionLogStr, 0));
            }
            else
            {
                throw new Exception("decision value not valid.");
            }
        }