📄 hearts.cpp
字号:
if (played.size ()) { // Check if cards of the same colour are available return (aPos[played[0]->colour ()] == -1) ? findWorstCard (pile, aPos) : findLowerCard (pile, aPos); } else { // Player starts the round: If he has loads of spades: Play them unsigned int nrSpades (numberOfCards (aPos, CardWidget::SPADES)); unsigned int missingSpades (cards.size () - nrSpades - aPlayed[CardWidget::SPADES]); // If there are still spades left (with other players) and either the // player has no high spades or loads of spades: Play them if (missingSpades && (!playedSQ) && (((aPos[CardWidget::SPADES] != -1) && (pile[aPos[CardWidget::SPADES]]->number () < CardWidget::QUEEN)) || (((missingSpades / 3) + 1) < nrSpades))) { unsigned int pos ((aPos[1] >= 0) ? aPos[1] + 1 : ((aPos[0] >= 0) ? aPos[0] + 1: 0)); TRACE5 ("Hearts::findPos2Play (unsigned int) - Starting with spade at " << pos << " (" << *pile[pos] << ')'); return pos; } // Else: Search for a low card int pos (0); for (unsigned int card (CardWidget::TWO); card <= CardWidget::ACE; ++card) { pos = 0; while ((pos = pile.find (CardWidget::NUMBERS (card), pos)) != -1) { CardWidget::COLOURS colour (pile[pos]->colour ()); // Play the lowest card, if there are still cards of that colour // owned by other players and - if it is a heart - there are // already played hearts. TRACE9 ("Hearts::findPos2Play (unsigned int) - Analyzing " << *pile[pos] << "; Played: " << aPlayed[colour] << "; I have: " << numberOfCards (aPos, colour)); if ((aPlayed[colour] + numberOfCards (aPos, colour)) < (cards.size () / NUM_PLAYERS)) { TRACE8 ("Hearts::findPos2Play (unsigned int) - Considering to " "play " << *pile[pos] << "; Played: " << aPlayed[colour]); if ((colour != CardWidget::HEARTS) || aPlayed[CardWidget::HEARTS]) { TRACE5 ("Hearts::findPos2Play (unsigned int) - Starting with " << *pile[pos]); return pos; } } ++pos; } } TRACE1 ("Hearts::findPos2Play (unsigned int) - All cards for player " << player); } return 0;}//-----------------------------------------------------------------------------/// Find a lower card than the previously played ones/// \param pile: Pile from which to play/// \param aPositions: Array with positions of cards/// \returns \c Position of card to play//-----------------------------------------------------------------------------unsigned int Hearts::findLowerCard (const ICardPile& pile, const int aPositions[4]) { TRACE9 ("Hearts::findLowerCard (const ICardPile&, const int[4]"); CardWidget::COLOURS colour (played[0]->colour ()); unsigned int posWinner (check4Winner ()); // Play queen of spades, if there's already a higher card in the pile if ((colour == CardWidget::SPADES) && (played[posWinner]->number () > CardWidget::QUEEN)) return ((pile[aPositions[CardWidget::SPADES]]->number () == CardWidget::QUEEN) || (numberOfCards (aPositions, CardWidget::SPADES) == 1) || (pile[aPositions[CardWidget::SPADES] - 1]->number () != CardWidget::QUEEN) ? aPositions[CardWidget::SPADES] : aPositions[CardWidget::SPADES] - 1); // Play high card of the colour, if last player and pile contains no // counting card, except if that would mean to play the queen of spades. if ((played.size () == (NUM_PLAYERS - 1)) && !pointsOfPile (played)) return ((colour != CardWidget::SPADES) || (pile[aPositions[CardWidget::SPADES]]->number () != CardWidget::QUEEN) || numberOfCards (aPositions, CardWidget::SPADES) == 1) ? aPositions[colour] : aPositions[colour] - 1; else { // Play highest card lower than the previously played ones int card (0); Check3 (played.size ()); CardWidget::NUMBERS highest (played[posWinner]->number ()); TRACE9 ("Hearts::findLowerCard (const ICardPile&, unsigned int[4]) - Try to" " be below " << *played[posWinner]); // Search for a lower card unsigned int nrCards (numberOfCards (aPositions, colour)); card = aPositions[colour] + 1; Check3 (card >= 1); do { Check3 (pile[card - 1]->colour () == colour); if (pile[--card]->number () < highest) { // Found a lower card; test if the highest is the ace of // spades and you have the queen and are about to play the king if ((colour == CardWidget::SPADES) && (highest == CardWidget::ACE) && card && (pile[card - 1]->number () == CardWidget::QUEEN) && (pile[card - 1]->colour () == CardWidget::SPADES)) --card; TRACE5 ("Hearts::findLowerCard (const ICardPile&, unsigned int[4]) - " "Playing card at " << card << ": " << *pile[card]); return card; } } while (--nrCards); // Try to not play the queen of spades, if possible if ((colour == CardWidget::SPADES) && (card < aPositions[CardWidget::SPADES]) && (pile[card]->number () == CardWidget::QUEEN)) { Check3 (pile[card + 1]->colour () == CardWidget::SPADES); ++card; } if (played.size () == (NUM_PLAYERS - 1)) card = aPositions[colour]; TRACE5 ("Hearts::findLowerCard (const ICardPile&, unsigned int[4]) - " "Forced to play card at " << card << ": " << *pile[card]); return card; }}//-----------------------------------------------------------------------------/// Find the worst card to play (defined as having the highest number of bad/// points (like the queen of spades with 13 points and every heart with 1/// point) or the highest numbered card)./// \param pile: Pile from which to play/// \param aPositions: Array with positions of cards/// \returns \c Position of card to play or -1//-----------------------------------------------------------------------------unsigned int Hearts::findWorstCard (const ICardPile& pile, const int aPositions[4]) { TRACE9 ("Hearts::findWorstCard (const ICardPile&, const int[4]"); // Search for queen of spades or any heart or a high card unsigned int cardsPlayed (0); for (unsigned int i (0); i < NUM_PLAYERS; ++i) cardsPlayed += players[i].won->size (); if (cardsPlayed) { TRACE5 ("Hearts::findWorstCard (const ICardPile&, const int[4]) - Searching" " for SQ"); if (aPositions[2] > 0) for (int pos ((aPositions[1] >= 0) ? aPositions[1] + 1 : ((aPositions[0] >= 0) ? aPositions[0] + 1: 0)); pos <= aPositions[2]; ++pos) { TRACE9 ("Hearts::findWorstCard (const ICardPile&, const int[4]) - " "Searching for SQ at position " << pos); Check3 (pile[pos]->colour () == CardWidget::SPADES); if (pile[pos]->number () >= CardWidget::QUEEN) return static_cast<unsigned int> (pos); } // No high spade found: Try to play a heart (after the first round) TRACE5 ("Hearts::findWorstCard (const ICardPile&, unsigned int[4]) - " "Searching for hearts"); if (aPositions[CardWidget::HEARTS] != -1) return aPositions[CardWidget::HEARTS]; } // If everything else failes: Play a high card TRACE5 ("Hearts::findWorstCard (const ICardPile&, unsigned int[4]) - Searching " "for high cards"); int pos (0); for (int card (CardWidget::ACE); card >= CardWidget::TWO; --card) { pos = 0; while ((pos = pile.find (CardWidget::NUMBERS (card), pos)) != -1) { CardWidget::COLOURS colour (pile[pos]->colour ()); TRACE2 ("Hearts::findWorstCard (const ICardPile&, unsigned int[4]) - " "Checking card " << *pile[pos] << " at pos " << pos << " against " << aPlayed[colour] << " cards"); if (cardsPlayed || ((colour == CardWidget::SPADES) ? (card != CardWidget::QUEEN) : (colour != CardWidget::HEARTS))) return pos; ++pos; } } Check3 (0); return -1U;}//-----------------------------------------------------------------------------/// Counts the points in the passed pile. The queen of spades counts 13 points/// and every heart 1 point/// \param pile: Pile to inspect/// \returns \c unsigned int: Number of points//-----------------------------------------------------------------------------unsigned int Hearts::pointsOfPile (ICardPile& pile) { unsigned int points (0); for (unsigned int i (0); i < pile.size (); ++i) { CardWidget::COLOURS colour (pile[i]->colour ()); if (colour == CardWidget::HEARTS) ++points; else if ((colour == CardWidget::SPADES) && pile[i]->number () == CardWidget::QUEEN) points += 13; } TRACE7 ("Hearts::pointsOfPile (ICardPile&) - Number of points: " << points); return points;}//-----------------------------------------------------------------------------/// Changes the names of the playing people/// \param newPlayer: Array holding the new player//-----------------------------------------------------------------------------void Hearts::changeNames (const std::vector<Player*>& newPlayer) { Game::changeNames (newPlayer); std::vector<Player*> player; for (unsigned int i (0); i < NUM_PLAYERS; ++i) { player.push_back (actPlayers[(i + posServer) & 0x3]); players[i].name.set_text (actPlayers[i]->getName ()); } if (pScoreDlg) pScoreDlg->update (player);}//----------------------------------------------------------------------------/// Converts a pile-number to the actual pile/// \param newPlayer: Array holding the new player/// \param pile: ID of the pile to return/// \returns ICardPile*: Pointer to pile to use or NULL//----------------------------------------------------------------------------ICardPile* Hearts::getPileOfPlayer (unsigned int player, unsigned int pile) { return ((player >= NUM_PLAYERS) || pile) ? NULL : players[player].hand;}//----------------------------------------------------------------------------/// Handles the messages the server might send for the hearts cardgame/// \param player: ID of player sending the message/// \param message: Message received from the server/// \returns bool: True, if message has been completey processed/// \throw YGP::ParseError, YGP::CommError: In case of an error an describing text//----------------------------------------------------------------------------bool Hearts::handleMessage (unsigned int player, const std::string& message) throw (YGP::ParseError, YGP::CommError) { if (gameStatus () == EXCHANGE) { TRACE1 ("Hearts::handleMessage (unsigned int player, const std::string&) - " << message << " (" << player << ')'); YGP::Tokenize command (message); std::string cmd (command.getNextNode ('=')); if (cmd == "Exchange") { std::string cards (command.getNextNode (';')); cmd = command.getNextNode ('='); unsigned long lPlayer (player); if ((cmd == "Player") && !stringToNumber (lPlayer, command.getNextNode (';').c_str ()) && (lPlayer < NUM_PLAYERS)) { Check3 (player ? (lPlayer == player) : true); if (!player) lPlayer = static_cast<unsigned long> (lPlayer); register unsigned int save (lPlayer); lPlayer = (lPlayer - posServer) & 0x3; // Don't exchange already exchanged cards if (save != posServer) { command = cards; unsigned long card (0); while (command.getNextNode (' ').size ()) { if (stringToNumber (card, command.getActNode ().c_str ())) break; TRACE9 ("Hearts::handleMessage (unsigned int, const std::string&) - " << lPlayer << ": " << card); card = players[lPlayer].hand->find (static_cast<unsigned int> (card)); Check3 (card < players[lPlayer].hand->size ()); if (card != -1U) movePile (aExchange[lPlayer], *players[lPlayer].hand, card, card); } } TRACE2 ("Hearts::handleMessage (unsigned int player, const std::string&) - " "Exchanged: " << aExchange[lPlayer].size () << " cards"); if (aExchange[lPlayer].size () == 3) { YGP::ConnectionMgr& cmgr (getConnectionMgr ()); // Inform other clients if (cmgr.getMode () == YGP::ConnectionMgr::SERVER) broadcastMessage (message); if (cardsExchanged (((cmgr.getMode () == YGP::ConnectionMgr::SERVER) ? (cmgr.getClients ().size () + 1) : NUM_PLAYERS) * 3)) { exchangeCards (); startPlaying (); } } return true; } } } return Game::handleMessage (player, message);}//----------------------------------------------------------------------------/// Checks if the number of exchanged cards is equal to the passed value./// \param cards: Number of cards to exchange/// \returns bool: True, if all cards have been exchanged/// \pre Game must be in EXCHANGE state//----------------------------------------------------------------------------bool Hearts::cardsExchanged (unsigned int cards) { Check1 (gameStatus () == EXCHANGE); for (unsigned i (0); i < NUM_PLAYERS; ++i) cards -= aExchange[i].size (); TRACE9 ("Hearts::cardsExchanged (unsigned int) - Remaining: " << cards); return !(cards - played.size ());}//-----------------------------------------------------------------------------/// Adds game-specific menus/// \param mgrUI: UIManager to add to//-----------------------------------------------------------------------------void Hearts::addMenus (Glib::RefPtr<Gtk::UIManager> mgrUI) { Check1 (mgrUI); Glib::ustring ui ("<menubar name='Menu'>" " <placeholder name='GameMenu'>" " <menu action='MB'>" " <menuitem action='HeartSort'/>" " <menuitem action='HeartSortCol'/>" " </menu></placeholder></menubar>"); Glib::RefPtr<Gtk::ActionGroup> grpAction (Gtk::ActionGroup::create ()); grpAction->add (Gtk::Action::create ("MB", _("H_earts"))); grpAction->add (Gtk::Action::create ("HeartSort", Gtk::Stock::SORT_ASCENDING, _("_Sort won cards (by number)")), Gtk::AccelKey ("<shft>S"), mem_fun (*this, &Hearts::sortWonByNumber)); grpAction->add (Gtk::Action::create ("HeartSortCol", Gtk::Stock::SORT_ASCENDING, _("Sort won cards (by _colour)")), Gtk::AccelKey ("S"), mem_fun (*this, &Hearts::sortWonByColour)); mgrUI->insert_action_group (grpAction); idMrg = mgrUI->add_ui_from_string (ui);}//-----------------------------------------------------------------------------/// Removes the game-specific menus/// \param mgrUI: UIManager to remove from//-----------------------------------------------------------------------------void Hearts::removeMenus (Glib::RefPtr<Gtk::UIManager> mgrUI) { Check1 (mgrUI); mgrUI->remove_ui (idMrg);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -