protected override Play GetDecision()
        {
            Dictionary <string, decimal> networkInputs = new Dictionary <string, decimal>();

            networkInputs.Add("ProbCardsWin", infoStore.GetInfoValue(InfoType.WR_CardsOnlyWinPercentage));
            networkInputs.Add("ProbCardsWinOpponentWin", (1 - infoStore.GetInfoValue(InfoType.WR_CardsOnlyWinPercentage)) / (infoStore.GetInfoValue(InfoType.GP_NumActivePlayers_Byte) - 1));

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

            if (currentGameStage == 0)
            {
                preFlop = 1;
            }
            else
            {
                preFlop = 0;
            }

            networkInputs.Add("PreFlop", preFlop);

            decimal currentRoundBetAmount = currentDecision.Cache.getPlayerCurrentRoundBetAmount(currentDecision.PlayerId);
            decimal minCallAmount         = infoStore.GetInfoValue(InfoType.BP_MinimumPlayAmount_Decimal);
            decimal scaledCallAmount      = (minCallAmount - currentRoundBetAmount) / currentDecision.Cache.MaxStack;

            if (scaledCallAmount > 1)
            {
                scaledCallAmount = 1;
            }
            else if (scaledCallAmount < 0)
            {
                scaledCallAmount = 0;
            }

            networkInputs.Add("ScaledCallAmount", scaledCallAmount);

            decimal raiseToCallAmount  = infoStore.GetInfoValue(InfoType.PAP_RaiseToCallAmount_Amount);
            decimal raiseToStealAmount = infoStore.GetInfoValue(InfoType.PAP_RaiseToStealAmount_Amount);

            decimal scaledRaiseToStealAmount = raiseToStealAmount / currentDecision.Cache.MaxStack;

            if (scaledRaiseToStealAmount > 1)
            {
                scaledRaiseToStealAmount = 1;
            }

            networkInputs.Add("ScaledRaiseToStealAmount", scaledRaiseToStealAmount);

            decimal raiseRatio     = 0;
            decimal totalNumRaises = infoStore.GetInfoValue(InfoType.BP_TotalNumRaises_Byte);
            decimal totalNumCalls  = infoStore.GetInfoValue(InfoType.BP_TotalNumCalls_Byte);
            decimal totalNumChecks = infoStore.GetInfoValue(InfoType.BP_TotalNumChecks_Byte);

            if (totalNumRaises + totalNumCalls + totalNumChecks > 0)
            {
                raiseRatio = totalNumRaises / (totalNumRaises + totalNumCalls + totalNumChecks);
            }

            networkInputs.Add("RaiseRatio", raiseRatio);
            networkInputs.Add("ImmediatePotOdds", infoStore.GetInfoValue(InfoType.BP_ImmediatePotOdds_Double));
            networkInputs.Add("UnactedRatio", infoStore.GetInfoValue(InfoType.GP_NumUnactedPlayers_Byte) / infoStore.GetInfoValue(InfoType.GP_NumActivePlayers_Byte));
            networkInputs.Add("ActiveRatio", infoStore.GetInfoValue(InfoType.GP_NumActivePlayers_Byte) / infoStore.GetInfoValue(InfoType.GP_NumTableSeats_Byte));

            networkInputs.Add("ProbRaiseToBotCheck", infoStore.GetInfoValue(InfoType.PAP_RaiseToBotCheck_Prob));
            networkInputs.Add("ProbRaiseToBotCall", infoStore.GetInfoValue(InfoType.PAP_RaiseToBotCall_Prob));
            networkInputs.Add("ProbFoldToBotCall", infoStore.GetInfoValue(InfoType.PAP_FoldToBotCall_Prob));
            networkInputs.Add("ProbRaiseToStealSuccess", infoStore.GetInfoValue(InfoType.PAP_RaiseToStealSuccess_Prob));

            networkInputs.Add("AvgScaledOppRaiseFreq", infoStore.GetInfoValue(InfoType.AP_AvgScaledOppRaiseFreq_Double));
            networkInputs.Add("AvgScaledOppCallFreq", infoStore.GetInfoValue(InfoType.AP_AvgScaledOppCallFreq_Double));
            networkInputs.Add("AvgScaledOppPreFlopPlayFreq", infoStore.GetInfoValue(InfoType.AP_AvgScaledOppPreFlopPlayFreq_Double));

            //probCardsWin, probCardsWinOpponentWin, preFlop, scaledCallAmount, scaledRaiseToStealAmount,
            //raiseRatio, immediatePotOdds, unactedRatio, activeRatio, probRaiseToBotCheck, probRaiseToBotCall,
            //probFoldToBotCall, probRaiseToStealSuccess, avgScaledOppRaiseFreq, avgScaledOppCallFreq,
            //avgScaledOppPreFlopPlayFreq;

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

            //decisionLogStr = aiDecisionData.ToString();

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

            NeuralAiDecision decision = new NeuralAiDecision(networkOutput[0], networkOutput[1], networkOutput[2], networkOutput[3], networkOutput[4]);
            //Debug.Print("AI Decision - [{0}], [{1}], [{2}], [{3}], [{4}]", networkOutput[0], networkOutput[1], networkOutput[2], networkOutput[3], networkOutput[4]);

            decimal playerRemainingStackAmount = currentDecision.Cache.getPlayerStack(currentDecision.PlayerId);

            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.Call, currentDecision.Cache.getMinimumPlayAmount() - currentRoundBetAmount, 0, currentDecision.Cache.getCurrentHandId(), currentDecision.PlayerId, decisionLogStr, 0));
            }
            else if (decision.BotAction == 2)
            {
                return(new Play(PokerAction.Raise, (decimal)raiseToCallAmount, 0, currentDecision.Cache.getCurrentHandId(), currentDecision.PlayerId, decisionLogStr, 0));
            }
            else if (decision.BotAction == 3)
            {
                return(new Play(PokerAction.Raise, (decimal)raiseToStealAmount, 0, currentDecision.Cache.getCurrentHandId(), currentDecision.PlayerId, decisionLogStr, 0));
            }
            else if (decision.BotAction == 4)
            {
                return(new Play(PokerAction.Raise, playerRemainingStackAmount + currentRoundBetAmount, 0, currentDecision.Cache.getCurrentHandId(), currentDecision.PlayerId, decisionLogStr, 0));
            }
            else
            {
                throw new Exception("Something has gone wery wong!");
            }

            //return new Play(PokerAction.NoAction, 0, 0, 0, playerId, decisionLogStr, aiDecisionData.AIDecisionStringType);
        }
