gtheler пре 5 година
родитељ
комит
ea938190cd
2 измењених фајлова са 104 додато и 68 уклоњено
  1. +95
    -67
      src/tty.cpp
  2. +9
    -1
      src/tty.h

+ 95
- 67
src/tty.cpp Прегледај датотеку

#include <thread> #include <thread>
#include <chrono> #include <chrono>


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

#ifdef HAVE_LIBREADLINE #ifdef HAVE_LIBREADLINE
#include <readline/readline.h> #include <readline/readline.h>
#include <readline/history.h> #include <readline/history.h>
#include "blackjack.h" #include "blackjack.h"
#include "tty.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) { Tty::Tty(Configuration &conf) {
conf.set(&flat_bet, {"flat_bet", "flatbet"}); conf.set(&flat_bet, {"flat_bet", "flatbet"});
conf.set(&no_insurance, {"no_insurance", "dont_insure"}); 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 // TODO: check conf for colors
prompt = cyan + " > " + reset; prompt = cyan + " > " + reset;
} }
// s = "shuffle"; // s = "shuffle";
s = "Deck needs to be shuffled."; s = "Deck needs to be shuffled.";
break; break;
case Info::CardPlayer: case Info::CardPlayer:
switch (currentHand->cards.size()) { switch (currentHand->cards.size()) {
case 1: case 1:
// s = "card_dealer_hole"; // s = "card_dealer_hole";
s = "Dealer's hole card was " + card[intData].utf8(); s = "Dealer's hole card was " + card[intData].utf8();
*(++(dealerHand.cards.begin())) = intData; *(++(dealerHand.cards.begin())) = intData;
renderTable();
break; break;
case Info::DealerBlackjack: case Info::DealerBlackjack:
// s = "dealer_blackjack"; // s = "dealer_blackjack";
s = "Dealer has Blackjack"; s = "Dealer has Blackjack";
// TODO: draw dealer's hand // TODO: draw dealer's hand
renderTable();
break; break;
case Info::PlayerWinsInsurance: case Info::PlayerWinsInsurance:
// s = "player_wins_insurance"; // s = "player_wins_insurance";
s = "Player wins insurance"; s = "Player wins insurance";
renderTable();
break; break;
case Info::PlayerBlackjackAlso: case Info::PlayerBlackjackAlso:
// s = "player_blackjack_also"; // s = "player_blackjack_also";
s = "Player also has Blackjack"; s = "Player also has Blackjack";
renderTable();
break; break;
case Info::PlayerPushes: case Info::PlayerPushes:
// s = "player_pushes"; // s = "player_pushes";
s = "Player pushes"; s = "Player pushes";
// TODO:
// print_hand_art (player->current_hand);
renderTable();
break; break;
case Info::PlayerLosses: case Info::PlayerLosses:
// s = "player_losses"; // s = "player_losses";
s = "Player losses"; s = "Player losses";
// TODO:
// print_hand_art (player->current_hand);
renderTable();
break; break;
case Info::PlayerBlackjack: case Info::PlayerBlackjack:
// s = "blackjack_player"; // s = "blackjack_player";
s = "Player has Blackjack"; s = "Player has Blackjack";
// TODO:
// print_hand_art (player->current_hand);
renderTable();
break; break;
case Info::PlayerWins: case Info::PlayerWins:
// s = "player_wins"; // s = "player_wins";
s = "Player wins " + std::to_string(intData); s = "Player wins " + std::to_string(intData);
renderTable();
break; break;
case Info::NoBlackjacks: case Info::NoBlackjacks:
} else { } else {
s = "Player busted all hands"; s = "Player busted all hands";
} }
renderTable();
break; break;
case Info::DealerBusts: case Info::DealerBusts:
// s = "no_blackjacks"; // s = "no_blackjacks";
s = "Dealer busts!"; s = "Dealer busts!";
renderTable();
break; break;
case Info::Help: case Info::Help:
} }
#ifdef HAVE_LIBREADLINE #ifdef HAVE_LIBREADLINE
rl_attempted_completion_function = blackjack_rl_completion;
rl_attempted_completion_function = rl_completion;
if ((input_buffer = readline(prompt.c_str())) == nullptr) { if ((input_buffer = readline(prompt.c_str())) == nullptr) {
// EOF means "quit" // EOF means "quit"
add_history(input_buffer); add_history(input_buffer);
actionTaken = PlayerActionTaken::None; 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 // check common commands first
if (strcmp(input_buffer, "quit") == 0 || strcmp(input_buffer, "q")== 0) {
if (command == "quit" || command == "q") {
actionTaken = PlayerActionTaken::Quit; actionTaken = PlayerActionTaken::Quit;
} else if (strcmp(input_buffer, "help") == 0) {
} else if (command == "help") {
actionTaken = PlayerActionTaken::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; actionTaken = PlayerActionTaken::Count;
} else if (strcmp(input_buffer, "upcard") == 0 || strcmp(input_buffer, "u")== 0) {
} else if (command == "upcard" || command == "u") {
actionTaken = PlayerActionTaken::UpcardValue; actionTaken = PlayerActionTaken::UpcardValue;
} else if (strcmp(input_buffer, "bankroll") == 0 || strcmp(input_buffer, "b")== 0) {
} else if (command == "bankroll" || command == "b") {
actionTaken = PlayerActionTaken::Bankroll; actionTaken = PlayerActionTaken::Bankroll;
} else if (strcmp(input_buffer, "hands") == 0) {
} else if (command == "hands") {
actionTaken = PlayerActionTaken::Hands; actionTaken = PlayerActionTaken::Hands;
} else if (strcmp(input_buffer, "table") == 0) {
actionTaken = PlayerActionTaken::Table;
} }
if (actionTaken == PlayerActionTaken::None) { if (actionTaken == PlayerActionTaken::None) {
break; break;


case PlayerActionRequired::Insurance: case PlayerActionRequired::Insurance:
if (strcmp(input_buffer, "y") == 0 || strcmp(input_buffer, "yes") == 0) {
if (command == "y" || command == "yes") {
actionTaken = PlayerActionTaken::Insure; actionTaken = PlayerActionTaken::Insure;
} else if (strcmp(input_buffer, "n") == 0 || strcmp(input_buffer, "no") == 0) {
} else if (command == "n" || command == "no") {
actionTaken = PlayerActionTaken::DontInsure; actionTaken = PlayerActionTaken::DontInsure;
} else { } else {
// TODO: chosse if we allow not(yes) == no // TODO: chosse if we allow not(yes) == no
case PlayerActionRequired::Play: case PlayerActionRequired::Play:


// TODO: sort by higher-expected response first // 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; actionTaken = PlayerActionTaken::Hit;
} else if (strcmp(input_buffer, "s") == 0 || strcmp(input_buffer, "stand") == 0) {
} else if (command == "s" || command == "stand") {
actionTaken = PlayerActionTaken::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; 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; actionTaken = PlayerActionTaken::Split;
} else { } else {
actionTaken = PlayerActionTaken::None; actionTaken = PlayerActionTaken::None;
return; 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 Прегледај датотеку

#define TTY_H #define TTY_H
#include "blackjack.h" #include "blackjack.h"


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

class Tty : public Player { class Tty : public Player {
public: public:
Tty(Configuration &); Tty(Configuration &);
int play() override; int play() override;
void info(Info = Info::None, int = 0) 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: private:


void renderHand(Hand *); void renderHand(Hand *);
std::string prompt; std::string prompt;
int delay = 200; int delay = 200;
std::string black = "\x1B[0m"; std::string black = "\x1B[0m";
std::string red = "\x1B[31m"; std::string red = "\x1B[31m";
std::string green = "\x1B[32m"; std::string green = "\x1B[32m";

Loading…
Откажи
Сачувај