summaryrefslogtreecommitdiff
path: root/server/player.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'server/player.cpp')
-rw-r--r--server/player.cpp595
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;
-}