private static List<Card> AddLands(List<Card> deck, List<Card> library, CardRatings cardRatings) { var minimalLandCount = DeckCardCount - deck.Count; var optimalLandCount = CalculateOptimalLandCount(deck); var landCount = Math.Max(minimalLandCount, optimalLandCount); var deckSize = landCount + deck.Count; if (deckSize > DeckCardCount) { RemoveWorstCards( deck, count: deckSize - DeckCardCount, cardRatings: cardRatings); } var distribution = GetLandsDistribution(deck, landCount); AddNonBasicLands(distribution, library, deck, cardRatings); AddCards("Plains", distribution[0], deck); AddCards("Island", distribution[1], deck); AddCards("Swamp", distribution[2], deck); AddCards("Mountain", distribution[3], deck); AddCards("Forest", distribution[4], deck); return deck; }
private static List <Card> TryBuildDeck(List <Card> cards, CardRatings cardRatings) { var deck = new List <Card>(); var creatures = cards .Where(x => x.Is().Creature) .OrderByDescending(x => cardRatings.GetRating(x.Name)) .ToList(); var bestCreatures = creatures .Take(MinCreatureCount); var otherCreatures = creatures.Skip(MinCreatureCount) .Take(MaxCreatureCount - MinCreatureCount); var spellsAndOtherCreatures = cards .Where(x => !x.Is().Creature&& !x.Is().Land) .Concat(otherCreatures) .OrderByDescending(x => cardRatings.GetRating(x.Name)); deck.AddRange(bestCreatures); deck.AddRange(spellsAndOtherCreatures.Take(MaxSpellCount - deck.Count)); if (deck.Count < MinSpellCount) { return(null); } return(AddLands(deck, cards, cardRatings)); }
private static List <Card> AddLands(List <Card> deck, List <Card> library, CardRatings cardRatings) { var minimalLandCount = DeckCardCount - deck.Count; var optimalLandCount = CalculateOptimalLandCount(deck); var landCount = Math.Max(minimalLandCount, optimalLandCount); var deckSize = landCount + deck.Count; if (deckSize > DeckCardCount) { RemoveWorstCards( deck, count: deckSize - DeckCardCount, cardRatings: cardRatings); } var distribution = GetLandsDistribution(deck, landCount); AddNonBasicLands(distribution, library, deck, cardRatings); AddCards("Plains", distribution[0], deck); AddCards("Island", distribution[1], deck); AddCards("Swamp", distribution[2], deck); AddCards("Mountain", distribution[3], deck); AddCards("Forest", distribution[4], deck); return(deck); }
public static Deck BuildDeck(IEnumerable <CardInfo> library, CardRatings cardRatings) { var cards = library.Select(x => Cards.All[x.Name]) .ToList(); var candidates = BuildDecks(cards, cardRatings) .Select(x => CreateDeckFromCardList(x, library)) .ToList(); return(DeckEvaluator.GetBestDeck(candidates)); }
private static void RemoveWorstCards(List <Card> deckNoLands, int count, CardRatings cardRatings) { var cardsToRemove = deckNoLands .OrderBy(x => cardRatings.GetRating(x.Name)) .Take(count); foreach (var card in cardsToRemove) { deckNoLands.Remove(card); } }
public static CardRatings Merge(CardRatings ratings1, CardRatings ratings2) { var result = new CardRatings(ratings1._ratings); foreach (var pair in ratings2._ratings) { result._ratings[pair.Key] = pair.Value; } return(result); }
public static CardRatings Merge(CardRatings ratings1, CardRatings ratings2) { var result = new CardRatings(ratings1._ratings); foreach (var pair in ratings2._ratings) { result._ratings[pair.Key] = pair.Value; } return result; }
public static Deck BuildDeck(IEnumerable<CardInfo> library, CardRatings cardRatings) { var cards = library.Select(x => Cards.All[x.Name]) .ToList(); var candidates = BuildDecks(cards, cardRatings) .Select(x => CreateDeckFromCardList(x, library)) .ToList(); return DeckEvaluator.GetBestDeck(candidates); }
private static List <Card> AddLands(List <Card> deck, List <Card> library, CardRatings cardRatings, int landCount) { var distribution = GetLandsDistribution(deck, landCount); AddNonBasicLands(distribution, library, deck, cardRatings); AddCards("Plains", distribution[0], deck); AddCards("Island", distribution[1], deck); AddCards("Swamp", distribution[2], deck); AddCards("Mountain", distribution[3], deck); AddCards("Forest", distribution[4], deck); return(deck); }
public DraftResults Run(int playerCount, string[] sets, CardRatings ratings) { var players = CreatePlayers(playerCount, ratings, _userInterface != null); var boosters = CreateBoosters(sets, players); var round = 1; var direction = 1; // clockwise while (round <= 3) { var roundBoosters = boosters .Skip((round - 1)*players.Count) .Take(players.Count) .ToList(); var cardCount = roundBoosters[0].Count; while (cardCount > 0) { for (var playerIndex = 0; playerIndex < players.Count; playerIndex++) { var boosterIndex = (100 + playerIndex + direction*cardCount)%players.Count; var player = players[playerIndex]; var draftedCard = player.Strategy.PickCard(roundBoosters[boosterIndex], round); if (_userInterface != null && _userInterface.PlayerLeftDraft) return null; player.Library.Add(draftedCard); roundBoosters[boosterIndex].Remove(draftedCard); } cardCount = roundBoosters[0].Count; } round++; direction = -direction; } return new DraftResults(players); }
private static List <List <Card> > BuildDecks(IEnumerable <Card> cards, CardRatings cardRatings) { var decks = new List <List <Card> >(); for (var i = CardColor.White; i <= CardColor.Green; i++) { var cardWithColorI = cards .Where(x => x.IsMultiColored == false) .Where(x => x.HasColor(i) || x.HasColor(CardColor.Colorless) || x.Is().Land) .ToList(); var monoColoredDeck = TryBuildDeck(cardWithColorI, cardRatings); if (monoColoredDeck != null) { decks.Add(monoColoredDeck); } for (var j = i + 1; j <= CardColor.Green; j++) { var dual = cards .Where(x => x.HasColor(i) || x.HasColor(j) || x.HasColor(CardColor.Colorless) || x.Is().Land) .ToList(); var firstcolorCount = dual.Count(x => Cards.All[x.Name].HasColor(i)); var secondcolorCount = dual.Count(x => Cards.All[x.Name].HasColor(j)); if (firstcolorCount >= MinSplashColorCardCount && secondcolorCount >= MinSplashColorCardCount) { var dualDeck = TryBuildDeck(dual, cardRatings); if (dualDeck != null) { decks.Add(dualDeck); } } } } return(decks); }
private static void AddNonBasicLands(List <int> distribution, List <Card> library, List <Card> deck, CardRatings cardRatings) { var nonBasicLands = library.Where(x => x.Is().Land).ToList(); var deckColors = distribution.Select((x, i) => x > 0 ? i : -1).Where(x => x >= 0).ToList(); var maxCountColor = distribution.IndexOf(distribution.Max()); var landsToReplaceBasic = new List <Card>(); foreach (var land in nonBasicLands) { var rating = cardRatings.GetRating(land.Name); if (rating < MinNonBasicLandRating) { continue; } var landColors = land.ProducableManaColors; if (landColors.Count == 1) { if (deckColors.Contains(landColors[0])) { distribution[landColors[0]]--; landsToReplaceBasic.Add(land); } } else if (landColors.Count > 1) { var matchCount = landColors.Count(deckColors.Contains); if (matchCount >= 2) { distribution[maxCountColor]--; landsToReplaceBasic.Add(land); } } } deck.AddRange(landsToReplaceBasic); }
public static Deck BuildDeck(IEnumerable <CardInfo> library, CardRatings cardRatings) { return(BuildDeck(library, cardRatings, DeckEvaluator.GetBestDeck)); }
private static void AddNonBasicLands(List<int> distribution, List<Card> library, List<Card> deck, CardRatings cardRatings) { var nonBasicLands = library.Where(x => x.Is().Land).ToList(); var deckColors = distribution.Select((x, i) => x > 0 ? i : -1).Where(x => x >= 0).ToList(); var maxCountColor = distribution.IndexOf(distribution.Max()); var cardsToRemoveCount = 0; var landsToReplaceBasic = new List<Card>(); foreach (var land in nonBasicLands) { var rating = cardRatings.GetRating(land.Name); if (rating < MinNonBasicLandRating) continue; var landColors = land.ProducableManaColors; if (landColors.Count == 0) { deck.Add(land); cardsToRemoveCount++; } if (landColors.Count == 1) { if (deckColors.Contains(landColors[0])) { distribution[landColors[0]]--; landsToReplaceBasic.Add(land); } else if (landColors[0] == (int) CardColor.Colorless) { if (deckColors.Count > 1) { deck.Add(land); cardsToRemoveCount++; } else { distribution[maxCountColor]--; landsToReplaceBasic.Add(land); } } } else if (landColors.Count > 1) { var matchCount = landColors.Count(deckColors.Contains); if (matchCount >= 2) { distribution[maxCountColor]--; landsToReplaceBasic.Add(land); } } } if (cardsToRemoveCount > 0) { // Some lands do not replace existing lands // e.g if they do not produce mana. // For each such land remove worst cards from deck // so that deck count will be 40. RemoveWorstCards(deck, cardsToRemoveCount, cardRatings); } deck.AddRange(landsToReplaceBasic); }
private static List<Card> TryBuildDeck(List<Card> cards, CardRatings cardRatings) { var deck = new List<Card>(); var creatures = cards .Where(x => x.Is().Creature) .OrderByDescending(x => cardRatings.GetRating(x.Name)) .ToList(); var bestCreatures = creatures .Take(MinCreatureCount); var otherCreatures = creatures.Skip(MinCreatureCount) .Take(MaxCreatureCount - MinCreatureCount); var spellsAndOtherCreatures = cards .Where(x => !x.Is().Creature && !x.Is().Land) .Concat(otherCreatures) .OrderByDescending(x => cardRatings.GetRating(x.Name)); deck.AddRange(bestCreatures); deck.AddRange(spellsAndOtherCreatures.Take(MaxSpellCount - deck.Count)); if (deck.Count < MinSpellCount) return null; return AddLands(deck, cards, cardRatings); }
private static void RemoveWorstCards(List<Card> deckNoLands, int count, CardRatings cardRatings) { var cardsToRemove = deckNoLands .OrderBy(x => cardRatings.GetRating(x.Name)) .Take(count); foreach (var card in cardsToRemove) { deckNoLands.Remove(card); } }
private static List<List<Card>> BuildDecks(IEnumerable<Card> cards, CardRatings cardRatings) { var decks = new List<List<Card>>(); for (var i = CardColor.White; i <= CardColor.Green; i++) { var cardWithColorI = cards .Where(x => x.IsMultiColored == false) .Where(x => x.HasColor(i) || x.HasColor(CardColor.Colorless) || x.Is().Land) .ToList(); var monoColoredDeck = TryBuildDeck(cardWithColorI, cardRatings); if (monoColoredDeck != null) decks.Add(monoColoredDeck); for (var j = i + 1; j <= CardColor.Green; j++) { var dual = cards .Where(x => x.HasColor(i) || x.HasColor(j) || x.HasColor(CardColor.Colorless) || x.Is().Land) .ToList(); var firstcolorCount = dual.Count(x => Cards.All[x.Name].HasColor(i)); var secondcolorCount = dual.Count(x => Cards.All[x.Name].HasColor(j)); if (firstcolorCount >= MinSplashColorCardCount && secondcolorCount >= MinSplashColorCardCount) { var dualDeck = TryBuildDeck(dual, cardRatings); if (dualDeck != null) decks.Add(dualDeck); } } } return decks; }
private List<DraftPlayer> CreatePlayers(int playerCount, CardRatings ratings, bool includeHumanPlayer) { var aiStrategies = new Func<IDraftingStrategy>[] { () => new Forcing(ratings), () => new Greedy(ratings), }; var players = new List<DraftPlayer>(); for (var i = 0; i < playerCount; i++) { players.Add(new DraftPlayer { Strategy = aiStrategies[RandomEx.Next(10) >= 3 ? 0 : 1]() }); } if (includeHumanPlayer) { players[0] = new DraftPlayer { Strategy = _userInterface }; } return players; }
private static List <List <Card> > BuildDecks(IEnumerable <Card> cards, CardRatings cardRatings) { var decks = new List <DeckCandidate>(); for (var i = CardColor.White; i <= CardColor.Green; i++) { var cardWithColorI = cards .Where(x => !x.IsMultiColored) .Where(x => x.HasColor(i) || x.HasColor(CardColor.Colorless) || x.Is().Land) .ToList(); var colorCount = cardWithColorI.Count(x => x.HasColor(i)); if (colorCount > 0) { var monoColoredDeck = BuildDeck(cardWithColorI, cardRatings); if (!decks.Any(x => x.Hash == monoColoredDeck.Hash)) { decks.Add(monoColoredDeck); } } for (var j = i + 1; j <= CardColor.Green; j++) { var dual = cards .Where(x => x.HasColor(i) || x.HasColor(j) || x.HasColor(CardColor.Colorless) || x.Is().Land) .ToList(); var firstcolorCount = dual.Count(x => Cards.All[x.Name].HasColor(i)); var secondcolorCount = dual.Count(x => Cards.All[x.Name].HasColor(j)); if (firstcolorCount > 0 && secondcolorCount > 0) { var dualDeck = BuildDeck(dual, cardRatings); if (!decks.Any(x => x.Hash == dualDeck.Hash)) { decks.Add(dualDeck); } } } } var playable = decks .Where(x => x.SpellCount == SpellCount) .OrderByDescending(x => x.Rating) .Select(x => x.Cards) .ToList(); if (playable.Count > 0) { return(playable); } var nonPlayable = decks .OrderByDescending(x => x.SpellCount) .Take(1) .Select(x => x.Cards).ToList(); return(nonPlayable); }
private static void AddNonBasicLands(List <int> distribution, List <Card> library, List <Card> deck, CardRatings cardRatings) { var nonBasicLands = library.Where(x => x.Is().Land).ToList(); var deckColors = distribution.Select((x, i) => x > 0 ? i : -1).Where(x => x >= 0).ToList(); var maxCountColor = distribution.IndexOf(distribution.Max()); var cardsToRemoveCount = 0; var landsToReplaceBasic = new List <Card>(); foreach (var land in nonBasicLands) { var rating = cardRatings.GetRating(land.Name); if (rating < MinNonBasicLandRating) { continue; } var landColors = land.ProducableManaColors; if (landColors.Count == 0) { deck.Add(land); cardsToRemoveCount++; } if (landColors.Count == 1) { if (deckColors.Contains(landColors[0])) { distribution[landColors[0]]--; landsToReplaceBasic.Add(land); } else if (landColors[0] == (int)CardColor.Colorless) { if (deckColors.Count > 1) { deck.Add(land); cardsToRemoveCount++; } else { distribution[maxCountColor]--; landsToReplaceBasic.Add(land); } } } else if (landColors.Count > 1) { var matchCount = landColors.Count(deckColors.Contains); if (matchCount >= 2) { distribution[maxCountColor]--; landsToReplaceBasic.Add(land); } } } if (cardsToRemoveCount > 0) { // Some lands do not replace existing lands // e.g if they do not produce mana. // For each such land remove worst cards from deck // so that deck count will be 40. RemoveWorstCards(deck, cardsToRemoveCount, cardRatings); } deck.AddRange(landsToReplaceBasic); }
private static DeckCandidate BuildDeck(List <Card> cards, CardRatings cardRatings) { var deck = new List <Card>(); var creatures = cards .Where(x => x.Is().Creature) .Select(x => { var convertedCost = x.ConvertedCost; if (convertedCost <= 2) { convertedCost = 2; } if (convertedCost >= 6) { convertedCost = 6; } return(new { Card = x, ConvertedCost = convertedCost, Rating = cardRatings.GetRating(x.Name) }); }) .GroupBy(x => x.ConvertedCost) .OrderBy(x => x.Key) .Select(x => { var cost = x.Key; var maxCreatureCount = CreaturesManaCurve[cost - 2]; var ordered = x.OrderByDescending(y => y.Rating) .ToList(); var selected = ordered .Take(maxCreatureCount) .Where(y => y.Rating > PlayableThreshold) .Select(y => new { y.Card, y.Rating }) .ToList(); var skipped = ordered .Where(y => !selected.Any(z => z.Card == y.Card)) .Select(y => new { y.Card, y.Rating }) .ToList(); return(new { Selected = selected, Skipped = skipped }); }) .ToList(); var selectedCreatures = creatures .SelectMany(x => x.Selected) .ToList(); var remaining = creatures .SelectMany(x => x.Skipped) .Concat(cards .Where(x => !x.Is().Creature&& !x.Is().Land) .Select(x => new { Card = x, Rating = cardRatings.GetRating(x.Name) })) .OrderByDescending(x => x.Rating) .ToList(); var selectedRemaining = remaining. Take(SpellCount - selectedCreatures.Count) .ToList(); var avarageRating = selectedCreatures.Concat(selectedRemaining) .Average(x => x.Rating); deck.AddRange(selectedCreatures.Select(x => x.Card)); deck.AddRange(selectedRemaining.Select(x => x.Card)); var spellCount = deck.Count; var landCount = DeckCardCount - spellCount; deck = AddLands(deck, cards, cardRatings, landCount); return(new DeckCandidate(deck, spellCount, avarageRating)); }