コード例 #1
0
		/// <summary>
		/// 
		/// </summary>
		/// <param name="pt"></param>
		/// <returns></returns>
		public override CardCollection GetCardsToDrag( Point pt )
		{
			// Loop backwards through all cards in this collection
			// and when we find a card that fits the bill, we return
			// that card and all cards on top of that card.
			// Also note that we don't allow dragging cards which are
			// face down.

			int i = base.Count - 1; 

			for ( ; i >= 0; i-- )
			{
				Card c = base.m_cards[ i ];
				if ( c.Contains( pt ) && c.FaceUp )
				{
					break;
				}
			}

			if ( i != -1 )
			{
				CardCollection cards = new CardCollection( );
				cards.AddRange( base.m_cards.GetRange( i, base.Count - i ) );
				return cards;
			}
			return null;
		}
コード例 #2
0
 public void Received(IEnumerable <Card> cards)
 {
     if (!this.IsTurnFinished)
     {
         _CardsReceived.AddRange(cards);
     }
     else
     {
         _CardsReceivedAfter.AddRange(cards);
     }
 }
コード例 #3
0
        public PileChangedEventArgs(Player player, Operation operation, IEnumerable <Card> cardsChanged)
            : this(player, operation)
        {
            switch (operation)
            {
            case PileChangedEventArgs.Operation.Added:
                _AddedCards.AddRange(cardsChanged);
                break;

            case PileChangedEventArgs.Operation.Removed:
                _RemovedCards.AddRange(cardsChanged);
                break;
            }
        }
コード例 #4
0
        void Produce(TextWriter report, Board board, Seat seat, Suit suit)
        {
            report.WriteLine("<td class='suit' colspan='2'>");
            switch (suit)
            {
            case Suit.Clubs: report.WriteLine("<span class='bsuit'>&clubs;</span>&nbsp;"); break;

            case Suit.Spades: report.WriteLine("<span class='bsuit'>&spades;</span>&nbsp;"); break;

            case Suit.Diamonds: report.WriteLine("<span class='rsuit'>&diams;</span>&nbsp;"); break;

            case Suit.Hearts: report.WriteLine("<span class='rsuit'>&hearts;</span>&nbsp;"); break;
            }
            var honours = new StringBuilder();
            var rags    = new StringBuilder();
            var cards   = new CardCollection();

            cards.AddRange(board.Hands[seat].Cards);
            cards.Sort((a, b) => (int)b.Rank - (int)a.Rank);
            foreach (Card card in cards)
            {
                if (card.Suit == suit)
                {
                    if (card.IsBiddingHonour)
                    {
                        honours.Append(card.ToString("P")[1]);
                    }
                    else
                    {
                        rags.Append(card.ToString("P")[1]);
                    }
                }
            }
            if (honours.Length > 0)
            {
                report.Write(honours.ToString());
            }
            if (rags.Length > 0)
            {
                report.Write("<span class='rags'>{0}</span>", rags.ToString());
            }

            report.WriteLine("</td>");
        }
コード例 #5
0
		protected override ChoiceResult Decide_Forge(Choice choice)
		{
			switch (choice.ChoiceType)
			{
				case ChoiceType.Cards:
					// Only trash Curses & Ruins
					CardCollection forgeToTrash = new CardCollection();

					// Always choose to trash all Curses
					forgeToTrash.AddRange(choice.Cards.Where(c => c.CardType == Cards.Universal.TypeClass.Curse));
					// Always choose to trash all Ruins
					forgeToTrash.AddRange(choice.Cards.Where(c => (c.Category & Category.Ruins) == Category.Ruins));

					return new ChoiceResult(forgeToTrash);

				case ChoiceType.Supplies:
					return new ChoiceResult(FindBestCardForCost(choice.Supplies.Values, null, false));

				default:
					return base.Decide_Forge(choice);
			}
		}
コード例 #6
0
		protected override ChoiceResult Decide_DameAnna(Choice choice)
		{
			if (choice.Text == "Choose up to 2 cards to trash")
			{
				CardCollection dameAnnaToTrash = new CardCollection();

				// Always choose to trash all Curses
				dameAnnaToTrash.AddRange(choice.Cards.Where(c => c.CardType == Cards.Universal.TypeClass.Curse).Take(2));
				// Always choose to trash all Ruins
				dameAnnaToTrash.AddRange(choice.Cards.Where(c => (c.Category & Category.Ruins) == Category.Ruins).Take(2 - dameAnnaToTrash.Count));

				return new ChoiceResult(dameAnnaToTrash);
			}
			else if (choice.Text == "Choose a card to trash")
				return new ChoiceResult(new CardCollection(FindBestCardsToTrash(choice.Cards, 1)));
			else
				return base.Decide_Rogue(choice);
		}
