#include "hand.h" bool Hand::agari(const Tiles& tiles) { return basic_format(tiles); } bool Hand::tenpai(const Tiles& tiles) { return basic_format_tenpai(tiles); } List Hand::get_breakdowns(const Tiles& tiles) { List hands; basic_format(tiles, hands); return hands; } bool Hand::basic_format(const Tiles& tiles, bool pair_eaten) { if(!tiles) { return true; // All tiles eaten. } Tiles rest; if(!pair_eaten) { rest = tiles; if(eat_pair(rest) && basic_format(rest, true)) { return true; } } if(tiles.size() < 3) { return false; } rest = tiles; if(eat_pon(rest) && basic_format(rest, pair_eaten)) { return true; } rest = tiles; if(eat_chi(rest) && basic_format(rest, pair_eaten)) { return true; } return false; } void Hand::basic_format(const Tiles& tiles, List& hands, const Sets& hand, bool pair_eaten) { if(!tiles) { hands.push_back(hand); return; // All tiles eaten. } Tiles rest; Sets new_hand; if(!pair_eaten) { rest = tiles; new_hand = hand; if(eat_pair(rest, new_hand)) { basic_format(rest, hands, new_hand, true); } } if(tiles.size() < 3) { return; } rest = tiles; new_hand = hand; if(eat_pon(rest, new_hand)) { basic_format(rest, hands, new_hand, pair_eaten); } rest = tiles; new_hand = hand; if(eat_chi(rest, new_hand)) { basic_format(rest, hands, new_hand, pair_eaten); } } bool Hand::basic_format_tenpai(const Tiles& tiles, bool pair_eaten, bool wait_eaten) { if(!tiles) { return true; } Tiles rest; if(!pair_eaten && !wait_eaten) { rest = tiles; if(eat_tanki(rest) && basic_format_tenpai(rest, true, true)) { return true; } } if(tiles.size() < 2) { return false; } if(!pair_eaten) { rest = tiles; if(eat_pair(rest) && basic_format_tenpai(rest, true, wait_eaten)) { return true; } } if(!wait_eaten) { rest = tiles; if(eat_chi_wait(rest) && basic_format_tenpai(rest, pair_eaten, true)) { return true; } } if(tiles.size() < 3) { return false; } rest = tiles; if(eat_pon(rest) && basic_format_tenpai(rest, pair_eaten, wait_eaten)) { return true; } rest = tiles; if(eat_chi(rest) && basic_format_tenpai(rest, pair_eaten, wait_eaten)) { return true; } return false; } bool Hand::eat_tanki(Tiles& tiles) { tiles.erase(tiles.begin()); return true; } bool Hand::eat_chi_wait(Tiles& tiles) { Tile::Set set = tiles.front().get_set(); int num = tiles.front().get_num(); if(set == Tile::Honor || num > 8) { return false; } // Look for T+1. Tiles::iterator it = std::find(tiles.begin(), tiles.end(), Tile(set, num + 1)); if(it != tiles.end()) { tiles.erase(it); tiles.erase(tiles.begin()); return true; } if(num > 7) { return Tiles(); } // Look for T+2. it = std::find(tiles.begin(), tiles.end(), Tile(set, num + 2)); if(it != tiles.end()) { tiles.erase(it); tiles.erase(tiles.begin()); return true; } return false; } bool Hand::eat_pair(Tiles& tiles) { if(tiles[0] == tiles[1]) { tiles.erase(tiles.begin(), tiles.begin() + 2); return true; } return false; } bool Hand::eat_pair(Tiles& tiles, Sets& hand) { if(tiles[0] == tiles[1]) { hand.push_back(Set(Set::Pair, Tiles(tiles.begin(), tiles.begin() + 2), false)); tiles.erase(tiles.begin(), tiles.begin() + 2); return true; } return false; } bool Hand::eat_pon(Tiles& tiles) { if(tiles[0] == tiles[2]) { tiles.erase(tiles.begin(), tiles.begin() + 3); return true; } return false; } bool Hand::eat_pon(Tiles& tiles, Sets& hand) { if(tiles[0] == tiles[2]) { hand.push_back(Set(Set::Pon, Tiles(tiles.begin(), tiles.begin() + 3), false)); tiles.erase(tiles.begin(), tiles.begin() + 3); return true; } return false; } bool Hand::eat_chi(Tiles& tiles) { Tile::Set set = tiles.front().get_set(); int num = tiles.front().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 true; } } return false; } bool Hand::eat_chi(Tiles& tiles, Sets& hand) { Tile::Set set = tiles.front().get_set(); int num = tiles.front().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 chi; chi.push_back(tiles.front()); chi.push_back(*it1); chi.push_back(*it2); hand.push_back(Set(Set::Chi, chi, false)); tiles.erase(it2); tiles.erase(it1); tiles.erase(tiles.begin()); return true; } } return false; }