Exemplo n.º 1
0
        public void SimpleStatement()
        {
            var ab = new ActionBucket
            {
                bar = "~`!1@2#3$4%5^6&7*8(9)0_-+={[}]:;\"\"<,<.?//*-+.a string pointed to by bar"
            };

            Func<Int64, Int64, Int64, Int64, ActionBucket> f = (a, b, c, d) => ab;
            var s = new TemplateDictionary
            {
                {"foo", f}
            };

            const string text = "$foo(1L,2L,3L,4L).func( 'a string', 0L )[1L,2L][1L,2L].func( 'adfasdfad', 92321312L )[123123L,123123L].bar";

            var result1 = Template.ImmediateApply(s, text);
            Assert.IsFalse(result1.Errors.ContainsError());
            Assert.IsFalse(result1.Errors.ContainsWarning());
            Assert.AreEqual(ab.bar, result1.Output);

            var result2 = Template.CompileAndRun("test", text, s);
            Assert.IsFalse(result2.Errors.ContainsError());
            Assert.IsFalse(result2.Errors.ContainsWarning());
            Assert.AreEqual(ab.bar, result2.Output);
        }
        /// <summary>
        /// Maps the action bucket to a real action
        /// the amount to call determines whether the real action will be check, respectively fold or bet, respectively raise.
        /// </summary>
        /// <param name="action">the abstracted action</param>
        /// <param name="amountToCall">current amount to call</param>
        /// <returns>real action</returns>
        public static ActionType MapToAction(ActionBucket action, int amountToCall)
        {
            switch (action)
            {
            case ActionBucket.Call:
                return(ActionType.Call);

            case ActionBucket.Pass:
                if (amountToCall == 0)
                {
                    return(ActionType.Check);
                }
                else
                {
                    return(ActionType.Fold);
                }

            case ActionBucket.LowBet:
            case ActionBucket.HighBet:
            case ActionBucket.MediumBet:
                if (amountToCall == 0)
                {
                    return(ActionType.Bet);
                }
                else
                {
                    return(ActionType.Raise);
                }
            }

            return(ActionType.Illegal);
        }
Exemplo n.º 3
0
Arquivo: Timer.cs Projeto: ktj007/mmo
 private Timer()
 {
     for (var index = 0; index < BucketCount; ++index)
     {
         _buckets[index] = new ActionBucket();
     }
 }
Exemplo n.º 4
0
        private float getProbability(ActionBucket bucket, List <float> optimalStrategy)
        {
            bool isCallActionEnabled = (optimalStrategy.Count == 5);
            int  passIndex           = 0;
            int  callIndex           = 1;
            int  lowBetIndex         = 2;
            int  mediumBetIndex      = 3;
            int  highBetIndex        = 4;

            if (!isCallActionEnabled)
            {
                lowBetIndex    = 1;
                mediumBetIndex = 2;
                highBetIndex   = 3;
            }

            float passProbability = optimalStrategy[passIndex];
            float callProbability = optimalStrategy[callIndex];
            float betProbability  = optimalStrategy[lowBetIndex] + optimalStrategy[mediumBetIndex] + optimalStrategy[highBetIndex];

            switch (bucket)
            {
            case ActionBucket.Pass:
                return(optimalStrategy[passIndex]);

            case ActionBucket.Call:
                if (isCallActionEnabled)
                {
                    return(optimalStrategy[callIndex]);
                }
                else
                {
                    return(0);
                }

            case ActionBucket.HighBet:
                return(optimalStrategy[highBetIndex]);

            case ActionBucket.LowBet:
                return(optimalStrategy[lowBetIndex]);

            case ActionBucket.MediumBet:
                return(optimalStrategy[mediumBetIndex]);

            default:
                throw new NotImplementedException("ActionBucket not implemented!");
            }
        }
        /// <summary>
        /// Maps the action bucket to an even more abstracted feature action
        /// </summary>
        /// <param name="actionBucket"></param>
        /// <returns></returns>
        public static FeatureAction FromActionBucket(ActionBucket actionBucket)
        {
            switch (actionBucket)
            {
            case ActionBucket.Call:
                return(FeatureAction.Call);

            case ActionBucket.LowBet:
            case ActionBucket.MediumBet:
            case ActionBucket.HighBet:
                return(FeatureAction.Bet);

            case ActionBucket.Pass:
                return(FeatureAction.Pass);

            default:
                throw new NotImplementedException("Action bucket not supported");
            }
        }
