void playmp_controller::play_side(const unsigned int team_index, bool save) { utils::string_map player; player["name"] = current_team().current_player(); std::string turn_notification_msg = _("$name has taken control"); turn_notification_msg = utils::interpolate_variables_into_string(turn_notification_msg, &player); gui_->send_notification(_("Turn changed"), turn_notification_msg); do { player_type_changed_ = false; if (!skip_next_turn_) end_turn_ = false; statistics::reset_turn_stats(teams_[team_index-1].save_id()); // we can't call playsingle_controller::play_side because // we need to catch exception here if(current_team().is_human()) { LOG_NG << "is human...\n"; try{ play_ai_turn(); before_human_turn(save); play_human_turn(); after_human_turn(); } catch(end_turn_exception& end_turn) { if (end_turn.redo == team_index) { player_type_changed_ = true; // if new controller is not human, // reset gui to prev human one if (!teams_[team_index-1].is_human()) { browse_ = true; int t = find_human_team_before(team_index); if (t <= 0) t = gui_->get_playing_team() + 1; gui_->set_team(t-1); gui_->recalculate_minimap(); gui_->invalidate_all(); gui_->draw(true,true); } } else { after_human_turn(); } } LOG_NG << "human finished turn...\n"; } else if(current_team().is_ai()) { play_ai_turn(); } else if(current_team().is_network()) { play_network_turn(); } } while (player_type_changed_); //keep looping if the type of a team (human/ai/networked) has changed mid-turn skip_next_turn_ = false; }
void playsingle_controller::play_side(const unsigned int team_index, bool save) { //check for team-specific items in the scenario gui_->parse_team_overlays(); //flag used when we fallback from ai and give temporarily control to human do { // Although this flag is used only in this method, // it has to be a class member since derived classes // rely on it player_type_changed_ = false; if (!skip_next_turn_) end_turn_ = false; statistics::reset_turn_stats(teams_[team_index - 1].save_id()); if (current_team().is_human()) { try { if (save) { play_ai_turn(); if (tent::mode == TOWER_MODE) { do_fresh_heros(current_team(), false); } } before_human_turn(save); play_human_turn(); after_human_turn(); } catch(end_turn_exception& end_turn) { if (end_turn.redo == team_index) { player_type_changed_ = true; // If new controller is not human, // reset gui to prev human one if (!teams_[team_index-1].is_human()) { browse_ = true; int t = find_human_team_before(team_index); if (t > 0) { gui_->set_team(t-1); gui_->recalculate_minimap(); gui_->invalidate_all(); gui_->draw(true,true); } } } } } else if(current_team().is_ai()) { play_ai_turn(); } } while (player_type_changed_); // Keep looping if the type of a team (human/ai/networked) // has changed mid-turn skip_next_turn_ = false; }
void playsingle_controller::play_side(const unsigned int side_number, bool save) { //check for team-specific items in the scenario gui_->parse_team_overlays(); //flag used when we fallback from ai and give temporarily control to human bool temporary_human = false; do { // Although this flag is used only in this method, // it has to be a class member since derived classes // rely on it player_type_changed_ = false; if (!skip_next_turn_) end_turn_ = false; statistics::reset_turn_stats(teams_[side_number - 1].save_id()); if(current_team().is_human() || temporary_human) { LOG_NG << "is human...\n"; try{ before_human_turn(save); play_human_turn(); after_human_turn(); } catch(end_turn_exception& end_turn) { if (end_turn.redo == side_number) { player_type_changed_ = true; // If new controller is not human, // reset gui to prev human one if (!teams_[side_number-1].is_human()) { browse_ = true; int t = find_human_team_before(side_number); if (t > 0) { update_gui_to_player(t-1); } } } } LOG_NG << "human finished turn...\n"; } else if(current_team().is_ai()) { try { play_ai_turn(); } catch(fallback_ai_to_human_exception&) { //give control to human for the rest of this turn player_type_changed_ = true; temporary_human = true; } } } while (player_type_changed_); // Keep looping if the type of a team (human/ai/networked) // has changed mid-turn skip_next_turn_ = false; }
void playsingle_controller::play_side_impl() { if (!skip_next_turn_) { end_turn_ = END_TURN_NONE; } if(replay_.get() != NULL) { REPLAY_RETURN res = replay_->play_side_impl(); if(res == REPLAY_FOUND_END_TURN) { end_turn_ = END_TURN_SYNCED; } if (player_type_changed_) { replay_.reset(); } } else if((current_team().is_local_human() && current_team().is_proxy_human())) { LOG_NG << "is human...\n"; // If a side is dead end the turn, but play at least side=1's // turn in case all sides are dead if (gamestate().board_.side_units(current_side()) == 0 && !(gamestate().board_.units().size() == 0 && current_side() == 1)) { end_turn_ = END_TURN_REQUIRED; } before_human_turn(); if (end_turn_ == END_TURN_NONE) { play_human_turn(); } if ( !player_type_changed_ && !is_regular_game_end()) { after_human_turn(); } LOG_NG << "human finished turn...\n"; } else if(current_team().is_local_ai() || (current_team().is_local_human() && current_team().is_droid())) { play_ai_turn(); } else if(current_team().is_network()) { play_network_turn(); } else if(current_team().is_local_human() && current_team().is_idle()) { end_turn_enable(false); do_idle_notification(); before_human_turn(); if (end_turn_ == END_TURN_NONE) { play_idle_loop(); } } else { // we should have skipped over empty controllers before so this shouldn't be possible ERR_NG << "Found invalid side controller " << current_team().controller().to_string() << " (" << current_team().proxy_controller().to_string() << ") for side " << current_team().side() << "\n"; } }
void playsingle_controller::play_side() { //check for team-specific items in the scenario gui_->parse_team_overlays(); maybe_do_init_side(); if(is_regular_game_end()) { return; } //flag used when we fallback from ai and give temporarily control to human bool temporary_human = false; do { //Update viewing team in case it has changed during the loop. if(int side_num = play_controller::find_last_visible_team()) { if(side_num != this->gui_->viewing_side()) { update_gui_to_player(side_num - 1); } } // This flag can be set by derived classes (in overridden functions). player_type_changed_ = false; if (!skip_next_turn_) end_turn_ = END_TURN_NONE; statistics::reset_turn_stats(gamestate_.board_.teams()[player_number_ - 1].save_id()); if((current_team().is_local_human() && current_team().is_proxy_human()) || temporary_human) { LOG_NG << "is human...\n"; temporary_human = false; // If a side is dead end the turn, but play at least side=1's // turn in case all sides are dead if (gamestate_.board_.side_units(player_number_) == 0 && !(gamestate_.board_.units().size() == 0 && player_number_ == 1)) { end_turn_ = END_TURN_REQUIRED; } before_human_turn(); if (end_turn_ == END_TURN_NONE) { play_human_turn(); } if(is_regular_game_end()) { return; } if ( !player_type_changed_ ) { after_human_turn(); } LOG_NG << "human finished turn...\n"; } else if(current_team().is_local_ai() || (current_team().is_local_human() && current_team().is_droid())) { try { play_ai_turn(); } catch(fallback_ai_to_human_exception&) { // Give control to a human for this turn. player_type_changed_ = true; temporary_human = true; } if(is_regular_game_end()) { return; } } else if(current_team().is_network()) { play_network_turn(); if(is_regular_game_end()) { return; } } else if(current_team().is_local_human() && current_team().is_idle()) { end_turn_enable(false); do_idle_notification(); before_human_turn(); if (end_turn_ == END_TURN_NONE) { play_idle_loop(); if(is_regular_game_end()) { return; } } } else { assert(current_team().is_empty()); // Do nothing. } } while (player_type_changed_); // Keep looping if the type of a team (human/ai/networked) // has changed mid-turn sync_end_turn(); assert(end_turn_ == END_TURN_SYNCED); skip_next_turn_ = false; }
int main(int argc, char** argv) { int c; int errflg = 0, fflg = 0; char *ifile; extern char *optarg; extern int optind, optopt; ai_t ai = eval1_iter_ai; // the default ai, if none is specified int depth_cutoff = 30; // the default search depth cut-off turn_t ai_turn = white; // the default first turn is white /* parse command line args */ while ((c = getopt(argc, argv, "wbh12345d:f:")) != -1) { switch(c) { case 'w': //AI white ai_turn = white; printf("AI white - human black\n"); break; case 'b': //AI black ai_turn = black; printf("human white - AI black\n"); break; case '1': // AI 1 - minimax ai = minimax_ai; break; case '2': // AI 2 - alpha-beta ai = alphabeta_ai; break; case '3': // AI 3 - iterative deepening alpha-beta ai = ab_iter_ai; break; case '4': // AI 4 - eval function 1 ai = eval1_ai; break; case '5': // AI 5 - eval function 2 ai = eval1_iter_ai; break; case 'h': //print help errflg++; break; case 'd': //depth cutoff depth_cutoff = atoi(optarg); if(depth_cutoff == 0) { fprintf(stderr, "depth cut-off must be a non-zero integer\n"); errflg++; } break; case 'f': //input file fflg++; ifile = optarg; break; case ':': /* -f or -o without operand */ fprintf(stderr, "Option -%c requires an operand\n", optopt); errflg++; break; case '?': fprintf(stderr, "Unrecognized option: -%c\n", optopt); errflg++; } } if (errflg) { printhelp(); exit(2); } //if no input file set, set to default if (fflg == 0) { ifile = DEFAULT_START; } //load starting position if(parsefile(ifile) != 0) exit(1); // show the loaded state printf("starting position:\n"); showstate(white_bits, black_bits); int result = 0; // check who starts if(ai_turn == white) { // AI starts printf("\nAI is white, AI starts. Press any key to start AI turn."); getchar(); // wait for key to be pressed result = play_ai_turn(ai_turn, ai, &bitboard_white, bitboard_black, white_bits, black_bits, depth_cutoff); while(result == 0) { int bytes_read; int nbytes = 5; char *user_input = (char *) malloc (6); int inputerr = 1; int user_x, user_y, user_dir; printf("\nYour turn to move black:\n"); while(inputerr != 0) { inputerr = 0; bytes_read = getline(&user_input, (size_t*)&nbytes, stdin); if(bytes_read == -1) inputerr++; user_x = (int)user_input[0] - 48; if(user_x < 1 || user_x > 7) inputerr++; user_y = (int)user_input[1] - 48; if(user_y < 1 || user_y > 7) inputerr++; switch(user_input[2]) { case 'N': user_dir = N; break; case 'E': user_dir = E; break; case 'W': user_dir = W; break; case 'S': user_dir = S; break; default: inputerr++; } if(inputerr) { printf("\nerror in input, try again:\n"); } else { user_x = user_x - 1; user_y = user_y - 1; int bit_number = 8*user_y + user_x; uint64_t piece = (uint64_t)1 << bit_number; // make sure its a valid piece if(piece & bitboard_black) { int i = 0; while(piece != black_bits[i]){ i++; } inputerr = trydir(user_dir, &piece, &bitboard_black, bitboard_white); if(inputerr == 0) { black_bits[i] = piece; } } else { inputerr++; } if(inputerr) printf("invalid move, try again:\n"); } } showstate(white_bits, black_bits); printf("\nAI turn\n"); result = play_ai_turn(ai_turn, ai, &bitboard_white, bitboard_black, white_bits, black_bits, depth_cutoff); } } else { // human starts, AI is black printf("AI is black, human starts. Enter the first move to start."); while(result == 0) { int bytes_read; int nbytes = 5; char *user_input = (char *) malloc (nbytes + 1); int inputerr = 1; int user_x, user_y, user_dir; printf("\nYour turn to move white:\n"); while(inputerr != 0) { inputerr = 0; bytes_read = getline(&user_input, (size_t*)&nbytes, stdin); if(bytes_read == -1) inputerr++; user_x = (int)user_input[0] - 48; if(user_x < 1 || user_x > 7) inputerr++; user_y = (int)user_input[1] - 48; if(user_y < 1 || user_y > 7) inputerr++; switch(user_input[2]) { case 'N': user_dir = N; break; case 'E': user_dir = E; break; case 'W': user_dir = W; break; case 'S': user_dir = S; break; default: inputerr++; } if(inputerr) { printf("\nerror in input, try again:\n"); } else { user_x = user_x - 1; user_y = user_y - 1; int bit_number = 8*user_y + user_x; uint64_t piece = (uint64_t)1 << bit_number; // make sure its a valid piece if(piece & bitboard_white) { int i = 0; while(piece != white_bits[i]){ i++; } inputerr = trydir(user_dir, &piece, &bitboard_white, bitboard_black); if(inputerr == 0) { white_bits[i] = piece; } } else { inputerr++; } if(inputerr) printf("invalid move, try again:\n"); } } showstate(white_bits, black_bits); printf("\nAI turn\n"); result = play_ai_turn(ai_turn, ai, &bitboard_black, bitboard_white, black_bits, white_bits, depth_cutoff); } } if(result == 1) { printf("\nAI wins!\n"); } else { printf("\nThe winner is YOU!\n"); } getchar(); return 0; }
possible_end_play_signal playsingle_controller::play_side() { //check for team-specific items in the scenario gui_->parse_team_overlays(); HANDLE_END_PLAY_SIGNAL( maybe_do_init_side(false) ); //flag used when we fallback from ai and give temporarily control to human bool temporary_human = false; do { // This flag can be set by derived classes (in overridden functions). player_type_changed_ = false; if (!skip_next_turn_) end_turn_ = false; statistics::reset_turn_stats(gamestate_.board_.teams()[player_number_ - 1].save_id()); if(current_team().is_human() || temporary_human) { LOG_NG << "is human...\n"; temporary_human = false; // If a side is dead end the turn, but play at least side=1's // turn in case all sides are dead if (gamestate_.board_.side_units(player_number_) != 0 || (resources::units->size() == 0 && player_number_ == 1)) { possible_end_play_signal signal = before_human_turn(); if (!signal) { signal = play_human_turn(); } if (signal) { switch (boost::apply_visitor(get_signal_type(), *signal)) { case END_LEVEL: return signal; case END_TURN: if (int(boost::apply_visitor(get_redo(),*signal)) == player_number_) { player_type_changed_ = true; // If new controller is not human, // reset gui to prev human one if (!gamestate_.board_.teams()[player_number_-1].is_human()) { browse_ = true; int s = find_human_team_before_current_player(); if (s <= 0) s = gui_->playing_side(); update_gui_to_player(s-1); } } } } } // Ending the turn commits all moves. undo_stack_->clear(); if ( !player_type_changed_ ) after_human_turn(); LOG_NG << "human finished turn...\n"; } else if(current_team().is_ai()) { try { play_ai_turn(); } catch(fallback_ai_to_human_exception&) { // Give control to a human for this turn. player_type_changed_ = true; temporary_human = true; } catch (end_level_exception & e) { //Don't know at the moment if these two are possible but can't hurt to add return possible_end_play_signal(e.to_struct()); } catch (end_turn_exception & e) { return possible_end_play_signal(e.to_struct()); } if(!player_type_changed_) { recorder.end_turn(); } } else if(current_team().is_network()) { PROPOGATE_END_PLAY_SIGNAL( play_network_turn() ); } else if(current_team().is_idle()) { end_turn_enable(false); do_idle_notification(); possible_end_play_signal signal = before_human_turn(); if (!signal) { signal = play_idle_loop(); } if (signal) { switch (boost::apply_visitor(get_signal_type(), *signal)) { case END_LEVEL: return signal; case END_TURN: LOG_NG << "Escaped from idle state with exception!" << std::endl; if (int(boost::apply_visitor(get_redo(), *signal)) == player_number_) { player_type_changed_ = true; // If new controller is not human, // reset gui to prev human one if (!gamestate_.board_.teams()[player_number_-1].is_human()) { browse_ = true; int s = find_human_team_before_current_player(); if (s <= 0) s = gui_->playing_side(); update_gui_to_player(s-1); } } } } } // Else current_team().is_empty(), so do nothing. } while (player_type_changed_); // Keep looping if the type of a team (human/ai/networked) // has changed mid-turn skip_next_turn_ = false; return boost::none; }
void playsingle_controller::play_side(const unsigned int side_number, bool save) { //check for team-specific items in the scenario gui_->parse_team_overlays(); //flag used when we fallback from ai and give temporarily control to human bool temporary_human = false; do { // This flag can be set by derived classes (in overridden functions). player_type_changed_ = false; if (!skip_next_turn_) end_turn_ = false; statistics::reset_turn_stats(teams_[side_number - 1].save_id()); if(current_team().is_human() || temporary_human) { LOG_NG << "is human...\n"; temporary_human = false; try{ before_human_turn(save); play_human_turn(); } catch(end_turn_exception& end_turn) { if (end_turn.redo == side_number) { player_type_changed_ = true; // If new controller is not human, // reset gui to prev human one if (!teams_[side_number-1].is_human()) { browse_ = true; int s = find_human_team_before(side_number); if (s <= 0) s = gui_->playing_side(); update_gui_to_player(s-1); } } } // Ending the turn commits all moves. undo_stack_->clear(); if ( !player_type_changed_ ) after_human_turn(); LOG_NG << "human finished turn...\n"; } else if(current_team().is_ai()) { try { play_ai_turn(); } catch(fallback_ai_to_human_exception&) { // Give control to a human for this turn. player_type_changed_ = true; temporary_human = true; } } else if(current_team().is_network()) { play_network_turn(); } // Else current_team().is_empty(), so do nothing. } while (player_type_changed_); // Keep looping if the type of a team (human/ai/networked) // has changed mid-turn skip_next_turn_ = false; }
void playsingle_controller::play_side() { //check for team-specific items in the scenario gui_->parse_team_overlays(); int end_ticks = calculate_end_ticks(); while (unit_map::main_ticks < end_ticks && !player_type_changed_) { VALIDATE(!unit::actor, "playsingle_controller::play_side, unit::actor isn't NULL!"); unit* u = &units_.current_unit(); if (!tent::turn_based) { int past_ticks = u->backward_ticks(u->ticks()); if (unit_map::main_ticks + past_ticks >= end_ticks) { units_.do_escape_ticks_uh(teams_, *gui_, end_ticks - unit_map::main_ticks, false); autosave_ticks_ = -1; continue; } u = NULL; units_.do_escape_ticks_uh(teams_, *gui_, past_ticks, true); } else { if (u->side() < player_number_) { unit_map::main_ticks = end_ticks; player_number_ = 1; continue; } } bool new_side = do_prefix_unit(end_ticks, loading_game_, true); if (actor_can_continue_action(units_, player_number_)) { team& t = teams_[player_number_ - 1]; // Although this flag is used only in this method, // it has to be a class member since derived classes // rely on it player_type_changed_ = false; if (!skip_next_turn_) { end_turn_ = false; } if (t.is_human()) { try { if (!loading_game_ && unit::actor->human_team_can_ai()) { play_ai_turn(NULL); } before_human_turn(new_side); play_human_turn(); after_human_turn(); } catch(end_turn_exception& end_turn) { if (end_turn.redo == player_number_ - 1) { player_type_changed_ = true; // If new controller is not human, // reset gui to prev human one if (!teams_[player_number_ - 2].is_human()) { browse_ = true; int t = find_human_team_before(player_number_ - 1); if (t > 0) { gui_->set_team(t-1); gui_->recalculate_minimap(); gui_->invalidate_all(); gui_->draw(true,true); } } } } } else if (t.is_ai()) { play_ai_turn(NULL); } } do_post_unit(false); if (!gui_->access_is_null(game_display::taccess_list::TROOP)) { gui_->verify_access_troops(); } loading_game_ = false; } // Keep looping if the type of a team (human/ai/networked) // has changed mid-turn skip_next_turn_ = false; }
void playmp_controller::play_side() { utils::string_map player; player["name"] = current_team().current_player(); std::string turn_notification_msg = _("$name has taken control"); turn_notification_msg = utils::interpolate_variables_into_string(turn_notification_msg, &player); gui_->send_notification(_("Turn changed"), turn_notification_msg); int end_ticks = calculate_end_ticks(); player_type_changed_ = false; while (unit_map::main_ticks < end_ticks && !player_type_changed_) { VALIDATE(!unit::actor, "playmp_controller::play_side, unit::actor isn't NULL!"); if (!skip_next_turn_) { end_turn_ = false; } unit* u = &units_.current_unit(); if (!tent::turn_based) { int past_ticks = u->backward_ticks(u->ticks()); if (unit_map::main_ticks + past_ticks >= end_ticks) { units_.do_escape_ticks_uh(teams_, *gui_, end_ticks - unit_map::main_ticks, false); autosave_ticks_ = -1; continue; } units_.do_escape_ticks_uh(teams_, *gui_, past_ticks, true); } else { if (u->side() < player_number_) { unit_map::main_ticks = end_ticks; player_number_ = 1; continue; } } // if exist spirit feature/technology, second maybe goto first. need reget u = &units_.current_unit(); player_number_ = u->side(); // init_turn_data need player_number_ be valid. team& t = teams_[player_number_ - 1]; bool local = t.is_local(); bool new_side = false; if (local || loading_game_) { if (local) { init_turn_data(); } new_side = do_prefix_unit(end_ticks, loading_game_, false); } if (t.is_network()) { play_network_turn(); } else if (actor_can_continue_action(units_, player_number_)) { // we can't call playsingle_controller::play_side because // we need to catch exception here if (t.is_human()) { try { if (!loading_game_ && unit::actor->human_team_can_ai()) { play_ai_turn(turn_data_); } before_human_turn(new_side); play_human_turn(); after_human_turn(); } catch (end_turn_exception& end_turn) { if (end_turn.redo == player_number_ - 1) { player_type_changed_ = true; // if new controller is not human, // reset gui to prev human one if (!teams_[player_number_ - 2].is_human()) { browse_ = true; int t = find_human_team_before(player_number_ - 1); if (t <= 0) t = gui_->get_playing_team() + 1; gui_->set_team(t-1); gui_->recalculate_minimap(); gui_->invalidate_all(); gui_->draw(true,true); } } else { after_human_turn(); } } } else if (t.is_ai()) { play_ai_turn(turn_data_); } } if (local) { do_post_unit(false); release_turn_data(); } loading_game_ = false; } //keep looping if the type of a team (human/ai/networked) has changed mid-turn skip_next_turn_ = false; }