コード例 #7
0
		protected override ChoiceResult Decide_Chapel(Choice choice)
		{
			CardCollection chapelToTrash = new CardCollection();

			// Always choose to trash all Curses
			chapelToTrash.AddRange(choice.Cards.Where(c => c.CardType == Cards.Universal.TypeClass.Curse).Take(4));
			// Always choose to trash all Ruins
			chapelToTrash.AddRange(choice.Cards.Where(c => (c.Category & Category.Ruins) == Category.Ruins).Take(4 - chapelToTrash.Count));

			return new ChoiceResult(chapelToTrash);
		}
コード例 #8
0
		protected override ChoiceResult Decide_Cellar(Choice choice)
		{
			CardCollection cellarCards = new CardCollection();
			// TODO -- the AI makes slightly bad decisions when it comes to Cellar -- Fix me!
			cellarCards.AddRange(choice.Cards.Where(c => c.CardType == Cards.Base.TypeClass.Cellar));
			cellarCards.AddRange(choice.Cards.Where(c => c.CardType == Cards.Universal.TypeClass.Curse));
			cellarCards.AddRange(choice.Cards.Where(c => (c.Category & Category.Ruins) == Category.Ruins));
			cellarCards.AddRange(choice.Cards.Where(c => c.CardType == Cards.Hinterlands.TypeClass.Tunnel));
			cellarCards.AddRange(choice.Cards.Where(c => c.CardType == Cards.DarkAges.TypeClass.Hovel));
			cellarCards.AddRange(choice.Cards.Where(c => c.CardType == Cards.DarkAges.TypeClass.OvergrownEstate));
			cellarCards.AddRange(choice.Cards.Where(c => c.CardType == Cards.DarkAges.TypeClass.Rats));
			cellarCards.AddRange(choice.Cards.Where(c => (c.Category == Category.Victory && c.CardType != Cards.Universal.TypeClass.Estate && c.CardType != Cards.Universal.TypeClass.Province)));
			if (choice.Cards.Count(c => c.CardType == Cards.Universal.TypeClass.Estate) > 0)
				cellarCards.AddRange(choice.Cards.Where(c => c.CardType == Cards.Universal.TypeClass.Estate).Take(choice.Cards.Count(c => c.CardType == Cards.Universal.TypeClass.Estate) - choice.Cards.Count(c => c.CardType == Cards.Intrigue.TypeClass.Baron)));
			if (choice.Cards.Count(c => c.CardType == Cards.Universal.TypeClass.Province) > 0)
				cellarCards.AddRange(choice.Cards.Where(c => c.CardType == Cards.Universal.TypeClass.Province).Take(choice.Cards.Count(c => c.CardType == Cards.Universal.TypeClass.Province) - choice.Cards.Count(c => c.CardType == Cards.Cornucopia.TypeClass.Tournament)));
			if (this.GameProgress < 0.63)
				cellarCards.AddRange(choice.Cards.Where(c => c.CardType == Cards.Universal.TypeClass.Copper || c.CardType == Cards.Guilds.TypeClass.Masterpiece));

			return new ChoiceResult(cellarCards);
		}
コード例 #9
0
		protected override IEnumerable<Card> FindBestCards(IEnumerable<Card> cards, int count)
		{
			// Choose the most expensive cards

			CardCollection cardsToReturn = new CardCollection();

			cardsToReturn.AddRange(cards.OrderByDescending(c => c.BaseCost).ThenBy(c => c.Name).Take(count));

			return cardsToReturn;
		}
コード例 #10
0
		protected override IEnumerable<Card> FindBestCardsToTrash(IEnumerable<Card> cards, int count)
		{
			// choose the worse card in hand in this order
			// 1) curse
			// 2) cheapest card left

			CardCollection cardsToTrash = new CardCollection();
			cardsToTrash.AddRange(cards.Where(c => c.Category == Category.Curse).Take(count));
			if (cardsToTrash.Count >= count)
				return cardsToTrash;

			cardsToTrash.AddRange(cards.OrderBy(c => c.BaseCost).ThenBy(c => c.Name).Where(c => !cardsToTrash.Contains(c)).Take(count - cardsToTrash.Count));

			return cardsToTrash;
		}
