refractor(game): enhance state management with clear and endGame methods

- Added `clear` methods to `PlayerState`, `ServerPlayerState`, and `HandCard`.
- Introduced `endGame` methods to `GameState`, `ClientGameState`, and `ServerGameState`.
- Improved `init` and `nextPlayer` logic in `ClientGameState`.
- Added `getClientGameStage` and `getServerGameStage` methods to retrieve game stages.
This commit is contained in:
Kieran Kihn
2025-12-07 19:03:13 +08:00
parent ebb49a02ef
commit 0802d989f8
4 changed files with 134 additions and 25 deletions

View File

@@ -46,6 +46,11 @@ namespace UNO::GAME {
return card; return card;
} }
void PlayerState::clear()
{
this->remainingCardCount_ = 0;
}
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)
{ {
@@ -84,16 +89,48 @@ namespace UNO::GAME {
return this->handCard_.isEmpty(); return this->handCard_.isEmpty();
} }
ClientGameState::ClientGameState(std::string name) : player_(std::move(name)) {} void ServerPlayerState::clear()
{
PlayerState::clear();
this->handCard_.clear();
}
ClientGameState::ClientGameState(std::string name) : player_(std::move(name)), clientGameStage_(ClientGameStage::PENDING_CONNECTION) {}
void ClientGameState::nextPlayer()
{
GameState::nextPlayer();
if (this->self_ == this->currentPlayer_) {
this->clientGameStage_ = ClientGameStage::ACTIVE;
}
else {
this->clientGameStage_ = ClientGameStage::IDLE;
}
}
const std::multiset<Card> &ClientGameState::getCards() const const std::multiset<Card> &ClientGameState::getCards() const
{ {
return this->player_.getCards(); return this->player_.getCards();
} }
void ClientGameState::init(DiscardPile discardPile) void ClientGameState::init(const std::vector<ClientPlayerState> &players,
const DiscardPile &discardPile,
const std::multiset<Card> &handCard,
const size_t &currentPlayerIndex,
const size_t &selfIndex)
{ {
this->discardPile_ = std::move(discardPile); this->players_ = players;
this->discardPile_ = discardPile;
player_.draw(std::vector<Card>(handCard.begin(), handCard.end()));
this->currentPlayer_ = this->players_.begin() + static_cast<int>(currentPlayerIndex);
this->self_ = this->players_.begin() + static_cast<int>(selfIndex);
if (this->self_ == this->currentPlayer_) {
this->clientGameStage_ = ClientGameStage::ACTIVE;
}
else {
this->clientGameStage_ = ClientGameStage::IDLE;
}
} }
@@ -117,26 +154,32 @@ namespace UNO::GAME {
return this->player_.isEmpty(); return this->player_.isEmpty();
} }
ServerGameState::ServerGameState() = default; ClientGameStage ClientGameState::getClientGameStage() const
{
return this->clientGameStage_;
}
void ClientGameState::endGame()
{
this->clientGameStage_ = ClientGameStage::PRE_GAME;
this->player_.clear();
}
ServerGameState::ServerGameState() : serverGameStage_(ServerGameStage::PRE_GAME) {}
void ServerGameState::init() void ServerGameState::init()
{ {
deck_.clear(), discardPile_.clear();
while (discardPile_.isEmpty() || discardPile_.getFront().getType() > CardType::NUM9) { while (discardPile_.isEmpty() || discardPile_.getFront().getType() > CardType::NUM9) {
discardPile_.add(deck_.draw()); discardPile_.add(deck_.draw());
} }
for (auto &player : this->players_) {
while (player.isEmpty() == false) {
player.play(*player.getCards().begin());
}
}
for (size_t i = 0; i < 7; i++) { for (size_t i = 0; i < 7; i++) {
for (auto &player : this->players_) { for (auto &player : this->players_) {
player.draw(1, this->deck_.draw(1)); player.draw(1, this->deck_.draw(1));
} }
} }
this->serverGameStage_ = ServerGameStage::IN_GAME;
} }
std::vector<Card> ServerGameState::updateStateByDraw() std::vector<Card> ServerGameState::updateStateByDraw()
@@ -151,18 +194,16 @@ namespace UNO::GAME {
return cards; return cards;
} }
void ServerGameState::reset() ServerGameStage ServerGameState::getServerGameStage() const
{ {
discardPile_.clear(); return this->serverGameStage_;
isReversed_ = false; }
drawCount_ = 0;
for (auto &player : players_) { void ServerGameState::endGame()
while (!player.isEmpty()) { {
player.play(*player.getCards().begin()); this->serverGameStage_ = ServerGameStage::PRE_GAME;
} deck_.clear();
}
currentPlayer_ = players_.begin(); GameState::endGame();
} }
} // namespace UNO::GAME } // namespace UNO::GAME

View File

