//
// FlashButton()
//
// used to temporarily flash a button's border
//
void CBidDialogSmall::FlashButton(int nBid)
{
	//
	CWnd *pWnd1 = NULL, *pWnd2 = NULL;
	//
	if (ISBID(nBid))
	{
		int nLevel = BID_LEVEL(nBid);
		int nSuit = BID_SUIT(nBid);
		pWnd1 = GetDlgItem(IDC_BID_LEVEL_1 + nLevel - 1);
		pWnd2 = GetDlgItem(IDC_SUIT_CLUBS + nSuit);
	}
	else if (nBid == BID_PASS)
		pWnd1 = GetDlgItem(IDC_BID_PASS);
	else if (nBid == BID_DOUBLE)
		pWnd1 = GetDlgItem(IDC_BID_DOUBLE);
	else if (nBid == BID_REDOUBLE)
		pWnd1 = GetDlgItem(IDC_BID_REDOUBLE);
	//
	if (pWnd1 == NULL)
		return;

	//
	FlashWindow(pWnd1, pWnd2);
}
//
// PressBidButton()
//
// used to make a button it appear pressed
//
void CBidDialogSmall::PressBidButton(int nBid)
{
	//
	CButton *pButton1 = NULL, *pButton2 = NULL;
	//
	if (ISBID(nBid))
	{
		int nLevel = BID_LEVEL(nBid);
		int nSuit = BID_SUIT(nBid);
		pButton1 = (CButton*) GetDlgItem(IDC_BID_LEVEL_1 + nLevel - 1);
		pButton2 = (CButton*) GetDlgItem(IDC_SUIT_CLUBS + nSuit);
	}
	else if (nBid == BID_PASS)
		pButton1 = (CButton*) GetDlgItem(IDC_BID_PASS);
	else if (nBid == BID_DOUBLE)
		pButton1 = (CButton*) GetDlgItem(IDC_BID_DOUBLE);
	else if (nBid == BID_REDOUBLE)
		pButton1 = (CButton*) GetDlgItem(IDC_BID_REDOUBLE);
	//
	if (pButton1 == NULL)
		return;

	//
	BOOL bWindow2Enabled = pButton2? pButton2->IsWindowEnabled() : FALSE;
	//
	pButton1->SetState(TRUE);
	if (pButton2)
	{
		pButton2->EnableWindow(TRUE);
		pButton2->SetState(TRUE);
	}
	//
	Sleep(300);
	//
	pButton1->SetState(FALSE);
	if (pButton2)
	{
		pButton2->SetState(FALSE);
		pButton2->EnableWindow(bWindow2Enabled);
	}

	// done
	return;
}
//
//===============================================================================
//
// TryConvention()
//
// check if we can use an Jacoby 2NT Bid here
//
BOOL CJacoby2NTConvention::TryConvention(const CPlayer& player, 
										 const CConventionSet& conventions, 
										 CHandHoldings& hand, 
										 CCardLocation& cardLocation, 
										 CGuessedHandHoldings** ppGuessedHands,
										 CBidEngine& bidState,  
										 CPlayerStatusDialog& status)
{
	//
	// the requirements for an Jacoby 2NT Bid are:
	// 1: Partner must have opened with 1 of a major
	// 2: we must not have bid yet
	// 3: we have 13+ points and 4+ card trump support

	int nOpeningBid = pDOC->GetOpeningBid();
	int nPartnersBid = bidState.nPartnersBid;

	// test conditions 1 - 4
	if ( ISBID(nOpeningBid) && (nOpeningBid == nPartnersBid) && 
		 (ISMAJOR(BID_SUIT(bidState.nPartnersBid))) && (bidState.nPartnersBidLevel == 1) &&
		 (bidState.m_numBidTurns == 0) && (bidState.fPts >= OPEN_PTS(13)) &&
		 (bidState.numSupportCards >= 4) )
	{
		 // passed the test
	}
	else
	{
		return FALSE;
	}
	
	// calc adjusted pts
	int nSuit = bidState.nPartnersSuit;
	bidState.SetAgreedSuit(nSuit);
	bidState.fAdjPts = hand.RevalueHand(REVALUE_DUMMY, nSuit, TRUE);

	//
	status << "J2N1! Partner opened " & BTS(nPartnersBid) & ", and with " &
			  bidState.fAdjPts & " pts in hand and " & bidState.numSupportCards & 
			  "-card trump support, we can bid Jacoby 2NT to ask for partner's strength.\n";
	bidState.SetBid(BID_2NT);
	bidState.SetConventionStatus(this, CONV_INVOKED);
	return TRUE;
}
Example #4
0
BOOL CEasyBDoc::ExportGameInfo(CArchive& ar) 
{
	// export game info
	// export hands
	WriteText(ar, "[Dealt Hands]\r\n");
	CString strHands = FormatOriginalHands();
	WriteText(ar, strHands);

	// export bidding history
	WriteText(ar, "\r\n\r\n");
	WriteText(ar, "[Bidding History]\r\n");
	const CString strBiddingHistory = pMAINFRAME->GetBiddingHistory();
	WriteText(ar, strBiddingHistory);
	if (ISBID(GetContract()))
	{
		int nDeclarer = GetDeclarerPosition();
		CString strContract = FormString("Contract: %s by %s; %s leads", pDOC->GetContractString(), PositionToString(nDeclarer), PositionToString(GetNextPlayer(nDeclarer)));
//		WriteText(pFile, strContract);
	}

	// export play history
	WriteText(ar, "\r\n\r\n\r\n");
	WriteText(ar, "[Play History]\r\n");
	const CString strPlayHistory = pMAINFRAME->GetPlayHistory();
	WriteText(ar, strPlayHistory);

	// export current hands
	if (GetNumTricksPlayed() > 0)
	{
		WriteText(ar, "\r\n\r\n\r\n");
		WriteText(ar, "[Current Hands]\r\n");
		CString strHands = pDOC->FormatCurrentHands();
		WriteText(ar, strHands);
	}

	// done
	ar.Flush();
	return TRUE;
}
Example #5
0
//
//---------------------------------------------------------
//
BOOL CEasyBDoc::ReadFile(CArchive& ar) 
{
	int i,nRtnCode,nLineCode,nSectionCode;
	int	nIndex,nValue,nOffset,nLen;
	int nPlayOffset, nPos;
	int nBidIndex = 0;
	CString strMessage,string,partString;
	CCard* pCard;
	double fValue;
	BOOL bValue;
	BOOL bFileInfoFound = FALSE;

	
	// read
	m_nLineNumber = 0;
	try
	{
		for(;;) 
		{

			nRtnCode = ReadLine(ar, strBuf);
next:		if (nRtnCode == EOF)
				break;
			if (nRtnCode == 0)
				continue;
			if ((strBuf[0] == '#') || (strBuf[0] == '*'))
				continue;
			nLineLen = nRtnCode;
			nLineCode = ParseLine(strBuf,nLineLen);
			
			if (nLineCode < 0) 
			{

				// section signifier
				nSectionCode = -nLineCode;
				if (nSectionCode == BLOCK_FILEINFO)
				{
					//
					bFileInfoFound = TRUE;
					// file info; skip this section
					do {
						nRtnCode = ReadLine(ar, strBuf);
					} while ((nRtnCode != EOF) && (strBuf.Left(2) != "[["));
					//
					goto next;
				} 
				//
				if (nSectionCode == BLOCK_FILEDESC) 
				{
					// file description; read until next block
					m_strFileDescription.Empty();
					do {
						nRtnCode = ReadLine(ar, strBuf);
						if (strBuf.Left(2) != "[[")
						{
							strBuf += "\r\n";
							m_strFileDescription += strBuf;
						}
					} while ((nRtnCode != EOF) && (strBuf.Left(2) != "[["));

					// trim ending CR/LF
					int nLen = m_strFileDescription.GetLength();
					if ((nLen >= 2) && (m_strFileDescription[nLen-1] == _T('\n')))
						m_strFileDescription = m_strFileDescription.Left(nLen-2);
					//
					goto next;
				} 
				else if (nSectionCode == BLOCK_COMMENTS) 
				{
					// file comments
					for (;;) 
					{
						nRtnCode = ReadLine(ar, strBuf);
						if ((nRtnCode == EOF) || (strBuf.Left(2) == "[[")) 
						{
							// update file comments dialog if it's open
							CWnd* pWnd = pMAINFRAME->GetDialog(twFileCommentsDialog);
							if (pWnd)
								pWnd->SendMessage(WM_COMMAND, WMS_UPDATE_TEXT, FALSE);
							goto next;
						}
						strBuf += "\r\n";
						m_strFileComments += strBuf;
					}
				}
				else if ((nSectionCode == BLOCK_SOUTH_ANALYSIS) ||
						 (nSectionCode == BLOCK_WEST_ANALYSIS) ||
						 (nSectionCode == BLOCK_NORTH_ANALYSIS) ||
						 (nSectionCode == BLOCK_EAST_ANALYSIS))
				{
					// don't bother to save the analysis
					int nPlayer = nSectionCode - BLOCK_SOUTH_ANALYSIS;
					CString strAnalysisBiffer;
					do {
						nRtnCode = ReadLine(ar, strBuf);
	//					strBuf += "\r\n";
	//					strAnalysisBiffer += strBuf;
					} while ((nRtnCode != EOF) && (strBuf.Left(2) != "[["));
	//				m_player[nPlayer].SetValueString(tszAnalysis,  strAnalysisBiffer);
					goto next;
				}

			} 
			else if (nLineCode > 0) 
			{

				// first skip spaces
				nLen = strBuf.GetLength();
				while ((nDataPosition < nLen) && 
						(strBuf[nDataPosition] == ' '))
					nDataPosition++;
				if (nDataPosition >= nLen)
					continue;
				// then get data item
				string = strBuf.Mid(nDataPosition);
				nValue = atoi(string);
				fValue = atof(string);
				if ((string == "Yes") || (string == "1"))
					bValue = TRUE;
				else
					bValue = FALSE;

				switch(nLineCode) 
				{

					case ITEM_PROGRAM_ID:
						m_strFileProgTitle = string;
						break;

					case ITEM_MAJOR_VERSIONNO:
						m_nFileProgMajorVersion = nValue;
						break;

					case ITEM_MINOR_VERSIONNO:
						m_nFileProgMinorVersion = nValue;
						break;

					case ITEM_INCREMENT_VERSIONNO:
						m_nFileProgIncrementVersion = nValue;
						break;

					case ITEM_BUILD_NUMBER:
						m_nFileProgBuildNumber = nValue;
						break;

					case ITEM_BUILD_DATE:
						m_strFileProgBuildDate = string;
						break;

					case ITEM_FILE_DATE:
						m_strFileDate = string;
						break;

					// hand info, 10..19
					case ITEM_CURRHAND_NORTH:
						AssignCards(string,NORTH);
						break;

					case ITEM_CURRHAND_EAST:
						AssignCards(string,EAST);
						break;

					case ITEM_CURRHAND_SOUTH:
						AssignCards(string,SOUTH);
						break;

					case ITEM_CURRHAND_WEST:
						AssignCards(string,WEST);
						break;

					case ITEM_ORIGHAND_NORTH:
						AssignCards(string,NORTH,TRUE);
						break;

					case ITEM_ORIGHAND_EAST:
						AssignCards(string,EAST,TRUE);
						break;

					case ITEM_ORIGHAND_SOUTH:
						AssignCards(string,SOUTH,TRUE);
						break;

					case ITEM_ORIGHAND_WEST:
						AssignCards(string,WEST,TRUE);
						break;

					// current round info
					case ITEM_CURR_ROUND_LEAD:
						m_nRoundLead = StringToPosition(string);
						break;

					case ITEM_NUM_CARDS_PLAYED_IN_ROUND:
						m_numCardsPlayedInRound = nValue;
						break;

					case ITEM_TRICK_CARD_1:
						m_pCurrTrick[0] = deck.GetCard(string);
						break;

					case ITEM_TRICK_CARD_2:
						m_pCurrTrick[1] = deck.GetCard(string);
						break;

					case ITEM_TRICK_CARD_3:
						m_pCurrTrick[2] = deck.GetCard(string);
						break;

					case ITEM_TRICK_CARD_4:
						m_pCurrTrick[3] = deck.GetCard(string);
						break;

					// game status info
					case ITEM_VIEW_STATUS_CODE:
						pVIEW->SetCurrentMode((CEasyBView::ScreenMode)nValue);
						break;

					case ITEM_RUBBER_IN_PROGRESS:
						theApp.SetValue(tbRubberInProgress, bValue);
						break;

					case ITEM_GAME_IN_PROGRESS:
						// TEMP
//						theApp.SetValue(tbGameInProgress, FALSE);
						theApp.SetValue(tbGameInProgress, bValue);
						break;

					case ITEM_BIDDING_IN_PROGRESS:
						theApp.SetValue(tbBiddingInProgress, bValue);
						break;

					case ITEM_HANDS_DEALT:
						m_bHandsDealt = bValue;
						break;
					
					case ITEM_CONTRACT_SUIT:
						nLen = string.GetLength();
						m_nContractSuit = CharToSuit(string.GetAt(0));
						break;

					case ITEM_CONTRACT_LEVEL:
						m_nContractLevel = nValue;
						break;

					case ITEM_CONTRACT_MODIFIER:
						switch(nValue) 
						{
							case 0:
								m_bDoubled = FALSE;
								m_bRedoubled = FALSE;
								m_nContractModifier = 0;
								break;
							case 1:
								m_bDoubled = TRUE;
								m_bRedoubled = FALSE;
								m_nContractModifier = 1;
								break;
							case 2:
								m_bDoubled = FALSE;
								m_bRedoubled = TRUE;
								m_nContractModifier = 2;
								break;
						}
						break;

					case ITEM_DEALER:
						m_nDealer = StringToPosition(string);
						break;

					case ITEM_NUM_BIDS:
//						m_numBidsMade = nValue;
						break;

					case ITEM_BIDDING_HISTORY:
						strBiddingHistory = string;
						break;

					case ITEM_DECLARER:
						m_nDeclarer = StringToPosition(string);
						m_nContractTeam = GetPlayerTeam(m_nDeclarer);
						m_nDefendingTeam = (m_nContractTeam == NORTH_SOUTH)? EAST_WEST : NORTH_SOUTH;
						break;

					// game record
					case ITEM_NUM_TRICKS_PLAYED:
						m_numTricksPlayed = nValue;
						break;

					case ITEM_NUM_TRICKS_WON_NS:
						m_numTricksWon[0] = nValue;
						break;

					case ITEM_NUM_TRICKS_WON_EW:
						m_numTricksWon[1] = nValue;
						break;

					case ITEM_GAME_LEAD:
						m_nGameLead = StringToPosition(string);
						break;

					case ITEM_GAME_TRICK_1: case ITEM_GAME_TRICK_2: 
					case ITEM_GAME_TRICK_3: case ITEM_GAME_TRICK_4: 
					case ITEM_GAME_TRICK_5: case ITEM_GAME_TRICK_6: 
					case ITEM_GAME_TRICK_7: case ITEM_GAME_TRICK_8: 
					case ITEM_GAME_TRICK_9: case ITEM_GAME_TRICK_10: 
					case ITEM_GAME_TRICK_11: case ITEM_GAME_TRICK_12: 
					case ITEM_GAME_TRICK_13:
						try
						{
							nIndex = nLineCode - ITEM_GAME_TRICK_1;
							nOffset = 0;
							nLen = string.GetLength();
							// first read the lead player for the trick
							partString = string.Mid(nOffset);
							m_nTrickLead[nIndex] = StringToPosition(partString);
							nOffset = string.Find(' ');
							//
							for(i=0;i<4;i++) 
							{
								while((nOffset < nLen) && (string[nOffset] == ' '))
									nOffset++;
								partString = string.Mid(nOffset);
								nOffset += 2;
								if (partString.IsEmpty()) 
								{
									strMessage.Format("Incomplete Trick record at line %d;\n%s",
													  m_nLineNumber, string);
									AfxMessageBox(strMessage);
									break;
								}
								//
								if (partString.Left(2) == "--")
								{
									m_pGameTrick[nIndex][i] = NULL;
								}
								else
								{
									pCard = deck.GetCard(partString);
									m_pGameTrick[nIndex][i] = pCard;
								}
							}
							// insert the trick record into the game record
							// in the proper order
							nPlayOffset = nIndex * 4;
							nPos = m_nTrickLead[nIndex];
							for(i=0;i<4;i++)
							{
								CCard* pCard = m_pGameTrick[nIndex][nPos];
								if (pCard)
									m_nPlayRecord[nPlayOffset+i] = pCard->GetDeckValue();
								nPos = GetNextPlayer(nPos);
							}
							// and finally read the trick's winner 
							while((nOffset < nLen) && (string[nOffset] == ' '))
								nOffset++;
							partString = string.Mid(nOffset);
							m_nTrickWinner[nIndex] = StringToPosition(partString);
						}
						catch(...)
						{
							// error
						}
						break;

					// match info
					case ITEM_SCORE_NS_BONUS:
						m_nBonusScore[NORTH_SOUTH] = nValue;
						break;

					case ITEM_SCORE_NS_GAME0:
						m_nGameScore[0][NORTH_SOUTH] = nValue;
						break;

					case ITEM_SCORE_NS_GAME1:
						m_nGameScore[1][NORTH_SOUTH] = nValue;
						break;

					case ITEM_SCORE_NS_GAME2:
						m_nGameScore[2][NORTH_SOUTH] = nValue;
						break;

					case ITEM_SCORE_NS_GAMES_WON:
						m_numGamesWon[NORTH_SOUTH] = nValue;
						break;

					case ITEM_SCORE_EW_BONUS:
						m_nBonusScore[EAST_WEST] = nValue;
						break;

					case ITEM_SCORE_EW_GAME0:
						m_nGameScore[0][EAST_WEST] = nValue;
						break;

					case ITEM_SCORE_EW_GAME1:
						m_nGameScore[1][EAST_WEST] = nValue;
						break;

					case ITEM_SCORE_EW_GAME2:
						m_nGameScore[2][EAST_WEST] = nValue;
						break;

					case ITEM_SCORE_EW_GAMES_WON:
						m_numGamesWon[EAST_WEST] = nValue;
						break;

					case ITEM_CURRENT_GAME_INDEX:
						m_nCurrGame = nValue-1;
						break;

					case ITEM_BONUS_SCORE_RECORD:
						m_strArrayBonusPointsRecord.Add(StripQuotes(string));
						break;

					case ITEM_GAME_SCORE_RECORD:
						m_strArrayTrickPointsRecord.Add(StripQuotes(string));
						break;

					// misc info
					case ITEM_AUTOSHOW_COMMENTS:
						m_bShowCommentsUponOpen = bValue;
						break;
					case ITEM_AUTOSHOW_BID_HISTORY:
						m_bShowBidHistoryUponOpen = bValue;
						break;
					case ITEM_AUTOSHOW_PLAY_HISTORY:
						m_bShowPlayHistoryUponOpen = bValue;
						break;
					case ITEM_AUTOSHOW_ANALYSES:
						m_bShowAnalysesUponOpen = bValue;
						break;

				}

			} 
			else 
			{

	/*
				// unknown line
				strMessage.Format("Found Unknown line\n%s.\nContinue?",strBuf);
				if (AfxMessageBox(strMessage, MB_ICONEXCLAMATION | MB_OKCANCEL) == IDCANCEL)
					break;
	*/
			}

		}
	}
	catch(...)
	{
		// handle any improper file error here
		ClearAllInfo();
//		AfxMessageBox("An error ocurred while reading the game file.");
		return FALSE;
	}

	// see if this was a valid file
	if (!bFileInfoFound)
	{
		AfxMessageBox("This is not a proper Easy Bridge game file.");
		AfxThrowFileException(CFileException::generic);
	}

	//
	// do some sanity checks
	//
	m_nContract = MAKEBID(m_nContractSuit, m_nContractLevel);
	if (!ISPLAYER(m_nDeclarer) || !ISBID(m_nContract))
		theApp.SetValue(tbGameInProgress, FALSE);

	//
	// parse the bidding history
	//
	if (!ISPLAYER(m_nDeclarer))
		m_nDeclarer = SOUTH;
	nPos = m_nDeclarer;
	m_nCurrPlayer = nPos;
	int nTeam = GetPlayerTeam(nPos);
	nOffset = 0;
	// 
	nLen = strBiddingHistory.GetLength();
	for(i=0;;i++) 
	{
		// skip leading spaces
		while((nOffset < nLen) && (strBiddingHistory[nOffset] == ' '))
			nOffset++;
		if (nOffset >= nLen)
			break;
		// grab the next bid
		partString = strBiddingHistory.Mid(nOffset);
		int nBid = ContractStringToBid(partString);
		// and record it
		m_nBiddingHistory[m_numBidsMade] = nBid;
		m_numBidsMade++;
		m_nCurrPlayer = GetNextPlayer(m_nCurrPlayer);
		int nBiddingRound = i % 4;
		m_nBidsByPlayer[nPos][nBiddingRound] = nBid;
		// see if this is an actual numeric bid
		if (ISBID(nBid))
		{
			m_nValidBidHistory[m_numValidBidsMade] = nBid;
			m_numValidBidsMade++;
			m_nLastValidBid = nBid;
			m_nLastValidBidTeam = nTeam;
		}
		// skip over remainder of current bid string
		while((nOffset < nLen) && (strBiddingHistory[nOffset] != ' '))
			nOffset++;
		// and move to the next player
		nPos = GetNextPlayer(nPos);
		nTeam = GetOpposingTeam(nTeam);
	}
	if (ISBID(m_nContract))
		UpdateBiddingHistory();


	// tally some figures
	m_nTotalScore[0] = m_nGameScore[0][0] + m_nGameScore[1][0] +
					   m_nGameScore[2][0] + m_nBonusScore[0];
	m_nTotalScore[1] = m_nGameScore[0][1] + m_nGameScore[1][1] +
					   m_nGameScore[2][1] + m_nBonusScore[1];

	// vulnerability
	if ((m_numGamesWon[0] > 0) && (m_numGamesWon[1] > 0)) 
	{
		m_nVulnerableTeam = BOTH;
		m_bVulnerable[0] = m_bVulnerable[1] = TRUE;
	} 
	else if (m_numGamesWon[0] > 0) 
	{
		m_nVulnerableTeam = NORTH_SOUTH;
		m_bVulnerable[0] = TRUE;
	} 
	else if (m_numGamesWon[1] > 0)
	{
		m_nVulnerableTeam = EAST_WEST;
		m_bVulnerable[1] = TRUE;
	} 
	else 
	{
		m_nVulnerableTeam = NEITHER;
	}

	//
	// set contract info
	//
	m_nContract = ContractParamsToBid(m_nContractSuit,m_nContractLevel);
	m_nTrumpSuit = m_nContractSuit;
	m_nBiddingRound = nBidIndex;
	// set play info 
	if (ISBID(m_nContract) && ISPLAYER(m_nDeclarer))
	{
		// contract has been reached
		m_nDummy = GetPartner((int) m_nDeclarer);
		m_nGameLead = GetNextPlayer(m_nDeclarer);
		m_nRoundLead = m_nGameLead;
		m_nCurrPlayer = m_nRoundLead;
		m_nTrickLead[0] = m_nRoundLead;
//		m_pPlayer[m_nDummy]->SetDummyFlag(TRUE);
//		m_pPlayer[m_nDeclarer]->SetDeclarerFlag(TRUE);
	}
	else
	{
		// contract has NOT been reached, so restart
		m_nCurrPlayer = m_nDealer;
		m_numBidsMade = 0;
	}

	// restore initial hands (temp?)
	for(i=0;i<4;i++)
		m_pPlayer[i]->RestoreInitialHand();

	// not reviewing game
	m_bReviewingGame = FALSE;

	// all done
	return TRUE;
}
Example #6
0
//
//---------------------------------------------------------
//
BOOL CEasyBDoc::ReadFilePBN(CArchive& ar) 
{
	int nLineCode, nValue, nCode;
	CString strMessage, string, strTag, strValue, partString, strModifier;
	double fValue;
	BOOL bValue;
	CString strLine;


	// init some flags
	m_bReviewingGame = FALSE;
	m_bGameReviewAvailable = FALSE;

	// preload the file
	numLines = PreloadPBNFile(ar, strLines);
/*
	int sizeOf = strLines.GetSize();   // NCR DEBUG ONLY
	for(int xxx = 0; xxx < sizeOf; xxx++) {
		CString nxtStr = strLines.GetAt(xxx);
		ASSERT(!nxtStr.IsEmpty());
	}
*/
	// read in the ines
	pGameRecord = NULL;
	m_nLineNumber = 0;
	nGameIndex = 0;
	nPreviousTag = 0;
	int numGamesLoaded = 0;
	int numInvalidGames = 0;
	int numTagsRead = 0;
	int numDeclarers = 0;		// NCR use to test reviewable deals ie no Declarer means no review

	//
	for(;;) 
	{
		// check for EOF
		if (m_nLineNumber >= numLines)
			break;

		strBuf = strLines.GetAt(m_nLineNumber++);

		//
		strBuf.TrimLeft();
		strBuf.TrimRight();
		nLineLen = strBuf.GetLength();

		// see if this is a blank line (but watch out for multiple empty lines)
		if (strBuf.IsEmpty())
		{
			// flush out the current game
			if (pGameRecord)
			{
				pGameRecord->AnalyzePlayRecord();
				if (pGameRecord->IsValid(isExportFile))   // NCR_PBNI added isExportFile
				{
					m_gameRecords.Add(pGameRecord);
					numGamesLoaded++;
					nGameIndex++;
				}
				else
				{
					delete pGameRecord;
					numInvalidGames++;
				}
				pGameRecord = NULL;
				nPreviousTag = 0;
				continue;
			}
		}

		// else parse the line for tokens
		nLineCode = ParseLinePBN(strBuf, strTag, strValue, nLineLen);

		// check for error
		if (nLineCode < 0)
		{
			// junk tag?
			if (m_nLineNumber == 0)
			{
				AfxMessageBox("This is not a proper PBN format file.");
				AfxThrowFileException(CFileException::generic);
			}
			continue;
		}

		//
		// else the tag is OK
		//

		// see if the value is "#" -- then substitute
		if ((strValue == "#") && (nGameIndex > 0))
		{
			// look up the value from the previous game
			CGameRecord* pPrevGame = m_gameRecords[nGameIndex-1];
			std::map<CString,CString>::const_iterator iter = pPrevGame->m_mapTagValues.find(strTag);
			if (iter != pPrevGame->m_mapTagValues.end())
				strValue = (*iter).second;
		}

		//
		// get data value
		//
		nValue = atoi(strValue);
		fValue = atof(strValue);
		if ((strValue == "Yes") || (strValue == "1"))
			bValue = TRUE;
		else
			bValue = FALSE;

		//
		// if this is a valid tag, alloc a new game object
		//
		if ((!strTag.IsEmpty()) && (pGameRecord == NULL))
		{
			pGameRecord = new CGameRecord;
			numTagsRead = 0;
		}


		//
		//-------------------------------------------------------------------
		//
		// process item
		//

		switch(nLineCode) 
		{
			case TAG_EVENT:
				break;

			case TAG_SITE:
				// ignore for now
				break;

			case TAG_DATE:
				// ignore for now
				break;

			case TAG_ROUND:
				// ignore for now
				break;

			case TAG_BOARD:
				// ignore for now
				break;

			case TAG_WEST:
				// ignore for now
				break;

			case TAG_NORTH:
				// ignore for now
				break;

			case TAG_EAST:
				// ignore for now
				break;

			case TAG_SOUTH:
				// ignore for now
				break;

			// dealer
			case TAG_DEALER:
				if (!strValue.IsEmpty() && (strValue[0] != '?'))
					pGameRecord->m_nDealer = CharToPosition(strValue[0]);
				break;

			// vulnerability
			case TAG_VULNERABLE:
				if (strValue.CompareNoCase("NS") == 0)
					pGameRecord->m_nVulnerability = NORTH_SOUTH;
				else if (strValue.CompareNoCase("EW") == 0)
					pGameRecord->m_nVulnerability = EAST_WEST;
				else if ((strValue.CompareNoCase("All") == 0) || (strValue.CompareNoCase("Both") == 0))
					pGameRecord->m_nVulnerability = BOTH;
				else if((strValue.CompareNoCase("None") == 0) || (strValue.CompareNoCase("-") == 0)) // NCR-PBNI
					pGameRecord->m_nVulnerability = NEITHER;
				else      // error if not above
					AfxMessageBox("Invalid Vulnerabliity: " + strValue);
				break;

			case TAG_DEAL:
//				AssignCardsPBN(strValue);
				break;

			case TAG_SCORING:
				// ignore for now
				break;

			case TAG_DECLARER:
				if (!strValue.IsEmpty() && (strValue[0] != '?')) {
					pGameRecord->m_nDeclarer = CharToPosition(strValue[0]);
					numDeclarers++;   // NCR count for need to do review
				}
				break;

			case TAG_CONTRACT:
				{
				// decipher the contract
				if ((strValue.GetLength() < 2) || (strValue[0] == '?'))
				{
					// contract has not yet been set
					theApp.SetValue(tbGameInProgress, FALSE);
					break;
				}
				int nContractLevel = atoi(strValue);
				int nContractSuit = CharToSuit(strValue[1]);
				int nContract = MAKEBID(nContractSuit, nContractLevel);
				int nContractModifier = 0;
				//
				pGameRecord->m_nContract = nContract;
				// get modifier
				if (nContractSuit == NOTRUMP)
					strModifier = strValue.Mid(3);
				else
					strModifier = strValue.Mid(2);
				if (strModifier.CompareNoCase("X") == 0)
					nContractModifier = 1;
				else if (strModifier.CompareNoCase("XX") == 0)
					nContractModifier = 2;
				//
				pGameRecord->m_nContractModifier = nContractModifier;
				break;
				}

			case TAG_RESULT:
				// ignore for now
				break;

			// ge the auction
			case TAG_AUCTION:
				if (strValue.IsEmpty())
					break;
				// parse the bids
				nCode = ParseBidsPBN(ar, strValue);
				break;

			case TAG_PLAY:
				// read in the plays
				if (strValue.IsEmpty() || (strValue[0] == '?'))
					break;
				// parse the plays
				nCode = ParsePlaysPBN(ar, strValue);
				// mark this file as being reviewable
				if (ISBID(pGameRecord->m_nContract))
				{
					// contract must also be valid
					m_bReviewingGame = TRUE;
					m_bGameReviewAvailable = TRUE;
				}
				break;

			case TAG_NOTE:
				// add to the appropriate list
				if (nPreviousTag == TAG_AUCTION)
					pGameRecord->m_strBiddingNotes.Add(strValue);
				else if (nPreviousTag == TAG_PLAY)
					pGameRecord->m_strPlayNotes.Add(strValue);
				break;


			case TAG_OPTIMUMSCORE:  // NCR-776 for BridgeWebs files
				// ignore 
				break;

			case TAG_TERMINATOR:
				// ignore for now
				break;
		} // end switch(nLineCode)

		// save this tag
		nPreviousTag = nLineCode;
		numTagsRead++;

		// save the tag-value pair in the map
		if (pGameRecord)
		{
			// but don't save notes here
			if (strTag.CompareNoCase("Note") != 0)
				pGameRecord->SetTagValue(strTag, strValue);
		}
		
	} // end for(;;) 

	// see if the file ended with no ending empty line
//	if (nGameIndex == 0 && pGameRecord)
	if (pGameRecord && (numTagsRead >= 1))
	{
		pGameRecord->AnalyzePlayRecord();

		if (pGameRecord->IsValid(isExportFile))  // NCR-PBNI added isExportFile
		{
			m_gameRecords.Add(pGameRecord);
			numGamesLoaded++;
			nGameIndex++;
		}
		//
		pGameRecord = NULL;
	}

	// if the file has > 1 game record, set game review mode
	if (nGameIndex > 1) 
	{
		m_bReviewingGame = TRUE;
		m_bGameReviewAvailable = TRUE;
	}

	// see if we have a dangling (invalid) game object
	if (pGameRecord)
		delete pGameRecord;

	// all done
	return TRUE;
}
//
//===============================================================================
//
// TryConvention()
//
// check if we can bid a takeout double here
//
BOOL CNegativeDoublesConvention::TryConvention(const CPlayer& player, 
											   const CConventionSet& conventions, 
											   CHandHoldings& hand, 
											   CCardLocation& cardLocation, 
											   CGuessedHandHoldings** ppGuessedHands,
											   CBidEngine& bidState,  
											   CPlayerStatusDialog& status)
{
	//
	// Negative doubles are made in the third position after
	// partner opens and RHO overcalls up to 2S.
	// The requirements for a negative doubles are:
	// 1: partner must have opened the bidding,
	// 2: we must either have passesed or not bid yet
	// 3: RHO must have overcalled at a level no higher than 2S, 
	// 4: have 4+ cards in each unbid major, (5+ at the 2-level), 
	// 5: holding 6+ points at the 1-level, or 11+ at the 2-level, and finally,
	// 6: don't have decent support for partner's suit

	// test conditions 1, 2, 3, and 5
	if ((bidState.m_bPartnerOpenedForTeam) && (bidState.m_numBidTurns <= 1) &&
		(bidState.nLHOBid <= BID_PASS) && (bidState.nRHOBid > BID_PASS)
		// NCR-145 Can't do NegDouble over Opening bid of Double 
		&& (bidState.nPartnersOpeningBid != BID_DOUBLE)
		// NCR-294 Can't do NegDbl over NT
		&& (bidState.nRHOSuit != NOTRUMP) 
		// NCR-116 split test into 2 parts depending on bid level
		&& (((bidState.nRHOBid <= BID_1S) && (bidState.fCardPts >= OPEN_PTS(6)))
		    // NCR-116 higher level takes more points
		    || ((bidState.nRHOBid <= BID_2S) && (bidState.fCardPts >= OPEN_PTS(11))))
		&& !ISBID(bidState.nPreviousBid))  // NCR test if we made a previous bid
	{
		 // passed the initial tests
	}
	else
	{
		return FALSE;
	}

	// test condition #6
	// if we can raise partner or shift over the opponent, 
	// don't bother with a negative double
	int nRHOBid = bidState.nRHOBid;
	int nRHOBidLevel = bidState.nRHOBidLevel;
	int nRHOSuit = bidState.nRHOSuit;
	//
	if (nRHOBidLevel == 1) 
	{
/*
		// see if we can raise partner at the 2-level
		if (pCurrConvSet->IsConventionEnabled(tidLimitRaises))
		{
			if ((bidState.numSupportCards >= 3) && (bidState.fPts >= OPEN_PTS(6)))
			{
				// we can raise partner at the 2-level, so forget the neg double
				return FALSE;
			}
			else if (bidState.numSupportCards >= 3) && (bidState.fPts >= OPEN_PTS(6)))
			{
				// likewise, w/o limit raises
				return FALSE;
			}
		}
*/
		if ((bidState.numSupportCards >= 3) &&
			(bidState.numSupportCards >= 3) && (bidState.fPts >= OPEN_PTS(6)))
		{
			// if we can raise partner at the 2-level, forget the neg double
			if (pCurrConvSet->IsConventionEnabled(tidLimitRaises) && 
						(bidState.fPts >= OPEN_PTS(11)) && (bidState.fPts < OPEN_PTS(13)))
				return FALSE;	// limit raise
			else if (!pCurrConvSet->IsConventionEnabled(tidLimitRaises) && 
						(bidState.fPts >= OPEN_PTS(13)) && (bidState.fPts < OPEN_PTS(17)))
				return FALSE;	// single raise
		}
		// check up to 2 suits
		for (int i=0;i<2;i++)
		{
			// see if we can switch to this suit
			int nSuit = hand.GetSuitsByPreference(i);
			if (bidState.IsSuitShiftable(nSuit) && (nSuit > nRHOSuit))
				return FALSE;
		}
	}
	//
	if (nRHOBidLevel == 2) 
	{
		// see if we can safely raise partner at the 2-level
		if ((bidState.numSupportCards >= 3) && (bidState.fPts >= OPEN_PTS(6)) && (bidState.nPartnersSuit > nRHOSuit))
		{
			// we can raise partner at the 2-level, so forget the neg double
			return FALSE;
		}
		// see if we can raise partner to the 3-level (either 11 or 13 pts)
		double nReqPts = pCurrConvSet->IsConventionEnabled(tidLimitRaises)? OPEN_PTS(11) : OPEN_PTS(13);
		if ((bidState.numSupportCards >= 4) && (bidState.fPts >= nReqPts))
		{
			// we can raise partner to the 3-level, so forget the neg double
			return FALSE;
		}
		// check up to 2 suits for a shift at the 2-level
		for (int i=0;i<2;i++)
		{
			// see if we can switch to this suit
			int nSuit = hand.GetSuitsByPreference(i);
			if (bidState.IsSuitShiftable(nSuit))
			{
				// we can shift to the suit, but see if we have the pts
				if ((nSuit < bidState.nPartnersSuit) && (bidState.fPts >= OPEN_PTS(10)))
					return FALSE;	// can shift to a lower suit at the 2-level
				else if ((nSuit > bidState.nPartnersSuit) && (bidState.fPts >= OPEN_PTS(19)))
					return FALSE;	// can (jump) shift to a higher suit at the 2-level
			}
		}
	}
	else if (nRHOBidLevel == 3) 
	{
		// opp. overcalled at 3-level; too high a level for a neg. double
		return FALSE;
	}

	// test condition 4
	// mark which majors are unbid
	int nMajorSuits[2] = { 1, 1 };
	if (bidState.nPartnersSuit == HEARTS)
		nMajorSuits[0] = 0;	// Hearts have been bid
	else if (bidState.nPartnersSuit == SPADES)
		nMajorSuits[1] = 0;	// spades have been bid
	//
	if (bidState.nRHOSuit == HEARTS)
		nMajorSuits[0] = 0;
	else if (bidState.nRHOSuit == SPADES)
		nMajorSuits[1] = 0;

	// if both majors have been bid, we can't use negative doubles
	if ((!nMajorSuits[0]) && (!nMajorSuits[1]))
		return FALSE;
	//
	if (bidState.nRHOBidLevel == 1)
	{
		// at the 1-level, need 4+ cards in each unbid major and 6+ pts
		if ( ((nMajorSuits[0]) && (hand.GetNumCardsInSuit(HEARTS) < 4)) || 
			 ((nMajorSuits[1]) && (hand.GetNumCardsInSuit(SPADES) < 4)) ||
			 (bidState.fPts < OPEN_PTS(6)))
			return FALSE;
	}
	else
	{
		// at the 2-level, need 5+ cards in each unbid major and 11+ pts
		if ( ((nMajorSuits[0]) && (hand.GetNumCardsInSuit(HEARTS) < 5)) || 
			 ((nMajorSuits[1]) && (hand.GetNumCardsInSuit(SPADES) < 5)) ||
			 (bidState.fPts < OPEN_PTS(11)))
			return FALSE;
	}

	//
	// finally, see if we have _too many_ points for a neg. double (19+)
	//
	if (bidState.fPts >= OPEN_PTS(19))
	{
//		status << "NEGDBLX! We have the holdings for a negative double, but our " &
//				  bidState.fPts & " points are too much\n";
		return FALSE;
	}

	//
	// we've now passed all the tests, so make the bid
	//
	if (bidState.nRHOBidLevel == 1)
		status << "NEGDBL1! With " & bidState.fPts & "/" & bidState.fPts & 
				  " points and 4 cards in the unbid majors, bid a negative double.\n";
	else
		status << "NEGDBL2! With " & bidState.fPts & "/" & bidState.fPts & 
				  " points and 5+ cards in the unbid majors, bid a negative double.\n";
	int nBid = BID_DOUBLE;
	bidState.SetBid(nBid);
//	bidState.SetConventionStatus(this, CONV_INVOKED);
	bidState.SetConventionStatus(this, CONV_FINISHED);
	return TRUE;
}
Example #8
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;
}
Example #9
0
void CBidDialog::UpdateBidDisplay(int nPos, int nBid, BOOL bPrompt, BOOL bTentative)
{
	int nTextID = IDC_BID_SOUTH + nPos;
	int nIconID = IDCI_BID_SOUTH + nPos;

	// see if we're using text for bids
	if (!UsingSuitSymbols() || !ISBID(nBid) || bTentative)
	{
		// show bid text
		GetDlgItem(nIconID)->ShowWindow(FALSE);
		GetDlgItem(nTextID)->ShowWindow(TRUE);
		CString strTemp;

		// show text
		if ((nPos == SOUTH) && (bPrompt))
		{
			SetDlgItemText(nTextID, "??");
		} 
		else if (nBid == -2)
		{
			SetDlgItemText(nTextID, "?");
		} 
		else if (nBid == -1) 
		{
			SetDlgItemText(nTextID, "");
		} 
		else if (bTentative)
		{
			strTemp = BidToShortString(nBid) + _T('?');
			SetDlgItemText(nTextID, (LPCTSTR)strTemp);
		}
		else 
		{
			// real bid
			strTemp = BidToShortString(nBid);
			SetDlgItemText(nTextID, (LPCTSTR)strTemp);
		}
		GetDlgItem(nTextID)->UpdateWindow();
	}
	else
	{
		// show bid icon
		GetDlgItem(nTextID)->ShowWindow(FALSE);
		GetDlgItem(nIconID)->ShowWindow(TRUE);
		CStatic* pStatic = (CStatic*) GetDlgItem(nIconID);
		if (ISBID(nBid))
		{
			int nSuit = (nBid-1) % 5;
			int nLevel = (nBid-1) / 5;
			pStatic->SetIcon(m_buttonIcons[nSuit][nLevel]);
		}
		else
		{
			pStatic->SetIcon(NULL);
		}
		//
		pStatic->UpdateWindow();
	}
/*
	CString strTemp;

	// show text
	if ((nPos == SOUTH) && (bPrompt))
	{
		SetDlgItemText(IDC_BID_SOUTH, "??");
	} 
	else if (nBid == -2)
	{
		SetDlgItemText(IDC_BID_SOUTH+nPos, "?");
	} 
	else if (nBid == -1) 
	{
		SetDlgItemText(IDC_BID_SOUTH+nPos, "");
	} 
	else if (bTentative)
	{
		strTemp = BidToShortString(nBid) + _T('?');
		SetDlgItemText(IDC_BID_SOUTH+nPos, (LPCTSTR)strTemp);
	}
	else 
	{
		// real bid
		strTemp = BidToShortString(nBid);

		// play sound if appropriate
		if (m_bSpeechEnabled)
		{
			CString strDir = theApp.GetValueString(tszProgramDirectory);
//			CString strPath = strDir +  _T("\\Sounds\\") + PositionToString(nPos) + strTemp + _T(".wav");
			CString strPath = strDir +  _T("\\Sounds\\") + strTemp + _T(".wav");
			CFile file;
			if (file.Open(strPath, CFile::modeRead))
			{
				file.Close();
				PlaySound(strPath, NULL, SND_SYNC | SND_NOSTOP | SND_NOWAIT);
			}
		}

		// show bid
		SetDlgItemText(IDC_BID_SOUTH+nPos, (LPCTSTR)strTemp);
	}
*/
}
//
//-----------------------------------------------------
//
// respond to partner's Michaels Cue Bid
//
BOOL CMichaelsCueBidConvention::RespondToConvention(const CPlayer& player, 
													const CConventionSet& conventions, 
													CHandHoldings& hand, 
													CCardLocation& cardLocation, 
												    CGuessedHandHoldings** ppGuessedHands,
													CBidEngine& bidState,  
													CPlayerStatusDialog& status)
{
	// first see if another convention is active
	if ((bidState.GetActiveConvention() != NULL) &&
					(bidState.GetActiveConvention() != this))
		return FALSE;

	//
	// make a responding bid
	//
	int nPartnersBid = bidState.nPartnersBid;
	int nPartnersBidLevel = bidState.nPartnersBidLevel;
	int nPartnersSuit = bidState.nPartnersSuit;
	int nPartnersPrevSuit = bidState.nPartnersPrevSuit;
	//
	int nBid, nSuit;
	double fPts = bidState.fPts;
	double fCardPts = bidState.fCardPts;

	// 
	// see what round this is
	//
	int nStatus = bidState.GetConventionStatus(this);
	if (nStatus == CONV_INACTIVE)
	{
		//
		// Bidding in response to partner's Michael's bid? check requirements
		//
		// the identifying marks of a Michaels bid are:
		// 1: we must not have bid yet
		// 2: LHO must have bid a suit at the 1 level, and 
		// 3: partner overcalled LHO's suit at the 2 level
		int nLastValidBid = pDOC->GetLastValidBid();

		// apply tests #1, 2, and 3
		int nOpeningBid = pDOC->GetOpeningBid();
		int nOpeningBidder = pDOC->GetOpeningBidder();
		BOOL bLHOMajor = ISMAJOR(nOpeningBid);
		if (ISBID(nOpeningBid) && (GetPlayerTeam(nOpeningBidder) != player.GetTeam()) &&
			 ((nOpeningBid >= BID_1C) && (nOpeningBid <= BID_1S)) &&
			  (nPartnersSuit == bidState.nLHOSuit) && (nPartnersBidLevel == 2) &&
			  (bidState.m_numBidsMade == 0) )
		{
			//
			status << "MCLR10! Partner has made a Michaels Cue bid of " & BTS(nPartnersBid) &
					  ", indicating 5/5 length in " &
					  (bLHOMajor? ((bidState.nLHOSuit == HEARTS)? "Spades and a minor" : "Hearts and a minor") : "the majors") & ".\n";
		}
		else
		{
			return FALSE;
		}

		// did partner bid a minor, indicating both majors?
		if (ISMINOR(nPartnersSuit))
		{
			// Pard has both majors -- pick the preferred one
			nSuit = bidState.PickSuperiorSuit(HEARTS, SPADES);
			if (hand.GetNumCardsInSuit(nSuit) < 3)
			{
				// should have at least 3 trumps
				int nOtherSuit = (nSuit == HEARTS)? SPADES : HEARTS;
				if (hand.GetNumCardsInSuit(nOtherSuit) >= 3)
					nSuit = nOtherSuit;
			}
		}
		else if (nPartnersSuit == HEARTS)
		{
			// pard has Spades + a minor
			// see if Spades are decent (3-card support)
//			if ((hand.GetNumCardsInSuit(SPADES) >= 3) && (hand.GetSuitStrength(SPADES) >= SS_MODERATE_SUPPORT))
			if (hand.GetNumCardsInSuit(SPADES) >= 3)
			{
				// fine, go with Spades
				nSuit = SPADES;
			}
			else 
			{
				// Spades are too weak; look for a minor
				if ((hand.GetSuitStrength(CLUBS) >= SS_MODERATE_SUPPORT) || (hand.GetSuitStrength(DIAMONDS) >= SS_MODERATE_SUPPORT))
					nSuit = NOTRUMP;
				else
					nSuit = SPADES;	// minors are no good either, so go with Spades
			}
		}
		else 
		{
			// pard has Hearts + a minor
			// see if Hearts are decent (3-card support)
//			if ((hand.GetNumCardsInSuit(HEARTS) >= 3) && (hand.GetSuitStrength(HEARTS) >= SS_MODERATE_SUPPORT))
			if (hand.GetNumCardsInSuit(HEARTS) >= 3)
			{
				// fine, go with Hearts
				nSuit = HEARTS;
			}
			else 
			{
				// Spades are too weak; look for a minor
				if ((hand.GetSuitStrength(CLUBS) >= SS_MODERATE_SUPPORT) || (hand.GetSuitStrength(DIAMONDS) >= SS_MODERATE_SUPPORT))
					nSuit = NOTRUMP;
				else
					nSuit = HEARTS;	// minors are no good either, so go with Hearts
			}
		}

		// now adjust point count
		if (ISSUIT(nSuit))
		{
			bidState.SetAgreedSuit(nSuit);
			fPts = bidState.fAdjPts = hand.RevalueHand(REVALUE_DECLARER, nSuit, TRUE);
		}
		// partner may have 6-11 OR 17+ pts; assume it's a weak hand
		bidState.AdjustPartnershipPoints(6, 11);

		// and make a responding bid
		CString strChoices = ISMINOR(nPartnersSuit)? "the two majors" : 
					(nPartnersSuit == HEARTS)? "Spades and a minor" : "Hearts and an unknown minor";
		int numTrumps = ISSUIT(nSuit)? hand.GetNumCardsInSuit(nSuit) : 0;

		// set initial convention status to finished
		bidState.SetConventionStatus(this, CONV_FINISHED);

		// see if we need to look at the minor
		if (nSuit == NOTRUMP)
		{
			// bid 2NT to ask for the minor
			nBid = BID_2NT;
			if (nBid > nLastValidBid)
			{
				if (nPartnersSuit == HEARTS)
					status << "MCLR12! Given a choice between a " & hand.GetNumCardsInSuit(SPADES) &
							  "-card Spade suit and an unknown minor, we're forced to ask for the minor by bidding " & BTS(nBid) & ".\n";
				else
					status << "MCLR12! Given a choice between a " & hand.GetNumCardsInSuit(HEARTS) &
							  "-card Heart suit and an unknown minor, we're forced to ask for the minor by bidding " & BTS(nBid) & ".\n";
				// this convention will go another round
				bidState.SetConventionStatus(this, CONV_RESPONDED_ROUND1);
			}
			else
			{
				nBid = BID_PASS;
				status << "MCLR13! We'd like to bid 2NT to ask for partner's minor, but we can't do so after RHO's interference, so we have to pass.\n";
			}
		}
		else if ((numTrumps >= 5) && (bidState.m_fMinTPPoints <= PT_COUNT(20)) &&
			ISMAJOR(nSuit) && (MAKEBID(nSuit, 4) > nLastValidBid))
		{
			// make a preemptive bid if possible
			nBid = MAKEBID(nSuit, 4);
			status << "MCLR15! With " & numTrumps & " " & STS(nSuit) & " and a total of " & 
					  bidState.m_fMinTPPoints & "-" & bidState.m_fMaxTPPoints &
					  " pts in the partnership, make a shutout bid in " & STS(nSuit) & 
					  " by jumping to " & BTS(nBid) & ".\n";
		}
		else if (bidState.m_fMinTPPoints <= PT_COUNT(21))
		{
			// respond at the 2-level
			nBid = bidState.GetCheapestShiftBid(nSuit, nLastValidBid);
			if (BID_LEVEL(nBid) == 2)
			{
				status << "MCLR20! Given a choice between " & strChoices & 
						   ", respond to partner's Michaels with the preferred " & 
						   STSS(nSuit) & " suit with a bid of " & BTS(nBid) & ".\n";
			}
			else
			{
				nBid = BID_PASS;
				status << "MCLR21! After RHO interference, we don't have the points to go to the 3-level in response to partner's Michaels, so pass.\n";
			}
		}
		else if (bidState.m_fMinTPPoints <= PT_COUNT(24))
		{
			// bid at the 3-level
			nBid = MAKEBID(nSuit, 3);
			if (nBid > nLastValidBid)
			{
				status << "MCLR24! With a total of " & bidState.m_fMinTPPoints & "-" & bidState.m_fMaxTPPoints &
						   " pts in the partnership and a choice between " & strChoices &
						   ", invite game in " & STS(nSuit) & " by jumping to " & BTS(nBid) & ".\n";
			}
			else
			{
				nBid = BID_PASS;
				status << "MCLR25! After RHO interference, we don't have the points to go to the 4-level in response to partner's Michaels, so pass.\n";
			}
		}
		else if (ISMINOR(nSuit) && (bidState.m_fMinTPPoints <= PT_COUNT(27)))
		{
			// with 25+ pts, bid game
			nBid = bidState.GetGameBid(nSuit);
			if (nBid > nLastValidBid)
			{
				status << "MCLR27! With a total of " & bidState.m_fMinTPPoints & "-" & bidState.m_fMaxTPPoints &
						   " pts in the partnership and a choice between " & strChoices & 
						   ", jump to the 4-level in " & STS(nSuit) & " with a bid of " & BTS(nBid) & ".\n";
			}
			else
			{
				nBid = BID_PASS;
				status << "MCLR28! After RHO interference, we don't have the points to go to the 5-level in response to partner's Michaels, so pass.\n";
			}
		}
		else
		{
			// with 25+ pts in a major, or 28+ pts in a minor, bid game
			nBid = bidState.GetGameBid(nSuit);
			if (nBid > nLastValidBid)
			{
				status << "MCLR30! With a total of " & bidState.m_fMinTPPoints & "-" & bidState.m_fMaxTPPoints &
						   " pts in the partnership and a choice between " & strChoices & 
						   ", jump to game in " & STS(nSuit) & " at " & BTS(nBid) & ".\n";
			}
			else
			{
				nBid = BID_PASS;
				status << "MCLR31! After RHO interference, we don't want to bid past game, so pass.\n";
			}
		}

		// done!
		bidState.SetBid(nBid);
		return TRUE;

	}
	else if (nStatus == CONV_RESPONDED_ROUND1)
	{
		//
		// round 2 -- we must've bid 2NT last time to ask for partner's minor
		//

		// see if partner cue bid the enemy suit again
		if (nPartnersSuit == nPartnersPrevSuit)
		{
			// partner has 17+ pts
			bidState.AdjustPartnershipPoints(OPEN_PTS(17), MIN(17,40 - bidState.fCardPts));

			// bid 4NT to ask for the minor again
			if (fPts >= PT_COUNT(15))
			{
				// else make a natural game bid
				nBid = BID_4NT;
				status << "MCLR35! Partner cue bid the enemy suit again, indicating a strong Michaels opening hand with " &
						   OPEN_PTS(17) & "+ pts; so with " & 
						   bidState.m_fMinTPPoints & "-" & bidState.m_fMaxTPPoints &
						   " pts in the partnership, ask for the other minor by bidding " & BTS(nBid) & ".\n";
				bidState.SetConventionStatus(this, CONV_RESPONDED_ROUND2);
			}
			else
			{
				// else make a natural 3NT game bid
				nBid = BID_3NT;
				status << "MCLR36! Partner cue bid the enemy suit again, indicating a strong Michaels opening hand with " &
						   OPEN_PTS(17) & "+ pts; but with " & 
						   bidState.m_fMinTPPoints & "-" & bidState.m_fMaxTPPoints &
						   " pts in the partnership, stop at game with a natural bid of " & BTS(nBid) & ".\n";
				bidState.SetConventionStatus(this, CONV_FINISHED);
			}
			// done
			bidState.SetBid(nBid);
			return TRUE;
		}

		// see if partner's bid is valid
		if (!ISMINOR(nPartnersSuit))
		{
			status << "MCLR40! After his opening Michaels Cue Bid, partner did not respond properly to our 2NT minor suit inquiry, so michaels is off.\n";
			bidState.SetConventionStatus(this, CONV_ERROR);
			return FALSE;
		}

		// see if we can live with partner's minor
		int nAgreedSuit;
		if (hand.GetNumCardsInSuit(nPartnersSuit) >= 3)
		{
			// stick with the minor
			status << "4MCLR41! Since we have " & hand.GetNumCardsInSuit(nPartnersSuit) & 
					  " cards in the " & STSS(nPartnersSuit) & " suit, choose that suit for our response.\n";
			nAgreedSuit = nPartnersSuit;
		}
		else
		{
			// minor's not so great; select the better of the minor or the major
			nAgreedSuit = bidState.PickSuperiorSuit(nPartnersSuit, bidState.nPartnersPrevSuit);
			if (nAgreedSuit == nPartnersSuit)
				status << "4MCLR42! The " & STSS(nPartnersSuit) & " suit isn't great, but it's better than " &
						   STS(bidState.nPartnersPrevSuit) & ", so choose that suit for our response.\n";
			else
				status << "4MCLR43! The " & STSS(nPartnersSuit) & " suit is poor, so pick the major suit ("& 
						   STS(bidState.nPartnersPrevSuit) & ") for our response.\n";
			bidState.SetAgreedSuit(bidState.PickSuperiorSuit(nPartnersSuit, bidState.nPartnersPrevSuit));
		}

		// recalc points as dummy
		bidState.SetAgreedSuit(nAgreedSuit);
		fPts = bidState.fAdjPts = hand.RevalueHand(REVALUE_DECLARER, nAgreedSuit, TRUE);
		bidState.AdjustPartnershipPoints();

		// select the bid level
		if (ISMINOR(nAgreedSuit))
		{
			// Clubs or Diamonds
			if (bidState.m_fMinTPPoints <= PTS_MINOR_GAME-6)	// <= 22
				nBid = BID_PASS;
			else if (bidState.m_fMinTPPoints <= PTS_MINOR_GAME-4)	// <= 24
				nBid = MAKEBID(nPartnersBid, 4);
			else 
				nBid = MAKEBID(nPartnersBid, 5);	// go for game
			//
			if (nBid == BID_PASS)
				status << "MCLR45! Partner showed his minor to be " & STS(nPartnersSuit) & 
						  ", which we can support with " & hand.GetNumCardsInSuit(nPartnersSuit) &
						  " trumps, but with only " & bidState.m_fMinTPPoints & "-" & bidState.m_fMaxTPPoints &
						  " pts in the partnership, we have to pass.\n";
			else
				status << "MCLR46! Partner showed his minor to be " & STS(nPartnersSuit) & 
						  ", which we can support with " & hand.GetNumCardsInSuit(nPartnersSuit) &
						  " trumps, so with " & bidState.m_fMinTPPoints & "-" & bidState.m_fMaxTPPoints &
						  " pts in the partnership, we bid " & BTS(nBid) & ".\n";
		}
		else
		{
			// sticking with the major (though not a very good one!)
			// sign off at the 3-level or go to game
			if (bidState.m_fMinTPPoints < PTS_MAJOR_GAME)	// < 25
				nBid = MAKEBID(nPartnersBid, 3);
			else	
				nBid = MAKEBID(nPartnersBid, 4);
			//
			if (BID_LEVEL(nBid) == 3)
				status << "MCLR47! With " & hand.GetNumCardsInSuit(nAgreedSuit) & 
						  "-card support for partner's " & STS(nAgreedSuit) & 
						  ", and with only " & bidState.m_fMinTPPoints & "-" & bidState.m_fMaxTPPoints &
						  " pts in the partnership, we have to pass.\n";
			else
				status << "MCLR47! With " & hand.GetNumCardsInSuit(nAgreedSuit) & 
						  "-card support for partner's " & STS(nAgreedSuit) & 
						  ", and with " & bidState.m_fMinTPPoints & "-" & bidState.m_fMaxTPPoints &
						  " pts in the partnership, we can go to game at " & BTS(nBid) & ".\n";
		}

		// done!
		bidState.SetBid(nBid);
		bidState.SetConventionStatus(this, CONV_FINISHED);
		return TRUE;
	}
	else if (nStatus == CONV_RESPONDED_ROUND2)
	{
		//
		// round 3 -- we must've bid 4NT last time to ask for partner's minor
		//            after partner's second Michaels cue bid
		//

	}


	//
	return FALSE;
}