コード例 #11
0
		private void PerformCleanup()
		{
			// Sets up card movements to indicate where each card should go.
			CardMovementCollection cardsToMove = new CardMovementCollection(this.SetAside, c => c.CanCleanUp, DeckLocation.SetAside, DeckLocation.Discard);
			cardsToMove.AddRange(this.Hand, DeckLocation.Hand, DeckLocation.Discard);
			cardsToMove.AddRange(this.InPlay, DeckLocation.InPlay, DeckLocation.Discard);

			foreach (Card durationCard in this.InPlay.Where(c => !c.CanCleanUp))
				cardsToMove[durationCard].Destination = DeckLocation.SetAside;
			IEnumerable<CardMovement> inPlayCards = cardsToMove.Where(cm => cm.CurrentLocation == DeckLocation.InPlay);

			ParallelQuery<CardMovement> pqCardsToMove = cardsToMove.AsParallel().Where(cm =>
				cm.CurrentLocation == DeckLocation.InPlay &&
				cm.Destination == DeckLocation.SetAside &&
				cm.Card.ModifiedBy != null &&
				cardsToMove.Contains(cm.Card.ModifiedBy.PhysicalCard) &&
				cardsToMove[cm.Card.ModifiedBy.PhysicalCard].Destination == DeckLocation.Discard);

			pqCardsToMove.ForAll(cm => cardsToMove[cm.Card.ModifiedBy.PhysicalCard].Destination = DeckLocation.SetAside);

			int drawSize = 5;
			if (CleaningUp != null)
			{
				Boolean cancelled = false;
				// Possibly changing events that can happen in the game
				CleaningUpEventArgs cuea = null;

				do
				{
					cuea = new CleaningUpEventArgs(this, 5, ref cardsToMove);
					cuea.Cancelled |= cancelled;
					CleaningUp(this, cuea);

					OptionCollection options = new OptionCollection();
					IEnumerable<Type> cardTypes = cuea.Actions.Keys;
					foreach (Type key in cardTypes)
						options.Add(new Option(cuea.Actions[key].Text, false));
					if (options.Count > 0)
					{
						options.Sort();
						Choice choice = new Choice("Performing Clean-up", options, this, cuea);
						ChoiceResult result = this.MakeChoice(choice);

						if (result.Options.Count > 0)
							cuea.Actions.First(kvp => kvp.Value.Text == result.Options[0]).Value.Method(this, ref cuea);
						else
							break;
					}
					else
						break;

					cancelled |= cuea.Cancelled;
				} while (CleaningUp != null);

				if (cuea != null)
					cancelled |= cuea.Cancelled;

				if (cancelled)
					return;

				if (cuea.NextPlayer != null)
					_CurrentTurn.NextPlayer = cuea.NextPlayer;
				_CurrentTurn.NextGrantedBy = cuea.NextGrantedBy;
				drawSize = cuea.DrawSize;
			}

			// Discard any Revealed cards (should be none?)
			this.DiscardRevealed();

			CardsDiscardAction cdaHand = null;
			if (cardsToMove.Count(c => c.CurrentLocation == DeckLocation.Hand) > 0)
				cdaHand = new CardsDiscardAction(this, null, "Discard hand", player_DiscardHand, true) { Data = cardsToMove };

			// Discard non-Duration (or Duration-modifying) cards in In Play & Set Aside at the same time
			this.Discard(DeckLocation.InPlayAndSetAside, cardsToMove.Where(cm =>
				(cm.CurrentLocation == DeckLocation.InPlay || cm.CurrentLocation == DeckLocation.SetAside) &&
				cm.Destination == DeckLocation.Discard).Select<CardMovement, Card>(cm => cm.Card), cdaHand);

			// Discard Hand
			this.AddCardsInto(DeckLocation.Discard,
				this.RetrieveCardsFrom(DeckLocation.Hand, c =>
					cardsToMove[c].CurrentLocation == DeckLocation.Hand && cardsToMove[c].Destination == DeckLocation.Discard));

			// Move Duration (and Duration-modifying) cards from In Play into Set Aside
			this.MoveInPlayToSetAside(c => cardsToMove.Contains(c) && cardsToMove[c].CurrentLocation == DeckLocation.InPlay && cardsToMove[c].Destination == DeckLocation.SetAside);

			// Move any cards that have had their Destination changed to their appropriate locations
			IEnumerable<Card> replaceCards = cardsToMove.Where(cm => cm.Destination == DeckLocation.Deck).Select(cm => cm.Card);
			if (replaceCards.Count() > 0)
			{
				Choice replaceChoice = new Choice("Choose order of cards to put back on your deck", null, replaceCards, this, true, replaceCards.Count(), replaceCards.Count());
				ChoiceResult replaceResult = this.MakeChoice(replaceChoice);
				this.RetrieveCardsFrom(DeckLocation.InPlay, c => cardsToMove[c].CurrentLocation == DeckLocation.InPlay && replaceResult.Cards.Contains(c));
				this.RetrieveCardsFrom(DeckLocation.SetAside, c => cardsToMove[c].CurrentLocation == DeckLocation.SetAside && replaceResult.Cards.Contains(c));
				this.AddCardsToDeck(replaceResult.Cards, DeckPosition.Top);
			}

#if DEBUG
			if (this.InPlay.Count > 0)
				throw new Exception("Something happened -- there are cards left in the player's In Play area!");
#endif

			if (CurrentTurn != null)
				CurrentTurn.Finished();

			_Actions = _Buys = 0;
			_Currency.Coin.Value = 0;
			_Currency.Potion.Value = 0;
			_ActionsPlayed = 0;

#if DEBUG
			// Check to see that there are no duplicate cards anywhere
			CardCollection allCards = new CardCollection();
			allCards.AddRange(this.Hand);
			allCards.AddRange(this.Revealed);
			allCards.AddRange(this.Private);
			allCards.AddRange(this.InPlay);
			allCards.AddRange(this.SetAside);
			allCards.AddRange(this.DrawPile.LookThrough(c => true));
			allCards.AddRange(this.DiscardPile.LookThrough(c => true));
			foreach (CardMat mat in this.PlayerMats.Values)
				allCards.AddRange(mat);

			ParallelQuery<Card> duplicateCards = allCards.AsParallel().Where(c => allCards.Count(ct => ct == c) > 1);

			//IEnumerable<Card> duplicateCards = allCards.FindAll(c => allCards.Count(ct => ct == c) > 1);
			if (duplicateCards.Count() > 0)
			{
				// Ruh Roh
				throw new Exception("Duplicate cards found!  Something went wrong!");
			}
#endif

			DrawHand(drawSize);
			if (CleanedUp != null)
			{
				CleanedUp(this, new CleanedUpEventArgs(this, drawSize));
			}
			if (TurnEnded != null)
			{
				TurnEnded(this, new TurnEndedEventArgs(this));
			}
		}
