diff --git a/cli_interface.cpp b/cli_interface.cpp index 7ec28f4..d130376 100644 --- a/cli_interface.cpp +++ b/cli_interface.cpp @@ -140,24 +140,28 @@ namespace Hanabi { } void cli(const std::shared_ptr& game) { + // Set up GNU readline rl_attempted_completion_function = cli_command_completion; using_history(); + + // Tracks the depth of the replay the user explores. We have to ensure that we don't revert too much. unsigned depth = 0; + while (true) { const std::string prompt = read_line_memory_safe("> "); add_history(prompt.c_str()); if (prompt.starts_with("help")) { - std::cout << "state: print information on current game state." << std::endl; - std::cout << "clue: give a clue." << std::endl; - std::cout << "play : play specified card." << std::endl; - std::cout << "discard: discard trash from hand." << std::endl; - std::cout << "opt: take optimal action. In case of ties, prefers plays and discards in that order." << std::endl; - std::cout << "revert: revert last turn of game." << std::endl; - std::cout << "actions: display list of reasonable actions to take and their winning chances." << std::endl; - std::cout << "evaluate: evaluate current game state recursively. Potentially runtime-expensive." << std::endl; - std::cout << "id: display id of state. Has no inherent meaning, useful for debugging." << std::endl; - std::cout << "quit: Quit this interactive shell." << std::endl; + std::cout << "state: print information on current game state." << std::endl; + std::cout << "clue: give a clue." << std::endl; + std::cout << "play : play specified card." << std::endl; + std::cout << "discard: discard trash from hand." << std::endl; + std::cout << "opt: take optimal action. In case of ties, prefers plays and discards in that order." << std::endl; + std::cout << "revert : revert specified number of turns (default 1)." << std::endl; + std::cout << "actions: display list of reasonable actions to take and their winning chances." << std::endl; + std::cout << "evaluate: evaluate current game state recursively. Potentially runtime-expensive." << std::endl; + std::cout << "id: display id of state. Has no inherent meaning, useful for debugging." << std::endl; + std::cout << "quit: Quit this interactive shell." << std::endl; continue; } @@ -203,9 +207,24 @@ namespace Hanabi { std::cout << "Cannot revert more than base state." << std::endl; continue; } - std::cout << "Reverting one turn" << std::endl; - game->revert(); - depth--; + unsigned turns_to_revert = 1; + if(prompt.length() > 7) { + try { + turns_to_revert = std::stoi(prompt.substr(7)); + } catch(const std::invalid_argument&) { + std::cout << "Could not parse number of turns to revert." << std::endl; + continue; + } + } + if (turns_to_revert > depth) { + turns_to_revert = depth; + std::cout << "Only revererting " << depth << " turns, since this is already the base state." << std::endl; + } + std::cout << "Reverting " << turns_to_revert << " turn(s)." << std::endl; + while(turns_to_revert--) { + game->revert(); + depth--; + } continue; } @@ -323,6 +342,7 @@ namespace Hanabi { default: break; } + depth++; continue; }