Example #1
0
CString CForce::GetFullDescription()
{
	return FormString("Play the %s from %s to force out the opponents' %s.",
					   CardToString(MAKEDECKVALUE(m_nSuit,m_nCardVal)),
					   (m_nTargetHand == IN_HAND)? "hand" : "dummy",
					   CardValToString(m_nTargetCardVal));
}
//
// PlayBestCard()
//
// called on the third and fourth hand plays to try to win the trick
//
CCard* CPlayEngine::PlayBestCard(int nPosition)
{
	CPlayerStatusDialog& status = *m_pStatusDlg;
//	status << "2PLAY3! Playing best card.\n";

	// get play info
	CCard* pCurrentCard = pDOC->GetCurrentTrickCardLed();
	int nSuitLed = pCurrentCard->GetSuit();
	int nTopPos;
	CCard* pCurrTopCard = pDOC->GetCurrentTrickHighCard(&nTopPos);
	CString strTopCardPos = PositionToString(nTopPos);
	BOOL bPartnerHigh = FALSE;
	int nCurrentRound = pDOC->GetPlayRound();
	int nCurrentSeat = pDOC->GetNumCardsPlayedInRound() + 1;
	CCard* pPartnersCard = pDOC->GetCurrentTrickCard(m_pPartner->GetPosition());
	if (pPartnersCard == pCurrTopCard)
		bPartnerHigh = TRUE;
	// 
	int nTrumpSuit = pDOC->GetTrumpSuit();
	int numCardsInSuitLed = m_pHand->GetNumCardsInSuit(nSuitLed);
	// card to play
	CCard* pCard = NULL;

	// 
	// first see if somebody trumped in this hand
	//
	if ((pDOC->WasTrumpPlayed()) && (nTrumpSuit != nSuitLed))
	{
		// a trump has been played 
		// see whether it was played by partner or by an opponent
		if (bPartnerHigh)
		{
			// partner trumped -- leave it alone for now
			pCard = GetDiscard();
			status << "PLAYB10! We let partner's " & pCurrTopCard->GetName() & " trump ride and discard the " &
					  pCard->GetName() & ".\n";
		}
		else
		{
			// it was an opponent that did the trumping
			// see if we can overtrump
			CSuitHoldings& trumpSuit = m_pHand->GetSuit(nTrumpSuit);
			CCard* pTopTrump = NULL;
			if (trumpSuit.GetNumCards() > 0)
				pTopTrump = trumpSuit.GetTopCard();
			if ((numCardsInSuitLed == 0) && (pTopTrump) && (*pTopTrump > *pCurrTopCard))
			{
				// get the lowest trump that wil top the current top trump
				int numTopCards = trumpSuit.GetNumCardsAbove(pCurrTopCard);
				pCard = trumpSuit[numTopCards-1];
				status << "PLAYB20! We can overtrump " & strTopCardPos & "'s " & pCurrTopCard->GetName() &
						  " with the " & pCard->GetFaceName() & ".\n";
			}
			else
			{
				// no chance to win, so discard
				pCard = GetDiscard();
				if ((numCardsInSuitLed == 0) && (trumpSuit.GetNumCards() > 0))
					status << "PLAYB22! We can't overtrump " & strTopCardPos & "'s " & 
							  pCurrTopCard->GetFaceName() & ", so discard the " & pCard->GetName() & ".\n";
				else
					status << "PLAYB23! We can't beat the opponent's " & pCurrTopCard->GetFaceName() & 
							  " of trumps, so discard the " & pCard->GetName() & ".\n";
			}							
		}
	}
	else
	{
		// else nobody has played a trump this round, _or_ a trump was led
		// see if we can play trumps
		if (numCardsInSuitLed > 0)
		{
			// nope, gotta follow the suit that was led, trumps or otherwise
			// if we can beat the current top card, do so with the cheapest card
			CSuitHoldings& suit = m_pHand->GetSuit(nSuitLed);
			if (*(suit.GetTopCard()) > *pCurrTopCard)
			{
				// but see if the top card is partner's
				if (bPartnerHigh) 
				{
					// see if we should unblock here
					if (ISSUIT(nTrumpSuit) && (nCurrentRound == 0) &&
						(suit.GetNumHonors() == 1))
					{
						// first round in an NT contract, with one honor 
						// in the suit -- unblock
						pCard = suit.GetTopCard();
						if (suit.GetNumCards() > 1)
							status << "PLAYB30! Drop the " & pCard->GetFaceName() & 
									  " here to unblock the suit for partner.\n";
					}
					else
					{
						// else this is not an unblocking situation
						if (nCurrentSeat == 4)
						{
							// playing in 4th seat, high card is partner, so discard
							pCard = GetDiscard();
							status << "PLAYB34! Partner's " & pCurrTopCard->GetFaceName() & 
									  " is high, so discard the " & pCard->GetName() & ".\n";
						}
						else
						{
							// playing in third position -- decide whether to 
							// let partner's card ride
							// do so if if partner's card beats all outstanding cards
							CCard* pTopOutstandingCard = GetHighestOutstandingCard(nSuitLed);
							if ((pTopOutstandingCard == NULL) || (*pCurrTopCard > *pTopOutstandingCard))
							{
								// let partner's card ride
								pCard = GetDiscard();
								status << "PLAYB36! Partner's " & pCurrTopCard->GetFaceName() & 
										  " is higher than any outstanding card, so discard the " & 
										  pCard->GetName() & ".\n";
							}
							else
							{
								// partner's card is not necessarily highest, so top it
								pCard = suit.GetTopSequence().GetBottomCard();
								status << "PLAYB37! Partner's " & pCurrTopCard->GetFaceName() & 
										  " might not win the round, so top it with the " & pCard->GetFaceName() & ".\n";
							}
						}
					}
				}
				else
				{
					// else high card is opponent's, so beat it w/ highest card affordable
					// although, if playing in 3rd pos ahead of dummy, just play
					// high enuff to beat dummy
					if ((nCurrentSeat == 3) && (m_bLHDefender))
					{
						CSuitHoldings& dummySuit = GetDummySuit(nSuitLed);
						int nDummyTopCard = 0;
						if (dummySuit.GetNumCards() > 0)
							nDummyTopCard = dummySuit[0]->GetFaceValue();
						int nTopVal = Max(nDummyTopCard, pCurrTopCard->GetFaceValue());
						pCard = suit.GetLowestCardAbove(nTopVal);
						// see if we can beat the top card or dummy's top card
						if (pCard)
						{
							if (nTopVal == nDummyTopCard)
							{
								// dummy has the top card and we can beat it
								status << "PLAYB38A! Playing third ahead of dummy, need to beat dummy's " & 
										  CardValToString(nDummyTopCard) & ".\n";
							}
							else
							{
								// the top card is declarer's
								status << "PLAYB38B! Play high to win with the " & pCard->GetFaceName() & ".\n";
							}
						}
						else
						{
							// else we can't beat dummy's top card, but play
							// high anyway to force out his winner
							pCard = suit.GetLowestCardAbove(pCurrTopCard);
							status << "PLAYB38C! We top declarer's " & pCurrTopCard->GetFaceName() &
								      " to force a winner from dummy.\n";
						}
					}
					else if (nCurrentSeat == 3) 
					{
						// else we're playing 3rd, so play the lowest card from the top sequence
						pCard = suit.GetTopSequence().GetBottomCard();
						status << "PLAYB40! Play high to win with the " & pCard->GetFaceName() & ".\n";
					}
					else
					{
						// else we're playing last (4th)
						// play the cheapest card that will beat the top card
						pCard = suit.GetLowestCardAbove(pCurrTopCard);
						status << "PLAYB41! Play the " & pCard->GetFaceName() & " to win the trick.\n";
					}
				}
			}
			else
			{
				// we don't have a card to top the current high card
				if (bPartnerHigh)
				{
					// but partner's card is high, so we're OK
					pCard = GetDiscard();
					status << "PLAYB47! Partner's " & pCurrTopCard->GetFaceName() & 
							  " can win the trick, so discard the " & pCard->GetName() & ".\n";
				}
				else
				{
					// else we're screwed
					pCard = GetDiscard();
					status << "PLAYB48! We can't beat " & strTopCardPos & "'s " & pCurrTopCard->GetFaceName() & 
							  ", so discard the " & pCard->GetName() & ".\n";
				}
			}
		}
		else if (ISSUIT(nTrumpSuit) && (nSuitLed != nTrumpSuit) &&
							(m_pHand->GetNumCardsInSuit(nTrumpSuit) > 0))
		{
			// here, we can play a trump, so do so if appropriate 
			// see who has the top card in this round
			if (bPartnerHigh)
			{
				// let partner's card ride
				pCard = GetDiscard();
				status << "PLAYB52! Although we could trump this hand, partner's " & pCurrTopCard->GetName() & 
						  " is high, so discard the " & pCard->GetName() & ".\n";
			}
			else
			{
				// opponents have the high card (non-trump) -- so slam 'em
				pCard = m_pHand->GetSuit(nTrumpSuit).GetBottomCard();
				status << "PLAYB55! With no cards in " & SuitToString(nSuitLed) & 
						  ", trump with the " & pCard->GetName() & ".\n";
			}
		}
		else
		{
			// here we have zero cards in the suit and in trumps, so we're hosed
			pCard = GetDiscard();
			status << "PLAYB52! With no cards in the suit led and no trumps, we discard the " & pCard->GetName() & ".\n";
		}
	}
	//
	ASSERT(pCard->IsValid());
	ASSERT(m_pHand->HasCard(pCard));
	//
	return pCard;
}
Example #3
0
//
// Perform()
//
PlayResult CForce::Perform(CPlayEngine& playEngine, CCombinedHoldings& combinedHand, 
				    CCardLocation& cardLocation, CGuessedHandHoldings** ppGuessedHands, 
				    CPlayerStatusDialog& status, CCard*& pPlayCard)
{
	// a "force" is a play of the lowest possible card that will force out
	// a key enemy card
	// check which hand this is
	int nOrdinal = pDOC->GetNumCardsPlayedInRound();
	CPlayer* pPlayer = playEngine.GetPlayer();
	BOOL bPlayingInHand = (pDOC->GetCurrentPlayer() == pPlayer);
	CHandHoldings& playerHand = *(combinedHand.GetPlayerHand());
	CHandHoldings& dummyHand = *(combinedHand.GetPartnerHand());
	CCombinedSuitHoldings& combinedSuit = combinedHand.GetSuit(m_nSuit);
	CSuitHoldings& playerSuit = playerHand.GetSuit(m_nSuit);
	CSuitHoldings& dummySuit = dummyHand.GetSuit(m_nSuit);
	CCard* pCardLed = pDOC->GetCurrentTrickCardByOrder(0);
	int nSuitLed = NONE;
	if (pCardLed)
		nSuitLed = pCardLed->GetSuit();
	// see if a trump was played in this round
	BOOL bTrumped = FALSE;
	if ((nSuitLed != pDOC->GetTrumpSuit()) && (pDOC->WasTrumpPlayed()))
		bTrumped = TRUE;
	pPlayCard = NULL;

	// test preconditions
	if (!CPlay::IsPlayUsable(combinedHand, playEngine))
	{
		m_nStatusCode = PLAY_INACTIVE;
		return PLAY_POSTPONE;
	}

	//
	// test to make sure that the required played cards have indeed been played
	//
	if (m_pRequiredPlayedCardsList)
	{
		// check if any of the cards that should have benen played 
		// are still outstanding
		for(int i=0;i<m_pRequiredPlayedCardsList->GetNumCards();i++)
		{
			CCard* pCard = (*m_pRequiredPlayedCardsList)[i];
			if (playEngine.IsCardOutstanding(pCard))
			{
				status << "5PLFRCA! The force play of the " & m_pConsumedCard->GetFaceName() &
						  " to force out the " & m_nTargetCardVal & 
						  " is not yet viable as the card [" & pCard->GetFaceName() & 
						  "] is still outstanding.\n";
				m_nStatusCode = PLAY_INACTIVE;
				return PLAY_POSTPONE;
			}
		}
	}


	//
	// check our position in the play
	//
	switch(nOrdinal)
	{
		case 0:
			// we're leading, player #0
			if (bPlayingInHand) 
			{
				// playing from our own hand (declarer)
				if (m_nTargetHand == IN_HAND)
				{
					// play the card necessary to force the opponent
					pPlayCard = playerSuit.GetHighestCardBelow(m_nTargetCardVal);
					// NCR check that dummy does not have a singleton honor that's same value as our lead
					if(dummySuit.IsSingleton() 
						&& ((dummySuit.GetTopCard()->GetFaceValue() > pPlayCard->GetFaceValue()) // NCR-28
						    || (combinedHand.AreEquivalentCards(pPlayCard, dummySuit.GetTopCard()))))
						pPlayCard = playerSuit.GetBottomCard(); // NCR get lowest card

					if (pPlayCard == NULL)
					{
						status << "4PLFRC02! Error in force play -- no cards in declarer hand usable in a force play.\n";
						m_nStatusCode = PLAY_ERROR;
						return m_nStatusCode;
					}
					status << "PLFRC04! Play the " & pPlayCard->GetName() &
							  " from hand to force out the opponents' " & CardValToString(m_nTargetCardVal) & ".\n";
				}
				else
				{
					// forcing from dummy, so lead a low card 
					if (playerSuit.GetNumCards() > 0)
					{
						pPlayCard = playerSuit.GetBottomCard();
						status << "PLFRC06! Lead a low " & STSS(m_nSuit) & 
								  " (" & pPlayCard->GetFaceName() &
								  ") from hand to trigger a force play in dummy.\n";
					}
					else
					{
						// oops, no card in the suit to lead!
						status << "4PLFRC08! Oops, we can't start a force play in the " & STSS(m_nSuit) & 
								  " suit from declarer, since we have no cards in the suit.\n";
						m_nStatusCode = PLAY_POSTPONE;
						return m_nStatusCode;
					}
				}
			}
			else
			{
				// leading from dummy
				if (m_nTargetHand == IN_DUMMY)
				{
					// forcing from dummy, so do it
					pPlayCard = dummySuit.GetHighestCardBelow(m_nTargetCardVal);
					if (pPlayCard == NULL)
					{
						status << "4PLFRC10! Error in force play -- no cards in dummy usable in a force play.\n";
						m_nStatusCode = PLAY_ERROR;
						return m_nStatusCode;
					}
					status << "PLFRC12! Play the " & pPlayCard->GetName() &
							  " from dummy to force out the opponents' " & CardValToString(m_nTargetCardVal) & ".\n";
				}
				else
				{
					// forcing from hand, so lead a low card from dummy 
					if (dummySuit.GetNumCards() > 0)
					{
						pPlayCard = dummySuit.GetBottomCard();
						status << "PLFRC14! Lead a low " & STSS(m_nSuit) & 
								  " (" & pPlayCard->GetFaceName() &
								  ") from dummy to trigger a force play in hand.\n";
					}
					else
					{
						// oops, no card in the suit to lead!
						status << "4PLFRC16! Oops, we can't start a force play in the " & STSS(m_nSuit) & 
								  " suit from dummy, since we have no cards in the suit.\n";
						m_nStatusCode = PLAY_POSTPONE;
						return m_nStatusCode;
					}
				}
			}
			// all went OK
			m_nStatusCode = PLAY_IN_PROGRESS;
//			m_nStatusCode = PLAY_COMPLETE;
			break;

		case 1:
			// playing second -- see if we can still force
			// (i.e., the right suit was led, and the card led < target card)
			if ((nSuitLed == m_nSuit) && (pCardLed->GetFaceValue() < m_nTargetCardVal))
			{
				// opponent led the suit, so we still try to force
				if ( ((bPlayingInHand) && (m_nTargetHand == IN_HAND)) ||
				     ((!bPlayingInHand) && (m_nTargetHand == IN_DUMMY)) )
				{
					// this is the right time to play the forcing card
					if (bPlayingInHand)
						pPlayCard = playerSuit.GetHighestCardBelow(m_nTargetCardVal);
					else
						pPlayCard = dummySuit.GetHighestCardBelow(m_nTargetCardVal);
					// check for error
					if (pPlayCard == NULL)
					{
						status << "4PLFRC20! Error in force play -- no cards in " &
								  (bPlayingInHand? "hand" : "dummy") & " usable in a force play.\n";
						m_nStatusCode = PLAY_ERROR;
						return m_nStatusCode;
					}
					// got the forcing card
					status << "PLFRC22! The opponents led a " & STSS(m_nSuit) & 
							  ", so play the " & pPlayCard->GetName() & " from " &
							  (bPlayingInHand? "hand" : "dummy") & " to try and force out the " & 
							  CardValToString(m_nTargetCardVal) & " now.\n";
//					m_nStatusCode = PLAY_IN_PROGRESS;
					m_nStatusCode = PLAY_COMPLETE;
				}
				else
				{
					// not the right hand. so discard
					pPlayCard = playEngine.GetDiscard();
					status << "4PLFRC24! We're not in the right position to play a forcing card, so discard the " &
							   pPlayCard->GetName() & ".\n";
					m_nStatusCode = PLAY_POSTPONE;
				}
			}
			else
			{
				// wrong suit led, so no point here
				m_nStatusCode = PLAY_POSTPONE;
			}
			// done
			return m_nStatusCode;
			break;

		case 2:
			// playing third
			// sanity check
			if ((m_nStatusCode != PLAY_IN_PROGRESS) || (nSuitLed != m_nSuit))
			{
				m_nStatusCode = PLAY_ERROR;
				return m_nStatusCode;
			}
			// see if RHO trumped
			if (bTrumped)
			{
				status << "5PLFR30! RHO trumped, rendering the force play of the " & m_pConsumedCard->GetFaceName() &
						  " ineffective, so skip the play.\n";
				m_nStatusCode = PLAY_POSTPONE;
				return m_nStatusCode;
			}

			// see if we're in the correct hand
			if ( (bPlayingInHand && (m_nTargetHand == IN_HAND)) ||
				 (!bPlayingInHand && (m_nTargetHand == IN_DUMMY)) )
			{
				// see if RHO played the target card
				CCard* pRHOCard = pDOC->GetCurrentTrickCardByOrder(1);
				if (pRHOCard->GetFaceValue() >= m_nTargetCardVal)
				{
					status << "5PLFR50! RHO played the " & CardValToString(m_nTargetCardVal) &
							  ", so skip this force play.\n";
					m_nStatusCode = PLAY_NOT_VIABLE;
					return m_nStatusCode;
				}

				// the target card has not been played yet, so proceed
				if (bPlayingInHand)
					pPlayCard = playerSuit.GetHighestCardBelow(m_nTargetCardVal);
				else
					pPlayCard = dummySuit.GetHighestCardBelow(m_nTargetCardVal);

				// NCR check if our card is less than the top card already played
				if(pPlayCard < pDOC->GetCurrentTrickHighCard())
				{
					m_nStatusCode = PLAY_POSTPONE; // or NOT_VIABLE ???
					return m_nStatusCode;
				}


				// see if we played a card from the other hand that's equivalent 
				// to this card; if so, discard low
				CSuitHoldings testSuit;
				testSuit << combinedSuit;
				testSuit << pCardLed;	// needed for valid test
				//
				if (testSuit.AreEquivalentCards(pCardLed, pPlayCard))
				{
					// the opposite card can do the trick
					if (bPlayingInHand && (playerSuit.GetNumCards() > 1))
					{
						pPlayCard = playerSuit.GetBottomCard();
						status << "PLFRC55! The " & pCardLed->GetName() & " is sufficient for the force, so discard the " &
								  pPlayCard->GetFaceName() & " from hand.\n";
					}
					else if (!bPlayingInHand && (dummySuit.GetNumCards() > 1))
					{
						pPlayCard = dummySuit.GetBottomCard();
						status << "PLFRC56! The " & pCardLed->GetName() & " is sufficient for the force, so discard the " &
								  pPlayCard->GetFaceName() & " from dummy.\n";
					}
				}
				else 
				{
					// check for error
					if (pPlayCard == NULL)
					{
						status << "4PLFRC61! Error in force play -- no cards in " &
								  (bPlayingInHand? "hand" : "dummy") & " usable in a force play.\n";
						m_nStatusCode = PLAY_ERROR;
						return m_nStatusCode;
					}
					// got the forcing card
					status << "PLFRC62! Play the " & pPlayCard->GetName() & " from " &
							  (bPlayingInHand? "hand" : "dummy") & " to try and force out the " & 
							  CardValToString(m_nTargetCardVal) & " now.\n";
					m_nStatusCode = PLAY_COMPLETE;
				}
			}
			else
			{
				// we're in the opposite (discard) hand. so discard
				pPlayCard = playEngine.GetDiscard();
				status << "PLFRC64! We're in the opposite hand of a force play, so discard the " &
						   pPlayCard->GetName() & ".\n";
				m_nStatusCode = PLAY_COMPLETE;
			}
			break;

		case 3:
			// playing fourth -- can't use a force play here
			return PLAY_POSTPONE;
			break;
	}

	// done
	ASSERT(pPlayCard->IsValid());
	return m_nStatusCode;
}