コード例 #12
0
		protected override ChoiceResult Decide_Stash(Choice choice)
		{
			// For now, always put Stash on top of the draw pile
			// This is very bad for instances involving Thief or Saboteur, but for now, it'll function
			CardCollection cards = new CardCollection();
			cards.AddRange(choice.Cards.Where(c => c.CardType == Cards.Promotional.TypeClass.Stash));
			cards.AddRange(choice.Cards.Where(c => c.CardType != Cards.Promotional.TypeClass.Stash));
			return new ChoiceResult(cards);
		}
コード例 #13
0
		protected override ChoiceResult Decide_Herald(Choice choice)
		{
			switch (choice.ChoiceType)
			{
				case ChoiceType.Options:
					for (int index = choice.Options.Count - 1; index >= 0; index--)
					{
						// Overpay by up to the amount of cards we have in our discard pile,
						// excluding Coppers, Curses, Ruins, Victory cards, & Shelters
						Currency overpayAmount = new DominionBase.Currency(choice.Options[index].Text);
						if (overpayAmount.Potion.Value > 0)
							continue;

						if (this.DiscardPile.LookThrough(c => 
							c.CardType != Cards.Universal.TypeClass.Copper &&
							c.CardType != Cards.Universal.TypeClass.Curse &&
							(c.Category & Category.Ruins) != Category.Ruins &&
							(c.Category & Category.Shelter) != Category.Shelter &&
							c.Category != Category.Victory &&
							c.CardType != Cards.Hinterlands.TypeClass.Tunnel).Count >= overpayAmount.Coin.Value)
							return new ChoiceResult(new List<String>() { choice.Options[index].Text });
					}
					return base.Decide_Herald(choice);

				case ChoiceType.Cards:
					// Find highest in-deck value cards to put on top
					// While ignoring Victory cards, Curses, & Shelters
					CardCollection heraldCards = new CardCollection(choice.Cards
						.Where(c => c.Category != Category.Victory &&
							c.CardType != Cards.Universal.TypeClass.Curse &&
							c.CardType != Cards.Hinterlands.TypeClass.Tunnel &&
							(c.Category & Category.Shelter) != Category.Shelter)
						.OrderByDescending(c => ComputeValueInDeck(c))
						.Take(choice.Minimum));

					// If this doesn't lead to enough cards, then include Shelters
					if (heraldCards.Count < choice.Minimum)
						heraldCards.AddRange(choice.Cards
							.Where(c => (c.Category & Category.Shelter) == Category.Shelter)
							.Take(choice.Minimum - heraldCards.Count));

					// If this *still* doesn't include enough cards, include Victory cards
					if (heraldCards.Count < choice.Minimum)
						heraldCards.AddRange(choice.Cards
							.Where(c => c.Category == Category.Victory ||
								c.CardType == Cards.Hinterlands.TypeClass.Tunnel)
							.OrderByDescending(c => ComputeValueInDeck(c))
							.Take(choice.Minimum - heraldCards.Count));

					// Uh... our deck is absolutely shit.  Just take the first however many cards
					if (heraldCards.Count < choice.Minimum)
						heraldCards = new CardCollection(choice.Cards
						.OrderByDescending(c => ComputeValueInDeck(c))
						.Take(choice.Minimum));

					return new ChoiceResult(heraldCards);

				default:
					return base.Decide_Herald(choice);
			}
		}
コード例 #14
0
ファイル: Deck.cs プロジェクト: VictorGressier/skul
		/// <summary>
		/// Removes the first count cards and returns them.
		/// </summary>
		/// <param name="count"></param>
		/// <returns></returns>
		public CardCollection RemoveCards( int count )
		{
			CardCollection cards = new CardCollection( );

			cards.AddRange( m_cards.GetRange( 0, count ) );
			m_cards.RemoveRange( 0, count );

			return cards;
		}
コード例 #15
0
		public override CardCollection CardStack()
		{
			CardCollection cc = new CardCollection() { this };
			if (this.ClonedCard != null)
				cc.AddRange(this.ClonedCard.CardStack());
			return cc;
		}