Beispiel #2
0
        /// <summary>
        /// Predict a players next action using the current cache reference.
        /// </summary>
        /// <param name="handId"></param>
        /// <param name="playerId"></param>
        /// <returns></returns>
        protected PlayerActionPrediction PredictPlayerAction(long handId, long predictPlayerId, decimal numActivePlayers,
                                                             decimal numUnactedPlayers, List <byte> simulatedFoldPositions, decimal betsToCall, decimal minCallAmount, decimal totalNumCalls, decimal totalNumRaises, decimal totalPotAmount, bool logNetworkInputs, PokerPlayerNNModelv1 playerActionNN)
        {
            //Load the network.
            decimal networkAccuracy = 0;

            //playerActionNN.Network = networkManager.getPlayerNetwork(predictPlayerId, ref networkAccuracy);

            if (tempLocalHandCache.handId != handId)
            {
                throw new Exception("The tempLocalHandCache has not been updated.");
            }

            Dictionary <string, decimal> networkInputs = new Dictionary <string, decimal>();

            #region compileNetworkInputs
            decimal playerCurrentRoundBetAmount;
            decimal totalPlayerMoneyInPot;
            decimal playerTotalStack;
            bool    playerLastRoundCall;
            bool    playerLastRoundRaise;
            decimal RFreq_PostFlop, CFreq_PostFlop, PreFlopPlayFreq;

            if (tempLocalPlayerCacheDict.Count != 0)
            {
                tempPlayerCache playerDetails;

                if (tempLocalPlayerCacheDict.ContainsKey(predictPlayerId))
                {
                    playerDetails = tempLocalPlayerCacheDict[predictPlayerId];
                }
                else
                {
                    throw new Exception("Played not found - The tempLocalPlayerCache should be built before PredictPlayerAction is called.");
                }

                playerCurrentRoundBetAmount = playerDetails.currentRoundPlayerBetAmount;
                totalPlayerMoneyInPot       = playerDetails.totalPlayerMoneyInPot;
                playerLastRoundCall         = playerDetails.playerLastRoundCall;
                playerLastRoundRaise        = playerDetails.playerLastRoundRaise;
                playerTotalStack            = playerDetails.playerStack;
                RFreq_PostFlop  = playerDetails.RFreq_PostFlop;
                CFreq_PostFlop  = playerDetails.CFreq_PostFlop;
                PreFlopPlayFreq = playerDetails.PreFlopPlayFreq;
            }
            else
            {
                throw new Exception("No entries - The tempLocalPlayerCache should be built before PredictPlayerAction is called.");
            }

            decimal imPotOdds;
            if (minCallAmount > 0)
            {
                //The immediatePotOdds will always be larger than 1 al the way to 10,000 (assuming $100 pot size and a $0.01 call amount)
                //Most immedaitePotOdds seem to fall between 1 and 10 (i.e. if a pot already has $5 in it the minimum expected call will be around $0.50)
                //A @imPotOdds = 1 means the pot odds are very good i.e. better than 10:1
                //A @imPotOdds = 0 means the pot odds are crap i.e. 1:1
                //cache.getPlayerCurrentRoundBetAmount(predictPlayerId, out playerCurrentRounBetAmount);
                decimal useThisCallAmount;
                if (minCallAmount > playerTotalStack + playerCurrentRoundBetAmount)
                {
                    useThisCallAmount = playerTotalStack + playerCurrentRoundBetAmount;
                }
                else
                {
                    useThisCallAmount = minCallAmount;
                }

                imPotOdds = ((totalPotAmount / (useThisCallAmount - playerCurrentRoundBetAmount)) / 10.0m) - 0.1m;
                if (imPotOdds > 1)
                {
                    imPotOdds = 1;
                }
                else if (imPotOdds < 0)
                {
                    throw new Exception("Error in predictPlayerAction. ImmediatePotOdds should never be negative. TotalPot: " + totalPotAmount.ToString() + ", MinCallAmount: " + minCallAmount.ToString() + ", PlayerCurrentRoundBetAmount:" + playerCurrentRoundBetAmount.ToString());
                }
            }
            else
            {
                imPotOdds = 1;
            }

            networkInputs.Add("ImPotOdds", imPotOdds);

            //Compile all inputs
            decimal raiseRatio = 0;
            if (totalNumRaises + totalNumCalls > 0)
            {
                raiseRatio = totalNumRaises / (totalNumRaises + totalNumCalls);
            }

            networkInputs.Add("RaiseRatio", raiseRatio);
            networkInputs.Add("PotRatio", totalPlayerMoneyInPot / totalPotAmount); // Own Money In Pot / Total Amount In Pot

            //Bets to Call
            decimal betsToCall0 = 0, betsToCall1 = 0, betsToCall2Greater = 0;
            if (betsToCall == 0)
            {
                betsToCall0 = 1;
            }
            else if (betsToCall == 1)
            {
                betsToCall1 = 1;
            }
            else if (betsToCall > 1)
            {
                betsToCall2Greater = 1;
            }
            else
            {
                throw new Exception("Meh!");
            }

            networkInputs.Add("BetsToCall0", betsToCall0);
            networkInputs.Add("BetsToCall1", betsToCall1);
            networkInputs.Add("BetsToCall2Greater", betsToCall2Greater);

            //Gamestage
            byte    gameStage = tempLocalHandCache.gameStage;
            decimal gameStage0 = 0, gameStage1 = 0, gameStage2 = 0, gameStage3 = 0;
            if (gameStage == 0)
            {
                gameStage0 = 1;
            }
            else if (gameStage == 1)
            {
                gameStage1 = 1;
            }
            else if (gameStage == 2)
            {
                gameStage2 = 1;
            }
            else if (gameStage == 3)
            {
                gameStage3 = 1;
            }
            else
            {
                throw new Exception("Meh!");
            }

            networkInputs.Add("GameStage0", gameStage0);
            networkInputs.Add("GameStage1", gameStage1);
            networkInputs.Add("GameStage2", gameStage2);
            networkInputs.Add("GameStage3", gameStage3);

            networkInputs.Add("PlayerLastRoundCall", Convert.ToDecimal(playerLastRoundCall));
            networkInputs.Add("PlayerLastRoundRaise", Convert.ToDecimal(playerLastRoundRaise));

            networkInputs.Add("DealtInPlayersRatio", tempLocalHandCache.numPlayersDealtIn / tempLocalHandCache.numTableSeats);
            networkInputs.Add("ActivePlayersRatio", numActivePlayers / tempLocalHandCache.numPlayersDealtIn);
            networkInputs.Add("UnactedPlayersRatio", numUnactedPlayers / numActivePlayers);

            networkInputs.Add("FlushPossible", Convert.ToDecimal(tempLocalHandCache.flushPossible));
            networkInputs.Add("StraightPossible", Convert.ToDecimal(tempLocalHandCache.straightPossible));
            networkInputs.Add("AceOnBoard", Convert.ToDecimal(tempLocalHandCache.aceOnBoard));
            networkInputs.Add("KingOnBoard", Convert.ToDecimal(tempLocalHandCache.kingOnBoard));
            networkInputs.Add("AceKingQueenRatio", tempLocalHandCache.aceKingQueenRatio);

            ////This is wrong and not going to work as we don't know where the simulated folded players sit!!
            //float dealerDistance = (cache.getActivePlayerDistanceToDealer(predictPlayerId) - (float)numSimulatedFoldPlayers) - 1  / ((float)numActivePlayers - 1);
            //Distance to dealer for this player
            networkInputs.Add("DealerDistance", 0);

            //Some aggression information
            networkInputs.Add("PreFlopPlayFreq", PreFlopPlayFreq);
            networkInputs.Add("CFreq_PostFlop", CFreq_PostFlop);
            networkInputs.Add("RFreq_PostFlop", RFreq_PostFlop);

            #endregion

            NNDataSource networkInputSource = new NNDataSource(networkInputs.Values.ToArray(), PokerPlayerNNModelv1.Input_Neurons);

            //Get the network output
            double[] networkInput = null;
            networkInputSource.returnInput(ref networkInput);
            double[] networkOutput = networkManager.getPlayerNetworkPrediction(predictPlayerId, networkInput, ref networkAccuracy);
            PlayerActionPrediction predictedAction = new PlayerActionPrediction(networkOutput[0], networkOutput[1], networkOutput[2], networkAccuracy);

#if logging
            logger.Debug("PPA," + handId + ", " + predictPlayerId + ",, " + networkInputSource.ToString() + ",, " + GenerateMD5(networkManager.GetDefaultNetwork()) + ", ," + networkOutput[0] + ", ," + networkOutput[1] + ", ," + networkOutput[2]);
#endif

            //Return as PlayerActionPrediction struct
            return(predictedAction);
        }
