//
// PlaySecond()
//
// default implementation, generally should be overridden in derived classes
//
CCard* CPlayEngine::PlaySecond()
{
	CPlayerStatusDialog& status = *m_pStatusDlg;
	status << "5PLAY2! Playing second, using default player logic.\n";

	// get play info
	int nDummyPos = pDOC->GetDummyPosition();
	CCard* pCardLed = pDOC->GetCurrentTrickCardLed();
	int nSuitLed = pCardLed->GetSuit();
	int nFaceValue = pCardLed->GetFaceValue();
	CCard* pCurrTopCard = pDOC->GetCurrentTrickHighCard();
	int nTrumpSuit = pDOC->GetTrumpSuit();
	CSuitHoldings& suit = m_pHand->GetSuit(nSuitLed);
	// card to play
	CCard* pCard = NULL;

	// second hand low
	int numCardsInSuit = suit.GetNumCards();
	if (numCardsInSuit > 0)
	{
		// default behavior -- just play the low card
		pCard = m_pHand->GetSuit(nSuitLed).GetBottomCard();
		if (numCardsInSuit > 1)
		{
			if (*pCard < *pCurrTopCard)
				status << "PLY2C1! Play second hand low with the " & pCard->GetFaceName() & ".\n";
			else
				status << "PLY2C2! As second hand, we play the lowest card we have in the suit, the " & pCard->GetFaceName() & ".\n";
		}
		else
		{
			status << "PLY2C4! Play our only " & STSS(nSuitLed) & ", the " & pCard->GetFaceName() & ".\n";
		}
	}
	else
	{
		// no cards in the suit led
		// trump here if possible
		if (m_pHand->GetNumTrumps() > 0)
		{
			//
			CSuitHoldings& trumpSuit = m_pHand->GetSuit(nTrumpSuit);

			// see if partner would win the suit otherwise
			CGuessedSuitHoldings& partnerSuit = m_pPlayer->GetGuessedHand(m_nPartnerPosition)->GetSuit(nSuitLed);
			CCardList outstandingCards;
			GetOutstandingCards(nSuitLed, outstandingCards);
			if (partnerSuit.AreAllCardsIdentified() && partnerSuit.HasCard(outstandingCards[0]->GetFaceValue()))
			{
				// partner may win the trick, so discard
				status << "PLY2K1! We could trump here, but we know partner holds the " & outstandingCards[0]->GetName() &
						  " and can win the trick, so discard the " & pCard->GetName() & ".\n";
			}
			else
			{
				// trump here if possible
				// but first see if we're playing ahead of dummy (dummy is to our left), 
				// and dummy is also void in the suit
				CGuessedHandHoldings* pDummyHand = m_pPlayer->GetGuessedHand(nDummyPos);
				if ((m_pLHOpponent == pDOC->GetDummyPlayer()) &&
					(pDummyHand->GetSuit(nSuitLed).GetNumRemainingCards() == 0) &&
					(pDummyHand->GetSuit(nTrumpSuit).GetNumRemainingCards() > 0))
				{
					// dummy is also void, so trump if we have a trump higher than dummy's
					CGuessedCard* pDummyTopTrump = pDummyHand->GetSuit(nTrumpSuit).GetAt(0);
					if (trumpSuit.GetNumCardsAbove(pDummyTopTrump->GetFaceValue()) > 0)
					{
						// go ahead and ruff
						pCard = trumpSuit.GetLowestCardAbove(pDummyTopTrump->GetFaceValue());
						status << "PLY2M1! Trump here, making sure to thwart dummy's " & pDummyTopTrump->GetFaceName() &
								  " of trumps by playing the " & pCard->GetFaceName() & ".\n";
					}
					else
					{
						// dummy would overtrump
						pCard = GetDiscard();
						status << "PLY2M2! We'd like to trump here, but Dummy may overruff, so discard the " & pCard->GetName() & ".\n";
					}
				}
				else
				{
					// safe to trump -- play the lowest trump
					pCard = trumpSuit.GetBottomCard();
					status << "PLY2P1! Trump with the " & pCard->GetFaceName() & ".\n";
				}
			}
		}
		else
		{
			// discard
			pCard = GetDiscard();
			status << "PLY2Y! We have no " & SuitToString(nSuitLed) & ", so discard the " & pCard->GetName() & ".\n";
		}
	}
	//
	ASSERT(pCard->IsValid());
	return pCard;
}
//
// 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;
}
void CStatusPlayPlanPage::Update()
{
	// return if not all inits are complete
	if ((!m_bInitialized) || (pDOC == NULL))
		return;
	if (!theApp.IsGameInProgress())
	{
		m_strDeclarer = "None";
		UpdateData(FALSE);
		return;
	}

	// clear existing items
	m_listPlayPlan.DeleteAllItems();

	// get the declarer & his play engine
	int nDeclarer = pDOC->GetDeclarerPosition();
	if (!ISPLAYER(nDeclarer))
		return;
	CPlayer* pPlayer = pDOC->GetDeclarer();
	CDeclarerPlayEngine* pPlayEngine = pPlayer->GetDeclarerEngine();
	CPlayList& playPlan = pPlayEngine->GetPlayPlan();

	// list declarer
	m_strDeclarer.Format("%s", PositionToString(pPlayer->GetPosition()));

	// & number of available plays
	int nCount = playPlan.GetSize();
	m_strNumPlays.Format("%d",nCount);

	// also list the current play
	const CPlay* pPlay = pPlayEngine->GetCurrentPlay();
	CString strFailedPlay = pPlayEngine->GetFailedPlayName();
	if (pPlay)
		m_strCurrentPlay = (const_cast<CPlay*>(pPlay))->GetDescription();
	else if (!strFailedPlay.IsEmpty())
		m_strCurrentPlay = strFailedPlay;
	else
		m_strCurrentPlay = "None";

	// now list the plays
	for(int i=0;i<nCount;i++)
	{
		CPlay* pPlay = playPlan[i];
		// set number
		m_listPlayPlan.InsertItem(i, FormString(i+1));
		// set name
		m_listPlayPlan.SetItem(i, 1, LVIF_TEXT, pPlay->GetPlayTypeName(), 0, 0, 0, 0L);
		// add description
		m_listPlayPlan.SetItem(i, 2, LVIF_TEXT, pPlay->GetDescription(), 0, 0, 0, 0L);
		// add winner coded
		int nProspect = pPlay->GetPlayProspect();
		m_listPlayPlan.SetItem(i, 3, LVIF_TEXT, szProspectDescription[nProspect], 0, 0, 0, 0L);
		// add consumed card
		CCard* pConsumedCard = pPlay->GetConsumedCard();
		m_listPlayPlan.SetItem(i, 4, LVIF_TEXT, (pConsumedCard? pConsumedCard->GetName() : ""), 0, 0, 0, 0L);
		// add target card
		CCard* pTargetCard = pPlay->GetTargetCard();
		m_listPlayPlan.SetItem(i, 5, LVIF_TEXT, (pTargetCard? pTargetCard->GetName() : ""), 0, 0, 0, 0L);
		// add key cards
		CCardList* pKeyCards = pPlay->GetKeyCardsList();
		m_listPlayPlan.SetItem(i, 6, LVIF_TEXT, (pKeyCards? pKeyCards->GetHoldingsString() : ""), 0, 0, 0, 0L);
		// add OR-Key cards
		CCardList* pORKeyCards = pPlay->GetOrKeyCardsList();
		m_listPlayPlan.SetItem(i, 7, LVIF_TEXT, (pORKeyCards? pORKeyCards->GetHoldingsString() : ""), 0, 0, 0, 0L);
		// add OR-Key cards 2
		CCardList* pORKeyCards2 = pPlay->GetOrKeyCardsList2();
		m_listPlayPlan.SetItem(i, 8, LVIF_TEXT, (pORKeyCards2? pORKeyCards2->GetHoldingsString() : ""), 0, 0, 0, 0L);
		// add opponents' key cards
		CCardList* pOppKeyCards = pPlay->GetEnemyKeyCardsList();
		m_listPlayPlan.SetItem(i, 9, LVIF_TEXT, (pOppKeyCards? pOppKeyCards->GetHoldingsString() : ""), 0, 0, 0, 0L);
		// add opponents' OR-Key cards
		CCardList* pOppORKeyCards = pPlay->GetEnemyOrKeyCardsList();
		m_listPlayPlan.SetItem(i, 10, LVIF_TEXT, (pOppORKeyCards? pOppORKeyCards->GetHoldingsString() : ""), 0, 0, 0, 0L);
		// add required played cards
		CCardList* pReqPlayedCards = pPlay->GetRequiredPlayedCardsList();
		m_listPlayPlan.SetItem(i, 11, LVIF_TEXT, (pReqPlayedCards? pReqPlayedCards->GetHoldingsString() : ""), 0, 0, 0, 0L);
	}

	// done
	UpdateData(FALSE);
	m_nPrevTooltipIndex = -1;
}
//
// GetLeadCard()
//
CCard* CPlayEngine::GetLeadCard()
{
	// default implementation 
	CPlayerStatusDialog& status = *m_pStatusDlg;
	CCard* pLeadCard = NULL;
	int nTrumpSuit = pDOC->GetTrumpSuit();
	
	// look to see if we have any winners
	if (m_pHand->GetNumWinners() > 0)
	{
		// return the first winner found
		// but avoid the trump suit unless there are no other winners
		int nSuit = NONE;
		if (ISSUIT(nTrumpSuit))
			nSuit = GetNextSuit(nTrumpSuit);
		else
			nSuit= CLUBS;	// else start with the club suit
		//
		for(int i=0;i<4;i++)
		{
			CSuitHoldings& suit = m_pHand->GetSuit(nSuit);
			if ((suit.GetNumTopCards() > 0) && (nSuit != nTrumpSuit))
			{
				pLeadCard = suit.GetTopSequence().GetBottomCard();
				status << "PLYLDA! With no other obvious plays, cash a winner with the " & pLeadCard->GetName() & ".\n";
				ASSERT(m_pHand->HasCard(pLeadCard));
				return pLeadCard;
			}
			// else look at the next suit
			nSuit = GetNextSuit(nSuit);
		}
	}

	// if we have a card in an unbid suit, lead from that suit.
	CArray<int,int> suitsUnbid;
	int numSuitsUnbid = pDOC->GetSuitsUnbid(suitsUnbid);
	for(int i=0;i<numSuitsUnbid;i++)
	{
		CSuitHoldings& suit = m_pHand->GetSuit(suitsUnbid[i]);
		if (suit.GetNumCards() > 0)
		{
			pLeadCard = suit.GetBottomCard();
			status << "PLYLDB! With no other clear plays available, lead a card from the unbid " &
					  STSS(pLeadCard->GetSuit()) & " suit.\n";
			ASSERT(m_pHand->HasCard(pLeadCard));
			return pLeadCard;
		}
	}

	// no winners in hand, so just lead anything
	if (ISSUIT(nTrumpSuit))
	{
		// playing in a suit contract
		// if we have any trumps left, _and_ have a singleton, then lead it
		if ((m_pHand->GetNumTrumps() > 0) && (m_pHand->GetNumSingletons() > 0))
		{
			// search for the singleton suit
			BOOL bSuitFound = FALSE;
			int nSuit;
			for(int i=3;i>=0;i--)
			{
				nSuit = m_pHand->GetSuitsByLength(3);
				if (m_pHand->GetNumCardsInSuit(nSuit) > 1)
					break;	// oops, no more singletons
				// check if this is a non-trump singleton suit
				if ((m_pHand->GetNumCardsInSuit(nSuit) == 1) && (nSuit != nTrumpSuit))
				{
					bSuitFound = TRUE;
					break;
				}
			}
			// lead a card from the suit
			if (bSuitFound)
			{
				CSuitHoldings& suit = m_pHand->GetSuit(nSuit);
				pLeadCard = suit[0];
				status << "PLYLDC! Lead the singleton " & pLeadCard->GetName() & " in the hopes of setting up a ruff later.\n";
				ASSERT(m_pHand->HasCard(pLeadCard));
				return pLeadCard;
			}
		}

		// else we're stuck -- just lead a card from the worst suit
		// (i.e., keep the "good" suits alive)
		for(int i=3;i>=0;i--)
		{
			int nSuit = m_pHand->GetSuitsByPreference(i);
			// avoid leading from the trump suit if we can help it
			if (nSuit == nTrumpSuit)
				continue;
			// else lead from this suit
			if (m_pHand->GetNumCardsInSuit(nSuit) > 0)
			{
				pLeadCard = m_pHand->GetSuit(nSuit).GetBottomCard();
				ASSERT(m_pHand->HasCard(pLeadCard));
				return pLeadCard;
			}
		}
		// else we're stuck with leading a trump
		if (m_pHand->GetNumTrumps() > 0)
			return m_pHand->GetSuit(nTrumpSuit).GetAt(0);
	}
	else
	{
		// playing in notrump
		// lead a card from the worst suit, keeping the good suits alive
		for(int i=3;i>=0;i--)
		{
			int nSuit = m_pHand->GetSuitsByPreference(i);
			if (m_pHand->GetNumCardsInSuit(nSuit) > 0)
			{
				pLeadCard = m_pHand->GetSuit(nSuit).GetBottomCard();
				ASSERT(m_pHand->HasCard(pLeadCard));
				return pLeadCard;
			}
		}
	}


	// we should NEVER get here
	ASSERT(FALSE);
	return NULL;
}
Beispiel #5
0
// 
// Perform()
//
// called to do the deed
//
PlayResult CCash::Perform(CPlayEngine& playEngine, CCombinedHoldings& combinedHand, 
				   CCardLocation& cardLocation, CGuessedHandHoldings** ppGuessedHands, 
				   CPlayerStatusDialog& status, CCard*& pPlayCard)
{
	// 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());
	CSuitHoldings& declarerSuit = playerHand.GetSuit(m_nSuit);
	CSuitHoldings& dummySuit = dummyHand.GetSuit(m_nSuit);
	CCombinedSuitHoldings& combinedSuit = combinedHand.GetSuit(m_nSuit);
	CCard* pCardLed = pDOC->GetCurrentTrickCardByOrder(0);
	int nSuitLed = pCardLed? pCardLed->GetSuit() : NONE;
	CDeclarerPlayEngine& declarerEngine = (CDeclarerPlayEngine&) playEngine;
	
	// see if a trump was played in this round
	BOOL bTrumped = FALSE;
	int nTrumpSuit = pDOC->GetTrumpSuit();
	if ((nSuitLed != nTrumpSuit) && (pDOC->WasTrumpPlayed()))
		bTrumped = TRUE;
	pPlayCard = NULL;

	// see what the top card in the round is
	CCard* pTopCard = pDOC->GetCurrentTrickHighCard();
	CCard* pDeclarerCard = pDOC->GetCurrentTrickCard(playEngine.GetPlayerPosition());
	CCard* pDummysCard = pDOC->GetCurrentTrickCard(playEngine.GetPartnerPosition());
	CCard* pPartnersCard = bPlayingInHand? pDummysCard : pDeclarerCard;
	BOOL bPartnerHigh = (pTopCard == pPartnersCard);

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

	// see if one or more opponents are void in the suit AND have not shown out
	// of trumps
	if (ISSUIT(nTrumpSuit))
	{
		int numOutstandingTrumps = playEngine.GetNumOutstandingCards(nTrumpSuit);
		BOOL bSkipPlay = FALSE;
		// if leading, check LHO
		CGuessedHandHoldings* pLHOHand = ppGuessedHands[playEngine.GetLHOpponent()->GetPosition()];
		if ((nOrdinal == 0) && (numOutstandingTrumps > 0) && pLHOHand->IsSuitShownOut(m_nSuit) && !pLHOHand->IsSuitShownOut(nTrumpSuit))
		{
			bSkipPlay = TRUE;
			status << "5PLCSHZ1! The play <" & m_strName & "> is not yet safe as LHO has shown out of the suit and may ruff.\n";
		}
		// also check RHO
		CGuessedHandHoldings* pRHOHand = ppGuessedHands[playEngine.GetRHOpponent()->GetPosition()];
		if ((numOutstandingTrumps > 0) && pRHOHand->IsSuitShownOut(m_nSuit) && !pRHOHand->IsSuitShownOut(nTrumpSuit))
		{
			bSkipPlay = TRUE;
			status << "5PLCSHZ2! The play <" & m_strName & "> is not yet safe as RHO has shown out of the suit and may ruff.\n";
		}
		//
		if (bSkipPlay)
		{
			// opponents might ruff
			m_nStatusCode = PLAY_INACTIVE;
			return PLAY_POSTPONE;
		}
	}

	// else proceed
	// check our position in the play
	switch(nOrdinal)
	{
		case 0:
			// we're leading, player #0
			if (bPlayingInHand) 
			{
				// playing from our own hand (declarer) and cashing in hand
				if (m_nTargetHand == IN_HAND)
				{
					// cashing from hand -- check to be sure the other hand has losers
					// i.e., don't discard a winner on a winner UNLESS both hands 
					// have nothing but winners, OR the other hand has only one card, 
					// a winner that's lower than the top card in this hand, 
					// AND this hand has only winners
					// this is because we don't want to end up stranded in the wrong hand
					// examples: 
					// ---------
					//   from Kx/A   -- don't lead the King!
					//        Kxx/AQ -- again, don't lead the King
					//        KJ/Q   -- we _can_ lead the K (in fact, we should)
					//        KQJ/T9 -- doesn't matter
					//        Qx/AKJ -- doesn't matter
					if ((dummySuit.GetNumCards() == 1) && (combinedSuit.GetNumDummyLosers() == 0) && 
								(combinedSuit.GetNumDeclarerLosers() == 0) && (*dummySuit[0] < *m_pConsumedCard))
					{
						// this is a special case, so it's OK
					}
					else if ((dummySuit.GetNumCards() > 0) && (combinedSuit.GetNumDummyLosers() == 0) && 
								(combinedSuit.GetNumDeclarerLosers() > 0) &&
								(combinedSuit.GetNumDummyWinners() < declarerSuit.GetNumCards()) &&
								(*dummySuit[0] > *declarerSuit[0]) &&
								(declarerEngine.GetNumDeclarerEntries() == 1) )
					{
						// here, nothing but higher winners in dummy, which is shorter than hand
						status << "5PLCSH02! We could cash the " & m_pConsumedCard->GetName() &
								  " from hand, but dummy has no losers to discard in the suit and could get stranded there.\n";
						m_nStatusCode = PLAY_INACTIVE;
						return PLAY_POSTPONE;
					}
					// proceed 
					pPlayCard = m_pConsumedCard;
					status << "PLCSH10! Cash the " & pPlayCard->GetName() &
							  " from hand.\n";
				}
				else
				{
					// playing from hand. but cashing from dummy,
					// lead a low card from hand
					if (declarerSuit.GetNumCards() > 0)
					{
						// we have cards in the suit
//						if (combinedSuit.GetNumDeclarerLosers() > 0)
						if (declarerSuit.GetNumCardsBelow(m_pConsumedCard) > 0)
						{
							// lead a low card, but test first
							pPlayCard = declarerSuit.GetBottomCard();
							if ( combinedSuit .AreEquivalentCards(pPlayCard, m_pConsumedCard) &&
//								 (declarerSuit.GetNumCards() > 1) && (ombinedSuit.GetNumDummyLosers() > 0) )
												 (combinedSuit.GetNumDummyLosers() > 0) )
							{
								// oops, the "low" card is equivalent to the cash card!
								status << "4PLCSH15! Oops, the lowest card we can lead from hand for the cash is the " & 
										  pPlayCard->GetFaceName() & ", which is equivalent to the " &
										  m_pConsumedCard->GetFaceName() & ", so skip the cash play.\n";
								m_nStatusCode = PLAY_INACTIVE;
								return PLAY_POSTPONE;
							}
							else
							{
								status << "PLCSH20! Lead a low " & STSS(m_nSuit) & 
										  " (the " & pPlayCard->GetFaceName() &
										  ") from hand in order to cash the " & 
										  m_pConsumedCard->GetFaceName() & " in dummy.\n";
							}
						}
						else 
						{
							// oops, we have no low cards in hand to lead!
							status << "4PLCSH21! Oops, we wanted to cash a " & STSS(m_nSuit) & 
									  " in dummy, but we have no low " & STS(m_nSuit) & 
									  " in hand to lead, so we have to abandon that play.\n";
							m_nStatusCode = PLAY_INACTIVE;
							return PLAY_POSTPONE;
						}
					}
					else
					{
						// oops, no card in the suit to lead!
						status << "4PLCSH22! Oops, we wanted to cash a " & STSS(m_nSuit) & 
								  " in dummy, but we have no " & STS(m_nSuit) & 
								  " in hand to lead, so we have to abandon that play.\n";
						m_nStatusCode = PLAY_NOT_VIABLE;
						return m_nStatusCode;
					}
				}
			}
			else
			{
				// playing in dummy
				if (m_nTargetHand == IN_DUMMY)
				{
					// we're leading from dummy and also cashing in dummy 
					// also check to be sure the player's hand has losers
					if ((declarerSuit.GetNumCards() == 1) && (combinedSuit.GetNumDeclarerLosers() == 0) && 
								(combinedSuit.GetNumDummyLosers() == 0) && (*declarerSuit[0] < *m_pConsumedCard))
					{
						// this is a special case (e.g., Kx/J), so it's OK
					}
					else if ((declarerSuit.GetNumCards() > 0) && (combinedSuit.GetNumDeclarerLosers() == 0) && 
								(combinedSuit.GetNumDummyLosers() > 0) &&
								(combinedSuit.GetNumDeclarerWinners() < dummySuit.GetNumCards()) &&
								(*declarerSuit[0] > *dummySuit[0]) &&
								(declarerEngine.GetNumDummyEntries() == 1) )
					{
						// here, nothing but higher winners in hand, which is shorter than dummy
						status << "5PLCSH12! We could cash the " & m_pConsumedCard->GetName() &
								  " from dummy, but we have no losers in hand to discard in the suit and could get stranded there.\n";
						m_nStatusCode = PLAY_INACTIVE;
						return PLAY_POSTPONE;
					}

					// proceed
					pPlayCard = m_pConsumedCard;
					status << "PLCSH30! Cash the " & pPlayCard->GetName() & " from dummy.\n";
				}
				else
				{
					// leading from dummy, but cashing from hand
					// lead a low card of the suit from dummy
					if (dummySuit.GetNumCards() > 0)
					{
//						if (combinedSuit.GetNumDummyLosers() > 0)
						if (dummySuit.GetNumCardsBelow(m_pConsumedCard) > 0)
						{
							pPlayCard = dummySuit.GetBottomCard();
							if ( combinedSuit .AreEquivalentCards(pPlayCard, m_pConsumedCard) &&
//								 (dummySuit.GetNumCards() > 1) && (combinedSuit.GetNumDeclarerLosers() > 0) )
												(combinedSuit.GetNumDeclarerLosers() > 0) )
							{
								// oops, the "low" card is equivalent to the cash card!
								status << "4PLCSH35! Oops, the lowest card we can lead from dummy for the cash is the " & 
										  pPlayCard->GetFaceName() & ", which is equivalent to the " &
										  m_pConsumedCard->GetFaceName() & ", so skip the cash play.\n";
								m_nStatusCode = PLAY_INACTIVE;
								return PLAY_POSTPONE;
							}
							else
							{
								status << "PLCSH40! Lead a low " & STSS(m_nSuit) & 
										  " (the " & pPlayCard->GetFaceName() &
										  ") from dummy in order to cash the " & 
										  m_pConsumedCard->GetFaceName() & " in hand.\n";
							}
						}
						else
						{
							// oops, we have no low cards in dummy to lead!
							status << "4PLCSH41! Oops, we wanted to cash a " & STSS(m_nSuit) & 
									  " in hand, but we have no low " & STS(m_nSuit) & 
									  " in dummy to lead, so we have to abandon that play.\n";
							m_nStatusCode = PLAY_INACTIVE;
							return PLAY_POSTPONE;
						}
					}
					else
					{
						// oops, no card in the suit to lead!
						status << "4PLCSH42! Oops, we wanted to cash a " & STSS(m_nSuit) & 
								  " in hand, but we have no " & STS(m_nSuit) & 
								  " in dummy to lead, so we have to abandon that play.\n";
						m_nStatusCode = PLAY_NOT_VIABLE;
						return m_nStatusCode;
					}
				}
			}
			// all went OK
			m_nStatusCode = PLAY_IN_PROGRESS;
			break;

		case 1:
			// playing second
			if (nSuitLed == m_nSuit)
			{
				// see if the card led is higher than ours
				if (*pCardLed > *m_pConsumedCard)
				{
					status << "3PLCSH53! the card led (" & pCardLed->GetName() & ") " & 
							  " beats the " & m_pConsumedCard->GetName() & 
							  " we were going to play, so skip the cash for now.\n";
					m_nStatusCode = PLAY_INACTIVE;
					return PLAY_POSTPONE;
				}
				// card led is not higher than our cash card
				// see if this is the correct hand for the cash
				if ( ((bPlayingInHand) && (m_nTargetHand == IN_HAND)) ||
				     ((!bPlayingInHand) && (m_nTargetHand == IN_DUMMY)) )
				{
					// this is the right time to play the cash card
					// but do a special test here -- see if partner 
					// has a singleton which is higher than this card
					if ( (bPlayingInHand && (dummySuit.GetNumCards() == 1) &&
					     (*(dummySuit[0]) > *m_pConsumedCard)) ||
						 (!bPlayingInHand && (declarerSuit.GetNumCards() == 1) &&
					     (*(declarerSuit[0]) > *m_pConsumedCard)) )
					{
						status << "3PLCSH54! Partner has a singleton which is higher than the " & 
								  m_pConsumedCard->GetName() & " we were going to cash, so skip the cash play for now.\n";
						m_nStatusCode = PLAY_INACTIVE;
						return PLAY_POSTPONE;
					}
					
					// also check if partner has nothing but winners in his hand
					if ( (bPlayingInHand && (dummySuit.GetNumCards() > 0) && (combinedSuit.GetNumDummyLosers() == 0) && (combinedSuit.GetNumDeclarerLosers() > 0)) ||
						 (!bPlayingInHand && (declarerSuit.GetNumCards() > 0) && (combinedSuit.GetNumDeclarerLosers() == 0) && (combinedSuit.GetNumDummyLosers() > 0)) )
					{
/*
 * ???
 */
						status << "5PLCSH54a! We could cash the " & m_pConsumedCard->GetName() & 
							(bPlayingInHand? " in hand" : " in dummy") & ", but we have no losers in " &
							(bPlayingInHand? " in dummy" : " in hand") & " in the suit, so skip this play.\n";
						m_nStatusCode = PLAY_INACTIVE;
						return PLAY_POSTPONE;
					}
					pPlayCard = m_pConsumedCard;
					status << "PLCSH55! The opponents led a " & STSS(m_nSuit) & 
							  ", so cash the " & pPlayCard->GetFaceName() & " now.\n";
				}
				else
				{
					// not the right hand, so discard from this hand
					// but skip if we have no losers in this hand but do in the other
					if ( (m_nTargetHand == IN_HAND) &&
								 (dummySuit.GetNumCards() > 0) && 
								 (combinedSuit.GetNumDummyLosers() == 0) &&
								 (combinedSuit.GetNumDeclarerLosers() > 0))
					{
						// no losers in dummy to discard, but some in hand!
						m_nStatusCode = PLAY_INACTIVE;
						return PLAY_POSTPONE;
					}
					if ( (m_nTargetHand == IN_DUMMY) &&
								 (declarerSuit.GetNumCards() > 0) && 
								 (combinedSuit.GetNumDeclarerLosers() == 0) &&
								 (combinedSuit.GetNumDummyLosers() > 0))
					{
						// no losers in hand to discard, but some in dummy!
						m_nStatusCode = PLAY_INACTIVE;
						return PLAY_POSTPONE;
					}

					// else go ahead and discard
					pPlayCard = playEngine.GetDiscard();
					status << "PLCSH56! Discard a " & STSS(m_nSuit) & " from " &
							  (bPlayingInHand? "hand" : "dummy") &
							  " in anticipation of cashing the " & 
							  m_pConsumedCard->GetFaceName() & " in " &
							  (bPlayingInHand? "dummy" : "hand") & ".\n";
				}
			}
			else
			{
				// wrong suit led, so no point here
				m_nStatusCode = PLAY_INACTIVE;
				return PLAY_POSTPONE;
			}
			// else we're ok
			m_nStatusCode = PLAY_IN_PROGRESS;
			break;


		case 2:
			// playing third -- this play may or may not be active
			// i.e., may have started one cash, then switched to another
			// see if the wrong suit was led 
			if (nSuitLed != m_nSuit)
			{
				m_nStatusCode = PLAY_INACTIVE;
				return PLAY_POSTPONE;
			}
			// see if RHO has trumped
			if (bTrumped)
			{
				status << "2PLCSH64! RHO has trumped, so abandon the cashing play for this round.\n";
				m_nStatusCode = PLAY_INACTIVE;
				return PLAY_POSTPONE;
			}
			// see if the current top card in the trick is higher than ours
			if (*pTopCard > *m_pConsumedCard)
			{
				status << "2PLCSH66! the " & m_pConsumedCard->GetName() & " can't beat the " &
						   pTopCard->GetName() & ", so skip the cash.\n";
				m_nStatusCode = PLAY_INACTIVE;
				return PLAY_POSTPONE;
			}
			// else check which hand we're playing in
			if (bPlayingInHand) 
			{
				// playing from our own hand (declarer)
				// see if it's time to cash
				if (m_nTargetHand == IN_HAND)
				{
					// proceed
					pPlayCard = m_pConsumedCard;
					status << "PLCSH68! Cash the " & pPlayCard->GetName() & " from hand.\n";
				}
				else
				{
					// cash is/was in dummy
					if (bTrumped)
					{
						pPlayCard = playEngine.GetDiscard();
						status << "2PLCSH70! RHO's trump negates our cash; discard the " &
								  pPlayCard->GetName() & ".\n";
					}
					else
					{
						// see if we need to win in this hand to cash the remaining winnners
						if ((dummySuit.GetNumCards() == 0) && (declarerSuit.GetNumCards() > 1) && 
								(declarerSuit.GetNumLosers() == 0) && (*declarerSuit[0] > *pCardLed))
						{
							pPlayCard = declarerSuit.GetLowestCardAbove(pCardLed);
							status << "PLCSH71! Our cash of the " & pCardLed->GetName() & 
									  " from dummy is holding, but we need to win in the hand to cash the remaining winners, so play the " &
									  pPlayCard->GetName() & " here.\n";
						}
						else
						{
							pPlayCard = playEngine.GetDiscard();
							status << "PLCSH72! Our cash of the " & pCardLed->GetName() & 
									  " from dummy is holding, so discard the " & pPlayCard->GetName() & ".\n";
						}
					}
				}
			}
			else
			{
				// playing in dummy
				// see if it's time to cash
				if (m_nTargetHand == IN_DUMMY)
				{
					// proceed
					pPlayCard = m_pConsumedCard;
					status << "PLCSH74! Cash the " & pPlayCard->GetName() &
							  " from dummy.\n";
				}
				else
				{
					// cashed from hand, so discard
					if (bTrumped)
					{
						pPlayCard = playEngine.GetDiscard();
						status << "2PLCSH76! RHO's trump negates our cash; discard the " &
								  pPlayCard->GetName() & ".\n";
					}
					else
					{
						// see if we need to win here in dummy to cash the remaining winnners
						if ((declarerSuit.GetNumCards() == 0) && (dummySuit.GetNumCards() > 1) && 
								(dummySuit.GetNumLosers() == 0) && (*dummySuit[0] > *pCardLed))
						{
							pPlayCard = dummySuit.GetLowestCardAbove(pCardLed);
							status << "PLCSH77! Our cash of the " & pCardLed->GetName() & 
									  " from hand is holding, but we need to win in dummy to cash the remaining winners, so play the " &
									  pPlayCard->GetName() & " here.\n";
						}
						else
						{
							pPlayCard = playEngine.GetDiscard();
							status << "PLCSH78! Our cash of the " &
									  pCardLed->GetName() & " from hand is holding, so discard the " &
									  pPlayCard->GetName() & ".\n";
						}
					}
				}
			}
			// all's OK
			m_nStatusCode = PLAY_COMPLETE;
			break;


		case 3:
			// playing fourth
			// make sure the play is in progress
			if (m_nStatusCode != PLAY_IN_PROGRESS)
				return PLAY_INACTIVE;
			// since opponent led the suit, we are still trying to cash
			status << "3PLCSH80! the opponents led a " & STSS(nSuitLed) & 
					  ", so see if we can finish up the cash play here.\n";
			// see if RHO (or partner) has trumped
			if (bTrumped)
			{
				status << "2PLCSH82! The suit was trumped, so abandon the cashing play for this round.\n";
				m_nStatusCode = PLAY_INACTIVE;
				return PLAY_POSTPONE;
			}
			// see if the current (opponents') top card in the trick is higher than ours
			if ((!bPartnerHigh) && (*pTopCard > *m_pConsumedCard))
			{
				status << "2PLCSH83! the " & m_pConsumedCard->GetName() & " we intended to cash can't beat the " &
						   pTopCard->GetName() & ", so skip the cash.\n";
				m_nStatusCode = PLAY_INACTIVE;
				return PLAY_POSTPONE;
			}
			// else see if partner played a top card (which wasn't part of the cash)
			if ((bPartnerHigh) && (m_pConsumedCard != pPartnersCard))
			{
				status << "2PLCSH84! Partner's " & pTopCard->GetName() & " is high, so skip the cash of the " &
						  m_pConsumedCard->GetFaceName() & ".\n";
				m_nStatusCode = PLAY_INACTIVE;
				return PLAY_POSTPONE;
			}
			// else check which hand we're playing in
			if (bPlayingInHand) 
			{
				// playing from our own hand (declarer)
				// see if it's time to cash
				if (m_nTargetHand == IN_HAND)
				{
					// cashing from hand, so do it
					// BUT see if we have a lower card which would win!
					if (declarerSuit.GetNumCardsAbove(pTopCard) > 1)
					{
						CCard* pCard = declarerSuit.GetLowestCardAbove(pTopCard);
						status << "3PLCSH85! We can actually play the " & pCard->GetFaceName() &
								  " to win this trick, so postpone the cash of the " &
								  m_pConsumedCard->GetFaceName() & ".\n";
						m_nStatusCode = PLAY_INACTIVE;
						return PLAY_POSTPONE;
					}
					pPlayCard = m_pConsumedCard;
					status << "PLCSH86! Cash the " & pPlayCard->GetName() & " from hand.\n";
				}
				else
				{
					// cash is/was in dummy, so discard
					if (bTrumped)
					{
						pPlayCard = playEngine.GetDiscard();
						status << "2PLCSH87! RHO's trump negates our cash; discard the " &
								  pPlayCard->GetName() & ".\n";
					}
					else
					{
						// see if we need to win in this hand to cash the remaining winnners
						if ((dummySuit.GetNumCards() == 0) && (declarerSuit.GetNumCards() > 1) && 
								(declarerSuit.GetNumLosers() == 0) && (*declarerSuit[0] > *pCardLed))
						{
							pPlayCard = declarerSuit.GetLowestCardAbove(pCardLed);
							status << "PLCSH88a! Our cash of the " & m_pConsumedCard->GetName() & 
									  " from dummy is holding, but we need to win in the hand to cash the remaining winners, so play the " &
									  pPlayCard->GetName() & " here.\n";
						}
						else
						{
							pPlayCard = playEngine.GetDiscard();
							status << "PLCSH88b! Our cash of the " &
									  m_pConsumedCard->GetName() & " from dummy is holding, so discard the " &
									  pPlayCard->GetName() & ".\n";
						}
					}
				}
			}
			else
			{
				// playing in dummy
				// see if it's time to cash
				if (m_nTargetHand == IN_DUMMY)
				{
					// cashing from dummy, so do it
					// BUT see if we have a lower card which would win!
					if (dummySuit.GetNumCardsAbove(pTopCard) > 1)
					{
						CCard* pCard = dummySuit.GetLowestCardAbove(pTopCard);
						status << "3PLCSH89! We can actually play the " & pCard->GetFaceName() &
								  " to win this trick, so postpone the cash of the " &
								  m_pConsumedCard->GetFaceName() & ".\n";
						m_nStatusCode = PLAY_INACTIVE;
						return PLAY_POSTPONE;
					}
					pPlayCard = m_pConsumedCard;
					status << "PLCSH90! Cash the " & pPlayCard->GetName() &
							  " from dummy.\n";
				}
				else
				{
					// cashed from hand, so discard
					if (bTrumped)
					{
						pPlayCard = playEngine.GetDiscard();
						status << "2PLCSH91! RHO's trump negates our cash; discard the " &
								  pPlayCard->GetName() & ".\n";
					}
					else
					{
						// see if we need to win here in dummy to cash the remaining winnners
						if ((declarerSuit.GetNumCards() == 0) && (dummySuit.GetNumCards() > 1) && 
								(dummySuit.GetNumLosers() == 0) && (*dummySuit[0] > *pCardLed))
						{
							pPlayCard = dummySuit.GetLowestCardAbove(pCardLed);
							status << "PLCSH92a! Our cash of the " & m_pConsumedCard->GetName() & 
									  " from hand is holding, but we need to win in dummy to cash the remaining winners, so play the " &
									  pPlayCard->GetName() & " here.\n";
						}
						else
						{
							pPlayCard = playEngine.GetDiscard();
							status << "PLCSH92b! Our cash of the " &
									  m_pConsumedCard->GetName() & " from hand is holding, so discard the " &
									  pPlayCard->GetName() & ".\n";
						}
					}
				}
			}
			// all's OK
			m_nStatusCode = PLAY_COMPLETE;
			break;
	}

	// ### TEMP ###
	if (pDOC->GetCurrentPlayerPosition() == playEngine.GetPlayerPosition())
		ASSERT(playEngine.GetPlayer()->HasCard(pPlayCard));
	else
		ASSERT(playEngine.GetPartner()->HasCard(pPlayCard));

	// done
	ASSERT(pPlayCard->IsValid());
	return m_nStatusCode;
}
Beispiel #6
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;
}
Beispiel #7
0
//
//---------------------------------------------------------
//
// PBN File output routine
//
BOOL CEasyBDoc::WriteFilePBN(CArchive& ar) 
{
	pFile = ar.GetFile();
	ASSERT(pFile != NULL);

	// write header
	WriteComment("");
	WriteComment("EXPORT");
	WriteComment("PBN Format 1.0");
	WriteComment(FormString("File generated by Easy Bridge version %s", theApp.GetProgramVersionString()));
	WriteComment("");

	//
	// write the data
	//

	// Event tag
	WriteLine(TAG_EVENT, FormString("%s Game", theApp.GetValue(tstrProgramTitle)));

	// Site Tag
	WriteLine(TAG_SITE, "At Home"); // NCR added At Home

	// Date Tag
	CTime time = CTime::GetCurrentTime();
	WriteLine(TAG_DATE, time.Format("%Y.%m.%d"));

/*
 * skip the round tag -- no longer mandatory in PBN 0.91+
 *
	// Round Tag
	WriteLine(TAG_ROUND, "");
 */

	// Board Tag
	WriteLine(TAG_BOARD, "1"); // NCR added 1

	// West/North/East/South Tags
	WriteLine(TAG_WEST, "Computer");
	WriteLine(TAG_NORTH, "Computer");
	WriteLine(TAG_EAST, "Computer");
	WriteLine(TAG_SOUTH, "Human Player");

	// Dealer Tag
	WriteLine(TAG_DEALER, FormString("%c", PositionToChar(m_nDealer)));

	// Vulnerable Tag
	CString strVulnerable;
	if ((m_bVulnerable[NORTH_SOUTH]) && (m_bVulnerable[EAST_WEST]))
		strVulnerable = "Both";
	else if (m_bVulnerable[NORTH_SOUTH])
		strVulnerable = "NS";
	else if (m_bVulnerable[EAST_WEST])
		strVulnerable = "EW";
	else
		strVulnerable = "None";
	WriteLine(TAG_VULNERABLE, strVulnerable);

	// deal tag
	CString strDeal = "W:";
	int nPos = WEST;
	int i; // NCR-FFS added here, removed below
	for(/*int*/ i=0;i<4;i++)
	{
		CCardHoldings& cards = m_pPlayer[nPos]->GetHand().GetInitialHand();
		strDeal += cards.GetGIBFormatHoldingsString();
		nPos = GetNextPlayer(nPos);
		if (i < 3)
			strDeal += ' ';
	}
	WriteLine(TAG_DEAL, strDeal);

	// Scoring tag
	if (theApp.IsRubberInProgress())
		WriteLine(TAG_SCORING, _T("Rubber"));
	else
		WriteLine(TAG_SCORING, _T("None"));

	// Declarer Tag
	if (ISPOSITION(m_nDeclarer))
		WriteLine(TAG_DECLARER, FormString("%c", PositionToChar(m_nDeclarer)));
	else
		WriteLine(TAG_DECLARER, "?");

	// Contract Tag
	if (ISBID(m_nContract)) 
	{
		// NCR Include ContractToString() here as PBN file does NOT have space before X
		CString strBid;
		strBid.Format("%d%s", 
					  BID_LEVEL(m_nContract), 
					  szSuitNameShort[BID_SUIT(m_nContract)]);
		int nModifier = pDOC->GetContractModifier();
		if (nModifier > 0)
			strBid += FormString("%s", ((nModifier == 1)? "X" : "XX")); // w/o space

		WriteLine(TAG_CONTRACT, strBid);  // NCR replaced ContractToString(m_nContract)
	}
	else
		WriteLine(TAG_CONTRACT, "?");

	// Result tag
	if (m_numTricksPlayed == 13)
		WriteLine(TAG_RESULT, FormString("%d", m_numTricksWon[m_nContractTeam])); // NCR removed extra "s
	else
		WriteLine(TAG_RESULT, "?");

	//
	// write out the hands in comment form
	//
	CString strHands = "{\r\n" + pDOC->FormatOriginalHands() + "}";
	WriteLine(strHands);

	//
	// write out auction
	//
	CString strBids = FormString("[Auction \"%c\"]", PositionToChar(m_nDealer)); // NCR Lowercased
	if (m_numBidsMade > 0)
		strBids += "\r\n";
	nPos = m_nDealer;
	for(i=0;i<m_numBidsMade;i++)
	{
		strBids += FormString("%s ", ::BidToPBNString(m_nBiddingHistory[i]));
		nPos = ::GetNextPlayer(nPos);
		if ( (((i+1) % 4) == 0) && (i < m_numBidsMade-1) )
			strBids += "\r\n";
	}
	// add marker if needed
	if (!ISBID(m_nContract))
		strBids += "\r\n*";
	// and write out
	WriteLine(strBids);


	//
	// write out plays
	//
	CString strPlays = FormString("[Play \"%c\"]", PositionToChar(m_nGameLead));  // NCR Lowercased
	if (m_numTricksPlayed> 0)
		strPlays += "\r\n";
	bool bLastRowFnd = false;  // NCR added - only output single row with -s
	for(i=0;i<m_numTricksPlayed;i++)
	{
		int nPos = m_nGameLead;
		for(int j=0;j<4;j++)
		{
			CCard* pCard = m_pGameTrick[i][nPos];
			if (pCard == NULL) {
				strPlays += "-  ";
				bLastRowFnd = true;  // NCR this row will end the output
			}
			else
				strPlays += FormString("%s ", pCard->GetName());
			nPos = ::GetNextPlayer(nPos);
		} // end for(j) thru poisitions
		if (i < m_numTricksPlayed-1)
			strPlays += "\r\n";
		if(bLastRowFnd)
			break;  // NCR finished output plays on line with -s
	} // end for(i) thru tricks
	// add marker if needed
	if (m_numTricksPlayed < 13)
		strPlays += "\r\n*";
	// and write out
	WriteLine(strPlays);


	// Generator Tag
	WriteLine(TAG_GENERATOR, FormString("Easy Bridge version %s", theApp.GetProgramVersionString()));

	// Description Tag
	WriteLine(TAG_DESCRIPTION, m_strFileDescription);

	// blank line
//	SkipLine();

	//
	// write out the auction
	//

	//	
	// All done
	//
	ar.Flush();
	return TRUE;
}
Beispiel #8
0
//
//---------------------------------------------------------
//
BOOL CEasyBDoc::WriteFile(CArchive& ar) 
{
	pFile = ar.GetFile();
	ASSERT(pFile != NULL);

	int i,j,numCards;
	CString	strTemp,strHand;
			
	// write the data

	//
	//-----------------------------------------------------
	//
	// first the file ID
	//
	WriteBlockHeader(BLOCK_FILEINFO);
	WriteString(ITEM_PROGRAM_ID,(LPCTSTR)theApp.GetValue(tstrProgramTitle));
	WriteInt(ITEM_MAJOR_VERSIONNO,theApp.GetValue(tnProgramMajorVersion));
	WriteInt(ITEM_MINOR_VERSIONNO,theApp.GetValue(tnProgramMinorVersion));
	WriteInt(ITEM_INCREMENT_VERSIONNO,theApp.GetValue(tnProgramIncrementVersion));
	WriteInt(ITEM_BUILD_NUMBER,theApp.GetValue(tnProgramBuildNumber));
	WriteString(ITEM_BUILD_DATE,(LPCTSTR)theApp.GetValue(tstrProgramBuildDate));
	CTime time = CTime::GetCurrentTime();
	strTemp.Format(" %s",(LPCTSTR)time.Format("%c"));
	WriteString(ITEM_FILE_DATE,strTemp);
	SkipLine();


	// then the file description
	WriteBlockHeader(BLOCK_FILEDESC);
	WriteString(ITEM_NONE,m_strFileDescription);
//	SkipLine();


	//
	//-----------------------------------------------------
	//
	// hand information
	//
	WriteBlockHeader(BLOCK_HANDINFO);
	// first the current hand
	for(i=0;i<4;i++) 
	{
		numCards = PLAYER(i).GetNumCards();
		strHand.Empty();
		for(j=0;j<numCards;j++) 
		{
			strHand += PLAYER(i).GetCardByPosition(j)->GetName();
			strHand += " ";
		}
		switch(i) 
		{
			case NORTH:
				WriteString(ITEM_CURRHAND_NORTH,strHand);
				break;
			case EAST:
				WriteString(ITEM_CURRHAND_EAST,strHand);
				break;
			case SOUTH:
				WriteString(ITEM_CURRHAND_SOUTH,strHand);
				break;
			case WEST:
				WriteString(ITEM_CURRHAND_WEST,strHand);
				break;
		}
	}
	// then the original hand
	for(i=0;i<4;i++) 
	{
		if (pVIEW->GetCurrentMode() == CEasyBView::MODE_CARDLAYOUT) 
		{
			numCards = PLAYER(i).GetNumCards();
			strHand.Empty();
			for(j=0;j<numCards;j++) 
			{
				strHand += PLAYER(i).GetCardByPosition(j)->GetName();
				strHand += " ";
			}
		} 
		else 
		{
			strHand.Empty();
			for(j=0;j<13;j++) 
			{
				strHand += PLAYER(i).GetInitialHandCard(j)->GetName();
				strHand += " ";
			}
		}
		switch(i) 
		{
			case NORTH:
				WriteString(ITEM_ORIGHAND_NORTH,strHand);
				break;
			case EAST:
				WriteString(ITEM_ORIGHAND_EAST,strHand);
				break;
			case SOUTH:
				WriteString(ITEM_ORIGHAND_SOUTH,strHand);
				break;
			case WEST:
				WriteString(ITEM_ORIGHAND_WEST,strHand);
				break;
		}
	}
	SkipLine();



	//
	//-----------------------------------------------------
	//
	// current round information
	//
	WriteBlockHeader(BLOCK_ROUNDINFO);
/*
	WriteString(ITEM_CURR_ROUND_LEAD, PositionToString(m_nRoundLead));
	//
	WriteInt(ITEM_NUM_CARDS_PLAYED_IN_ROUND, m_numCardsPlayedInRound);
	// tricks in current round
	for(i=0;i<m_numCardsPlayedInRound;i++)
		WriteString(ITEM_TRICK_CARD_1+i,m_pCurrTrick[i]->GetName());
*/
	//
	SkipLine();



	//
	//-----------------------------------------------------
	//
	// game status info
	//
	WriteBlockHeader(BLOCK_GAMEINFO);
	WriteInt(ITEM_VIEW_STATUS_CODE,pVIEW->GetCurrentMode());
	WriteBool(ITEM_RUBBER_IN_PROGRESS,theApp.IsRubberInProgress());
	WriteBool(ITEM_GAME_IN_PROGRESS,theApp.IsGameInProgress());
	WriteBool(ITEM_BIDDING_IN_PROGRESS,theApp.IsBiddingInProgress());
	WriteBool(ITEM_HANDS_DEALT,m_bHandsDealt);
	strTemp.Format("%s",SuitToString(m_nContractSuit));
	WriteString(ITEM_CONTRACT_SUIT,strTemp);
	WriteInt(ITEM_CONTRACT_LEVEL,m_nContractLevel);
	WriteInt(ITEM_CONTRACT_MODIFIER, m_bRedoubled? 2 : m_bDoubled? 1 : 0);
	WriteString(ITEM_DEALER,PositionToString(m_nDealer));
	WriteInt(ITEM_NUM_BIDS,m_numBidsMade);
	// declarer & bidding history
	strTemp.Empty();
	int nIndex = 0;
	for(i=0;i<=m_numBidsMade;i++) 
	{
		strTemp += BidToShortString(m_nBiddingHistory[i]);
		strTemp += " ";
	}
	WriteString(ITEM_DECLARER,PositionToString(m_nDeclarer));
	WriteString(ITEM_BIDDING_HISTORY,strTemp);
	SkipLine();


	//
	//-----------------------------------------------------
	//
	// game play record
	//
	WriteBlockHeader(BLOCK_GAMERECORD);
	if (m_bSaveIntermediatePositions)
	{
		// write the # tricks played
		int numTricks = m_numTricksPlayed;
		
		// see if the current trick is incomplete
		if ((pDOC->GetNumCardsPlayedInRound() > 0) && (numTricks < 13))
			numTricks++;
		WriteInt(ITEM_NUM_TRICKS_PLAYED,numTricks);
		
		// # tricks won by each side
		WriteInt(ITEM_NUM_TRICKS_WON_NS,m_numTricksWon[0]);
		WriteInt(ITEM_NUM_TRICKS_WON_EW,m_numTricksWon[1]);
		WriteString(ITEM_GAME_LEAD,PositionToString(m_nGameLead));

		// and the record of tricks
		for(i=0;i<13;i++) 
		{
			if (i <= m_numTricksPlayed)
			{
				strTemp.Empty();
				strTemp += PositionToString(m_nTrickLead[i]);
				strTemp += " ";
				for(j=0;j<4;j++) 
				{
					CCard* pCard = NULL;
					if (i < m_numTricksPlayed)
						pCard = m_pGameTrick[i][j];
					else
						pCard = m_pCurrTrick[j];
					//
					if (pCard != NULL)
					{
						strTemp += pCard->GetName();
						strTemp += " ";
					}
					else
					{
						strTemp += "-- ";
					}
				}
				strTemp += PositionToString(m_nTrickWinner[i]);
			}
			else
			{
				strTemp = "";
			}
			WriteString(ITEM_GAME_TRICK_1+i,strTemp);
		}
	}
	else
	{
		WriteInt(ITEM_NUM_TRICKS_PLAYED, 0);
	}
	//
	SkipLine();



	//
	//-----------------------------------------------------
	//
	// match info
	//
	if (theApp.IsRubberInProgress())
	{
		// write block header
		WriteBlockHeader(BLOCK_MATCHINFO);

		// write out scores
		WriteInt(ITEM_SCORE_NS_BONUS, m_nBonusScore[NORTH_SOUTH]);
		WriteInt(ITEM_SCORE_NS_GAME0, m_nGameScore[0][NORTH_SOUTH]);
		WriteInt(ITEM_SCORE_NS_GAME1, m_nGameScore[1][NORTH_SOUTH]);
		WriteInt(ITEM_SCORE_NS_GAME2, m_nGameScore[2][NORTH_SOUTH]);
		WriteInt(ITEM_SCORE_NS_GAMES_WON, m_numGamesWon[NORTH_SOUTH]);
		//
		WriteInt(ITEM_SCORE_EW_BONUS, m_nBonusScore[EAST_WEST]);
		WriteInt(ITEM_SCORE_EW_GAME0, m_nGameScore[0][EAST_WEST]);
		WriteInt(ITEM_SCORE_EW_GAME1, m_nGameScore[1][EAST_WEST]);
		WriteInt(ITEM_SCORE_EW_GAME2, m_nGameScore[2][EAST_WEST]);
		WriteInt(ITEM_SCORE_EW_GAMES_WON, m_numGamesWon[EAST_WEST]);

		// write out current game
		WriteInt(ITEM_CURRENT_GAME_INDEX, m_nCurrGame+1);

		// write out score record
		int numBonusScoreRecords = m_strArrayBonusPointsRecord.GetSize();
		for(int i=0;i<numBonusScoreRecords;i++)
			WriteString(ITEM_BONUS_SCORE_RECORD, WrapInQuotes(m_strArrayBonusPointsRecord.GetAt(i)));
		//
		int numGameScoreRecords = m_strArrayTrickPointsRecord.GetSize();
		for(i=0;i<numGameScoreRecords;i++)
			WriteString(ITEM_GAME_SCORE_RECORD, WrapInQuotes(m_strArrayTrickPointsRecord.GetAt(i)));
		//
		SkipLine();
	}



	//
	//-----------------------------------------------------
	//
	// misc info
	//
	WriteBlockHeader(BLOCK_MISCINFO);
	WriteBool(ITEM_AUTOSHOW_COMMENTS,m_bShowCommentsUponOpen);
	WriteBool(ITEM_AUTOSHOW_BID_HISTORY,m_bShowBidHistoryUponOpen);
	WriteBool(ITEM_AUTOSHOW_PLAY_HISTORY,m_bShowPlayHistoryUponOpen);
	WriteBool(ITEM_AUTOSHOW_ANALYSES,m_bShowAnalysesUponOpen);
	SkipLine();

	//
	//-----------------------------------------------------
	//
	// file comments
	//
	WriteBlockHeader(BLOCK_COMMENTS);
	// get the current file comments text if the dialog is open
	CWnd* pWnd = pMAINFRAME->GetDialog(twFileCommentsDialog);
	if (pWnd)
		pWnd->SendMessage(WM_COMMAND, WMS_UPDATE_TEXT, TRUE);
	WriteString(0,m_strFileComments);
	SkipLine();

	//	
	//-----------------------------------------------------
	//
	// PlayerAnalysis, if appropriate
	//
	for(i=0;i<4;i++)
	{
		if (m_bSavePlayerAnalysis[i])
		{
			// save out the player analysis text
			WriteBlockHeader(BLOCK_PLAYER_ANALYSIS + i);
			WriteString(0, m_pPlayer[i]->GetValueString(tszAnalysis));
			SkipLine();
		}
	}

	//	
	//-----------------------------------------------------
	//
	// All done
	//
	ar.Flush();
	return TRUE;
}
Beispiel #9
0
//
// Perform()
//
PlayResult CRuff::Perform(CPlayEngine& playEngine, CCombinedHoldings& combinedHand, 
				   CCardLocation& cardLocation, CGuessedHandHoldings** ppGuessedHands, 
				   CPlayerStatusDialog& status, CCard*& pPlayCard)
{
	// 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());
	CSuitHoldings& playerSuit = playerHand.GetSuit(m_nSuit);
	CSuitHoldings& dummySuit = dummyHand.GetSuit(m_nSuit);
	CCombinedSuitHoldings& combinedSuit = combinedHand.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;
	int nTrumpSuit = pDOC->GetTrumpSuit();
	if ((nSuitLed != nTrumpSuit) && (pDOC->WasTrumpPlayed()))
		bTrumped = TRUE;
	pPlayCard = NULL;
	CCard* pOppCard = NULL;
	//
	CCard* pRoundTopCard = pDOC->GetCurrentTrickHighCard();
	CCard* pDeclarerCard = pDOC->GetCurrentTrickCard(playEngine.GetPlayerPosition());
	CCard* pDummysCard = pDOC->GetCurrentTrickCard(playEngine.GetPartnerPosition());
	CCard* pPartnersCard = bPlayingInHand? pDummysCard : pDeclarerCard;
	BOOL bPartnerHigh = (pRoundTopCard == pPartnersCard);
	//
	BOOL bValid = FALSE;


	// test preconditions
	if (!CPlay::IsPlayUsable(combinedHand, playEngine))
	{
		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)?  can't do so!
				if (m_nTargetHand == IN_HAND)
				{
					// can't ruff here
//					status << "4PLRUF02! Can't ruff a card when leading.\n";
					m_nStatusCode = PLAY_POSTPONE;
					return m_nStatusCode;
				}
				else
				{
					// ruffing in dummy -- first check eligibility
					if (dummyHand.GetNumCardsInSuit(m_nSuit) > 0)
					{
						// can't use this now
						m_nStatusCode = PLAY_POSTPONE;
						return m_nStatusCode;
					}
					// now lead a low card of the suit from hand
					if (combinedSuit.GetNumDeclarerLosers() > 0)
					{
						pPlayCard = playerHand.GetSuit(m_nSuit).GetBottomCard();
						status << "PLRUF04! Lead a low " & STSS(m_nSuit) & 
								  " (the " & pPlayCard->GetFaceName() & ") from hand to ruff in dummy.\n";
					}
					else
					{
						// oops, no card in the suit to lead!
						status << "4PLRUF08! Oops, we wanted to ruff a " & STSS(m_nSuit) & 
								  " in dummy, but we have no " & STSS(m_nSuit) & 
								  " losers in hand to lead, so we have to abandon the play.\n";
						m_nStatusCode = PLAY_NOT_VIABLE;
						return m_nStatusCode;
					}
				}
			}
			else
			{
				// leading from dummy
				if (m_nTargetHand == IN_DUMMY)
				{
					// leading from dummy & ruffing in dummy? no can do
//					status << "4PLRUF12! Can't lead from dummy and ruff in dummy at the same time.\n";
					m_nStatusCode = PLAY_POSTPONE;
					return m_nStatusCode;
				}
				else 
				{
					// ruffing in hand -- first check eligibility
					if (playerHand.GetNumCardsInSuit(m_nSuit) > 0)
					{
						// can't use this now
						m_nStatusCode = PLAY_POSTPONE;
						return m_nStatusCode;
					}
					// now lead a low card of the suit from dummy
					if (combinedSuit.GetNumDummyLosers() > 0)
					{
						pPlayCard = dummyHand.GetSuit(m_nSuit).GetBottomCard();
						status << "PLRUF14! Lead a low " & STSS(m_nSuit) & 
								  " (the " & pPlayCard->GetFaceName() & ") from dummy to ruff in hand.\n";
					}
					else
					{
						// oops, no card in the suit to lead!
						status << "4PLRUF18! Oops, we wanted to ruff a " & STSS(m_nSuit) & 
								  " in hand, but we have no " & STS(m_nSuit) & 
								  " losers in dummy to lead, so we have to abandon the play.\n";
						m_nStatusCode = PLAY_NOT_VIABLE;
						return m_nStatusCode;
					}
				}
			}
			// at this point, all went OK
			m_nStatusCode = PLAY_IN_PROGRESS;
			break;

		case 1:
			// playing second -- may be able to ruff here, intended or not
			if (nSuitLed == nTrumpSuit)
			{
				// but not if a trump was led
					m_nStatusCode = PLAY_POSTPONE;
					return m_nStatusCode;
			}

			// an unintended ruff is OK only if the card led is not a trump card, 
			// _and_ we have zero cards in the suit in the appropriate hand
			if ( ((m_nTargetHand == IN_HAND) && (playerHand.GetNumCardsInSuit(nSuitLed) == 0)) ||
				 ((m_nTargetHand == IN_DUMMY) && (dummyHand.GetNumCardsInSuit(nSuitLed) == 0)) )
			{
				status << "3PLRUF20! We can ruff in the suit led by the opponent.\n";
			}
			else
			{
//				status << "3PLRUF21! A ruff here is not possible.\n";
				m_nStatusCode = PLAY_POSTPONE;
				return m_nStatusCode;
			}

			// see which hand this is
			if (bPlayingInHand) 
			{
				// playing second in hand -- see where the ruff is
				if (m_nTargetHand == IN_HAND)
				{
					// ruff here
					CSuitHoldings& playerTrumps = playerHand.GetSuit(nTrumpSuit);
					if (playerTrumps.GetNumCards() > 0)
					{
						pPlayCard = playerTrumps.GetBottomCard();
						status << "PLRUF30! Ruff in hand with the " & pPlayCard->GetName() & ".\n";
					}
					else
					{
						status << "4PLRUF32! Error - no trumps left in hand to use in a ruff.\n";
						m_nStatusCode = PLAY_ERROR;
						return m_nStatusCode;
					}
				}
				else
				{
					// we'll be ruffing in dummy later, so discard
					pPlayCard = playEngine.GetDiscard();
					status << "PLRUF34! We'll be ruffing in dummy, so discard the " &
							  pPlayCard->GetName() & " from hand.\n";
				}
			}
			else
			{
				// playing second in dummy -- see where the finese card is located
				if (m_nTargetHand == IN_DUMMY)
				{
					// ruff here
					CSuitHoldings& dummyTrumps = dummyHand.GetSuit(nTrumpSuit);
					if (dummyTrumps.GetNumCards() > 0)
					{
						pPlayCard = dummyTrumps.GetBottomCard();
						status << "PLRUF40! Ruff in dummy with the " & pPlayCard->GetName() & ".\n";
					}
					else
					{
						status << "4PLRUF42! Error - no trumps left in dummy to use in a ruff.\n";
						m_nStatusCode = PLAY_ERROR;
						return m_nStatusCode;
					}
				}
				else
				{
					// finessing in hand, so discard from dummy 
					pPlayCard = playEngine.GetDiscard();
					status << "PLRUF44! We'll be ruffing in hand, so discard the " &
							  pPlayCard->GetName() & " from dummy.\n";
				}
			}
			// done here
			m_nStatusCode = PLAY_IN_PROGRESS;
			break;


		case 2:  case 3:
			// playing third -- ruff if possible
