refactor(game): introduce draw and play methods in PlayerState and subclasses

- Replaced `setRemainingCardCount` with `draw` and `play` methods.
- Added virtual overrides for player-specific behaviors in `ClientPlayerState` and `ServerPlayerState`.
- Refactored `ServerGameState::init` to centralize deck and discard pile setup.
- Updated `updateStateByDraw` to leverage `PlayerState::draw` for consistency.
This commit is contained in:
Kieran Kihn
2025-11-17 21:16:50 +08:00
parent 03e1d363e2
commit ebac6291b0
2 changed files with 129 additions and 43 deletions

View File

@@ -15,7 +15,6 @@ namespace UNO::GAME {
{ {
} }
std::string PlayerState::getName() const std::string PlayerState::getName() const
{ {
return this->name_; return this->name_;
@@ -30,59 +29,100 @@ namespace UNO::GAME {
{ {
return this->remainingCardCount_; return this->remainingCardCount_;
} }
void PlayerState::setRemainingCardCount(size_t x)
{
this->remainingCardCount_ = x;
}
void PlayerState::setIsUno(bool x) void PlayerState::setIsUno(bool x)
{ {
this->isUno_ = x; this->isUno_ = x;
} }
void PlayerState::draw(size_t n, const std::vector<Card> &cards)
{
this->remainingCardCount_ += n;
}
Card PlayerState::play(const Card &card)
{
this->remainingCardCount_--;
return card;
}
ClientPlayerState::ClientPlayerState(std::string name, size_t remainingCardCount, bool isUno) : ClientPlayerState::ClientPlayerState(std::string name, size_t remainingCardCount, bool isUno) :
PlayerState(std::move(name), remainingCardCount, isUno) PlayerState(std::move(name), remainingCardCount, isUno)
{ {
} }
ServerPlayerState::ServerPlayerState(std::string name, size_t remainingCardCount, bool isUno, HandCard *handCard) : void ClientPlayerState::draw(size_t n, const std::vector<Card> &cards)
PlayerState(std::move(name), remainingCardCount, isUno), handCard(handCard)
{ {
PlayerState::draw(n, cards);
}
Card ClientPlayerState::play(const Card &card)
{
return PlayerState::play(card);
}
ServerPlayerState::ServerPlayerState(std::string name, size_t remainingCardCount, bool isUno) :
PlayerState(std::move(name), remainingCardCount, isUno)
{
}
const std::multiset<Card> &ServerPlayerState::getCards() const
{
return this->handCard_.getCards();
}
void ServerPlayerState::draw(size_t x, const std::vector<Card> &cards)
{
PlayerState::draw(x, cards);
this->handCard_.draw(cards);
}
Card ServerPlayerState::play(const Card &card)
{
PlayerState::play(card);
for (auto it = this->handCard_.getCards().begin();; it++) {
if (it == this->handCard_.getCards().end()) {
throw std::invalid_argument("Card not found in hand");
}
if (card.getType() == it->getType()
&& (card.getType() == CardType::WILD || card.getType() == CardType::WILDDRAWFOUR || card.getColor() == it->getColor())) {
this->handCard_.play(it);
break;
}
}
return PlayerState::play(card);
}
bool ServerPlayerState::isEmpty() const
{
return this->handCard_.isEmpty();
} }
ClientGameState::ClientGameState(GameStatus gameStatus, Player player) : GameState(gameStatus), player(std::move(player)) {} ClientGameState::ClientGameState(GameStatus gameStatus, Player player) : GameState(gameStatus), player(std::move(player)) {}
ServerGameState::ServerGameState() : GameState(GameStatus::WAITING_PLAYERS_TO_JOIN) {} ServerGameState::ServerGameState() : GameState(GameStatus::WAITING_PLAYERS_TO_JOIN) {}
void ServerGameState::updateStateByCard(const Card &card) void ServerGameState::init()
{ {
if (this->discardPile_.isEmpty() == false && card.canBePlayedOn(this->discardPile_.getFront()) == false) { deck_.clear(), discardPile_.clear();
throw std::invalid_argument("Card cannot be played"); while (discardPile_.isEmpty() || discardPile_.getFront().getType() > CardType::NUM9) {
discardPile_.add(deck_.draw());
} }
const auto &handCardSet = this->getCurrentPlayer()->handCard->getCards(); for (size_t i = 0; i < 7; i++) {
for (auto it = handCardSet.begin(); ; it++) { for (auto &player : this->players_) {
if (it == handCardSet.end()) { player.draw(1, this->deck_.draw(1));
throw std::invalid_argument("Card not found in hand");
}
if (card.getType() == it->getType() && (card.getType() == CardType::WILD || card.getType() == CardType::WILDDRAWFOUR || card.getColor() == it->getColor())) {
this->getCurrentPlayer()->handCard->play(it);
break;
} }
} }
GameState::updateStateByCard(card);
} }
void ServerGameState::updateStateByDraw() void ServerGameState::updateStateByDraw()
{ {
if (this->drawCount_ == 0) { if (this->drawCount_ == 0) {
this->drawCount_ = 1; this->drawCount_ = 1;
} }
this->currentPlayer_->handCard->draw(this->deck_.draw(this->drawCount_)); this->currentPlayer_->draw(this->drawCount_, deck_.draw(this->drawCount_));
this->drawCount_ = 0;
GameState::updateStateByDraw(); this->nextPlayer();
} }
} // namespace UNO::GAME } // namespace UNO::GAME

View File

@@ -23,9 +23,11 @@ namespace UNO::GAME {
size_t remainingCardCount_; size_t remainingCardCount_;
bool isUno_; bool isUno_;
public:
PlayerState(std::string name, size_t remainingCardCount, bool isUno); PlayerState(std::string name, size_t remainingCardCount, bool isUno);
public:
virtual ~PlayerState() = default;
/** /**
* @return 玩家名字 * @return 玩家名字
*/ */
@@ -41,35 +43,80 @@ namespace UNO::GAME {
*/ */
[[nodiscard]] size_t getRemainingCardCount() const; [[nodiscard]] size_t getRemainingCardCount() const;
/**
* 将剩余手牌设置为 x 张
* @param x 要设置的张数
*/
void setRemainingCardCount(size_t x);
/** /**
* 设置 Uno 状态 * 设置 Uno 状态
* @param x Uno 状态 * @param x Uno 状态
*/ */
void setIsUno(bool x); void setIsUno(bool x);
/**
* 摸牌
* @param n 摸的张数
* @param cards 摸到的牌
*/
void virtual draw(size_t n, const std::vector<Card> &cards);
/**
* 出一张牌
*/
Card virtual play(const Card &card);
}; };
/** /**
* (供客户端使用)玩家状态 * (供客户端使用)玩家状态
*/ */
class ClientPlayerState : public PlayerState { class ClientPlayerState final : public PlayerState {
public: public:
ClientPlayerState(std::string name, size_t remainingCardCount, bool isUno); ClientPlayerState(std::string name, size_t remainingCardCount, bool isUno);
/**
* 摸牌
* @param n 摸的张数
* @param cards 摸的牌
*/
void draw(size_t n, const std::vector<Card> &cards) override;
/**
* 出一张牌
*/
Card play(const Card &card) override;
}; };
/** /**
* (供服务端使用)玩家状态 * (供服务端使用)玩家状态
*/ */
class ServerPlayerState : public PlayerState { class ServerPlayerState final : public PlayerState {
public: private:
explicit ServerPlayerState(std::string name, size_t remainingCardCount, bool isUno, HandCard *handCard); HandCard handCard_;
HandCard *handCard; public:
explicit ServerPlayerState(std::string name, size_t remainingCardCount, bool isUno);
/**
* 获得当前手牌
* @return 当前手牌的集合
*/
[[nodiscard]] const std::multiset<Card> &getCards() const;
/**
* 摸牌
* @param x 摸的张数
* @param cards 摸的牌
*/
void draw(size_t x, const std::vector<Card> &cards) override;
/**
* 打出一张牌
* @param card 要打出的手牌
* @return 打出的手牌
*/
Card play(const Card &card) override;
/**
* @return 手牌是否为空
*/
[[nodiscard]] bool isEmpty() const;
}; };
/** /**
@@ -241,7 +288,7 @@ namespace UNO::GAME {
if (this->discardPile_.isEmpty() == false && card.canBePlayedOn(this->discardPile_.getFront()) == false) { if (this->discardPile_.isEmpty() == false && card.canBePlayedOn(this->discardPile_.getFront()) == false) {
throw std::invalid_argument("Card cannot be played"); throw std::invalid_argument("Card cannot be played");
} }
this->currentPlayer_->setRemainingCardCount(this->currentPlayer_->getRemainingCardCount() - 1); this->currentPlayer_->play(card);
if (card.getType() == CardType::DRAW2) { if (card.getType() == CardType::DRAW2) {
this->drawCount_ += 2; this->drawCount_ += 2;
} }
@@ -264,7 +311,7 @@ namespace UNO::GAME {
if (this->drawCount_ == 0) { if (this->drawCount_ == 0) {
this->drawCount_ = 1; this->drawCount_ = 1;
} }
this->currentPlayer_->setRemainingCardCount((this->currentPlayer_->getRemainingCardCount() + this->drawCount_)); this->currentPlayer_->draw(this->drawCount_, {});
this->drawCount_ = 0; this->drawCount_ = 0;
this->nextPlayer(); this->nextPlayer();
} }
@@ -284,10 +331,9 @@ namespace UNO::GAME {
ServerGameState(); ServerGameState();
/** /**
* 由于用户出牌而改变状态 * 开始游戏
* @param card 用户出的牌
*/ */
void updateStateByCard(const Card &card) override; void init();
/** /**
* 由于用户摸牌而改变状态 * 由于用户摸牌而改变状态