Beispiel #3
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));
        }
 public VectorDistanceElement(double distance, NNDataSource element)
 {
     this.totalVectorDistance = distance;
     this.element             = element;
 }
        protected override Play GetDecision()
        {
            //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);
            decimal currentPotAmount     = infoStore.GetInfoValue(InfoType.BP_TotalPotAmount_Decimal);
            decimal remainingPlayerStack = currentDecision.Cache.getPlayerStack(currentDecision.PlayerId);

            //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 NewRaiseAmounts
            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 * currentRoundLastRaiseAmount;
                    }
                    else if (randomNumber > 0.45)
                    {
                        additionalNewRaiseAmount = 1.5m * currentRoundLastRaiseAmount;
                    }
                    else
                    {
                        additionalNewRaiseAmount = 1 * currentRoundLastRaiseAmount;
                    }

                    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 + (decimal)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
            if (currentRoundPlayerActions.Count(entry => entry == PokerAction.Raise) >= 2)
            {
                raiseToCallAmountNew  = maximumRaiseAmount;
                raiseToStealAmountNew = maximumRaiseAmount;
            }
            #endregion RaiseAmounts

            #region EV and CheckPossibilitiy

            decimal probWin = 1.0m - infoStore.GetInfoValue(InfoType.WR_ProbOpponentHasBetterWRFIXED);
            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

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

            decimal probAllOpponentFoldRaiseToCall  = infoStore.GetInfoValue(InfoType.WR_RaiseToCallStealSuccessProb);
            decimal probAllOpponentFoldRaiseToSteal = (currentDecision.Cache.getBettingRound() == 0 ? 0 : infoStore.GetInfoValue(InfoType.WR_RaiseToStealSuccessProb));
            long[]  activePlayerIds = currentDecision.Cache.getActivePlayerIds();

            #region RaiseToCallEV
            decimal scaledRaiseToCallEV = 0;
            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 (currentDecision.Cache.getBettingRound() == 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;
                //if (scaledRaiseToCallEV > 1) networkInputs.Add("ScaledRaiseToCallEV", 1);
                //else if (scaledRaiseToCallEV < -1) networkInputs.Add("ScaledRaiseToCallEV", -1);
                //else networkInputs.Add("ScaledRaiseToCallEV", scaledRaiseToCallEV);
            }
            #endregion

            #region RaiseToStealEV
            decimal scaledRaiseToStealEV = 0;
            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 (currentDecision.Cache.getBettingRound() == 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;
                //if (scaledRaiseToStealEV > 1) networkInputs.Add("ScaledRaiseToStealEV", 1);
                //else if (scaledRaiseToStealEV < -1) networkInputs.Add("ScaledRaiseToStealEV", -1);
                //else networkInputs.Add("ScaledRaiseToStealEV", scaledRaiseToStealEV);
            }
            #endregion
            #endregion

            Dictionary <string, decimal> networkInputs = new Dictionary <string, decimal>();

            #region neuralInputs

            //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("HoleCardsSuited", infoStore.GetInfoValue(InfoType.CP_HoleCardsSuited_Bool));

            networkInputs.Add("HoleCardPlayability", infoStore.GetInfoValue(InfoType.CP_HoleCardsMatchedPlayability));

            /*
             * networkInputs.Add("HoleCardsMidConnector", infoStore.GetInfoValue(InfoType.CP_HoleCardsMidConnector_Bool));
             * networkInputs.Add("HoleCardsLowConnector", infoStore.GetInfoValue(InfoType.CP_HoleCardsLowConnector_Bool));
             *
             * networkInputs.Add("HoleCardsFlushDraw", infoStore.GetInfoValue(InfoType.CP_HoleCardsFlushDraw_Bool));
             * networkInputs.Add("HoleCardsOuterStraightDraw", infoStore.GetInfoValue(InfoType.CP_HoleCardsOuterStraightDrawWithHC_Bool));
             * networkInputs.Add("HoleCardsInnerStraightDraw", infoStore.GetInfoValue(InfoType.CP_HoleCardsInnerStraightDrawWithHC_Bool));
             * networkInputs.Add("HoleCardsTopOrTwoPair", infoStore.GetInfoValue(InfoType.CP_HoleCardsTopOrTwoPair_Bool));
             * networkInputs.Add("HoleCardsAorKinHand", infoStore.GetInfoValue(InfoType.CP_HoleCardsAOrKInHand_Bool));
             * networkInputs.Add("HoleCards3KindOrBetter", infoStore.GetInfoValue(InfoType.CP_HoleCards3KindOrBetterMadeWithHC_Bool));
             * networkInputs.Add("AonBoard", infoStore.GetInfoValue(InfoType.CP_AOnBoard_Bool));
             * networkInputs.Add("KonBoard", infoStore.GetInfoValue(InfoType.CP_KOnBoard_Bool));
             * networkInputs.Add("AKQRatio", infoStore.GetInfoValue(InfoType.CP_AKQToBoardRatio_Real));
             *
             * networkInputs.Add("FlushPossible", infoStore.GetInfoValue(InfoType.CP_FlushPossible_Bool));
             * networkInputs.Add("StraightPossible", infoStore.GetInfoValue(InfoType.CP_StraightPossible_Bool));
             * networkInputs.Add("TableStraightDraw", infoStore.GetInfoValue(InfoType.CP_TableStraightDraw_Bool));
             * networkInputs.Add("TableFlushDraw", infoStore.GetInfoValue(InfoType.CP_TableFlushDraw_Bool));
             */

            //DealtInRatio, ActiveRatio and UnactedRatio
            //networkInputs.Add("DealtInRatio", infoStore.GetInfoValue(InfoType.GP_NumPlayersDealtIn_Byte) / infoStore.GetInfoValue(InfoType.GP_NumTableSeats_Byte));
            //networkInputs.Add("ActiveRatio", infoStore.GetInfoValue(InfoType.GP_NumActivePlayers_Byte) / infoStore.GetInfoValue(InfoType.GP_NumPlayersDealtIn_Byte));
            //networkInputs.Add("UnactedRatio", infoStore.GetInfoValue(InfoType.GP_NumUnactedPlayers_Byte) / infoStore.GetInfoValue(InfoType.GP_NumActivePlayers_Byte));

            #region gameStage

            decimal gameStagePreFlop = 0;
            decimal gameStageRiver   = 0;

            if (infoStore.GetInfoValue(InfoType.GP_GameStage_Byte) == 0)
            {
                gameStagePreFlop = 1;
            }
            else if (infoStore.GetInfoValue(InfoType.GP_GameStage_Byte) == 3)
            {
                gameStageRiver = 1;
            }

            networkInputs.Add("GameStagePreFlop", gameStagePreFlop);
            networkInputs.Add("GameStageRiver", gameStageRiver);

            #endregion gameStage

            #region dealerDistance

            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("FirstToAct", (infoStore.GetInfoValue(InfoType.GP_NumActivePlayers_Byte) == infoStore.GetInfoValue(InfoType.GP_NumUnactedPlayers_Byte) ? 1 : 0));
            networkInputs.Add("LastToAct", (infoStore.GetInfoValue(InfoType.GP_NumUnactedPlayers_Byte) == 1 ? 1 : 0));

            #endregion dealerDistance

            networkInputs.Add("ImmediatePotOdds", infoStore.GetInfoValue(InfoType.BP_ImmediatePotOdds_Double));
            //networkInputs.Add("ImpliedPotOdds", 0); //(infoStore.GetInfoValue(InfoType.IO_ImpliedPotOdds_Double))

            decimal potCommitted = 0;
            if (infoStore.GetInfoValue(InfoType.BP_PlayerMoneyInPot_Decimal) > infoStore.GetInfoValue(InfoType.BP_PlayerHandStartingStackAmount_Decimal) / 2)
            {
                potCommitted = 1;
            }

            networkInputs.Add("PotCommitted", potCommitted);
            networkInputs.Add("PotRatio", infoStore.GetInfoValue(InfoType.BP_PlayerMoneyInPot_Decimal) / infoStore.GetInfoValue(InfoType.BP_TotalPotAmount_Decimal));

            #region raise & check ratio

            decimal raiseRatio     = 0;
            decimal checkRatio     = 0;
            decimal totalNumRaises = infoStore.GetInfoValue(InfoType.BP_TotalNumRaises_Byte);
            decimal totalNumCalls  = infoStore.GetInfoValue(InfoType.BP_TotalNumCalls_Byte);
            decimal totalNumChecks = infoStore.GetInfoValue(InfoType.BP_TotalNumChecks_Byte);
            if (totalNumRaises + totalNumCalls + totalNumChecks > 0)
            {
                raiseRatio = totalNumRaises / (totalNumRaises + totalNumCalls + totalNumChecks);
                checkRatio = totalNumChecks / (totalNumRaises + totalNumCalls + totalNumChecks);
            }

            networkInputs.Add("RaiseRatio", raiseRatio);
            networkInputs.Add("CheckRatio", checkRatio);

            #endregion raise & check ratio

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

            /*
             * double betsToCall = infoStore.GetInfoValue(InfoType.BP_BetsToCall_Byte);
             * double betsToCall0 = 0;
             * double betsToCall1 = 0;
             * double betsToCall2Greater = 0;
             *
             * if (betsToCall >= 2)
             *  betsToCall2Greater = 1;
             * else if (betsToCall == 1)
             *  betsToCall1 = 1;
             * else if (betsToCall == 0)
             *  betsToCall0 = 1;
             * else
             *  throw new Exception("This is impossible!!");
             *
             * networkInputs.Add("BetsToCall0", betsToCall0);
             * networkInputs.Add("BetsToCall1", betsToCall1);
             * networkInputs.Add("BetsToCall2Greater", betsToCall2Greater);
             *
             * double betsLastRound1Greater = 0;
             * if (infoStore.GetInfoValue(InfoType.BP_LastRoundBetsToCall_Byte) > 0)
             *  betsLastRound1Greater = 1;
             *
             * networkInputs.Add("BetsLastRound1Greater", betsLastRound1Greater);
             */

            /*
             * double raisedLastRound = 0;
             * if (infoStore.GetInfoValue(InfoType.BP_RaisedLastRound_Bool) == 1)
             *  raisedLastRound = 1;
             *
             * networkInputs.Add("RaisedLastRound", raisedLastRound);
             *
             * double lastActionRaise = 0;
             * if (infoStore.GetInfoValue(InfoType.BP_PlayerLastAction_Short) == 9)
             *  lastActionRaise = 1;
             *
             * networkInputs.Add("LastActionRaise", lastActionRaise);
             */

            //call and raise amounts
            networkInputs.Add("ScaledCallAmount", infoStore.GetInfoValue(InfoType.BP_ScaledCallAmount_Double));
            networkInputs.Add("CallAmountBB", ((decimal)infoStore.GetInfoValue(InfoType.BP_MinimumPlayAmount_Decimal) - (decimal)infoStore.GetInfoValue(InfoType.BP_PlayerBetAmountCurrentRound_Decimal)) == currentDecision.Cache.BigBlind ? 1 : 0);
            //networkInputs.Add("ScaledRaiseToCallAmount", BetsProvider.ScaleRaiseAmount(cache.BigBlind, infoStore.GetInfoValue(InfoType.PAP_RaiseToCallAmount_Amount) - infoStore.GetInfoValue(InfoType.BP_MinimumPlayAmount_Decimal), infoStore.GetInfoValue(InfoType.BP_TotalPotAmount_Decimal)));
            //networkInputs.Add("ScaledRaiseToStealAmount", BetsProvider.ScaleRaiseAmount(cache.BigBlind, infoStore.GetInfoValue(InfoType.PAP_RaiseToStealAmount_Amount) - infoStore.GetInfoValue(InfoType.BP_MinimumPlayAmount_Decimal), infoStore.GetInfoValue(InfoType.BP_TotalPotAmount_Decimal)));

            //WinRatio
            //networkInputs.Add("WRProbCardsWin", infoStore.GetInfoValue(InfoType.WR_CardsOnlyWinPercentage));
            //networkInputs.Add("WRProbCardsOpponentWin", infoStore.GetInfoValue(InfoType.WR_CardsOnlyOpponentWinPercentage));
            networkInputs.Add("WRProbBeat", infoStore.GetInfoValue(InfoType.WR_ProbOpponentHasBetterWRFIXED));
            //networkInputs.Add("WRLastRoundWRChange", infoStore.GetInfoValue(InfoType.WR_CardsOnlyWinPercentageLastRoundChange));
            networkInputs.Add("WRHandIndexTop10Hands", (infoStore.GetInfoValue(InfoType.WR_CardsOnlyWinPercentageIndex) < 0.01m ? 1 : 0));

            //networkInputs.Add("ProbRaiseToBotCheck",infoStore.GetInfoValue(InfoType.PAP_RaiseToBotCheck_Prob));
            //networkInputs.Add("ProbRaiseToBotCall",infoStore.GetInfoValue(InfoType.PAP_RaiseToBotCall_Prob));
            //networkInputs.Add("ProbFoldToBotCall",infoStore.GetInfoValue(InfoType.PAP_FoldToBotCall_Prob));
            networkInputs.Add("ProbRaiseToStealSuccess", infoStore.GetInfoValue(InfoType.PAP_RaiseToStealSuccess_Prob));

            ////////////////////////////////////////////////////////////////////
            ///////// MASSIVE HACK BEGIN ///////////////////////////////////////
            ////////////////////////////////////////////////////////////////////
            //We need to disable the aggression information for fixed marc and ailwyn bots
            //if (currentDecision.RequiredInfoTypeUpdateConfigs.ContainsKey(InfoType.CP_HoleCardsMatchedPlayability))
            //{
            //    string holeCardsMatchedPlayability = currentDecision.RequiredInfoTypeUpdateConfigs[InfoType.CP_HoleCardsMatchedPlayability];
            //    if (aggressionInfoDisbleList.Contains(holeCardsMatchedPlayability))
            //    {
            //        networkInputs.Add("AvgScaledOppPreFlopPlayFreq", AggressionProvider.DEFAULT_pFREQ_PREFLOP);
            //        if (gameStagePreFlop == 1)
            //        {
            //            networkInputs.Add("AvgScaledOppRaiseFreq", AggressionProvider.DEFAULT_rFREQ_PREFLOP);
            //            networkInputs.Add("AvgScaledOppCallFreq", AggressionProvider.DEFAULT_cFREQ_PREFLOP);
            //        }
            //        else
            //        {
            //            networkInputs.Add("AvgScaledOppRaiseFreq", AggressionProvider.DEFAULT_rFREQ_POSTFLOP);
            //            networkInputs.Add("AvgScaledOppCallFreq", AggressionProvider.DEFAULT_cFREQ_POSTFLOP);
            //        }
            //    }
            //    else
            //    {
            //        networkInputs.Add("AvgScaledOppRaiseFreq", infoStore.GetInfoValue(InfoType.AP_AvgScaledOppRaiseFreq_Double));
            //        networkInputs.Add("AvgScaledOppCallFreq", infoStore.GetInfoValue(InfoType.AP_AvgScaledOppCallFreq_Double));
            //        networkInputs.Add("AvgScaledOppPreFlopPlayFreq", infoStore.GetInfoValue(InfoType.AP_AvgScaledOppPreFlopPlayFreq_Double));
            //    }
            //}
            //else
            //{
            //    networkInputs.Add("AvgScaledOppRaiseFreq", infoStore.GetInfoValue(InfoType.AP_AvgScaledOppRaiseFreq_Double));
            //    networkInputs.Add("AvgScaledOppCallFreq", infoStore.GetInfoValue(InfoType.AP_AvgScaledOppCallFreq_Double));
            //    networkInputs.Add("AvgScaledOppPreFlopPlayFreq", infoStore.GetInfoValue(InfoType.AP_AvgScaledOppPreFlopPlayFreq_Double));
            //}

            //All of V4 players get aggression defaults
            networkInputs.Add("AvgScaledOppPreFlopPlayFreq", AggressionProvider.DEFAULT_pFREQ_PREFLOP);
            if (gameStagePreFlop == 1)
            {
                networkInputs.Add("AvgScaledOppRaiseFreq", AggressionProvider.DEFAULT_rFREQ_PREFLOP);
                networkInputs.Add("AvgScaledOppCallFreq", AggressionProvider.DEFAULT_cFREQ_PREFLOP);
            }
            else
            {
                networkInputs.Add("AvgScaledOppRaiseFreq", AggressionProvider.DEFAULT_rFREQ_POSTFLOP);
                networkInputs.Add("AvgScaledOppCallFreq", AggressionProvider.DEFAULT_cFREQ_POSTFLOP);
            }
            ////////////////////////////////////////////////////////////////////
            ///////// MASSIVE HACK END /////////////////////////////////////////
            ////////////////////////////////////////////////////////////////////

            #endregion neuralInputs

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

            //decisionLogStr = aiDecisionData.ToString();

            //decimal playerRemainingStackAmount = currentDecision.Cache.getPlayerStack(currentDecision.PlayerId);
            decimal raiseToCallAmount  = (decimal)infoStore.GetInfoValue(InfoType.PAP_RaiseToCallAmount_Amount);
            decimal raiseToStealAmount = (decimal)infoStore.GetInfoValue(InfoType.PAP_RaiseToStealAmount_Amount);

            if (true)
            {
                //Get the network outputs
                double[] networkInputsArray = null;
                aiDecisionData.returnInput(ref networkInputsArray);
                double[] networkOutput = getPlayerNetworkPrediction(currentDecision.AiConfigStr, networkInputsArray);
                //Debug.Print(Math.Round(networkOutput[0], 2) + ", " + Math.Round(networkOutput[1], 2) + ", " + Math.Round(networkOutput[2], 2) + ", " + Math.Round(networkOutput[3], 2) + ", " + Math.Round(networkOutput[4], 2));

                NeuralAiDecision decision;
                //We use the network outputs and do raises amounts slightly differently for the current genetic distribution
                if (currentDecision.RequiredInfoTypeUpdateConfigs.ContainsKey(InfoType.IS_CURRENT_GENETIC))
                {
                    //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
                    decision = new NeuralAiDecision(networkOutput, !Convert.ToBoolean(gameStageRiver) || checkPossible, randomGen.NextDouble(), true);

                    if (decision.BotAction >= 3)
                    {
                        //If we have set a config for PAP_RaiseToCallAmount_Amount then we limit raises per round to three
                        if (currentDecision.Cache.getPlayerCurrentRoundActions(currentDecision.PlayerId).Count(entry => entry == PokerAction.Raise) >= 2)
                        {
                            raiseToCallAmount  = remainingPlayerStack + (decimal)infoStore.GetInfoValue(InfoType.BP_PlayerBetAmountCurrentRound_Decimal);
                            raiseToStealAmount = raiseToCallAmount;
                        }
                    }
                }
                else
                {
                    //We enable stochastisim on all but the river
                    decision = new NeuralAiDecision(networkOutput, !Convert.ToBoolean(gameStageRiver), randomGen.NextDouble(), false);
                    //Debug.Print("AI Decision - [{0}], [{1}], [{2}], [{3}], [{4}]", networkOutput[0], networkOutput[1], networkOutput[2], networkOutput[3], networkOutput[4]);

                    //Lets put a little double check here for the AI outputs
                    if (checkPossible && decision.BotAction == 0)
                    {
                        decision.BotAction = 1;
                    }
                    else if (!checkPossible && decision.BotAction == 1)
                    {
                        decision.BotAction = 0;
                    }
                }

                //Need to work out WTF is going on!!
#if logging
                lock (locker)
                {
                    if (currentDecision.Cache.getCurrentHandId() == 880)
                    {
                        mem = new System.IO.MemoryStream();
                        bin.Serialize(mem, Encog.Neural.Networks.Structure.NetworkCODEC.NetworkToArray(PlayerNetworkCopy(currentDecision.AiConfigStr)));
                        string networkHash = BitConverter.ToString(md5.ComputeHash(mem.ToArray()));

                        using (System.IO.StreamWriter sw = new System.IO.StreamWriter("aiDecisionsLog.csv", true))
                            sw.WriteLine(currentDecision.Cache.getCurrentHandId() + ", " + currentDecision.Cache.getMostRecentLocalIndex()[1] + ", " + currentDecision.PlayerId + ", " + decision.StochasticDouble + ", ," + aiDecisionData.ToString() + ", ," + Math.Round(networkOutput[0], 2) + ", " + Math.Round(networkOutput[1], 2) + ", " + Math.Round(networkOutput[2], 2) + ", " + Math.Round(networkOutput[3], 2) + ", " + Math.Round(networkOutput[4], 2) + ", " + decision.BotAction + ",," + infoStore.GetInfoValue(InfoType.PAP_RaiseToCallAmount_Amount) + "," + infoStore.GetInfoValue(InfoType.PAP_RaiseToStealAmount_Amount) + ",," + networkHash + ",," + currentDecision.Cache.CurrentHandHash(true));
                        //sw.WriteLine(cache.getCurrentHandId() + ", " + +cache.getMostRecentLocalIndex() + ", " + playerId + ", " + cache.CurrentHandHash(true) + ",," + aiDecisionData.ToString());
                        //sw.WriteLine(currentDecision.Cache.getCurrentHandId() + ", " + currentDecision.Cache.getMostRecentLocalIndex() + ", " + currentDecision.PlayerId + ", " + currentDecision.Cache.CurrentHandHash(true) + ",," + networkInputs["WRProbBeat"]);
                    }
                }
#endif

                //Decision override to prevent horrificly wrong decision
                if (decision.BotAction > 1 && scaledCallCheckEV < -0.2M && scaledRaiseToCallEV < -0.2M && scaledRaiseToStealEV < -0.2M)
                {
                    if (checkPossible)
                    {
                        decision.BotAction = 1;
                    }
                    else
                    {
                        decision.BotAction = 0;
                    }
                }

                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, currentDecision.Cache.getMinimumPlayAmount() - (decimal)infoStore.GetInfoValue(InfoType.BP_PlayerBetAmountCurrentRound_Decimal), 0, currentDecision.Cache.getCurrentHandId(), currentDecision.PlayerId, decisionLogStr, 0));
                }
                else if (decision.BotAction == 3)
                {
                    return(new Play(PokerAction.Raise, raiseToCallAmount, 0, currentDecision.Cache.getCurrentHandId(), currentDecision.PlayerId, decisionLogStr, 0));
                }
                else if (decision.BotAction == 4)
                {
                    return(new Play(PokerAction.Raise, raiseToStealAmount, 0, currentDecision.Cache.getCurrentHandId(), currentDecision.PlayerId, decisionLogStr, 0));
                }
                //else if (decision.BotAction == 4)
                //    return new Play(PokerAction.Raise, playerRemainingStackAmount + (decimal)infoStore.GetInfoValue(InfoType.BP_PlayerBetAmountCurrentRound_Decimal), 0, cache.getCurrentHandId(), playerId, decisionLogStr, 0);
                else
                {
                    throw new Exception("Something has gone wery wong!");
                }
            }

            //return new Play(PokerAction.Fold, 0, 0, cache.getCurrentHandId(), playerId, decisionLogStr, 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);
            decimal currentPotAmount     = infoStore.GetInfoValue(InfoType.BP_TotalPotAmount_Decimal);
            decimal remainingPlayerStack = currentDecision.Cache.getPlayerStack(currentDecision.PlayerId);

            //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 * currentRoundLastRaiseAmount;
                    }
                    else if (randomNumber > 0.45)
                    {
                        additionalNewRaiseAmount = 1.5m * currentRoundLastRaiseAmount;
                    }
                    else
                    {
                        additionalNewRaiseAmount = 1 * currentRoundLastRaiseAmount;
                    }

                    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 + (decimal)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
            if (currentRoundPlayerActions.Count(entry => entry == PokerAction.Raise) >= 2)
            {
                raiseToCallAmountNew  = maximumRaiseAmount;
                raiseToStealAmountNew = maximumRaiseAmount;
            }
            #endregion RaiseAmounts

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

            #region neuralInputs

            #region gameStage

            decimal gameStagePreFlop  = 0;
            decimal gameStagePostFlop = 0;
            decimal gameStageRiver    = 0;

            if (infoStore.GetInfoValue(InfoType.GP_GameStage_Byte) == 0)
            {
                gameStagePreFlop = 1;
            }
            else
            {
                gameStagePostFlop = 1;
            }

            if (infoStore.GetInfoValue(InfoType.GP_GameStage_Byte) == 3)
            {
                gameStageRiver = 1;
            }

            networkInputs.Add("GameStagePreFlop", gameStagePreFlop);
            networkInputs.Add("GameStagePostFlop", gameStagePostFlop);
            networkInputs.Add("GameStageRiver", gameStageRiver);

            #endregion gameStage
            //3 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
            //12 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
            //19 inputs

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

            networkInputs.Add("PotCommitted", potCommitted);
            #endregion
            //20 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
            //24 inputs

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

            #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;
            if (scaledCallCheckEV > 1)
            {
                networkInputs.Add("ScaledCallCheckEV", 1);
            }
            else if (scaledCallCheckEV < -1)
            {
                networkInputs.Add("ScaledCallCheckEV", -1);
            }
            else
            {
                networkInputs.Add("ScaledCallCheckEV", scaledCallCheckEV);
            }
            #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);

            decimal probAllOpponentFoldRaiseToCall  = infoStore.GetInfoValue(InfoType.WR_RaiseToCallStealSuccessProb);
            decimal probAllOpponentFoldRaiseToSteal = (gameStagePreFlop == 1 ? 0 : infoStore.GetInfoValue(InfoType.WR_RaiseToStealSuccessProb));
            long[]  activePlayerIds = currentDecision.Cache.getActivePlayerIds();

            #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
            //28 inputs

            #region PAP
            //probAllOpponentFoldRaiseToSteal == 0 preflop
            networkInputs.Add("ProbRaiseToStealSuccess", ScaleContInput(probAllOpponentFoldRaiseToSteal));
            #endregion
            //29 inputs

            #region PlayerAggression
            //All of V4 players get aggression defaults
            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
            //33 inputs

            #endregion neuralInputs

            NNDataSource aiDecisionData = new NNDataSource(networkInputs.Values.ToArray(), NeuralAINNModelV6.Input_Neurons, true);
            //decisionLogStr = aiDecisionData.ToStringAdv(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
                NeuralAiDecision decision = new NeuralAiDecision(networkOutput, !Convert.ToBoolean(gameStageRiver) /*|| checkPossible*/, randomGen.NextDouble(), true);

                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)
                {
                    return(new Play(PokerAction.Raise, raiseToCallAmountNew, 0, currentDecision.Cache.getCurrentHandId(), currentDecision.PlayerId, decisionLogStr, 0));
                }
                else if (decision.BotAction == 4)
                {
                    return(new Play(PokerAction.Raise, raiseToStealAmountNew, 0, currentDecision.Cache.getCurrentHandId(), currentDecision.PlayerId, decisionLogStr, 0));
                }
                else
                {
                    throw new Exception("Something has gone wery wong!");
                }
            }
        }
