summaryrefslogtreecommitdiff
path: root/server
diff options
context:
space:
mode:
Diffstat (limited to 'server')
-rw-r--r--server/game.cpp330
-rw-r--r--server/player.cpp331
2 files changed, 331 insertions, 330 deletions
diff --git a/server/game.cpp b/server/game.cpp
index 65d5cf2..9a56b47 100644
--- a/server/game.cpp
+++ b/server/game.cpp
@@ -297,333 +297,3 @@ void Game::round_end() {
#endif
}
-
-void Game::Player::round_start() {
- // Reset contents.
- hand.clear();
- open.clear();
- pond.clear();
- riichi = false;
-
- // Notify client of round start.
- client->round_start();
-}
-
-Game::Player::State Game::Player::get_state() {
- State state = {hand, open, pond};
- return state;
-}
-
-Game::Player::State Game::Player::get_state_filtered() {
- State state = {hand, open, pond};
- return state;
-}
-
-Actions Game::Player::get_actions_draw() {
- Actions possible_actions;
-
- // Check if player can force a draw.
- // Check if player can tsumo.
- if(can_tsumo()) {
- possible_actions.push_back(Action(Action::Tsumo));
- }
-
- // Check if player can declare a concealed kan or extend an open pon. List all possibilities.
-
- if(!riichi) {
- // Check if player can riichi.
-
- // List all tiles that can be discarded.
- for(std::size_t i = 0; i < hand.size(); i++) {
- possible_actions.push_back(Action(Action::Discard, Action::Hand, i));
- }
-
- } else {
- // Only tile that can be discarded is the last drawn one.
- possible_actions.push_back(Action(Action::Discard, Action::Hand, hand.size() - 1));
- }
-
- return possible_actions;
-}
-
-Actions Game::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::Hand, *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::Hand, target + 1));
-
- // Check if tile can be called for a kan.
- if(can_kan(tile, target)) {
- possible_actions.push_back(Action(Action::Kan, Action::Hand, 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;
-}
-
-Game::Player::Targets Game::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 Game::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;
-}
-
-//Game::Player::Targets Game::Player::can_kan() {
-// return Targets(); // TODO
-//}
-
-bool Game::Player::can_kan(Tile tile, int target) {
- if(std::size_t(target + 2) < hand.size() && hand[target + 2] == tile) {
- return true;
- }
- 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);
-}
-
-bool Game::Player::can_ron(Tile tile) {
- Tiles tiles = hand;
- tiles.push_back(tile);
- tiles.sort();
- return complete_hand(tiles);
-}
-
-void Game::Player::draw(Tile tile) {
- hand.push_back(tile);
-}
-
-void Game::Player::discard(int target) {
- Tile tile = hand[target];
- hand.erase(hand.begin() + target);
- hand.sort();
- pond.push_back(tile);
-}
-
-Tile Game::Player::last_discard() {
- return pond.back();
-}
-
-Tile Game::Player::claim() {
- Tile& t = pond.back();
- t.invisible = true;
- return t;
-}
-
-void Game::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(chi);
-}
-
-void Game::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(pon);
-}
-
-void Game::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(kan);
-} \ No newline at end of file
diff --git a/server/player.cpp b/server/player.cpp
new file mode 100644
index 0000000..61f5831
--- /dev/null
+++ b/server/player.cpp
@@ -0,0 +1,331 @@
+#include "game.h"
+
+void Game::Player::round_start() {
+ // Reset contents.
+ hand.clear();
+ open.clear();
+ pond.clear();
+ riichi = false;
+
+ // Notify client of round start.
+ client->round_start();
+}
+
+Game::Player::State Game::Player::get_state() {
+ State state = {hand, open, pond};
+ return state;
+}
+
+Game::Player::State Game::Player::get_state_filtered() {
+ State state = {hand, open, pond};
+ return state;
+}
+
+Actions Game::Player::get_actions_draw() {
+ Actions possible_actions;
+
+ // Check if player can force a draw.
+ // Check if player can tsumo.
+ if(can_tsumo()) {
+ possible_actions.push_back(Action(Action::Tsumo));
+ }
+
+ // Check if player can declare a concealed kan or extend an open pon. List all possibilities.
+
+ if(!riichi) {
+ // Check if player can riichi.
+
+ // List all tiles that can be discarded.
+ for(std::size_t i = 0; i < hand.size(); i++) {
+ possible_actions.push_back(Action(Action::Discard, Action::Hand, i));
+ }
+
+ } else {
+ // Only tile that can be discarded is the last drawn one.
+ possible_actions.push_back(Action(Action::Discard, Action::Hand, hand.size() - 1));
+ }
+
+ return possible_actions;
+}
+
+Actions Game::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::Hand, *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::Hand, target + 1));
+
+ // Check if tile can be called for a kan.
+ if(can_kan(tile, target)) {
+ possible_actions.push_back(Action(Action::Kan, Action::Hand, 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;
+}
+
+Game::Player::Targets Game::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 Game::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;
+}
+
+//Game::Player::Targets Game::Player::can_kan() {
+// return Targets(); // TODO
+//}
+
+bool Game::Player::can_kan(Tile tile, int target) {
+ if(std::size_t(target + 2) < hand.size() && hand[target + 2] == tile) {
+ return true;
+ }
+ 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);
+}
+
+bool Game::Player::can_ron(Tile tile) {
+ Tiles tiles = hand;
+ tiles.push_back(tile);
+ tiles.sort();
+ return complete_hand(tiles);
+}
+
+void Game::Player::draw(Tile tile) {
+ hand.push_back(tile);
+}
+
+void Game::Player::discard(int target) {
+ Tile tile = hand[target];
+ hand.erase(hand.begin() + target);
+ hand.sort();
+ pond.push_back(tile);
+}
+
+Tile Game::Player::last_discard() {
+ return pond.back();
+}
+
+Tile Game::Player::claim() {
+ Tile& t = pond.back();
+ t.invisible = true;
+ return t;
+}
+
+void Game::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(chi);
+}
+
+void Game::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(pon);
+}
+
+void Game::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(kan);
+}