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