diff options
author | Vegard Storheil Eriksen <zyp@jvnv.net> | 2010-12-25 12:54:59 +0100 |
---|---|---|
committer | Vegard Storheil Eriksen <zyp@jvnv.net> | 2010-12-25 12:54:59 +0100 |
commit | fae209a9e93400c3a2072befda9c820634cf9278 (patch) | |
tree | 2d69e2c75fff0e08468c168f773abbc939a2ff03 /server/player.cpp | |
parent | 94a1189d757f0269ac081ad2d750152e30564986 (diff) |
Diffstat (limited to 'server/player.cpp')
-rw-r--r-- | server/player.cpp | 595 |
1 files changed, 0 insertions, 595 deletions
diff --git a/server/player.cpp b/server/player.cpp deleted file mode 100644 index a267b1d..0000000 --- a/server/player.cpp +++ /dev/null @@ -1,595 +0,0 @@ -#include "game.h" - -#include "hand.h" - -#include <boost/assign/list_of.hpp> -using boost::assign::list_of; - -void Player::round_start(int w) { - // Reset contents. - hand.clear(); - open.clear(); - pond.clear(); - tenpai_indexes.clear(); - riichi = false; - score = 25000; - wind = w; - won = 0; - - // Notify client of round start. - client->round_start(); -} - -PlayerState Player::get_state() { - Tilegroups h; - h.push_back(hand); - - for(Sets::iterator it = open.begin(); it != open.end(); it++) { - h.push_back(it->tiles); - } - - PlayerState state = {h, pond, riichi, score, wind}; - return state; -} - -PlayerState Player::get_state_filtered() { - Tiles hand_filtered; - for(int i = 0; i < hand.size(); i++) { - hand_filtered.push_back(Tile::Back); - } - - Tilegroups h; - h.push_back(hand_filtered); - - for(Sets::iterator it = open.begin(); it != open.end(); it++) { - h.push_back(it->tiles); - } - - PlayerState state = {h, pond, riichi, score, wind}; - return state; -} - -Actions Player::get_actions_draw() { - Actions possible_actions; - - // Check if player can force a draw. - // TODO: Implementation. (Low priority) - - // Check if player can tsumo. - if(can_tsumo()) { - possible_actions.push_back(Action(Action::Tsumo)); - } - - // Check if player can declare a concealed kan. - Targets targets = can_kan(); - for(Targets::iterator it = targets.begin(); it != targets.end(); it++) { - possible_actions.push_back(Action(Action::Kan, Action::Index, *it + 2)); - } - - // Check if player can extend an open pon. - targets = can_kan_extend(); - for(Targets::iterator it = targets.begin(); it != targets.end(); it++) { - possible_actions.push_back(Action(Action::Kan, Action::Group, *it)); - } - - if(!riichi) { - // Check if player can riichi. - if(can_riichi()) { - possible_actions.push_back(Action(Action::Riichi)); - } - - // List all tiles that can be discarded. - for(std::size_t i = 0; i < hand.size(); i++) { - // Skip tiles already used to call kan. - if(possible_actions.contains(Action(Action::Kan, Action::Index, i))) { - continue; - } - - possible_actions.push_back(Action(Action::Discard, Action::Index, i)); - } - - } else { - if(tenpai_indexes) { - for(List<int>::iterator it = tenpai_indexes.begin(); it != tenpai_indexes.end(); it++) { - possible_actions.push_back(Action(Action::Discard, Action::Index, *it)); - } - tenpai_indexes.clear(); - } else { - // Only tile that can be discarded is the last drawn one. - possible_actions.push_back(Action(Action::Discard, Action::Index, hand.size() - 1)); - } - } - - return possible_actions; -} - -Actions 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::Index, *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::Index, target + 1)); - - // Check if tile can be called for a kan. - if(can_kan(tile, target)) { - possible_actions.push_back(Action(Action::Kan, Action::Index, 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; -} - -bool Player::can_riichi() { - if(open) { - return false; - } - - // Iterate over the hand, testing to remove each tile and see if it gives tenpai. - for(Tiles::iterator it = hand.begin(); it != hand.end(); it++) { - Tiles tiles = hand; - tiles.del(it - hand.begin()); - tiles.sort(); - - if(Hand::tenpai(tiles)) { - tenpai_indexes.push_back(it - hand.begin()); - } - } - - return bool(tenpai_indexes); -} - -Player::Targets 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 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; -} - -Player::Targets Player::can_kan() { - Targets targets; - - for(Tiles::iterator it = hand.begin(); it != hand.end(); it++) { - Tiles::iterator it_s = it; - int i = 1; - do { - it_s = std::find(it_s + 1, hand.end(), *it); - } while(it_s != hand.end() && i++); - if(i >= 4) { - targets.push_back(it - hand.begin()); - } - } - - return targets; -} - -Player::Targets Player::can_kan_extend() { - Targets targets; - - for(Sets::iterator it = open.begin(); it != open.end(); it++) { - if(it->type == Set::Pon && hand.contains(it->tiles.front())) { - targets.push_back(it - open.begin() + 1); - } - } - - return targets; -} - -bool Player::can_kan(Tile tile, int target) { - if(std::size_t(target + 2) < hand.size() && hand[target + 2] == tile) { - return true; - } - return false; -} - -bool Player::can_tsumo() { - Tiles tiles = hand; - tiles.sort(); - return Hand::agari(tiles); -} - -bool Player::can_ron(Tile tile) { - // Check furiten. - if(pond.contains(tile)) { - return false; - } - // TODO: Furiten due to unclaimed discard in last go-around. - - Tiles tiles = hand; - tiles.push_back(tile); - tiles.sort(); - return Hand::agari(tiles); -} - -void Player::draw(Tile tile) { - hand.push_back(tile); -} - -void Player::discard(int target) { - Tile tile = hand[target]; - hand.erase(hand.begin() + target); - hand.sort(); - pond.push_back(tile); -} - -Tile Player::last_discard() { - return pond.back(); -} - -Tile Player::claim() { - Tile& t = pond.back(); - t.invisible = true; - return t; -} - -void Player::declare_riichi() { - riichi = true; -} - -void 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(Set(Set::Chi, chi, true)); -} - -void 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(Set(Set::Pon, pon, true)); -} - -void 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(Set(Set::Kan, kan, true)); -} - -void Player::make_kan(int target) { - Tiles kan; - - Tiles::iterator it = hand.begin() + target; - Tile t = *it; - kan.push_back(Tile::Back); - it = hand.erase(it); - - it = std::find(it, hand.end(), t); - kan.push_back(*it); - it = hand.erase(it); - - it = std::find(it, hand.end(), t); - kan.push_back(*it); - it = hand.erase(it); - - it = std::find(it, hand.end(), t); - kan.push_back(Tile::Back); - hand.erase(it); - - open.push_back(Set(Set::Kan, kan, false)); -} - -void Player::make_kan_extend(int target) { - Set& set = open[target - 1]; - - Tiles::iterator it = std::find(hand.begin(), hand.end(), set.tiles.front()); - Tile t = *it; - hand.erase(it); - - t.rotated = true; - - for(it = set.tiles.begin(); it != set.tiles.end(); it++) { - if(it->rotated) { - set.tiles.insert(it + 1, t); - break; - } - } - - set.type = Set::Kan; -} - -void Player::declare_ron(Tile tile) { - hand.push_back(tile); - // TODO: Mark winning tile. - hand.sort(); - - List<Sets> hands = Hand::get_breakdowns(hand); - - Sets hand = hands.front(); - hand.insert(hand.end(), open.begin(), open.end()); - - List<std::pair<std::string, int> > han; - - Score score = calculate_score(hand, han, false); - - won = true; - won_han = han; - won_value = score; -} - -void Player::declare_tsumo() { - // TODO: Mark winning tile. - hand.sort(); - - List<Sets> hands = Hand::get_breakdowns(hand); - - Sets hand = hands.front(); - hand.insert(hand.end(), open.begin(), open.end()); - - List<std::pair<std::string, int> > han; - - Score score = calculate_score(hand, han, true); - - won = true; - won_han = han; - won_value = score; -} - -Score Player::calculate_score(const Sets& hand, List<std::pair<std::string, int> >& han, bool tsumo) { - Tiles yakuhai = list_of(Tile::Chun)(Tile::Hatsu)(Tile::Haku); // TODO: Add seat and prevalent wind. - Tiles dora; // TODO: Fill this. - Tiles uradora; // TODO: Fill this. - - Score score(0, 20, 0); // Always 20 fu for winning. - - // Check riichi. - if(riichi) { - score.yaku += 1; - han.push_back(std::make_pair("Riichi", 1)); - // TODO: Check ippatsu. - } - - // Check menzen tsumo. - if(tsumo && !open) { - score.yaku += 1; - han.push_back(std::make_pair("Menzen tsumo", 1)); - } - - bool possible_tanyao = true; - bool possible_toitoi = true; - int dora_n = 0; - int uradora_n = 0; - int akadora_n = 0; - - for(Sets::const_iterator set = hand.begin(); set != hand.end(); set++) { - switch(set->type) { - case Set::Pair: - // Check for pair-related fu. - score.fu += 2 * yakuhai.count(set->tiles.front()); - - break; - - case Set::Chi: - // Toitoi can't contain chi. - possible_toitoi = false; - break; - - case Set::Pon: - case Set::Kan: - // Calculate fu. - score.fu += 2 << (!set->open + !set->tiles.front().is_simple() + 2 * (set->type == Set::Kan)); - - // Check yakuhai. - if(int yakuhai_n = yakuhai.count(set->tiles.front())) { - score.yaku += yakuhai_n; - han.push_back(std::make_pair("Yakuhai", yakuhai_n)); // TODO: Specify which tile. - } - - break; - } - - for(Tiles::const_iterator tile = set->tiles.begin(); tile != set->tiles.end(); tile++) { - // Check tanyao. - if(!tile->is_simple()) { - possible_tanyao = false; - } - - // Check dora. - dora_n += dora.count(*tile); - - // Check uradora. - uradora_n += uradora.count(*tile); - - // Check akadora. - if(tile->red) { - akadora_n += 1; - } - } - } - - // Check tanyao. - if(possible_tanyao) { - score.yaku += 1; - han.push_back(std::make_pair("Tanyao", 1)); - } - - // Check toitoi. - if(possible_toitoi) { - score.yaku += 2; - han.push_back(std::make_pair("Toitoi", 2)); - } - - // Check pinfu. - if(score.fu == 20) { - if(open) { - score.fu += 2; - } else { - score.yaku += 1; - han.push_back(std::make_pair("Pinfu", 1)); - } - } else if(tsumo) { - score.fu += 2; - } - - // Check fu for ron. - if(!tsumo && !open) { - // 10 fu for ron. - score.fu += 10; - } - - // Check dora. - if(dora_n) { - score.dora += dora_n; - han.push_back(std::make_pair("Dora", dora_n)); - } - - // Check uradora. - if(uradora_n) { - score.dora += uradora_n; - han.push_back(std::make_pair("Uradora", uradora_n)); - } - - // Check akadora. - if(akadora_n) { - score.dora += akadora_n; - han.push_back(std::make_pair("Akadora", akadora_n)); - } - - return score; -} |