Selaa lähdekoodia

autocompletion

master
gtheler 5 vuotta sitten
vanhempi
commit
ea938190cd
2 muutettua tiedostoa jossa 104 lisäystä ja 68 poistoa
  1. +95
    -67
      src/tty.cpp
  2. +9
    -1
      src/tty.h

+ 95
- 67
src/tty.cpp Näytä tiedosto

@@ -25,6 +25,11 @@
#include <thread>
#include <chrono>

#include <algorithm>
#include <functional>
#include <cctype>
#include <locale>

#ifdef HAVE_LIBREADLINE
#include <readline/readline.h>
#include <readline/history.h>
@@ -34,58 +39,30 @@
#include "blackjack.h"
#include "tty.h"

// TODO: make class static
std::vector<std::string> commands;




// extern "C" {

char *blackjack_commands[] = {
"help",
"hit",
"stand",
"yes",
"no",
NULL
};


char *blackjack_command_generator(const char *text, int state) {
static int list_index, len;
char *name;

if (!state) {
list_index = 0;
len = strlen(text);
}

while ((name = blackjack_commands[list_index++])) {
name = strdup(name);

if (strncmp(name, text, len) == 0) {
return name;
} else {
free(name);
}
}

return NULL;
// trim from start (in place)
static inline void ltrim(std::string &s) {
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) {
return !std::isspace(ch);
}));
}

char **blackjack_rl_completion(const char *text, int start, int end) {
char **matches = NULL;

#ifdef HAVE_LIBREADLINE
matches = rl_completion_matches(text, blackjack_command_generator);
#endif

return matches;
// trim from end (in place)
static inline void rtrim(std::string &s) {
s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) {
return !std::isspace(ch);
}).base(), s.end());
}



// }

// trim from both ends (in place)
static inline void trim(std::string &s) {
ltrim(s);
rtrim(s);
}