コード例 #16
0
		internal void player_GainMandarin(Player player, ref Players.CardGainEventArgs e)
		{
			CardCollection cardsInPlay = new CardCollection(player.InPlay[Cards.Category.Treasure]);
			cardsInPlay.AddRange(player.SetAside[Cards.Category.Treasure]);
			Choice replaceChoice = new Choice("Choose order of Treasure cards to put back on your deck", this, cardsInPlay, player, true, cardsInPlay.Count, cardsInPlay.Count);
			ChoiceResult replaceResult = player.MakeChoice(replaceChoice);

			player.RetrieveCardsFrom(DeckLocation.InPlay, c => replaceResult.Cards.Contains(c));
			player.RetrieveCardsFrom(DeckLocation.SetAside, c => replaceResult.Cards.Contains(c));

			player.AddCardsToDeck(replaceResult.Cards, DeckPosition.Top);

			e.HandledBy.Add(TypeClass.Mandarin);

			// Clear out the Event Triggers -- this only happens when its Gained, so we don't care any more
			foreach (Player playerLoop in _CardGainedHandlers.Keys)
				playerLoop.CardGained -= _CardGainedHandlers[playerLoop];
			_CardGainedHandlers.Clear();
		}
コード例 #17
0
		private CardCollection GetSelectableCards(CleaningUpEventArgs e)
		{
			CardCollection allInPlayCards = new CardCollection();
			allInPlayCards.AddRange(e.CardsMovements.Where(cm =>
				((cm.Card.Category & Cards.Category.Action) == Cards.Category.Action) &&
				cm.CurrentLocation == DeckLocation.InPlay &&
				(cm.Destination == DeckLocation.SetAside || cm.Destination == DeckLocation.Discard)).Select(cm => cm.Card));

			// This is used to separate the In Play from the Set Aside for the Choice.MakeChoice call
			allInPlayCards.Add(new Universal.Dummy());

			allInPlayCards.AddRange(e.CardsMovements.Where(cm =>
				((cm.Card.Category & Cards.Category.Action) == Cards.Category.Action) &&
				cm.CurrentLocation == DeckLocation.SetAside &&
				cm.Destination == DeckLocation.Discard).Select(cm => cm.Card));

			if (allInPlayCards.FirstOrDefault() is Universal.Dummy)
				allInPlayCards.RemoveAt(0);
			if (allInPlayCards.LastOrDefault() is Universal.Dummy)
				allInPlayCards.RemoveAt(allInPlayCards.Count - 1);

			return allInPlayCards;
		}
コード例 #18
0
 public void Bought(IEnumerable <Card> cards)
 {
     _CardsBought.AddRange(cards);
 }
コード例 #19
0
		protected override ChoiceResult Decide_SecretChamber(Choice choice)
		{
			if (choice.Text == "Choose order of cards to put back on your deck")
			{
				// Order all the cards
				IEnumerable<Card> cardsToReturn = this.FindBestCardsToDiscard(choice.Cards, choice.Cards.Count());

				// Try to save 1 Curse if we can
				if (choice.CardTriggers[0].CardType == Cards.Prosperity.TypeClass.Mountebank)
				{
					cardsToReturn = cardsToReturn.Take(3);
					if (cardsToReturn.ElementAt(0).CardType == Cards.Universal.TypeClass.Curse)
						return new ChoiceResult(new CardCollection(cardsToReturn.Skip(1)));
					if (cardsToReturn.ElementAt(1).CardType == Cards.Universal.TypeClass.Curse)
						return new ChoiceResult(new CardCollection() { cardsToReturn.ElementAt(0), cardsToReturn.ElementAt(2)});
				}
				
				// Try to not put Treasure cards onto our deck, even if that means putting Action cards there
				else if (choice.CardTriggers[0].CardType == Cards.Seaside.TypeClass.PirateShip)
				{
					CardCollection pirateShipCards = new CardCollection(cardsToReturn.Where(c => (c.Category & Category.Treasure) != Category.Treasure));
					if (pirateShipCards.Count < 2)
						pirateShipCards.AddRange(cardsToReturn.Where(c => (c.Category & Category.Treasure) != Category.Treasure).Take(2 - pirateShipCards.Count));
					return new ChoiceResult(pirateShipCards);
				}

				return new ChoiceResult(new CardCollection(cardsToReturn.Take(2)));
			}
			else
			{
				CardCollection scCards = new CardCollection();
				foreach (Card card in choice.Cards)
				{
					if (card.Category == Category.Curse ||
						((card.Category & Category.Victory) == Category.Victory && (card.Category & Category.Treasure) != Category.Treasure) ||
						(card.CardType == Cards.Universal.TypeClass.Copper && this.RealThis.InPlay[Cards.Intrigue.TypeClass.Coppersmith].Count == 0) ||
						(this.RealThis.Actions == 0 && (card.Category & Category.Treasure) != Category.Treasure))
						scCards.Add(card);
				}
				return new ChoiceResult(scCards);
			}
		}
