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)); }
void CRuff::Init() { CPlay::Init(); // m_nEndingHand = m_nTargetHand; m_nStartingHand = (m_nEndingHand == IN_HAND)? IN_DUMMY : IN_HAND; // form name & description m_strName.Format("%s Ruff", STSS(m_nSuit)); m_strDescription.Format("Ruff a %s in %s", SuitToSingularString(m_nSuit), ((m_nTargetHand == IN_HAND)? "hand" : "dummy")); }
CString CType1Finesse::GetFullDescription() { CString strText; int nTrumpSuit = pDOC->GetTrumpSuit(); if (m_pCoverCards->GetNumCards() > 1) return FormString("Lead a low %s from %s to finesse the %s in %s against %s, with the { %s } as possible cover cards.", ((m_nSuit == nTrumpSuit)? "trump" : STSS(m_nSuit)), ((m_nTargetHand == IN_HAND)? "dummy" : "hand"), m_pConsumedCard->GetFaceName(), // STS(m_nSuit), ((m_nTargetHand == 0)? "hand" : "dummy"), PositionToString(m_nTargetPos), m_pCoverCards->GetHoldingsString()); else return FormString("Lead a low %s from %s to finesse the %s in %s against %s, with the %s as cover.", ((m_nSuit == nTrumpSuit)? "trump" : STSS(m_nSuit)), ((m_nTargetHand == IN_HAND)? "dummy" : "hand"), m_pConsumedCard->GetFaceName(), // STS(m_nSuit), ((m_nTargetHand == IN_HAND)? "hand" : "dummy"), PositionToString(m_nTargetPos), m_pCoverCards->GetAt(0)->GetFaceName()); }
// //--------------------------------------------------------------- // // 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; }
// //--------------------------------------------------------------- // // 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; } }
// //--------------------------------------------------------------- // // 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);; }
// //========================================================== // // 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; } }
// //========================================================== // // 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 an Gambling 3NT Bid here // BOOL CGambling3NTConvention::TryConvention(const CPlayer& player, const CConventionSet& conventions, CHandHoldings& hand, CCardLocation& cardLocation, CGuessedHandHoldings** ppGuessedHands, CBidEngine& bidState, CPlayerStatusDialog& status) { // // the requirements for opening a STANDARD Gambling 3NT Bid are: // 1: a solid 7+ card minor suit, // 2: 10-12 HCPs, // 3: no voids or small singletons, and // 4: no outside stoppers // // the requirements for opening an ACOL Gambling 3NT Bid are: // 1: a solid 7+ card minor suit, // 2: 16-21 HCPs, // 3: no voids or small singletons, and // 4: stoppers in at least 2 of the remaining 3 suits // see which version we're playing int bStandardGambling3NT = (pCurrConvSet->GetValue(tnGambling3NTVersion) == 0); // see if we have any small singletons bool bSmallSingletons = false; if (bidState.numSingletons > 0) { for(int i=0; i<4; i++) { CSuitHoldings& suit = hand.GetSuit(i); if ((suit.GetNumCards() == 1) && (suit[0]->GetFaceValue() < TEN)) { bSmallSingletons = true; break; } } } // see if we have a solid suit int nSuit = NONE; if (hand.GetSuit(CLUBS).IsSolid() && (bidState.numCardsInSuit[CLUBS] >= 7)) nSuit = CLUBS; else if (hand.GetSuit(DIAMONDS).IsSolid() && (bidState.numCardsInSuit[DIAMONDS] >= 7)) nSuit = DIAMONDS; // test for std and ACOL Gambling 3NT conditions int numValidBidsMade = pDOC->GetNumValidBidsMade(); if ( bStandardGambling3NT && (numValidBidsMade == 0) && (ISSUIT(nSuit)) && (bidState.fCardPts >= OPEN_PTS(10)) && (bidState.fCardPts <= OPEN_PTS(12)) && (bidState.numVoids == 0) && !bSmallSingletons && (bidState.numSuitsStopped == 1) ) { // passed the test for standard gambling 3NT status << "G3NT1! With a solid " & bidState.numCardsInSuit[nSuit] & "-card " & STSS(nSuit) & " suit, " & bidState.fCardPts & " HCPs, no voids, no small singletons, and no outside stoppers, " " go ahead and bid a Gambling 3NT.\n"; } else if ( !bStandardGambling3NT && (numValidBidsMade == 0) && (ISSUIT(nSuit)) && (bidState.fCardPts >= OPEN_PTS(16)) && (bidState.fCardPts <= OPEN_PTS(21)) && (bidState.numVoids == 0) && !bSmallSingletons && (bidState.numSuitsStopped >= 3) ) { // passed the test for ACOL gambling 3NT status << "G3NT2! With a solid " & bidState.numCardsInSuit[nSuit] & "-card " & STSS(nSuit) & " suit, " & bidState.fCardPts & " HCPs, no voids, no small singletons, and stoppers in " & ((bidState.numSuitsStopped == 4)? "all four suits" : "two outside suits") & ", go ahead and bid an ACOL Gambling 3NT.\n"; } else { return FALSE; } // OK, go ahead and bid 3NT bidState.SetBid(BID_3NT); bidState.SetConventionStatus(this, CONV_INVOKED); return TRUE; }
// // 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); } } } }
// //=============================================================================== // // 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; }
// //=============================================================================== // // 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; }
// // 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; }
// // 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; }
// //========================================================== // // 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; }
// // 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; }
// // GetLeadCard() // CCard* CPlayEngine::GetLeadCard() { // default implementation CPlayerStatusDialog& status = *m_pStatusDlg; CCard* pLeadCard = NULL; int nTrumpSuit = pDOC->GetTrumpSuit(); // look to see if we have any winners if (m_pHand->GetNumWinners() > 0) { // return the first winner found // but avoid the trump suit unless there are no other winners int nSuit = NONE; if (ISSUIT(nTrumpSuit)) nSuit = GetNextSuit(nTrumpSuit); else nSuit= CLUBS; // else start with the club suit // for(int i=0;i<4;i++) { CSuitHoldings& suit = m_pHand->GetSuit(nSuit); if ((suit.GetNumTopCards() > 0) && (nSuit != nTrumpSuit)) { pLeadCard = suit.GetTopSequence().GetBottomCard(); status << "PLYLDA! With no other obvious plays, cash a winner with the " & pLeadCard->GetName() & ".\n"; ASSERT(m_pHand->HasCard(pLeadCard)); return pLeadCard; } // else look at the next suit nSuit = GetNextSuit(nSuit); } } // if we have a card in an unbid suit, lead from that suit. CArray<int,int> suitsUnbid; int numSuitsUnbid = pDOC->GetSuitsUnbid(suitsUnbid); for(int i=0;i<numSuitsUnbid;i++) { CSuitHoldings& suit = m_pHand->GetSuit(suitsUnbid[i]); if (suit.GetNumCards() > 0) { pLeadCard = suit.GetBottomCard(); status << "PLYLDB! With no other clear plays available, lead a card from the unbid " & STSS(pLeadCard->GetSuit()) & " suit.\n"; ASSERT(m_pHand->HasCard(pLeadCard)); return pLeadCard; } } // no winners in hand, so just lead anything if (ISSUIT(nTrumpSuit)) { // playing in a suit contract // if we have any trumps left, _and_ have a singleton, then lead it if ((m_pHand->GetNumTrumps() > 0) && (m_pHand->GetNumSingletons() > 0)) { // search for the singleton suit BOOL bSuitFound = FALSE; int nSuit; for(int i=3;i>=0;i--) { nSuit = m_pHand->GetSuitsByLength(3); if (m_pHand->GetNumCardsInSuit(nSuit) > 1) break; // oops, no more singletons // check if this is a non-trump singleton suit if ((m_pHand->GetNumCardsInSuit(nSuit) == 1) && (nSuit != nTrumpSuit)) { bSuitFound = TRUE; break; } } // lead a card from the suit if (bSuitFound) { CSuitHoldings& suit = m_pHand->GetSuit(nSuit); pLeadCard = suit[0]; status << "PLYLDC! Lead the singleton " & pLeadCard->GetName() & " in the hopes of setting up a ruff later.\n"; ASSERT(m_pHand->HasCard(pLeadCard)); return pLeadCard; } } // else we're stuck -- just lead a card from the worst suit // (i.e., keep the "good" suits alive) for(int i=3;i>=0;i--) { int nSuit = m_pHand->GetSuitsByPreference(i); // avoid leading from the trump suit if we can help it if (nSuit == nTrumpSuit) continue; // else lead from this suit if (m_pHand->GetNumCardsInSuit(nSuit) > 0) { pLeadCard = m_pHand->GetSuit(nSuit).GetBottomCard(); ASSERT(m_pHand->HasCard(pLeadCard)); return pLeadCard; } } // else we're stuck with leading a trump if (m_pHand->GetNumTrumps() > 0) return m_pHand->GetSuit(nTrumpSuit).GetAt(0); } else { // playing in notrump // lead a card from the worst suit, keeping the good suits alive for(int i=3;i>=0;i--) { int nSuit = m_pHand->GetSuitsByPreference(i); if (m_pHand->GetNumCardsInSuit(nSuit) > 0) { pLeadCard = m_pHand->GetSuit(nSuit).GetBottomCard(); ASSERT(m_pHand->HasCard(pLeadCard)); return pLeadCard; } } } // we should NEVER get here ASSERT(FALSE); return NULL; }
// // Perform() // PlayResult CForce::Perform(CPlayEngine& playEngine, CCombinedHoldings& combinedHand, CCardLocation& cardLocation, CGuessedHandHoldings** ppGuessedHands, CPlayerStatusDialog& status, CCard*& pPlayCard) { // a "force" is a play of the lowest possible card that will force out // a key enemy card // 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()); CCombinedSuitHoldings& combinedSuit = combinedHand.GetSuit(m_nSuit); 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; // test preconditions if (!CPlay::IsPlayUsable(combinedHand, playEngine)) { m_nStatusCode = PLAY_INACTIVE; return PLAY_POSTPONE; } // // test to make sure that the required played cards have indeed been played // if (m_pRequiredPlayedCardsList) { // check if any of the cards that should have benen played // are still outstanding for(int i=0;i<m_pRequiredPlayedCardsList->GetNumCards();i++) { CCard* pCard = (*m_pRequiredPlayedCardsList)[i]; if (playEngine.IsCardOutstanding(pCard)) { status << "5PLFRCA! The force play of the " & m_pConsumedCard->GetFaceName() & " to force out the " & m_nTargetCardVal & " is not yet viable as the card [" & pCard->GetFaceName() & "] is still outstanding.\n"; 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) if (m_nTargetHand == IN_HAND) { // play the card necessary to force the opponent pPlayCard = playerSuit.GetHighestCardBelow(m_nTargetCardVal); // NCR check that dummy does not have a singleton honor that's same value as our lead if(dummySuit.IsSingleton() && ((dummySuit.GetTopCard()->GetFaceValue() > pPlayCard->GetFaceValue()) // NCR-28 || (combinedHand.AreEquivalentCards(pPlayCard, dummySuit.GetTopCard())))) pPlayCard = playerSuit.GetBottomCard(); // NCR get lowest card if (pPlayCard == NULL) { status << "4PLFRC02! Error in force play -- no cards in declarer hand usable in a force play.\n"; m_nStatusCode = PLAY_ERROR; return m_nStatusCode; } status << "PLFRC04! Play the " & pPlayCard->GetName() & " from hand to force out the opponents' " & CardValToString(m_nTargetCardVal) & ".\n"; } else { // forcing from dummy, so lead a low card if (playerSuit.GetNumCards() > 0) { pPlayCard = playerSuit.GetBottomCard(); status << "PLFRC06! Lead a low " & STSS(m_nSuit) & " (" & pPlayCard->GetFaceName() & ") from hand to trigger a force play in dummy.\n"; } else { // oops, no card in the suit to lead! status << "4PLFRC08! Oops, we can't start a force play in the " & STSS(m_nSuit) & " suit from declarer, since we have no cards in the suit.\n"; m_nStatusCode = PLAY_POSTPONE; return m_nStatusCode; } } } else { // leading from dummy if (m_nTargetHand == IN_DUMMY) { // forcing from dummy, so do it pPlayCard = dummySuit.GetHighestCardBelow(m_nTargetCardVal); if (pPlayCard == NULL) { status << "4PLFRC10! Error in force play -- no cards in dummy usable in a force play.\n"; m_nStatusCode = PLAY_ERROR; return m_nStatusCode; } status << "PLFRC12! Play the " & pPlayCard->GetName() & " from dummy to force out the opponents' " & CardValToString(m_nTargetCardVal) & ".\n"; } else { // forcing from hand, so lead a low card from dummy if (dummySuit.GetNumCards() > 0) { pPlayCard = dummySuit.GetBottomCard(); status << "PLFRC14! Lead a low " & STSS(m_nSuit) & " (" & pPlayCard->GetFaceName() & ") from dummy to trigger a force play in hand.\n"; } else { // oops, no card in the suit to lead! status << "4PLFRC16! Oops, we can't start a force play in the " & STSS(m_nSuit) & " suit from dummy, since we have no cards in the suit.\n"; m_nStatusCode = PLAY_POSTPONE; return m_nStatusCode; } } } // all went OK m_nStatusCode = PLAY_IN_PROGRESS; // m_nStatusCode = PLAY_COMPLETE; break; case 1: // playing second -- see if we can still force // (i.e., the right suit was led, and the card led < target card) if ((nSuitLed == m_nSuit) && (pCardLed->GetFaceValue() < m_nTargetCardVal)) { // opponent led the suit, so we still try to force if ( ((bPlayingInHand) && (m_nTargetHand == IN_HAND)) || ((!bPlayingInHand) && (m_nTargetHand == IN_DUMMY)) ) { // this is the right time to play the forcing card if (bPlayingInHand) pPlayCard = playerSuit.GetHighestCardBelow(m_nTargetCardVal); else pPlayCard = dummySuit.GetHighestCardBelow(m_nTargetCardVal); // check for error if (pPlayCard == NULL) { status << "4PLFRC20! Error in force play -- no cards in " & (bPlayingInHand? "hand" : "dummy") & " usable in a force play.\n"; m_nStatusCode = PLAY_ERROR; return m_nStatusCode; } // got the forcing card status << "PLFRC22! The opponents led a " & STSS(m_nSuit) & ", so play the " & pPlayCard->GetName() & " from " & (bPlayingInHand? "hand" : "dummy") & " to try and force out the " & CardValToString(m_nTargetCardVal) & " now.\n"; // m_nStatusCode = PLAY_IN_PROGRESS; m_nStatusCode = PLAY_COMPLETE; } else { // not the right hand. so discard pPlayCard = playEngine.GetDiscard(); status << "4PLFRC24! We're not in the right position to play a forcing card, so discard the " & pPlayCard->GetName() & ".\n"; m_nStatusCode = PLAY_POSTPONE; } } else { // wrong suit led, so no point here m_nStatusCode = PLAY_POSTPONE; } // done return m_nStatusCode; break; case 2: // playing third // sanity check if ((m_nStatusCode != PLAY_IN_PROGRESS) || (nSuitLed != m_nSuit)) { m_nStatusCode = PLAY_ERROR; return m_nStatusCode; } // see if RHO trumped if (bTrumped) { status << "5PLFR30! RHO trumped, rendering the force play of the " & m_pConsumedCard->GetFaceName() & " ineffective, so skip the play.\n"; m_nStatusCode = PLAY_POSTPONE; return m_nStatusCode; } // see if we're in the correct hand if ( (bPlayingInHand && (m_nTargetHand == IN_HAND)) || (!bPlayingInHand && (m_nTargetHand == IN_DUMMY)) ) { // see if RHO played the target card CCard* pRHOCard = pDOC->GetCurrentTrickCardByOrder(1); if (pRHOCard->GetFaceValue() >= m_nTargetCardVal) { status << "5PLFR50! RHO played the " & CardValToString(m_nTargetCardVal) & ", so skip this force play.\n"; m_nStatusCode = PLAY_NOT_VIABLE; return m_nStatusCode; } // the target card has not been played yet, so proceed if (bPlayingInHand) pPlayCard = playerSuit.GetHighestCardBelow(m_nTargetCardVal); else pPlayCard = dummySuit.GetHighestCardBelow(m_nTargetCardVal); // NCR check if our card is less than the top card already played if(pPlayCard < pDOC->GetCurrentTrickHighCard()) { m_nStatusCode = PLAY_POSTPONE; // or NOT_VIABLE ??? return m_nStatusCode; } // see if we played a card from the other hand that's equivalent // to this card; if so, discard low CSuitHoldings testSuit; testSuit << combinedSuit; testSuit << pCardLed; // needed for valid test // if (testSuit.AreEquivalentCards(pCardLed, pPlayCard)) { // the opposite card can do the trick if (bPlayingInHand && (playerSuit.GetNumCards() > 1)) { pPlayCard = playerSuit.GetBottomCard(); status << "PLFRC55! The " & pCardLed->GetName() & " is sufficient for the force, so discard the " & pPlayCard->GetFaceName() & " from hand.\n"; } else if (!bPlayingInHand && (dummySuit.GetNumCards() > 1)) { pPlayCard = dummySuit.GetBottomCard(); status << "PLFRC56! The " & pCardLed->GetName() & " is sufficient for the force, so discard the " & pPlayCard->GetFaceName() & " from dummy.\n"; } } else { // check for error if (pPlayCard == NULL) { status << "4PLFRC61! Error in force play -- no cards in " & (bPlayingInHand? "hand" : "dummy") & " usable in a force play.\n"; m_nStatusCode = PLAY_ERROR; return m_nStatusCode; } // got the forcing card status << "PLFRC62! Play the " & pPlayCard->GetName() & " from " & (bPlayingInHand? "hand" : "dummy") & " to try and force out the " & CardValToString(m_nTargetCardVal) & " now.\n"; m_nStatusCode = PLAY_COMPLETE; } } else { // we're in the opposite (discard) hand. so discard pPlayCard = playEngine.GetDiscard(); status << "PLFRC64! We're in the opposite hand of a force play, so discard the " & pPlayCard->GetName() & ".\n"; m_nStatusCode = PLAY_COMPLETE; } break; case 3: // playing fourth -- can't use a force play here return PLAY_POSTPONE; break; } // done ASSERT(pPlayCard->IsValid()); return m_nStatusCode; }
// // PlaySecond() // // default implementation, generally should be overridden in derived classes // CCard* CPlayEngine::PlaySecond() { CPlayerStatusDialog& status = *m_pStatusDlg; status << "5PLAY2! Playing second, using default player logic.\n"; // get play info int nDummyPos = pDOC->GetDummyPosition(); CCard* pCardLed = pDOC->GetCurrentTrickCardLed(); int nSuitLed = pCardLed->GetSuit(); int nFaceValue = pCardLed->GetFaceValue(); CCard* pCurrTopCard = pDOC->GetCurrentTrickHighCard(); int nTrumpSuit = pDOC->GetTrumpSuit(); CSuitHoldings& suit = m_pHand->GetSuit(nSuitLed); // card to play CCard* pCard = NULL; // second hand low int numCardsInSuit = suit.GetNumCards(); if (numCardsInSuit > 0) { // default behavior -- just play the low card pCard = m_pHand->GetSuit(nSuitLed).GetBottomCard(); if (numCardsInSuit > 1) { if (*pCard < *pCurrTopCard) status << "PLY2C1! Play second hand low with the " & pCard->GetFaceName() & ".\n"; else status << "PLY2C2! As second hand, we play the lowest card we have in the suit, the " & pCard->GetFaceName() & ".\n"; } else { status << "PLY2C4! Play our only " & STSS(nSuitLed) & ", the " & pCard->GetFaceName() & ".\n"; } } else { // no cards in the suit led // trump here if possible if (m_pHand->GetNumTrumps() > 0) { // CSuitHoldings& trumpSuit = m_pHand->GetSuit(nTrumpSuit); // see if partner would win the suit otherwise CGuessedSuitHoldings& partnerSuit = m_pPlayer->GetGuessedHand(m_nPartnerPosition)->GetSuit(nSuitLed); CCardList outstandingCards; GetOutstandingCards(nSuitLed, outstandingCards); if (partnerSuit.AreAllCardsIdentified() && partnerSuit.HasCard(outstandingCards[0]->GetFaceValue())) { // partner may win the trick, so discard status << "PLY2K1! We could trump here, but we know partner holds the " & outstandingCards[0]->GetName() & " and can win the trick, so discard the " & pCard->GetName() & ".\n"; } else { // trump here if possible // but first see if we're playing ahead of dummy (dummy is to our left), // and dummy is also void in the suit CGuessedHandHoldings* pDummyHand = m_pPlayer->GetGuessedHand(nDummyPos); if ((m_pLHOpponent == pDOC->GetDummyPlayer()) && (pDummyHand->GetSuit(nSuitLed).GetNumRemainingCards() == 0) && (pDummyHand->GetSuit(nTrumpSuit).GetNumRemainingCards() > 0)) { // dummy is also void, so trump if we have a trump higher than dummy's CGuessedCard* pDummyTopTrump = pDummyHand->GetSuit(nTrumpSuit).GetAt(0); if (trumpSuit.GetNumCardsAbove(pDummyTopTrump->GetFaceValue()) > 0) { // go ahead and ruff pCard = trumpSuit.GetLowestCardAbove(pDummyTopTrump->GetFaceValue()); status << "PLY2M1! Trump here, making sure to thwart dummy's " & pDummyTopTrump->GetFaceName() & " of trumps by playing the " & pCard->GetFaceName() & ".\n"; } else { // dummy would overtrump pCard = GetDiscard(); status << "PLY2M2! We'd like to trump here, but Dummy may overruff, so discard the " & pCard->GetName() & ".\n"; } } else { // safe to trump -- play the lowest trump pCard = trumpSuit.GetBottomCard(); status << "PLY2P1! Trump with the " & pCard->GetFaceName() & ".\n"; } } } else { // discard pCard = GetDiscard(); status << "PLY2Y! We have no " & SuitToString(nSuitLed) & ", so discard the " & pCard->GetName() & ".\n"; } } // ASSERT(pCard->IsValid()); return pCard; }
// //----------------------------------------------------- // // 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; }
// //=============================================================================== // // TryConvention() // // check if we can open with a preemptive 3 or 4 bid // BOOL CShutoutBidsConvention::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 // //-------------------------------------------------------- // // Now check for a shutout bid of 3 or 4 // // at the very minimum, should have a 6-card suit // if (hand.GetNumSuitsOfAtLeast(6) < 1) return FALSE; // // first find (a) long suit // /* for(i=0;i<4;i++) { if (hand.numCardsInSuit[i] >= 6) { // a 7-card suit needs 2 honors, and a a 6-card suit needs 3 if ( ((hand.GetNumCardsInSuit(i) >= 7) && (hand.GetNumhonorsInSuit(i) >= 2)) || ((hand.GetNumCardsInSuit(i) == 6) && (hand.GetNumhonorsInSuit(i) >= 3)) ) break; } } */ // assume the long suit is the preferred one int nSuit = hand.GetPreferredSuit(); CSuitHoldings& suit = hand.GetSuit(nSuit); int numCards = suit.GetNumCards(); int numHonors = suit.GetNumHonors(); // a 6-card suit needs 3 honors, and a 7+ card suit needs 2 if ( ((numCards == 6) && (numHonors < 3)) || ((numCards >= 7) && (numHonors < 2)) ) return FALSE; // // then check for Aces, Kings, or Queens in outside suits int nBid; BOOL bViolation = FALSE; for(int i=0;i<4;i++) { if (i == nSuit) continue; // a solitary Q is okay for a Shutout bid, but any higher honors // are not CSuitHoldings& suit = hand.GetSuit(i); if (suit.HasAce() || suit.HasKing()) return FALSE; } // if (bidState.numCardsInSuit[nSuit] >= 8) { nBid = MAKEBID(nSuit,4); status << "D00! Have a " & bidState.numCardsInSuit[nSuit] & "-card " & STSS(nSuit) & " suit with no tricks outside the suit, so make a shutout bid of " & BTS(nBid) & ".\n"; } else if (bidState.numCardsInSuit[nSuit] >= 7) { nBid = MAKEBID(nSuit,3); status << "D04! Have a " & bidState.numCardsInSuit[nSuit] & "-card " & STSS(nSuit) & " suit with no tricks outside the suit, so make a shutout bid of " & BTS(nBid) & ".\n"; } bidState.SetBid(nBid); bidState.SetConventionStatus(this, CONV_INVOKED); return TRUE; }
// //----------------------------------------------------- // // 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; }