Exemplo n.º 6
0
        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
                }));
            }
        }
Exemplo n.º 7
0
        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
                }));
            }
        }
        /// <summary>
        /// Minimise exploitability by mapping the bucket based on the distance to the nearest neighbours
        /// </summary>
        /// <param name="amount"></param>
        /// <param name="low"></param>
        /// <param name="high"></param>
        /// <param name="lowBucket"></param>
        /// <param name="highBucket"></param>
        /// <returns>action bucket</returns>
        private static ActionBucket getBucketByDistanceProbability(int amount, int low, int high, ActionBucket lowBucket, ActionBucket highBucket)
        {
            var     random = new Random();
            int     distanceAmountToLow       = amount - low;
            int     distanceLowToHigh         = high - low;
            decimal probabilityHigh           = (decimal)(distanceAmountToLow / distanceLowToHigh) * 100;
            int     probabilityHighPercentage = (int)Math.Round(probabilityHigh);
            int     randomValue = random.Next(1, 100);

            if (randomValue <= probabilityHighPercentage)
            {
                return(highBucket);
            }
            else
            {
                return(lowBucket);
            }
        }
        /// <summary>
        /// Maps the action bucket based on the current amount to call and the pot size to a suitable bet size.
        /// </summary>
        /// <param name="action">abstracted action</param>
        /// <param name="amountToCall">current amount to call (if this is zero, the player is betting, otherwise the player is raising)</param>
        /// <param name="potSize">current pot size</param>
        /// <returns>bet size</returns>
        public static int GetBetSize(ActionBucket action, int amountToCall, int potSize)
        {
            int currentMoneyInPot = (potSize - amountToCall) / 2;
            int betSize           = 0;

            if (amountToCall == 0)
            {
                switch (action)
                {
                case ActionBucket.HighBet:
                    betSize = HeadsupGame.StackSize - currentMoneyInPot;
                    break;

                case ActionBucket.MediumBet:
                    betSize = potSize;
                    break;

                case ActionBucket.LowBet:
                    betSize = potSize / 2;
                    break;
                }

                if (betSize + currentMoneyInPot > HeadsupGame.StackSize)
                {
                    betSize = HeadsupGame.StackSize - currentMoneyInPot;
                }
            }
            else
            {
                int betSizeFactor = 0;
                if (amountToCall == HeadsupGame.SmallBlindSize)
                {
                    betSizeFactor = HeadsupGame.BigBlindSize;
                }
                else
                {
                    betSizeFactor = amountToCall;
                }

                switch (action)
                {
                case ActionBucket.HighBet:
                    betSize = HeadsupGame.StackSize - currentMoneyInPot;
                    break;

                case ActionBucket.MediumBet:
                    betSize = betSizeFactor * 3;
                    break;

                case ActionBucket.LowBet:
                    betSize = betSizeFactor * 2;
                    break;
                }
            }

            if (potSize + betSize > HeadsupGame.StackSize * 2)
            {
                int opponentMoneyInPot       = potSize - currentMoneyInPot;
                int maxAmountOpponentCanCall = HeadsupGame.StackSize - opponentMoneyInPot;
                if (maxAmountOpponentCanCall > 0)
                {
                    betSize = amountToCall + maxAmountOpponentCanCall;
                }
                else
                {
                    betSize = (HeadsupGame.StackSize * 2 - potSize);
                }

                if (betSize < 0)
                {
                    betSize = 0;
                }
            }

            return(betSize);
        }
