#include "game.h" #include #include #include #include #include "../common/set.h" bool MyDataSortPredicate(const Tile& d1, const Tile& d2) { return d1.type < d2.type; } Game::p Game::create(Player::p player_1, Player::p player_2, Player::p player_3, Player::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(Player::p player_1, Player::p player_2, Player::p player_3, Player::p player_4) { players.push_back(player_1); players.push_back(player_2); players.push_back(player_3); players.push_back(player_4); } void Game::handle_ready() { std::cout << "Still waiting for " << waiting_players << "." << std::endl; if(--waiting_players) { return; } std::cout << "All ready!" << std::endl; round_start(); } void Game::round_start() { players[0]->round_start(); players[1]->round_start(); players[2]->round_start(); players[3]->round_start(); // Sett opp runden sin state //game_state = make_shared(); // Simulates drawing 4, 4 ,4 for each player for (int i = 0; i < 3; i++) { for (int player_num = 0; player_num < 4; player_num++) { for (int y = 0; y < 4; y++) { game_state.players[player_num].hand.push_back(wall.take_one()); } } } // Simulates the second part of drawing with only 1 tile for (int player_num = 0; player_num < 4; player_num++) { game_state.players[player_num].hand.push_back(wall.take_one()); } std::sort(game_state.players[0].hand.begin(),game_state.players[0].hand.end(), MyDataSortPredicate); std::sort(game_state.players[1].hand.begin(),game_state.players[1].hand.end(), MyDataSortPredicate); std::sort(game_state.players[2].hand.begin(),game_state.players[2].hand.end(), MyDataSortPredicate); std::sort(game_state.players[3].hand.begin(),game_state.players[3].hand.end(), MyDataSortPredicate); most_value_action.type = Action::Pass; current_player = 3; num_player_actions = 0; draw_phase = true; round_update(); } void Game::round_update() { char smart = 0; // We're in the draw_phase whenever a player draws a tile from the wall if(draw_phase) { // If the wall is empty (Contains only 14 tiles) when we enter draw phase the round is over. if(wall.is_done()) { round_end(); } // Since we've entered the draw-phase it's the next players turn if (current_player == 3) { current_player = 0; } else { current_player++; } #ifdef DEBUG time_t current_time = std::time(0); std::cout << std::ctime(¤t_time) << " - Waiting for action from player: " << current_player << std::endl; #endif // Let's take a tile Tile from_wall = wall.take_one(); // We then add the tile to the current players hand game_state.players[current_player].hand.push_back(from_wall); // Need to sort again. std::sort(game_state.players[current_player].hand.begin(),game_state.players[current_player].hand.end(), MyDataSortPredicate); // Construct the discard action that the player can do. Action discard; discard.type = Action::Discard; discard.player = current_player; game_state.possible_actions.push_back(discard); //num_player_actions++; // Enter the discard phase next loop; draw_phase = false; smart = smart | (1 << current_player); } else { //We chwck to see if player can chi from last discard int temp_next_player; if (current_player == 3) { temp_next_player = 0; } else { temp_next_player = current_player + 1; } Tiles* pond = &game_state.players[current_player].pond; Tile temp_tile = pond->back(); Tiles::iterator it; Tile* tile_2u = NULL; Tile* tile_1u = NULL; Tile* tile_1o = NULL; Tile* tile_2o = NULL; unsigned int count = 0, tile_2u_id,tile_1u_id,tile_1o_id,tile_2o_id; Tile::Type check_tile; for(it = game_state.players[temp_next_player].hand.begin(); it != game_state.players[temp_next_player].hand.end(); ++it) { check_tile = Tile::Type(temp_tile.type - 2); if(it->type == check_tile) { tile_2u = &(*it); tile_2u_id = count; } check_tile = Tile::Type(temp_tile.type - 1); if(it->type == check_tile) { tile_1u = &(*it); tile_1u_id = count; } check_tile = Tile::Type(temp_tile.type + 1); if(it->type == check_tile) { tile_1o = &(*it); tile_1o_id = count; } check_tile = Tile::Type(temp_tile.type + 2); if(it->type == check_tile) { tile_2o = &(*it); tile_2o_id = count; } count++; } bool chi; if(tile_2u && tile_1u) { Action temp_action; chi = false; //Make sure we have a chi within the same series. if(tile_2u->type <= Tile::Man_7 && tile_2u->type >= Tile::Man_1) { if(temp_tile.type <= Tile::Man_9 && temp_tile.type >= Tile::Man_3) { chi = true; } } else if(tile_2u->type <= Tile::Pin_7 && tile_2u->type >= Tile::Pin_1) { if(temp_tile.type <= Tile::Pin_9 && temp_tile.type >= Tile::Pin_3) { chi = true; } } else if(tile_2u->type <= Tile::Sou_1 && tile_2u->type >= Tile::Sou_1) { if(temp_tile.type <= Tile::Sou_9 && temp_tile.type >= Tile::Sou_3) { chi = true; } } if(chi) { temp_action.player = temp_next_player; temp_action.target = tile_2u_id; temp_action.type = Action::Chi; game_state.possible_actions.push_back(temp_action); #ifdef DEBUG time_t current_time = std::time(0); std::cout << std::ctime(¤t_time) << " Player: " << temp_action.player << " Can do action: " << temp_action.type << " On target: " << temp_action.target << std::endl; #endif } } if(tile_1u && tile_1o) { Action temp_action; chi = false; //Make sure we have a chi within the same series. if(tile_1u->type <= Tile::Man_7 && tile_1u->type >= Tile::Man_1) { if(tile_1o->type <= Tile::Man_9 && tile_1o->type >= Tile::Man_3) { chi = true; } } else if(tile_1u->type <= Tile::Pin_7 && tile_1u->type >= Tile::Pin_1) { if(tile_1o->type <= Tile::Pin_9 && tile_1o->type >= Tile::Pin_3) { chi = true; } } else if(tile_1u->type <= Tile::Sou_1 && tile_1u->type >= Tile::Sou_1) { if(tile_1o->type <= Tile::Sou_9 && tile_1o->type >= Tile::Sou_3) { chi = true; } } if(chi) { temp_action.player = temp_next_player; temp_action.target = tile_1u_id; temp_action.type = Action::Chi; game_state.possible_actions.push_back(temp_action); #ifdef DEBUG time_t current_time = std::time(0); std::cout << std::ctime(¤t_time) << " Player: " << temp_action.player << " Can do action: " << temp_action.type << " On target: " << temp_action.target << std::endl; #endif } } if(tile_1o && tile_2o) { Action temp_action; chi = false; //Make sure we have a chi within the same series. if(temp_tile.type <= Tile::Man_7 && temp_tile.type >= Tile::Man_1) { if(tile_2o->type <= Tile::Man_9 && tile_2o->type >= Tile::Man_3) { chi = true; } } else if(temp_tile.type <= Tile::Pin_7 && temp_tile.type >= Tile::Pin_1) { if(tile_2o->type <= Tile::Pin_9 && tile_2o->type >= Tile::Pin_3) { chi = true; } } else if(temp_tile.type <= Tile::Sou_1 && temp_tile.type >= Tile::Sou_1) { if(tile_2o->type <= Tile::Sou_9 && tile_2o->type >= Tile::Sou_3) { chi = true; } } if(chi) { temp_action.player = temp_next_player; temp_action.target = tile_1o_id; temp_action.type = Action::Chi; game_state.possible_actions.push_back(temp_action); #ifdef DEBUG time_t current_time = std::time(0); std::cout << std::ctime(¤t_time) << " Player: " << temp_action.player << " Can do action: " << temp_action.type << " On target: " << temp_action.target << std::endl; #endif } } //Go back into draw_phase0 draw_phase = true; // Not implemented yet for(Actions::iterator it = game_state.possible_actions.begin(); it != game_state.possible_actions.end(); ++it) { smart = smart | (0x0001 << it->player); } if(smart & 1) { Action pass; pass.type = Action::Pass; pass.player = 0; game_state.possible_actions.push_back(pass); } if(smart & 2) { Action pass; pass.type = Action::Pass; pass.player = 1; game_state.possible_actions.push_back(pass); } if(smart & 4) { Action pass; pass.type = Action::Pass; pass.player = 2; game_state.possible_actions.push_back(pass); } if(smart & 8) { Action pass; pass.type = Action::Pass; pass.player = 3; game_state.possible_actions.push_back(pass); } } // Send the updates state to the players players[0]->round_state(game_state); players[1]->round_state(game_state); players[2]->round_state(game_state); players[3]->round_state(game_state); // Only implemented discard so far, so only current player that needs to be able to do a action. if(smart & 1) { num_player_actions++; players[0]->get_action(boost::bind(&Game::handle_action, shared_from_this(), _1)); } if(smart & 2) { num_player_actions++; players[1]->get_action(boost::bind(&Game::handle_action, shared_from_this(), _1)); } if(smart & 4) { num_player_actions++; players[2]->get_action(boost::bind(&Game::handle_action, shared_from_this(), _1)); } if(smart & 8) { num_player_actions++; players[3]->get_action(boost::bind(&Game::handle_action, shared_from_this(), _1)); } if(num_player_actions == 0) { round_update(); } } void Game::handle_action(Action action) { players[action.player]->kill_action(); #ifdef DEBUG time_t current_time = std::time(0); std::cout << std::ctime(¤t_time) << " Player: " << action.player << " Did action: " << action.type << " On target: " << action.target << std::endl; #endif // Lots of actions to test if the player doing the action is allowed to do it // Check if we're actually waiting for actions. if (game_state.possible_actions.empty()) { return; } // Check if the player is allowed to do this action bool found_action = false; for(Actions::iterator it = game_state.possible_actions.begin(); it != game_state.possible_actions.end(); ++it) { if(it->player == action.player && it->type == action.type) { found_action = true; } } if(!found_action) { return; } switch ( action.type ) { case Action::Pass: { } break; case Action::Discard: { Tile discarded_tile = game_state.players[action.player].hand[action.target]; game_state.players[action.player].pond.push_back(discarded_tile); game_state.players[action.player].hand.erase(game_state.players[action.player].hand.begin() + action.target); } break; case Action::Riichi: { } break; case Action::Chi: { if(most_value_action.type != Action::Pon && most_value_action.type != Action::Kan && most_value_action.type != Action::Ron) { most_value_action = action; } } break; case Action::Pon: { if(most_value_action.type != Action::Ron) { most_value_action = action; } } break; case Action::Kan: { } break; case Action::Ron: { } break; case Action::Tsumo: { } break; case Action::Draw: { } break; default: break; } num_player_actions--; // Remove all the actions that this player could do since he now did one. std::vector positions; int position = 0; for(Actions::iterator it = game_state.possible_actions.begin(); it != game_state.possible_actions.end(); ++it) { if (it->player == action.player) { positions.push_back(position); } position++; } if (!positions.empty()) { int found = 0; for(std::vector::iterator it = positions.begin(); it != positions.end(); ++it) { game_state.possible_actions.erase(game_state.possible_actions.begin() + (*it - found)); found++; } } //When everyone has done their action we empty the list (just to be sure) and then do a round_update() if(num_player_actions == 0) { game_state.possible_actions.empty(); if(most_value_action.type != Action::Pass) { switch (most_value_action.type) { case Action::Chi: { Set chi; Tile left_tile = game_state.players[current_player].pond.back(); left_tile.rotated = true; chi.add_tile(left_tile); Tile middle_tile = game_state.players[action.player].hand[action.target]; chi.add_tile(middle_tile); Tile right_tile; if(Tile::Type(game_state.players[action.player].hand[action.target].type + 1) == left_tile.type) { right_tile = game_state.players[action.player].hand[action.target + 2]; } else { right_tile = game_state.players[action.player].hand[action.target + 1]; } chi.add_tile(right_tile); game_state.players[action.player].open.push_back(chi); game_state.players[action.player].hand.erase(game_state.players[action.player].hand.begin() + action.target); game_state.players[action.player].hand.erase(game_state.players[action.player].hand.begin() + action.target); } break; case Action::Pon: { } break; case Action::Kan: { } break; case Action::Ron: { } break; default: break; } most_value_action.type = Action::Pass; } round_update(); } // Sjekk action, sjekk om endelig action er avgjort // Oppdater state // Evt. round_end() } void Game::round_end() { // Flere runder? round_start() // Ferdig? game_end() players[0]->round_end(); players[1]->round_end(); players[2]->round_end(); players[3]->round_end(); #ifdef DEBUG time_t current_time = std::time(0); std::cout << std::ctime(¤t_time) << " Round is over..." << std::endl; #endif } void Game::start() { std::cout << "Started a game with " << players[0]->nick() << ", " << players[1]->nick() << ", " << players[2]->nick() << " and " << players[3]->nick() << "." << std::endl; players[0]->id = 0; players[1]->id = 1; players[2]->id = 2; players[3]->id = 3; waiting_players = 4; players[0]->game_start(boost::bind(&Game::handle_ready, shared_from_this()), players); 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); }