//			if (m_nStatusCode != PLAY_IN_PROGRESS)
//				return PLAY_INACTIVE;
			// unintended ruff is OK only if the card led is not a trump card, 
			// _and_ we have zero cards in the suit
			if (bPlayingInHand)
			{
				if ( (m_nStatusCode == PLAY_IN_PROGRESS) ||
					 ((nSuitLed != nTrumpSuit) && (playerHand.GetNumCardsInSuit(nSuitLed) == 0)) )
					bValid = TRUE;
			}
			else
			{
				if ( (m_nStatusCode == PLAY_IN_PROGRESS) ||
					 ((nSuitLed != nTrumpSuit) && (dummyHand.GetNumCardsInSuit(nSuitLed) == 0)) )
					bValid = TRUE;
			}
			//
			if (bValid)
			{
				// bonanza
//				status << "3PLRUF50! We can ruff in the suit led by the opponent.\n";
//				status << "3PLRUF50! We can ruff here.\n";
			}
			else
			{
//				status << "3PLRUF51! A ruff here is not possible.\n";
				m_nStatusCode = PLAY_POSTPONE;
				return m_nStatusCode;
			}

			// at this point, we MUST be in the proper hand to ruff
			if (bPlayingInHand) 
			{
				// playing third/fourth in hand -- see where the ruff is
				if (m_nTargetHand == IN_HAND)
				{
					// ruff here
					CSuitHoldings& playerTrumps = playerHand.GetSuit(nTrumpSuit);
					if (playerTrumps.GetNumCards() > 0)
					{
						// see if RHO trumped
						if (bTrumped && (pPartnersCard != pRoundTopCard))
						{
							// see if we can beat it
							pPlayCard = playerTrumps.GetLowestCardAbove(pRoundTopCard);
							if (pPlayCard)
							{
								status << "PLRUF56! Overruff RHO's trump " & pRoundTopCard->GetFaceName() & 
										  " with the " & pPlayCard->GetFaceName() & ".\n";
							}
							else
							{
								status << "4PLRUF58! RHO ruffed, and we can't overruff.\n";
								m_nStatusCode = PLAY_POSTPONE;
								return m_nStatusCode;
							}
						}
						else if (pPartnersCard == pRoundTopCard)
						{
							status << "4PLRUF59! Partner'" & pPartnersCard->GetName() & " is high, so don't ruff it.\n";
							m_nStatusCode = PLAY_POSTPONE;
							return m_nStatusCode;
						}
						else
						{
							// go ahead and ruff
							pPlayCard = playerTrumps.GetBottomCard();
							status << "PLRUF60! Ruff in hand with the " & pPlayCard->GetName() & ".\n";
						}
					}
					else
					{
						status << "4PLRUF62! Error - no trumps left in hand to use in a ruff.\n";
						m_nStatusCode = PLAY_ERROR;
						return m_nStatusCode;
					}
				}
				else
				{
					// if we're playing 4th, we can discard (ruffed opposite)
					if (nOrdinal == 3)
					{
						if (bPartnerHigh)
						{
							pPlayCard = playEngine.GetDiscard();
							status << "PLRUF63! Complete the ruff by discarding the " & pPlayCard->GetName() & " from hand.\n";
						}
						else
						{
							// oops, opponents overruffed
							status << "3PLRUF63a! Oops, the opponents overruffed, so skip the play.\n";
							m_nStatusCode = PLAY_FAILED;
							return m_nStatusCode;
						}
					}
					else
					{
						// can't use _this_ ruff here
//						status << "4PLRUF64! Oops, we ended up in hand opposite a ruff in dummy.\n";
//						m_nStatusCode = PLAY_ERROR;
						m_nStatusCode = PLAY_POSTPONE;
						return m_nStatusCode;
					}
				}
			}
			else
			{
				// playing second in dummy -- see if we're ruffing here
				if (m_nTargetHand == IN_DUMMY)
				{
					// ruff here
					CSuitHoldings& dummyTrumps = dummyHand.GetSuit(nTrumpSuit);
					if (dummyTrumps.GetNumCards() > 0)
					{
						// see if RHO trumped
						if (bTrumped && (pPartnersCard != pRoundTopCard))
						{
							// see if we can beat it
							pPlayCard = dummyTrumps.GetLowestCardAbove(pRoundTopCard);
							if (pPlayCard)
							{
								status << "PLRUF70! Overruff RHO's trump " & pRoundTopCard->GetFaceName() & 
										  " with the " & pPlayCard->GetFaceName() & ".\n";
							}
							else
							{
								status << "3PLRUF72! RHO ruffed, and we can't overruff.\n";
								m_nStatusCode = PLAY_POSTPONE;
								return m_nStatusCode;
							}
						}
						else if (pPartnersCard == pRoundTopCard)
						{
							status << "4PLRUF73! Partner'" & pPartnersCard->GetName() & " is high, so don't ruff it.\n";
							m_nStatusCode = PLAY_POSTPONE;
							return m_nStatusCode;
						}
						else
						{
							// go ahead and ruff
							pPlayCard = dummyTrumps.GetBottomCard();
							status << "PLRUF74! Ruff in dummy with the " & pPlayCard->GetName() & ".\n";
						}
					}
					else
					{
						status << "4PLRUF76! Error - no trumps left in dummy to use in a ruff.\n";
						m_nStatusCode = PLAY_ERROR;
						return m_nStatusCode;
					}
				}
				else
				{
					// if we're playing 4th, we can discard (ruffed opposite)
					if (nOrdinal == 3)
					{
						if (bPartnerHigh)
						{
							pPlayCard = playEngine.GetDiscard();
							status << "PLRUF77! Complete the ruff by discarding the " & pPlayCard->GetName() & " from hand.\n";
						}
						else
						{
							// oops, opponents overruffed
							status << "3PLRUF77a! Oops, the opponents overruffed, so skip the play.\n";
							m_nStatusCode = PLAY_FAILED;
							return m_nStatusCode;
						}
					}
					else
					{
						// can't ruff here
//						status << "4PLRUF78! Oops, we ended up in dummy opposite a ruff in hand.\n";
//						m_nStatusCode = PLAY_ERROR;
						m_nStatusCode = PLAY_POSTPONE;
						return m_nStatusCode;
					}
				}
			}
			// else all went OK
			m_nStatusCode = PLAY_COMPLETE;
			break;
	}

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