diff options
Diffstat (limited to 'server')
-rw-r--r-- | server/SConstruct | 32 | ||||
-rw-r--r-- | server/client.cpp | 213 | ||||
-rw-r--r-- | server/client.h | 132 | ||||
-rw-r--r-- | server/connection.cpp | 67 | ||||
-rw-r--r-- | server/connection.h | 53 | ||||
-rw-r--r-- | server/game.cpp | 456 | ||||
-rw-r--r-- | server/game.h | 75 | ||||
-rw-r--r-- | server/hand.cpp | 252 | ||||
-rw-r--r-- | server/hand.h | 43 | ||||
-rw-r--r-- | server/lobby.cpp | 81 | ||||
-rw-r--r-- | server/lobby.h | 33 | ||||
-rw-r--r-- | server/main.cpp | 13 | ||||
-rw-r--r-- | server/player.cpp | 595 | ||||
-rw-r--r-- | server/player.h | 118 | ||||
-rw-r--r-- | server/score.cpp | 65 | ||||
-rw-r--r-- | server/score.h | 40 | ||||
-rw-r--r-- | server/tcpserver.cpp | 32 | ||||
-rw-r--r-- | server/tcpserver.h | 27 | ||||
-rw-r--r-- | server/tests/SConscript | 11 | ||||
-rw-r--r-- | server/tests/calculate_score.cpp | 47 | ||||
-rw-r--r-- | server/tests/test_framework.cpp | 1 | ||||
-rw-r--r-- | server/wall.cpp | 42 | ||||
-rw-r--r-- | server/wall.h | 30 |
23 files changed, 0 insertions, 2458 deletions
diff --git a/server/SConstruct b/server/SConstruct deleted file mode 100644 index 09f34c7..0000000 --- a/server/SConstruct +++ /dev/null @@ -1,32 +0,0 @@ -import os - -env = Environment( - ENV = os.environ, -) - -AddOption('--release', action = 'store_true') -AddOption('--profiling', action = 'store_true') - -if env['PLATFORM'] == 'win32': - env.Append(CPPFLAGS = ['-D _WIN32_WINNT']) - env.Append(LINKFLAGS = ['-Wl,--enable-auto-import']) - env.Append(LIBS = ['libboost_system-mgw44-mt-1_44.a', 'wsock32', 'ws2_32']) -else: - env.Append(LIBS = ['boost_system', 'boost_serialization', 'pthread']) - -if not GetOption('release'): - env.Append(CPPFLAGS = ['-Wall', '-g', '-D DEBUG']) - -if GetOption('profiling'): - env.Append(CPPFLAGS = ['-pg']) - env.Append(LINKFLAGS = ['-pg']) - -Export('env') - -env.Program('aotenjoud', Glob('*.cpp') + Glob('../common/*.cpp')) - -env.SConscript('tests/SConscript') - -Default('aotenjoud') - -# vim: syn=python diff --git a/server/client.cpp b/server/client.cpp deleted file mode 100644 index afec605..0000000 --- a/server/client.cpp +++ /dev/null @@ -1,213 +0,0 @@ -#include "client.h" - -#include <boost/bind.hpp> - -std::map<uint64_t, boost::weak_ptr<Client> > Client::client_list; - -Client::p Client::create(Connection::p c, std::string n) { - Client::p p(new Client(c, n)); - p->start(); - return p; -} - -Client::p Client::exists(Message::Login::p login_msg) { - if(client_list.count(login_msg->cookie)) { - // Obtain shared pointer to existing client. - Client::p client = client_list[login_msg->cookie].lock(); - - // TODO: Check if game still is ongoing? - // A client should only be reconnected to if still participating in an active game. - // It may however be proven that a client is always destructed if the game has ended, so this test might not be neccessary. - - return client; - - } else { - // No or invalid existing client found. - return Client::p(); - } -} - -Client::Client(Connection::p c, std::string n) : connection(c), timer(c->socket.get_io_service()), nick_(n) { - -} - -Client::~Client() { - client_list.erase(cookie); -} - -void Client::reconnect(Connection::p c) { - connection = c; - // TODO: Resync client. -} - -void Client::start() { - // Create a unique cookie for this client. - cookie = uint64_t(this); // TODO: Use a better cookie source. - - // Store a weak pointer to this client. - client_list[cookie] = shared_from_this(); - - // Logged in to lobby. - connection->send(make_shared<Message::LoginResponse>(Message::LoginResponse::Lobby)); -} - -void Client::handle_login(Message::p msg, boost::function<void (Client::p)> login_callback) { - if(msg->type != Message::Types::Login) { - return; - } - - Message::Login::p login_msg = dynamic_pointer_cast<Message::Login>(msg); - - // Check if nick is invalid. - if(login_msg->nick.size() == 0) { - connection->send(make_shared<Message::LoginResponse>(Message::LoginResponse::Invalid)); - connection->recv(boost::bind(&Client::handle_login, shared_from_this(), _1, login_callback)); - return; - } - - connection->send(make_shared<Message::LoginResponse>(Message::LoginResponse::Lobby)); - - nick_ = login_msg->nick; - - login_callback(shared_from_this()); -} - -void Client::handle_lobby(Message::p msg, boost::function<void (int)> lobby_callback) { - if(msg->type != Message::Types::LobbyAction) { - return; - } - - Message::LobbyAction::p lobby_msg = dynamic_pointer_cast<Message::LobbyAction>(msg); - - lobby_callback(lobby_msg->index); -} - -void Client::handle_ready(Message::p msg, boost::function<void ()> ready_callback) { - if(msg->type != Message::Types::Ready) { - // Wait for another message. - connection->recv(boost::bind(&Client::handle_ready, shared_from_this(), _1, ready_callback)); - return; - } - - ready_callback(); -} - -void Client::handle_action(Message::p msg, boost::function<void (Action)> action_callback, Actions possible_actions) { - if(msg->type != Message::Types::RoundAction) { - return; - } - - Message::RoundAction::p action_msg = dynamic_pointer_cast<Message::RoundAction>(msg); - - // Check if the action is valid. - if(possible_actions.contains(action_msg->action)) { - action_callback(action_msg->action); - } else { - action_callback(possible_actions.back()); - } -} - -void Client::lobby_status(const std::vector<std::string>& game_modes, boost::function<void (int)> callback) { - Message::LobbyStatus::p msg = make_shared<Message::LobbyStatus>(); - - msg->game_modes = game_modes; - - connection->send(msg); - - connection->recv(boost::bind(&Client::handle_lobby, shared_from_this(), _1, callback)); -} - -std::string Client::nick() { - return nick_; -} - -void Client::game_start(boost::function<void ()> callback, std::vector<std::string> players) { - if(connection) { - Message::GameStart::p msg = make_shared<Message::GameStart>(); - - msg->players = players; - - connection->send(msg); - - connection->recv(boost::bind(&Client::handle_ready, shared_from_this(), _1, callback)); - } else { - callback(); - } -} - -void Client::round_start() { - if(connection) { - connection->send(make_shared<Message::RoundStart>()); - } -} - -void Client::round_state(const PlayerState& pl_d, const PlayerState& pl_r, const PlayerState& pl_u, const PlayerState& pl_l, const GameState& g, const Actions& a) { - if(connection) { - connection->send(make_shared<Message::RoundState>(pl_d, pl_r, pl_u, pl_l, g, a)); - } -} - -void Client::round_end(Message::RoundEnd::p msg, boost::function<void ()> callback) { - if(connection) { - connection->send(msg); - - // Check if we're waiting for ready. - if(callback) { - connection->recv(boost::bind(&Client::handle_ready, shared_from_this(), _1, callback)); - } - } else { - if(callback){callback();} - } -} - -void Client::get_action(boost::function<void (Action)> callback, Actions expected_actions) { - if(connection) { - connection->recv(boost::bind(&Client::handle_action, shared_from_this(), _1, callback, expected_actions)); - } else { - callback(expected_actions.back()); - } -} - -void Client::game_end(Message::GameEnd::p msg, boost::function<void ()> callback) { - if(connection) { - connection->send(msg); - - if(callback) { - connection->recv(boost::bind(&Client::handle_ready, shared_from_this(), _1, callback)); - } - } else { - callback(); - } -} - -unsigned int ClientDumb::id() { - return 0; -} - -std::string ClientDumb::nick() { - return "CPU"; -} - -void ClientDumb::game_start(boost::function<void ()> callback, std::vector<std::string> players) { - callback(); -} - -void ClientDumb::round_start() { - -} - -void ClientDumb::round_state(const PlayerState& pl_d, const PlayerState& pl_r, const PlayerState& pl_u, const PlayerState& pl_l, const GameState& g, const Actions& a) { - -} - -void ClientDumb::round_end(Message::RoundEnd::p msg, boost::function<void ()> callback) { - if(callback) callback(); -} - -void ClientDumb::get_action(boost::function<void (Action)> callback, Actions expected_actions) { - callback(expected_actions.back()); -} - -void ClientDumb::game_end(Message::GameEnd::p msg, boost::function<void ()> callback) { - callback(); -} diff --git a/server/client.h b/server/client.h deleted file mode 100644 index e6cfcc7..0000000 --- a/server/client.h +++ /dev/null @@ -1,132 +0,0 @@ -#ifndef CLIENT_H -#define CLIENT_H - -#include <string> -#include <map> -#include <boost/shared_ptr.hpp> -#include <boost/enable_shared_from_this.hpp> -#include <boost/function.hpp> -#include <boost/asio.hpp> - -#include "connection.h" - -//! Abstract client base class. -class ClientBase { - public: - typedef boost::shared_ptr<ClientBase> p; - - virtual ~ClientBase() {} - - //! Return client's nick. - virtual std::string nick() = 0; - - //! Notify client of a game start. - virtual void game_start(boost::function<void ()> callback, std::vector<std::string> players) = 0; - - //! Notify client of a round start. - virtual void round_start() = 0; - - //! Send round state. - virtual void round_state(const PlayerState& pl_d, const PlayerState& pl_r, const PlayerState& pl_u, const PlayerState& pl_l, const GameState& g, const Actions& a) = 0; - - //! Send round end. - virtual void round_end(Message::RoundEnd::p msg, boost::function<void ()> callback) = 0; - - //! Get action. Upon connection error, last element of expected_actions will be provided. - virtual void get_action(boost::function<void (Action)> callback, Actions expected_actions) = 0; - - virtual void game_end(Message::GameEnd::p msg, boost::function<void ()> callback) = 0; - -}; - -//! Class implementing ClientBase for real clients. -class Client : public ClientBase, public boost::enable_shared_from_this<Client> { - public: - typedef boost::shared_ptr<Client> p; - - //! Construct and return a new Client instance. - static p create(Connection::p c, std::string n); - - //! Check if a Client instance of the user already exists and return it. - static p exists(Message::Login::p login_msg); - - ~Client(); - - private: - uint64_t cookie; - - static std::map<uint64_t, boost::weak_ptr<Client> > client_list; - - Connection::p connection; - - boost::asio::deadline_timer timer; - - std::string nick_; - - Client(Connection::p c, std::string n); - - //! Start communicating. - void start(); - - //! Handle Login-message. - void handle_login(Message::p msg, boost::function<void (Client::p)> login_callback); - - //! Handle LobbyAction-message. - void handle_lobby(Message::p msg, boost::function<void (int)> lobby_callback); - - //! Handle Ready-message. - void handle_ready(Message::p msg, boost::function<void ()> ready_callback); - - //! Handle Action-message. - void handle_action(Message::p msg, boost::function<void (Action)> action_callback, Actions expected_actions); - - public: - //! Inform client of lobby status (available game modes). - void lobby_status(const std::vector<std::string>& game_modes, boost::function<void (int)> callback); - - //! Return client's nick. - virtual std::string nick(); - - //! Notify client of a game start. - virtual void game_start(boost::function<void ()> callback, std::vector<std::string> players); - - //! Notify client of a round start. - virtual void round_start(); - - //! Send round state. - virtual void round_state(const PlayerState& pl_d, const PlayerState& pl_r, const PlayerState& pl_u, const PlayerState& pl_l, const GameState& g, const Actions& a); - - //! Send round end. - virtual void round_end(Message::RoundEnd::p msg, boost::function<void ()> callback); - - //! Get action. Upon connection error, last element of expected_actions will be provided. - virtual void get_action(boost::function<void (Action)> callback, Actions expected_actions); - - //! Reconnect a player. - virtual void reconnect(Connection::p c); - - virtual void game_end(Message::GameEnd::p msg, boost::function<void ()> callback); -}; - -typedef std::vector<Client> Clients; - -class ClientDumb : public ClientBase { - public: - virtual unsigned int id(); - - virtual std::string nick(); - - virtual void game_start(boost::function<void ()> callback, std::vector<std::string> players); - - virtual void round_start(); - - virtual void round_state(const PlayerState& pl_d, const PlayerState& pl_r, const PlayerState& pl_u, const PlayerState& pl_l, const GameState& g, const Actions& a); - - virtual void round_end(Message::RoundEnd::p msg, boost::function<void ()> callback); - - virtual void get_action(boost::function<void (Action)> callback, Actions expected_actions); - - virtual void game_end(Message::GameEnd::p msg, boost::function<void ()> callback); -}; - -#endif diff --git a/server/connection.cpp b/server/connection.cpp deleted file mode 100644 index 1e38f7b..0000000 --- a/server/connection.cpp +++ /dev/null @@ -1,67 +0,0 @@ -#include "connection.h" - -#include <boost/bind.hpp> - -Connection::Connection(boost::asio::io_service& io_service) : socket(io_service) { - -} - -void Connection::handle_read(uint8_t* data, std::size_t bytes, const boost::system::error_code& error_code) { - if(error_code) { - error("Read error."); - return; - } - - got_data(data, bytes); - - delete[] data; -} - -void Connection::handle_write() { - -} - -void Connection::request_data(std::size_t bytes) { - uint8_t* buf = new uint8_t[bytes]; - - boost::asio::async_read(socket, boost::asio::buffer(buf, bytes), - boost::bind(&Connection::handle_read, shared_from_this(), buf, bytes, boost::asio::placeholders::error)); -} - -void Connection::got_message(const Message::p& msg) { - // TODO: Implement message queueing. For now, unexpected messages will cause an error. - - boost::function<void (Message::p)> f = recv_callback; - recv_callback.clear(); - error_callback.clear(); - - f(msg); -} - -void Connection::error(const std::string& msg) { - if(error_callback) { - boost::function<void (const std::string&)> f = error_callback; - recv_callback.clear(); - error_callback.clear(); - - f(msg); - } else { - recv_callback.clear(); - } -} - -void Connection::write_data(uint8_t* data, std::size_t bytes) { - boost::asio::async_write(socket, boost::asio::buffer(data, bytes), - boost::bind(&Connection::handle_write, shared_from_this())); -} - -Connection::p Connection::create(boost::asio::io_service& io_service) { - return Connection::p(new Connection(io_service)); -} - -void Connection::recv(boost::function<void (Message::p)> callback, boost::function<void (const std::string&)> error) { - recv_callback = callback; - error_callback = error; - - start_recv(); -}
\ No newline at end of file diff --git a/server/connection.h b/server/connection.h deleted file mode 100644 index b51a67f..0000000 --- a/server/connection.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef CONNECTION_H -#define CONNECTION_H - -#include <boost/asio.hpp> -#include <boost/enable_shared_from_this.hpp> -#include <boost/function.hpp> - -#include "../common/connectionbase.h" - -class Connection : public ConnectionBase, public boost::enable_shared_from_this<Connection> { - private: - friend class TCPServer; - friend class Client; - - boost::asio::ip::tcp::socket socket; - - boost::function<void (Message::p)> recv_callback; - boost::function<void (const std::string&)> error_callback; - - Connection(boost::asio::io_service& io_service); - - //! Callback for when data is read. - void handle_read(uint8_t* data, std::size_t bytes, const boost::system::error_code& error_code); - - //! Callback for when data is written. - void handle_write(); - - protected: - //! Implements request_data(). - virtual void request_data(std::size_t bytes); - - //! Implements write_data(). - virtual void write_data(uint8_t* data, std::size_t bytes); - - //! Implements got_message(). - virtual void got_message(const Message::p& msg); - - //! Implements error(). - virtual void error(const std::string& msg); - - public: - typedef boost::shared_ptr<Connection> p; - - //! Constructs a new instance and returns a shared pointer. - static p create(boost::asio::io_service& io_service); - - //! Initiates an asynchronous message receive. - //! \param callback Callback for received message. - //! \param error Callback for error. - void recv(boost::function<void (Message::p)> callback, boost::function<void (const std::string&)> error = 0); -}; - -#endif diff --git a/server/game.cpp b/server/game.cpp deleted file mode 100644 index e791379..0000000 --- a/server/game.cpp +++ /dev/null @@ -1,456 +0,0 @@ -#include "game.h" - -#include <boost/bind.hpp> - -#include <iostream> -#include <algorithm> -#include <map> - -#ifdef DEBUG -#include <ctime> -#endif - -Game::p Game::create(ClientBase::p player_1, ClientBase::p player_2, ClientBase::p player_3, ClientBase::p player_4) { - Game::p p(new Game(player_1, player_2, player_3, player_4)); - p->start(); - return p; -} - -Game::~Game() { - std::cout << "Game destroyed." << std::endl; -} - -Game::Game(ClientBase::p player_1, ClientBase::p player_2, ClientBase::p player_3, ClientBase::p player_4) { - players[0].client = player_1; - players[1].client = player_2; - players[2].client = player_3; - players[3].client = player_4; -} - -void Game::handle_ready() { - if(--awaiting_players) { - return; - } - - std::cout << "All ready!" << std::endl; - - round_start(); -} - -void Game::start() { - std::cout << "Started a game with " - << players[0].client->nick() << ", " - << players[1].client->nick() << ", " - << players[2].client->nick() << " and " - << players[3].client->nick() << "." << std::endl; - - round_wind = 0; - round_num = 0; - - awaiting_players = 4; - - std::vector<std::string> pl; - - pl.push_back(players[0].client->nick()); - pl.push_back(players[1].client->nick()); - pl.push_back(players[2].client->nick()); - pl.push_back(players[3].client->nick()); - - players[0].client->game_start(boost::bind(&Game::handle_ready, shared_from_this()), pl); - - pl.erase(pl.begin()); - pl.push_back(players[0].client->nick()); - players[1].client->game_start(boost::bind(&Game::handle_ready, shared_from_this()), pl); - - pl.erase(pl.begin()); - pl.push_back(players[1].client->nick()); - players[2].client->game_start(boost::bind(&Game::handle_ready, shared_from_this()), pl); - - pl.erase(pl.begin()); - pl.push_back(players[2].client->nick()); - players[3].client->game_start(boost::bind(&Game::handle_ready, shared_from_this()), pl); -} - -void Game::round_start() { - std::cout << "Starting a new round." << std::endl; - - // Build a new wall. - wall.build(); - - // Clear previous dora and draw a new. - dora.clear(); - dora.push_back(wall.take_one()); - - kan_dora_pending = false; - - // Notify players of round start. - // TODO: Tell them where wall is broken. - players[0].round_start(-round_num); - players[1].round_start(-round_num + 1); - players[2].round_start(-round_num + 2); - players[3].round_start(-round_num + 3); - - // Draw hands. - for(int i = 0; i < 13; i++) { - players[0].draw(wall.take_one()); - players[1].draw(wall.take_one()); - players[2].draw(wall.take_one()); - players[3].draw(wall.take_one()); - } - - // Sort hands. - players[0].hand.sort(); - players[1].hand.sort(); - players[2].hand.sort(); - players[3].hand.sort(); - - // Give east an extra tile. - players[0].draw(wall.take_one()); - - current_player = 0; - - round_update_draw(); -} - -void Game::round_update_draw() { - // Get possible actions for current player. - Actions possible_actions = players[current_player].get_actions_draw(); - - // Construct and send state to each client. - PlayerNum player = 0; - do { - PlayerState state[4]; - - state[0] = players[player].get_state(); - state[1] = players[player + 1].get_state_filtered(); - state[2] = players[player + 2].get_state_filtered(); - state[3] = players[player + 3].get_state_filtered(); - - Actions a; - if(player == current_player) { - a = possible_actions; - } - - GameState gstate = {dora, current_player - player, round_wind, round_num, 0, 0}; - - players[player].client->round_state(state[0], state[1], state[2], state[3], gstate, a); - } while(++player); - - // Await action from client. - players[current_player].client->get_action(boost::bind(&Game::handle_action_draw, shared_from_this(), _1), possible_actions); -} - -void Game::round_update_discard() { - Tile discarded_tile = players[current_player].last_discard(); - - std::map<int, Actions> possible_actions; - - // Construct and send state to each client. - PlayerNum player = 0; - do { - PlayerState state[4]; - - state[0] = players[player].get_state(); - state[1] = players[player + 1].get_state_filtered(); - state[2] = players[player + 2].get_state_filtered(); - state[3] = players[player + 3].get_state_filtered(); - - Actions a; - if(player != current_player) { - if(a = players[player].get_actions_discard(discarded_tile, current_player - player)) { - possible_actions[player] = a; - } - } - - GameState gstate = {dora, current_player - player, round_wind, round_num, 0, 0}; - - players[player].client->round_state(state[0], state[1], state[2], state[3], gstate, a); - } while(++player); - - preceding_action = Action::Pass; - if(possible_actions.empty()) { - awaiting_players = 1; - handle_action_discard(Action::Pass, 0); - } else { - awaiting_players = possible_actions.size(); - for(std::map<int, Actions>::iterator it = possible_actions.begin(); it != possible_actions.end(); it++) { - players[it->first].client->get_action(boost::bind(&Game::handle_action_discard, shared_from_this(), _1, it->first), it->second); - } - } -} - -void Game::handle_action_draw(Action action) { - switch(action.type) { - case Action::Discard: { - players[current_player].discard(action.target_offset); - if(kan_dora_pending) { - kan_dora_pending = false; - dora.push_back(wall.take_one()); - } - round_update_discard(); - } break; - - case Action::Tsumo: { - players[current_player].declare_tsumo(); - round_end(Tsumo); - } break; - - case Action::Riichi: { - players[current_player].declare_riichi(); - round_update_draw(); - } break; - - case Action::Kan: { - if(action.target_type == Action::Index) { - players[current_player].make_kan(action.target_offset - 2); - dora.push_back(wall.take_one()); - } else { - players[current_player].make_kan_extend(action.target_offset); - kan_dora_pending = true; - } - players[current_player].draw(wall.take_one()); - round_update_draw(); - } break; - - case Action::Draw: - // Not implemented yet. - - // Will never occur on draw: - case Action::Pass: - case Action::Chi: - case Action::Pon: - case Action::Ron: - break; - } -} - -void Game::handle_action_discard(Action action, int player) { - switch(preceding_action.type) { - case Action::Pass: - - case Action::Chi: - if(action.type == Action::Chi) { - preceding_action = action; - preceding_action_owner = player; - break; - } - - case Action::Kan: - if(action.type == Action::Kan) { - preceding_action = action; - preceding_action_owner = player; - break; - } - - case Action::Pon: - if(action.type == Action::Pon) { - preceding_action = action; - preceding_action_owner = player; - break; - } - - // First ron. - if(action.type == Action::Ron) { - preceding_action = action; - preceding_action_owner = player; - break; - } - - // Multiple ron. - case Action::Ron: - if(action.type == Action::Ron && current_player - player > current_player - preceding_action_owner) { - preceding_action = action; - preceding_action_owner = player; - break; - } - break; - - // Will never occur on discard: - case Action::Discard: - case Action::Riichi: - case Action::Tsumo: - case Action::Draw: - break; - } - - if(--awaiting_players) { - return; - } - - switch(preceding_action.type) { - case Action::Pass: { - // Tile not claimed, next player draws. - - // Check if the wall has run out. - if(wall.remaining() <= 14) { - round_end(Draw); - break; - } - - players[++current_player].draw(wall.take_one()); - round_update_draw(); - } break; - - case Action::Chi: { - players[preceding_action_owner].make_chi(players[current_player].claim(), preceding_action.target_offset); - current_player = preceding_action_owner; - round_update_draw(); - } break; - - case Action::Pon: { - players[preceding_action_owner].make_pon(players[current_player].claim(), preceding_action.target_offset - 1, current_player - preceding_action_owner); - current_player = preceding_action_owner; - round_update_draw(); - } break; - - case Action::Kan: { - players[preceding_action_owner].make_kan(players[current_player].claim(), preceding_action.target_offset - 2, current_player - preceding_action_owner); - current_player = preceding_action_owner; - kan_dora_pending = true; - players[current_player].draw(wall.take_one()); - round_update_draw(); - } break; - - case Action::Ron: { - players[preceding_action_owner].declare_ron(players[current_player].claim()); - round_end(Ron); - } break; - - // Will never occur on discard: - case Action::Discard: - case Action::Riichi: - case Action::Tsumo: - case Action::Draw: - break; - } -} - -Tiles merge_hand_open(const Tiles& hand, const Sets& open) { - Tiles tiles = hand; - for(Sets::const_iterator it = open.begin(); it != open.end(); it++) { - tiles.insert(tiles.end(), it->tiles.begin(), it->tiles.end()); - } - return tiles; -} - -void Game::round_end(Endcondition end) { - - Message::RoundEnd::p msg[4] = make_shared<Message::RoundEnd>(); - - for(CyclicInt<4> count_player = 0; count_player < 4; count_player++) { - msg[count_player]->total_han = msg[count_player]->total_fu = msg[count_player]->won = msg[count_player]->score[count_player].won = 0; - for(int i = 0; i < 4; i++) { - msg[count_player]->score[count_player + i].score = players[count_player + i].get_state().score; - msg[count_player]->score[count_player + i].won = 0; - } - - switch(end) { - case Draw: - //msg->total_han = msg->total_fu = msg->won = 0; - break; - - case Tsumo: { - Player& player = players[current_player]; - - msg[count_player]->hand = merge_hand_open(player.hand, player.open); - - msg[count_player]->yakus = player.won_han; - - msg[count_player]->total_han = player.won_value.han(); - msg[count_player]->total_fu = player.won_value.fu_rounded(); - - if(current_player == round_num) { - msg[count_player]->won = 3 * player.won_value.tsumo_east(); - - for(int y = 0; y < 4; y++) { - msg[count_player]->score[current_player + y].won = -(msg[count_player]->won / 3); - } - msg[count_player]->score[count_player + current_player ].won = msg[count_player]->won; - - } else { - msg[count_player]->won = player.won_value.tsumo_east() + 2 * player.won_value.tsumo(); - - for(int y = 0; y < 4; y++) { - if(count_player + y == current_player) { - msg[count_player]->score[y].won = msg[count_player]->won; - } else if (count_player + y == round_num){ - msg[count_player]->score[y].won = -(player.won_value.tsumo_east()); - } else { - msg[count_player]->score[y].won = -(player.won_value.tsumo()); - } - } - } - - } break; - - case Ron: - for(int i = 0; i < 4; i++) { - if(players[current_player + i].won) { - Player& player = players[current_player + i]; - - msg[count_player]->hand = merge_hand_open(player.hand, player.open); - - msg[count_player]->yakus = player.won_han; - - msg[count_player]->total_han = player.won_value.han(); - msg[count_player]->total_fu = player.won_value.fu_rounded(); - - if(current_player + i == round_num) { - msg[count_player]->won = player.won_value.ron_east(); - msg[count_player]->score[current_player + i].won = player.won_value.ron_east(); - msg[count_player]->score[current_player].won = -(player.won_value.ron_east()); - - } else { - msg[count_player]->won = player.won_value.ron(); - msg[count_player]->score[current_player + i].won = player.won_value.ron(); - msg[count_player]->score[current_player].won = -(player.won_value.ron()); - } - - // TODO: Support multiple wins. - break; - } - } - break; - } - - //Send med score - msg[count_player]->game_end = false; - if(count_player == 3) break; - } - - round_num++; - - if(!round_num) { - round_wind++; - //Do a 4-round game for now - for(int i = 0; i < 4; ++i) { - msg[i]->game_end = true; - players[i].client->round_end(msg[i], 0); - } - game_end(); - } else { - awaiting_players = 4; - players[0].client->round_end(msg[0], boost::bind(&Game::handle_ready, shared_from_this())); - players[1 |