summaryrefslogtreecommitdiff
path: root/server
diff options
context:
space:
mode:
Diffstat (limited to 'server')
-rw-r--r--server/game.cpp155
-rw-r--r--server/game.h53
2 files changed, 208 insertions, 0 deletions
diff --git a/server/game.cpp b/server/game.cpp
index 07373ac..f2b1c06 100644
--- a/server/game.cpp
+++ b/server/game.cpp
@@ -142,4 +142,159 @@ void Game::start() {
players[1]->game_start(boost::bind(&Game::handle_ready, shared_from_this()), players);
players[2]->game_start(boost::bind(&Game::handle_ready, shared_from_this()), players);
players[3]->game_start(boost::bind(&Game::handle_ready, shared_from_this()), players);
+void Game::Player::round_start() {
+ // Reset contents.
+ hand.clear();
+ open.clear();
+ pond.clear();
+ riichi = false;
+
+ // Notify client of round start.
+ client->round_start();
+}
+
+State::Player Game::Player::get_state() {
+ State::Player state = {hand, open, pond};
+ return state;
+}
+
+State::Player Game::Player::get_state_filtered() {
+ State::Player 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.
+ // 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, i));
+ }
+
+ } else {
+ // Only tile that can be discarded is the last drawn one.
+ possible_actions.push_back(Action(Action::Discard, hand.size() - 1));
+ }
+
+ return possible_actions;
+}
+
+Actions Game::Player::get_actions_discard(Tile tile) {
+ Actions possible_actions;
+
+ if(!riichi) {
+ // Check if tile can be called for a chi. Enumerate all combinations.
+ 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, *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, target));
+
+ // Check if tile can be called for a kan.
+ if(can_kan(tile, target)) {
+ possible_actions.push_back(Action(Action::Kan, target));
+ }
+ }
+ }
+
+ // Check if tile can be ron-ed.
+
+ // 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;
+}
+
+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();
}
diff --git a/server/game.h b/server/game.h
index 2574dc3..9c2513e 100644
--- a/server/game.h
+++ b/server/game.h
@@ -9,6 +9,7 @@
#include "wall.h"
#include "client.h"
#include "../common/action.h"
+#include "../common/state.h"
#include "gamevariant.h"
#include "standard.h"
@@ -23,6 +24,58 @@ class Game : public boost::enable_shared_from_this<Game> {
private:
std::vector<Client::p> players;
+ class Player {
+ public:
+ Client::p client;
+
+ Tiles hand;
+ Tiles open;
+ Tiles pond;
+ bool riichi;
+
+ //! Prepare for a new round.
+ void round_start();
+
+ //! Get a state snapshot.
+ State::Player get_state();
+
+ //! Get a state snapshot, with concealed tiles filtered.
+ State::Player get_state_filtered();
+
+ //! Get possible actions after a draw.
+ Actions get_actions_draw();
+
+ //! Get possible actions on discarded tile.
+ Actions get_actions_discard(Tile tile);
+
+ typedef std::vector<int> Targets;
+
+ //! Check if tile can be called for a chi.
+ Targets can_chi(Tile tile);
+
+ //! Check if tile can be called for a pon.
+ int can_pon(Tile tile);
+
+ //! Check if it's possible to make a concealed kan or extend an open kan.
+ Targets can_kan();
+
+ // Check if tile can be called to kan target.
+ bool can_kan(Tile tile, int target);
+
+ //! Draw tile.
+ void draw(Tile tile);
+
+ //! Discard tile.
+ void discard(int target);
+
+ //! Look at last discard in pond.
+ Tile last_discard();
+
+ //! Claim last discard from pond.
+ Tile claim();
+
+
+ };
int waiting_players;