diff options
-rw-r--r-- | server/game.cpp | 330 | ||||
-rw-r--r-- | server/player.cpp | 331 |
2 files changed, 331 insertions, 330 deletions
diff --git a/server/game.cpp b/server/game.cpp index 65d5cf2..9a56b47 100644 --- a/server/game.cpp +++ b/server/game.cpp @@ -297,333 +297,3 @@ void Game::round_end() { #endif } - -void Game::Player::round_start() { - // Reset contents. - hand.clear(); - open.clear(); - pond.clear(); - riichi = false; - - // Notify client of round start. - client->round_start(); -} - -Game::Player::State Game::Player::get_state() { - State state = {hand, open, pond}; - return state; -} - -Game::Player::State Game::Player::get_state_filtered() { - State 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. - if(can_tsumo()) { - possible_actions.push_back(Action(Action::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, Action::Hand, i)); - } - - } else { - // Only tile that can be discarded is the last drawn one. - possible_actions.push_back(Action(Action::Discard, Action::Hand, hand.size() - 1)); - } - - return possible_actions; -} - -Actions Game::Player::get_actions_discard(Tile tile, PlayerNum discarder) { - Actions possible_actions; - - if(!riichi) { - // Check if tile can be called for a chi. Enumerate all combinations. - if(discarder == 3) { - 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, Action::Hand, *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, Action::Hand, target + 1)); - - // Check if tile can be called for a kan. - if(can_kan(tile, target)) { - possible_actions.push_back(Action(Action::Kan, Action::Hand, target + 2)); - } - } - } - - // Check if tile can be ron-ed. - if(can_ron(tile)) { - possible_actions.push_back(Action(Action::Ron)); - } - - // 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; -} - -//! Recursive function that eats away sets from a hand to determine if it's valid or not. -bool complete_hand(Tiles tiles, bool pair_eaten = false) { - if(!tiles) { - return true; // All tiles eaten. - } - - if(tiles[0] == tiles[1]) { - if(!pair_eaten) { - // We can eat a pair of tiles. - Tiles t = tiles; - t.erase(t.begin(), t.begin() + 2); - if(complete_hand(t, true)) { - return true; - } - } - - if(tiles[1] == tiles[2]) { - // We can eat a pon of tiles. - Tiles t = tiles; - t.erase(t.begin(), t.begin() + 3); - if(complete_hand(t, pair_eaten)) { - return true; - } - } - } - - Tile::Set set = tiles[0].get_set(); - int num = tiles[0].get_num(); - - if(set == Tile::Honor || num > 7) { - // Can't be chi-ed. - return false; - } - - Tiles::iterator it1 = std::find(tiles.begin(), tiles.end(), Tile(set, num + 1)); - if(it1 != tiles.end()) { - Tiles::iterator it2 = std::find(tiles.begin(), tiles.end(), Tile(set, num + 2)); - if(it2 != tiles.end()) { - // We can eat a chi of tiles. - tiles.erase(it2); - tiles.erase(it1); - tiles.erase(tiles.begin()); - return complete_hand(tiles, pair_eaten); - } - } - - return false; -} - -bool Game::Player::can_tsumo() { - return complete_hand(hand); -} - -bool Game::Player::can_ron(Tile tile) { - Tiles tiles = hand; - tiles.push_back(tile); - tiles.sort(); - return complete_hand(tiles); -} - -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(); -} - -Tile Game::Player::claim() { - Tile& t = pond.back(); - t.invisible = true; - return t; -} - -void Game::Player::make_chi(Tile tile, int target) { - Tiles chi; - - tile.rotated = true; - chi.push_back(tile); - - Tile::Set set = tile.get_set(); - int num = tile.get_num(); - - Tiles::iterator it = hand.begin(); - - switch(hand[target].get_num() - num) { - case -2: - it = std::find(it, hand.end(), Tile(set, num - 2)); - chi.push_back(*it); - it = hand.erase(it); - - case -1: - it = std::find(it, hand.end(), Tile(set, num - 1)); - chi.push_back(*it); - it = hand.erase(it); - - case 1: - if(chi.size() == 3) { - break; - } - - it = std::find(it, hand.end(), Tile(set, num + 1)); - chi.push_back(*it); - it = hand.erase(it); - - if(chi.size() == 3) { - break; - } - - it = std::find(it, hand.end(), Tile(set, num + 2)); - chi.push_back(*it); - hand.erase(it); - } - - open.push_back(chi); -} - -void Game::Player::make_pon(Tile tile, int target, PlayerNum discarder) { - Tiles pon; - - tile.rotated = true; - - if(discarder == 3) { - pon.push_back(tile); - } - - pon.push_back(hand[target]); - hand.del(target); - - if(discarder == 2) { - pon.push_back(tile); - } - - pon.push_back(hand[target]); - hand.del(target); - - if(discarder == 1) { - pon.push_back(tile); - } - - open.push_back(pon); -} - -void Game::Player::make_kan(Tile tile, int target, PlayerNum discarder) { - Tiles kan; - - tile.rotated = true; - - if(discarder == 3) { - kan.push_back(tile); - } - - kan.push_back(hand[target]); - hand.del(target); - - if(discarder == 2) { - kan.push_back(tile); - } - - kan.push_back(hand[target]); - hand.del(target); - - kan.push_back(hand[target]); - hand.del(target); - - if(discarder == 1) { - kan.push_back(tile); - } - - open.push_back(kan); -}
\ No newline at end of file diff --git a/server/player.cpp b/server/player.cpp new file mode 100644 index 0000000..61f5831 --- /dev/null +++ b/server/player.cpp @@ -0,0 +1,331 @@ +#include "game.h" + +void Game::Player::round_start() { + // Reset contents. + hand.clear(); + open.clear(); + pond.clear(); + riichi = false; + + // Notify client of round start. + client->round_start(); +} + +Game::Player::State Game::Player::get_state() { + State state = {hand, open, pond}; + return state; +} + +Game::Player::State Game::Player::get_state_filtered() { + State 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. + if(can_tsumo()) { + possible_actions.push_back(Action(Action::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, Action::Hand, i)); + } + + } else { + // Only tile that can be discarded is the last drawn one. + possible_actions.push_back(Action(Action::Discard, Action::Hand, hand.size() - 1)); + } + + return possible_actions; +} + +Actions Game::Player::get_actions_discard(Tile tile, PlayerNum discarder) { + Actions possible_actions; + + if(!riichi) { + // Check if tile can be called for a chi. Enumerate all combinations. + if(discarder == 3) { + 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, Action::Hand, *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, Action::Hand, target + 1)); + + // Check if tile can be called for a kan. + if(can_kan(tile, target)) { + possible_actions.push_back(Action(Action::Kan, Action::Hand, target + 2)); + } + } + } + + // Check if tile can be ron-ed. + if(can_ron(tile)) { + possible_actions.push_back(Action(Action::Ron)); + } + + // 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; +} + +//! Recursive function that eats away sets from a hand to determine if it's valid or not. +bool complete_hand(Tiles tiles, bool pair_eaten = false) { + if(!tiles) { + return true; // All tiles eaten. + } + + if(tiles[0] == tiles[1]) { + if(!pair_eaten) { + // We can eat a pair of tiles. + Tiles t = tiles; + t.erase(t.begin(), t.begin() + 2); + if(complete_hand(t, true)) { + return true; + } + } + + if(tiles[1] == tiles[2]) { + // We can eat a pon of tiles. + Tiles t = tiles; + t.erase(t.begin(), t.begin() + 3); + if(complete_hand(t, pair_eaten)) { + return true; + } + } + } + + Tile::Set set = tiles[0].get_set(); + int num = tiles[0].get_num(); + + if(set == Tile::Honor || num > 7) { + // Can't be chi-ed. + return false; + } + + Tiles::iterator it1 = std::find(tiles.begin(), tiles.end(), Tile(set, num + 1)); + if(it1 != tiles.end()) { + Tiles::iterator it2 = std::find(tiles.begin(), tiles.end(), Tile(set, num + 2)); + if(it2 != tiles.end()) { + // We can eat a chi of tiles. + tiles.erase(it2); + tiles.erase(it1); + tiles.erase(tiles.begin()); + return complete_hand(tiles, pair_eaten); + } + } + + return false; +} + +bool Game::Player::can_tsumo() { + return complete_hand(hand); +} + +bool Game::Player::can_ron(Tile tile) { + Tiles tiles = hand; + tiles.push_back(tile); + tiles.sort(); + return complete_hand(tiles); +} + +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(); +} + +Tile Game::Player::claim() { + Tile& t = pond.back(); + t.invisible = true; + return t; +} + +void Game::Player::make_chi(Tile tile, int target) { + Tiles chi; + + tile.rotated = true; + chi.push_back(tile); + + Tile::Set set = tile.get_set(); + int num = tile.get_num(); + + Tiles::iterator it = hand.begin(); + + switch(hand[target].get_num() - num) { + case -2: + it = std::find(it, hand.end(), Tile(set, num - 2)); + chi.push_back(*it); + it = hand.erase(it); + + case -1: + it = std::find(it, hand.end(), Tile(set, num - 1)); + chi.push_back(*it); + it = hand.erase(it); + + case 1: + if(chi.size() == 3) { + break; + } + + it = std::find(it, hand.end(), Tile(set, num + 1)); + chi.push_back(*it); + it = hand.erase(it); + + if(chi.size() == 3) { + break; + } + + it = std::find(it, hand.end(), Tile(set, num + 2)); + chi.push_back(*it); + hand.erase(it); + } + + open.push_back(chi); +} + +void Game::Player::make_pon(Tile tile, int target, PlayerNum discarder) { + Tiles pon; + + tile.rotated = true; + + if(discarder == 3) { + pon.push_back(tile); + } + + pon.push_back(hand[target]); + hand.del(target); + + if(discarder == 2) { + pon.push_back(tile); + } + + pon.push_back(hand[target]); + hand.del(target); + + if(discarder == 1) { + pon.push_back(tile); + } + + open.push_back(pon); +} + +void Game::Player::make_kan(Tile tile, int target, PlayerNum discarder) { + Tiles kan; + + tile.rotated = true; + + if(discarder == 3) { + kan.push_back(tile); + } + + kan.push_back(hand[target]); + hand.del(target); + + if(discarder == 2) { + kan.push_back(tile); + } + + kan.push_back(hand[target]); + hand.del(target); + + kan.push_back(hand[target]); + hand.del(target); + + if(discarder == 1) { + kan.push_back(tile); + } + + open.push_back(kan); +} |