Example #1
0
void CHoldUp::Init()
{
	CPlay::Init();
	// form name & description
	m_strName.Format("%s Hold up", STSS(m_nSuit));
	m_strDescription.Format("Hold up a round of %s", STS(m_nSuit));
}
Example #2
0
void vacfunc(real_T *dx, real_T *xms, SimStruct *S)
{
    real_T mvs[NM], x[NS];
#ifdef DEBUG
    debug("vacfunc entered.\n");
#endif
// #ifdef DEBUG
    // debug("Time:%f (in minutes: %f) entered.\n",GETTIME(S), GETTIME(S)*60);
// #endif
    GETXMV(XMV,S);
    GETIDV(IDV,S);
    VAModel(dx, x, mvs, xms, STS(S), XMV, GETTIME(S)*60, 0, IDV);
#if defined(CONTINUOUS_STATES)
    MULTIPLY(dx, NS, 60);
#elif defined(DISCRETE_STATES)
    DIVIDE(dx, NS, 180);
#endif
#ifdef DEBUG
    debug("vacfunc left.\n");
#endif
}
//
//-----------------------------------------------------
//
// respond to partner's negative double
//
BOOL CNegativeDoublesConvention::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;

	//
	// Bidding in response to partner's negative bid? check requirements
	//
	// the identifying marks of a negative double are:
	// 1: this must be round #1 or 2
	// 2: we must have opened bidding, and 
	// 3: LHO must have bid over our initial bid, up to 2S
	//

	int nBid;
	int nPartnersBid = bidState.nPartnersBid;
	int nMajorSuits[2] = { 1, 1 };
	if (bidState.nPreviousSuit == HEARTS)
		nMajorSuits[0] = 0;
	else if (bidState.nPreviousSuit == SPADES)
		nMajorSuits[1] = 0;
	//
	if (bidState.nLHOSuit == HEARTS)
		nMajorSuits[0] = 0;
	else if (bidState.nLHOSuit == SPADES)
		nMajorSuits[1] = 0;

	// apply tests #1, 2, and 3
	if ( (nPartnersBid == BID_DOUBLE) &&
		 ((bidState.nRound == 0) || (bidState.nRound == 1)) && 
		 (bidState.m_bOpenedBiddingForTeam) && 
		 (bidState.nLHOBid > BID_PASS) && (bidState.nLHOBid <= BID_2S)
		 // NCR-195 bid must be suit
		 && ISSUIT(BID_SUIT(bidState.nLHOBid))
		 )
	{
		//
		status << "NEGDR2! Partner has bid a negative double, indicating 4+ cards in the unbid majors " &
				  ((nMajorSuits[0] && nMajorSuits[1])? "(Hearts and Spades)" :
					nMajorSuits[0]? "(Hearts)" : "(Spades)") & ".\n";
	}
	else
	{
		return FALSE;
	}

	//
	// estimate partner's strength
	//
	if (bidState.nLHOBidLevel == 1)
	{
		// 6-9 pts for a neg dbl the 1-level  (NCR TryConvention uses 19 max???)
		bidState.m_fPartnersMin = OPEN_PTS(6);
		bidState.m_fPartnersMax = Min(OPEN_PTS(19),40 - bidState.fCardPts); // NCR changed 9 to 19
		bidState.m_fMinTPPoints = bidState.fPts + bidState.m_fPartnersMin;
		bidState.m_fMaxTPPoints = bidState.fPts + bidState.m_fPartnersMax;
		bidState.m_fMinTPCPoints = bidState.fCardPts + bidState.m_fPartnersMin;
		bidState.m_fMaxTPCPoints = bidState.fCardPts + bidState.m_fPartnersMax;
		status << "2NEGDR8! Partner's negative double indicates " &  
				  bidState.m_fPartnersMin & "-" & bidState.m_fPartnersMax &
				  " points, for a total in the partnership of " &
				  bidState.m_fMinTPPoints & "-" & bidState.m_fMaxTPPoints & 
				  " points.\n";
	}
	else
	{
		// 11-18 pts for a neg double at the 2 level
		bidState.m_fPartnersMin = OPEN_PTS(11);
		bidState.m_fPartnersMax = Min(OPEN_PTS(18),40 - bidState.fCardPts);
		bidState.m_fMinTPPoints = bidState.fPts + bidState.m_fPartnersMin;
		bidState.m_fMaxTPPoints = bidState.fPts + bidState.m_fPartnersMax;
		bidState.m_fMinTPCPoints = bidState.fCardPts + bidState.m_fPartnersMin;
		bidState.m_fMaxTPCPoints = bidState.fCardPts + bidState.m_fPartnersMax;
		status << "2NEGDRT8! Partner's negative double indicates 11+ pts, for a total in the partnership of " &
				  bidState.m_fMinTPPoints & "-" & bidState.m_fMaxTPPoints & 
				  " points.\n";
	}

	//
	// and respond to the bid
	//
	int nSuit;
	double fCardPts = bidState.fCardPts;
	double fPts = bidState.fPts;
	int nLHOBid = bidState.nLHOBid;
	int nRHOBid = bidState.nRHOBid;

	//
	// with support for one or the other major, raise
	// but discount the majors already bid by us or LHO
	//
	int numHearts = hand.GetNumCardsInSuit(HEARTS);
	int numSpades = hand.GetNumCardsInSuit(SPADES);

	// gotta beat RHO's bid if possible
	int nTopBid = nLHOBid;
	if ((nRHOBid > BID_PASS) && (nRHOBid != BID_REDOUBLE))
		nTopBid = nRHOBid;
	// see if the majors are available
	if ( (nMajorSuits[0] && nMajorSuits[1]) &&
		 ((numHearts >= 3) || (numSpades >= 3)) )
	{
		// both majors are available, so pick the better one
		int nSuit = bidState.PickSuperiorSuit(HEARTS,SPADES);
		nBid = bidState.GetCheapestShiftBid(nSuit, nTopBid);
		// see if the bid is affordable
		if (bidState.IsBidSafe(nBid))
		{
			status << "NEGDTR20! With " & bidState.m_fMinTPPoints & " pts in the partnership and " &
				      " both majors available in response to the negative double, go with the " &
					  hand.GetNumCardsInSuit(nSuit) & "-card " & STSS(nSuit) & " suit and bid " & 
					  BTS(nBid) & ".\n";
			bidState.SetBid(nBid);
		}
		else
		{
			status << "NEGDTR21! We have both majors avaialblem but with " & bidState.m_fMinTPPoints & 
					  " pts in the partnership, we do not have enough points to bid either suit and have to pass.\n";
			bidState.SetBid(BID_PASS);
		}
		bidState.SetConventionStatus(this, CONV_FINISHED);
		return TRUE;
	}
	else if ( ((nMajorSuits[0]) && (numHearts >= 3)) ||
			  ((nMajorSuits[1]) && (numSpades >= 3)) )
	{
		// bid the suit
		if ((nMajorSuits[0]) && (numHearts >= 3))
			nSuit = HEARTS;
		else
			nSuit = SPADES;
		nBid = bidState.GetCheapestShiftBid(nSuit, nTopBid);
		// see if the bid is affordable
		double fAdj = bidState.fAdjPts; // NCR-717 theApp.GetBiddingAgressiveness()*1.5; // NCR change test amt?
		if (bidState.IsBidSafe(nBid, fAdj)) // NCR adjust???
		{
			status << "NEGDTR30! With " & bidState.m_fMinTPPoints & " pts in the partnership and " &
				      hand.GetNumCardsInSuit(nSuit) & " cards available in " &
					  STS(nSuit) &", bid " & BTS(nBid) & ".\n";
			bidState.SetBid(nBid);
		}
		else
		{
			status << "NEGDTR31! We have " & hand.GetNumCardsInSuit(nSuit) & " cards in the " & 
					  STSS(nSuit) & " suit, but with only " & bidState.m_fMinTPPoints & 
					  " pts in the partnership, we can't go any higher.\n";
			bidState.SetBid(BID_PASS);
		}
		bidState.SetConventionStatus(this, CONV_FINISHED);
		return TRUE;
	}

	//
	// we have no majors available, so bid NT if possible
	//
	if (bidState.BidNoTrumpAsAppropriate(FALSE))
	{
		bidState.SetConventionStatus(this, CONV_FINISHED);
		return TRUE;
	}

	// else bid something, anything
	nSuit = bidState.GetRebidSuit(bidState.nPreviousSuit);
	if(nSuit == NONE) { //NCR test for no rebidable suit return
		nBid = BID_1NT;  // NCR Hardcoded ??? vs get cheapest
	}else{
		nBid = bidState.GetCheapestShiftBid(nSuit, nTopBid);
	}
	// NCR-415 Test if safe bid
	if (!bidState.IsBidSafe(nBid, bidState.fDistPts)  // NCR-592 set adj to dist pts
		&& (bidState.nRHOBid > BID_PASS) ) // NCR-637 Only if RHO bid
	{
		nBid = BID_PASS;
		status << "NEGDTR36! With a total of " & bidState.m_fMinTPPoints & "-" & bidState.m_fMaxTPPoints
				  & " pts in the partnership, we cannot safely bid further, so pass.\n";
	}  // end NCR-415
	else
	{
		if (!ISMAJOR(nSuit))
			status << "NEGDTR40! Unfortunately we don't have a major to respond with, so bid " & BTS(nBid) & ".\n";
		else
			status << "NEGDTR41! Our best response is " & BTS(nBid) & ".\n";
	}
	bidState.SetBid(nBid);
	bidState.SetConventionStatus(this, CONV_FINISHED);
	return TRUE;
} 
Example #4
0
//
// Perform()
//
PlayResult CHoldUp::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);
	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;
	}

	// a holdup is simple -- discard instead of winning
	switch(nOrdinal)
	{
		case 0:
			// can't hold up here
			m_nStatusCode = PLAY_INACTIVE;
			return PLAY_POSTPONE;

		case 1:
			if (bPlayingInHand) 
				pPlayCard = playerHand.GetDiscard();
			else
				pPlayCard = dummyHand.GetDiscard();
			status << "PLHLD04! Hold up a round of " & STS(m_nSuit) & 
					  " and discard the " & pPlayCard->GetFaceName() & " from " &
					  (bPlayingInHand? "hand" : "dummy") & ".\n";
			m_nStatusCode = PLAY_IN_PROGRESS;
			break;

		case 2:
			// can't hold up here
			m_nStatusCode = PLAY_INACTIVE;
			return PLAY_POSTPONE;

		case 3:
			// complete the hold-up
			if (m_nStatusCode != PLAY_IN_PROGRESS)
				return PLAY_INACTIVE;
			if (bPlayingInHand) 
				pPlayCard = playerHand.GetDiscard();
			else
				pPlayCard = dummyHand.GetDiscard();
			status << "PLHLD08! Finish the hold-up and discard the " & 
					  pPlayCard->GetFaceName() & " from " & (bPlayingInHand? "hand" : "dummy") & ".\n";
			m_nStatusCode = PLAY_COMPLETE;
			break;
	}

	// done
	ASSERT(pPlayCard->IsValid());
	return m_nStatusCode;
}
Example #5
0
CString CHoldUp::GetFullDescription()
{
	return FormString("Hold up a round of %s.",STS(m_nSuit));
}
//
//-----------------------------------------------------
//
// 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;
} 
//
// GetMinCardsInSuit()
//
// returns the minimum number of cards a player currently holds in a suit
//
int CPlayEngine::GetMinCardsInSuit(int nPlayer, int nSuit) const
{
	VERIFY((nPlayer >= 0) && (nPlayer <= 3) && ISSUIT(nSuit));

	// see if the hand's cards have all been identified
	CGuessedSuitHoldings& suit = m_ppGuessedHands[nPlayer]->GetSuit(nSuit);
	if (suit.AreAllCardsIdentified())
		return suit.GetNumMinRemainingCards();

	// else see if the player is dummy & his cards are visible
	if (nPlayer == pDOC->GetDummyPosition() && pDOC->IsDummyExposed())
	{
		CHandHoldings& hand = pDOC->GetDummyPlayer()->GetHand();
		return hand.GetNumCardsInSuit(nSuit);
	}

	// the initial minimum is of course 0
	int nMin = 0;

	// adjust the minimum only if everyone but ourselves (and the player)
	// has shown out, and there are still cards outstanding
	BOOL bAllShownOut = TRUE;
	int nOurPos = m_pPlayer->GetPosition();
	for(int nPos=0;nPos<4;nPos++)
	{
		if ((nPos == nOurPos) || (nPos == nPlayer))
			continue;
		if (!m_ppGuessedHands[nPos]->IsSuitShownOut(nSuit))
		{
			// someone may still have cards left
			bAllShownOut = FALSE;
			break;
		}
	}

	// see if the two other players have shown out
	if (bAllShownOut)
	{
		// see if the number of suit cards played so far, plus the suit
		// cards we have remaining, add up to to less than 13
		int numCardsPlayed = 0;
		// count the cards that have been played in the suit
		for(int i=0;i<4;i++)
			numCardsPlayed += m_ppGuessedHands[i]->GetSuit(nSuit).GetNumCardsPlayed();
		// add the suit cards remaining in our own hand
		numCardsPlayed += m_pHand->GetSuit(nSuit).GetNumCards();
		if (numCardsPlayed < 13)
		{
			// the player must have the remaining cards
			nMin = 13 - numCardsPlayed;
			// take this opportunity to update the player's info
			// mark the player as having the missing cards
			CSuitHoldings  missingCards;
			int nCount = GetOutstandingCards(nSuit, missingCards);
			VERIFY(nCount == nMin);
			CGuessedHandHoldings* pHand = m_ppGuessedHands[nPlayer];
			for(int j=0;j<nCount;j++)
			{
				CGuessedCard* pGuessedCard = new CGuessedCard(missingCards[j],	// card
															  TRUE,				// still outstanding
															  nPlayer,			// location
															  1.0);				// known with certainty
				*pHand << pGuessedCard;
			}
			// update status
			suit.MarkAllCardsIdentified();
			CPlayerStatusDialog& status = *m_pStatusDlg;
			status << "4PLEMN5! " & PositionToString(nPlayer) &
					  " is now known to hold the remaining " & 
					  missingCards.GetNumCards() & " " & STS(nSuit) & 
					  " (" & missingCards.GetHoldingsString() & ").\n";
			// and update counts
			suit.SetNumOriginalCards(nMin + m_ppGuessedHands[nPlayer]->GetSuit(nSuit).GetNumCardsPlayed());
			suit.SetNumRemainingCards(nMin);
			suit.SetNumLikelyCards(nMin);
			suit.SetNumMinRemainingCards(nMin);
			suit.SetNumMaxRemainingCards(nMin);
		}
	}

	// done
	return nMin;
}
//
//---------------------------------------------------------------
//
// TryCueBid()
//
BOOL CCueBidConvention::TryCueBid(CHandHoldings& hand, CBidEngine& bidState,  CPlayerStatusDialog& status)
{
	// check basic requirements
	if (bidState.m_nAgreedSuit == NONE)
		return FALSE;

	// don't make a cue bid if we're already done with it 
	int nStatus = bidState.GetConventionStatus(this);
	if (nStatus != CONV_INACTIVE)
		return FALSE;

	// get adjusted point count as declarer
	// NCR BIG PROBLEM HERE - This changes a global variable. The changes are now always wanted ???
	bidState.fAdjPts = hand.RevalueHand(REVALUE_DECLARER, bidState.m_nAgreedSuit, TRUE);
	bidState.m_fMinTPPoints = bidState.fAdjPts + bidState.m_fPartnersMin;
	bidState.m_fMaxTPPoints = bidState.fAdjPts + bidState.m_fPartnersMax;
	bidState.m_fMinTPCPoints = bidState.fCardPts + bidState.m_fPartnersMin;
	bidState.m_fMaxTPCPoints = bidState.fCardPts + bidState.m_fPartnersMax;

	//
	// try a cue bid only if we have an interest in slam 
	// 
	if (bidState.m_fMinTPPoints < 30)
		return FALSE;

	// also, we shouldn't use cue bid if we have all four aces
	if (bidState.numAces == 4)
		return FALSE;

	// or if we're already at a slam level
	if (bidState.nPartnersBidLevel >= 6)
		return FALSE;
	int nLastBid = pDOC->GetLastValidBid();
	if (nLastBid >= bidState.GetGameBid(BID_SUIT(nLastBid)))
		return FALSE;

	// special test -- dont' cue bid if partner just raised a suit that we
	// shifted to artificially
	if ((bidState.nPartnersSuit == bidState.nPreviousSuit) && 
				( (ISSUIT(bidState.m_nAgreedSuit) && (bidState.nPreviousSuit != bidState.m_nAgreedSuit)) ||
				  (ISSUIT(bidState.m_nIntendedSuit) && (bidState.nPreviousSuit != bidState.m_nIntendedSuit)) ) )
		return FALSE;


	//
	// see what stage we're at
	//
	if (nStatus == CONV_INACTIVE)
	{
		//
		// showing first round controls 
		//
//		bidState.SetConventionStatus(this, CONV_INVOKED_ROUND1);
		// find cheapest ace
		int nBid;
		int nAgreedSuit = bidState.m_nAgreedSuit;
		int nSuit = GetCheapestAce(hand, nAgreedSuit);

		// 
		if ((nSuit != bidState.m_nAgreedSuit) && (nSuit != bidState.nPartnersSuit))
		{
			// found a suit to cue bid
			// the bid must be at a level that commits the partnership to game
			// i.e., for a major, it must be > 3 of the suit; for a minor, > 4
			nBid = bidState.GetCheapestShiftBid(nSuit);
			int nBidLevel = BID_LEVEL(nBid);
			// see if the bid is too high to qualify as a cue bid
		    if ( (ISMAJOR(nAgreedSuit) && (nBidLevel >= 5)) ||
			     (ISMINOR(nAgreedSuit) && (nBidLevel >= 6)) )
				return FALSE;
			// else if it's too low, adjust it upwards
		    if ( (ISMAJOR(nAgreedSuit) && (nBid < MAKEBID(nAgreedSuit,3))) ||
			     (ISMINOR(nAgreedSuit) && (nBid < MAKEBID(nAgreedSuit,4))) )
				nBid += 5;
			// alternatively, see if the bid is too high
			if (nBid > bidState.GetGameBid(nAgreedSuit))
				return FALSE;
			status << "CUET10! With " & bidState.m_fMinTPPoints & 
					  "+ pts and possible slam aspirations, make a cue bid, showing the cheapest ace (" & 
					  STS(nSuit) & ") with a bid of " & BTS(nBid) & ".\n";
			bidState.SetBid(nBid);
			bidState.SetConventionStatus(this, CONV_INVOKED_ROUND1);
			return TRUE;
		}
		else
		{
			// either we don't have any aces, or the ace is in the trump suit
			// either way, we can't make a cue bid with this holding
			return FALSE;
		}
	}
	else if (nStatus == CONV_INVOKED_ROUND1)
	{
		//
		// showing second round controls, necesary if we want to proceed to a grand slam
		//
		bidState.SetConventionStatus(this, CONV_INVOKED_ROUND2);
		// find cheapest king or void suit
		int nSuit = GetCheapestKingOrVoid(hand, bidState.m_nAgreedSuit);
		int nPartnersBid = bidState.nPartnersBid;
		// 
		if (nSuit != bidState.m_nAgreedSuit) 
		{
			// found a suit to cue bid
			int nBid = bidState.GetCheapestShiftBid(nSuit);
			status << "CUET20! Make a second-round cue bid, showing the cheapest " &
					  ((hand.GetSuitLength(nSuit) == 0)? "void suit" : "king") &
					  " (in " & STS(nSuit) & ") with a bid of " & BTS(nBid) & ".\n";
			bidState.SetBid(nBid);
			bidState.SetConventionStatus(this, CONV_INVOKED_ROUND2);
			return TRUE;
		}
		else
		{
			// either we don't have any second-round control to show,
			// so stop cue bidding and return to the trump suit
			int nBid = bidState.GetCheapestShiftBid(bidState.m_nAgreedSuit);
			status << "CUET24! With no second-round controls to cue bid, we have to return to the trump suit at a bid of " &
					  BTS(nBid) & ".\n";
			bidState.SetBid(nBid);
			bidState.SetConventionStatus(this, CONV_INVOKED_ROUND2);
			return TRUE;
		}
	}
	else if (nStatus == CONV_INVOKED_ROUND2)
	{
		// both we and partner have shown first and second-round controls, so
		// it;s time to put up or shut up
	}
	else
	{	
		// error!
		AfxMessageBox("Error while attempting cue bid!");
		bidState.SetConventionStatus(this, CONV_ERROR);
	}
	//
	return TRUE;
}
//
//---------------------------------------------------------------
//
// RespondToConvention()
//
BOOL CCueBidConvention::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() &&
							(bidState.GetActiveConvention() != this))
		return FALSE;

	// basic test -- see if we had agreed on a suit last time
	if (bidState.m_nAgreedSuit == NONE)
		return FALSE;

	// get status
	int nStatus = bidState.GetConventionStatus(this);

	//
	int nPartnersBid = bidState.nPartnersBid;
	int nPartnersBidLevel = bidState.nPartnersBidLevel;
	int nPartnersSuit = bidState.nPartnersSuit;
	int nPartnersPrevSuit = bidState.nPartnersPrevSuit;
	int nAgreedSuit = bidState.m_nAgreedSuit;
	int nSupportLevel = bidState.nPartnersSuitSupport;
	int nBid;

	// see if partner made a cue bid
	// it needs to be a bid that commits the partnership to game, 
	// after a suit has been agreed upon
	if ((nAgreedSuit != NONE) && (nPartnersSuit != NOTRUMP) && (nPartnersSuit != nAgreedSuit) &&
		((nPartnersBid > MAKEBID(nAgreedSuit,3)) && (nPartnersBid < bidState.GetGameBid(nAgreedSuit))))
	{
		//NCR what if suit was previously bid by this player???
		// EG: N->1H, S->2C, N->3C, S->3H  3H is NOT a cue bid, it's a response to this player's  previous bid
		// NCR how to test if partner's current bid was in suit previously bid ???
		// NCR what about a game bid???
		int nSuit =  BID_SUIT(nPartnersBid);
		for(int i=0; i < player.GetNumBidsMade(); i++) { // NCR had to add const to this function def
			int nSuitBid = pDOC->GetBidByPlayer(player.GetPosition(), i);
			if(BID_SUIT(nSuitBid) == nSuit)
				return FALSE;  // NCR not cue if partner bid before ???
		}
                                            // NCR-295 game bid in agreed suit???
		if(bidState.IsGameBid(nPartnersBid) && (nSuit == nAgreedSuit) ) // || CheckIfSuitBid(player, BID_SUIT(nPartnersBid))) 
		{
			return FALSE;  //NCR don't treat Game bid as cue bid
		}
		// met the requirements
		status << "CUR0! Partner made a cue bid of " & BTS(nPartnersBid) &
				  ", hinting at slam prospects.\n";
	}
	else
	{
		// this is not a cue bid
		return FALSE;
	}

	//
	// respond to a cue bid only if we have an interest in slam 
	// 
	// only qualify if we have 30+ team points, _OR_
	// strong trump support and 28+ poitns
	//
	if (bidState.m_fMinTPPoints >= 30)
	{
		// 30+ team points
		status << "2CUR1! And since we have " & 
				  bidState.m_fMinTPPoints & "-" & bidState.m_fMaxTPPoints &
				  "+ points in the partnership, we want to respond favorably.\n";
	}
	else if ((nSupportLevel >= SS_GOOD_SUPPORT) && 
								(bidState.m_fMinTPPoints >= 28))
	{
		// good support (4 good or 5 moderate cards)
		status << "2CUR2! And since we have " & bidState.SLTS(nPartnersSuit) &
				   " trump support, " & 
				   ((bidState.m_fMinTPPoints >= 30)? " as well as " : " albeit only with ") &
				   bidState.m_fMinTPPoints & "-" & bidState.m_fMaxTPPoints &
				   " points in the partnership, we want to respond favorably.\n";
	}
	else
	{
		// insufficient strength for slam -- correct back to the agreed suit
		nBid = bidState.GetCheapestShiftBid(nAgreedSuit);
		status << "CUR4! But we don't have the points (only " & 
				  bidState.m_fMinTPPoints & "-" & bidState.m_fMaxTPPoints &
				  " pts in the partnership) or the excellent trump support needed for a marginal slam, so we decline by returning to the agreed suit at a bid of " &
				  BTS(nBid) & ".\n";
		bidState.SetBid(nBid);
		bidState.SetConventionStatus(this, CONV_FINISHED);
		return TRUE;
	}

	//
	// else we're playing along -- find the cheapest response
	//
	if (nStatus == CONV_INACTIVE)
	{
		// first invocation -- find the cheapest Ace
		int nSuit = GetCheapestAce(hand, nPartnersSuit, bidState.m_nAgreedSuit);
		// found a suit with an ace?
		if ((nSuit != nPartnersSuit) && (nSuit != nAgreedSuit)) 
		{
			// found a suit to cue bid
			nBid = bidState.GetCheapestShiftBid(nSuit);
			status << "CUR20! Respond to partner's cue bid, showing our cheapest ace (" &
					  STS(nSuit) & ") with a bid of " & BTS(nBid) & ".\n";
			bidState.SetBid(nBid);
			bidState.SetConventionStatus(this, CONV_RESPONDED_ROUND1);
			return TRUE;
		} 
		else 
		{
			// found no ace, or else it's in the trump suit, so either way
			// just sign off at the agreed suit
			nBid = bidState.GetCheapestShiftBid(nAgreedSuit);
			if (hand.SuitHasCard(nSuit, ACE))
				status << "CUR22! But our only Ace is in the trump suit of " &
						  STSS(nAgreedSuit) & ", so sign off at a bid of " & BTS(nBid) & ".\n";
			else
				status << "CUR24! We have no other Aces to offer, so sign off with the agreed " &
						  STSS(nAgreedSuit) & " suit at a bid of " & BTS(nBid) & ".\n";
			bidState.SetBid(nBid);
			bidState.SetConventionStatus(this, CONV_FINISHED);
			return TRUE;
		}
	}
	else if (nStatus == CONV_RESPONDED_ROUND1)
	{
		// second invocation -- find cheapest King or void
		// first invocation -- find teh cheapest Ace
		int nSuit = GetCheapestKingOrVoid(hand, nPartnersSuit, bidState.m_nAgreedSuit);
		// found an appropriate suit?
		if ((nSuit != nPartnersSuit) && (nSuit != nAgreedSuit)) 
		{
			// found a suit to cue bid
			nBid = bidState.GetCheapestShiftBid(nSuit);
			status << "CUR30! Respond to partner's cue bid, showing our cheapest " &
					  ((hand.GetSuitLength(nSuit) > 0)? "King" : "void suit") &
					  " (in " & STS(nSuit) & ") with a bid of " & BTS(nBid) & ".\n";
			bidState.SetBid(nBid);
//			bidState.SetConventionStatus(this, CONV_RESPONDED_ROUND2);
			bidState.SetConventionStatus(this, CONV_FINISHED);
			return TRUE;
		} 
		else 
		{
			// found no king or void, or else found a king in the trump suit, 
			// so either way, just sign off at the agreed suit
			nBid = bidState.GetCheapestShiftBid(nAgreedSuit);
			if (hand.SuitHasCard(nSuit, KING))
				status << "CUR32! But our only Ace is in the trump suit of " &
						  STSS(nAgreedSuit) & ", so sign off at a bid of " & BTS(nBid) & ".\n";
			else
				status << "CUR34 We have no other Kings or void suits to offer, so sign off with the agreed " &
						  STSS(nAgreedSuit) & " suit at a bid of " & BTS(nBid) & ".\n";
			bidState.SetBid(nBid);
			bidState.SetConventionStatus(this, CONV_FINISHED);
			return TRUE;
		}
	}
	else
	{
		// error!
		bidState.SetConventionStatus(this, CONV_ERROR);
		return FALSE;
	}
}
Example #10
0
//
// Perform()
//
PlayResult CType1Finesse::Perform(CPlayEngine& playEngine, CCombinedHoldings& combinedHand, 
						   CCardLocation& cardLocation, CGuessedHandHoldings** ppGuessedHands, 
						   CPlayerStatusDialog& status, CCard*& pPlayCard)
{
	// Type I Finesse 
	// - lead of a low card towards a higher card in the opposite hand, 
	//	 which holds a higher cover card and a commanding top card.
	//   e.g., AQ3 (dummy) / 4 (hand) -- lead the 4, then finesse the Q

	// 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);
	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;
	CCard* pOppCard = NULL;
//	BOOL bLeading = TRUE;
	CString strRHO = bPlayingInHand? playEngine.szRHO : playEngine.szLHO;

	// 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)
				// see where the finese card is located
				if (m_nTargetHand == IN_HAND)
				{
					// can't finesse here
					status << "4PL1FNS10! Can't use this (Type I) finesse leading from hand, as the finesse card (" &
							   m_pConsumedCard->GetName() & ") and its covers are in our own hand.\n";
					m_nStatusCode = PLAY_INACTIVE;
					return PLAY_POSTPONE;
				}
				else
				{
					// finessing from dummy so lead low card of the suit from hand
					if (playerHand.GetNumCardsInSuit(m_nSuit) > 0)
					{
						pPlayCard = playerHand.GetSuit(m_nSuit).GetBottomCard();
						status << "PL1FN12! Leading a low " & STSS(m_nSuit) & 
								  " (the " & pPlayCard->GetFaceName() &
								  ") from hand to finesse the " & 
								  m_pConsumedCard->GetFaceName() & " in dummy.\n";
					}
					else
					{
						// oops, no card in the suit to lead!
						status << "4PL1FN14! Oops, we wanted to finesse a " & STSS(m_nSuit) & 
								  " in dummy, but we have no " & STS(m_nSuit) & 
								  " 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 & finessing in dummy? no can do
					status << "4PL1FNS20! Can't use this (Type I) finesse leading from dummy, as the finesse card (" &
							  m_pConsumedCard->GetName() & ") and its covers are in dummy.\n";
					m_nStatusCode = PLAY_INACTIVE;
					return PLAY_POSTPONE;
				}
				else 
				{
					// leading from dummy and finessing in hand, so do it
					if (dummyHand.GetNumCardsInSuit(m_nSuit) > 0)
					{
						pPlayCard = dummyHand.GetSuit(m_nSuit).GetBottomCard();
						status << "PL1FN22! Lead a low " & STSS(m_nSuit) & 
								  " (the " & pPlayCard->GetFaceName() &
								  ") from dummy to finesse the " & 
								  m_pConsumedCard->GetFaceName() & " in hand.\n";
					}
					else
					{
						// oops, no card in the suit to lead!
						status << "4PL1FN24! Oops, we wanted to finesse a " & STSS(m_nSuit) & 
								  " in hand, but we have no " & STS(m_nSuit) & 
								  " 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 -- can't really use the type I finesse here
			m_nStatusCode = PLAY_INACTIVE;
			return PLAY_POSTPONE;

		case 2:
			// playing third -- this is the key to the finesse
			// make sure the play is still on
			{
			if (m_nStatusCode != PLAY_IN_PROGRESS)
				return PLAY_INACTIVE;
			// see if the wrong suit was led 
			if (nSuitLed != m_nSuit)
			{
				m_nStatusCode = PLAY_NOT_VIABLE;
				return m_nStatusCode;
			}
			// see if LHO trumped
			if (bTrumped)
			{
				status << "3PL1FN50! the opponent has trumped, so abandon the finesse for this round.\n";
				m_nStatusCode = PLAY_INACTIVE;
				return PLAY_POSTPONE;
			}
			// see if RHO showed out
			CCard* pLHOCard = pDOC->GetCurrentTrickCardByOrder(1);
			if (pLHOCard->GetSuit() != nSuitLed)
			{
				// oops! RHO showed out! the finesse can't win!
				status << "3PL1FN55! Oops -- RHO (" & strRHO &
						  ") showed out of " & STS(nSuitLed) & ", meaning that LHO holds the " & 
						  m_pGapCards->GetAt(0)->GetFaceName() & ", so the finesse cannot succeed -- so skip it.\n";
				m_nStatusCode = PLAY_NOT_VIABLE;
				return m_nStatusCode;
/*
				// play the cover card
				pPlayCard = m_pCoverCards->GetBottomCard();
				ASSERT(pPlayCard->IsValid());
				status << "3PL1FN55! Oops -- " & playEngine.szLHO & " showed out of " & STS(nSuitLed) & 
						  ", meaning that RHO holds the " & m_pGapCards[0]->GetFaceName() & 
						  ", so the finesse cannot succeed -- so play the cover card (the " &
						  pCoverCard->GetFaceName() & ").\n";
				m_nStatusCode = PLAY_COMPLETE;
				return m_nStatusCode;
*/
			}
			// check the intervening opponents's card
			pOppCard = pDOC->GetCurrentTrickCardByOrder(1);
			// else check which hand we're playing in
			if (bPlayingInHand) 
			{
				// playing third from our own hand (declarer)
				// see if it's time to finesse
				if (m_nTargetHand == IN_HAND)
				{
					// see if RHO's card is higher than the intended finesse
					if (*pOppCard > *m_pConsumedCard)
					{
						// if so, play a cover card if possible
// ???					pPlayCard = dummySuit.GetLowestCardAbove(pOppCard);
						pPlayCard = playerSuit.GetTopSequence().GetBottomCard();
						status << "PL1FN62! RHO has played a higher card (the " & 
								  pOppCard->GetFaceName() & ") than our intended finesse (the " &
								  m_pConsumedCard->GetFaceName() & "), so cover with the " &
								  pPlayCard->GetFaceName() & ".\n";
					}
					else
					{
						// OK, finesse the card as intended
						pPlayCard = m_pConsumedCard;
						status << "PL1FN64! Finesse the " & pPlayCard->GetName() & " from hand.\n";
					}
				}
				else
				{
					// finessing in hand, but this is dummy? messed up
					status << "4PL1FN66! We intended to finesse in hand, but ended up here in dummy in third position -- so skip this play.\n";
					m_nStatusCode = PLAY_INACTIVE;
					return PLAY_POSTPONE;
				}
			}
			else
			{
				// playing third in dummy
				// see if it's time to finnesse here
				if (m_nTargetHand == IN_DUMMY)
				{
					// see if LHO's card is higher than the intended finesse
					if (*pOppCard > *m_pConsumedCard)
					{
						// if so, play a cover card
						// NCR-454 Which card to play? Mininum cover or a top sequence card?
						pPlayCard = dummySuit.GetLowestCardAbove(pOppCard);
						
//???NCR-454						pPlayCard = dummySuit.GetTopSequence().GetBottomCard();
						status << "PL1FN72! LHO has played a higher card (the " & 
								  pOppCard->GetFaceName() & ") than our intended finesse (the " &
								  m_pConsumedCard->GetFaceName() & "), so cover with the " &
								  pPlayCard->GetFaceName() & ".\n";
					}
					else
					{
						// finesse the card from dummy 
						pPlayCard = m_pConsumedCard;
						status << "PLCSH74! Finesse the " & pPlayCard->GetName() & " from dummy.\n";
					}
				}
				else
				{
					// messed up
					status << "4PL1FN76! We intended to finesse in hand, but ended up here in dummy in third position -- so skip this play.\n";
					m_nStatusCode = PLAY_INACTIVE;
					return PLAY_POSTPONE;
				}
			}
			// else all went OK
			m_nStatusCode = PLAY_COMPLETE;
			break;
			}

		case 3:
			//  can't use the type I finesse in 4th position!
			m_nStatusCode = PLAY_INACTIVE;
			return PLAY_POSTPONE;
	}

	// done
	ASSERT(pPlayCard->IsValid());
	return m_nStatusCode;
}
Example #11
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;
}
//
//-----------------------------------------------------
//
// respond to partner's Jacoby 2NT Bid
//
BOOL CJacoby2NTConvention::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 nPreviousBid = bidState.nPreviousBid;
	int numTotalBidTurns = pDOC->GetNumBidsMade();

	//
	int nBid;
	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 Jacoby 2NT bid? 
		//
		// the requirements for a Jacoby 2NT Bid are:
		// 1: we must have opened the bidding with 1 of a major
		// 2: Partner responded with 2NT
		int nOpeningBid = pDOC->GetOpeningBid();

		// test conditions
		if ( (bidState.m_numBidTurns == 1) && (ISMAJOR(BID_SUIT(nPreviousBid))) && 
			(nOpeningBid == nPreviousBid) && (BID_LEVEL(nPreviousBid) == 1) && 
			 (bidState.nPartnersBid == BID_2NT) )
		{
			 // passed the test
		}
		else
		{
			return FALSE;
		}

		status << "J2N20! Partner has made a Jacoby 2NT inquiry bid, indicating " & 
				  OPEN_PTS(13) & " pts and 4+ card support.\n";

		// adjust points as declarer
		int nSuit = bidState.nPreviousSuit;
		bidState.SetAgreedSuit(nSuit);
		fPts = bidState.fAdjPts = hand.RevalueHand(REVALUE_DECLARER, nSuit, TRUE);

		// partner has 13+ pts
		bidState.AdjustPartnershipPoints(13, 13);

		//
		// our options are as follows, in order:
		//
		// - with 18+ pts, rebid the suit at the 3 level
		// - with 15-17 pts and a strong 5-card side suit, bid that suit at the 4-level
		// - with 15-17 pts and a short suit, bid the short suit at the 3 level
		// - with 15-17 pts an no short suit, bid 3NT
		// - otherwise, sign off in game at the 4-level

		// check point count
		if (fPts >= 18)
		{
			nBid = MAKEBID(nSuit, 3);
			status << "J2N21! With " & fPts & " points in hand, "
					  "respond to partner's Jacoby 2NT inquiry with a bid of " & BTS(nBid) & ".\n";
		}
		else if (fPts >= 15)
		{
			// see if we have a strong side suit
			int nSideSuit = NONE;
			for(int i=0;i<4;i++)
			{
				if ((i != nSuit) && (bidState.nSuitStrength[i] <= SS_STRONG) &&
						(bidState.numCardsInSuit[i] >= 5))
					break;
			}
			//
			if (i < 4)
			{
				// bid the suit at the 4 level
				nSuit = i;
				nBid = MAKEBID(nSuit, 4);
				status << "J2N22! With " & fPts & " points in hand and a good " & 
						  bidState.numCardsInSuit[nSuit] & "-card suit in " & STS(nSuit) & 
						  ", respond to partner's Jacoby 2NT inquiry with " & BTS(nBid) & ".\n";
			}
			else if (bidState.numVoids >= 1)
			{
				// bid the void suit
				for(nSuit=0;nSuit<4;nSuit++)
				{
					if (bidState.numCardsInSuit[nSuit] == 0)
						break;
				}
				nBid = MAKEBID(nSuit, 3);
				status << "J2N24! With " & fPts & " points in hand and a void suit in " & STS(nSuit) & 
						  ", respond to partner's Jacoby 2NT inquiry with a bid of " & BTS(nBid) & ".\n";
			}
			else if (bidState.numSingletons >= 1)
			{
				// bid the singleton
				for(nSuit=0;nSuit<4;nSuit++)
				{
					if (bidState.numCardsInSuit[nSuit] == 1)
						break;
				}
				nBid = MAKEBID(nSuit, 3);
				status << "J2N26! With " & fPts & " points in hand and a singleton in " & STS(nSuit) & 
						  ", respond to partner's Jacoby 2NT inquiry with a bid of " & BTS(nBid) & ".\n";
			}
			else
			{
				// bid 3NT
				nBid = BID_3NT;
				status << "J2N28! With " & fPts & " points in hand and no short suits, " 
						  " respond to partner's Jacoby 2NT inquiry with a bid of " & BTS(nBid) & ".\n";
			}
		}
		else
		{
			// sign off at the 4-level
			nBid = MAKEBID(nSuit, 4);
			status << "J2N31! With only " & fPts & " points in hand, sign off in game at " & 
					  BTS(nBid) & ".\n";
		}

		// and return
		bidState.SetBid(nBid);
		bidState.SetConventionStatus(this, CONV_FINISHED);
		return TRUE;
	}

	//
	return FALSE;
} 
//
//==========================================================
//
// Rebidding as opener after partner responds to an Jacoby 2NT Bid
//
BOOL CJacoby2NTConvention::HandleConventionResponse(const CPlayer& player, 
													const CConventionSet& conventions, 
													CHandHoldings& hand, 
													CCardLocation& cardLocation, 
													CGuessedHandHoldings** ppGuessedHands,
													CBidEngine& bidState,  
													CPlayerStatusDialog& status)
{
	// check status
	if ((bidState.GetConventionStatus(this) != CONV_INVOKED_ROUND1) &&
		(bidState.GetConventionStatus(this) != CONV_INVOKED_ROUND2))
		return FALSE;

	// get some info
	//
	int nBid = NONE;
	int nPrevSuit = bidState.nPartnersPrevSuit;
	int nSuit = bidState.nPartnersSuit;
	int nPartnersBid = bidState.nPartnersBid;
	int nPartnersBidLevel = bidState.nPartnersBidLevel;
	int numSupportCards = bidState.numSupportCards;

	//
	// handling partner's Drury response
	//
	int nStatus = bidState.GetConventionStatus(this);

	if (nStatus == CONV_INVOKED)
	{
		//
		// here, our actions depend on partner's response
		//
		if (bidState.nPartnersBid == MAKEBID(nPrevSuit, 3))
		{
			// partner responded in the suit at the 3-level, for 18+ pts
			status << "J2N40! Partner responded to our Jacoby 2NT inquiry by rebidding his " & 
					   STSS(nPrevSuit) & " suit at the 3-level, indicating " & 
					   OPEN_PTS(18) & "+ points.\n";

			// revalue partnership totals
			bidState.AdjustPartnershipPoints(18, pCurrConvSet->GetValue(tn2ClubOpeningPoints));
		}
		else if ((nPartnersBidLevel == 3) && ISSUIT(nSuit) && (nSuit != nPrevSuit))
		{
			// partner responded in a different suit at the 3-level
			status << "J2N41! Partner responded to our Jacoby 2NT inquiry by bidding the " & 
					   STSS(nSuit) & " suit at the 3-level, indicating " & OPEN_PTS(15) & "-" & OPEN_PTS(17) & 
					   " points and a singleton or void in " & STS(nSuit) & ".\n";

			// revalue partnership totals
			bidState.AdjustPartnershipPoints(15, 17);
		}
		else if (nPartnersBid == BID_3NT)
		{
			// partner responded with 3NT
			status << "J2N42! Partner responded to our Jacoby 2NT inquiry by bidding 3NT, indicating " &
					   OPEN_PTS(15) & "-" & OPEN_PTS(17) & " points with a balanced hand.\n";

			// revalue partnership totals
			bidState.AdjustPartnershipPoints(15, 17);
		}
		else if ((nPartnersBidLevel == 4) && ISSUIT(nSuit) && (nSuit != nPrevSuit))
		{
			// partner responded in a different suit at the 4-level
			status << "J2N44! Partner responded to our Jacoby 2NT inquiry by bidding the " & 
					   STSS(nSuit) & " suit at the 4-level, indicating a strong 5-card side suit and " & 
					   OPEN_PTS(15) & "-" & OPEN_PTS(17) & " points in the hand.\n";

			// revalue partnership totals
			bidState.AdjustPartnershipPoints(15, 17);
		}
		else if ((nPartnersBidLevel == 4) && (nSuit == nPrevSuit))
		{
			// partner responded in the original suit at the 4-level
			status << "J2N44! Partner responded to our Jacoby 2NT inquiry by rebidding his " & 
					   STSS(nSuit) & " suit at the 4-level, indicating a minimum opener of approx. " & 
					   OPEN_PTS(12) & "-" & OPEN_PTS(14) & " points in the hand.\n";

			// revalue partnership totals
			bidState.AdjustPartnershipPoints(12, 14);
		}
		else if ((nPartnersBid == BID_DOUBLE) || (nPartnersBid == BID_REDOUBLE))
		{
			// the convention is cancelled!
			bidState.SetConventionStatus(this, CONV_ERROR);
			return FALSE;
		}

		// now figure out what to do
		if (bidState.m_fMinTPPoints >= PTS_SLAM)
		{
			// go to Blackwood
			status << "J2N60! With a total of " & bidState.m_fMinTPPoints & "-" & bidState.m_fMaxTPPoints &
					  " pts in the partnership, push on to slam in partner's " & STSS(nPrevSuit) & " suit.\n";
			bidState.InvokeBlackwood(nPrevSuit);
			bidState.SetConventionStatus(this, CONV_FINISHED);
			return TRUE;
		}
		else if (bidState.m_fMinTPPoints >= PTS_MAJOR_GAME)
		{
			// we want to bid game
			if (nPartnersBid < bidState.GetGameBid(nPrevSuit))
			{
				// raise or shift to game
				nBid = bidState.GetGameBid(nPrevSuit);
				status << "J2N62! With a total of " & bidState.m_fMinTPPoints & "-" & bidState.m_fMaxTPPoints &
						  " pts in the partnership, go to game in " & STS(nPrevSuit) &
						  " with a bid of " & BTS(nBid) & ".\n";
			}
			else
			{
				// here partner bid game or higher -- pass unless it needs correction
				if (nSuit == nPrevSuit)
				{
					nBid = BID_PASS;
					status << "J2N64! With a total of " & bidState.m_fMinTPPoints & "-" & bidState.m_fMaxTPPoints &
							  " pts in the partnership, pass partner's " & BTS(nPartnersBid) & " bid.\n";
				}
				else
				{
					// correct to the original suit
					nBid = bidState.GetCheapestShiftBid(nPrevSuit, nPartnersBid);
					status << "J2N66! With a total of " & bidState.m_fMinTPPoints & "-" & bidState.m_fMaxTPPoints &
							  " pts in the partnership, we want to stop at game in " & STS(nPrevSuit) & 
							  "; correct partner's " & BTS(nPartnersBid) & " bid to " & BTS(nBid) & ".\n";
				}
			}
		}
		else
		{
			// oops, caught with too few points
			// either pass 3NT , or return to the suit at the cheapest level possible
			if ((nPartnersBid == BID_3NT) || ((nSuit == nPrevSuit)))
			{
				nBid = BID_PASS;
				status << "J2N70! With a total of only " & bidState.m_fMinTPPoints & "-" & bidState.m_fMaxTPPoints &
						  " pts in the partnership, we have to stop here at " & BTS(nPartnersBid) &
						  ", so pass.\n";
			}
			else
			{
				nBid = bidState.GetCheapestShiftBid(nPrevSuit, nPartnersBid);
				status << "J2N72! With a total of only " & bidState.m_fMinTPPoints & "-" & bidState.m_fMaxTPPoints &
						  " pts in the partnership, we have to return to the " & STSS(nPrevSuit) & 
						  " and stop at " & BTS(nBid) & ".\n";
			}
		}

		// done
		bidState.SetBid(nBid);
		bidState.SetConventionStatus(this, CONV_FINISHED);
		return TRUE;

	}

	// oops!
	bidState.SetConventionStatus(this, CONV_ERROR);
	return FALSE;
}
//
//==========================================================
//
// Rebidding as opener after partner responds to a Michaels Cue Bid
//
BOOL CMichaelsCueBidConvention::HandleConventionResponse(const CPlayer& player, 
													     const CConventionSet& conventions, 
													     CHandHoldings& hand, 
														 CCardLocation& cardLocation, 
														 CGuessedHandHoldings** ppGuessedHands,
													     CBidEngine& bidState,  
													     CPlayerStatusDialog& status)
{
	// check status
	if ((bidState.GetConventionStatus(this) != CONV_INVOKED_ROUND1) &&
		(bidState.GetConventionStatus(this) != CONV_INVOKED_ROUND2))
		return FALSE;

	//
	// get some info
	//
	int nBid;
	double fPts = bidState.fPts;
	double fAdjPts = bidState.fAdjPts;
	double fCardPts = bidState.fCardPts;
	int nPrefSuit = bidState.nPrefSuit;
	int nPrefSuitStrength = bidState.nPrefSuitStrength;
	int nPreviousSuit = bidState.nPreviousSuit;
	int nPreviousBidLevel = bidState.nPreviousBidLevel;
	BOOL bBalanced = bidState.bBalanced;
	//
	int nPartnersBid = bidState.nPartnersBid;
	int nPartnersBidLevel = bidState.nPartnersBidLevel;
	int nPartnersSuit = bidState.nPartnersSuit;
	int nPartnersSuitSupport = bidState.nPartnersSuitSupport;
	int nPartnersPrevSuit = bidState.nPartnersPrevSuit;
	int numSupportCards = bidState.numSupportCards;

	//
	// handling partner's Michaels response
	//
	int nStatus = bidState.GetConventionStatus(this);

	if (nStatus == CONV_INVOKED)
	{
		// first check for a strange response
		if ((nPartnersBid == BID_DOUBLE) || (nPartnersBid == BID_REDOUBLE))
		{
			// we don't understand partner's bid
			return CConvention::HandleConventionResponse(player, conventions, hand, cardLocation, ppGuessedHands, bidState, status);
		}

		// if we're holding the STRONG Michaels hand indicate it by cue-bidding the
		// enemy suit again
		if (bidState.fPts >= PT_COUNT(17))
		{
			nBid = MAKEBID(nPreviousSuit, 3);
			status << "MCLRH12! with a strong Michaels hand (" & bidState.fPts & 
					  " pts), cue bid the enemy suit again at " & BTS(nBid) & 
					  " to indicate our strength.\n";
			bidState.SetBid(nBid);
			bidState.SetConventionStatus(this, CONV_INVOKED_ROUND2);
			return TRUE;
		}

		// did partner bid 2NT, asking for the minor?
		if (ISMAJOR(nPreviousSuit) && (nPartnersBid == BID_2NT))
		{
			// with a weak Michaels opener, indicate the minor
			int nSuit = bidState.GetLongerSuit(CLUBS, DIAMONDS);
			nBid = MAKEBID(nSuit, 3);
			status << "MCLRH10! With the weak flavor of Michaels, respond to partner's Michaels minor inquiry with a bid of " & BTS(nBid) &
					  ", indicating " & STS(nSuit) & " as the unknown minor.\n";
			bidState.SetBid(nBid);
			bidState.SetConventionStatus(this, CONV_INVOKED_ROUND2);
			return TRUE;
		}

		// did partner cue-bid the enemy suit (a slam try)?
		if ((nPartnersSuit == nPreviousSuit) && (nPartnersBidLevel == nPreviousBidLevel+1))
		{
			// determine the cheapest of the two suits
			int nCheapestSuit;
			if (ISMINOR(nPreviousSuit))
				nCheapestSuit = HEARTS;		// 5/5 in the majors, so Hearts is cheapest
			else
				nCheapestSuit = bidState.GetLongerSuit(CLUBS, DIAMONDS);

			// respond affirmatively only with a strong hand
			status << "2MCLRH20! Partner cue bid the enemy suit, which is a game or slam try.\n";
			if (bidState.fPts >= PT_COUNT(17))
			{
				// jump into Blackwood
				status << "MCLRH21! And with " & bidState.fPts & " pts in hand, proceed towards slam in the preferred "&
						  STSS(bidState.nPrefSuit) & " suit.\n";
				bidState.InvokeBlackwood(bidState.nPrefSuit);
			}
			else if ( (ISMAJOR(nCheapestSuit) && (bidState.fPts >= PT_COUNT(9))) ||
				(ISMINOR(nCheapestSuit) && (bidState.fPts >= PT_COUNT(12))) )
			{
				// stop at game in the cheapest suit
				nBid = bidState.GetGameBid(nCheapestSuit);
				status << "MCLRH22! But with only " & bidState.fPts & " pts in hand, forget about slam and stop at game in the cheapest suit ("&
						  STS(nCheapestSuit) & ") at " & BTS(nBid) & ".\n";
				bidState.SetBid(nBid);
			}
			else 
			{
				// 8 or fewer pts -- bail out in the cheapest suit
				nBid = bidState.GetCheapestShiftBid(nCheapestSuit);
				status << "MCLRH23! But with only " & bidState.fPts & " pts in hand, forget about slam and bail out in the cheapest suit (" &
						  STS(nCheapestSuit) & ") at " & BTS(nBid) & ".\n";
				bidState.SetBid(nBid);
			}
			// done
			bidState.SetConventionStatus(this, CONV_FINISHED);
			return TRUE;
		}

		//
		// else partner made a signoff, invitational, or game bid
		//
		if (bidState.IsGameBid(nPartnersBid))
		{
			status << "MCLRH30! Partner responded to our Michaels Cue bid with a game bid of " & 
					  bidState.szPB & ", so we should pass.\n";
			nBid = BID_PASS;	
		}
		else if (nPartnersBid != BID_PASS) 
		{
			// see if we should raise partner to game
			status << "2MCLRH40! Partner responded to our Michaels Cue bid with a bid of " & 
					  bidState.szPB & ", a possible invitation to game.\n";
			// go to game with 17+ pts (strong hand)
			if (fPts < PT_COUNT(17))
			{
				nBid = BID_PASS;	
				status << "MCLRH41! But since we opened Michaels with a weak hand (" & fPts &
						  ") pts, we likely do not have the points for game and have to pass.\n";
			}
			else
			{
				nBid = bidState.GetGameBid(nPartnersSuit);	
				status << "MCLRH42! and since we opened Michaels with a strong hand (" & fPts &
						  ") pts, we can raise to game at " & BTS(nBid) & ".\n";
			}
		}
		else
		{
			status << "2MCLRH49! Partner passed" & (bidState.bLHOInterfered? "after opponents interference" : "") &
					  ", so Michaels is off.\n";
			bidState.SetConventionStatus(this, CONV_FINISHED);
			return FALSE;
		}

		// done
		bidState.SetBid(nBid);
		bidState.SetConventionStatus(this, CONV_FINISHED);
		return TRUE;

	}
	else if (nStatus == CONV_INVOKED_ROUND2)
	{
		// last time, we either showed our minor suit or indicated our strength 
		// with another cue bid of the opponents' suit

		// first check for a strange response
		if ((nPartnersBid == BID_DOUBLE) || (nPartnersBid == BID_REDOUBLE))
		{
			// we don't understand partner's bid
			return CConvention::HandleConventionResponse(player, conventions, hand, cardLocation, ppGuessedHands, bidState, status);
		}

		// did we have the strong hand?
		if (bidState.fPts >= PT_COUNT(17))
		{
			// see what partner's reaction was
			if (nPartnersSuit == BID_4NT)
			{
				// parter still wants to see our minor!!!
				int nSuit = bidState.GetLongerSuit(CLUBS, DIAMONDS);
				nBid = bidState.GetCheapestShiftBid(nSuit);
				status << "MCLRH50! After our second Michaels cue bid of the enemy suit, partner still wants to see the unknown minor, so show it (" &
						  STS(nSuit) & ") with a bid of " & BTS(nBid) & ".\n";
				bidState.SetBid(nBid);
				bidState.SetConventionStatus(this, CONV_INVOKED_ROUND3);
				return TRUE;
			}

			// else partner's bid was natural
			if (bidState.IsGameBid(nPartnersBid))
			{
				if (fPts < PT_COUNT(20))
				{
					status << "MCLRH55! Partner responded to our second Michaels cue bid with a game bid of " & 
							  bidState.szPB & ", so we should pass.\n";
					nBid = BID_PASS;
				}
				else
				{
					// jump to slam
					nBid = MAKEBID(nPartnersSuit, 6);
					status << "MCLRH55! Partner responded to our second Michaels cue bid with a game bid of " & 
							  bidState.szPB & ", and with " & fPts & "+ in hand, we can go ahead and jump to slam at " & BTS(nBid) & ".\n";
				}
			}
			else if (nPartnersBid != BID_PASS)
			{
				// see if we should raise partner to game
				nBid = bidState.GetGameBid(nPartnersSuit);
				status << "MCLRH56! Partner responded to our second Michaels cue bid of the enemy suit with a bid of " & 
						  bidState.szPB & ", an invitation to game -- so go ahead and bid game at " & BTS(nBid) & ".\n";
			}
			else
			{
				if (bidState.bLHOInterfered)
					status << "MCLRH58! Partner passed our second Michaels cue bid after interference, so we have to pass also.\n";
				else
					status << "MCLRH59! Partner passed in spite of our second Michaels cue bid, so we should pass also.\n";
				nBid = BID_PASS;
			}
		}
		else
		{
			// partner responded to our minor answer
			if (bidState.IsGameBid(nPartnersBid))
			{
				status << "MCLRH60! Partner responded to our Michaels minors answer with a game bid of " & 
						  bidState.szPB & ", so we should pass.\n";
				nBid = BID_PASS;
			}
			else if (nPartnersBid != BID_PASS)
			{
				// see if we should raise partner to game
				status << "MCLRH70! Partner responded to our Michaels minor answer with a bid of " & 
						  bidState.szPB & ", a possible invitation to game.\n";

				// go to game with 17+ pts (strong hand)
				if (fPts < PT_COUNT(17))
				{
					nBid = BID_PASS;	
					status << "MCLRH72! But since we opened Michaels with a weak hand (" & fPts &
							  ") pts, we likely do not have the points for game and have to pass.\n";
				}
				else
				{
					nBid = bidState.GetGameBid(nPartnersSuit);	
					status << "MCLRH72! and since we opened Michaels with a strong hand (" & fPts &
							  ") pts, we can raise to game at " & BTS(nBid) & ".\n";
				}
			}
			else
			{
				if (bidState.bLHOInterfered)
					status << "MCLRH75! Partner passed our Michaels minor answer after interference, so we have to pass also.\n";
				else
					status << "MCLRH76! Partner passed our Michaels minor answer, so we should pass also.\n";
				nBid = BID_PASS;
			}
		}

		// done
		bidState.SetBid(nBid);
		bidState.SetConventionStatus(this, CONV_FINISHED);
		return TRUE;

	}
	else if (nStatus == CONV_INVOKED_ROUND3)
	{
		// first check for a strange response
		if ((nPartnersBid == BID_DOUBLE) || (nPartnersBid == BID_REDOUBLE))
		{
			// we don't understand partner's bid
			return CConvention::HandleConventionResponse(player, conventions, hand, cardLocation, ppGuessedHands, bidState, status);
		}

		// we indicated our strength with another cue bid, and partner asked
		// to see our minor, _then_ bid
		if (bidState.IsGameBid(nPartnersBid))
		{
			if (fPts < PT_COUNT(20))
			{
				status << "MCLRH80! Partner responded to our Michaels minor answer with a game bid of " & 
						  bidState.szPB & ", so we should pass.\n";
				nBid = BID_PASS;
			}
			else
			{
				// jump to slam
				nBid = MAKEBID(nPartnersSuit, 6);
				status << "MCLRH81! Partner responded to our Michaels minor answer with a game bid of " & 
						  bidState.szPB & ", and with " & fPts & "+ in hand, we can go ahead and jump to slam at " & BTS(nBid) & ".\n";
			}
		}
		else if (nPartnersBid != BID_PASS)
		{
			// see if we should raise partner to game
			nBid = bidState.GetGameBid(nPartnersSuit);
			status << "MCLRH85! Partner responded to our Michaels minor answer with a bid of " & 
					  bidState.szPB & ", an invitation to game -- so go ahead and bid game at " & BTS(nBid) & ".\n";
		}
		else
		{
			if (bidState.bLHOInterfered)
				status << "MCLRH86! Partner passed our Michaels minor answer after interference, so we have to pass also.\n";
			else
				status << "MCLRH87! Partner passed in spite of our Michaels minor answer, so we should pass also.\n";
			nBid = BID_PASS;
		}

		// done (finally!)
		bidState.SetBid(nBid);
		bidState.SetConventionStatus(this, CONV_FINISHED);
		return TRUE;
	}

	// oops!
	bidState.SetConventionStatus(this, CONV_ERROR);
	return FALSE;
}
//
//===============================================================================
//
// TryConvention()
//
// check if we can use a Michaels Cue Bid here
//
BOOL CMichaelsCueBidConvention::TryConvention(const CPlayer& player, 
											  const CConventionSet& conventions, 
											  CHandHoldings& hand, 
											  CCardLocation& cardLocation, 
											  CGuessedHandHoldings** ppGuessedHands,
											  CBidEngine& bidState,  
											  CPlayerStatusDialog& status)
{
	//
	// the requirements for a Michaels Cue Bid are:
	// 1: RHO must have opened a suit (not NT) at the 1-level
	// 2: this must be our first bidding opportunity
	// 3: need a 2-suited hand; i.e., 
	//    - if RHO bid a minor, need 5/5 or 5/(good)4 in the majors
	//    - if RHO bid a major, need 5 in the other major, plus 5 in a minor
	//    the two suits should also be rather comparable
	// 4: need either 6-11 pts or 17+ pts
	//    (with 12-16 pts, we generally overcall or double for takeout)
	// 5: if we have 12+ pts and playing takeout doubles, cannot have a 
	//    hand suitable for a takeout (???)

	// test conditions 1, 2, & 4
	if ( ((bidState.nRHOBid >= BID_1C) && (bidState.nRHOBid <= BID_1S)) &&
		 ( ((bidState.fPts >= OPEN_PTS(6)) && (bidState.fPts <= OPEN_PTS(11))) || ((bidState.fPts >= OPEN_PTS(17))/*&& (bidState.fPts <= 18)*/) ) &&
 		  (bidState.m_numBidTurns == 0) && (bidState.m_numPartnerBidTurns == 0) )
	{
		 // passed
	}
	else
	{
		return FALSE;
	}

	// test condition #3
	int nOppSuit = bidState.nRHOSuit;
	BOOL bEnoughLength = FALSE;
	//
	if (ISMINOR(nOppSuit))
	{
		// need 5/5 in the majors, or 5 + good 4
		int numHearts = hand.GetNumCardsInSuit(HEARTS);
		int numSpades = hand.GetNumCardsInSuit(SPADES);
		if ((hand.GetSuitStrength(HEARTS) < SS_MARGINAL_OPENER) || (hand.GetSuitStrength(SPADES) < SS_MARGINAL_OPENER) ||
			(Abs(hand.GetSuitStrength(HEARTS) - hand.GetSuitStrength(SPADES)) > 1) )
			return FALSE;
		//
		if ((numHearts >= 5) && (numSpades >= 5))
		{
			bEnoughLength = TRUE;
			status << "2MCL1! We have at least 5/5 in the majors, so we can make a Michaels cue bid.\n";
		}
		else if ((numHearts >= 5) && (numSpades == 4) && 
						(hand.GetSuitStrength(SPADES) >= SS_STRONG))
		{
			bEnoughLength = TRUE;
			status << "2MCL2! We have 5/4 in the majors, but the 4 Spades are strong, so we can make a Michaels cue bid.\n";
		}
		else if ((numHearts == 4) && (numSpades >= 5) && (hand.GetSuitStrength(HEARTS) >= SS_STRONG))
		{
			bEnoughLength = TRUE;
			status << "2MCL3! We have 5/4 in the majors, but the 4 Hearts are strong, so we can make a Michaels cue bid.\n";
		}
	}
	else
	{
		// need 5 in the unbid major, and 5 in a minor
		int nOtherMajor = (nOppSuit == HEARTS)? SPADES : HEARTS;
		int numMajors = hand.GetNumCardsInSuit(nOtherMajor);
		int numClubs = hand.GetNumCardsInSuit(CLUBS);
		int numDiamonds = hand.GetNumCardsInSuit(CLUBS);

		// check that the major suit is OK
		if ((numMajors < 5) || (hand.GetSuitStrength(nOtherMajor) < SS_MARGINAL_OPENER))
			return FALSE;

		// then check the minor & compare the suits
		if ((numClubs >= 5) && (hand.GetSuitStrength(CLUBS) >= SS_MARGINAL_OPENER) &&
			(Abs(hand.GetSuitStrength(nOtherMajor) - hand.GetSuitStrength(CLUBS)) <= 1) )
		{
			bEnoughLength = TRUE;
			status << "2MCL5! We have 5+ cards in " & STS(nOtherMajor) & 
					  " and 5+ cards in a minor (Clubs), so we can make a Michaels cue bid.\n";
		}
		else if ((numDiamonds >= 5) && (hand.GetSuitStrength(DIAMONDS) >= SS_MARGINAL_OPENER) &&
				(Abs(hand.GetSuitStrength(nOtherMajor) - hand.GetSuitStrength(DIAMONDS)) <= 1) )
		{
			bEnoughLength = TRUE;
			status << "2MCL5! We have 5+ cards in " & STS(nOtherMajor) & 
					  " and 5+ cards in a minor (Diamonds), so we can make a Michaels cue bid.\n";
		}
	}

	// check condition
	if (!bEnoughLength)
		return FALSE;

	// OK, go ahead and cue-bid the enemy suit
	int nBid = MAKEBID(nOppSuit, 2);
	status << "MCL9! With a 2-suited hand, make a Michaels cue bid over RHO's " & STS(nOppSuit) & 
			  " with a bid of " & BTS(nBid) & ".\n";
	bidState.SetBid(nBid);
	bidState.SetConventionStatus(this, CONV_INVOKED);
	return TRUE;
}
//
//==========================================================
//
// Rebidding as opener after partner responds to a takeout double
//
BOOL CNegativeDoublesConvention::HandleConventionResponse(const CPlayer& player, 
														  const CConventionSet& conventions, 
														  CHandHoldings& hand, 
														  CCardLocation& cardLocation, 
														  CGuessedHandHoldings** ppGuessedHands,
														  CBidEngine& bidState,  
														  CPlayerStatusDialog& status)
{
	// there's no code here for now
	return FALSE;

  
	// check status
	if ((bidState.GetConventionStatus(this) != CONV_INVOKED_ROUND1) &&
		(bidState.GetConventionStatus(this) != CONV_INVOKED_ROUND2))
		return FALSE;

	//
	// get some info
	//
//	int nBid;
	double fPts = bidState.fPts;
	double fAdjPts = bidState.fAdjPts;
	double fCardPts = bidState.fCardPts;
	int nPrefSuit = bidState.nPrefSuit;
	int nPrefSuitStrength = bidState.nPrefSuitStrength;
	int nPreviousSuit = bidState.nPreviousSuit;
	BOOL bBalanced = bidState.bBalanced;
	//
	int nPartnersBid = bidState.nPartnersBid;
	int nPartnersBidLevel = bidState.nPartnersBidLevel;
	int nPartnersSuit = bidState.nPartnersSuit;
	int nPartnersSuitSupport = bidState.nPartnersSuitSupport;
	int nPartnersPrevSuit = bidState.nPartnersPrevSuit;
	int numSupportCards = bidState.numSupportCards;

	// first check for a strange response
	if ((nPartnersBid == BID_DOUBLE) || (nPartnersBid == BID_REDOUBLE))
	{
		// we don't understand partner's bid
		return CConvention::HandleConventionResponse(player, conventions, hand, cardLocation, ppGuessedHands, bidState, status);
	}

	//
	if (bidState.GetConventionStatus(this) == CONV_INVOKED_ROUND1) 
	{
		//
		//--------------------------------------------------------
		// responding to partner's forced bid
		// - estimate partner's strength
		//

		//
		// did partner pass? (horror of horrors!)
		//
		if (nPartnersBid == BID_PASS) 
		{
			if (bidState.nLHOBid >= BID_PASS)
				status << "NGDRb10! After interference from the left-hand opponent, partner passed our takeout.\n";
			else
				status << "NGDRb12! Partner unexpectedly passed our takeout double, which is supposed to be forcing.  Bidding will proceed as if the takeout was not made\n";
			bidState.SetConventionStatus(this, CONV_FINISHED);
			return FALSE;
		}

		// set team point estimates -- be conservative
		BOOL bPartnerJumped = FALSE;
		BOOL bPartnerJumpedToGame = FALSE;
		int nEnemyBid = pDOC->GetValidBidRecord(0);
		int nEnemyBidLevel = BID_LEVEL(nEnemyBid);
		int nEnemySuit = BID_SUIT(nEnemyBid);
		if (nPartnersBidLevel > (nEnemyBidLevel + 1))
			bPartnerJumped = TRUE;
		if (nPartnersBid == bidState.GetGameBid(nPartnersSuit))
			bPartnerJumpedToGame = TRUE;
		// flag to see if we doubled in preference to an overcall
		BOOL bWantedToOvercall = FALSE;

		//
		if (nPartnersSuit == NOTRUMP)
		{
			//
			if (nPartnersBid == BID_1NT)
			{
				// partner has 6-9 HCPs
				bidState.m_fPartnersMin = 6;
				bidState.m_fPartnersMax = 9;
			}
			else if (nPartnersBid == BID_2NT)
			{
				// partner has 10-12 HCPs, maybe more
				bidState.m_fPartnersMin = 10;
				bidState.m_fPartnersMax = 12;
			}
			else if (nPartnersBid == BID_3NT)
			{
				// partner has 13+ HCPs
				bidState.m_fPartnersMin = 13;
				bidState.m_fPartnersMax = 40 - fCardPts;
				status << "NGDRb20! Partner's response of 3NT to our takeout double indicates that the opponent's suit is well stopped.\n";
			}
			else
			{
				// partner has 13+ HCPs???
				status << "NGDRb21! Partner's response of " & BTS(nPartnersBid) & 
						  " to our takeout double is unorthodox; treating it like a 3NT response.\n";
				bidState.m_fPartnersMin = 13;
				bidState.m_fPartnersMax = MIN(22, 40 - fCardPts);
			}
			// accept NT if we hold at least a semi-balanced 
			// and we don't have a 6-card major
			if ( !(ISMAJOR(bidState.nPrefSuit) && (bidState.numPrefSuitCards >= 6)) &&
				 (bidState.bSemiBalanced) )
				bidState.m_nAgreedSuit = NOTRUMP;
			//
			bidState.m_fMinTPPoints = fAdjPts + bidState.m_fPartnersMin;
			bidState.m_fMaxTPPoints = fAdjPts + bidState.m_fPartnersMax;
			bidState.m_fMinTPCPoints = fCardPts + bidState.m_fPartnersMin;
			bidState.m_fMaxTPCPoints = fCardPts + bidState.m_fPartnersMax;
			status << "NGDRb29! Partner's response of " & BTS(nPartnersBid) & 
					  " to our takeout double indicates " & 
					  bidState.m_fPartnersMin & "-" & bidState.m_fPartnersMax & 
					  " HCPs, for a total of " &
					  bidState.m_fMinTPCPoints & "-" & bidState.m_fMaxTPCPoints & " / " &
					  bidState.m_fMinTPPoints & "-" & bidState.m_fMaxTPPoints & 
					  " pts in the partnership.\n";

		}
		else
		{
			// partner bid a suit
			// see if we really intended to overcall last time
			if (bidState.GetConventionStatus(&overcallsConvention) == CONV_SUBSUMED)
				bWantedToOvercall = TRUE;
			//
			if (nPartnersSuit == nEnemySuit)
			{
				// partner bid the enemy suit, showing 13+ pts.
				status << "NEGDRb40! Partner has responded in the enemy suit, indicating 13+ pts but no long suits.\n";
				bidState.m_fPartnersMin = 13;
				bidState.m_fPartnersMax = MIN(22, 40 - bidState.fCardPts);
				bidState.m_bGameForceActive = TRUE;
			}
			else if (bPartnerJumpedToGame)
			{
				// partner had 13+ pts & a 5-card major
				status << "NEGDRb41! Partner has jumped to game in " & STS(nPartnersSuit) &
						  ", indicating 13+ pts and a 5+ card suit.\n";
				bidState.m_fPartnersMin = 30;
				bidState.m_fPartnersMax = MIN(22, 40 - bidState.fCardPts);
				if (!bWantedToOvercall)
					bidState.m_nAgreedSuit = nPartnersSuit;
			}
			else if (bPartnerJumped)
			{
				// partner had 10-12 pts
				status << "NEGDRb42! Partner has made a jump response of " & BTS(nPartnersBid) &
						  ", indicating 10-12 pts and a 4-5 card suit.\n";
				bidState.m_fPartnersMin = 10;
				bidState.m_fPartnersMax = 12;
				if (!bWantedToOvercall)
					bidState.m_nAgreedSuit = nPartnersSuit;
			}
			else
			{
				// partner had <= 9 pts
				status << "NEGDRb43! Partner has made a minimum response of " & BTS(nPartnersBid) &
						  ", indicating no more than 9 points.\n";
				bidState.m_fPartnersMin = 0;
				bidState.m_fPartnersMax = 9;
				if (!bWantedToOvercall)
					bidState.m_nAgreedSuit = nPartnersSuit;
			}
			//
			bidState.m_fMinTPPoints = fAdjPts + bidState.m_fPartnersMin;
			bidState.m_fMaxTPPoints = fAdjPts + bidState.m_fPartnersMax;
			bidState.m_fMinTPCPoints = fCardPts + bidState.m_fPartnersMin;
			bidState.m_fMaxTPCPoints = fCardPts + bidState.m_fPartnersMax;
			status << "NGDRb49! The total point count in the partnership is therefore " &
					  bidState.m_fMinTPPoints & "-" & bidState.m_fMaxTPPoints & 
					  " pts.\n";
		}

			
		//
		// see if RHO bid after partner's response -- that mitigates our responsibility
		// to bid again, unless partner's bid was game forcing
		//
	//	if (bidState.nRHOBid > BID_PASS)
		if ((bidState.nRHOBid > BID_PASS) && 
			(bidState.nRHOBid != BID_DOUBLE) && (bidState.nRHOBid != BID_REDOUBLE))
		{
			status << "2NGDRb51! The right-hand opponent has " &
					  ((bidState.nRHOBid == BID_DOUBLE)? "doubled" : "bid") &
					  " after partner's response, interfering with our communication.\n";
		}


		//
		//---------------------------------------------------------------------
		// see if we have an agreed suit
		//
		int nBid;
		if (bidState.m_nAgreedSuit > NONE)
		{
			if (bidState.m_nAgreedSuit == NOTRUMP)
			{
				// we've agreed to play in NoTrump
				// see if we can raise partner to a higher NT contract
				if (bidState.BidNoTrumpAsAppropriate(FALSE,STOPPED_DONTCARE))
				{
					bidState.SetConventionStatus(this, CONV_FINISHED);
					return TRUE;
				}
				// else pass
				nBid = BID_PASS;
				status << "NGDRb69! With a total of " &
						  bidState.m_fMinTPCPoints & "-" & bidState.m_fMaxTPCPoints &
						  " HCPs in the partnership, we have insufficient strength to raise partner's " &
						  BTS(nPartnersBid) & " bid, so we have to pass.\n";
				bidState.SetBid(nBid);
				bidState.SetConventionStatus(this, CONV_FINISHED);
				return TRUE;
			}
			else
			{
				// we've agreed on a suit, so raise if possible
				// if partner didn't jump, we may have credited him with
				// zero pts, so adjust rqmts accordingly

				// if partner jumped to game && we have < 32 pts, pass
				if ((bPartnerJumpedToGame) && (bidState.m_fMinTPPoints < 32))
				{
					status << "NGDRb70! Partner jumped to game in his " & bidState.szPSS & 
							  " suit, so with a team total of " &
							  bidState.m_fMinTPPoints & "-" & bidState.m_fMaxTPPoints &
							  " points, we pass.\n";
					bidState.SetBid(BID_PASS);
					bidState.SetConventionStatus(this, CONV_FINISHED);
					return TRUE;
				}
				// raise partner if possible -- bearing in mind that 
				// partner may have a wide range of points

				// raise a major to game with 23-31 pts and 4 trumps
				//					  or with 26-31 pts and 3 trumps
				// or raise to the 3-level with 20-24 pts and 3 trumps
				if ( (bidState.RaisePartnersSuit(SUIT_MAJOR,RAISE_TO_4,PTS_MAJOR_GAME-3,31,SUPLEN_4)) ||
				     (bidState.RaisePartnersSuit(SUIT_MAJOR,RAISE_TO_4,PTS_MAJOR_GAME,31,SUPLEN_3)) ||
					 (bidState.RaisePartnersSuit(SUIT_MAJOR,RAISE_TO_3,PTS_MAJOR_GAME-6,24,SUPLEN_3)))
				{
					if (!bPartnerJumped)
						status << "NGDRb71a! (we can assume partner has some strength in the " & bidState.szPSS & 
								  " suit, so we are shading the requirements slightly.\n";
					bidState.SetConventionStatus(this, CONV_INVOKED_ROUND2);
					return TRUE;
				}
				// raise a minor to game with 28-32 pts and 4 trumps
				//                    or with 29-32 pts and 3 trumps
				// or raise to the 4-level with 26-28 pts and 3 trumps
				// or raise to the 3-level with 23-25 pts and 3 trumps
				if ( (bidState.RaisePartnersSuit(SUIT_MINOR,RAISE_TO_5,PTS_MINOR_GAME-1,PTS_SLAM-1,SUPLEN_4)) ||
					 (bidState.RaisePartnersSuit(SUIT_MINOR,RAISE_TO_5,PTS_MINOR_GAME,PTS_SLAM-1,SUPLEN_3)) ||
					 (bidState.RaisePartnersSuit(SUIT_MINOR,RAISE_TO_4,PTS_MINOR_GAME-3,PTS_MINOR_GAME-1,SUPLEN_3)) ||
					 (bidState.RaisePartnersSuit(SUIT_MINOR,RAISE_TO_3,PTS_MINOR_GAME-6,PTS_MINOR_GAME-4,SUPLEN_3)) )
				{
					if (!bPartnerJumped)
						status << "NGDRb71b! We can assume partner has some strength in the " & bidState.szPSS & 
								  " suit, so we can shade the requirements slightly.\n";
					bidState.SetConventionStatus(this, CONV_INVOKED_ROUND2);
					return TRUE;
				}
				// with 32+ pts, invoke Blackwood
				if (bidState.m_fMinTPCPoints >= 32)
				{
					bidState.InvokeBlackwood(bidState.m_nAgreedSuit);
					bidState.SetConventionStatus(this, CONV_INVOKED_ROUND2);
					return TRUE;
				}
				// else pass
				nBid = BID_PASS;
				status << "NGDRb90! With a total of " &
						  bidState.m_fMinTPPoints & "-" & bidState.m_fMaxTPPoints &
						  " points in the partnership, we have insufficient strength to raise partner's " &
						  BTS(nPartnersBid) & " bid, so we have to pass.\n";
				bidState.SetBid(nBid);
				bidState.SetConventionStatus(this, CONV_FINISHED);
				return TRUE;
			}
		}


		//
		//--------------------------------------------------------------------------
		// here, we have no suit agreement (e.g., partner bid the opponents' suit)
		//
		int nLastBid = pDOC->GetLastValidBid();
		if (bBalanced)
		{
			// try notrumps
			if (hand.IsSuitProbablyStopped(nEnemySuit))
			{
				status << "NGDRb80! Without clear suit agreement, and holding a blanaced hand, we want to steer towards a contract in No Trump.\n";
				if (bidState.BidNoTrumpAsAppropriate(FALSE,STOPPED_DONTCARE))
				{
					bidState.SetConventionStatus(this, CONV_INVOKED_ROUND2);
					return TRUE;
				}
			}
			// else pass
			status << "NGDRb81! But as we do not have a proper hand to bid No Trump at the appropriate level, we have to pass.\n";
			bidState.SetBid(BID_PASS);
			bidState.SetConventionStatus(this, CONV_FINISHED);
			return TRUE;
		}
		else if (bidState.numPrefSuitCards >= 5)
		{
			// bid the suit
			nBid = bidState.GetCheapestShiftBid(nPrefSuit, nLastBid);
			if (bidState.IsBidSafe(nBid, 4))
			{
				if (bWantedToOvercall)
					status << "NGDRb90! Partner's forced response of " & bidState.szPB & 
							 " not withstanding, we can now show the " & 
							  STSS(nPrefSuit) & " suit that we wanted to overcall with last round by bidding " &
							  BTS(nBid) & ".\n";
				else
					status << "NGDRb91! Without clear suit agreement, we bid our " &
							  bidState.numPrefSuitCards & "-card " & STSS(bidState.nPrefSuit) &
							  " suit at " & BTS(nBid) & ".\n";
				bidState.SetBid(nBid);
				bidState.SetConventionStatus(this, CONV_INVOKED_ROUND2);
				return TRUE;
			}
		}


		//
		//--------------------------------------------------------------------------
		// else we have no other options, so pass
		status << "NEGDRb99! We see no good fit with partner and no other options, so pass.\n";
		bidState.SetBid(BID_PASS);
		bidState.SetConventionStatus(this, CONV_FINISHED);
		return TRUE;

	}
	else
	{
		//
		// responding after partner's second response to our takeout
		//

		// did partner pass?
		if (nPartnersBid == BID_PASS) 
		{
			bidState.SetConventionStatus(this, CONV_FINISHED);
			return FALSE;
		}

		//
		// otherwise, consider the choices:
		//
		// - with suit agreement, raise if possible
		//         S    N     S     N     S
		//   e.g., X -> 1C -> 1S -> 2S -> ???
		// - without suit agreement,
		//   e.g., X -> 1C -> 1S -> 2H -? ???
		//   bid the 4th suit if we have the pts (26+)
		// - without suit agreement, but if partner bids NT,
		//   or if we have a balanaced hand, bid NT
		//
		double fMinTPPoints = bidState.m_fMinTPPoints;
		double fMaxTPPoints = bidState.m_fMaxTPPoints;
		double fMinTPCPoints = bidState.m_fMinTPCPoints;
		double fMaxTPCPoints = bidState.m_fMaxTPCPoints;
		int nBid;
		
		//
		// see if we have suit agreement
		//
		if (nPartnersSuit == nPreviousSuit)
		{
			// partner raised our suit -- re-raise if possible
			bidState.m_nAgreedSuit = nPreviousSuit;
			if (nPartnersBid >= bidState.GetGameBid(nPreviousSuit))
			{
				// partner bid game or beyond
				if ((nPartnersBidLevel == 7) ||
					((nPartnersBidLevel == 6) && (fMinTPPoints <= 36)) )
				{
					nBid = BID_PASS;
					status << "NGDRc10! Partner raised our " & bidState.szPVSS & 
							  " suit to a slam, so pass.\n";
				}
				else if ((nPartnersBidLevel <= 6) && (fMinTPPoints >= 37))
				{
					nBid = MAKEBID(nPreviousSuit, 7);
					status << "NGDRc11! Partner raised our " & bidState.szPVSS & 
							  " suit to " & 
							  ((nPartnersBidLevel == 6)? "slam" : "game") &
							  ", but we have the poitns to push to a grand slam, so bid " & 
							  BTS(nBid) & ".\n";
				}
				else if ((nPartnersBidLevel < 6) && (fMinTPPoints >= 33))
				{
					nBid = MAKEBID(nPreviousSuit, 6);
					status << "NGDRc12! Partner raised our " & bidState.szPVSS & 
							  " suit to game, but we have the poitns for a slam, so bid " & 
							  BTS(nBid) & ".\n";
				}
				else
				{
					nBid = BID_PASS;
					status << "NGDRc13! Partner raised our " & bidState.szPVSS & 
							  " suit to game, which is acceptable with " & 
							  fMinTPPoints & "-" & fMaxTPPoints & 
							  " pts in the partnership, so pass.\n";
				}
			}
			else
			{
				// partner raised below game
				// re-raise if possible
				if ( (ISMAJOR(nPreviousSuit) && (fMinTPPoints >= PTS_MAJOR_GAME)) ||
					 (ISMINOR(nPreviousSuit) && (fMinTPPoints >= PTS_MINOR_GAME)) )
				{
					nBid = bidState.GetGameBid(nPreviousSuit);
					status << "NGDRc20! With a total of " & 
							  fMinTPPoints & "-" & fMaxTPPoints & 
							  " pts in the partnership, raise to game in the " &
							  bidState.szPVSS & " suit at " & BTS(nBid) & ".\n";
				}
				else
				{
					// else try to raise cheaply
					nBid = bidState.GetCheapestShiftBid(nPreviousSuit);
					if (bidState.IsBidSafe(nBid))
					{
						status << "NGDRc22! With a total of " & 
								  fMinTPPoints & "-" & fMaxTPPoints & 
								  " pts in the partnership, we can raise again to " &
								  BTS(nBid) & ".\n";
					}
					else
					{
						nBid = BID_PASS;
						status << "NGDRc29! With a total of " & 
								  fMinTPPoints & "-" & fMaxTPPoints & 
								  " pts in the partnership, we cannot safely raise any partner further, so pass.\n";
					}
				}
			}
		}
		else if ((nPartnersSuit == NOTRUMP) || (bidState.bBalanced))
		{
			//
			// partner bid NT, or else we have a balanced hand
			//
			if (bidState.BidNoTrumpAsAppropriate(FALSE, STOPPED_DONTCARE))
			{
				nBid = bidState.m_nBid;
				status << "NGDRc30! With a total of " & 
						  fMinTPCPoints & "-" & fMaxTPCPoints & 
						  " HCPs in the partnership, we can bid " & BTS(nBid) & ".\n";
			}
			else
			{
				nBid = BID_PASS;
				if (nPartnersSuit == NOTRUMP)
					status << "NGDRc35! We're willing to accept a contract in NoTrumps, but don't have the points to raise further, so pass.\n";
				else
					status << "NGDRc36! We'd like to play in NoTrumps, but don't have the points to bid agian, so pass.\n";
			}
		}
		else
		{
			//
			// else we have no suit agreement, and can't play NT
			//

			//
			// bid the 4th suit if we have enough pts
			//
			int nSuit = bidState.GetFourthSuit(nPreviousSuit, nPartnersSuit, nPartnersPrevSuit);
			nBid = bidState.GetCheapestShiftBid(nSuit);

			if ((fMinTPPoints >= PTS_GAME) && (nBid < bidState.GetGameBid(nSuit)))
			{
				status << "NGDRc40! With a total of " & 
						  fMinTPPoints & "-" & fMaxTPPoints & 
						  " pts in the partnership and no suit agreement, bid another suit (" &
						  STS(nSuit) & ") at " & BTS(nBid) & ".\n";
			}
			else
			{
				// gotta pass
				nBid = BID_PASS;
				if (nPartnersBid >= bidState.GetGameBid(nPartnersSuit))
					status << "NGDRc45! With a total of " & 
							  fMinTPPoints & "-" & fMaxTPPoints & 
							  " pts in the partnership, partner has gone to game in his suit at " &
							  bidState.szPB & ", so pass.\n";
				else if (fMinTPPoints >= PTS_GAME)
					status << "NGDRc46! With a total of " & 
							  fMinTPPoints & "-" & fMaxTPPoints & 
							  " pts in the partnership, but having run out of bidding room, we have to bail out and pass.\n";
				else 
					status << "NGDRc47! With a total of only " & 
							  fMinTPPoints & "-" & fMaxTPPoints & 
							  " pts in the partnership, and no agreement in suits, we have to pass.\n";
			}
		}
		// done with the second rebid 
		bidState.SetBid(nBid);
		bidState.ClearConventionStatus(this);
		return TRUE;
	}
}
Example #17
0
//
//---------------------------------------------------------------
//
// MakeOpeningBid()
//
// make initial bid
//
int CBidEngine::MakeOpeningBid()
{
	CPlayerStatusDialog& status = *m_pStatusDlg;

	//
	status << "2Opening bid for team.\n";



	//
	//--------------------------------------------------------
	//
	// First check to see if we can open using a convention
	// e.g., weak 2, stong 2, preemptive 3/4, etc.
	//
	if (pCurrConvSet->ApplyConventionTests(*m_pPlayer, *m_pHand, *m_pCardLocation, m_ppGuessedHands, *this, *m_pStatusDlg))
	{
		return ValidateBid(m_nBid);
	}




	//
	//--------------------------------------------------------
	//
	// see if we can open No Trumps
	//

	int	NTMin[3], NTMax[3];
	//
	NTMin[0] = pCurrConvSet->GetValue(tn1NTRangeMinPts);
	NTMax[0] = pCurrConvSet->GetValue(tn1NTRangeMaxPts);
	NTMin[1] = pCurrConvSet->GetValue(tn2NTRangeMinPts);
	NTMax[1] = pCurrConvSet->GetValue(tn2NTRangeMaxPts);
	NTMin[2] = pCurrConvSet->GetValue(tn3NTRangeMinPts);
	NTMax[2] = pCurrConvSet->GetValue(tn3NTRangeMaxPts);

	//
	if ((bBalanced) && (fCardPts >= OPEN_PTS(NTMin[0]))) 
	{
		//
		status << "A00! Have " & fCardPts & " HCP's with a balanced hand.\n";

		// but if we have a good 5-card major, open it in a suit
		// but not if we have to overcall to do so
		BOOL bNeedToOvercall = FALSE;
		if ( ((nLHOBid > BID_PASS) || (nRHOBid > BID_PASS)) && (nPartnersBid <= BID_PASS))
			bNeedToOvercall = TRUE;
		//
		if (IsSuitOpenable(HEARTS) && !bNeedToOvercall)
		{
			status << "A02! But with an openable " & numCardsInSuit[HEARTS] &
					  "-card Heart suit, prefer to open in the major instead of in No Trump.\n";
			goto escape1;
		}
		if (IsSuitOpenable(SPADES) && !bNeedToOvercall) 
		{
			status << "A04! But with an openable " & numCardsInSuit[SPADES] &
					  "-card Spade suit, prefer to open in the major instead of in No Trump.\n";
			goto escape1;
		}

		// check range for 1NT
		// NCR-285 Need stopper if opponents have bid!!!
		BOOL bHaveOppsStopped = TRUE;
		if ((nRHOBid != BID_PASS) && ISSUIT(nRHOSuit))
			bHaveOppsStopped = m_pHand->IsSuitStopped(nRHOSuit);  // NCR-285 consider if their suit is stopped
		else if ((nLHOBid != BID_PASS) && ISSUIT(nLHOSuit))
			bHaveOppsStopped = m_pHand->IsSuitStopped(nLHOSuit);  // NCR-285 ditto

		if ((fCardPts >= OPEN_PTS(NTMin[0])) && (fCardPts <= NTMax[0]) && bHaveOppsStopped) // NCR-285 added test
		{
			// NCR-18 Check if RHO bid NT and double 
			if(nRHOBid == BID_1NT){
				m_nBid = BID_DOUBLE;	// NCR-337 Problem here. This is not a Takeout double???
				status << "A07! This meet the rqmts for the 1NT opening range (" & NTMin[0] & "-" & NTMax[0] 
						& "), but RHO has bid 1NT, so Double.\n";
			}else {
				// open 1NT
				m_nBid = BID_1NT;
				status << "A08! This meet the rqmts for the 1NT opening range (" & NTMin[0] & "-" & NTMax[0] & "), so bid 1NT.\n";
			}
			return ValidateBid(m_nBid);
			
		} 
		else if ((fCardPts > OPEN_PTS(NTMax[0])) && (fCardPts < NTMin[1])) 
		{
			// in-between 1 & 2 situation; bid interim suit
			m_nNextIntendedBid = NIB_JUMP_NT;
			if (numOpenableSuits > 0) 
			{
				// bid 1 of lowest openable suit
				m_nBid = GetLowestOpenableBid(SUITS_ANY,OT_OPENER,1);
				// NCR-335 Don't bid 4 card major with 5CardMajor convention
				if (ISMAJOR(BID_SUIT(m_nBid)) && pCurrConvSet->IsConventionEnabled(tid5CardMajors)
					&& (numCardsInSuit[BID_SUIT(m_nBid)] < 5) ) 
				{
					// Use Diamonds if 4, else clubs (have balanced hand here)
					Suit bidThis = numCardsInSuit[DIAMONDS] >= 4 ? DIAMONDS : CLUBS;
					m_nBid = MAKEBID(bidThis, 1);  // NCR-335 use minor
                }
				status << "A10! This exceeds the max pts for a 1NT opening (" & NTMax[0] & 
								 "), but is less than min pts for 2NT (" & NTMin[1] & 
								 ").  So bid the lowest openable suit of " & BTS(m_nBid) & 
								 " for now, then try for a jump shift to 2NT later.\n";
			} 
			else 
			{
				// go ahead and bid the preferred suit
				if (!pCurrConvSet->IsConventionEnabled(tid5CardMajors) )
				{
					m_nBid = MAKEBID(nPrefSuit,1);
				} 
				else 
				{
					m_nBid = BID_1C;
				}
				status << "A14! This exceeds the max pts for a 1NT opening (" & NTMax[0] &
					      "), but is less than min pts for 2NT (" & NTMin[1] &
						  " and we have no good openable suit, so just bid " & BTS(m_nBid) &
						  " for now.\n";
			}
			return ValidateBid(m_nBid);

		} 
		// NCR can't use 2NT if using unusual NT convention
		else if ((fCardPts >= OPEN_PTS(NTMin[1])) && (fCardPts <= NTMax[1]) 
//			     && !pCurrConvSet->IsConventionEnabled(tidUnusualNT)  // NCR not relevant for Opening???
				 // NCR test that hand does NOT have a worthless doubleton
				 && ((m_pHand->GetNumDoubletons() == 0)  // OK if no doubletons
				     || (m_pHand->GetNumDoubletons() >= 1) 
				         && !m_pHand->HasWorthlessDoubleton()) //or if its not worthless
				) 
		{
			// open 2NT
			m_nBid = BID_2NT;
			status << "A20! This meets the rqmts for a 2NT opening (" & 
					  NTMin[1] & "-" & NTMax[1] & "), so bid 2NT.\n";
			return ValidateBid(m_nBid);

		} 
		else if ((fCardPts >= OPEN_PTS(NTMax[1])) && (NTMin[2] < 0))  // NCR ??? see next else if
		{

			// > pts for 2NT, but 3NT opening not allowed  NCR what does not allowed mean???
			// so bid 2C
			m_nBid = BID_2C;
			status << "A30! This exceeds the max pts for a 2NT opening (" & NTMax[1] & 
					   "), but a 3NT opening has been disallowed, so open with " & BTS(m_nBid) & ".\n";
			return ValidateBid(m_nBid);

		} 
		else if ((fCardPts > OPEN_PTS(NTMax[1])) && (fCardPts < NTMin[2])) 
		{

			// in-between 2 & 3 situation; bid 2 of interim suit
			// and bid NT later
			m_nNextIntendedBid = NIB_NT;
			if (numOpenableSuits > 0) 
			{
				// bid 1 of lowest openable suit
				m_nBid = GetLowestOpenableBid(SUITS_ANY,OT_OPENER,1);
				status << "A40! This exceeds the max pts for a 2NT opening (" &
						  NTMax[1] & "), but is less than min pts for 3NT (" &
						  NTMin[2] & ").  So bid the lowest openable suit of " &
						  BTS(m_nBid) & " for now, then jump shift to NT later.\n";
			} 
			else 
			{
				// no good openable suits; just bid preferred suit
				m_nBid = MAKEBID(nPrefSuit,1);;
				status << "A42! This exceeds the max pts for a 2NT opening (" &
						  NTMax[1] & "), but is less than min pts for 3NT (" &
						  NTMin[2] & "), and have no good openable suit, so bid " &
						  BTS(m_nBid) & " for now.\n";
			}
			return ValidateBid(m_nBid);

		} 
		else if ((fCardPts >= OPEN_PTS(NTMin[2])) && (fCardPts <= NTMax[2])
				 // NCR test that hand does NOT have a worthless doubleton
				 && ((m_pHand->GetNumDoubletons() == 0)  // OK if no doubletons
				     || (m_pHand->GetNumDoubletons() >= 1) 
				         && !m_pHand->HasWorthlessDoubleton()) //or if its not worthless

			     ) 
		{
			// open 3NT
			m_nBid = BID_3NT;
			status << "A50! Bid 3NT.\n";
			return ValidateBid(m_nBid);
		} 
/*  NCR remove falling into a 3NT bid
		else // if(!pCurrConvSet->IsConventionEnabled(tidUnusualNT)) // NCR added Unusual test??? 
		{
			// > 3NT point range? unusual, but open 3NT for now
			m_nBid = BID_3NT;
			status << "A60! bid 3NT with balanced hand and " & fCardPts & " points.\n"; // NCR
			return ValidateBid(m_nBid);
		}
*/
	}  // end balanced hand with > min pts

escape1:


		



	//
	//-------------------------------------------------------------------
	//
	// See if we can open at the 1-level
	//
	// open at the 1-level if we have:
	//  1:  14+ points in high cards
	//  2:  13+ HCPs with 2 Quick Tricks
	//  3:  12+ HCPs with 2 QTs and a rebiddable suit
	//  4:  12+ HCPs with 2 QTs and a 5-card suit
	//  5:  12+ HCPs with balanced dist (weak NT mode only)
	//  6:  10+ HCPs opening in 3rd or 4th seat and a good suit  NCR ???
	//  7:  15+ Total points with 2 QTs
	//  8:  14+ Total points with 2 QTs and a rebiddable suit
	//  9:  13+ Total points with 2 QTs and a rebiddable suit of 6+ cards
	//
	
	// we can only open if the opponents haven't opened yet
	// if they have, the COvercallsCovention object should have looked into
	// a posssible overcall.
	if ((nLHOBid > BID_PASS) || (nRHOBid > BID_PASS))
	{
		status << "B00! We cannot overcall and the hand is not appropriate for any other bid, so pass.\n";
		m_nBid = BID_PASS;
		return ValidateBid(m_nBid);
	}

	// the suit to open us usually the best suit
	nSuit = GetBestOpeningSuit();

	// case 1:  14+ points in high cards
	if (fCardPts >= OPEN_PTS(14)) 
	{
		m_nBid = MAKEBID(nSuit,1);
		status << "E01! Have " & fCardPts & " points in high cards, so bid " & BTS(m_nBid) & ".\n";
		return ValidateBid(m_nBid);
	}
	// case 2:  13+ HCP's && 2 QT's
	if ((fCardPts >= OPEN_PTS(13)) && (numQuickTricks >= 2)) 
	{
		m_nBid = MAKEBID(nSuit,1);
		status << "E02! Have " & fCardPts & " points in high cards and " & numQuickTricks & 
				  " quick tricks, so bid " & BTS(m_nBid) & ".\n";
		return ValidateBid(m_nBid);;
	}
	// case 3:  12+ HCP's, 2 QT's, & a rebiddable suit
	// NCR-680  reduce QTs
	if ((fCardPts >= OPEN_PTS(12)) && (numQuickTricks >= PT_COUNT(2)) && 
								(numRebiddableSuits > 0)) 
	{
		m_nBid = MAKEBID(nSuit,1);
		status << "E03! Have " & fCardPts & " points in high cards, " & numQuickTricks &
				  " quick tricks, and a rebiddable suit in " & STS(nSuit) & 
				  ", so bid " & BTS(m_nBid) & ".\n";
		return ValidateBid(m_nBid);;
	}
	// case 4:  12+ HCP's, 2 QT's, & a 5-card suit
	if ((fCardPts >= OPEN_PTS(12)) && (numQuickTricks >= 2) && 
							(m_pHand->GetNumSuitsOfAtLeast(5) > 0)) 
	{
		m_nBid = MAKEBID(nSuit,1);
		status << "E04! Have " & fCardPts & " points in high cards, " & numQuickTricks & 
				  " quick tricks, and a " & numCardsInSuit[nSuit] & 
				  "-card suit, so bid " & BTS(m_nBid) & ".\n";
		return ValidateBid(m_nBid);
	}
	// case 5:  12+ HCP's & a balanced dist in Weak NTs
	if ((fCardPts >= OPEN_PTS(12)) && (bBalanced) && 
				(pCurrConvSet->GetValue(tn1NTRange) == 0)) 
	{
		m_nBid = BID_1NT;
		status << "E05! Have " & fCardPts & " points in high cards, a balanced hand, " &
				  "and playing Weak No Trumps, so bid " & BTS(m_nBid) & ".\n";
		return ValidateBid(m_nBid);
	}
	// case 6:  10+ HCPs opening in 3rd or 4th seat & a good suit
//	if ((fCardPts >= OPEN_PTS(10)) 
	if ((fCardPts >= 10)  // NCR-206 Hard 10  and > 4 cards  
		 && (((nBiddingOrder == 2) && (numCardsInSuit[nSuit] > 4)) 
		                              // NCR require Having spades to open light in 4th
		     || ((nBiddingOrder == 3) & (numCardsInSuit[SPADES] > 3))
		                              && (nSuit == SPADES))
		 &&	(numOpenableSuits > 0)) 
	{
		m_nBid = MAKEBID(nSuit,1);
		status << "E07! Have " & fCardPts & " points in high cards in " 
				  & ((nBiddingOrder == 2)? "3rd" :  "4th") &
				  " position and a " & SSTS(nSuit) & " " & STSS(nSuit) & 
				  " suit, so bid " & BTS(m_nBid) & ".\n";
		return ValidateBid(m_nBid);
	}
	// case 7:  15+ Total points and 10 HCPs, with 2 QTs
	if ((fPts >= OPEN_PTS(15)) && (fCardPts >= OPEN_PTS(10)) && (numQuickTricks >= 2)) 
	{
		m_nBid = MAKEBID(nSuit,1);
		status << "E08! Have " & fCardPts & "/" & fPts & " total points with " 
				  & numQuickTricks & " QT's, so bid " & BTS(m_nBid) & ".\n";
		return ValidateBid(m_nBid);
	}
	//
	// case 8:  14+ Total points with 10+ HCPs, 2 QTs 
	// and a rebiddable suit
	if ((fPts >= OPEN_PTS(14)) && (fCardPts >= OPEN_PTS(10)) && 
		(numQuickTricks >= 2) && (numRebiddableSuits > 0)) 
	{
		m_nBid = MAKEBID(nSuit,1);
		status << "E09! Have " & fCardPts & "/" & fPts & " total points with "
				  & numQuickTricks & " QT's and a rebiddable suit, so bid "
				  & BTS(m_nBid) & ".\n";
		return ValidateBid(m_nBid);;
	}
	//
	// case 9:  13+ Total points with 10+ HCPs, 2 QTs and a 
	// rebiddable suit of 6+ cards
	if ((fPts >= OPEN_PTS(13)) && (fCardPts >= OPEN_PTS(10)) && 
		(numQuickTricks >= 2) && (numRebiddableSuits > 0) && 
		(numPrefSuitCards >= 6) &&
		(nSuitStrength[nPrefSuit] > SS_OPENABLE)) 
	{
		m_nBid = MAKEBID(nSuit,1);
		status << "E10! Have " & fCardPts & "/" & fPts & " total points with "
				  & numQuickTricks & " QT's and a " & numCardsInSuit[nSuit] & 
				  "-card rebiddable suit, so bid " & BTS(m_nBid) & ".\n";
		return ValidateBid(m_nBid);
	}



	//
	//---------------------------------------------------------
	//
	// now test for optional 1-level openings
	//
	int nAllowed1Opens = pCurrConvSet->GetValue(tnAllowable1Openings);

	//
	// option 1:  11+ HCPs with 2 QTs, a rebiddable suit, &
	// length in both majors
	//
	if ((nAllowed1Opens & OB_11_HCPS_RBS_LM) && (fCardPts >= OPEN_PTS(11)) && 
		(numQuickTricks >= 2) && (numRebiddableSuits > 0) &&
		(numCardsInSuit[HEARTS] >= 4) && (numCardsInSuit[SPADES] >= 4)) 
	{
		m_nBid = MAKEBID(nSuit,1);
		status << "E21! Have " & fCardPts & " points in high cards, " & numQuickTricks & 
				   " quick tricks, a rebiddable suit, and length in both majors " &
				   "(optional opening condition #1), so bid " & BTS(m_nBid) & ".\n";
		return ValidateBid(m_nBid);
	}
	//
	// option 2:  11+ HCPs with 2 QTs and a 6-card suit
	//
	if ((nAllowed1Opens & OB_11_HCPS_6CS) && (fCardPts >= OPEN_PTS(11)) && 
				(numQuickTricks >= 2) && 
				(m_pHand->GetNumSuitsOfAtLeast(6) > 0)) 
	{
		m_nBid = MAKEBID(nSuit,1);
		status << "E22! Have " & fCardPts & " points in high cards with " & numQuickTricks & 
			      " QT's and a " & numCardsInSuit[nSuit] & 
				  "-card suit (optional opening condition #2), so bid " & BTS(m_nBid) & ".\n";
		return ValidateBid(m_nBid);;
	}
	//
	// option 3:  14+ Total points with 10 HCPs, 2 QTs, and a 
	// good suit
	//
	if ((nAllowed1Opens & OB_14_TCPS_GS) && 
				(fPts >= OPEN_PTS(14)) && (fCardPts >= OPEN_PTS(10)) && 
				(numQuickTricks >= 2) && (numSolidSuits > 0)) 
	{
		m_nBid = MAKEBID(nSuit,1);
		status << "E23! Have " & fCardPts & "/" & fPts & "total points with " & numQuickTricks &
				  " QT's and a " & SSTS(nSuit) & " " & STSS(nSuit) & 
				  " suit (optional opening condition #3), so bid " & BTS(m_nBid) & ".\n";
		return ValidateBid(m_nBid);;
	}
	//
	// option 4:  14+ Total points with 10 HCPs, 2 QTs, and a 
	// long suit (6+ cards)
	//
	if ((nAllowed1Opens & OB_14_TCPS_LS) && 
		(fPts >= OPEN_PTS(14)) && (fCardPts >= OPEN_PTS(10)) && 
		(numQuickTricks >= 2) && 
		(m_pHand->GetNumSuitsOfAtLeast(6) > 0)) 
	{
		m_nBid = MAKEBID(nSuit,1);
		status << "E24! Have " & fCardPts & "/" & fPts & " total points with " & numQuickTricks &
				  " QT's and a " & numCardsInSuit[nSuit] &"-card " & STSS(nSuit) & 
				  " suit (optional opening condition #4), so bid " & BTS(m_nBid) & ".\n";
		return ValidateBid(m_nBid);;
	}
	//
	// option 5:  13+ Total points with 2 QTs, 10 HCPs,
	// and a 6-card suit
	//
	if ((nAllowed1Opens & OB_13_TCPS_LS) && 
		      // NCR-390 Add in distribution points here and below in status msg
		((fPts + fDistPts) >= OPEN_PTS(13)) && (fCardPts >= OPEN_PTS(10)) && 
		(numQuickTricks >= 2) && 
		(m_pHand->GetNumSuitsOfAtLeast(6) > 0)) 
	{
		m_nBid = MAKEBID(nSuit,1);
		status << "E25! Have " & fCardPts & "/" & (fPts+fDistPts) &" total points with " & numQuickTricks &
				  " QT's and a " & numCardsInSuit[nSuit] & "-card " & STSS(nSuit) & 
				  " suit (optional opening condition #5), so bid " & BTS(m_nBid) & ".\n";
		return ValidateBid(m_nBid);
	}

/*
	//
	// special case:  13 pts + 1 for every 0.5 QTs missing
	if ((fPts > OPEN_PTS(13)) && (numQuickTricks < 2)) 
	{
		int nRqmt = 13 + (int)(((2.0 - numQuickTricks)*2));
		if (fPts >= nRqmt) 
		{
			m_nBid = MAKEBID(nSuit,1);
			status << "E27! Have " & fCardPts & "/" & fPts & 
					  " total points; shade opening requirement of 2 QT's and make do with " & numQuickTricks &
					  " QT's in light of the high total point count; open " & BTS(m_nBid) & ".\n";
			return ValidateBid(m_nBid);;
		}
	}
*/
	// NCR-356 Loosen up a bit here - bid 5 card major if ...
	if((fCardPts >= OPEN_PTS(13)) &&  ISMAJOR(nSuit) && (numCardsInSuit[nSuit] >= 5)
		&& pCurrConvSet->IsConventionEnabled(tid5CardMajors) )
	{
		m_nBid = MAKEBID(nSuit,1);
		status << "E28! Have " & fCardPts & "/" & fPts & 
				  " total points; shade opening requirement of 2 QT's and make do with " & numQuickTricks &
				  " QT's; open " & BTS(m_nBid) & ".\n";
		return ValidateBid(m_nBid);;
	} // end NCR-356


	// NCR Is Convenient minor (goes with 5card Majors) appropriate - 13 HCPs and 3 clubs
	if((fCardPts >= OPEN_PTS(13)) && pCurrConvSet->IsConventionEnabled(tid5CardMajors)
		&& (numCardsInSuit[CLUBS] >= 3)) 
	{
		m_nBid = BID_1C;
		if(numCardsInSuit[DIAMONDS] > numCardsInSuit[CLUBS]) // NCR-507 Bid Diamonds if more of them
			m_nBid = BID_1D;
		status << "E31! Have " & fCardPts & " points in high cards , so bid a Convenient minor "
			        & BTS(m_nBid) & ".\n";
		return ValidateBid(m_nBid);
	}

	//
	//--------------------------------------------------------
	//
	// All attempts at opening failed, so return a PASS
	//
	status << "Z00! Hand is insufficient for any opening, so pass.\n";
	m_nBid = BID_PASS;
	return ValidateBid(m_nBid);;				

}
//
//===============================================================================
//
// RespondToConvention()
//
// partner bid at the 2-level (strong 2 bid)
//
// in general, partner's opening 2-bid denotes an extremely
// powerful hand.  So the question is whether to try for game
// or slam.  Therefore, we respond positively if we want attempt 
// a slam, or negatively for game
//
BOOL CStrongTwoBidsConvention::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())
		return FALSE;

	//
	// Bidding in response to an opening strong 2 bid? check requirements
	//
	int nPartnersBid = bidState.nPartnersBid;
	int nPartnersBidLevel = bidState.nPartnersBidLevel;
	int nPartnersSuit = bidState.nPartnersSuit;
	int nPartnersSuitSupport = bidState.nPartnersSuitSupport;
	int numSupportCards = bidState.numSupportCards;
	int numPartnerBidsMade = bidState.m_numPartnerBidsMade;
	//
	//
	// partner must've bid at the 2 level, but not 2C,
	// and partner's bid must have been the first bid made
	//
	if ((nPartnersBidLevel == 2) && (nPartnersBid != BID_2C) &&
					(bidState.m_bPartnerOpenedForTeam) &&
					(numPartnerBidsMade == 1) &&
					(nPartnersBid == pDOC->GetValidBidRecord(0)))
	{
		// okay, met requirements
	}
	else
	{
		// 
		return FALSE;
	}

	//
	int nBid;
	double fPts = bidState.fPts;
	double fAdjPts = bidState.fAdjPts;
	double fCardPts = bidState.fCardPts;
	int nPrefSuit = bidState.nPrefSuit;
	int numPrefSuitCards = bidState.numPrefSuitCards;
	double numQuickTricks = bidState.numQuickTricks;

	// state expectations
	bidState.m_fPartnersMin = 16;
	bidState.m_fPartnersMax = 22;
	status << "RSTRT! Partner made a strong 2-bid, showing a very good suit or two solid suits, 9+ playing tricks, and 4+ quick tricks.  We have to respond positively if interested in slam, or negatively otherwise.\n";

	// set partnership point count minimums & maximums
	bidState.m_fMinTPPoints = fAdjPts + bidState.m_fPartnersMin;
	bidState.m_fMaxTPPoints = fAdjPts + bidState.m_fPartnersMax;
	bidState.m_fMinTPCPoints = fCardPts + bidState.m_fPartnersMin;
	bidState.m_fMaxTPCPoints = fCardPts + bidState.m_fPartnersMax;

	// the bid is forcing to game
	bidState.m_bGameForceActive = TRUE;		

	//
	// if we have less than 1 Quick trick, respond negatively
	//
	if (numQuickTricks < 1.0) 
	{
		nBid = BID_2NT;
		status << "RSTRT10! But with only " & numQuickTricks & 
				  " QT's, we have to make the negative response of " & BTS(nBid) & 
				  " to deny slam values.\n";
		bidState.SetBid(nBid);
		return TRUE;
	}

	//
	// else we have >= 1 Quick trick, so respond positively
	//
	status << "2RSTRT20! We have " & numQuickTricks & 
			  " QT's, so we can make a positive response.\n";

	// if we have even half-decent support for partner's suit, show it
	if (nPartnersSuitSupport >= SS_WEAK_SUPPORT) 
	{

		nBid = MAKEBID(nPartnersSuit,3);
		status << "RSTRT22! And we have " & bidState.SLTS(nPartnersSuit) & 
				  " support for partner's long " & bidState.szPSS &
				  " suit (holding " & bidState.szHP & 
				  "), so raise partner's bid to " & BTS(nBid) & ".\n";
	} 
	else if ((nPrefSuit != nPartnersSuit) &&
			   (bidState.nPrefSuitStrength >= SS_OPENABLE) &&
			   (numPrefSuitCards >= 5)) 
	{

		// or show our own suit if we have a good 5+ suiter
		int nSuit = nPrefSuit;
		// jump shift if the suits is really strong
		if (bidState.nPrefSuitStrength >= SS_ABSOLUTE) 
		{
			nBid = bidState.GetJumpShiftBid(nSuit,nPartnersBid);
			status << "RSTRT24! We lack good support for partner's " & 
					  bidState.szPSS & " suit (holding " & bidState.szHP & 
					  "), but we have an excellent " & 
					  bidState.LEN(nSuit) & "-card suit of our own in " & STS(nSuit) & 
					  " (holding " & bidState.SHTS(nSuit) & "), so show it in a bid of " &
					  BTS(nBid) & ".\n";
		} 
		else 
		{
			nBid = bidState.GetCheapestShiftBid(nSuit);
			status << "RSTRT26! But we lack good support for partner's " & 
					  bidState.szPSS & " suit (holding " & bidState.szHP & 
					  "), so show our preferred " & 
					  bidState.LEN(nSuit) & "-card " & STSS(nSuit) & " suit in a bid of " &
					  BTS(nBid) & ".\n";
		}

	} 
	else if ((bidState.bBalanced) && (bidState.m_fMinTPCPoints >= 26)) 
	{
		// here, we lack good support for partner's suit, and don't have a good
		// suit of our own.  so we jump to 3NT if we have a
		// balanced hand & 26+ total HCPs
		nBid = BID_3NT;
		status << "RSTRT28! But we lack good support for partner's " & 
				  bidState.szPSS & " suit (holding " & bidState.szHP & 
				  ") with a balanced hand, so jump to " &
				  BTS(nBid) & ".\n";
	} 
	else 
	{

		// here, we don't have good support for partner's
		// suit, nor a good suit of our own, nor a balanced
		// hand.  So bid 2NT in a negative response.
		nBid = BID_2NT;
		status << "RSTRT40! But unfortunately we have poor support for partner's " & 
				  bidState.szPSS & " suit (holding " & bidState.szHP & 
				  "), no good suit of our own, and an unbalanced hand, so we have to make the negative response of " & BTS(nBid) & ".\n";
	}
	//
	bidState.SetBid(nBid);
	return TRUE;
}
//
//---------------------------------------------------------------
//
// HandleConventionResponse()
//
BOOL CCueBidConvention::HandleConventionResponse(const CPlayer& player, 
												 const CConventionSet& conventions, 
												 CHandHoldings& hand, 
												 CCardLocation& cardLocation, 
												 CGuessedHandHoldings** ppGuessedHands,
												 CBidEngine& bidState,  
												 CPlayerStatusDialog& status)
{
	// check state
	int nStatus = bidState.GetConventionStatus(this);
	if (nStatus <= 0)
		return FALSE;

	//
	int nPartnersBid = bidState.nPartnersBid;
	int nPartnersBidLevel = bidState.nPartnersBidLevel;
	int nPartnersSuit = bidState.nPartnersSuit;
	int nPreviousBid = bidState.nPreviousBid;
	int nAgreedSuit = bidState.m_nAgreedSuit;
	int nBid;

	//
	// first check if partner returned to the trump suit, regardless of 
	// which cue bidding round this is 
	//
	if ( ((nStatus == CONV_INVOKED_ROUND1) || (nStatus == CONV_INVOKED_ROUND2)) &&
						(nPartnersSuit == nAgreedSuit) )
	{
		// first check for a strange response
		if ((nPartnersBid == BID_DOUBLE) || (nPartnersBid == BID_REDOUBLE))
		{
			// we don't understand partner's bid
			return CConvention::HandleConventionResponse(player, conventions, hand, cardLocation, ppGuessedHands, bidState, status);
		}

		// first check for a direct raise to slam by partner in response to our
		// cue bid(unlikely, but hey...)
		if (nPartnersBidLevel >= 6)
		{
			status << "HRCB0! In response to our cue bid, partner returned to the agreed " & STSS(nAgreedSuit) &
					  " trump suit with a slam bid at " & BTS(nPartnersBid) & ".\n";
			// raise to a grand slam if possible
			if ((nPartnersBidLevel == 6) && (bidState.m_fMinTPPoints >= 37))
			{
				nBid = MAKEBID(nAgreedSuit,7);
				status << "HRCB1! And with " &
						  bidState.m_fMinTPPoints & "-" & bidState.m_fMaxTPPoints &
						  " points in the partnership, go ahead and raise to " &
						  BTS(nBid) & ".\n";
			}
			else
			{
				// sign off on the slam
				nBid = BID_PASS;
				status << "HRCB2! And with " &
						  bidState.m_fMinTPPoints & "-" & bidState.m_fMaxTPPoints &
						  " points in the partnership, sign off on the slam bid and pass.\n";
			}
			//
			bidState.SetBid(nBid);
			bidState.SetConventionStatus(this, CONV_FINISHED);
			return TRUE;
		}

		//
		// otherwise partner returned to the agreed suit below slam, 
		// a discouraging sign
		//
		status << "HRCB5! Partner returned to the agreed " & STSS(nAgreedSuit) &
				  " trump suit in response to our cue bid of " & BTS(nPreviousBid) &
				  ", which is a discouraging sign.\n";
		// pass with < 33 team points
		if (bidState.m_fMinTPPoints < 33)
		{
			//
			nBid = BID_PASS;
			status << "HRCB6! And with only " & 
					  bidState.m_fMinTPPoints & "-" & bidState.m_fMaxTPPoints &
					  " points in the partnership, we have to forget about slam and pass.\n" &
					  BTS(nBid) & ".\n";
		}
		else if (bidState.m_fMinTPPoints < 37)
		{
			// with 33-36 pts, bid small slam anyway
			nBid = MAKEBID(nAgreedSuit, 6);
			status << "HRCB7! But with " & 
					  bidState.m_fMinTPPoints & "-" & bidState.m_fMaxTPPoints &
					  " points in the partnership, go ahead and bid a small slam anyway at " &
					  BTS(nBid) & ".\n";
		}
		else
		{
			// with 33-37 pts, bid a grand slam anyway
			nBid = MAKEBID(nAgreedSuit, 7);
			status << "HRCB8! But with " & 
					  bidState.m_fMinTPPoints & "-" & bidState.m_fMaxTPPoints &
					  " points in the partnership, go ahead and bid a grand slam anyway at " &
					  BTS(nBid) & ".\n";
		}
		//
		bidState.SetBid(nBid);
		bidState.SetConventionStatus(this, CONV_FINISHED);
		return TRUE;
	}



	//
	//-----------------------------------------------------------------
	//
	// else partner made a responding cue bid, an encouraging sign
	// now see what stage we're at
	//
	if (nStatus == CONV_INVOKED_ROUND1)
	{
		// first check for a strange response
		if ((nPartnersBid == BID_DOUBLE) || (nPartnersBid == BID_REDOUBLE))
		{
			// we don't understand partner's bid
			return CConvention::HandleConventionResponse(player, conventions, hand, cardLocation, ppGuessedHands, bidState, status);
		}

		//
		status << "HRCB40! Partner responded with a cue bid of " & BTS(nPartnersBid) &
				  ", showing an Ace in " & STS(nPartnersSuit) & ".\n";
		//
		// see if we want to proceed to a second round of cue bidding
		// we need 36+ pts and controls in all four suits
		//
		BOOL bAllFourControls;
		if ((bidState.numAces + 1) == 4)
		{
			status << "HRCB42! And with partner's " & STSS(nPartnersSuit) & 
					  ", we have all four Aces for full first-round control.\n";
			bAllFourControls = TRUE;
		}
		else
		{
			status << "HRCB43! But even with partner's " & STSS(nPartnersSuit) & 
					  ", it's not clear we have all four Aces for full first-round control.\n";
			bAllFourControls = FALSE;
		}

		//
		if ((bidState.m_fMinTPPoints < PTS_SLAM) || (!bAllFourControls))
		{
			// gotta stop below slam
			nBid = bidState.GetCheapestShiftBid(nAgreedSuit);
			status << "HRCB46! With only " & 
					  bidState.m_fMinTPPoints & "-" & bidState.m_fMaxTPPoints &
					  " points in the partnership" &
					  ((bAllFourControls)? "," : "and without clear first round controls,") &
					  " we can't afford to bid slam, so settle for a contract of " & 
					  BTS(nBid) & ".\n";
			bidState.SetBid(nBid);
			bidState.SetConventionStatus(this, CONV_FINISHED);
			return TRUE;
		}
		// else we have >= 33 pts and all four controls
		else if (bidState.m_fMinTPPoints < 36)
		{
			// can only make a small slam
			nBid = MAKEBID(nAgreedSuit, 6);
			status << "HRCB46! But with only " & 
					  bidState.m_fMinTPPoints & "-" & bidState.m_fMaxTPPoints &
					  " points in the partnership, we have to stop at a small with a contract of " &
					  BTS(nBid) & ".\n";
			bidState.SetBid(nBid);
			bidState.SetConventionStatus(this, CONV_FINISHED);
			return TRUE;
		}

		//
		// at this point, we have 36+ points, so trigger another round of cue bidding
		// find cheapest king or void suit
		//
		int nSuit = GetCheapestKingOrVoid(hand, bidState.m_nAgreedSuit);
		if (nSuit != nAgreedSuit) 
		{
			// found a suit to cue bid for second round
			nBid = bidState.GetCheapestShiftBid(nSuit);
			status << "HRCB60! Make a second-round cue bid, showing the cheapest " &
					  ((hand.GetSuitLength(nSuit) == 0)? "void suit" : "king") &
					  " (in " & STS(nSuit) & ") with a bid of " & BTS(nBid) & ".\n";
		}
		else
		{
			// either we don't have any second-round control to show, or the
			// second round card is in the trump
			// so stop cue bidding and return to the trump suit at a small slam
			nBid = MAKEBID(nAgreedSuit, 6);
			status << "HRCB80! With no second-round controls to cue bid, we have to return to the trump suit with a small slam at " &
					  BTS(nBid) & ".\n";
		}
		//
		bidState.SetBid(nBid);
		bidState.SetConventionStatus(this, CONV_FINISHED);
		return TRUE;

	}
	else if (nStatus == CONV_INVOKED_ROUND2)
	{
		// first check for a strange response
		if ((nPartnersBid == BID_DOUBLE) || (nPartnersBid == BID_REDOUBLE))
		{
			// we don't understand partner's bid
			return CConvention::HandleConventionResponse(player, conventions, hand, cardLocation, ppGuessedHands, bidState, status);
		}

		//
		// both we and partner have shown first and second-round controls, 
		// so now it's time to put up or shut up
		//
		// if we like the controls and have enough points, bid grand slam;
		// else bid a small slam or game
		//
		//
		// see if we want to proceed to a second round of cue bidding
		// we need 36+ pts and controls in all four suits
		//
		BOOL bAllFourSecondRoundControls;
		if ((bidState.numKings + 1) == 4)
		{
			status << "HRCBS10! And with partner's " & STSS(nPartnersBid) & 
					  " bid showing a King or void, in " & STS(nPartnersSuit) &
					  ", we have scond-round control of all four suits.\n";
			bAllFourSecondRoundControls = TRUE;
		}
		else
		{
			status << "HRCBS12! But even with partner's " & STSS(nPartnersBid) & 
					  ", it's not clear we have all full second-round control.\n";
			bAllFourSecondRoundControls = FALSE;
		}

		//
		if ((bidState.m_fMinTPPoints < 32) || (!bAllFourSecondRoundControls))
		{
			// gotta stop below slam
			nBid = bidState.GetCheapestShiftBid(nAgreedSuit);
			status << "HRCBS20! With only " & 
					  bidState.m_fMinTPPoints & "-" & bidState.m_fMaxTPPoints &
					  " points in the partnership " &
					  ((bAllFourSecondRoundControls)? "," : "and without clear second round controls,") &
					  " we can't afford to bid slam, so settle for a contract of " & 
					  BTS(nBid) & ".\n";
		}
		// else we have >= 32 pts and all four controls
		else if (bidState.m_fMinTPPoints < 36)
		{
			// can only make a small slam
			nBid = MAKEBID(nAgreedSuit, 6);
			status << "HRCBS24! But with only " & 
					  bidState.m_fMinTPPoints & "-" & bidState.m_fMaxTPPoints &
					  " points in the partnership, we have to stop at a small with a contract of " &
					  BTS(nBid) & ".\n";
		}
		else
		{
			//
			// else we have 36+ points, so go ahead and bid a grand slam
			// 
			int nBid = MAKEBID(nAgreedSuit, 7);
			status << "HRCBS40! With a total of " &
					  bidState.m_fMinTPPoints & "-" & bidState.m_fMaxTPPoints &
					  " points in the partnership and full first and second-round controls, go head and bid a grand slam at " &
					  BTS(nBid) & ".\n";
		}
		//
		bidState.SetBid(nBid);
		bidState.SetConventionStatus(this, CONV_FINISHED);
		return TRUE;

	}
	else
	{	

		// N/A
		return FALSE;

	}
	//
	return TRUE;
}
//
//==========================================================
//
// Rebidding as opener after a strong 2-level opening
//
//
BOOL CStrongTwoBidsConvention::HandleConventionResponse(const CPlayer& player, 
												        const CConventionSet& conventions, 
												        CHandHoldings& hand, 
												        CCardLocation& cardLocation, 
													    CGuessedHandHoldings** ppGuessedHands,
												        CBidEngine& bidState,  
												        CPlayerStatusDialog& status)
{
	if (bidState.GetConventionStatus(this) != CONV_INVOKED)
		return FALSE;
	bidState.ClearConventionStatus(this);

	//
	// estimate partner's strength
	//
	int nBid;
	double fPts = bidState.fPts;
	double fAdjPts = bidState.fAdjPts;
	double fCardPts = bidState.fCardPts;
	int nPrefSuit = bidState.nPrefSuit;
	int nPrefSuitStrength = bidState.nPrefSuitStrength;
	int nPreviousSuit = bidState.nPreviousSuit;
	int nPartnersBid = bidState.nPartnersBid;
	int nPartnersBidLevel = bidState.nPartnersBidLevel;
	int nPartnersSuit = bidState.nPartnersSuit;
	int nPartnersSuitSupport = bidState.nPartnersSuitSupport;
	int numSupportCards = bidState.numSupportCards;
	BOOL bBalanced = bidState.bBalanced;

	//
	// did we get a negative response from partner?
	//
	if (nPartnersBid == BID_2NT) 
	{
		status << "2S2Rb0! After our strong " & bidState.szPVB & 
			" opening bid, partner's 2NT bid is a negative response, denying slam values (less than 1 Quick Trick).\n";

		// estimate points -- 0 to 6 for now
		bidState.m_fPartnersMin = 0;
		bidState.m_fPartnersMax = 6;
		bidState.m_fMinTPPoints = fAdjPts + bidState.m_fPartnersMin;
		bidState.m_fMaxTPPoints = fAdjPts + bidState.m_fPartnersMax;
		bidState.m_fMinTPCPoints = fCardPts + bidState.m_fPartnersMin;
		bidState.m_fMaxTPCPoints = fCardPts + bidState.m_fPartnersMax;

		// after a negative response, bid 3NT if balanced
		// with 26+ HCPs
		if ((bBalanced) && (bidState.m_fMinTPCPoints >= PTS_NT_GAME)) 
		{
			nBid = BID_3NT;
			status << "S2RB1! With a balanced distribution and " &
					  fCardPts & " HCPs in hand, rebid " & BTS(nBid) & ".\n";
		}
		// else show a second preferred suit if available
		if (bidState.numPreferredSuits > 0) 
		{
			int nSuit = bidState.GetRebidSuit(nPreviousSuit);
			nBid = bidState.GetCheapestShiftBid(nSuit);
			status << "S2RB4! With a good second suit in " &
					  STS(nSuit) & ", show it in a rebid of " & BTS(nBid) & ".\n";
		}
		// otherwise rebid our original suit (if not 2C)
		if (bidState.nPreviousBid == BID_2C) 
		{
			nBid = bidState.GetCheapestShiftBid(nPrefSuit);
			status << "S2RB6! With no other good suits, go ahead and bid our " &
					  bidState.szPrefS & " suit at " & BTS(nBid) & ".\n";
		} 
		else 
		{
			nBid = bidState.GetCheapestShiftBid(nPreviousSuit);
			status << "B3E32! With no other good suits, go ahead and rebid our " &
					  bidState.szPVSS & " suit at " & BTS(nBid) & ".\n";
		}
		//
		bidState.SetBid(nBid);
		return TRUE;
	}
	
	//
	// otherwise, got a positive response, and partner has shown 
	// his long suit -- so either raise partner's suit, bid NT, or
	// rebid our own suit
	//
	status << "2S2Rb20! After our strong " & bidState.szPVB &
			  " opening bid, partner's " & bidState.szPB & 
			  " bid was a positive response, indicating 1+ Quick Tricks.\n";

	// estimate points -- 3+ pts for now
	bidState.m_fPartnersMin = 3;
	bidState.m_fPartnersMax = MIN(22, 40 - fCardPts);
	bidState.m_fMinTPPoints = fAdjPts + bidState.m_fPartnersMin;
	bidState.m_fMaxTPPoints = fAdjPts + bidState.m_fPartnersMax;
	bidState.m_fMinTPCPoints = fCardPts + bidState.m_fPartnersMin;
	bidState.m_fMaxTPCPoints = fCardPts + bidState.m_fPartnersMax;

	// bid No Trump if balanced
	if (bBalanced) 
	{
		nBid = BID_3NT;
		status << "With a balanced hand, bid game at " & BTS(nBid) & ".\n";
	} 
	// see if there's a suit agreement from a strong 2 bid
	if ((nPreviousSuit == nPartnersSuit) && (bidState.nLastBid != BID_2C)) 
	{
		// try for a slam; use Blackwood
		status << "S2RB24! Partner's encouraging raise to " & bidState.szPB & 
				  " indicates 1+ Quick Tricks and slam possibilities.\n";
		bidState.InvokeBlackwood(nPartnersSuit);
		return TRUE;
	}
	// raise partner's suit if possible
	if (nPartnersSuitSupport >= SS_GOOD_SUPPORT) 
	{
		// double raise partner if major, or go directly to Blackwood
		// if minor (double raise from 3C or 3D would exceed 4NT
		if (ISMAJOR(nPartnersSuit))
		{
			bidState.m_nAgreedSuit = nPartnersSuit;
			nBid = MAKEBID(nPartnersSuit,nPartnersBidLevel+2);
			status << "S2RB28! With " & bidState.SLTS(nPartnersSuit) & 
					  " support for partner's " & bidState.szPS & 
					  " (holding " & bidState.szHP & 
					  "), go ahead and jump raise to " & BTS(nBid) & ".\n";
		}
		else
		{
			status << "S2RB32! We have " & bidState.SLTS(nPartnersSuit) & 
					  " support for partner's " & bidState.szPS & 
					  " (holding " & bidState.szHP & 
					  ").\n";
			bidState.InvokeBlackwood(nPartnersSuit);
			return TRUE;
		}
	}

	// else show a second preferred suit if available
	if (bidState.numPreferredSuits > 1) 
	{
		int nSuit = bidState.GetRebidSuit(nPreviousSuit);
		nBid = bidState.GetCheapestShiftBid(nSuit);
		status << "S2RB36! But we don't like partner's " & bidState.szPSS & 
				  " suit (holding " & bidState.szHP & 
				  "), and we hold a good second suit in " & STS(nSuit) & 
				  ", so show it in a rebid of " & BTS(nBid) & ".\n";
	}
	// otherwise rebid our original suit (if not 2C)
	if (bidState.nPreviousBid == BID_2C) 
	{
		nBid = bidState.GetCheapestShiftBid(nPrefSuit);
		status << "S2RB44! But we don't like partner's " &
				  bidState.szPSS & " suit (holding " & bidState.szHP & 
				  "), so bid our own " & bidState.szPrefS & 
				  " suit at " & BTS(nBid) & ".\n";
	} 
	else 
	{
		nBid = bidState.GetCheapestShiftBid(nPreviousSuit);
		status << "S2RB50! But we don't like partner's " &
				  bidState.szPSS & " suit (holding " & bidState.szHP & 
				  "), so rebid our own " & bidState.szPVSS & 
				  " suit at " & BTS(nBid) & ".\n";
	}
	//
	bidState.SetBid(nBid);
	return TRUE;
}
Example #21
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;
}
//
//===============================================================================
//
// TryConvention()
//
// check if we can open with a strong two-bid
//
BOOL CStrongTwoBidsConvention::TryConvention(const CPlayer& player, 
											 const CConventionSet& conventions, 
											 CHandHoldings& hand, 
											 CCardLocation& cardLocation, 
											 CGuessedHandHoldings** ppGuessedHands,
											 CBidEngine& bidState,  
											 CPlayerStatusDialog& status)
{
	// basic requirements: no non-pass bid must have been entered yet
	if (bidState.nLastValidRecordedBid != BID_PASS)
		return FALSE;	// someone else has opened already
	
	// To open with a strong two bid, we need either a long, very good suit 
	// or 2 string suits, with 9+ playing tricks for majors (10+ for minors)
	// plus 4 quick tricks.
	// we also need a _minimum_ of 16 HCPs, no matter what
	if ( ((bidState.numAbsoluteSuits >= 1) || (bidState.numSolidSuits >= 2)) &&
		  (bidState.numLikelyWinners >= 9) && (bidState.numQuickTricks >= 4) &&
			  								(bidState.fCardPts >= 16)) 
	{
		// bid 2 of lowest openable solid suit
		double fPts = bidState.fPts;
		double fCardPts = bidState.fCardPts;
		int nBid = bidState.GetLowestOpenableBid(SUITS_ANY, OT_STRONG, 2);
		if ((nBid == BID_2C) && (pCurrConvSet->IsConventionEnabled(tidArtificial2ClubConvention)))
		{
			// we can't open a strong 2C when playing the 2Club convention,
			// so see if we can find another strong suit
			int nextBestSuit = bidState.nPrefSuitList[1];
			if (bidState.nSuitStrength[nextBestSuit] >= SS_STRONG)
			{
				nBid = MAKEBID(nextBestSuit ,2);
				status << "STR2C1! Have a strong Club suit and " & fPts & 
						  " points, but can't open at 2 Club, so we'll have to bid " & 
						  STS(nextBestSuit) & " instead.\n";
			}
			else
			{
				// can't bid at the 1-level
				status << "STR2C2! Have a strong Club suit and no others, but can't open 2C with only " &
						   fCardPts & " HCPs, so bid " & BTS(nBid) & " instead.\n";
				return FALSE;
			}
		}
		// a biddable suit has been established
		if (bidState.numSolidSuits > 1)
		{
			status << "STR2C10! Have " & bidState.numSolidSuits & " solid " & 
					  ((bidState.numSolidSuits>1)? "suits" :  "suit") &
					  " with " & bidState.numLikelyWinners & " playing tricks and " &
					  bidState.numQuickTricks & " quick tricks, so bid a strong " &
					  BTS(nBid) & ".\n";
		}
		else
		{
			status << "STR2C12! Have a solid " & STSS(bidState.nPrefSuit) & 
					  " suit with " & bidState.numLikelyWinners & 
					  " playing tricks and " & bidState.numQuickTricks & 
					  " quick tricks, so bid a strong " & BTS(nBid) & ".\n";
		}
		bidState.SetBid(nBid);
//		bidState.SetConventionStatus(this, CONV_INVOKED);
		return TRUE;
	}
	// failed the test
	return FALSE;
}
Example #23
0
//
// AdjustCardCountFromPlay()
//
// adjust card count and analysis after a card is played
//
void CPlayEngine::AdjustCardCountFromPlay(int nPos, CCard* pCard)
{
	// default code
//	if (nPos != m_pPlayer->GetPosition())
//	{
		// note the card that was played
		CGuessedHandHoldings* pPlayerHoldings = m_ppGuessedHands[nPos];
		CGuessedCard* pGuessedCard = new CGuessedCard(pCard,	// card
													  FALSE,	// no longer outstanding
													  nPos,		// location
													  1.0);		// known with certainty
		*pPlayerHoldings << pGuessedCard;

		// see if the player showed out
		CPlayerStatusDialog& status = *m_pStatusDlg;
		CCard* pCardLed = pDOC->GetCurrentTrickCardByOrder(0);
		if (pCard)
		{
			int nSuitLed = pCardLed->GetSuit();
			ASSERT(nSuitLed != NONE);
			CGuessedSuitHoldings& suit = pPlayerHoldings->GetSuit(nSuitLed);
			if ((pCard->GetSuit() != nSuitLed) && (!suit.IsSuitShownOut()))
			{
				status << "4RCP10! " & PositionToString(nPos) & 
						  " shows out of " & STS(nSuitLed) & ".\n";
				suit.MarkSuitShownOut();
				if (pPlayerHoldings->GetNumSuitsFullyIdentified() > 1)
				{
					// multiple suits identified
					status << "4RCP1A! " & PositionToString(nPos) & 
							  " is now known to have started with ";
					int numTotalIdentifiedSuits = pPlayerHoldings->GetNumSuitsFullyIdentified();
					int numIdentifiedSuits = 0;
					int numTotalIdentifiedCards = 0;
					int numTotalOriginalCards = 0;
					int nIdentifiedSuits[4];
					for(int i=0;i<4;i++)
					{
						if (pPlayerHoldings->GetSuit(i).AreAllCardsIdentified())
						{
							CGuessedSuitHoldings& currSuit = pPlayerHoldings->GetSuit(i);
							status < ((numIdentifiedSuits > 0)? " and " : " ") &
									  currSuit.GetNumOriginalCards() & " " & 
									  ((suit.GetNumOriginalCards() > 1)? STS(i) : STSS(i));
							nIdentifiedSuits[numIdentifiedSuits] = i;
							numIdentifiedSuits++;
							numTotalIdentifiedCards += currSuit.GetNumDefiniteCards();
							numTotalOriginalCards += currSuit.GetNumOriginalCards();
						}
					}
					status < ".\n";
					// if the number of cards is known in 3 suits, the orignal 
					// and current length of the 4th suit is also known
					if (numTotalIdentifiedSuits == 3)
					{
						// first identify the fourth suit
						int nFourthSuit = NONE;
						for(int i=0;i<4;i++)
						{
							// test each suit to see if it's in the list of know suits
							for(int j=0;j<3;j++)
							{
								if (nIdentifiedSuits[j] == i)
									break;
							}
							if (j == 3)
								nFourthSuit = i;
						}
						//
						VERIFY(nFourthSuit != NONE);
						CGuessedSuitHoldings& fourthSuit = pPlayerHoldings->GetSuit(nFourthSuit);
						int numOriginalCards = 13 - numTotalOriginalCards;
						VERIFY(numOriginalCards >= 0);
						fourthSuit.SetNumOriginalCards(numOriginalCards);
						int numRemainingCards = numOriginalCards - fourthSuit.GetNumCardsPlayed();
						VERIFY(numRemainingCards >= 0);
						// mark the # of remaining cards
						// revisit this later
	//					fourthSuit.SetNumLikelyCards(numRemainingCards);
						fourthSuit.SetNumRemainingCards(numRemainingCards);
						//
						status << "4RCP1B! Therefore, " & PositionToString(nPos) &
								  " started with " & numOriginalCards & " " & STS(nFourthSuit) &
								  " and has " & numRemainingCards & " left.\n";
					}
				}
				else
				{
					status < "RCP5A! " & PositionToString(nPos) & 
							  " is now known to have started with " &
							  suit.GetNumOriginalCards() & " " & 
							  ((suit.GetNumOriginalCards() == 1)? STSS(nSuitLed) : STS(nSuitLed)) & ".\n";
				}
			}

			// also, if this is the dummy, and the dummy plays his last card 
			// in the suit, he has effectively shown out
			CPlayer* pDummy = pDOC->GetDummyPlayer();
			if ((nPos == pDummy->GetPosition()) && (pDummy->AreCardsExposed()))
			{
				if ((pCard->GetSuit() == nSuitLed) && 
					(pDummy->GetHand().GetNumCardsInSuit(nSuitLed) == 0) &&
					(!pPlayerHoldings->IsSuitShownOut(nSuitLed)))
				{
					status << "3RCP20! Dummy is now out of " & STS(nSuitLed) & ".\n";
					pPlayerHoldings->MarkSuitShownOut(nSuitLed);
				}
			}
		}
//	}

	// special code -- if dummy has just been laid down, mark a suit as shown
	// out if dummy is void in the suit
	CPlayer* pDummy = pDOC->GetDummyPlayer();
	int nRound = pDOC->GetPlayRound();
	if ((nRound == 0) && (nPos == pDummy->GetPosition()) && (pDummy->AreCardsExposed()))
	{
		CHandHoldings& dummy = pDummy->GetHand();
		for(int i=0;i<4;i++)
		{
			if (dummy.GetNumCardsInSuit(i) == 0) 
			{
				status << "3RCP25! Dummy is shown to be void in " & STS(i) & ".\n";
				pPlayerHoldings->MarkSuitShownOut(i);
			}
		}
	}
}
Example #24
0
void SearchBestAlternate(NMEA_INFO *Basic, 
			 DERIVED_INFO *Calculated)
{
  int sortedLandableIndex[MAXBEST];
  double sortedArrivalAltitude[MAXBEST];
  int sortApproxDistance[MAXBEST*2];
  int sortApproxIndex[MAXBEST*2];
  int i, k, l;
  int j;
  double arrival_altitude;
  int active_bestalternate_on_entry=-1;
  int bestalternate=-1;

  #ifdef DEBUG_BESTALTERNATE
  TCHAR ventabuffer[200];
  #endif

  if (WayPointList.empty()) return;

  CScopeLock Lock(LockTaskData, UnlockTaskData);
  
  if( DisableBestAlternate ) {
      if ( HomeWaypoint >= 0 )
          BestAlternate=HomeWaypoint;
      else
          BestAlternate = 0; // RESWP_TAKEOFF
      return;
  }

  // We are not considering total energy here, forbidden for safety reasons
  // V5: double searchrange=(Calculated->NavAltitude-(SAFETYALTITUDEARRIVAL/10))* GlidePolar::bestld /1000;
  // V6: we enlarge preliminar search range because of possible tail wind for some destinations
  double searchrange=(Calculated->NavAltitude)* 1.2 * GlidePolar::bestld /1000;
  if (searchrange <= 0) 
	searchrange=2; // lock to home airport at once
  if (searchrange > ALTERNATE_MAXRANGE) 
	searchrange=ALTERNATE_MAXRANGE;

  active_bestalternate_on_entry = BestAlternate;

  // Do preliminary fast search
  int scx_aircraft, scy_aircraft;
  LatLon2Flat(Basic->Longitude, Basic->Latitude, &scx_aircraft, &scy_aircraft);

  // Clear search lists
  for (i=0; i<MAXBEST*2; i++) {
	sortApproxIndex[i]= -1;
	sortApproxDistance[i] = 0;
  }
  #ifdef LOGBEST
  STS("\n\nNEW SEARCH\n\n"));
  #endif
  for (j=0; j<RangeLandableNumber; j++) {
	i=RangeLandableIndex[j];

	int approx_distance = CalculateWaypointApproxDistance(scx_aircraft, scy_aircraft, i);

	// Size a reasonable distance, wide enough 
	if ( approx_distance > searchrange ) continue;

	// see if this fits into slot
	for (k=0; k< MAXBEST*2; k++)  {
      
		if (((approx_distance < sortApproxDistance[k]) 
			// wp is closer than this one
			|| (sortApproxIndex[k]== -1))   // or this one isn't filled
			&& (sortApproxIndex[k]!= i))    // and not replacing with same
		{
			// ok, got new biggest, put it into the slot.
			for (l=MAXBEST*2-1; l>k; l--) {
				if (l>0) {
					sortApproxDistance[l] = sortApproxDistance[l-1];
					sortApproxIndex[l] = sortApproxIndex[l-1];
				}
			}

			sortApproxDistance[k] = approx_distance;
			sortApproxIndex[k] = i;
                        #ifdef LOGBEST
                        STS("INSERT FROM RANGELANDABLE: [%d] %d %s\n"),k,sortApproxIndex[k],WayPointList[sortApproxIndex[k]].Name);
                        #endif
			k=MAXBEST*2;
		}
	} // for k
  #ifdef LOGBEST
  STS("------------\n"));
  #endif
  } // for all waypoints, or the reduced list by Range

  #ifdef DEBUG_BESTALTERNATE
  FILE *fp;
  if ( (fp=_tfopen(_T("DEBUG.TXT"),_T("a"))) != NULL )  {
	_stprintf(ventabuffer,TEXT("==================\n"));
	fprintf(fp,"%S",ventabuffer);
	_stprintf(ventabuffer,TEXT("[GPSTIME=%02d:%02d:%02d] Altitude=%dm searchrange=%dKm Curr.Best=%d\n\n"),
	     GPS_INFO.Hour, GPS_INFO.Minute, GPS_INFO.Second,
	     (int)Calculated->NavAltitude, (int)searchrange, BestAlternate);
	fprintf(fp,"%S",ventabuffer);
	for ( int dbug=0; dbug<MAXBEST*2; dbug++) {
		if ( sortApproxIndex[dbug] <0 ) _stprintf(ventabuffer,_T("%d=empty\n"), dbug);
		else
			_stprintf(ventabuffer,TEXT("%d=%s(%d)\n"), dbug, 
			WayPointList[sortApproxIndex[dbug]].Name, sortApproxDistance[dbug] );
		fprintf(fp,"%S",ventabuffer);
	}
	fclose(fp);
  } else
	DoStatusMessage(_T("CANNOT OPEN DEBUG FILE"));
  #endif


  // Now do detailed search
  for (i=0; i<MAXBEST; i++) {
	sortedLandableIndex[i]= -1;
	sortedArrivalAltitude[i] = 0;
  }


  for (int scan_airports_slot=0; scan_airports_slot<2; scan_airports_slot++) {
  #ifdef LOGBEST
  STS("SCAN SLOT= %d\n"),scan_airports_slot);
  #endif
	for (i=0; i<MAXBEST*2; i++) {
		if (sortApproxIndex[i]<0) { // ignore invalid points
			continue;
		}
                #ifdef LOGBEST
                STS("Examine: [%d] %d %s\n"),i,sortApproxIndex[i],WayPointList[sortApproxIndex[i]].Name);
                #endif

		if ((scan_airports_slot==0) && 
			(!WayPointCalc[sortApproxIndex[i]].IsAirport))
		{
			// we are in the first scan, looking for airports only
                        // In second scan we accept again airports and also outlandings
                        #ifdef LOGBEST
                        STS("... scanning only for airports, this one is not an airport\n"));
                        #endif
			continue;
		}

		arrival_altitude = CalculateWaypointArrivalAltitude(Basic, Calculated, sortApproxIndex[i]);
                #ifdef LOGBEST
                STS("...... arrival altitude is %f\n"),arrival_altitude);
                #endif

		WayPointCalc[sortApproxIndex[i]].AltArriv[AltArrivMode] = arrival_altitude; 
		// This is holding the real arrival value

		if (scan_airports_slot==0) {
			if (arrival_altitude<0) {
                                #ifdef LOGBEST
                                STS("... scanning only for airports, and this is unreachable (%f), continue\n"),arrival_altitude);
                                #endif
				// in first scan, this airport is unreachable, so ignore it.
				continue;
			} 
		}

		// see if this fits into slot
		for (k=0; k< MAXBEST; k++) {
			if (((arrival_altitude > sortedArrivalAltitude[k]) 
				// closer than this one
				||(sortedLandableIndex[k]== -1))
				// or this one isn't filled
				&&(sortedLandableIndex[k]!= sortApproxIndex[i]))  // and not replacing with same
			{
				double wp_distance, wp_bearing;
				DistanceBearing(Basic->Latitude , Basic->Longitude ,
					WayPointList[sortApproxIndex[i]].Latitude,
					WayPointList[sortApproxIndex[i]].Longitude,
					&wp_distance, &wp_bearing);

				WayPointCalc[sortApproxIndex[i]].Distance = wp_distance;
				WayPointCalc[sortApproxIndex[i]].Bearing = wp_bearing;
            
				bool out_of_range;
			#ifdef GTL2
				double distance_soarable = FinalGlideThroughTerrain(wp_bearing, Basic->Latitude,
					Basic->Longitude, Calculated->NavAltitude, Calculated,
			#else
				double distance_soarable = FinalGlideThroughTerrain(wp_bearing, Basic, Calculated,
			#endif
					NULL, NULL, wp_distance, &out_of_range, NULL);
            
				// V5 bug: if ((distance_soarable>= wp_distance)||(arrival_altitude<0)) {
				if ((distance_soarable>= wp_distance)) {
					// only put this in the index if it is reachable
					// and doesn't go through terrain, OR, if it is unreachable
					// it doesn't matter if it goes through terrain because
					// pilot has to climb first anyway
                                        // 160407: THE ^^ ABOVE WAS A BUG. Because we were inserting a waypoint
                                        // if it had no obstacles, OR if it had an obstacle but with a NEGATIVE arrival
                                        // altitude. We were thus including negative arrival altitudes wp.
              
					// ok, got new biggest, put it into the slot.
					for (l=MAXBEST-1; l>k; l--) {
						if (l>0) {
							sortedArrivalAltitude[l] = sortedArrivalAltitude[l-1];
							sortedLandableIndex[l] = sortedLandableIndex[l-1];
						}
					}

					sortedArrivalAltitude[k] = arrival_altitude;
					sortedLandableIndex[k] = sortApproxIndex[i];
                                        #ifdef LOGBEST
                                        STS("INSERT INTO LANDABLES: [%d] %d %s\n"),k,sortedLandableIndex[k],WayPointList[sortedLandableIndex[k]].Name);
                                        #endif
					k=MAXBEST;
				} 
			} // if (((arrival_altitude > sortedArrivalAltitude[k]) ...
		} // for (k=0; k< MAXBEST; k++) {