diff options
-rw-r--r-- | server/game.cpp | 155 | ||||
-rw-r--r-- | server/game.h | 53 |
2 files changed, 208 insertions, 0 deletions
diff --git a/server/game.cpp b/server/game.cpp index 07373ac..f2b1c06 100644 --- a/server/game.cpp +++ b/server/game.cpp @@ -142,4 +142,159 @@ void Game::start() { players[1]->game_start(boost::bind(&Game::handle_ready, shared_from_this()), players); players[2]->game_start(boost::bind(&Game::handle_ready, shared_from_this()), players); players[3]->game_start(boost::bind(&Game::handle_ready, shared_from_this()), players); +void Game::Player::round_start() { + // Reset contents. + hand.clear(); + open.clear(); + pond.clear(); + riichi = false; + + // Notify client of round start. + client->round_start(); +} + +State::Player Game::Player::get_state() { + State::Player state = {hand, open, pond}; + return state; +} + +State::Player Game::Player::get_state_filtered() { + State::Player state = {hand, open, pond}; + return state; +} + +Actions Game::Player::get_actions_draw() { + Actions possible_actions; + + // Check if player can force a draw. + // Check if player can tsumo. + // Check if player can declare a concealed kan or extend an open pon. List all possibilities. + + if(!riichi) { + // Check if player can riichi. + + // List all tiles that can be discarded. + for(std::size_t i = 0; i < hand.size(); i++) { + possible_actions.push_back(Action(Action::Discard, i)); + } + + } else { + // Only tile that can be discarded is the last drawn one. + possible_actions.push_back(Action(Action::Discard, hand.size() - 1)); + } + + return possible_actions; +} + +Actions Game::Player::get_actions_discard(Tile tile) { + Actions possible_actions; + + if(!riichi) { + // Check if tile can be called for a chi. Enumerate all combinations. + Targets targets = can_chi(tile); + if(!targets.empty()) { + for(Targets::iterator it = targets.begin(); it != targets.end(); it++) { + possible_actions.push_back(Action(Action::Chi, *it)); + } + } + + // Check if tile can be called for a pon. + int target = can_pon(tile); + if(target > 0) { + possible_actions.push_back(Action(Action::Pon, target)); + + // Check if tile can be called for a kan. + if(can_kan(tile, target)) { + possible_actions.push_back(Action(Action::Kan, target)); + } + } + } + + // Check if tile can be ron-ed. + + // If any action is possible, add option to pass. + if(possible_actions) { + possible_actions.push_back(Action::Pass); + } + + return possible_actions; +} + +Game::Player::Targets Game::Player::can_chi(Tile tile) { + Targets targets; + + Tile::Set set = tile.get_set(); + int num = tile.get_num(); + + // Check if tile actually can be chi-ed. + if(set == Tile::Honor) { + return targets; + } + + bool have_above = false; + + // Check if we have tile below. + Tiles::iterator it = std::find(hand.begin(), hand.end(), Tile(set, num - 1)); + if(num > 1 && it != hand.end()) { + + // Check if we also have tile below tile below. + Tiles::iterator it2 = std::find(hand.begin(), hand.end(), Tile(set, num - 2)); + if(num > 2 && it2 != hand.end()) { + targets.push_back(it2 - hand.begin()); // (T-2 T-1 T) + } + + // Check if we have tile above. + it2 = std::find(hand.begin(), hand.end(), Tile(set, num + 1)); + if(num < 9 && it2 != hand.end()) { + targets.push_back(it - hand.begin()); // (T-1 T T+1) + have_above = true; + it = it2; + } + } + + // Check if we have tile above. + if(have_above || (it = std::find(hand.begin(), hand.end(), Tile(set, num + 1))) != hand.end()) { + // Check if we have tile above tile above. + Tiles::iterator it2 = std::find(hand.begin(), hand.end(), Tile(set, num + 2)); + if(num < 8 && it2 != hand.end()) { + targets.push_back(it - hand.begin()); // (T T+1 T+2) + } + } + + return targets; +} + +int Game::Player::can_pon(Tile tile) { + Tiles::iterator it = std::find(hand.begin(), hand.end(), tile); + if(it + 1 < hand.end() && it[1] == tile) { + return it - hand.begin(); + } + + return -1; +} + +//Game::Player::Targets Game::Player::can_kan() { +// return Targets(); // TODO +//} + +bool Game::Player::can_kan(Tile tile, int target) { + if(std::size_t(target + 2) < hand.size() && hand[target + 2] == tile) { + return true; + } + return false; +} + +void Game::Player::draw(Tile tile) { + hand.push_back(tile); +} + +void Game::Player::discard(int target) { + Tile tile = hand[target]; + hand.erase(hand.begin() + target); + hand.sort(); + pond.push_back(tile); +} + +Tile Game::Player::last_discard() { + return pond.back(); } diff --git a/server/game.h b/server/game.h index 2574dc3..9c2513e 100644 --- a/server/game.h +++ b/server/game.h @@ -9,6 +9,7 @@ #include "wall.h" #include "client.h" #include "../common/action.h" +#include "../common/state.h" #include "gamevariant.h" #include "standard.h" @@ -23,6 +24,58 @@ class Game : public boost::enable_shared_from_this<Game> { private: std::vector<Client::p> players; + class Player { + public: + Client::p client; + + Tiles hand; + Tiles open; + Tiles pond; + bool riichi; + + //! Prepare for a new round. + void round_start(); + + //! Get a state snapshot. + State::Player get_state(); + + //! Get a state snapshot, with concealed tiles filtered. + State::Player get_state_filtered(); + + //! Get possible actions after a draw. + Actions get_actions_draw(); + + //! Get possible actions on discarded tile. + Actions get_actions_discard(Tile tile); + + typedef std::vector<int> Targets; + + //! Check if tile can be called for a chi. + Targets can_chi(Tile tile); + + //! Check if tile can be called for a pon. + int can_pon(Tile tile); + + //! Check if it's possible to make a concealed kan or extend an open kan. + Targets can_kan(); + + // Check if tile can be called to kan target. + bool can_kan(Tile tile, int target); + + //! Draw tile. + void draw(Tile tile); + + //! Discard tile. + void discard(int target); + + //! Look at last discard in pond. + Tile last_discard(); + + //! Claim last discard from pond. + Tile claim(); + + + }; int waiting_players; |