gtheler 5 lat temu
rodzic
commit
9ffde324c0
7 zmienionych plików z 272 dodań i 61 usunięć
  1. +1
    -0
      Makefile.am
  2. +11
    -0
      TODO
  3. +95
    -22
      src/base.h
  4. +109
    -33
      src/blackjack.cpp
  5. +13
    -5
      src/blackjack.h
  6. +43
    -0
      src/cards.cpp
  7. +0
    -1
      src/main.cpp

+ 1
- 0
Makefile.am Wyświetl plik

@@ -18,5 +18,6 @@ blackjack_LDADD = $(all_libraries)
blackjack_SOURCES = \
src/main.cpp \
src/blackjack.cpp \
src/cards.cpp \
src/stdinout.cpp \
src/tty.cpp

+ 11
- 0
TODO Wyświetl plik

@@ -0,0 +1,11 @@
* arranged shoes
* multithreading
* deterministic seeds
* better RNGs
* ENHC
* blackjack switch
* siete y medio
* name of the game the dealer deals
* name of the games the player can play
* delays?

+ 95
- 22
src/base.h Wyświetl plik

@@ -33,7 +33,6 @@ enum class DealerAction {
StartNewHand,
AskForBets,
DealPlayerFirstCard,
DealDealerHoleCard,
AskForInsurance,
CheckforBlackjacks,
PayOrTakeInsuranceBets,
@@ -70,39 +69,103 @@ enum class PlayerActionTaken {
Hit,
};

// alphabetically-sorted
enum class Suit {
Clubs = 0,
Diamonds = 1,
Hearts = 2,
Spades = 3
};

#define CARD_ART_LINES 6
#define CARD_TYPES 5
#define CARD_SIZE 16

class Card {
public:
int tag;
int value;
private:
std::string token[CARD_TYPES];
std::string text;
std::string art[CARD_ART_LINES];
Card(unsigned int);
~Card() { };
// TODO: delete copy & move
// TODO: decidir si conviene usar getters o public members
/*
Suit getSuit() { return suit; };
unsigned int getNumber() { return number; };
unsigned int getValue() { return value; };
*/
// std::string get
Suit suit;
unsigned int number;
unsigned int value;
std::string ascii() {
return valueASCII + suitASCII;
}
std::string utf8() {
return valueASCII + suitUTF8;
}
std::string text();
private:
std::string valueASCII;
std::string suitASCII;
std::string suitUTF8;
std::string suitName;
};


extern Card card[52];


// TODO: base + daugthers, para diferenciar entre dealer y player y otros juegos
class Hand {
public:
bool insured;
bool soft;
bool blackjack;
bool busted;
bool holeCardShown; // maybe we need a separate class for dealer and for player?
int bet;
int count;
std::list<Card> cards;
bool insured = false;
bool holeCardShown = false;
int bet = 0;
std::list<unsigned int> cards;
int total() {
unsigned int soft = 0;
unsigned int n = 0;
unsigned int value = 0;
for (auto tag : cards) {
value = card[tag].value;
n += value;
soft += (value == 11);
}
while (n > 21 && soft > 0){
n -= 10;
soft--;
}
return (soft)?(-n):(n);
};
bool blackjack() {
return (total() == 21 && cards.size() == 2);
};
bool busted() {
return (total() > 21);
}

private:
};

class dealerHand {
public:
std::list<unsigned int> cards;
unsigned int total() {
return 0;
}
private:
};


class Player {
public:
Player() = default;
@@ -133,7 +196,12 @@ class Player {
int flatBet = 0;
int currentBet = 0;
int n_hands = 0; // this is different from the dealer's due to splitting
int n_insured_hands = 0;

bool no_insurance = false;
bool always_insure = false;
double bankroll = 0;
double total_money_waged = 0;
double current_result = 0;
double mean = 0;
@@ -154,7 +222,10 @@ class Dealer {
Dealer(Dealer &&) = delete;
Dealer(const Dealer &&) = delete;

// maybe this first one does not need to be deleted
virtual void shuffle() = 0;
virtual void deal(Player *) = 0;
virtual int dealCard(Hand * = nullptr) = 0;
virtual int process(Player *) = 0;
@@ -188,7 +259,9 @@ class Dealer {
// TODO: most of the games will have a single element, but maybe
// there are games where the dealer has more than one hand
std::list <Hand> hands;
// std::list <Hand> hands;
Hand hand;
};


+ 109
- 33
src/blackjack.cpp Wyświetl plik

@@ -22,11 +22,19 @@

#include <iostream>
#include <utility>
//#include <random>
#include <cstdlib>
#include <ctime>

#include "blackjack.h"

Blackjack::Blackjack() {
std::cout << "I'm your Blackjack dealer!" << std::endl;
// TODO: better RNGs
// https://codeforces.com/blog/entry/61587
srand((int)time(0));

}

Blackjack::~Blackjack() {
@@ -34,6 +42,9 @@ Blackjack::~Blackjack() {
}

void Blackjack::deal(Player *player) {
// let's start by assuming the player does not need to do anything
setInputNeeded(false);
switch(next_action) {
// -------------------------------------------------------------------------
@@ -59,9 +70,9 @@ void Blackjack::deal(Player *player) {
infinite_decks_card_number_for_arranged_ones = 0;
n_hand++;
// clear dealer's hand, create a new one and add it to the list
hands.clear();
hands.push_back(std::move(Hand()));
// clear dealer's hand
hand.holeCardShown = false;
hand.cards.clear();

// erase all the player's, create one, add and make it the current one
player->hands.clear();
@@ -74,11 +85,12 @@ void Blackjack::deal(Player *player) {
player->hasDoubled = 0;
if (lastPass) {
// TODO: send informative messages to the player
// tell people we are shuffling
// bjcall (blackjack.current_player->write (player, "shuffling"));
// shuffle the cards
// shuffle_shoe ();
shuffle();
// TODO: reset card counting systems
// burn as many cards as asked
@@ -95,9 +107,8 @@ void Blackjack::deal(Player *player) {
setNextAction(DealerAction::AskForBets);
}

// bjcall (blackjack.current_player->write (player, "new_hand"));
// TODO: think!
std::cout << "new_hand" << std::endl;
return;
break;
@@ -110,50 +121,77 @@ void Blackjack::deal(Player *player) {
// TODO: setter
player->actionRequired = PlayerActionRequired::Bet;
setInputNeeded(true);
return;
break;

case DealerAction::DealPlayerFirstCard:
// where's step 2?
// where's step 2? <- probably that's the player's bet
// step 3. deal the first card to each player
player->n_hands++; // splits are counted as a single hand
player->total_money_waged += player->currentHand->bet;

Card card;
card.tag = 7;
player->currentHand->cards.push_back(card);
std::cout << "card_player_first " << player->currentHand->cards.begin()->tag << std::endl;
// bjcall (write_formatted_card (player, 0, "card_player_first", card));
playerFirstCard = dealCard(&(*player->currentHand));
std::cout << "card_player_first " << card[playerFirstCard].ascii() << std::endl;
std::cout << "card_player_first " << card[playerFirstCard].text() << std::endl;
std::cout << "card_player_first " << card[playerFirstCard].utf8() << std::endl;
/*
// step 4. show dealer's upcard
card = deal_card_to_hand (blackjack.dealer_hand);
bjcall (write_formatted_card (player, 0, "card_dealer_up", card));
if (stdout_opts.isatty)
{
print_card_art (card);
}
upCard = dealCard(&hand);
std::cout << "card_dealer_up " << card[upCard].text() << std::endl;

// step 5. deal the second card to each player
card = deal_card_to_hand (player->current_hand);
bjcall (write_formatted_card (player, 0, "card_player_second", card));
if (stdout_opts.isatty)
{
print_hand_art (player->current_hand);
}
playerSecondCard = dealCard(&(*player->currentHand));
std::cout << "card_player_second " << card[playerSecondCard].utf8() << std::endl;
// step 6. deal the dealer's hole card
holeCard = dealCard(&hand);
std::cout << "card_dealer_hole" << std::endl;

// TODO: ENHC
blackjack.next_dealer_action = DEAL_DEALERS_HOLE_CARD;
break;
*/
// TODO: print (draw) the hand

// step 7.a. if the upcard is an ace ask for insurance
if (card[upCard].value == 11) {
if (player->no_insurance == false && player->always_insure == false) {
player->actionRequired = PlayerActionRequired::Insurance;
setNextAction(DealerAction::AskForInsurance);
setInputNeeded(true);
return;
} else if (player->always_insure) {
player->currentHand->insured = true;
// TODO: allow insurance for less than one half of the original bet
player->current_result -= 0.5 * player->currentHand->bet;
player->bankroll -= 0.5 * player->currentHand->bet;
player->n_insured_hands++;
player->actionRequired = PlayerActionRequired::None;
setNextAction(DealerAction::CheckforBlackjacks);
setInputNeeded(false);
return;
}
}
// step 7.b. if either the dealer or the player has a chance to have a blackjack, check
if ((card[upCard].value == 10 || card[upCard].value == 11) || player->currentHand->total() == 21) {
player->actionRequired = PlayerActionRequired::None;
setNextAction(DealerAction::CheckforBlackjacks);
setInputNeeded(false);
return;
}

// step 7.c. ask the player to play
player->actionRequired = PlayerActionRequired::Play;
setNextAction(DealerAction::AskForPlay);
setInputNeeded(true);
return;
break;
/*
case DealerAction::DealDealerHoleCard:
break;
case DealerAction::AskForInsurance:
std::cout << "hola" << std::endl;
break;
/*
case DealerAction::CheckforBlackjacks:
break;
case DealerAction::PayOrTakeInsuranceBets:
@@ -261,3 +299,41 @@ int Blackjack::process(Player *player) {
return 0;
}


void Blackjack::shuffle() {
// for infinite decks there is no need to shuffle (how would one do it?)
// we just pick a random card when we need to deal and that's it
if (n_decks == -1) {
return;
}
// TODO: shuffle shoe
return;
}


int Blackjack::dealCard(Hand *hand) {
int dealt_tag = 0;

if (n_decks == -1) {
// TODO: arranged cards
int random_integer = random();
dealt_tag = (random_integer % 32) + (random_integer % 16) + (random_integer % 4);
} else {
dealt_tag = 1;
}
if (hand != nullptr) {
}
return dealt_tag;
}

+ 13
- 5
src/blackjack.h Wyświetl plik

@@ -28,18 +28,26 @@ class Blackjack : public Dealer {
Blackjack();
~Blackjack();
void shuffle() override;
int dealCard(Hand *) override;
void deal(Player *) override;
int process(Player *) override;
private:
bool lastPass = false;
int n_hands = 0;
int n_hand = 0;
unsigned int upCard;
unsigned int holeCard;
unsigned int playerFirstCard;
unsigned int playerSecondCard;
int max_bet = 0;
int number_of_burnt_cards = 0;
int infinite_decks_card_number_for_arranged_ones = 0;
int n_decks = -1;
unsigned long int n_hands = 0;
unsigned long int n_hand = 0;
unsigned int max_bet = 0;
unsigned int number_of_burnt_cards = 0;
unsigned int infinite_decks_card_number_for_arranged_ones = 0;
double insurance = 0;

+ 43
- 0
src/cards.cpp Wyświetl plik

@@ -0,0 +1,43 @@
#include "base.h"

static std::string TJQK[4] = {"T", "J", "Q", "K"};
static std::string numbers[14] = {"", "ace", "deuce", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "jack", "queen", "king"};

Card::Card(unsigned int tag) {
number = 1 + (tag % 13);
suit = static_cast<Suit>(tag/13);
value = (number == 1) ? 11 : ((number > 10) ? 10 : number);
valueASCII = (number < 11) ? std::to_string(number) : TJQK[number-10];
switch (suit){
case Suit::Clubs:
suitName = "clubs";
suitASCII = "C";
suitUTF8 = "♣";
break;
case Suit::Diamonds:
suitName = "diamonds";
suitASCII = "D";
suitUTF8 = "♦";
break;
case Suit::Hearts:
suitName = "hearts";
suitASCII = "H";
suitUTF8 = "♥";
break;
case Suit::Spades:
suitName = "spades";
suitASCII = "S";
suitUTF8 = "♠";
break;
}
};

std::string Card::text() {
return numbers[number] + " of " + suitName;
}

Card card[52] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51};

+ 0
- 1
src/main.cpp Wyświetl plik

@@ -46,7 +46,6 @@ int main(int argc, char **argv) {
dealer->setNextAction(DealerAction::StartNewHand);
while (!dealer->finished()) {
dealer->setInputNeeded(false);
dealer->deal(player);
if (dealer->getInputNeeded()) {
do {

Ładowanie…
Anuluj
Zapisz