Beispiel #7
0
        protected override Play GetDecision()
        {
            Dictionary <string, decimal> networkInputs = new Dictionary <string, decimal>();

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

            #region neuralInputs

            #region gameStage

            decimal gameStagePreFlop  = 0;
            decimal gameStagePostFlop = 0;
            decimal gameStageRiver    = 0;

            if (infoStore.GetInfoValue(InfoType.GP_GameStage_Byte) == 0)
            {
                gameStagePreFlop = 1;
            }
            else
            {
                gameStagePostFlop = 1;
            }

            if (infoStore.GetInfoValue(InfoType.GP_GameStage_Byte) == 3)
            {
                gameStageRiver = 1;
            }

            networkInputs.Add("GameStagePreFlop", gameStagePreFlop);
            networkInputs.Add("GameStagePostFlop", gameStagePostFlop);
            networkInputs.Add("GameStageRiver", gameStageRiver);

            #endregion gameStage
            //3 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
            //12 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
            //19 inputs

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

            networkInputs.Add("PotCommitted", potCommitted);
            #endregion
            //20 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;
            //if ((callCount > 0 || checkCount > 0) && raiseCount > 0)
            //    //We scale our own aggression to be between 1 and 0, 1 being very aggressive, 0 being very passive
            //    currentHandOurAggression = (decimal)((Math.Log10(raiseCount / (callCount + checkCount)) + 2.0) / 3.0);
            //else if (callCount == 0 && checkCount == 0 && raiseCount > 0)
            //    currentHandOurAggression = 1;

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

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

            //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();

            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
            //24 inputs

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

            #region CallEV and CheckPossibilitiy
            //We are only going to use call EV
            //Defined as (Pot * ProbWin) - (Call Amount * ProbLoose)
            decimal additionaCallAmount = currentDecision.Cache.getMinimumPlayAmount() - (decimal)infoStore.GetInfoValue(InfoType.BP_PlayerBetAmountCurrentRound_Decimal);

            //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 actualCallEV = (infoStore.GetInfoValue(InfoType.BP_TotalPotAmount_Decimal) * probWin) - ((1.0m - probWin) * additionaCallAmount);

            //We now have to scale the actualCallEV amount between 1 and -1 as a fraction of the big blind amount
            decimal scaledCallEV = (actualCallEV / currentDecision.Cache.BigBlind) / 5.0m;
            if (scaledCallEV > 1)
            {
                networkInputs.Add("ScaledCallEV", 1);
            }
            else if (scaledCallEV < -1)
            {
                networkInputs.Add("ScaledCallEV", -1);
            }
            else
            {
                networkInputs.Add("ScaledCallEV", scaledCallEV);
            }

            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
            //28 inputs

            #region PAP
            if (gameStagePreFlop == 1)
            {
                networkInputs.Add("ProbRaiseToStealSuccess", ScaleContInput(0));
            }
            else
            {
                networkInputs.Add("ProbRaiseToStealSuccess", ScaleContInput(infoStore.GetInfoValue(InfoType.WR_RaiseToStealSuccessProb)));
            }
            #endregion
            //29 inputs

            #region PlayerAggression
            //All of V4 players get aggression defaults
            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
            //33 inputs

            #endregion neuralInputs

            #region RaiseAmounts
            decimal raiseToCallAmount, raiseToStealAmount;

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

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

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

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

                raiseToStealAmount = 1.5m * raiseToCallAmount;

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

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

            NNDataSource aiDecisionData = new NNDataSource(networkInputs.Values.ToArray(), NeuralAINNModelV5.Input_Neurons, true);
            //decisionLogStr = aiDecisionData.ToStringAdv(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
                NeuralAiDecision decision = new NeuralAiDecision(networkOutput, !Convert.ToBoolean(gameStageRiver) /*|| checkPossible*/, randomGen.NextDouble(), true);

                if (decision.BotAction >= 3)
                {
                    //We need to cap the raise to steal amount as it's probably too large!!
                    //if (raiseToStealAmount > 1.3m * infoStore.GetInfoValue(InfoType.BP_TotalPotAmount_Decimal))
                    //    raiseToStealAmount = 1.3m * infoStore.GetInfoValue(InfoType.BP_TotalPotAmount_Decimal);

                    //if (raiseToCallAmount > 1.3m * infoStore.GetInfoValue(InfoType.BP_TotalPotAmount_Decimal))
                    //    raiseToCallAmount = 1.3m * infoStore.GetInfoValue(InfoType.BP_TotalPotAmount_Decimal);

                    //If we have set a config for PAP_RaiseToCallAmount_Amount then we limit raises per round to three
                    if (currentRoundPlayerActions.Count(entry => entry == PokerAction.Raise) >= 2)
                    {
                        raiseToCallAmount  = currentDecision.Cache.getPlayerStack(currentDecision.PlayerId) + (decimal)infoStore.GetInfoValue(InfoType.BP_PlayerBetAmountCurrentRound_Decimal);
                        raiseToStealAmount = raiseToCallAmount;
                    }
                }

                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, additionaCallAmount, 0, currentDecision.Cache.getCurrentHandId(), currentDecision.PlayerId, decisionLogStr, 0));
                }
                else if (decision.BotAction == 3)
                {
                    return(new Play(PokerAction.Raise, raiseToCallAmount, 0, currentDecision.Cache.getCurrentHandId(), currentDecision.PlayerId, decisionLogStr, 0));
                }
                else if (decision.BotAction == 4)
                {
                    return(new Play(PokerAction.Raise, raiseToStealAmount, 0, currentDecision.Cache.getCurrentHandId(), currentDecision.PlayerId, decisionLogStr, 0));
                }
                else
                {
                    throw new Exception("Something has gone wery wong!");
                }
            }
        }
        protected override Play GetDecision()
        {
            //We need to write to the decision string here!
            Dictionary <string, decimal> networkInputs = new Dictionary <string, decimal>();

            networkInputs.Add("ProbCardsWin", infoStore.GetInfoValue(InfoType.WR_CardsOnlyWinPercentage));
            networkInputs.Add("ProbCardsWinOpponentWin", (1 - infoStore.GetInfoValue(InfoType.WR_CardsOnlyWinPercentage)) / (infoStore.GetInfoValue(InfoType.GP_NumActivePlayers_Byte) - 1));

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

            if (currentGameStage == 0)
            {
                postFlop = 0;
            }
            else
            {
                postFlop = 1;
            }

            networkInputs.Add("PostFlop", postFlop);

            decimal currentRoundBetAmount = currentDecision.Cache.getPlayerCurrentRoundBetAmount(currentDecision.PlayerId);
            decimal minCallAmount         = infoStore.GetInfoValue(InfoType.BP_MinimumPlayAmount_Decimal);
            decimal raiseToCallAmount     = (infoStore.GetInfoValue(InfoType.PAP_RaiseToCallAmount_Amount));

            decimal scaledCurrentRoundMinimumPlayAmount = (minCallAmount / currentDecision.Cache.MaxStack);
            decimal scaledCurrentRoundPlayerBetAmount   = (currentRoundBetAmount / currentDecision.Cache.MaxStack);

            if (scaledCurrentRoundMinimumPlayAmount > 1)
            {
                scaledCurrentRoundMinimumPlayAmount = 1;
            }
            if (scaledCurrentRoundPlayerBetAmount > 1)
            {
                scaledCurrentRoundPlayerBetAmount = 1;
            }

            networkInputs.Add("ScaledCurrentRoundMinimumPlayAmount", scaledCurrentRoundMinimumPlayAmount);
            networkInputs.Add("ScaledCurrentRoundPlayerBetAmount", scaledCurrentRoundPlayerBetAmount);

            //(probCardsWin, probCardsWinOpponentWin, postFlop, scaledCurrentRoundMinimumPlayAmount, scaledCurrentRoundPlayerBetAmount);
            NNDataSource aiDecisionData = new NNDataSource(networkInputs.Values.ToArray(), NeuralAINNModelV2.Input_Neurons);

            //decisionLogStr = aiDecisionData.ToString();

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

            NeuralAiDecision decision = new NeuralAiDecision(networkOutput);
            //Debug.Print("AI Decision - [{0}], [{1}], [{2}], [{3}], [{4}]", networkOutput[0], networkOutput[1], networkOutput[2], networkOutput[3], networkOutput[4]);
            Play botAction;

            if (decision.BotAction == 0)
            {
                botAction = new Play(PokerAction.Fold, 0, 0, currentDecision.Cache.getCurrentHandId(), currentDecision.PlayerId, decisionLogStr, 0);
            }
            else if (decision.BotAction == 1)
            {
                botAction = new Play(PokerAction.Call, currentDecision.Cache.getMinimumPlayAmount() - currentRoundBetAmount, 0, currentDecision.Cache.getCurrentHandId(), currentDecision.PlayerId, decisionLogStr, 0);
            }
            else if (decision.BotAction == 2)
            {
                botAction = new Play(PokerAction.Raise, (decimal)raiseToCallAmount, 0, currentDecision.Cache.getCurrentHandId(), currentDecision.PlayerId, decisionLogStr, 0);
            }
            else
            {
                throw new Exception("Something has gone wery wong!");
            }

            //Call if already raised pre flop
            if (infoStore.GetInfoValue(InfoType.GP_GameStage_Byte) == 0 && botAction.Action == PokerAction.Raise)
            {
                //Split down into seperate IF to make sure there is not too much of a performance hit
                if (currentDecision.Cache.getPlayerCurrentRoundActions(currentDecision.PlayerId).Contains(PokerAction.Raise))
                {
                    botAction.Action = PokerAction.Call;
                    botAction.Amount = (decimal)(minCallAmount - currentRoundBetAmount);
                }
            }

            return(botAction);
        }
