public override Task <Card> GetCountCard(List <Card> playedCards, List <Card> uncountedCards, int currentCount)
        {
            var  maxScore = -1;
            Card maxCard  = null;
            var  score    = 0;

            if (uncountedCards.Count == 1)
            {
                if (uncountedCards[0].Value + currentCount <= 31)
                {
                    return(Task.FromResult(uncountedCards[0]));
                }
                else
                {
                    return(null);
                }
            }

            //
            //  see which card we can play that gives us the most points
            foreach (var c in uncountedCards)
            {
                score = CardScoring.ScoreCountingCardsPlayed(playedCards, c, currentCount, out var scoreList);
                if (score > maxScore)
                {
                    maxScore = score;
                    maxCard  = c;
                }
            }

            if (maxScore == -1)
            {
                return(null); // we have no valid card to play
            }

            if (maxScore == 0) // there isn't a card for us to play that generates points
            {
                //
                //  play a card that we have a pair so we can get 3 of a kind - as long as it isn't a 5 and the 3 of a kind makes > 31
                //

                for (var i = 0; i < uncountedCards.Count - 1; i++)
                {
                    //  dont' do it if it will force us over 31
                    if (uncountedCards[i].Rank * 3 + currentCount > 31)
                    {
                        continue;
                    }

                    if (uncountedCards[i].Rank == uncountedCards[i + 1].Rank)
                    {
                        if (uncountedCards[i].Rank != 5)
                        {
                            return(Task.FromResult(uncountedCards[i]));
                        }
                    }
                }

                //
                //  try to play a card that will create a run
                var combinations = new Combinations <Card>(uncountedCards, 2); // at most 6 of these: 4 choose 2
                foreach (List <Card> cards in combinations)
                {
                    var diff = Math.Abs(cards[0].Ordinal - cards[1].Ordinal);
                    if (diff == 1) // they are consecutive
                    {
                        var val = cards[0].Value + cards[1].Value;
                        if (val + currentCount > 31)
                        {
                            continue;
                        }
                        //
                        //  assume sorted

                        if (cards[0].Ordinal > CardOrdinal.Ace)
                        {
                            //
                            //  this means we have somehing like 3 and 4 in our hand.  if we play 7 and they play 6, we can play the 8
                            if (val + currentCount + cards[0].Value - 1 <= 31)
                            {
                                if (cards[0].Rank != 5)
                                {
                                    return(Task.FromResult(cards[0]));
                                }
                                else
                                {
                                    return(Task.FromResult(cards[1]));
                                }
                            }
                        }
                        else
                        {
                            var highCardVal = cards[1].Value;
                            if (highCardVal > 10)
                            {
                                highCardVal = 10;
                            }

                            if (val + currentCount + highCardVal <= 31)
                            {
                                if (cards[0].Rank != 5)
                                {
                                    return(Task.FromResult(cards[0]));
                                }
                                else
                                {
                                    return(Task.FromResult(cards[1]));
                                }
                            }
                        }
                    }

                    if (diff == 2) // there is a gap between the two cards -- eg.  4 and 6
                    {
                    }
                }

                //
                //  make the right choice if assuming they'll play a 10
                //
                combinations = new Combinations <Card>(uncountedCards, 2); // at most 6 of these: 4 choose 2
                foreach (List <Card> cds in combinations)
                {
                    var sum = cds[0].Value + cds[1].Value;
                    if (sum + currentCount == 5) // i'll 15 them if they play a 10
                    {
                        return(Task.FromResult(cds[1]));
                    }

                    if (sum + currentCount == 21) // i'll 31 them if they play a 10
                    {
                        return(Task.FromResult(cds[1]));
                    }
                }
            }

            if (maxCard.Rank == 5)
            {
                foreach (var c in uncountedCards)
                {
                    if (c.Rank != 5 && c.Value + currentCount <= 31)
                    {
                        maxCard = c;
                        break;
                    }
                }
            }

            return(Task.FromResult(maxCard));
        }
