public override Card MakeTurn(GameContext gameContext) { var curRound = gameContext.CurRound; var curTrick = curRound.CurTrick; var curRoundTricks = curRound.Tricks; var playableCards = CardUtils.GetPlayableCards(_hand, curTrick.LeadingSuite); List <Card> allKnownCards = _hand.Concat(curRoundTricks.Aggregate(new List <Card>(), (acc, trick) => { acc.AddRange(trick.CardsPlayed); return(acc); })).ToList(); List <Card> remainingCards = new List <Card>(new Deck().Cards); foreach (var card in allKnownCards) { remainingCards.Remove(card); } Dictionary <Card, int> winsByCard = playableCards.Aggregate(new Dictionary <Card, int>(), (acc, next) => { acc[next] = 0; return(acc); }); for (int i = 0; i < SIMULATION_COUNT; i++) { foreach (var card in playableCards) { var curSimRemainingCards = new List <Card>(remainingCards); var cardsPlayed = new List <Card>(curTrick.CardsPlayed); cardsPlayed.Add(card); // each remaining player plays a random card from a randomly generated hand for (int j = cardsPlayed.Count(); j < gameContext.PlayerCount; j++) { // rand hand selected from the remaining cards specific to this simulation var randHand = takeRandomCardsFromList(curSimRemainingCards, _hand.Count()); var playableCardsFromRandHand = CardUtils.GetPlayableCards(randHand, curTrick.LeadingSuite); cardsPlayed.Add(playableCardsFromRandHand[_rand.Next() % playableCardsFromRandHand.Count()]); } var winningCard = CardUtils.CalcWinningCard(cardsPlayed, curRound.TrumpSuite, curTrick.LeadingSuite); if (card.Equals(winningCard)) { winsByCard[card]++; } } } List <KeyValuePair <Card, double> > cardsSortedByWinPctg = winsByCard.Aggregate(new List <KeyValuePair <Card, double> >(), (acc, nextPair) => { double winPercentage = nextPair.Value * 1.0 / SIMULATION_COUNT; acc.Add(new KeyValuePair <Card, double>(nextPair.Key, winPercentage)); return(acc); }); // sort it so that weakest cards are at lower indices and stronger card at higher indices cardsSortedByWinPctg.Sort((a, b) => a.Value < b.Value ? -1 : 1); var curBid = curRound.Bids[this]; var curWins = curRound.Results[this]; var roundsLeft = curRound.RoundNum - curRound.Tricks.Count + 1; /* * requieredStrengthOfPlay is a value determining strength of card to play based on game context * given that requiredStrengthOfPlay = k: * * k>1 => impossible to win, play strongest card * k=1 => play strongest cards from here on out to win * 0<k<1 => sort cards by strength and select closest index to k val * i.e. k = .6 and 5 cards => choose card 3 /5 ranked by strength * k=0 => play weakest cards from here on out to win * k<0 => won too many, impossible to win, play weakest card * */ double requiredStrengthOfPlay = (curBid - curWins) * 1.0 / roundsLeft; Card cardToPlay = null; if (requiredStrengthOfPlay >= 1) { cardToPlay = cardsSortedByWinPctg.Last().Key; } else if (requiredStrengthOfPlay <= 0) { cardToPlay = cardsSortedByWinPctg.First().Key; } else { // requiredStrengthOfPlay between 0 and 1 int indexToPlay = (int)(requiredStrengthOfPlay * cardsSortedByWinPctg.Count()); cardToPlay = cardsSortedByWinPctg[indexToPlay].Key; } _frontend.DisplayTurnInProgress(this); _hand.Remove(cardToPlay); return(cardToPlay); }