📄 hearts.cpp
字号:
//$Id: Hearts.cpp,v 1.51 2006/08/09 16:33:32 markus Rel $//PROJECT : Cardgames//SUBSYSTEM : Hearts//REFERENCES ://TODO ://BUGS ://REVISION : $Revision: 1.51 $//AUTHOR : Markus Schwab//CREATED : 24.12.2002//COPYRIGHT : Copyright (C) 2002 - 2006// This program is free software; you can redistribute it and/or modify// it under the terms of the GNU General Public License as published by// the Free Software Foundation; either version 2 of the License, or// (at your option) any later version.// This program is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the// GNU General Public License for more details.// You should have received a copy of the GNU General Public License// along with this program; if not, write to the Free Software// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.#include <sstream>#include <cardgames-cfg.h>#include <gtkmm/menu.h>#include <gtkmm/stock.h>#include <gtkmm/statusbar.h>#include <gtkmm/messagedialog.h>#include <YGP/Check.h>#include <YGP/Trace.h>#include <YGP/ConnMgr.h>#include <YGP/Tokenize.h>#include <Player.h>#include <ScoreDlg.h>#include "Hearts.h"const unsigned int Hearts::COLS_PLAYER[NUM_PLAYERS] = { 5, 3, 5, 9 };const unsigned int Hearts::ROWS_PLAYER[NUM_PLAYERS] = { 3, 7, 10, 7 };unsigned int Hearts::ENDPOINTS (100);//-----------------------------------------------------------------------------/// Constructor/// \param parent: Parent widget to display the game in/// \param statusbar: Status bar widget to display information about the game/// \param cardset: Cardset to use/// \param player: Vector of player/// \param posPlayer: Position of player for the server/// \param mxSerialize: Mutex to serialize messages from the server//-----------------------------------------------------------------------------Hearts::Hearts (Gtk::Box& parent, Gtk::Statusbar& statusbar, CardSet& cardset, const std::vector<Player*>& player, unsigned int posPlayer, YGP::Mutex& mxSerialize) : Game (parent, statusbar, cardset, player, posPlayer, mxSerialize, 18, 12), playedSQ (false), player2Exchange (3), played (ICardPile::COMPRESSED, ICardPile::SHOWFACE), pScoreDlg (NULL) { TRACE9 ("Hearts::Hearts (Box&, Statusbar&, CardSet&, ..."); CardHPile* hand0 (new CardHPile); players[0].hand = hand0; CardHPile* won0 (new CardHPile); players[0].won = won0; CardHPile* hand2 (new CardHPile); players[2].hand = hand2; CardHPile* won2 (new CardHPile); players[2].won = won2; CardVPile* hand1 (new CardVPile); players[1].hand = hand1; CardVPile* won1 (new CardVPile); players[1].won = won1; CardVPile* hand3 (new CardVPile); players[3].hand = hand3; CardVPile* won3 (new CardVPile); players[3].won = won3; int width (cards.getCard (0).getImageWidth ()); int height (cards.getCard (0).getImageHeight ()); attach (*won0, COLS_PLAYER[0], COLS_PLAYER[0] + 3, ROWS_PLAYER[0] - 2, ROWS_PLAYER[0] - 1, Gtk::EXPAND); attach (*hand0, COLS_PLAYER[0], COLS_PLAYER[0] + 3, ROWS_PLAYER[0], ROWS_PLAYER[0] + 1, Gtk::EXPAND); won0->set_size_request (width + 12 * 7, height + 5); hand0->set_size_request (width + 12 * 18, height + 5); attach (*won1, COLS_PLAYER[1] - 2, COLS_PLAYER[1] - 1, ROWS_PLAYER[1], ROWS_PLAYER[1] + 1, Gtk::EXPAND); attach (*hand1, COLS_PLAYER[1], COLS_PLAYER[1] + 1, ROWS_PLAYER[1], ROWS_PLAYER[1] + 1, Gtk::EXPAND); won1->set_size_request (width + 5, height + 12 * 7); hand1->set_size_request (width + 5, height + 12 * 7); attach (*won2, COLS_PLAYER[2], COLS_PLAYER[2] + 3, ROWS_PLAYER[2] + 4, ROWS_PLAYER[2] + 5, Gtk::EXPAND); attach (*hand2, COLS_PLAYER[2], COLS_PLAYER[2] + 3, ROWS_PLAYER[2], ROWS_PLAYER[2] + 1, Gtk::EXPAND); won2->set_size_request (width + 12 * 7, height + 5); hand2->set_size_request (width + 12 * 18, height + 5); attach (*won3, COLS_PLAYER[3] + 2, COLS_PLAYER[3] + 3, ROWS_PLAYER[3], ROWS_PLAYER[3] + 1, Gtk::EXPAND); attach (*hand3, COLS_PLAYER[3], COLS_PLAYER[3] + 1, ROWS_PLAYER[3], ROWS_PLAYER[3] + 1, Gtk::EXPAND); won3->set_size_request (width + 5, height + 12 * 7); hand3->set_size_request (width + 5, height + 12 * 7); // Show and attach card-piles changeNames (player); for (unsigned int i (0); i < NUM_PLAYERS; ++i) { attach (players[i].name, COLS_PLAYER[i], COLS_PLAYER[i] + ((i & 1) ? 1 : 3), ROWS_PLAYER[i] + 2, ROWS_PLAYER[i] + 3, Gtk::EXPAND, Gtk::EXPAND, 1); players[i].won->setShowOption (ICardPile::SHOWBACK); players[i].hand->setShowOption (i ? ICardPile::SHOWBACK : ICardPile::SHOWFACE); players[i].hand->setStyle ((i & 1) ? ICardPile::QUITE_COMPRESSED : ICardPile::COMPRESSED); players[i].won->setStyle (ICardPile::VERY_COMPRESSED); } // Show played area played.setStyle (ICardPile::COMPRESSED); attach (played, 6, 7, 7, 8, Gtk::SHRINK, Gtk::SHRINK, 5); played.set_size_request (width + 150, height); show_all ();}//-----------------------------------------------------------------------------/// Destructor//-----------------------------------------------------------------------------Hearts::~Hearts () { TRACE9 ("Hearts::~Hearts ()"); delete pScoreDlg; clean ();}//-----------------------------------------------------------------------------/// Makes the move for the next player./// \param player: Actual player/// \returns \c int: Next player or -1 if end of game//-----------------------------------------------------------------------------int Hearts::makeMove (unsigned int player) { TRACE5 ("Hearts::makeMove () - Turn of player " << player); Check1 (gameStatus () == PLAYING); Check3 (pos2Play == pos1Play); if (pos2Play == -1U) { pos2Play = pos1Play = findPos2Play (player); TRACE8 ("Hearts::makeMove (unsigned int) - Going to play card at pos " << pos2Play); flipCards2Play (*players[player].hand, pos1Play, pos2Play); } else { TRACE9 ("Hearts::makeMove (unsigned int) - Playing card at pos " << pos2Play); ICardPile& pile (*players[player].hand); Check3 (pos2Play < pile.size ()); aPlayed[pile[pos2Play]->colour ()]++; if ((pile[pos2Play]->colour () == CardWidget::SPADES) && (pile[pos2Play]->number () == CardWidget::QUEEN)) playedSQ = true; movePile (played, pile, pos1Play, pos2Play); pos1Play = pos2Play = -1U; player = calcNextPlayer (player); } return player;}//-----------------------------------------------------------------------------/// Starts the game by dealing the cards//-----------------------------------------------------------------------------void Hearts::start () { TRACE9 ("Hearts::start ()"); Game::start (); // Hide won pile again (if not in debug-mode)#if TRACELEVEL > 0 if (players[1].won->getShowOption () == ICardPile::SHOWBACK)#endif showWonCards (false); Check2 (!played.size ()); ICardPile pile; if (randomizeCardsToPile (pile)) { for (unsigned int i (0); i < NUM_PLAYERS; ++i) for (unsigned int j (0); j < (cards.size () / NUM_PLAYERS); ++j) players[(i - posServer) & 0x3].hand->insertColourSorted (pile.removeTopCard ()); if (pScoreDlg) { unsigned int player; int points; pScoreDlg->getMaxPoints (points, player); if ((unsigned int)points >= ENDPOINTS) { delete pScoreDlg; pScoreDlg = NULL; } } if (player2Exchange) { Glib::ustring stat (_("Select 3 cards to exchange with %1")); Check3 (actPlayers.size () > player2Exchange); Check3 (actPlayers[player2Exchange & 0x3]); stat.replace (stat.find ("%1"), 2, actPlayers[player2Exchange]->getName ()); status.pop (); status.push (stat); setGameStatus (EXCHANGE); setNextPlayer (0); enableHuman (); } else startPlaying (); }}//-----------------------------------------------------------------------------/// Remove cards from everything which can hold them//-----------------------------------------------------------------------------void Hearts::clean () { TRACE9 ("Hearts::clean ()"); for (unsigned int i (0); i < NUM_PLAYERS; ++i) { players[i].hand->clear (); players[i].won->clear (); } played.clear (); disableHuman (); Game::clean ();}//-----------------------------------------------------------------------------/// Shows or hides the cards of the computer player/// \param open: Flag if cards should be shown or hidden//-----------------------------------------------------------------------------void Hearts::playOpen (bool open) { for (unsigned int i (1); i < NUM_PLAYERS; ++i) { players[i].hand->setShowOption (open ? ICardPile::SHOWFACE : ICardPile::SHOWBACK); players[i].hand->setStyle (open ? ICardPile::COMPRESSED : ICardPile::QUITE_COMPRESSED); players[i].won->setShowOption (open ? ICardPile::SHOWFACE : ICardPile::SHOWBACK); players[i].won->setStyle (open ? ICardPile::COMPRESSED : ICardPile::VERY_COMPRESSED); } players[0].won->setShowOption (open ? ICardPile::SHOWFACE : ICardPile::SHOWBACK); players[0].won->setStyle (open ? ICardPile::COMPRESSED : ICardPile::VERY_COMPRESSED);}//-----------------------------------------------------------------------------/// Enables the cards of the human player/// \returns \c Flag, if time should be continued/// \remarks Depending of the status of the game (PLAYING2) also the top card/// of the played pile is enabled//-----------------------------------------------------------------------------bool Hearts::enableHuman () { Check3 (activeCards.empty ()); Check3 ((gameStatus () == PLAYING) || (gameStatus () == EXCHANGE)); TRACE2 ("Hearts::enableHuman () - Human has " << players[0].hand->size () << " cards"); for (int i (players[0].hand->size () - 1); i >= 0; --i) activeCards.push_back ((*players[0].hand)[i]->signal_clicked ().connect (bind (mem_fun (*this, (&Hearts::cardSelected)), i))); if (gameStatus () == EXCHANGE) for (int i (played.size () - 1); i >= 0; --i) activeCards.push_back (played[i]->signal_clicked ().connect (bind (mem_fun (*this, (&Hearts::takeCard)), i))); return Game::enableHuman ();}//-----------------------------------------------------------------------------/// Callback after clicking on a card in the played field/// \param iCard: Offset of card in hand//-----------------------------------------------------------------------------void Hearts::takeCard (unsigned int iCard) { TRACE9 ("Hearts::takeCard (unsigned int) - Picking up card " << iCard); Check1 (iCard < played.size ()); Check1 (gameStatus () == EXCHANGE); movePile (*players[0].hand, played, iCard, iCard); players[0].hand->sortByColour (); makeNextMoves ();}//-----------------------------------------------------------------------------/// Callback after clicking on a card in hand/// \param iCard: Offset of card in hand//-----------------------------------------------------------------------------void Hearts::cardSelected (unsigned int iCard) { TRACE5 ("Hearts::cardSelected (unsigned int) - Position " << iCard); Check1 (iCard < players[0].hand->size ()); Check3 ((gameStatus () == PLAYING) || (gameStatus () == EXCHANGE)); Check3 (pos1Play == -1U); Check3 (pos2Play == -1U); // Hide won pile again (if not in debug-mode)#if TRACELEVEL > 0 if (players[1].won->getShowOption () == ICardPile::SHOWBACK)#endif showWonCards (false); if (moveSelectedCardToPlayed (0, iCard)) { if (gameStatus () == PLAYING) { if (getConnectionMgr ().getMode () != YGP::ConnectionMgr::NONE) { // Send played card to all clients (if any) std::ostringstream msg; msg << "Play=" << played[played.size () - 1]->id () << ";Target=0"; if (getConnectionMgr ().getMode () == YGP::ConnectionMgr::CLIENT) ignoreNextMsg = true; broadcastMessage (msg.str ()); } setNextPlayer (calcNextPlayer (currentPlayer ())); } else { Check3 (gameStatus () == EXCHANGE); if (played.size () == 3) { // Exchange the cards in pre-play TRACE7 ("Hearts::cardSelected (unsigned int) - Finished exchange"); if (getConnectionMgr ().getMode () == YGP::ConnectionMgr::NONE) { exchangeCards (); startPlaying (); } else { std::ostringstream msg; msg << "Exchange=" << played[0]->id () << ' ' << played[1]->id () << ' ' << played[2]->id () << ";Player=" << posServer; broadcastMessage (msg.str ()); YGP::ConnectionMgr& cmgr (getConnectionMgr ()); if ((cmgr.getMode () == YGP::ConnectionMgr::SERVER) && cardsExchanged ((cmgr.getClients ().size () + 1) * 3)) { exchangeCards (); startPlaying (); } else { status.pop (); status.push (_("Waiting for other player to exchange their cards ...")); } } disableHuman (); return; } } makeNextMoves (); }}//-----------------------------------------------------------------------------/// Starts the playing phase of the game//-----------------------------------------------------------------------------void Hearts::startPlaying () { TRACE7 ("Hearts::startPlaying ()"); // Clear variables for a new game memset (aPlayed, 0, sizeof (aPlayed));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -