diff options
Diffstat (limited to 'server')
| -rw-r--r-- | server/game.h | 3 | ||||
| -rw-r--r-- | server/hand.cpp | 92 | ||||
| -rw-r--r-- | server/hand.h | 12 | ||||
| -rw-r--r-- | server/player.cpp | 28 | 
4 files changed, 133 insertions, 2 deletions
| diff --git a/server/game.h b/server/game.h index 6c986f5..1de6c73 100644 --- a/server/game.h +++ b/server/game.h @@ -50,6 +50,9 @@ class Game : public boost::enable_shared_from_this<Game> {  				typedef std::vector<int> Targets; +				//! Check if player can declare riichi. +				bool can_riichi(); +				  				//! Check if tile can be called for a chi.  				Targets can_chi(Tile tile); diff --git a/server/hand.cpp b/server/hand.cpp index 393a6c0..abdeb4b 100644 --- a/server/hand.cpp +++ b/server/hand.cpp @@ -4,6 +4,10 @@ bool Hand::agari(const Tiles& tiles) {  	return basic_format(tiles);  } +bool Hand::tenpai(const Tiles& tiles) { +	return basic_format_tenpai(tiles); +} +  bool Hand::basic_format(const Tiles& tiles, bool pair_eaten) {  	if(!tiles) {  		return true; // All tiles eaten. @@ -34,6 +38,90 @@ bool Hand::basic_format(const Tiles& tiles, bool pair_eaten) {  	return false;  } +bool Hand::basic_format_tenpai(const Tiles& tiles, bool pair_eaten, bool wait_eaten) { +	if(!tiles) { +		return true; +	} +	 +	if(!pair_eaten && !wait_eaten) { +		if(basic_format_tenpai(eat_tanki(tiles), true, true)) { +			return true; +		} +	} +	 +	if(tiles.size() < 2) { +		return false; +	} +	 +	if(!pair_eaten) { +		if(Tiles rest = eat_pair(tiles)) { +			if(basic_format_tenpai(rest, true, wait_eaten)) { +				return true; +			} +		} +	} +	 +	if(!wait_eaten) { +		if(Tiles rest = eat_chi_wait(tiles)) { +			if(basic_format_tenpai(rest, pair_eaten, true)) { +				return true; +			} +		} +	} +	 +	if(tiles.size() < 3) { +		return false; +	} +	 +	if(Tiles rest = eat_pon(tiles)) { +		if(basic_format_tenpai(rest, pair_eaten, wait_eaten)) { +			return true; +		} +	} +	 +	if(Tiles rest = eat_chi(tiles)) { +		return basic_format_tenpai(rest, pair_eaten, wait_eaten); +	} +	 +	return false; +} + +Tiles Hand::eat_tanki(Tiles tiles) { +	tiles.erase(tiles.begin()); +	return tiles; +} + +Tiles 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 Tiles(); +	} +	 +	// 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 tiles; +	} +	 +	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 tiles; +	} +	 +	return Tiles(); +} +  Tiles Hand::eat_pair(Tiles tiles) {  	if(tiles[0] == tiles[1]) {  		tiles.erase(tiles.begin(), tiles.begin() + 2); @@ -51,8 +139,8 @@ Tiles Hand::eat_pon(Tiles tiles) {  }  Tiles Hand::eat_chi(Tiles tiles) { -	Tile::Set set = tiles[0].get_set(); -	int num = tiles[0].get_num(); +	Tile::Set set = tiles.front().get_set(); +	int num = tiles.front().get_num();  	if(set == Tile::Honor || num > 7) {  		// Can't be chi-ed. diff --git a/server/hand.h b/server/hand.h index 46ae40a..e38a387 100644 --- a/server/hand.h +++ b/server/hand.h @@ -7,9 +7,21 @@ namespace Hand {  	//! Check if the tiles constitute a complete hand. Also valid for the concealed part of an open hand.  	bool agari(const Tiles& tiles); +	//! Check if the tiles miss only one from constituting a complete hand. Also valid for the concealed part of an open hand. +	bool tenpai(const Tiles& tiles); +	  	// Check if the tiles is matching the normal format of one pair and rest triplets.  	bool basic_format(const Tiles& tiles, bool pair_eaten = false); +	// Check if the tiles is matching the normal format but missing one. +	bool basic_format_tenpai(const Tiles& tiles, bool pair_eaten = false, bool wait_eaten = false); +	 +	// Eat a single tile (i.e. the tanki machi) from beginning of list and return rest. +	Tiles eat_tanki(Tiles tiles); +	 +	// Eat two tiles waiting for a third to complete a chi (i.e. ryanmen, penchan or kanchan machi) if possible. +	Tiles eat_chi_wait(Tiles tiles); +	  	// Eat a pair from beginning of list if possible and return rest, else return empty list.  	Tiles eat_pair(Tiles tiles); diff --git a/server/player.cpp b/server/player.cpp index 4407095..37dc3bc 100644 --- a/server/player.cpp +++ b/server/player.cpp @@ -36,6 +36,9 @@ Actions Game::Player::get_actions_draw() {  	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++) { @@ -89,6 +92,31 @@ Actions Game::Player::get_actions_discard(Tile tile, PlayerNum discarder) {  	return possible_actions;  } +bool Game::Player::can_riichi() { +	if(open) { +		return false; +	} +	 +	Tiles tiles = hand; +	 +	// Take first tile out of the set. +	Tile out = tiles.front(); +	tiles.erase(tiles.begin()); +	 +	// Iterate over the rest of the set, exchanging the tile until a tenpai is found or all is tested. +	for(Tiles::iterator it = tiles.begin(); it != tiles.end(); it++) { +		if(Hand::tenpai(tiles)) { +			return true; +		} +		 +		// TODO: Skip unnecessary tests if player got several equal tiles on hand. +		 +		std::swap(*it, out); +	} +	 +	return false; +} +  Game::Player::Targets Game::Player::can_chi(Tile tile) {  	Targets targets; | 
