public override Task <GameActionEntity> GetAction(List <ActionType> possibleActions, int amountToCall) { var infoSet = new InformationSet <ActionBucket>(); infoSet.ActionHistory = actionHistory; infoSet.CardBucket = handBucket; RegretGameNode <ActionBucket> gameNode; trainedTree.TryGetValue(infoSet.GetLongHashCode(), out gameNode); if (gameNode == null) { // this should never occur randomBot.ChipStack = this.ChipStack; return(randomBot.GetAction(possibleActions, amountToCall)); } else { var optimalStrategy = gameNode.calculateAverageStrategy(); var rand = new Random(); double randomValue = rand.NextDouble(); bool isCallActionEnabled = (optimalStrategy.Count == 5); int index = 0; double sumPercent = 0; ActionBucket selectedActionBucket = ActionBucket.None; foreach (ActionBucket action in Enum.GetValues(typeof(ActionBucket))) { if (action == ActionBucket.None) { continue; } if (action == ActionBucket.Call && !isCallActionEnabled) { continue; } double newSumPercent = sumPercent + optimalStrategy[index]; if (randomValue >= sumPercent && randomValue <= newSumPercent) { selectedActionBucket = action; break; } sumPercent = newSumPercent; index++; } ActionType selectedAction = ActionAbstracter.MapToAction(selectedActionBucket, amountToCall); int betSize = 0; switch (selectedAction) { case ActionType.Bet: case ActionType.Raise: betSize = ActionAbstracter.GetBetSize(selectedActionBucket, amountToCall, currentGame.PotSize); break; case ActionType.Call: betSize = amountToCall; break; } if (!possibleActions.Contains(selectedAction)) { // in all-in scenarios actions from bot may differ from possible actions switch (selectedAction) { case ActionType.Bet: case ActionType.Raise: case ActionType.Check: if (possibleActions.Contains(ActionType.Call)) { selectedAction = ActionType.Call; } break; default: throw new Exception("Selected action is illegal!"); } } if (ChipStack < betSize) { betSize = this.ChipStack; } return(Task.FromResult <GameActionEntity>(new GameActionEntity { ActionType = selectedAction, Amount = betSize, PlayerId = this.Id })); } }
public override Task <GameActionEntity> GetAction(List <ActionType> possibleActions, int amountToCall) { var possibleFeatureActions = new List <FeatureAction>(); foreach (var possibleAction in possibleActions) { var featureAction = FeatureActionAbstracter.FromActionType(possibleAction); if (!possibleFeatureActions.Contains(featureAction)) { possibleFeatureActions.Add(featureAction); } } var currentPhasehistory = actionHistoriesPerPhase.FirstOrDefault(x => x.Phase == currentGame.Phase); Positioning opponentPositioning = Positioning.None; Aggression opponentAggression = Aggression.None; if (currentGame.Phase > GamePhase.PreFlop) { opponentPositioning = getOpponentPositioning(currentPhasehistory.ActionHistory.Count); opponentAggression = getOpponentAggression(opponentPositioning); } var counterAction = opponent.GetCounterAction(possibleFeatureActions, currentPhasehistory.ActionHistory, currentGame.Phase, opponentAggression, opponentPositioning); ActionBucket selectedActionBucket = ActionBucket.None; if (counterAction == null) { if (currentGame.Phase == GamePhase.PreFlop) { switch (opponent.PlayStyle) { case PlayStyle.LooseAggressive: case PlayStyle.LoosePassive: if (this.IsBigBlind) { selectedActionBucket = ActionBucket.LowBet; } else { if (startHandBucket >= StartHandBucket.VeryBad) { selectedActionBucket = ActionBucket.LowBet; } else { selectedActionBucket = ActionBucket.Pass; } } break; case PlayStyle.TightAggressive: case PlayStyle.TightPassive: //play hyper aggressive selectedActionBucket = ActionBucket.LowBet; break; } } else { switch (opponent.PlayStyle) { case PlayStyle.LooseAggressive: //play TightAggressive if (handStrengthBucket >= HandStrengthBucket.HighCardAce) { selectedActionBucket = ActionBucket.LowBet; } else { selectedActionBucket = ActionBucket.Pass; } break; case PlayStyle.LoosePassive: selectedActionBucket = ActionBucket.LowBet; break; case PlayStyle.TightAggressive: //play LooseAggressive if (handStrengthBucket >= HandStrengthBucket.LowPair) { selectedActionBucket = ActionBucket.LowBet; } else { selectedActionBucket = ActionBucket.Pass; } break; case PlayStyle.TightPassive: //play LooseAggressive if (handStrengthBucket >= HandStrengthBucket.HighCardElse) { selectedActionBucket = ActionBucket.LowBet; } else { selectedActionBucket = ActionBucket.Pass; } break; } } } else { if (currentGame.Phase == GamePhase.PreFlop) { switch (counterAction) { case FeatureAction.Bet: if (startHandBucket > StartHandBucket.Worst) { selectedActionBucket = ActionBucket.LowBet; } break; case FeatureAction.Pass: if (startHandBucket < StartHandBucket.Bad) { selectedActionBucket = ActionBucket.Pass; } break; } } else { switch (counterAction) { case FeatureAction.Bet: selectedActionBucket = ActionBucket.LowBet; break; case FeatureAction.Pass: if (handStrengthBucket < HandStrengthBucket.LowPair) { selectedActionBucket = ActionBucket.Pass; } break; } } } switch (selectedActionBucket) { case ActionBucket.None: //no counter move has been found. Fall back to randomness randomBot.ChipStack = this.ChipStack; return(randomBot.GetAction(possibleActions, amountToCall)); default: ActionType selectedAction = ActionAbstracter.MapToAction(selectedActionBucket, amountToCall); int betSize = 0; switch (selectedAction) { case ActionType.Bet: case ActionType.Raise: betSize = ActionAbstracter.GetBetSize(selectedActionBucket, amountToCall, currentGame.PotSize); break; case ActionType.Call: betSize = amountToCall; break; } if (!possibleActions.Contains(selectedAction)) { switch (selectedAction) { case ActionType.Bet: case ActionType.Raise: case ActionType.Check: if (possibleActions.Contains(ActionType.Call)) { selectedAction = ActionType.Call; } break; default: throw new Exception("Selected action is illegal!"); } } if (ChipStack < betSize) { betSize = this.ChipStack; } return(Task.FromResult <GameActionEntity>( new GameActionEntity { ActionType = selectedAction, Amount = betSize, PlayerId = this.Id })); } }