HoldemHand.Hand.OutsMaskDiscounted C# (CSharp) Method

OutsMaskDiscounted() public static method

Creates a Hand mask with the cards that will improve the specified players hand against a list of opponents or if no opponents are list just the cards that improve the players current hand. This implements the concept of 'discounted outs'. That is outs that will improve the players hand, but not potentially improve an opponents hand to an even better one. For example drawing to a straight that could end up loosing to a flush. Please note that this only looks at single cards that improve the hand and will not specifically look at runner-runner possiblities. Players pocket cards The board (must contain either 3 or 4 cards) A list of zero or more opponent pocket cards A mask of all of the cards that improve the hand applying the following discouting rules: 1) Drawing to a pair must use an over card (ie a card higher than all those on the board) 2) Drawing to 2 pair / pairing your hand is discounted if the board is paired (ie your 2 pair drawing deat to trips) 3) Drawing to a hand lower than a flush must not make a 3 suited board or the board be 3 suited. 4) Drawing to a hand lower than a stright, the flop must not be 3card connected or on the turn allow a straight to be made with only 1 pocket card or the out make a straight using only 1 card. Function provided by Matt Baker.
public static OutsMaskDiscounted ( ulong player, ulong board ) : ulong
player ulong Players pocket hand
board ulong Board mask
return ulong
        public static ulong OutsMaskDiscounted(ulong player, ulong board, params ulong[] opponents)
        {
            ulong retval = 0UL, dead = 0UL;
            int ncards = Hand.BitCount(player | board);
            #if DEBUG
            Debug.Assert(Hand.BitCount(player) == 2); // Must have two cards for a legit set of pocket cards
            if (ncards != 5 && ncards != 6)
                throw new ArgumentException("Outs only make sense after the flop and before the river");
            #endif

            if (opponents.Length > 0)
            {
                // Check opportunities to improve against one or more opponents
                foreach (ulong opp in opponents)
                {
                    Debug.Assert(Hand.BitCount(opp) == 2); // Must have two cards for a legit set of pocket cards
                    dead |= opp;
                }

                uint playerOrigHandVal = Hand.Evaluate(player | board, ncards);
                uint playerOrigHandType = Hand.HandType(playerOrigHandVal);
                uint playerOrigTopCard = Hand.TopCard(playerOrigHandVal);

                foreach (ulong card in Hand.Hands(0UL, dead | board | player, 1))
                {
                    bool bWinFlag = true;
                    uint playerHandVal = Hand.Evaluate(player | board | card, ncards + 1);
                    uint playerNewHandType = Hand.HandType(playerHandVal);
                    uint playerNewTopCard = Hand.TopCard(playerHandVal);
                    foreach (ulong oppmask in opponents)
                    {
                        uint oppHandVal = Hand.Evaluate(oppmask | board | card, ncards + 1);

                        bWinFlag = oppHandVal < playerHandVal && (playerNewHandType > playerOrigHandType || (playerNewHandType == playerOrigHandType && playerNewTopCard > playerOrigTopCard));
                        if (!bWinFlag)
                            break;
                    }
                    if (bWinFlag)
                        retval |= card;
                }
            }
            else
            {
                // Look at the cards that improve the hand.
                uint playerOrigHandVal = Hand.Evaluate(player | board, ncards);
                uint playerOrigHandType = Hand.HandType(playerOrigHandVal);
                uint playerOrigTopCard = Hand.TopCard(playerOrigHandVal);
                uint boardOrigHandVal = Hand.Evaluate(board);
                uint boardOrigHandType = Hand.HandType(boardOrigHandVal);
                uint boardOrigTopCard = Hand.TopCard(boardOrigHandVal);

                // Look at players pocket cards for special cases.
                uint playerPocketHandVal = Hand.Evaluate(player);
                uint playerPocketHandType = Hand.HandType(playerPocketHandVal);

                // Seperate out by suit
                uint sc = (uint)((board >> (CLUB_OFFSET)) & 0x1fffUL);
                uint sd = (uint)((board >> (DIAMOND_OFFSET)) & 0x1fffUL);
                uint sh = (uint)((board >> (HEART_OFFSET)) & 0x1fffUL);
                uint ss = (uint)((board >> (SPADE_OFFSET)) & 0x1fffUL);

                // Check if board is 3 suited.
                bool discountSuitedBoard = ((nBitsTable[sc] > 2) || (nBitsTable[sd] > 2) || (nBitsTable[sh] > 2) || (nBitsTable[ss] > 2));

                // Check if board is 3 Conected on the flop. A dangerous board:
                // 3 possible straights using 2 pocket cards and a higher chance
                // of 2 pair; players often play 2 connected cards which can hit.
                int CountContiguous = 0;
                int boardCardCount = BitCount(board);

                if (boardCardCount == 3)
                {
                    uint bf = CardMask(board, Clubs) | CardMask(board, Diamonds) | CardMask(board, Hearts) | CardMask(board, Spades);

                    if (BitCount(0x1800 & bf) == 2) CountContiguous++;
                    if (BitCount(0xc00 & bf) == 2) CountContiguous++;
                    if (BitCount(0x600 & bf) == 2) CountContiguous++;
                    if (BitCount(0x300 & bf) == 2) CountContiguous++;
                    if (BitCount(0x180 & bf) == 2) CountContiguous++;
                    if (BitCount(0xc0 & bf) == 2) CountContiguous++;
                    if (BitCount(0x60 & bf) == 2) CountContiguous++;
                    if (BitCount(0x30 & bf) == 2) CountContiguous++;
                    if (BitCount(0x18 & bf) == 2) CountContiguous++;
                    if (BitCount(0xc & bf) == 2) CountContiguous++;
                    if (BitCount(0x6 & bf) == 2) CountContiguous++;
                    if (BitCount(0x3 & bf) == 2) CountContiguous++;
                    if (BitCount(0x1001 & bf) == 2) CountContiguous++;

                }
                bool discountStraight = (CountContiguous > 1);

                // Look ahead one card
                foreach (ulong card in Hand.Hands(0UL, dead | board | player, 1))
                {
                    uint boardNewHandval = Hand.Evaluate(board | card);
                    uint boardNewHandType = Hand.HandType(boardNewHandval);
                    uint boardNewTopCard = Hand.TopCard(boardNewHandval);
                    uint playerNewHandVal = Hand.Evaluate(player | board | card, ncards + 1);
                    uint playerNewHandType = Hand.HandType(playerNewHandVal);
                    uint playerNewTopCard = Hand.TopCard(playerNewHandVal);
                    bool playerImproved = (playerNewHandType > playerOrigHandType || (playerNewHandType == playerOrigHandType && playerNewTopCard > playerOrigTopCard) || (playerNewHandType == playerOrigHandType && playerNewHandType == (uint)HandTypes.TwoPair && playerNewHandVal > playerOrigHandVal));
                    bool playerStrongerThanBoard = (playerNewHandType > boardNewHandType || (playerNewHandType == boardNewHandType && playerNewTopCard > boardNewTopCard));

                    if (playerImproved && playerStrongerThanBoard)
                    {
                        bool isOut = false;

                        bool discountSuitedOut = false;
                        if (!discountSuitedBoard)
                        {
                            // Get suit of card.
                            uint cc = (uint)((card >> (CLUB_OFFSET)) & 0x1fffUL);
                            uint cd = (uint)((card >> (DIAMOND_OFFSET)) & 0x1fffUL);
                            uint ch = (uint)((card >> (HEART_OFFSET)) & 0x1fffUL);
                            uint cs = (uint)((card >> (SPADE_OFFSET)) & 0x1fffUL);

                            // Check if card will make a 3 suited board.
                            discountSuitedOut = ((nBitsTable[sc] > 1 && nBitsTable[cc] == 1) || (nBitsTable[sd] > 1 && nBitsTable[cd] == 1) || (nBitsTable[sh] > 1 && nBitsTable[ch] == 1) || (nBitsTable[ss] > 1 && nBitsTable[cs] == 1));
                        }

                        // Check if board is 4 connected or card + board is 4 connected.
                        // Dangerous board: straight using 1 pocket card only.
                        if (boardCardCount == 4)
                        {
                            // We need to check for the following:
                            // 9x,8x,7x,6x (4 in a row)
                            // 9x,8x,7x,5x (3 in a row with a 1 gap connected card)
                            // 9x,8x,6x,5x (2 connected with a 1 gap connected in the middle)
                            CountContiguous = 0;
                            uint bf = CardMask(board | card, Clubs) | CardMask(board | card, Diamonds) | CardMask(board | card, Hearts) | CardMask(board | card, Spades);

                            // AxKx
                            if (BitCount(0x1800 & bf) == 2)
                            {
                                CountContiguous++;
                            }

                            // KxQx
                            if (BitCount(0xc00 & bf) == 2)
                            {
                                CountContiguous++;
                            }
                            else
                            {
                                if (CountContiguous == 1 && BitCount(0x300 & bf) == 2)
                                    // 2 connected with a 1 gap connected in the middle
                                    discountStraight = true;

                                CountContiguous = 0;
                            }

                            // QxJx
                            if (BitCount(0x600 & bf) == 2)
                            {
                                CountContiguous++;
                            }
                            else
                            {
                                switch (CountContiguous)
                                {
                                    case 1:
                                        if (BitCount(0x180 & bf) == 2)
                                            // 2 connected with a 1 gap in the middle
                                            discountStraight = true;
                                        break;
                                    case 2:
                                        // test for a T
                                        if (BitCount(0x100 & bf) == 1)
                                            // 3 in a row with a 1 gap connected
                                            discountStraight = true;
                                        break;
                                }
                                CountContiguous = 0;
                            }

                            // JxTx
                            if (BitCount(0x300 & bf) == 2)
                                CountContiguous++;
                            else
                            {
                                switch (CountContiguous)
                                {
                                    case 1:
                                        if (BitCount(0xc0 & bf) == 2)
                                            // 2 connected with a 1 gap in the middle
                                            discountStraight = true;
                                        break;
                                    case 2:
                                        // test for 9x
                                        if (BitCount(0x80 & bf) == 1)
                                            // 3 in a row with a 1 gap connected
                                            discountStraight = true;
                                        break;
                                    case 3: // 4 in a row
                                        discountStraight = true;
                                        break;
                                }
                                CountContiguous = 0;
                            }

                            // Tx9x
                            if (BitCount(0x180 & bf) == 2)
                                CountContiguous++;
                            else
                            {
                                switch (CountContiguous)
                                {
                                    case 1:
                                        if (BitCount(0x60 & bf) == 2)
                                            // 2 connected with a 1 gap in the middle
                                            discountStraight = true;
                                        break;
                                    case 2:
                                        // test for 8x or Ax
                                        if (BitCount(0x1040 & bf) == 1)
                                            // 3 in a row with a 1 gap connected
                                            discountStraight = true;
                                        break;
                                    case 3: // 4 in a row
                                        discountStraight = true;
                                        break;
                                }
                                CountContiguous = 0;
                            }

                            // 9x8x
                            if (BitCount(0xc0 & bf) == 2)
                                CountContiguous++;
                            else
                            {
                                switch (CountContiguous)
                                {
                                    case 1:
                                        if (BitCount(0x30 & bf) == 2)
                                            // 2 connected with a 1 gap in the middle
                                            discountStraight = true;
                                        break;
                                    case 2:
                                        // test for 7x or Kx
                                        if (BitCount(0x820 & bf) == 1)
                                            // 3 in a row with a 1 gap connected
                                            discountStraight = true;
                                        break;
                                    case 3: // 4 in a row
                                        discountStraight = true;
                                        break;
                                }
                                CountContiguous = 0;
                            }

                            // 8x7x
                            if (BitCount(0x60 & bf) == 2)
                                CountContiguous++;
                            else
                            {
                                switch (CountContiguous)
                                {
                                    case 1:
                                        if (BitCount(0x18 & bf) == 2)
                                            // 2 connected with a 1 gap in the middle
                                            discountStraight = true;
                                        break;
                                    case 2:
                                        // test for 6x or Qx
                                        if (BitCount(0x410 & bf) == 1)
                                            // 3 in a row with a 1 gap connected
                                            discountStraight = true;
                                        break;
                                    case 3: // 4 in a row
                                        discountStraight = true;
                                        break;
                                }
                                CountContiguous = 0;
                            }

                            // 7x6x
                            if (BitCount(0x30 & bf) == 2)
                                CountContiguous++;
                            else
                            {
                                switch (CountContiguous)
                                {
                                    case 1:
                                        if (BitCount(0xc & bf) == 2)
                                            // 2 connected with a 1 gap in the middle
                                            discountStraight = true;
                                        break;
                                    case 2:
                                        // test for 5x or Jx
                                        if (BitCount(0x208 & bf) == 1)
                                            // 3 in a row with a 1 gap connected
                                            discountStraight = true;
                                        break;
                                    case 3: // 4 in a row
                                        discountStraight = true;
                                        break;
                                }
                                CountContiguous = 0;
                            }

                            // 6x5x
                            if (BitCount(0x18 & bf) == 2)
                                CountContiguous++;
                            else
                            {
                                switch (CountContiguous)
                                {
                                    case 1:
                                        if (BitCount(0x6 & bf) == 2)
                                            // 2 connected with a 1 gap in the middle
                                            discountStraight = true;
                                        break;
                                    case 2:
                                        // test for 4x or Tx
                                        if (BitCount(0x104 & bf) == 1)
                                            // 3 in a row with a 1 gap connected
                                            discountStraight = true;
                                        break;
                                    case 3: // 4 in a row
                                        discountStraight = true;
                                        break;
                                }
                                CountContiguous = 0;
                            }

                            // 5x4x
                            if (BitCount(0xc & bf) == 2)
                                CountContiguous++;
                            else
                            {
                                switch (CountContiguous)
                                {
                                    case 1:
                                        if (BitCount(0x3 & bf) == 2)
                                            // 2 connected with a 1 gap in the middle
                                            discountStraight = true;
                                        break;
                                    case 2:
                                        // test for 3x or 9x
                                        if (BitCount(0x82 & bf) == 1)
                                            // 3 in a row with a 1 gap connected
                                            discountStraight = true;
                                        break;
                                    case 3: // 4 in a row
                                        discountStraight = true;
                                        break;
                                }
                                CountContiguous = 0;
                            }

                            // 4x3x
                            if (BitCount(0x6 & bf) == 2)
                                CountContiguous++;
                            else
                            {
                                switch (CountContiguous)
                                {
                                    case 1:
                                        if (BitCount(0x1001 & bf) == 2)
                                            // 2 connected with a 1 gap in the middle
                                            discountStraight = true;
                                        break;
                                    case 2:
                                        // test for 2x or 8x
                                        if (BitCount(0x41 & bf) == 1)
                                            // 3 in a row with a 1 gap connected
                                            discountStraight = true;
                                        break;
                                    case 3: // 4 in a row
                                        discountStraight = true;
                                        break;
                                }
                                CountContiguous = 0;
                            }

                            // 3x2x
                            if (BitCount(0x3 & bf) == 2)
                                CountContiguous++;
                            else
                            {
                                switch (CountContiguous)
                                {
                                    case 2:
                                        // test for Ax or 7x
                                        if (BitCount(0x1020 & bf) == 1)
                                            // 3 in a row with a 1 gap connected
                                            discountStraight = true;
                                        break;
                                    case 3: // 4 in a row
                                        discountStraight = true;
                                        break;
                                }
                                CountContiguous = 0;
                            }

                            // 2xAx
                            if (BitCount(0x1001 & bf) == 2)
                            {
                                CountContiguous++;

                                // Check one last time.
                                switch (CountContiguous)
                                {
                                    case 2:
                                        // test for 5x
                                        if (BitCount(0x8 & bf) == 1)
                                            // 3 in a row with a 1 gap connected
                                            discountStraight = true;
                                        break;
                                    case 3: // 4 in a row
                                        discountStraight = true;
                                        break;
                                }
                            }
                            else
                            {
                                switch (CountContiguous)
                                {
                                    case 2:
                                        // test for 6x
                                        if (BitCount(0x10 & bf) == 1)
                                            // 3 in a row with a 1 gap connected
                                            discountStraight = true;
                                        break;
                                    case 3: // 4 in a row
                                        discountStraight = true;
                                        break;
                                }
                            }
                        }

                        // Hand imporving to a pair, must use overcards and not make a 3 suited board.
                        if (playerNewHandType == (uint)HandTypes.Pair)
                        {
                            uint newCardVal = Hand.Evaluate(card);
                            uint newTopCard = Hand.TopCard(newCardVal);

                            if (boardOrigTopCard < newTopCard && !(discountSuitedBoard || discountSuitedOut) && !(discountStraight))
                                isOut = true;
                        }

                                // Hand imporving to two pair, must use one of the players pocket cards and
                        // the player already has a pair, either a pocket pair or a pair using the board.
                        // ie: not drawing to two pair when trips is out - drawing dead.
                        // And not make a 3 suited board and not discounting for a straight.
                        else if (playerNewHandType == (uint)HandTypes.TwoPair)
                        {
                            // Special case pair improving to two pair must use one of the players cards.
                            uint playerPocketHandNewCardVal = Hand.Evaluate(player | card);
                            uint playerPocketHandNewCardType = Hand.HandType(playerPocketHandNewCardVal);

                            if ((playerPocketHandNewCardType == (uint)HandTypes.Pair && playerPocketHandType != (uint)HandTypes.Pair) && (boardOrigHandType != (uint)HandTypes.Pair || playerOrigHandType == (uint)HandTypes.TwoPair))
                            {
                                if (!(discountSuitedBoard || discountSuitedOut) && !(discountStraight))
                                    isOut = true;
                            }
                        }
                        // New hand better than two pair.
                        else if (playerNewHandType > (uint)HandTypes.TwoPair)
                        {
                            // Hand imporving trips, must not make a 3 suited board and not discounting for a straight.
                            if (playerNewHandType == (uint)HandTypes.Trips)
                            {
                                if (!(discountSuitedBoard || discountSuitedOut) && !(discountStraight))
                                    isOut = true;
                            }
                            // Hand imporving to a straight, must not make a 3 suited board.
                            else if (playerNewHandType == (uint)HandTypes.Straight)
                            {
                                if (!(discountSuitedBoard || discountSuitedOut))
                                    isOut = true;
                            }
                            else
                                // No discounting for a Flush (should we consider a straight Flush?),
                                // Full House, Four of a Kind and Straight Flush.
                                isOut = true;
                        }
                        if (isOut)
                            retval |= card;
                    }
                }
            }

            return retval;
        }