コード例 #20
0
ファイル: HandEvaluator.cs プロジェクト: bberak/PokerDotNet
        public bool CheckHighestPairConfiguration(out Hand hand)
        {
            checkCardList();

            // make a copy
            //List<Card> cardList = new List<Card>(_cardList);
            CardCollection cardList = new CardCollection(_cardList);
            cardList.Sort();

            // this is a list of cards that match the key value
            Dictionary<int, CardCollection> matches = new Dictionary<int, CardCollection>();

            int numPairs = 0;
            int numThrees = 0;
            int numFours = 0;

            // Construct the dictionary
            foreach (Card card in cardList)
            {
                if (matches.ContainsKey(card.Value))
                    matches[card.Value].Add(card);
                else
                    matches.Add(card.Value, new CardCollection(new Card[] { card }));
                    //matches.Add(card.Value, new List<Card>(new Card[] { card }));
            }

            // Determine the number of pairs, threes, and fours
            //foreach (List<Card> cardPairs in matches.Values)
            foreach (CardCollection cardPairs in matches.Values)
            {
                if (cardPairs.Count == 2)
                    numPairs++;

                if (cardPairs.Count == 3)
                    numThrees++;

                if (cardPairs.Count == 4)
                    numFours++;
            }

            //List<Card> resultCards = new List<Card>();
            CardCollection resultCards = new CardCollection();

            // Okay, here comes the real logic
            // One Pair and One Pair Only
            if (numPairs == 1 && numThrees == 0 && numFours == 0)
            {
                // Continue with the assumption that we'll only find one pair
                foreach (int cardValue in matches.Keys)
                {
                    if (matches[cardValue].Count == 2) // this is our pair
                    {
                        resultCards.AddRange(matches[cardValue]);
                        break;
                    }
                }

                // Also add the next highest card
                for (int highCard = cardList.Count - 1; highCard >= 0; highCard--)
                {
                    if (!resultCards.Contains(cardList[highCard]))
                    {
                        // Add the next highest card from the sorted list and break
                        resultCards.Add(cardList[highCard]);
                        break;
                    }
                }

                // Construct the Best Hand for one pair and return true
                //hand = new BestHand(resultCards, HandType.OnePair);
                hand = new Hand(resultCards, Combination.OnePair);
                return true;
            }

            // Two Pair and two pair only
            else if (numPairs >= 2 && numThrees == 0 && numFours == 0)
            {
                int numPairsFound = 0;

                // Continue with the assumption that we'll only find two pairs
                foreach (int cardValue in new Stack<int>(matches.Keys))
                {
                    if (matches[cardValue].Count == 2) // this is our pair
                    {
                        resultCards.AddRange(matches[cardValue]);
                        numPairs++;
                        if (numPairsFound >= 2)
                            break;
                    }
                }

                // Also add the next highest card
                for (int highCard = cardList.Count - 1; highCard >= 0; highCard--)
                {
                    if (!resultCards.Contains(cardList[highCard]))
                    {
                        // Add the next highest card from the sorted list and break
                        resultCards.Add(cardList[highCard]);
                        break;
                    }
                }

                // Construct the Best Hand for one pair and return true
                //hand = new BestHand(resultCards, HandType.TwoPair);
                hand = new Hand(resultCards, Combination.TwoPair);
                return true;
            }

            // Three of a kind only
            else if (numPairs == 0 && numThrees >= 1 && numFours == 0)
            {
                foreach (int cardValue in new Stack<int>(matches.Keys))
                {
                    if (matches[cardValue].Count == 3) // this is our highest 3
                    {
                        resultCards.AddRange(matches[cardValue]);
                        break;
                    }
                }

                // Also add the next highest card
                for (int highCard = cardList.Count - 1; highCard >= 0; highCard--)
                {
                    if (!resultCards.Contains(cardList[highCard]))
                    {
                        // Add the next highest card from the sorted list and break
                        resultCards.Add(cardList[highCard]);
                        break;
                    }
                }

                // Construct the Best Hand for one pair and return true
                //hand = new BestHand(resultCards, HandType.ThreeOfAKind);
                hand = new Hand(resultCards, Combination.ThreeOfAKind);
                return true;
            }

            // four of a kind only
            else if (numPairs <= 1 && numThrees <= 1 && numFours == 1)
            {
                foreach (int cardValue in new Stack<int>(matches.Keys))
                {
                    if (matches[cardValue].Count == 4) // this is the 4
                    {
                        resultCards.AddRange(matches[cardValue]);
                        break;
                    }
                }

                // Also add the next highest card
                for (int highCard = cardList.Count - 1; highCard >= 0; highCard--)
                {
                    if (!resultCards.Contains(cardList[highCard]))
                    {
                        resultCards.Add(cardList[highCard]);
                        break;
                    }
                }

                // Construct the Best Hand for one pair and return true
                //hand = new BestHand(resultCards, HandType.FourOfAKind);
                hand = new Hand(resultCards, Combination.FourOfAKind);
                return true;
            }

            // Full house only
            else if (numPairs >= 1 && numThrees == 1 && numFours == 0)
            {
                foreach (int cardValue in new Stack<int>(matches.Keys))
                {
                    if (matches[cardValue].Count == 3) // this is the 3 in the full house
                        resultCards.AddRange(matches[cardValue]);

                    if (matches[cardValue].Count == 2) // this is the 2
                        resultCards.AddRange(matches[cardValue]);

                    if (resultCards.Count >= 5)
                        break;
                }

                // Construct the Best Hand for one pair and return true
                //hand = new BestHand(resultCards, HandType.FullHouse);
                hand = new Hand(resultCards, Combination.FullHouse);
                return true;
            }

            else
            {
                // Just return the high card
                //List<Card> highCard = new List<Card>();
                CardCollection highCard = new CardCollection();
                highCard.Add(cardList[cardList.Count - 1]);
                //hand = new BestHand(highCard, HandType.HighCard);
                hand = new Hand(highCard, Combination.HighCard);
                return false;
            }
        }
