Ejemplo n.º 1
0
//
// PickFinalDiscardSuit()
//
int CPlayEngine::PickFinalDiscardSuit(CHandHoldings& hand)
{
	// this routine is called by the declarer & defender engined when
	// they absolutely can't find a card to discard
	int nDiscardSuit = NONE;

	// this means generally tha twe have no suits with losers, 
	// or that the only one with losers in the current hand is the priority suit
	// so look through suits by preference for one that has losers
	for(int i=3;i>=0;i--)
	{
		int nSuit = hand.GetSuitsByPreference(i);
		CSuitHoldings& testSuit = hand.GetSuit(nSuit);
		// avoid letting go of winners!
		if ((testSuit.GetNumCards() > 0) && (testSuit.GetNumCards() > testSuit.GetNumWinners()))
		{
			nDiscardSuit = nSuit;
			break;
		}
	}			
	
	// if we failed above, we aboslutely have no losers anywhere 
	// so search for a suit that has winners but no outstanding cards
	// i.e., suits that we may not be able to cash
	if (!ISSUIT(nDiscardSuit))
	{
		for(i=3;i>=0;i--)
		{
			int nSuit = hand.GetSuitsByPreference(i);
			// see if we have cards in this suit, and no outstanding cards in the suit
			if ((hand.GetNumCardsInSuit(nSuit) > 0) && (GetNumOutstandingCards(nSuit) == 0))
			{
				nDiscardSuit = nSuit;
				break;
			}
				
		}
	}
	
	// finally, give up and get any old suit that has cards
	if (!ISSUIT(nDiscardSuit))
 	{
		for(i=3;i>=0;i--)
		{
			int nSuit = hand.GetSuitsByPreference(i);
			if (hand.GetNumCardsInSuit(nSuit) > 0)
			{
				nDiscardSuit = nSuit;
				break;
			}
		}
	}

	//
	ASSERT(ISSUIT(nDiscardSuit));
	return nDiscardSuit;

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

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

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

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

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

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

	//
	// we've now passed all the tests, so make the bid
	//
	if (bidState.nRHOBidLevel == 1)
		status << "NEGDBL1! With " & bidState.fPts & "/" & bidState.fPts & 
				  " points and 4 cards in the unbid majors, bid a negative double.\n";
	else
		status << "NEGDBL2! With " & bidState.fPts & "/" & bidState.fPts & 
				  " points and 5+ cards in the unbid majors, bid a negative double.\n";
	int nBid = BID_DOUBLE;
	bidState.SetBid(nBid);
//	bidState.SetConventionStatus(this, CONV_INVOKED);
	bidState.SetConventionStatus(this, CONV_FINISHED);
	return TRUE;
}