// // 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; }