コード例 #21
0
		protected override ChoiceResult Decide_Vault(Choice choice)
		{
			switch (choice.ChoiceType)
			{
				case ChoiceType.Options:
					// If there are at least 2 non-Action & non-Treasure cards, discard 2 of them
					IEnumerable<Card> vaultDiscardableCards = this.RealThis.Hand[c =>
						(c.Category & Category.Treasure) != Category.Treasure &&
						(c.Category & Category.Action) != Category.Action];

					if (vaultDiscardableCards.Count() >= 2)
						return new ChoiceResult(new List<String>() { choice.Options[0].Text });
					else
						return new ChoiceResult(new List<String>() { choice.Options[1].Text });

				case ChoiceType.Cards:
					if (choice.Text.StartsWith("Discard any number of cards"))
					{
						/// TODO -- this needs to be a bit smarter.  It shouldn't discard Action cards if we have 1+ Actions left
						/// It can also be improved to chain with Tactician (and so can Secret Chamber, for that matter)
						// Discard all non-Treasure cards
						return new ChoiceResult(new CardCollection(choice.Cards.Where(c => (c.Category & Category.Treasure) != Category.Treasure)));
					}
					else // "Choose 2 cards to discard"
					{
						CardCollection vDiscards = new CardCollection();
						vDiscards.AddRange(choice.Cards.Where(c => (c.Category & Category.Curse) == Category.Curse));
						if (vDiscards.Count < 2)
							vDiscards.AddRange(choice.Cards.Where(card => (card.Category & Category.Ruins) == Category.Ruins));
						if (vDiscards.Count < 2)
							vDiscards.AddRange(choice.Cards.Where(card => card.Category == Category.Victory));
						if (vDiscards.Count > 2)
							vDiscards.RemoveRange(2, vDiscards.Count - 2);
						else
							vDiscards.AddRange(this.FindBestCardsToDiscard(choice.Cards, 2 - vDiscards.Count));
						return new ChoiceResult(vDiscards);
					}

				default:
					return base.Decide_Vault(choice);
			}
		}
コード例 #22
0
		protected IEnumerable<Card> FindBestCardsToTrash(IEnumerable<Card> cards, int count, Boolean onlyReturnTrashables)
		{
			// choose the worse card in hand in this order
			// 1) curse
			// 2) any ruins
			// 3) Sea Hag if there are no curses left
			// 4) Loan if we have fewer than 3 Coppers left
			// 5) Copper if we've got a lot of better Treasure
			// 6) Fortress
			// (If onlyReturnTrashables is false):
			// 7) lowest value from ComputeValueInDeck

			CardCollection cardsToTrash = new CardCollection();
			cardsToTrash.AddRange(cards.Where(c => c.Category == Category.Curse).Take(count));
			if (cardsToTrash.Count >= count)
				return cardsToTrash;

			cardsToTrash.AddRange(cards.Where(c => (c.Category & Category.Ruins) == Category.Ruins).Take(count - cardsToTrash.Count));
			if (cardsToTrash.Count >= count)
				return cardsToTrash;

			if (this.RealThis._Game.Table.Curse.Count <= 1)
			{
				cardsToTrash.AddRange(cards.Where(c => c.CardType == Cards.Seaside.TypeClass.SeaHag).Take(count - cardsToTrash.Count));
				if (cardsToTrash.Count >= count)
					return cardsToTrash;
			}

			cardsToTrash.AddRange(cards.Where(c => c.CardType == Cards.DarkAges.TypeClass.OvergrownEstate).Take(count - cardsToTrash.Count));
			if (cardsToTrash.Count >= count)
				return cardsToTrash;

			cardsToTrash.AddRange(cards.Where(c => c.CardType == Cards.DarkAges.TypeClass.Hovel).Take(count - cardsToTrash.Count));
			if (cardsToTrash.Count >= count)
				return cardsToTrash;

			if (this.RealThis.CountAll(this.RealThis, c => (c.Category & Category.Treasure) == Category.Treasure && (c.Benefit.Currency.Coin > 1 || c.CardType == Cards.Prosperity.TypeClass.Bank)) >=
				this.RealThis.CountAll(this.RealThis, c => c.CardType == Cards.Universal.TypeClass.Copper))
			{
				cardsToTrash.AddRange(cards.Where(c => c.CardType == Cards.Universal.TypeClass.Copper).Take(count - cardsToTrash.Count));
				if (cardsToTrash.Count >= count)
					return cardsToTrash;
			}

			if (this.RealThis.CountAll(this.RealThis, c => c.CardType == Cards.Universal.TypeClass.Copper) < 3)
			{
				cardsToTrash.AddRange(cards.Where(c => c.CardType == Cards.Prosperity.TypeClass.Loan).Take(count - cardsToTrash.Count));
				if (cardsToTrash.Count >= count)
					return cardsToTrash;
			}

			cardsToTrash.AddRange(cards.Where(c => c.CardType == Cards.DarkAges.TypeClass.Fortress).Take(count - cardsToTrash.Count));
			if (cardsToTrash.Count >= count)
				return cardsToTrash;

			if (!onlyReturnTrashables)
				cardsToTrash.AddRange(cards.OrderBy(c => ComputeValueInDeck(c)).ThenBy(c => c.Name).Where(c => !cardsToTrash.Contains(c)).Take(count - cardsToTrash.Count));

			return cardsToTrash;
		}