Beispiel #2
0
        public override Task <Card> GetCountCard(List <Card> playedCards, List <Card> uncountedCards, int currentCount)
        {
            var  maxScore = -1;
            Card maxCard  = null;
            var  score    = 0;


            //
            // if we have only 1 card, play it if we legally can
            //  NOTE: we assume that the Player correctly returns a legal card!
            //
            if (uncountedCards.Count == 1)
            {
                if (uncountedCards[0].Value + currentCount <= 31)
                {
                    return(Task.FromResult(uncountedCards[0]));
                }
                else
                {
                    return(Task.FromResult <Card>(null));
                }
            }

            //
            //  see which card we can play that gives us the most points
            foreach (var c in uncountedCards)
            {
                score = CardScoring.ScoreCountingCardsPlayed(playedCards, c, currentCount, out var scoreList);
                if (score > maxScore)
                {
                    maxScore = score;
                    maxCard  = c;
                }
            }

            if (maxScore == -1)
            {
                return(Task.FromResult <Card>(null));
            }
            ;  // we have no valid card to play

            if (maxScore > 0)
            {
                return(Task.FromResult(maxCard));
            }

            if (maxScore == 0) // there isn't a card for us to play that generates points
            {
                //
                //  play a card that we have a pair so we can get 3 of a kind - as long as it isn't a 5 and the 3 of a kind makes > 31
                //
                //  this optimization changes the average count score from 2.59948 to 2.66909 over 100,000 games
                //
                for (var i = 0; i < uncountedCards.Count - 1; i++)
                {
                    //  dont' do it if it will force us over 31
                    if (uncountedCards[i].Rank * 3 + currentCount > 31)
                    {
                        continue;
                    }

                    if (uncountedCards[i].Rank == uncountedCards[i + 1].Rank)
                    {
                        if (uncountedCards[i].Rank != 5)
                        {
                            return(Task.FromResult(uncountedCards[i]));
                        }
                    }
                }

                //
                //  make the right choice if assuming they'll play a 10
                //
                //  this optimization changes the average count score from 2.64235 to 2.67764 over 100,000 games
                //
                var combinations = new Combinations <Card>(uncountedCards, 2); // at most 6 of these: 4 choose 2
                foreach (List <Card> cards in combinations)
                {
                    var sum = cards[0].Value + cards[1].Value;
                    if (sum + currentCount == 5) // i'll 15 them if they play a 10
                    {
                        return(Task.FromResult(cards[1]));
                    }

                    if (sum + currentCount == 21) // i'll 31 them if they play a 10
                    {
                        return(Task.FromResult(cards[1]));
                    }
                }

                // tried returning the smallest legal card -- no difference
                // tried returning the highest legal card -- no difference
            }

            // tried to generate a random card if currentCount == 0 -- no difference


            //
            //  this one is important -- it basically says "if you can't score any points, induce a 3 of a kind, or try to create a run play whatever card we ened up with.
            //  UNLESS IT IS A FIVE!...then pick a different one.  over the course of 100,000 games, this is the difference between 2.61423 and 2.71498 ave counting points
            //  turns out that if we don't do this, then both players get ~2.65 points / counting session - e.g. if one is not worried about dropping 5's and the other is, it
            //  adds about .1/count and if both are being silly and dropping 5's then both get about .04 ave point boost.  still a good optimization when playing humans.

            if (maxCard.Rank == 5)
            {
                foreach (var c in uncountedCards)
                {
                    if (c.Rank != 5 && c.Value + currentCount <= 31)
                    {
                        maxCard = c;
                        break;
                    }
                }
            }

            //
            //   don't play a card that adds up to 5 because there are so many 10's

            if (maxCard.Value + currentCount != 5)
            {
                return(Task.FromResult(maxCard));
            }


            foreach (var c in uncountedCards)
            {
                //
                //  also don't play a card that if they play the same card will give them
                //  both a pair and a 15
                if (c.Value + currentCount == 5 || c.Value * 2 + currentCount == 15)
                {
                }
                else
                {
                    maxCard = c;
                    break;
                }
            }


            return(Task.FromResult(maxCard));
        }