int main(int argc, char *argv[]) { // Setup deck of cards CardSet deck; for (Rank r = RANK_BEGIN; r != RANK_END; ++r) { for (Suit s = SUIT_BEGIN; s != SUIT_END; ++s) { Card card(r, s); deck.insert(card); } } unsigned long long count = 0; // Test each starting hand for (CardSet::const_iterator i = deck.begin(); i != deck.end(); ++i) { CardSet::const_iterator j = i; for (++j; j != deck.end(); ++j) { string hole = Card::pairString(*i, *j); CardSet test(deck); Hand hand; test.erase(*i); hand.append(*i); test.erase(*j); hand.append(*j); count++; board(hole, test, hand); } } cout << "TOTAL: " << count << endl; printStats(); return 0; }
void Observer::cardsPickedUp(const PlayerId *playerId, const CardSet &cardSet) { mPlayersCards[playerId] += cardSet.size(); CardSet& set = mCurrentRoundData->mPickedUpCards[playerId]; unsigned int oldSize = set.size(); set.insert(cardSet.begin(), cardSet.end()); assert(oldSize + cardSet.size() == set.size()); }
bool Engine::findByPtr(const CardSet& cards, const Card* card) { for (CardSet::const_iterator it = cards.begin(); it != cards.end(); ++it) { if (&*it == card) { return true; } } return false; }
void Observer::cardsDropped(const PlayerId *playerId, const CardSet &cardSet) { mPlayersCards[playerId] -= cardSet.size(); if (mCurrentRoundData->mDroppedCards.find(playerId) == mCurrentRoundData->mDroppedCards.end()) { mCurrentRoundData->mDroppedCards[playerId] = CardSet(); } CardSet& set = mCurrentRoundData->mDroppedCards[playerId]; unsigned int oldSize = set.size(); set.insert(cardSet.begin(), cardSet.end()); assert(oldSize + cardSet.size() == set.size()); }
void board(const string& hole, const CardSet& deck, const Hand& hand) { HandStats s = stats[hole]; for (CardSet::const_iterator i = deck.begin(); i != deck.end(); ++i) { CardSet::const_iterator j = i; for (++j; j != deck.end(); ++j) { CardSet::const_iterator k = j; for (++k; k != deck.end(); ++k) { s.count++; s.outs[ board_rank(hand, *i, *j, *k) ]++; } } } stats[hole] = s; }
bool Engine::playCurrentRound() { #define CHECK_QUIT \ if (mQuit.get()) { \ return false; \ } lock(); if (!mCurrentRoundIndex) { mCurrentRoundIndex = &mRoundIndex; // prepare round data // pick current player as first attacker mAttackers.push_back(mCurrentPlayer); // if there was no deal yet (very first round) - do not consider cards while picking next players std::map<const PlayerId*, CardSet>* cards = *mCurrentRoundIndex ? &mPlayersCards : NULL; // pick next player as defender mDefender = Rules::pickNext(mGeneratedIds, mCurrentPlayer, cards); // gather rest players as additional attackers const PlayerId* attacker = mDefender; while((attacker = Rules::pickNext(mGeneratedIds, attacker, cards)) != mCurrentPlayer) { if (attacker) { mAttackers.push_back(attacker); } } unlock(); std::for_each(mGameObservers.begin(), mGameObservers.end(), RoundStartNotification(mAttackers, mDefender, mRoundIndex)); // deal cards dealCards(); lock(); mMaxAttackCards = Rules::maxAttackCards(mPlayersCards[mDefender].size()); assert(mMaxAttackCards); } CardSet& defenderCards = mPlayersCards[mDefender]; if (!mCurrentRoundAttackerId) { mCurrentRoundAttackerId = mAttackers[0]; mPassedCounter = 0; } Player& defender = *mPlayers[mDefender]; unlock(); for (;;) { if (mTableCards.attackCards().size() == mMaxAttackCards) { // defender has no more cards - defend succeeded break; } const Card* attackCardPtr; if (mPickAttackCardFromTable) { assert(!mTableCards.attackCards().empty()); attackCardPtr = &*(mTableCards.attackCards().end() - 1); } else { CardSet attackCards = Rules::getAttackCards(mTableCards.all(), mPlayersCards[mCurrentRoundAttackerId]); Player& currentAttacker = *mPlayers[mCurrentRoundAttackerId]; if (mTableCards.empty()) { attackCardPtr = attackCards.empty() ? NULL : ¤tAttacker.attack(mDefender, attackCards); } else { // ask for pitch even with empty attackCards - expected NULL attack card pointer attackCardPtr = currentAttacker.pitch(mDefender, attackCards); } // check if quit requested and only after that transfer move to defender CHECK_QUIT; if (attackCards.empty() || !attackCardPtr) { lock(); // player skipped the move - pick next attacker mCurrentRoundAttackerId = Rules::pickNext(mAttackers, mCurrentRoundAttackerId, &mPlayersCards); // if more than one attacker and we have first attacker again - reset pass counter if (mAttackers.size() > 1 && mCurrentRoundAttackerId == mAttackers[0]) { mPassedCounter = 0; } mPassedCounter++; unlock(); if (mPassedCounter == mAttackers.size()) { // all attackers "passed" - round ended break; } continue; } assert(attackCardPtr); if(!findByPtr(attackCards, attackCardPtr)) { // invalid card returned - the card is not from attackCards assert(!attackCards.empty()); // take any card attackCardPtr = &*attackCards.begin(); } Card attackCard = *attackCardPtr; lock(); mTableCards.addAttackCard(attackCard); mPlayersCards[mCurrentRoundAttackerId].erase(attackCard); unlock(); CHECK_QUIT; std::for_each(mGameObservers.begin(), mGameObservers.end(), CardsDroppedNotification(mCurrentRoundAttackerId, attackCard)); // the card is removed from the `attackCards` and is added to `mTableCards`, so update its pointer attackCardPtr = &*std::find(mTableCards.attackCards().begin(), mTableCards.attackCards().end(), attackCard); } if (mDefendFailed) { continue; } CardSet defendCards = Rules::getDefendCards(*attackCardPtr, defenderCards, mDeck->trumpSuit()); const Card* defendCardPtr = defender.defend(mCurrentRoundAttackerId, *attackCardPtr, defendCards); bool noCardsToDefend = defendCards.empty(); bool userGrabbedCards = !defendCardPtr; bool invalidDefendCard = !findByPtr(defendCards, defendCardPtr); lock(); mPickAttackCardFromTable = false; unlock(); if(noCardsToDefend || userGrabbedCards || invalidDefendCard) { // defend failed lock(); mDefendFailed = true; unlock(); } else { lock(); mTableCards.addDefendCard(*defendCardPtr); defenderCards.erase(*defendCardPtr); unlock(); CHECK_QUIT; std::for_each(mGameObservers.begin(), mGameObservers.end(), CardsDroppedNotification(mDefender, *defendCardPtr)); } } if (mDefendFailed) { lock(); defenderCards.insert(mTableCards.all().begin(), mTableCards.all().end()); defender.cardsUpdated(defenderCards); unlock(); CHECK_QUIT; std::for_each(mGameObservers.begin(), mGameObservers.end(), CardsReceivedNotification(mDefender, mTableCards.all())); } else { std::for_each(mGameObservers.begin(), mGameObservers.end(), CardsGoneNotification(mTableCards.all())); } // cleanup lock(); mCurrentRoundAttackerId = NULL; mMaxAttackCards = 0; mCurrentRoundIndex = NULL; unlock(); CHECK_QUIT; std::for_each(mGameObservers.begin(), mGameObservers.end(), RoundEndNotification(mRoundIndex)); return !mDefendFailed; }