Beispiel #9
0
        protected override Play GetDecision()
        {
            //List<double> networkInputs = new List<double>();
            Dictionary <string, decimal> networkInputs = new Dictionary <string, decimal>();

            //We need to write to the decision string here!

            #region neuralInputs

            //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));
            networkInputs.Add("HoleCardsFlushDraw", infoStore.GetInfoValue(InfoType.CP_HoleCardsFlushDraw_Bool));

            networkInputs.Add("HoleCardsOuterStraightDraw", infoStore.GetInfoValue(InfoType.CP_HoleCardsOuterStraightDrawWithHC_Bool));
            networkInputs.Add("HoleCardsInnerStraightDraw", infoStore.GetInfoValue(InfoType.CP_HoleCardsInnerStraightDrawWithHC_Bool));
            networkInputs.Add("HoleCardsTopOrTwoPair", infoStore.GetInfoValue(InfoType.CP_HoleCardsTopOrTwoPair_Bool));
            networkInputs.Add("HoleCardsAorKinHand", infoStore.GetInfoValue(InfoType.CP_HoleCardsAOrKInHand_Bool));
            networkInputs.Add("HoleCards3KindOrBetter", infoStore.GetInfoValue(InfoType.CP_HoleCards3KindOrBetterMadeWithHC_Bool));
            networkInputs.Add("AonBoard", infoStore.GetInfoValue(InfoType.CP_AOnBoard_Bool));
            networkInputs.Add("KonBoard", infoStore.GetInfoValue(InfoType.CP_KOnBoard_Bool));
            networkInputs.Add("AKQRatio", infoStore.GetInfoValue(InfoType.CP_AKQToBoardRatio_Real));

            networkInputs.Add("FlushPossible", infoStore.GetInfoValue(InfoType.CP_FlushPossible_Bool));
            networkInputs.Add("StraightPossible", infoStore.GetInfoValue(InfoType.CP_StraightPossible_Bool));
            networkInputs.Add("TableStraightDraw", infoStore.GetInfoValue(InfoType.CP_TableStraightDraw_Bool));
            networkInputs.Add("TableFlushDraw", infoStore.GetInfoValue(InfoType.CP_TableFlushDraw_Bool));

            //DealtInRatio, ActiveRatio and UnactedRatio
            networkInputs.Add("DealtInRatio", infoStore.GetInfoValue(InfoType.GP_NumPlayersDealtIn_Byte) / infoStore.GetInfoValue(InfoType.GP_NumTableSeats_Byte));
            networkInputs.Add("ActiveRatio", infoStore.GetInfoValue(InfoType.GP_NumActivePlayers_Byte) / infoStore.GetInfoValue(InfoType.GP_NumPlayersDealtIn_Byte));
            networkInputs.Add("UnactedRatio", infoStore.GetInfoValue(InfoType.GP_NumUnactedPlayers_Byte) / infoStore.GetInfoValue(InfoType.GP_NumActivePlayers_Byte));

            #region gameStage

            decimal gameStagePreFlop   = 0;
            decimal gameStageFlop      = 0;
            decimal gameStageTurnRiver = 0;

            if (infoStore.GetInfoValue(InfoType.GP_GameStage_Byte) == 0)
            {
                gameStagePreFlop = 1;
            }
            else if (infoStore.GetInfoValue(InfoType.GP_GameStage_Byte) == 1)
            {
                gameStageFlop = 1;
            }
            else
            {
                gameStageTurnRiver = 1;
            }

            networkInputs.Add("GameStagePreFlop", gameStagePreFlop);
            networkInputs.Add("GameStageFlop", gameStageFlop);
            networkInputs.Add("GameStageTurnRiver", gameStageTurnRiver);

            #endregion gameStage

            #region dealerDistance

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

            #endregion dealerDistance

            networkInputs.Add("ImmediatePotOdds", infoStore.GetInfoValue(InfoType.BP_ImmediatePotOdds_Double));
            networkInputs.Add("ImpliedPotOdds", 0); //(infoStore.GetInfoValue(InfoType.IO_ImpliedPotOdds_Double))

            decimal potCommitted = 0;
            if (infoStore.GetInfoValue(InfoType.BP_PlayerMoneyInPot_Decimal) > infoStore.GetInfoValue(InfoType.BP_PlayerHandStartingStackAmount_Decimal) / 2)
            {
                potCommitted = 1;
            }

            networkInputs.Add("PotCommitted", potCommitted);
            networkInputs.Add("PotRatio", infoStore.GetInfoValue(InfoType.BP_PlayerMoneyInPot_Decimal) / infoStore.GetInfoValue(InfoType.BP_TotalPotAmount_Decimal));

            #region raise & check ratio

            decimal raiseRatio     = 0;
            decimal checkRatio     = 0;
            decimal totalNumRaises = infoStore.GetInfoValue(InfoType.BP_TotalNumRaises_Byte);
            decimal totalNumCalls  = infoStore.GetInfoValue(InfoType.BP_TotalNumCalls_Byte);
            decimal totalNumChecks = infoStore.GetInfoValue(InfoType.BP_TotalNumChecks_Byte);
            if (totalNumRaises + totalNumCalls + totalNumChecks > 0)
            {
                raiseRatio = totalNumRaises / (totalNumRaises + totalNumCalls + totalNumChecks);
                checkRatio = totalNumChecks / (totalNumRaises + totalNumCalls + totalNumChecks);
            }

            networkInputs.Add("RaiseRatio", raiseRatio);
            networkInputs.Add("CheckRatio", checkRatio);

            #endregion raise & check ratio

            decimal betsToCall         = infoStore.GetInfoValue(InfoType.BP_BetsToCall_Byte);
            decimal betsToCall0        = 0;
            decimal betsToCall1        = 0;
            decimal betsToCall2Greater = 0;

            if (betsToCall >= 2m)
            {
                betsToCall2Greater = 1;
            }
            else if (betsToCall == 1m)
            {
                betsToCall1 = 1;
            }
            else if (betsToCall == 0)
            {
                betsToCall0 = 1;
            }
            else
            {
                throw new Exception("This is impossible!!");
            }

            networkInputs.Add("BetsToCall0", betsToCall0);
            networkInputs.Add("BetsToCall1", betsToCall1);
            networkInputs.Add("BetsToCall2Greater", betsToCall2Greater);

            decimal betsLastRound1Greater = 0;
            if (infoStore.GetInfoValue(InfoType.BP_LastRoundBetsToCall_Byte) > 0)
            {
                betsLastRound1Greater = 1;
            }

            networkInputs.Add("BetsLastRound1Greater", betsLastRound1Greater);
            networkInputs.Add("CurrentCallAmountLarger4BB", infoStore.GetInfoValue(InfoType.BP_CurrentCallAmountLarger4BB));

            decimal raisedLastRound = 0;
            if (infoStore.GetInfoValue(InfoType.BP_RaisedLastRound_Bool) == 1)
            {
                raisedLastRound = 1;
            }

            networkInputs.Add("RaisedLastRound", raisedLastRound);

            decimal lastActionRaise = 0;
            if (infoStore.GetInfoValue(InfoType.BP_PlayerLastAction_Short) == 9)
            {
                lastActionRaise = 1;
            }

            networkInputs.Add("LastActionRaise", lastActionRaise);

            #region winPercentage

            networkInputs.Add("probCardsWin", infoStore.GetInfoValue(InfoType.WR_CardsOnlyWinPercentage));
            networkInputs.Add("probCardsWeightedWin", infoStore.GetInfoValue(InfoType.WR_CardsOnlyWinPercentage));

            //networkInputs.Add("probCardsWinOpponentWin",infoStore.GetInfoValue(InfoType.WR_CardsOnlyOpponentWinPercentage));
            networkInputs.Add("probCardsWinOpponentWin", (1 - infoStore.GetInfoValue(InfoType.WR_CardsOnlyWinPercentage)) / (infoStore.GetInfoValue(InfoType.GP_NumActivePlayers_Byte) - 1));

            //networkInputs.Add("probCardsOpponentWeightedWin",infoStore.GetInfoValue(InfoType.WR_CardsOnlyOpponentWinPercentage));
            networkInputs.Add("probCardsOpponentWeightedWin", (1 - infoStore.GetInfoValue(InfoType.WR_CardsOnlyWinPercentage)) / (infoStore.GetInfoValue(InfoType.GP_NumActivePlayers_Byte) - 1));

            networkInputs.Add("probCardsOnlyWinPercentageLastRoundChange", infoStore.GetInfoValue(InfoType.WR_CardsOnlyWinPercentageLastRoundChange));

            #endregion winPercentage

            #region PAP

            networkInputs.Add("ProbRaiseToBotCheck", infoStore.GetInfoValue(InfoType.PAP_RaiseToBotCheck_Prob));
            networkInputs.Add("ProbRaiseToBotCall", infoStore.GetInfoValue(InfoType.PAP_RaiseToBotCall_Prob));
            networkInputs.Add("ProbFoldToBotCall", infoStore.GetInfoValue(InfoType.PAP_FoldToBotCall_Prob));
            networkInputs.Add("ProbRaiseToStealSuccess", infoStore.GetInfoValue(InfoType.PAP_RaiseToStealSuccess_Prob));

            #endregion PAP

            #endregion neuralInputs

            //We have 53 Inputs

            /*
             *  AAPocketPair, KKPocketPair,AKPocket,OtherHighPocketPair,OtherLowPocketPair,HoleCardTrouble,midConnectorPocket,lowConnectorPocket,suitedPocket,holeCardsFlushDraw;
             *  holeCardsOuterStraightDraw,holeCardsInnerStraightDraw,holeCardsTopOrTwoPair,holeCardsAorK,holeCards3KindOrBetter, aceOnBoard,kingOnBoard,tableAKQRatio;
             *  tableFlushPossible, tableStraightPossible,tableStraightDraw, tableFlushDraw // 22 Card Types
             *
             *  dealtInRatio, activeRatio,unactedRatio,stagePreFlop,stageFlop,stageTurnRiver,tablePositionEarly,tablePositionMid, tablePositionLate // 9 Game Types
             *
             *  imPotOdds,impliedPotOdds, potCommitted, potRatio, raiseRatio, checkRatio,betsToCall0,betsToCall1,betsToCall2Greater,betsLastRound1Greater,callAmountGreaterThan4BB
             *  raisedLastRound, lastActionRaise // 13 Bet Types
             *
             *  probCardsWin,probCardsWeightedWin,probCardsOpponentWin,probCardsWeightedOpponentWin,cardsWinPercentageLastRoundChange; // 5 Monto Carlo Types
             *
             *  probRaiseToBotCheck,probRaiseToBotCall,probFoldToBotCall,probRaiseToStealSuccess // 4 Prediction Types
             */

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

            //decisionLogStr = aiDecisionData.ToString();

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

            NeuralAiDecision decision = new NeuralAiDecision(networkOutput[0], networkOutput[1], networkOutput[2], networkOutput[3], networkOutput[4]);
            //Debug.Print("AI Decision - [{0}], [{1}], [{2}], [{3}], [{4}]", networkOutput[0], networkOutput[1], networkOutput[2], networkOutput[3], networkOutput[4]);

            decimal raiseToCallAmount          = (infoStore.GetInfoValue(InfoType.PAP_RaiseToCallAmount_Amount));
            decimal raiseToStealAmount         = (infoStore.GetInfoValue(InfoType.PAP_RaiseToStealAmount_Amount));
            decimal minCallAmount              = infoStore.GetInfoValue(InfoType.BP_MinimumPlayAmount_Decimal);
            decimal currentRoundBetAmount      = currentDecision.Cache.getPlayerCurrentRoundBetAmount(currentDecision.PlayerId);
            decimal playerRemainingStackAmount = currentDecision.Cache.getPlayerStack(currentDecision.PlayerId);

            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.Call, currentDecision.Cache.getMinimumPlayAmount() - currentRoundBetAmount, 0, currentDecision.Cache.getCurrentHandId(), currentDecision.PlayerId, decisionLogStr, 0));
            }
            else if (decision.BotAction == 2)
            {
                return(new Play(PokerAction.Raise, (decimal)raiseToCallAmount, 0, currentDecision.Cache.getCurrentHandId(), currentDecision.PlayerId, decisionLogStr, 0));
            }
            else if (decision.BotAction == 3)
            {
                return(new Play(PokerAction.Raise, (decimal)raiseToStealAmount, 0, currentDecision.Cache.getCurrentHandId(), currentDecision.PlayerId, decisionLogStr, 0));
            }
            else if (decision.BotAction == 4)
            {
                return(new Play(PokerAction.Raise, playerRemainingStackAmount + currentRoundBetAmount, 0, currentDecision.Cache.getCurrentHandId(), currentDecision.PlayerId, decisionLogStr, 0));
            }
            else
            {
                throw new Exception("Something has gone wery wong!");
            }
        }