// // PlayBestCard() // // called on the third and fourth hand plays to try to win the trick // CCard* CPlayEngine::PlayBestCard(int nPosition) { CPlayerStatusDialog& status = *m_pStatusDlg; // status << "2PLAY3! Playing best card.\n"; // get play info CCard* pCurrentCard = pDOC->GetCurrentTrickCardLed(); int nSuitLed = pCurrentCard->GetSuit(); int nTopPos; CCard* pCurrTopCard = pDOC->GetCurrentTrickHighCard(&nTopPos); CString strTopCardPos = PositionToString(nTopPos); BOOL bPartnerHigh = FALSE; int nCurrentRound = pDOC->GetPlayRound(); int nCurrentSeat = pDOC->GetNumCardsPlayedInRound() + 1; CCard* pPartnersCard = pDOC->GetCurrentTrickCard(m_pPartner->GetPosition()); if (pPartnersCard == pCurrTopCard) bPartnerHigh = TRUE; // int nTrumpSuit = pDOC->GetTrumpSuit(); int numCardsInSuitLed = m_pHand->GetNumCardsInSuit(nSuitLed); // card to play CCard* pCard = NULL; // // first see if somebody trumped in this hand // if ((pDOC->WasTrumpPlayed()) && (nTrumpSuit != nSuitLed)) { // a trump has been played // see whether it was played by partner or by an opponent if (bPartnerHigh) { // partner trumped -- leave it alone for now pCard = GetDiscard(); status << "PLAYB10! We let partner's " & pCurrTopCard->GetName() & " trump ride and discard the " & pCard->GetName() & ".\n"; } else { // it was an opponent that did the trumping // see if we can overtrump CSuitHoldings& trumpSuit = m_pHand->GetSuit(nTrumpSuit); CCard* pTopTrump = NULL; if (trumpSuit.GetNumCards() > 0) pTopTrump = trumpSuit.GetTopCard(); if ((numCardsInSuitLed == 0) && (pTopTrump) && (*pTopTrump > *pCurrTopCard)) { // get the lowest trump that wil top the current top trump int numTopCards = trumpSuit.GetNumCardsAbove(pCurrTopCard); pCard = trumpSuit[numTopCards-1]; status << "PLAYB20! We can overtrump " & strTopCardPos & "'s " & pCurrTopCard->GetName() & " with the " & pCard->GetFaceName() & ".\n"; } else { // no chance to win, so discard pCard = GetDiscard(); if ((numCardsInSuitLed == 0) && (trumpSuit.GetNumCards() > 0)) status << "PLAYB22! We can't overtrump " & strTopCardPos & "'s " & pCurrTopCard->GetFaceName() & ", so discard the " & pCard->GetName() & ".\n"; else status << "PLAYB23! We can't beat the opponent's " & pCurrTopCard->GetFaceName() & " of trumps, so discard the " & pCard->GetName() & ".\n"; } } } else { // else nobody has played a trump this round, _or_ a trump was led // see if we can play trumps if (numCardsInSuitLed > 0) { // nope, gotta follow the suit that was led, trumps or otherwise // if we can beat the current top card, do so with the cheapest card CSuitHoldings& suit = m_pHand->GetSuit(nSuitLed); if (*(suit.GetTopCard()) > *pCurrTopCard) { // but see if the top card is partner's if (bPartnerHigh) { // see if we should unblock here if (ISSUIT(nTrumpSuit) && (nCurrentRound == 0) && (suit.GetNumHonors() == 1)) { // first round in an NT contract, with one honor // in the suit -- unblock pCard = suit.GetTopCard(); if (suit.GetNumCards() > 1) status << "PLAYB30! Drop the " & pCard->GetFaceName() & " here to unblock the suit for partner.\n"; } else { // else this is not an unblocking situation if (nCurrentSeat == 4) { // playing in 4th seat, high card is partner, so discard pCard = GetDiscard(); status << "PLAYB34! Partner's " & pCurrTopCard->GetFaceName() & " is high, so discard the " & pCard->GetName() & ".\n"; } else { // playing in third position -- decide whether to // let partner's card ride // do so if if partner's card beats all outstanding cards CCard* pTopOutstandingCard = GetHighestOutstandingCard(nSuitLed); if ((pTopOutstandingCard == NULL) || (*pCurrTopCard > *pTopOutstandingCard)) { // let partner's card ride pCard = GetDiscard(); status << "PLAYB36! Partner's " & pCurrTopCard->GetFaceName() & " is higher than any outstanding card, so discard the " & pCard->GetName() & ".\n"; } else { // partner's card is not necessarily highest, so top it pCard = suit.GetTopSequence().GetBottomCard(); status << "PLAYB37! Partner's " & pCurrTopCard->GetFaceName() & " might not win the round, so top it with the " & pCard->GetFaceName() & ".\n"; } } } } else { // else high card is opponent's, so beat it w/ highest card affordable // although, if playing in 3rd pos ahead of dummy, just play // high enuff to beat dummy if ((nCurrentSeat == 3) && (m_bLHDefender)) { CSuitHoldings& dummySuit = GetDummySuit(nSuitLed); int nDummyTopCard = 0; if (dummySuit.GetNumCards() > 0) nDummyTopCard = dummySuit[0]->GetFaceValue(); int nTopVal = Max(nDummyTopCard, pCurrTopCard->GetFaceValue()); pCard = suit.GetLowestCardAbove(nTopVal); // see if we can beat the top card or dummy's top card if (pCard) { if (nTopVal == nDummyTopCard) { // dummy has the top card and we can beat it status << "PLAYB38A! Playing third ahead of dummy, need to beat dummy's " & CardValToString(nDummyTopCard) & ".\n"; } else { // the top card is declarer's status << "PLAYB38B! Play high to win with the " & pCard->GetFaceName() & ".\n"; } } else { // else we can't beat dummy's top card, but play // high anyway to force out his winner pCard = suit.GetLowestCardAbove(pCurrTopCard); status << "PLAYB38C! We top declarer's " & pCurrTopCard->GetFaceName() & " to force a winner from dummy.\n"; } } else if (nCurrentSeat == 3) { // else we're playing 3rd, so play the lowest card from the top sequence pCard = suit.GetTopSequence().GetBottomCard(); status << "PLAYB40! Play high to win with the " & pCard->GetFaceName() & ".\n"; } else { // else we're playing last (4th) // play the cheapest card that will beat the top card pCard = suit.GetLowestCardAbove(pCurrTopCard); status << "PLAYB41! Play the " & pCard->GetFaceName() & " to win the trick.\n"; } } } else { // we don't have a card to top the current high card if (bPartnerHigh) { // but partner's card is high, so we're OK pCard = GetDiscard(); status << "PLAYB47! Partner's " & pCurrTopCard->GetFaceName() & " can win the trick, so discard the " & pCard->GetName() & ".\n"; } else { // else we're screwed pCard = GetDiscard(); status << "PLAYB48! We can't beat " & strTopCardPos & "'s " & pCurrTopCard->GetFaceName() & ", so discard the " & pCard->GetName() & ".\n"; } } } else if (ISSUIT(nTrumpSuit) && (nSuitLed != nTrumpSuit) && (m_pHand->GetNumCardsInSuit(nTrumpSuit) > 0)) { // here, we can play a trump, so do so if appropriate // see who has the top card in this round if (bPartnerHigh) { // let partner's card ride pCard = GetDiscard(); status << "PLAYB52! Although we could trump this hand, partner's " & pCurrTopCard->GetName() & " is high, so discard the " & pCard->GetName() & ".\n"; } else { // opponents have the high card (non-trump) -- so slam 'em pCard = m_pHand->GetSuit(nTrumpSuit).GetBottomCard(); status << "PLAYB55! With no cards in " & SuitToString(nSuitLed) & ", trump with the " & pCard->GetName() & ".\n"; } } else { // here we have zero cards in the suit and in trumps, so we're hosed pCard = GetDiscard(); status << "PLAYB52! With no cards in the suit led and no trumps, we discard the " & pCard->GetName() & ".\n"; } } // ASSERT(pCard->IsValid()); ASSERT(m_pHand->HasCard(pCard)); // return pCard; }
// // 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); } } } }
// // 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; }
// // 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; }
// // Perform() // PlayResult CTypeAFinesse::Perform(CPlayEngine& playEngine, CCombinedHoldings& combinedHand, CCardLocation& cardLocation, CGuessedHandHoldings** ppGuessedHands, CPlayerStatusDialog& status, CCard*& pPlayCard) { // Type A Finesse // - opportunistic play of a non-top card in second position to // finesse against LHO // 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; CCard* pTopCard = pDOC->GetCurrentTrickHighCard(); pPlayCard = NULL; CCard* pOppCard = NULL; // test preconditions if (!CPlay::IsPlayUsable(combinedHand, playEngine)) { m_nStatusCode = PLAY_INACTIVE; return PLAY_POSTPONE; } // check our position in the play switch(nOrdinal) { case 0: // can't use in first seat m_nStatusCode = PLAY_NOT_VIABLE; return m_nStatusCode; case 1: // playing second -- this is the key to the finesse // see if the wrong suit was led if (nSuitLed != m_nSuit) { m_nStatusCode = PLAY_INACTIVE; return PLAY_POSTPONE; } // check which hand we're playing in if (bPlayingInHand) { // playing second in our own hand (declarer) // see if it's time to finesse if (m_nTargetHand == IN_HAND) { // play the finesse card pPlayCard = m_pConsumedCard; status << "PLAFN20! Opportunistically finesse the " & pPlayCard->GetName() & " from hand in second position against " & PositionToString(playEngine.GetLHOpponent()->GetPosition()) & ".\n"; } else { // finessing in hand, but this is dummy? messed up status << "4PLAFN30! 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) { // finesse the card from dummy pPlayCard = m_pConsumedCard; status << "PLAFN54! Opportunistically finesse the " & pPlayCard->GetName() & " from dummy in second position against " & PositionToString(playEngine.GetRHOpponent()->GetPosition()) & ".\n"; } else { // messed up status << "4PLAFN60! 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; } } // all went OK m_nStatusCode = PLAY_IN_PROGRESS; break; case 2: // can't use this play in third posiiton m_nStatusCode = PLAY_NOT_VIABLE; return m_nStatusCode; case 3: // in 4th position, simply discard if (m_nStatusCode == PLAY_IN_PROGRESS) { // discard here, but see if we won if (pTopCard == m_pConsumedCard) { pPlayCard = playEngine.GetDiscard(); status << "PLAFN76! The finesse worked; finish the play by discarding the " & pPlayCard->GetName() & ".\n"; m_nStatusCode = PLAY_COMPLETE; } else { status << "PLAFN77! The finesse failed, so abandon the play\n"; m_nStatusCode = PLAY_NOT_VIABLE; } return m_nStatusCode; } else { // play is not active m_nStatusCode = PLAY_INACTIVE; return m_nStatusCode; } } // done ASSERT(pPlayCard->IsValid()); return m_nStatusCode; }
// // Perform() // PlayResult CHoldUp::Perform(CPlayEngine& playEngine, CCombinedHoldings& combinedHand, CCardLocation& cardLocation, CGuessedHandHoldings** ppGuessedHands, CPlayerStatusDialog& status, CCard*& pPlayCard) { // check which hand this is int nOrdinal = pDOC->GetNumCardsPlayedInRound(); CPlayer* pPlayer = playEngine.GetPlayer(); BOOL bPlayingInHand = (pDOC->GetCurrentPlayer() == pPlayer); CHandHoldings& playerHand = *(combinedHand.GetPlayerHand()); CHandHoldings& dummyHand = *(combinedHand.GetPartnerHand()); CSuitHoldings& playerSuit = playerHand.GetSuit(m_nSuit); CSuitHoldings& dummySuit = dummyHand.GetSuit(m_nSuit); CCard* pCardLed = pDOC->GetCurrentTrickCardByOrder(0); int nSuitLed = NONE; if (pCardLed) nSuitLed = pCardLed->GetSuit(); // see if a trump was played in this round BOOL bTrumped = FALSE; int nTrumpSuit = pDOC->GetTrumpSuit(); if ((nSuitLed != nTrumpSuit) && (pDOC->WasTrumpPlayed())) bTrumped = TRUE; pPlayCard = NULL; CCard* pOppCard = NULL; // CCard* pRoundTopCard = pDOC->GetCurrentTrickHighCard(); CCard* pDeclarerCard = pDOC->GetCurrentTrickCard(playEngine.GetPlayerPosition()); CCard* pDummysCard = pDOC->GetCurrentTrickCard(playEngine.GetPartnerPosition()); CCard* pPartnersCard = bPlayingInHand? pDummysCard : pDeclarerCard; BOOL bPartnerHigh = (pRoundTopCard == pPartnersCard); // BOOL bValid = FALSE; // test preconditions if (!CPlay::IsPlayUsable(combinedHand, playEngine)) { m_nStatusCode = PLAY_INACTIVE; return PLAY_POSTPONE; } // a holdup is simple -- discard instead of winning switch(nOrdinal) { case 0: // can't hold up here m_nStatusCode = PLAY_INACTIVE; return PLAY_POSTPONE; case 1: if (bPlayingInHand) pPlayCard = playerHand.GetDiscard(); else pPlayCard = dummyHand.GetDiscard(); status << "PLHLD04! Hold up a round of " & STS(m_nSuit) & " and discard the " & pPlayCard->GetFaceName() & " from " & (bPlayingInHand? "hand" : "dummy") & ".\n"; m_nStatusCode = PLAY_IN_PROGRESS; break; case 2: // can't hold up here m_nStatusCode = PLAY_INACTIVE; return PLAY_POSTPONE; case 3: // complete the hold-up if (m_nStatusCode != PLAY_IN_PROGRESS) return PLAY_INACTIVE; if (bPlayingInHand) pPlayCard = playerHand.GetDiscard(); else pPlayCard = dummyHand.GetDiscard(); status << "PLHLD08! Finish the hold-up and discard the " & pPlayCard->GetFaceName() & " from " & (bPlayingInHand? "hand" : "dummy") & ".\n"; m_nStatusCode = PLAY_COMPLETE; break; } // done ASSERT(pPlayCard->IsValid()); return m_nStatusCode; }
// // 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; }