#include "game.h" #include #include #include #include #ifdef DEBUG #include #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 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 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::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: { // Score calculation or something. round_end(); } break; case Action::Riichi: { players[current_player].declare_riichi(); round_update_draw(); } break; case Action::Kan: 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; } case Action::Ron: if(action.type == Action::Ron) { // TODO: Handle simultanous ron. 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(); 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: { // Score calculation or something. round_end(); } break; // Will never occur on discard: case Action::Discard: case Action::Riichi: case Action::Tsumo: case Action::Draw: break; } } void Game::round_end() { // Flere runder? round_start() round_num++; if(!round_num) { round_wind++; } awaiting_players = 4; players[0].client->round_end(boost::bind(&Game::handle_ready, shared_from_this())); players[1].client->round_end(boost::bind(&Game::handle_ready, shared_from_this())); players[2].client->round_end(boost::bind(&Game::handle_ready, shared_from_this())); players[3].client->round_end(boost::bind(&Game::handle_ready, shared_from_this())); // Ferdig? game_end() }