diff options
Diffstat (limited to 'src/hand.cpp')
-rw-r--r-- | src/hand.cpp | 252 |
1 files changed, 252 insertions, 0 deletions
diff --git a/src/hand.cpp b/src/hand.cpp new file mode 100644 index 0000000..bc4fb7a --- /dev/null +++ b/src/hand.cpp @@ -0,0 +1,252 @@ +#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<Sets> Hand::get_breakdowns(const Tiles& tiles) { + List<Sets> 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<Sets>& 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; +} |