/// <summary> /// Strategy: weight cards by type. /// </summary> protected StrategyContinuation StrategyWeightByType(List <Card> possibleCards) { // matched only by value, times StandardValueMatchPriority var cardsByValue = CurrentHand.Where(hc => hc.Value == TopCard.Value && hc.Color != TopCard.Color).ToList(); for (int i = 0; i < Config.StandardValueMatchPriority; ++i) { possibleCards.AddRange(cardsByValue); } // matched only by color, times StandardColorMatchPriority var cardsByColor = CurrentHand.Where(hc => hc.Color == TopCard.Color && hc.Value != TopCard.Value).ToList(); for (int i = 0; i < Config.StandardColorMatchPriority; ++i) { possibleCards.AddRange(cardsByColor); } // matched by both color and value, times StandardColorAndValueMatchPriority var identicalCards = CurrentHand.Where(hc => hc.Color == TopCard.Color && hc.Value == TopCard.Value).ToList(); for (int i = 0; i < Config.StandardColorAndValueMatchPriority; ++i) { possibleCards.AddRange(identicalCards); } // color changers (W, WD4), times StandardColorChangePriority var colorChangeCards = CurrentHand.Where(hc => hc.Color == CardColor.Wild).ToList(); for (int i = 0; i < Config.StandardColorChangePriority; ++i) { possibleCards.AddRange(colorChangeCards); } // player sequence reordering cards (R, S, D2, WD4), times StandardReorderPriority var reorderCards = CurrentHand.Where(hc => hc.Value == CardValue.WildDrawFour || ( ( hc.Color == TopCard.Color || hc.Value == TopCard.Value ) && ( hc.Value == CardValue.DrawTwo || hc.Value == CardValue.Reverse || hc.Value == CardValue.Skip ) ) ).ToList(); for (int i = 0; i < Config.StandardReorderPriority; ++i) { possibleCards.AddRange(reorderCards); } return(StrategyContinuation.ContinueToNextStrategy); }
protected override void PlayACard() { // find a playable card with the lowest malus var cardToPlay = CurrentHand .Where(IsCardPlayable) .OrderBy(c => c.Malus) .Select(c => (Card?)c) .FirstOrDefault(); if (cardToPlay.HasValue) { if (cardToPlay.Value.Color == CardColor.Wild) { // choose the color of which we have the most cards, or red var colorsByCount = CurrentHand .Where(c => c.Color != CardColor.Wild) .GroupBy(c => c.Color) .Select(grp => new { Color = grp.Key, Count = grp.Count() }) .OrderByDescending(cc => cc.Count) .ToList(); var colorToPlay = (colorsByCount.Count > 0) ? colorsByCount[0].Color : CardColor.Red; PlayWildCard(cardToPlay.Value.Value, colorToPlay); } else { PlayColorCard(cardToPlay.Value); } DrewLast = false; } else { if (DrewLast) { PassAfterDrawing(); } else { DrawACard(); } } }
protected override CardColor PickAColor() { if (ColorRequest.HasValue) { // we have a pending color request; honor it var color = ColorRequest.Value; StrategyLogger.LogDebug("honoring color request {Color}", color); ColorRequest = null; return(color); } // choose the color of which we have the most cards, or red var colorsByCount = CurrentHand .Where(c => c.Color != CardColor.Wild) .GroupBy(c => c.Color) .Select(grp => new { Color = grp.Key, Count = grp.Count() }) .OrderByDescending(cc => cc.Count) .ToList(); return((colorsByCount.Count > 0) ? colorsByCount[0].Color : CardColor.Red); }
/// <summary> /// Strategy: honor color requests. /// </summary> protected StrategyContinuation StrategyHonorColorRequests(List <Card> possibleCards) { if (!ColorRequest.HasValue) { // no color request to honor return(StrategyContinuation.ContinueToNextStrategy); } // do I have a usable card that matches the target color? possibleCards.AddRange(CurrentHand.Where(hc => hc.Color == ColorRequest.Value && hc.Value == TopCard.Value)); if (possibleCards.Count == 0) { // nope; try changing with a wild card instead possibleCards.AddRange(CurrentHand.Where(hc => hc.Color == CardColor.Wild)); } if (possibleCards.Count > 0) { // alright, no need for the standard pick return(StrategyContinuation.SkipAllOtherStrategiesUnlessFilteredEmpty); } return(StrategyContinuation.ContinueToNextStrategy); }
protected StrategyContinuation StrategyAnyCard(List <Card> possibleCards) { // just anything possibleCards.AddRange(CurrentHand.Where(IsCardPlayable)); return(StrategyContinuation.ContinueToNextStrategy); }
public string GetChoice() { List <int> smallerChoice = CurrentHand.Where(x => x <= PlayerStatistics.ActualMana).ToList(); if (smallerChoice.Count <= 0) { return(string.Empty); } if (smallerChoice.Contains(0)) { return("0"); } if (smallerChoice.Any(x => x == PlayerStatistics.ActualMana)) { return(smallerChoice.First(x => x == PlayerStatistics.ActualMana).ToString()); } int HigherToLower = 0; int LowerToHigher = 0; int MiddleChoice = 0; int MiddleDefinitiveChoice = 0; int tempMana = PlayerStatistics.ActualMana; List <int> replica = new List <int>(smallerChoice); while (replica.Any() && tempMana >= 0) { if (replica.Max() <= tempMana) { HigherToLower += replica.Max(); tempMana -= replica.Max(); } replica.Remove(replica.Max()); } replica = new List <int>(smallerChoice); tempMana = PlayerStatistics.ActualMana; while (replica.Any() && tempMana >= 0) { if (replica.Min() <= tempMana) { LowerToHigher += replica.Min(); tempMana -= replica.Min(); } replica.Remove(replica.Min()); } replica = new List <int>(smallerChoice); tempMana = PlayerStatistics.ActualMana; while (replica.Any() && tempMana >= 0) { double avg = replica.Average(); replica.Sort(); var higher = replica.FirstOrDefault(x => x >= Math.Ceiling(avg)); var lower = replica.FirstOrDefault(x => x <= Math.Floor(avg)); if (higher != 0 && tempMana >= higher && higher > lower) { MiddleChoice += higher; if (MiddleDefinitiveChoice == 0) { MiddleDefinitiveChoice = higher; } tempMana -= higher; replica.Remove(higher); } else if (lower != 0 && tempMana >= lower && lower > higher) { MiddleChoice += lower; if (MiddleDefinitiveChoice == 0) { MiddleDefinitiveChoice = higher; } tempMana -= lower; replica.Remove(lower); } else { if (tempMana >= 0) { try { var temp = replica.Where(x => x <= tempMana).ToList().Max(); MiddleChoice += temp; replica.Remove(temp); } catch { break; } } } } if (HigherToLower > LowerToHigher && HigherToLower > MiddleChoice) { return(smallerChoice.Max().ToString()); } else if (LowerToHigher > HigherToLower && LowerToHigher > MiddleChoice) { return(smallerChoice.Min().ToString()); } else if (MiddleChoice > HigherToLower && MiddleChoice > LowerToHigher) { return(MiddleDefinitiveChoice.ToString()); } else { return(string.Empty); } }
/// <summary> /// Strategy: try to destroy the next player if they are close to winning. /// </summary> protected StrategyContinuation StrategyDestroyNextPlayerIfDangerous(List <Card> possibleCards) { if (NextPlayer == null || !CurrentCardCounts.ContainsKey(NextPlayer)) { // not sure who my next player is or how many cards they have return(StrategyContinuation.ContinueToNextStrategy); } StrategyLogger.LogDebug("next player {Nickname} has {CardCount} cards", NextPlayer, CurrentCardCounts[NextPlayer]); if (CurrentCardCounts[NextPlayer] > Config.PlayToWinThreshold) { // not dangerous return(StrategyContinuation.ContinueToNextStrategy); } // the player after me has too few cards; try finding an evil card first StrategyLogger.LogDebug("trying to find an evil card"); // offensive cards first: D2, WD4 possibleCards.AddRange(CurrentHand.Where(hc => hc.Color == TopCard.Color && hc.Value == CardValue.DrawTwo)); possibleCards.AddRange(CurrentHand.Where(hc => hc.Value == CardValue.WildDrawFour)); if (possibleCards.Count == 0) { // defensive cards next: S, R possibleCards.AddRange(CurrentHand.Where(hc => hc.Color == TopCard.Color && ( hc.Value == CardValue.Skip || hc.Value == CardValue.Reverse ) )); } if (possibleCards.Count > 0) { StrategyLogger.LogDebug("we have at least one evil card for the next player ({Cards})", possibleCards.StringJoin(", ")); // don't add the next pick return(StrategyContinuation.SkipAllOtherStrategiesUnlessFilteredEmpty); } else if (!DrewLast) { if (CurrentHand.Count <= Config.PlayToWinThreshold) { StrategyLogger.LogDebug("not risking emergency strategic draw for evil card"); } else if (Config.EmergencyStrategicDrawPercentage > 0) { var emergencyStrategicDraw = (Randomizer.Next(100) < Config.EmergencyStrategicDrawPercentage); if (emergencyStrategicDraw) { StrategyLogger.LogDebug("emergency strategic draw for evil card"); DrawACard(); return(StrategyContinuation.DontPlayCard); } else { StrategyLogger.LogDebug("skipping emergency strategic draw for evil card"); } } } return(StrategyContinuation.ContinueToNextStrategy); }