//
// 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;
}
Exemple #2
0
std::ostream& operator<<(std::ostream& stream, const Card& other)
{
	return stream << ValueToString(other.mValue) << " of " << SuitToString(other.mSuit);
}
//
// 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;
}
//
//---------------------------------------------------------
//
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;
}