| @@ -26,6 +26,13 @@ | |||
| #include <cstdlib> | |||
| #include <ctime> | |||
| #include <sstream> | |||
| #include <algorithm> | |||
| #include <iterator> | |||
| #include <list> | |||
| #include "blackjack.h" | |||
| Blackjack::Blackjack(Configuration &conf) : rng(dev_random()), fiftyTwoCards(0, 51) { | |||
| @@ -35,10 +42,24 @@ Blackjack::Blackjack(Configuration &conf) : rng(dev_random()), fiftyTwoCards(0, | |||
| conf.set(&max_bet, {"max_bet", "maxbet"}); | |||
| conf.set(&hit_soft_17, {"h17", "hit_soft_17"}); | |||
| conf.set(&double_after_split, {"das", "double_after_split"}); | |||
| conf.set(&blackjack_pays, {"blackjack_pays"}); | |||
| conf.set(&number_of_burnt_cards, {"number_of_burnt_cards", "n_burnt_cards", "burnt_cards"}); | |||
| conf.set(&penetration, {"penetration"}); | |||
| conf.set(&penetration_sigma, {"penetration_sigma", "penetration_dispersion"}); | |||
| conf.set(&shuffle_every_hand, {"shuffle_every_hand"}); | |||
| if (conf.exists("arranged_cards")) { | |||
| std::istringstream x(conf.getString("arranged_cads")); | |||
| std::list<std::string> chunks; | |||
| std::copy(std::istream_iterator<std::string>(x), std::istream_iterator<std::string>(), std::back_inserter(chunks)); | |||
| for (auto it : chunks) { | |||
| arranged_cards.push_back(std::stoi(it)); | |||
| } | |||
| } | |||
| // TODO: what's this? | |||
| conf.set(&infinite_decks_card_number_for_arranged_ones, {"infinite_decks_card_number_for_arranged_ones"}); | |||
| @@ -48,11 +69,6 @@ Blackjack::Blackjack(Configuration &conf) : rng(dev_random()), fiftyTwoCards(0, | |||
| if (explicit_seed) { | |||
| rng = std::mt19937(rng_seed); | |||
| } | |||
| /* | |||
| std::random_device random_device; | |||
| std::mt19937 random_engine(random_device()); | |||
| std::uniform_int_distribution<int> distribution_1_100(1, 100); | |||
| */ | |||
| } | |||
| Blackjack::~Blackjack() { | |||
| @@ -54,13 +54,24 @@ class Blackjack : public Dealer { | |||
| unsigned long int n_hands = 0; | |||
| unsigned long int n_hand = 0; | |||
| bool hit_soft_17 = true; | |||
| bool double_after_split = true; | |||
| bool shuffle_every_hand = false; | |||
| std::vector<unsigned int> arranged_cards; | |||
| unsigned int max_bet = 0; | |||
| unsigned int number_of_burnt_cards = 0; | |||
| unsigned int infinite_decks_card_number_for_arranged_ones = 0; | |||
| bool hit_soft_17 = true; | |||
| double insurance = 0; | |||
| double blackjack_pays = 1.5; | |||
| double penetration = 0.75; | |||
| double penetration_sigma = 0; | |||
| }; | |||
| #endif | |||
| @@ -4,7 +4,9 @@ | |||
| #include <fstream> | |||
| #include <algorithm> | |||
| #include <map> | |||
| #include <getopt.h> | |||
| #include <unistd.h> | |||
| // source https://www.walletfox.com/course/parseconfigfile.php | |||
| @@ -100,6 +102,29 @@ Configuration::Configuration(int argc, char **argv) { | |||
| if (default_file.good()) { | |||
| readConfigFile(configFilePath, explicitConfigFile); | |||
| } | |||
| if (set(dealer, {"dealer", "game"}) == false) { | |||
| // we play old-school blackjack by default | |||
| dealer = "blackjack"; | |||
| } | |||
| if (set(player, {"player"}) == false) { | |||
| // if we are on an interactive terminal we play through tty otherwise stdinout | |||
| if (isatty(1)) { | |||
| player = "tty"; | |||
| } else { | |||
| player = "stdinout"; | |||
| } | |||
| } | |||
| // common settings to all dealers and players | |||
| set(&max_incorrect_commands, {"max_incorrect_commands"}); | |||
| set(&error_standard_deviations, {"error_standard_deviations"}); | |||
| set(yaml_report_path, {"yaml_report", "yaml_report_path"}); | |||
| } | |||
| @@ -187,6 +212,16 @@ bool Configuration::set(unsigned long int *value, std::list<std::string> key) { | |||
| return false; | |||
| } | |||
| bool Configuration::set(std::string &value, std::list<std::string> key) { | |||
| for (auto it : key) { | |||
| if (exists(*(&it))) { | |||
| value = data[*(&it)]; | |||
| return true; | |||
| } | |||
| } | |||
| return false; | |||
| } | |||
| bool Configuration::set(double *value, std::list<std::string> key) { | |||
| for (auto it : key) { | |||
| if (exists(*(&it))) { | |||
| @@ -210,6 +245,11 @@ int Configuration::getInt(std::string key) { | |||
| return (it != data.end()) ? std::stoi(it->second) : 0; | |||
| } | |||
| std::string Configuration::getString(std::string key) { | |||
| auto it = data.find(key); | |||
| return (it != data.end()) ? it->second : ""; | |||
| } | |||
| Configuration::~Configuration() { | |||
| data.clear(); | |||
| } | |||
| @@ -41,6 +41,7 @@ class Configuration { | |||
| bool set(unsigned int *, std::list<std::string>); | |||
| bool set(long unsigned int *, std::list<std::string>); | |||
| bool set(double *, std::list<std::string>); | |||
| bool set(std::string &, std::list<std::string>); | |||
| void show(void); | |||
| @@ -48,15 +49,28 @@ class Configuration { | |||
| int getInt(std::string); | |||
| std::string getString(std::string); | |||
| std::string getDealerName(void) { return dealer; }; | |||
| std::string getPlayerName(void) { return player; }; | |||
| unsigned int max_incorrect_commands = 10; | |||
| std::string yaml_report_path; | |||
| unsigned int hands_per_char = false; | |||
| double error_standard_deviations; | |||
| private: | |||
| std::string configFilePath = "./blackjack.conf"; | |||
| std::map<std::string, std::string> data; | |||
| std::string configFilePath = "./blackjack.conf"; | |||
| bool explicitConfigFile = false; | |||
| std::string dealer; | |||
| std::string player; | |||
| bool show_help = false; | |||
| bool show_version = false; | |||
| bool show_bar = false; | |||
| bool bar_already_alloced = false; | |||
| std::map<std::string, std::string> data; | |||
| unsigned int hands_per_char = false; | |||
| // bool show_bar = false; | |||
| // bool bar_already_alloced = false; | |||
| }; | |||
| #endif | |||
| @@ -21,7 +21,6 @@ | |||
| */ | |||
| #include <iostream> | |||
| #include <unistd.h> | |||
| #include "base.h" | |||
| #include "conf.h" | |||
| @@ -35,24 +34,37 @@ int main(int argc, char **argv) { | |||
| Player *player = nullptr; | |||
| Configuration conf(argc, argv); | |||
| // TODO: read the args/conf to know what kind of dealer and player we are having | |||
| // TODO: pass args/conf to the constructor | |||
| dealer = new Blackjack(conf); | |||
| if (isatty(1)) { | |||
| player = new Tty(conf); | |||
| if (conf.getDealerName() == "blackjack") { | |||
| dealer = new Blackjack(conf); | |||
| } else { | |||
| player = new StdInOut(); | |||
| std::cerr << "Unknown dealer for '" << conf.getDealerName() <<"' game." << std::endl; | |||
| return -1; | |||
| } | |||
| if (conf.getPlayerName() == "tty") { | |||
| player = new Tty(conf); | |||
| } else if (conf.getPlayerName() == "stdinout") { | |||
| player = new StdInOut(); | |||
| // TODO: player strategy from file | |||
| } else { | |||
| std::cerr << "Unknown player '" << conf.getPlayerName() <<".'" << std::endl; | |||
| return -1; | |||
| } | |||
| dealer->nextAction = DealerAction::StartNewHand; | |||
| // let the action begin! | |||
| int unknownCommands = 0; | |||
| dealer->nextAction = DealerAction::StartNewHand; | |||
| while (!dealer->finished()) { | |||
| dealer->deal(player); | |||
| if (player->actionRequired != PlayerActionRequired::None) { | |||
| do { | |||
| // TODO: check for too many errors meaning dealer and player do not understand each other | |||
| if (unknownCommands++ > conf.max_incorrect_commands) { | |||
| std::cerr << "Too many unknown commands." << std::endl; | |||
| return -2; | |||
| } | |||
| player->play(); | |||
| } while (dealer->process(player) <= 0); | |||
| } | |||
| @@ -63,4 +75,5 @@ int main(int argc, char **argv) { | |||
| delete player; | |||
| delete dealer; | |||
| return 0; | |||
| } | |||