コード例 #23
0
		public CardCollection DrawFrom(DeckPosition deckPosition, int number, Object destination)
		{
			CardCollection cards = new CardCollection();
			if (number <= 0)
				return cards;

			CardCollection cardsFirst = _DrawPile.Retrieve(this, deckPosition, c => true, number);
			cards.AddRange(cardsFirst);
			cards.RemovedFrom(DeckLocation.Deck, this);

			if (_AsynchronousDrawing)
			{
				if (_AsynchronousCardsDrawnEventArgs == null)
					_AsynchronousCardsDrawnEventArgs = new CardsDrawnEventArgs(cardsFirst, deckPosition, number);
				else
					_AsynchronousCardsDrawnEventArgs.Cards.AddRange(cardsFirst);
			}
			else if (CardsDrawn != null)
			{
				CardsDrawnEventArgs cdea = new CardsDrawnEventArgs(cardsFirst, deckPosition, number);
				CardsDrawn(this, cdea);
			}

			if (destination is Type)
				this.AddCardsInto((Type)destination, cardsFirst);
			else if (destination is DeckLocation)
				this.AddCardsInto((DeckLocation)destination, cardsFirst);
			else
				throw new Exception(String.Format("Destination of {0} ({1}) is not supported", destination, destination.GetType()));
			
			if (cardsFirst.Count < number && _DrawPile.Count == 0 && _DiscardPile.Count > 0)
			{
				this.ShuffleForDrawing();

				CardCollection cardsSecond = _DrawPile.Retrieve(this, deckPosition, c => true, number < 0 ? number : number - cards.Count);
				cards.AddRange(cardsSecond);
				cardsSecond.RemovedFrom(DeckLocation.Deck, this);

				if (_AsynchronousDrawing)
				{
					if (_AsynchronousCardsDrawnEventArgs == null)
						_AsynchronousCardsDrawnEventArgs = new CardsDrawnEventArgs(cardsSecond, deckPosition, number);
					else
						_AsynchronousCardsDrawnEventArgs.Cards.AddRange(cardsSecond);
				}
				else if (CardsDrawn != null)
				{
					CardsDrawnEventArgs cdea = new CardsDrawnEventArgs(cardsSecond, deckPosition, number);
					CardsDrawn(this, cdea);
				}

				if (destination is Type)
					this.AddCardsInto((Type)destination, cardsSecond);
				else if (destination is DeckLocation)
					this.AddCardsInto((DeckLocation)destination, cardsSecond);
				else
					throw new Exception(String.Format("Destination of {0} ({1}) is not supported", destination, destination.GetType()));
			}

			return cards;
		}
コード例 #24
0
		protected override IEnumerable<Card> FindBestCardsToDiscard(IEnumerable<Card> cards, int count)
		{
			// choose the worse card in hand in this order
			// 1) positive victory points
			// 2) curse
			// 3) cheapest card left

			CardCollection cardsToDiscard = new CardCollection();
			CardCollection cardsLeftOver = new CardCollection();
			foreach (Card card in cards)
			{
				if (card.Category == Category.Victory)
					cardsToDiscard.Add(card);
				else
					cardsLeftOver.Add(card);
				if (cardsToDiscard.Count >= count)
					break;
			}
			if (cardsToDiscard.Count >= count)
				return cardsToDiscard;
			cardsToDiscard.AddRange(FindBestCardsToTrash(cardsLeftOver, count - cardsToDiscard.Count));
			return cardsToDiscard;
		}