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