expand cli interface
new commands opt and initials
This commit is contained in:
parent
4718698ddc
commit
a95efaea4a
3 changed files with 64 additions and 8 deletions
|
@ -29,7 +29,7 @@ namespace Hanabi {
|
|||
return ret;
|
||||
}
|
||||
|
||||
constexpr static std::array<std::string, 10> cli_commands = {
|
||||
constexpr static std::array<std::string, 12> cli_commands = {
|
||||
"play",
|
||||
"clue",
|
||||
"discard",
|
||||
|
@ -40,6 +40,8 @@ namespace Hanabi {
|
|||
"evaluate",
|
||||
"help",
|
||||
"quit",
|
||||
"initials",
|
||||
"opt",
|
||||
};
|
||||
|
||||
char * cli_commands_generator(const char *text, int state) {
|
||||
|
@ -61,18 +63,17 @@ namespace Hanabi {
|
|||
|
||||
|
||||
Card parse_card(std::string card_str) {
|
||||
if (card_str == "trash") {
|
||||
if (card_str == "trash" or card_str == "kt") {
|
||||
return Cards::trash;
|
||||
}
|
||||
if(card_str.size() != 2) {
|
||||
return Cards::unknown;
|
||||
}
|
||||
constexpr std::array<char, 6> color_initials = {'r', 'y', 'g', 'b', 'p', 't'};
|
||||
auto it = std::find(color_initials.begin(), color_initials.end(), card_str[0]);
|
||||
if (it == color_initials.end()) {
|
||||
auto it = std::find(suit_initials.begin(), suit_initials.end(), card_str[0]);
|
||||
if (it == suit_initials.end()) {
|
||||
return Cards::unknown;
|
||||
}
|
||||
const suit_t suit = std::distance(color_initials.begin(), it);
|
||||
const suit_t suit = std::distance(suit_initials.begin(), it);
|
||||
try {
|
||||
const rank_t rank = 5 - std::stoi(card_str.substr(1, 1));
|
||||
return Card {suit, rank};
|
||||
|
@ -98,6 +99,7 @@ namespace Hanabi {
|
|||
std::cout << " copie(s) in draw) " << probability << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
if (num_trash > 0) {
|
||||
std::cout << Cards::trash << " (" << num_trash << " copie(s) in draw) " << trash_discard_prob << std::endl;
|
||||
}
|
||||
|
@ -150,6 +152,7 @@ namespace Hanabi {
|
|||
std::cout << "clue: give a clue." << std::endl;
|
||||
std::cout << "play <card>: 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;
|
||||
|
@ -164,6 +167,23 @@ namespace Hanabi {
|
|||
break;
|
||||
}
|
||||
|
||||
if (prompt.starts_with("initials")) {
|
||||
if (prompt.length() < 12) {
|
||||
std::cout << "At least 3 initials need to be specified" << std::endl;
|
||||
continue;
|
||||
}
|
||||
const std::string new_initials = prompt.substr(9);
|
||||
for(size_t i = 0; i < std::min(size_t(6), new_initials.length()); i++) {
|
||||
suit_initials[i] = new_initials[i];
|
||||
}
|
||||
std::cout << "Updated initials to ";
|
||||
for(const char c: suit_initials) {
|
||||
std::cout << c;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (prompt.starts_with("state")) {
|
||||
std::cout << *game << std::endl;
|
||||
const std::optional<probability_t> prob = game->lookup();
|
||||
|
@ -259,6 +279,38 @@ namespace Hanabi {
|
|||
continue;
|
||||
}
|
||||
|
||||
if (prompt.starts_with("opt")) {
|
||||
const auto reasonable_actions = game->get_reasonable_actions();
|
||||
if(reasonable_actions.empty()) {
|
||||
std::cout << "Game is over, no actions to take." << std::endl;
|
||||
continue;
|
||||
}
|
||||
Action best_action;
|
||||
std::optional<probability_t> best_probability;
|
||||
for (const auto &[action, probability] : game->get_reasonable_actions()) {
|
||||
if (!best_probability.has_value() or (probability.has_value() and probability.value() > best_probability.value())) {
|
||||
best_action = action;
|
||||
best_probability = probability;
|
||||
}
|
||||
}
|
||||
switch(best_action.type) {
|
||||
case ActionType::play:
|
||||
std::cout << "Playing " << best_action.card << std::endl;
|
||||
game->play(game->find_card_in_hand(best_action.card));
|
||||
break;
|
||||
case ActionType::discard:
|
||||
std::cout << "Discarding" << std::endl;
|
||||
game->discard(game->find_card_in_hand(best_action.card));
|
||||
break;
|
||||
case ActionType::clue:
|
||||
std::cout << "Giving a clue" << std::endl;
|
||||
game->give_clue();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "Unrecognized command. Type 'help' for a list of available commands." << std::endl;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,7 +43,8 @@ namespace Hanabi {
|
|||
|
||||
// We might want to change these at runtime to adapt to other variants.
|
||||
// However, a global variable is used so that we can have an output operator for cards reading from here
|
||||
static std::array<char, 6> suit_initials = {'r', 'y', 'g', 'b', 'p', 't'};
|
||||
// Note that this is therefore not static so that we have external linking
|
||||
inline std::array<char, 6> suit_initials = {'r', 'y', 'g', 'b', 'p', 't'};
|
||||
|
||||
struct Card {
|
||||
suit_t suit;
|
||||
|
|
|
@ -56,7 +56,10 @@ namespace Hanabi {
|
|||
template<size_t num_suits>
|
||||
std::ostream &operator<<(std::ostream &os, const Stacks<num_suits> &stacks) {
|
||||
for (size_t i = 0; i < stacks.size() - 1; i++) {
|
||||
os << starting_card_rank - stacks[i] << ", ";
|
||||
os << starting_card_rank - stacks[i];
|
||||
if(i < stacks.size() - 1) {
|
||||
os << ", ";
|
||||
}
|
||||
}
|
||||
os << starting_card_rank - stacks.back();
|
||||
return os;
|
||||
|
|
Loading…
Reference in a new issue