From 44e1ff4182f6983f2f363f12ff12970749ae8b46 Mon Sep 17 00:00:00 2001
From: Vegard Storheil Eriksen <zyp@jvnv.net>
Date: Wed, 1 Dec 2010 15:23:25 +0100
Subject: Move hand calculations to a new file.

---
 server/hand.cpp   | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 server/hand.h     | 23 +++++++++++++++++
 server/player.cpp | 55 +++-------------------------------------
 3 files changed, 103 insertions(+), 51 deletions(-)
 create mode 100644 server/hand.cpp
 create mode 100644 server/hand.h

(limited to 'server')

diff --git a/server/hand.cpp b/server/hand.cpp
new file mode 100644
index 0000000..393a6c0
--- /dev/null
+++ b/server/hand.cpp
@@ -0,0 +1,76 @@
+#include "hand.h"
+
+bool Hand::agari(const Tiles& tiles) {
+	return basic_format(tiles);
+}
+
+bool Hand::basic_format(const Tiles& tiles, bool pair_eaten) {
+	if(!tiles) {
+		return true; // All tiles eaten.
+	}
+	
+	if(!pair_eaten) {
+		if(Tiles rest = eat_pair(tiles)) {
+			if(basic_format(rest, true)) {
+				return true;
+			}
+		}
+	}
+	
+	if(tiles.size() < 3) {
+		return false;
+	}
+	
+	if(Tiles rest = eat_pon(tiles)) {
+		if(basic_format(rest, pair_eaten)) {
+			return true;
+		}
+	}
+	
+	if(Tiles rest = eat_chi(tiles)) {
+		return basic_format(rest, pair_eaten);
+	}
+	
+	return false;
+}
+
+Tiles Hand::eat_pair(Tiles tiles) {
+	if(tiles[0] == tiles[1]) {
+		tiles.erase(tiles.begin(), tiles.begin() + 2);
+		return tiles;
+	}
+	return Tiles();
+}
+
+Tiles Hand::eat_pon(Tiles tiles) {
+	if(tiles[0] == tiles[2]) {
+		tiles.erase(tiles.begin(), tiles.begin() + 3);
+		return tiles;
+	}
+	return Tiles();
+}
+
+Tiles Hand::eat_chi(Tiles tiles) {
+	Tile::Set set = tiles[0].get_set();
+	int num = tiles[0].get_num();
+	
+	if(set == Tile::Honor || num > 7) {
+		// Can't be chi-ed.
+		return Tiles();
+	}
+	
+	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 tiles;
+		}
+	}
+	return Tiles();
+}
+
+
diff --git a/server/hand.h b/server/hand.h
new file mode 100644
index 0000000..46ae40a
--- /dev/null
+++ b/server/hand.h
@@ -0,0 +1,23 @@
+#ifndef HAND_H
+#define HAND_H
+
+#include "../common/tile.h"
+
+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 is matching the normal format of one pair and rest triplets.
+	bool basic_format(const Tiles& tiles, bool pair_eaten = false);
+	
+	// Eat a pair from beginning of list if possible and return rest, else return empty list.
+	Tiles eat_pair(Tiles tiles);
+	
+	// Eat a pon from beginning of list if possible and return rest, else return empty list.
+	Tiles eat_pon(Tiles tiles);
+	
+	// Eat a chi from beginning of list if possible and return rest, else return empty list.
+	Tiles eat_chi(Tiles tiles);
+}
+
+#endif
diff --git a/server/player.cpp b/server/player.cpp
index 61f5831..4407095 100644
--- a/server/player.cpp
+++ b/server/player.cpp
@@ -1,5 +1,7 @@
 #include "game.h"
 
+#include "hand.h"
+
 void Game::Player::round_start() {
 	// Reset contents.
 	hand.clear();
@@ -151,64 +153,15 @@ bool Game::Player::can_kan(Tile tile, int target) {
 	return false;
 }
 
-//! Recursive function that eats away sets from a hand to determine if it's valid or not.
-bool complete_hand(Tiles tiles, bool pair_eaten = false) {
-	if(!tiles) {
-		return true; // All tiles eaten.
-	}
-	
-	if(tiles[0] == tiles[1]) {
-		if(!pair_eaten) {
-			// We can eat a pair of tiles.
-			Tiles t = tiles;
-			t.erase(t.begin(), t.begin() + 2);
-			if(complete_hand(t, true)) {
-				return true;
-			}
-		}
-		
-		if(tiles[1] == tiles[2]) {
-			// We can eat a pon of tiles.
-			Tiles t = tiles;
-			t.erase(t.begin(), t.begin() + 3);
-			if(complete_hand(t, pair_eaten)) {
-				return true;
-			}
-		}
-	}
-	
-	Tile::Set set = tiles[0].get_set();
-	int num = tiles[0].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 complete_hand(tiles, pair_eaten);
-		}
-	}
-	
-	return false;
-}
-
 bool Game::Player::can_tsumo() {
-	return complete_hand(hand);
+	return Hand::agari(hand);
 }
 
 bool Game::Player::can_ron(Tile tile) {
 	Tiles tiles = hand;
 	tiles.push_back(tile);
 	tiles.sort();
-	return complete_hand(tiles);
+	return Hand::agari(tiles);
 }
 
 void Game::Player::draw(Tile tile) {
-- 
cgit v1.2.3