Tty::Tty(Configuration &conf) {
@@ -93,6 +70,17 @@ Tty::Tty(Configuration &conf) {
conf.set(&flat_bet, {"flat_bet", "flatbet"});
conf.set(&no_insurance, {"no_insurance", "dont_insure"});

if (commands.size() == 0) {
// commands.push_back("help");
commands.push_back("hit");
commands.push_back("stand");
commands.push_back("double");
commands.push_back("split");
commands.push_back("yes");
commands.push_back("no");
commands.push_back("quit");
}
// TODO: check conf for colors
prompt = cyan + " > " + reset;
}
@@ -128,6 +116,7 @@ void Tty::info(Info msg, int intData) {
// s = "shuffle";
s = "Deck needs to be shuffled.";
break;
case Info::CardPlayer:
switch (currentHand->cards.size()) {
case 1:
@@ -167,44 +156,48 @@ void Tty::info(Info msg, int intData) {
// s = "card_dealer_hole";
s = "Dealer's hole card was " + card[intData].utf8();
*(++(dealerHand.cards.begin())) = intData;
renderTable();
break;
case Info::DealerBlackjack:
// s = "dealer_blackjack";
s = "Dealer has Blackjack";
// TODO: draw dealer's hand
renderTable();
break;
case Info::PlayerWinsInsurance:
// s = "player_wins_insurance";
s = "Player wins insurance";
renderTable();
break;
case Info::PlayerBlackjackAlso:
// s = "player_blackjack_also";
s = "Player also has Blackjack";
renderTable();
break;
case Info::PlayerPushes:
// s = "player_pushes";
s = "Player pushes";
// TODO:
// print_hand_art (player->current_hand);
renderTable();
break;
case Info::PlayerLosses:
// s = "player_losses";
s = "Player losses";
// TODO:
// print_hand_art (player->current_hand);
renderTable();
break;
case Info::PlayerBlackjack:
// s = "blackjack_player";
s = "Player has Blackjack";
// TODO:
// print_hand_art (player->current_hand);
renderTable();
break;
case Info::PlayerWins:
// s = "player_wins";
s = "Player wins " + std::to_string(intData);
renderTable();
break;
case Info::NoBlackjacks:
@@ -219,11 +212,13 @@ void Tty::info(Info msg, int intData) {
} else {
s = "Player busted all hands";
}
renderTable();
break;
case Info::DealerBusts:
// s = "no_blackjacks";
s = "Dealer busts!";
renderTable();
break;
case Info::Help:
@@ -274,7 +269,7 @@ int Tty::play() {
}
#ifdef HAVE_LIBREADLINE
rl_attempted_completion_function = blackjack_rl_completion;
rl_attempted_completion_function = rl_completion;
if ((input_buffer = readline(prompt.c_str())) == nullptr) {
// EOF means "quit"
@@ -286,22 +281,24 @@ int Tty::play() {
add_history(input_buffer);
actionTaken = PlayerActionTaken::None;

// TODO: convertir a string y usar algo comun para non-readline
// TODO: better solution
std::string command = input_buffer;
trim(command);
// check common commands first
if (strcmp(input_buffer, "quit") == 0 || strcmp(input_buffer, "q")== 0) {
if (command == "quit" || command == "q") {
actionTaken = PlayerActionTaken::Quit;
} else if (strcmp(input_buffer, "help") == 0) {
} else if (command == "help") {
actionTaken = PlayerActionTaken::Help;
} else if (strcmp(input_buffer, "count") == 0 || strcmp(input_buffer, "c")== 0) {
} else if (command == "count" || command == "c") {
actionTaken = PlayerActionTaken::Count;
} else if (strcmp(input_buffer, "upcard") == 0 || strcmp(input_buffer, "u")== 0) {
} else if (command == "upcard" || command == "u") {
actionTaken = PlayerActionTaken::UpcardValue;
} else if (strcmp(input_buffer, "bankroll") == 0 || strcmp(input_buffer, "b")== 0) {
} else if (command == "bankroll" || command == "b") {
actionTaken = PlayerActionTaken::Bankroll;
} else if (strcmp(input_buffer, "hands") == 0) {
} else if (command == "hands") {
actionTaken = PlayerActionTaken::Hands;
} else if (strcmp(input_buffer, "table") == 0) {
actionTaken = PlayerActionTaken::Table;
}
if (actionTaken == PlayerActionTaken::None) {
@@ -313,9 +310,9 @@ int Tty::play() {
break;

case PlayerActionRequired::Insurance:
if (strcmp(input_buffer, "y") == 0 || strcmp(input_buffer, "yes") == 0) {
if (command == "y" || command == "yes") {
actionTaken = PlayerActionTaken::Insure;
} else if (strcmp(input_buffer, "n") == 0 || strcmp(input_buffer, "no") == 0) {
} else if (command == "n" || command == "no") {
actionTaken = PlayerActionTaken::DontInsure;
} else {
// TODO: chosse if we allow not(yes) == no
@@ -326,13 +323,13 @@ int Tty::play() {
case PlayerActionRequired::Play:

// TODO: sort by higher-expected response first
if (strcmp(input_buffer, "h") == 0 || strcmp(input_buffer, "hit") == 0) {
if (command == "h" || command =="hit") {
actionTaken = PlayerActionTaken::Hit;
} else if (strcmp(input_buffer, "s") == 0 || strcmp(input_buffer, "stand") == 0) {
} else if (command == "s" || command == "stand") {
actionTaken = PlayerActionTaken::Stand;
} else if (strcmp(input_buffer, "d") == 0 || strcmp(input_buffer, "double") == 0) {
} else if (command == "d" || command == "double") {
actionTaken = PlayerActionTaken::Stand;
} else if (strcmp(input_buffer, "p") == 0 || strcmp(input_buffer, "pair") == 0 || strcmp(input_buffer, "split") == 0) {
} else if (command == "p" || command == "split" || command == "pair") {
actionTaken = PlayerActionTaken::Split;
} else {
actionTaken = PlayerActionTaken::None;
@@ -442,3 +439,34 @@ void Tty::renderHand(Hand *hand) {
return;
}


int Tty::list_index = 0;
int Tty::len = 0;

char *Tty::rl_command_generator(const char *text, int state) {
if (!state) {
list_index = 0;
len = strlen(text);
}

for (auto i = list_index; i < commands.size(); i++) {
if (commands[i].compare(0, len, text) == 0) {
list_index = i+1;
return strdup(commands[i].c_str());
}
}

return NULL;
}

char **Tty::rl_completion(const char *text, int start, int end) {
char **matches = NULL;

#ifdef HAVE_LIBREADLINE
matches = rl_completion_matches(text, rl_command_generator);
#endif

return matches;
}

+ 9
- 1
src/tty.h Näytä tiedosto

@@ -24,6 +24,8 @@
#define TTY_H
#include "blackjack.h"

extern std::vector<std::string> commands;

class Tty : public Player {
public:
Tty(Configuration &);
@@ -32,6 +34,12 @@ class Tty : public Player {
int play() override;
void info(Info = Info::None, int = 0) override;

// for readline's autocompletion
static char *rl_command_generator(const char *, int);
static char **rl_completion(const char *, int, int);
static int list_index;
static int len;
private:

void renderHand(Hand *);
@@ -47,7 +55,7 @@ class Tty : public Player {
std::string prompt;
int delay = 200;
std::string black = "\x1B[0m";
std::string red = "\x1B[31m";
std::string green = "\x1B[32m";

Loading…
Peruuta
Tallenna