| #include <cstdlib> | #include <cstdlib> | ||||
| #include <ctime> | #include <ctime> | ||||
| #include <sstream> | |||||
| #include <algorithm> | |||||
| #include <iterator> | |||||
| #include <list> | |||||
| #include "blackjack.h" | #include "blackjack.h" | ||||
| Blackjack::Blackjack(Configuration &conf) : rng(dev_random()), fiftyTwoCards(0, 51) { | Blackjack::Blackjack(Configuration &conf) : rng(dev_random()), fiftyTwoCards(0, 51) { | ||||
| conf.set(&max_bet, {"max_bet", "maxbet"}); | conf.set(&max_bet, {"max_bet", "maxbet"}); | ||||
| conf.set(&hit_soft_17, {"h17", "hit_soft_17"}); | 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(&blackjack_pays, {"blackjack_pays"}); | ||||
| conf.set(&number_of_burnt_cards, {"number_of_burnt_cards", "n_burnt_cards", "burnt_cards"}); | 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? | // TODO: what's this? | ||||
| conf.set(&infinite_decks_card_number_for_arranged_ones, {"infinite_decks_card_number_for_arranged_ones"}); | conf.set(&infinite_decks_card_number_for_arranged_ones, {"infinite_decks_card_number_for_arranged_ones"}); | ||||
| if (explicit_seed) { | if (explicit_seed) { | ||||
| rng = std::mt19937(rng_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() { | Blackjack::~Blackjack() { |
| unsigned long int n_hands = 0; | unsigned long int n_hands = 0; | ||||
| unsigned long int n_hand = 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 max_bet = 0; | ||||
| unsigned int number_of_burnt_cards = 0; | unsigned int number_of_burnt_cards = 0; | ||||
| unsigned int infinite_decks_card_number_for_arranged_ones = 0; | unsigned int infinite_decks_card_number_for_arranged_ones = 0; | ||||
| bool hit_soft_17 = true; | |||||
| double insurance = 0; | double insurance = 0; | ||||
| double blackjack_pays = 1.5; | double blackjack_pays = 1.5; | ||||
| double penetration = 0.75; | |||||
| double penetration_sigma = 0; | |||||
| }; | }; | ||||
| #endif | #endif |
| #include <fstream> | #include <fstream> | ||||
| #include <algorithm> | #include <algorithm> | ||||
| #include <map> | #include <map> | ||||
| #include <getopt.h> | #include <getopt.h> | ||||
| #include <unistd.h> | |||||
| // source https://www.walletfox.com/course/parseconfigfile.php | // source https://www.walletfox.com/course/parseconfigfile.php | ||||
| if (default_file.good()) { | if (default_file.good()) { | ||||
| readConfigFile(configFilePath, explicitConfigFile); | 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"}); | |||||
| } | } | ||||
| return false; | 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) { | bool Configuration::set(double *value, std::list<std::string> key) { | ||||
| for (auto it : key) { | for (auto it : key) { | ||||
| if (exists(*(&it))) { | if (exists(*(&it))) { | ||||
| return (it != data.end()) ? std::stoi(it->second) : 0; | 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() { | Configuration::~Configuration() { | ||||
| data.clear(); | data.clear(); | ||||
| } | } |
| bool set(unsigned int *, std::list<std::string>); | bool set(unsigned int *, std::list<std::string>); | ||||
| bool set(long unsigned int *, std::list<std::string>); | bool set(long unsigned int *, std::list<std::string>); | ||||
| bool set(double *, std::list<std::string>); | bool set(double *, std::list<std::string>); | ||||
| bool set(std::string &, std::list<std::string>); | |||||
| void show(void); | void show(void); | ||||
| int getInt(std::string); | int getInt(std::string); | ||||
| std::string getString(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: | private: | ||||
| std::string configFilePath = "./blackjack.conf"; | |||||
| std::map<std::string, std::string> data; | |||||
| std::string configFilePath = "./blackjack.conf"; | |||||
| bool explicitConfigFile = false; | bool explicitConfigFile = false; | ||||
| std::string dealer; | |||||
| std::string player; | |||||
| bool show_help = false; | bool show_help = false; | ||||
| bool show_version = 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 | #endif |
| */ | */ | ||||
| #include <iostream> | #include <iostream> | ||||
| #include <unistd.h> | |||||
| #include "base.h" | #include "base.h" | ||||
| #include "conf.h" | #include "conf.h" | ||||
| Player *player = nullptr; | Player *player = nullptr; | ||||
| Configuration conf(argc, argv); | 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 { | } 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 | // 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()) { | while (!dealer->finished()) { | ||||
| dealer->deal(player); | dealer->deal(player); | ||||
| if (player->actionRequired != PlayerActionRequired::None) { | if (player->actionRequired != PlayerActionRequired::None) { | ||||
| do { | 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(); | player->play(); | ||||
| } while (dealer->process(player) <= 0); | } while (dealer->process(player) <= 0); | ||||
| } | } | ||||
| delete player; | delete player; | ||||
| delete dealer; | delete dealer; | ||||
| return 0; | |||||
| } | } |