Exemplo n.º 10
0
Arquivo: Timer.cs Projeto: ktj007/mmo
 private Timer()
 {
     for (var index = 0; index < BucketCount; ++index)
         _buckets[index] = new ActionBucket();
 }
        /// <summary>
        /// Traverses the sub tree of the passed hand buckets recursively. Calculates and then backpropagates the counter factual regret for each node.
        /// </summary>
        /// <param name="gameState"></param>
        /// <param name="handBuckets"></param>
        /// <param name="actions"></param>
        /// <param name="probabilityPlayer1">probability of player 1 to reach this node</param>
        /// <param name="probabilityPlayer2">probability of player 2 to reach this node</param>
        /// <returns></returns>
        private float CalculateCounterFactualRegret(HeadsUpGameState gameState, byte[] handBuckets, List <ActionBucket> actions, float probabilityPlayer1, float probabilityPlayer2)
        {
            int plays       = actions.Count;
            int playerIndex = plays % 2;

            var          newState   = gameState.GetCopy();
            ActionBucket lastAction = ActionBucket.None;

            if (actions.Count > 0)
            {
                lastAction = actions[plays - 1];
            }
            ActionBucket secondLastAction = ActionBucket.None;

            if (actions.Count > 1)
            {
                secondLastAction = actions[plays - 2];
            }

            bool nextActionCallEnabled = true;
            bool phaseChanged          = false;

            //the last actions determine whether the next phase has to be set or whether the game (i.e. the recursion) ends
            switch (lastAction)
            {
            case ActionBucket.Pass:
                if (secondLastAction == ActionBucket.LowBet ||
                    secondLastAction == ActionBucket.HighBet ||
                    secondLastAction == ActionBucket.MediumBet)
                {
                    int payoff = (newState.PotSize - newState.AmountToCall) / 2;
                    return((playerIndex == 0) ? payoff : -payoff);
                }

                switch (secondLastAction)
                {
                case ActionBucket.None:
                    return((playerIndex == 0) ? HeadsupGame.SmallBlindSize : -HeadsupGame.SmallBlindSize);

                case ActionBucket.Call:
                    newState.SetNextPhase(newState.Phase);
                    phaseChanged = true;
                    break;

                case ActionBucket.Pass:
                    //check if last pass count is dividable by 2 (then it's a new phase)
                    int lastActionPassCount = 0;
                    for (int i = actions.Count - 1; i >= 0; i--)
                    {
                        if (actions[i] == ActionBucket.Pass)
                        {
                            lastActionPassCount++;
                        }
                        else
                        {
                            //special case: if it's first round, call pass results in ending the round
                            if ((actions[i] == ActionBucket.Call && i == 0) &&
                                actions.Count > 2 && actions[i + 1] == ActionBucket.Pass)
                            {
                                lastActionPassCount--;
                            }
                            break;
                        }
                    }

                    if (lastActionPassCount % 2 == 0)
                    {
                        newState.SetNextPhase(newState.Phase);
                        phaseChanged = true;
                    }
                    break;
                }
                nextActionCallEnabled = false;
                break;

            case ActionBucket.Call:
                newState.PotSize     += newState.AmountToCall;
                newState.AmountToCall = 0;
                //special case for first round: big blind needs to check or bet
                if (actions.Count == 1)
                {
                    nextActionCallEnabled = false;
                }
                else
                {
                    newState.SetNextPhase(newState.Phase);
                    phaseChanged = true;
                }
                break;

            case ActionBucket.HighBet:
            case ActionBucket.MediumBet:
            case ActionBucket.LowBet:
                int betSize = 0;
                if (newState.AmountToCall > 0 && newState.AmountToCall == HeadsupGame.SmallBlindSize)
                {
                    //exception: first round
                    newState.PotSize += HeadsupGame.SmallBlindSize;
                }

                int lastActionLowBetCount = 0;
                for (int i = actions.Count - 1; i >= 0; i--)
                {
                    if (actions[i] == ActionBucket.LowBet)
                    {
                        lastActionLowBetCount++;
                    }
                    else
                    {
                        break;
                    }
                }

                betSize = ActionAbstracter.GetBetSize(lastAction, newState.AmountToCall, newState.PotSize);
                if (betSize > 0)
                {
                    newState.AmountToCall = betSize;
                    newState.PotSize     += betSize;
                    if (newState.PotSize >= HeadsupGame.StackSize * 2)
                    {
                        phaseChanged   = true;
                        newState.Phase = GamePhase.Showdown;
                    }
                }
                else
                {
                    phaseChanged   = true;
                    newState.Phase = GamePhase.Showdown;
                }
                break;
            }

            //if the phase has changed, the next event has to occur (e.g. adding a card to the current board)
            if (phaseChanged)
            {
                if (newState.Phase == GamePhase.Showdown)
                {
                    int payoff         = newState.PotSize / 2;
                    var handComparison = HandComparer.Compare(newState.Player1HoleCards, newState.Player2HoleCards, newState.Board);
                    switch (handComparison)
                    {
                    case HandComparison.None:
                        return(0);

                    case HandComparison.Player1Won:
                        return((playerIndex == 0) ? payoff : -payoff);

                    case HandComparison.Player2Won:
                        return((playerIndex == 0) ? -payoff : payoff);
                    }
                }
                else
                {
                    nextActionCallEnabled = false;

                    List <Card> currentBoard = null;
                    switch (newState.Phase)
                    {
                    case GamePhase.Flop:
                        currentBoard = gameState.Board.Take(3).ToList();
                        break;

                    case GamePhase.Turn:
                        currentBoard = gameState.Board.Take(4).ToList();
                        break;

                    case GamePhase.River:
                        currentBoard = gameState.Board;
                        break;
                    }

                    //evaluate new hand buckets
                    byte bucket1 = (byte)HandStrengthAbstracter.MapToBucket(currentBoard, newState.Player1HoleCards);
                    byte bucket2 = (byte)HandStrengthAbstracter.MapToBucket(currentBoard, newState.Player2HoleCards);
                    handBuckets = new byte[] { bucket1, bucket2 };
                }
            }

            var infoSet = new InformationSet <ActionBucket>()
            {
                CardBucket    = handBuckets[playerIndex],
                ActionHistory = actions
            };

            int numberOfActions = Settings.NumberOfActions;

            if (!nextActionCallEnabled)
            {
                numberOfActions = Settings.NumberOfActions - 1;
            }

            RegretGameNode <ActionBucket> node = null;
            long hash = infoSet.GetLongHashCode();

            //checks if the current information set already exists in O(1)
            if (!GameNodes.TryGetValue(hash, out node))
            {
                node         = new RegretGameNode <ActionBucket>(numberOfActions);
                node.InfoSet = infoSet;
                GameNodes.Add(hash, node);
            }

            //gets the strategy of the current player
            var strategy = node.calculateStrategy(playerIndex == 0 ? probabilityPlayer1 : probabilityPlayer2);

            // initialise utilities  with zeros
            var utilities = new List <float>(numberOfActions);

            for (int i = 0; i < numberOfActions; i++)
            {
                utilities.Add(0);
            }

            float nodeUtility = 0;
            int   index       = 0;

            // traverse the tree further down with a breadth first search
            foreach (ActionBucket nextAction in Enum.GetValues(typeof(ActionBucket)))
            {
                //skip illegal actions
                if (nextAction == ActionBucket.None)
                {
                    continue;
                }
                if (nextAction == ActionBucket.Call && !nextActionCallEnabled)
                {
                    continue;
                }

                var nextHistory = new List <ActionBucket>();
                nextHistory.AddRange(actions.ToArray());
                nextHistory.Add(nextAction);

                utilities[index] = playerIndex == 0
                    ? -CalculateCounterFactualRegret(newState, handBuckets, nextHistory, probabilityPlayer1 * strategy[index], probabilityPlayer2)
                   : -CalculateCounterFactualRegret(newState, handBuckets, nextHistory, probabilityPlayer1, probabilityPlayer2 * strategy[index]);

                //accumulate the utility of the sub branches
                nodeUtility += strategy[index] * utilities[index];
                index++;
            }

            for (int i = 0; i < numberOfActions; i++)
            {
                //calculate the regret
                float regret = utilities[i] - nodeUtility;
                //calculate the regret sum based on the current player
                node.RegretSum[i] += (playerIndex == 0 ? probabilityPlayer2 : probabilityPlayer1) * regret;
            }

            return(nodeUtility);
        }