@@ -60,6 +60,11 @@ namespace UNO::GAME {
* 出一张牌 * 出一张牌
*/ */
Card virtual play(const Card &card); Card virtual play(const Card &card);
/**
* 清空手牌
*/
void virtual clear();
}; };
/** /**
@@ -112,6 +117,8 @@ namespace UNO::GAME {
* @return 手牌是否为空 * @return 手牌是否为空
*/ */
[[nodiscard]] bool isEmpty() const; [[nodiscard]] bool isEmpty() const;
void clear() override;
}; };
/** /**
@@ -142,7 +149,7 @@ namespace UNO::GAME {
/** /**
* 下一个玩家 * 下一个玩家
*/ */
void nextPlayer(); void virtual nextPlayer();
public: public:
virtual ~GameState() = default; virtual ~GameState() = default;
@@ -189,6 +196,8 @@ namespace UNO::GAME {
* 由于用户摸牌而改变状态 * 由于用户摸牌而改变状态
*/ */
std::vector<Card> virtual updateStateByDraw(); std::vector<Card> virtual updateStateByDraw();
void virtual endGame();
}; };
template<PlayerStateTypeConcept PlayerStateType> template<PlayerStateTypeConcept PlayerStateType>
@@ -300,9 +309,26 @@ namespace UNO::GAME {
return {}; return {};
} }
template<PlayerStateTypeConcept PlayerStateType>
void GameState<PlayerStateType>::endGame()
{
discardPile_.clear();
for (auto &player : this->players_) {
player.clear();
}
}
enum class ClientGameStage { PENDING_CONNECTION, PRE_GAME, ACTIVE, IDLE };
class ClientGameState final : public GameState<ClientPlayerState> { class ClientGameState final : public GameState<ClientPlayerState> {
private: private:
Player player_; Player player_;
std::vector<ClientPlayerState>::const_iterator self_;
ClientGameStage clientGameStage_;
private:
void nextPlayer() override;
public: public:
explicit ClientGameState(std::string name); explicit ClientGameState(std::string name);
@@ -316,7 +342,11 @@ namespace UNO::GAME {
/** /**
* 初始化客户端状态 * 初始化客户端状态
*/ */
void init(DiscardPile discardPile); void init(const std::vector<ClientPlayerState> &players,
const DiscardPile &discardPile,
const std::multiset<Card> &handCard,
const size_t &currentPlayerIndex,
const size_t &selfIndex);
/** /**
* 摸一张牌 * 摸一张牌
@@ -340,11 +370,25 @@ namespace UNO::GAME {
* @return 手牌是否为空 * @return 手牌是否为空
*/ */
[[nodiscard]] bool isEmpty() const; [[nodiscard]] bool isEmpty() const;
/**
* 获取游戏阶段
* @return 游戏阶段
*/
[[nodiscard]] ClientGameStage getClientGameStage() const;
/**
* 结束当前局
*/
void endGame() override;
}; };
enum class ServerGameStage { PRE_GAME, IN_GAME };
class ServerGameState final : public GameState<ServerPlayerState> { class ServerGameState final : public GameState<ServerPlayerState> {
private: private:
Deck deck_; Deck deck_;
ServerGameStage serverGameStage_;
public: public:
ServerGameState(); ServerGameState();
@@ -360,9 +404,15 @@ namespace UNO::GAME {
std::vector<Card> updateStateByDraw() override; std::vector<Card> updateStateByDraw() override;
/** /**
* 重置游戏状态(用于重新开始) * 获取游戏阶段
* @return 游戏阶段
*/ */
void reset(); [[nodiscard]] ServerGameStage getServerGameStage() const;
/**
* 结束当前局
*/
void endGame() override;
}; };
} // namespace UNO::GAME } // namespace UNO::GAME

View File

@@ -54,6 +54,11 @@ namespace UNO::GAME {
return cards_.empty(); return cards_.empty();
} }
void HandCard::clear()
{
this->cards_.clear();
}
Player::Player(std::string name) : name_(std::move(name)) {} Player::Player(std::string name) : name_(std::move(name)) {}
const std::string &Player::getName() const const std::string &Player::getName() const
@@ -86,5 +91,8 @@ namespace UNO::GAME {
return this->handCard_.play(card); return this->handCard_.play(card);
} }
void Player::clear()
{
this->handCard_.clear();
} }
} // namespace UNO::GAME } // namespace UNO::GAME

View File

@@ -59,6 +59,11 @@ namespace UNO::GAME {
* @return 手牌是否为空 * @return 手牌是否为空
*/ */
[[nodiscard]] bool isEmpty() const; [[nodiscard]] bool isEmpty() const;
/**
* 清空手牌
*/
void clear();
}; };
/** /**
@@ -105,6 +110,11 @@ namespace UNO::GAME {
* @return 手牌是否为空 * @return 手牌是否为空
*/ */
[[nodiscard]] bool isEmpty() const; [[nodiscard]] bool isEmpty() const;
/**
* 清空手牌
*/
void clear();
}; };
} // namespace UNO::GAME } // namespace UNO::GAME