浏览代码

fixes & improvements

master
gtheler 5 年前
父节点
当前提交
f19d5c757b
共有 9 个文件被更改,包括 153 次插入153 次删除
  1. +5
    -6
      TODO
  2. +3
    -4
      blackjack.conf
  3. +8
    -3
      src/base.h
  4. +55
    -80
      src/blackjack.cpp
  5. +1
    -0
      src/main.cpp
  6. +1
    -1
      src/stdinout.cpp
  7. +1
    -1
      src/stdinout.h
  8. +78
    -57
      src/tty.cpp
  9. +1
    -1
      src/tty.h

+ 5
- 6
TODO 查看文件

@@ -1,9 +1,10 @@
* version and copyright
* messages implemented on the player's side
* arranged shoes
* handle no readline
* to_string() para floats
* max_splits through conf (default 3)
* DAS
* shoes (and arranged shoes)
* name of the game the dealer deals
* name of the games the player can play
* delays?
* dealers
* ENHC
* blackjack switch
@@ -24,5 +25,3 @@
* multithreading
* use of const and restrict

+ 3
- 4
blackjack.conf 查看文件

@@ -1,5 +1,4 @@
# flat_bet = 1
# max_bet = 2
arranged_cards = 9,8,13,12
delay = 0
; flat_bet = 1
; arranged_cards = 3,8,3,13,4,13,11,7
; delay = 0


+ 8
- 3
src/base.h 查看文件

@@ -92,7 +92,7 @@ enum class Info {
PlayerBlackjack,
PlayerWins,
NoBlackjacks,
PlayerBustsAllHands,
// PlayerBustsAllHands,
DealerBusts,
Help,
Bye,
@@ -106,6 +106,11 @@ enum class Suit {
Spades = 3
};

enum class Color {
Black,
Red
};


class Card {
public:
@@ -146,7 +151,7 @@ extern Card card[53];

class Hand {
public:
std::list<int> cards;
std::list<unsigned int> cards;

// inline on purpose
int total() {
@@ -198,7 +203,7 @@ class Player {
Player(const Player &&) = delete;

virtual int play() = 0;
virtual void info(Info = Info::None, int = 0) = 0;
virtual void info(Info = Info::None, int = 0, int = 0) = 0;
PlayerActionRequired actionRequired = PlayerActionRequired::None;
PlayerActionTaken actionTaken = PlayerActionTaken::None;

+ 55
- 80
src/blackjack.cpp 查看文件

@@ -144,7 +144,7 @@ void Blackjack::deal(Player *player) {

}

player->info(Info::NewHand, player->bankroll);
player->info(Info::NewHand, n_hand, 1e3*player->bankroll);
return;
break;
@@ -172,7 +172,7 @@ void Blackjack::deal(Player *player) {
// step 6. deal the dealer's hole card
holeCard = drawCard(&hand);
player->info(Info::CardDealer, -1);
player->info(Info::CardDealer);

// step 7.a. if the upcard is an ace ask for insurance
if (card[upCard].value == 11) {
@@ -221,7 +221,7 @@ void Blackjack::deal(Player *player) {
player->blackjacksDealer++;

if (player->currentHand->insured) {
player->info(Info::PlayerWinsInsurance, player->currentHand->bet);
player->info(Info::PlayerWinsInsurance, 1e3*player->currentHand->bet);
player->current_result += player->currentHand->bet;
player->bankroll += player->currentHand->bet;
player->winsInsured++;
@@ -229,12 +229,12 @@ void Blackjack::deal(Player *player) {

if (playerBlackack) {
player->info(Info::PlayerBlackjackAlso);
player->info(Info::PlayerPushes);
player->info(Info::PlayerPushes, 1e3*player->currentHand->bet);
player->blackjacksPlayer++;
player->pushes++;
} else {
player->info(Info::PlayerLosses);
player->info(Info::PlayerLosses, 1e3*player->currentHand->bet);
player->current_result -= player->currentHand->bet;
player->bankroll -= player->currentHand->bet;
if (player->bankroll < player->worst_bankroll) {
@@ -252,7 +252,7 @@ void Blackjack::deal(Player *player) {
player->bankroll += blackjack_pays * player->currentHand->bet;
player->blackjacksPlayer++;
player->info(Info::PlayerWins, blackjack_pays * player->currentHand->bet);
player->info(Info::PlayerWins, 1e3 * blackjack_pays*player->currentHand->bet);
player->wins++;
player->winsBlackjack++;

@@ -304,10 +304,7 @@ void Blackjack::deal(Player *player) {
}

if (player->bustedAllHands) {

player->info(Info::PlayerBustsAllHands);
player->info(Info::CardDealerRevealsHole, holeCard);
// TODO: no tengo que sacarle todo el dinero?
player->actionRequired = PlayerActionRequired::None;
nextAction = DealerAction::StartNewHand;
@@ -324,23 +321,53 @@ void Blackjack::deal(Player *player) {
player->info(Info::CardDealerRevealsHole, holeCard);

// hit if count is less than 17 (or equalt to soft 17 if hit_soft_17 is true)
// hit while count is less than 17 (or equal to soft 17 if hit_soft_17 is true)
dealerTotal = hand.total();
while ((std::abs(dealerTotal) < 17 || (hit_soft_17 && dealerTotal == -17)) && hand.busted() == 0) {
unsigned int dealerCard = drawCard(&hand);
player->info(Info::CardDealer, dealerCard);
dealerTotal = hand.total();
}

dealerTotal = std::abs(hand.total());

if (hand.busted()) {
player->info(Info::DealerBusts);
player->bustsDealer++;
for (auto playerHand : player->hands) {
if (playerHand.busted() == false) {
player->info(Info::PlayerWins, playerHand.bet);
if (hand.busted()) {
player->info(Info::DealerBusts, dealerTotal);
player->bustsDealer++;
for (auto playerHand : player->hands) {
if (playerHand.busted() == false) {
player->info(Info::PlayerWins, 1e3*playerHand.bet);
player->current_result += playerHand.bet;
player->bankroll += playerHand.bet;
player->wins++;
player->winsDoubled += playerHand.doubled;
}
}
} else {
for (auto playerHand : player->hands) {
if (playerHand.busted() == false) { // busted hands have already been solved
playerTotal = std::abs(playerHand.total());
if (dealerTotal > playerTotal) {
player->info(Info::PlayerLosses, 1e3*playerHand.bet, playerTotal);
player->bankroll -= playerHand.bet;
if (player->bankroll < player->worst_bankroll) {
player->worst_bankroll = player->bankroll;
}
player->losses++;
} else if (dealerTotal == playerTotal) {
player->info(Info::PlayerPushes, 1e3*playerHand.bet);
player->pushes++;
} else {
player->info(Info::PlayerWins, 1e3*playerHand.bet, playerTotal);
player->current_result += playerHand.bet;
player->bankroll += playerHand.bet;
player->wins++;

if (playerHand.doubled) {
player->winsDoubled++;
} else {
@@ -348,40 +375,6 @@ void Blackjack::deal(Player *player) {
}
}
}
} else {
for (auto playerHand : player->hands) {
if (playerHand.busted() == false) { // busted hands have already been solved
playerTotal = std::abs(playerHand.total());
if (dealerTotal > playerTotal) {
player->info(Info::PlayerLosses, playerHand.bet);
player->bankroll -= playerHand.bet;
if (player->bankroll < player->worst_bankroll) {
player->worst_bankroll = player->bankroll;
}
player->losses++;
} else if (dealerTotal == playerTotal) {
player->info(Info::PlayerPushes, playerHand.bet);
player->pushes++;
} else {
player->info(Info::PlayerWins, playerHand.bet);
player->current_result += playerHand.bet;
player->bankroll += playerHand.bet;
player->wins++;

if (playerHand.doubled) {
player->winsDoubled++;
} else {
player->wins++;
}
}
}
}
}
}
@@ -409,8 +402,6 @@ int Blackjack::process(Player *player) {
switch (player->actionTaken) {

// TODO: maybe we have to call a basic method with common commands?
// we first check common commands
///ig+quit+name quit
///ig+quit+desc Finish the game
@@ -431,19 +422,7 @@ int Blackjack::process(Player *player) {
player->info(Info::Help);
return 0;
break;
case PlayerActionTaken::Count:
std::cout << "count " << (*player->currentHand).total() <<std::endl;
return 0;
break;
case PlayerActionTaken::UpcardValue:
std::cout << "upcard " << card[upCard].utf8() <<std::endl;
return 0;
break;
case PlayerActionTaken::Bankroll:
std::cout << "bankroll " << player->bankroll <<std::endl;
return 0;
break;
case PlayerActionTaken::None:
return 0;
break;
@@ -511,22 +490,19 @@ int Blackjack::process(Player *player) {
///ip+double+detail This command can be abbreviated as `d`.
case PlayerActionTaken::Double:
if (player->currentHand->cards.size() == 2) {
std::cout << "double_down" << std::endl;

// TODO: check bankroll
player->total_money_waged += player->currentHand->bet;
player->total_money_waged += player->currentHand->bet;
player->currentHand->bet *= 2;
player->currentHand->doubled = true;
player->currentHand->doubled = true;
player->handsDoubled++;

playerCard = drawCard(&(*player->currentHand));
unsigned int playerTotal = player->currentHand->total();
std::cout << "card_player" << card[playerCard].utf8() << std::endl;
std::cout << "player_total " << playerTotal << std::endl;
player->info(Info::CardPlayer, playerCard);

if (player->currentHand->busted()) {
std::cout << "player_busted" << std::endl;
player->info(Info::PlayerLosses, 1e3*player->currentHand->bet, playerTotal);
player->current_result -= player->currentHand->bet;
player->bankroll -= player->currentHand->bet;
player->bustsPlayer++;
@@ -555,9 +531,9 @@ int Blackjack::process(Player *player) {
secondCard = *(++player->currentHand->cards.begin());
// up to three splits (i.e. four hands)
// TODO: choose
if (player->currentSplits < 3 && player->currentHand->cards.size() == 2 &&
card[firstCard].value == card[secondCard].value) {
// TODO: choose through conf
// TODO: check bankroll to see if player can split
if (player->currentSplits < 3 && player->currentHand->cards.size() == 2 && card[firstCard].value == card[secondCard].value) {
// mark that we split to put ids in the hands and to limi the number of spltis
player->currentSplits++;

@@ -569,7 +545,6 @@ int Blackjack::process(Player *player) {
// create a new hand
PlayerHand newHand;
newHand.id = player->currentHand->id + 1;
// TODO: check bankroll
newHand.bet = player->currentHand->bet;
player->total_money_waged += player->currentHand->bet;
@@ -629,10 +604,10 @@ int Blackjack::process(Player *player) {
///ip+hit+detail
///ip+hit+detail This command can be abbreviated as `h`.
playerCard = drawCard(&(*player->currentHand));
std::cout << "card_player " << card[playerCard].utf8() << std::endl;
player->info(Info::CardPlayer, playerCard);

if (player->currentHand->busted()) {
std::cout << "busted_player " << player->currentHand->total() << std::endl;
player->info(Info::PlayerLosses, 1e3*player->currentHand->bet);
player->current_result -= player->currentHand->bet;
player->bankroll -= player->currentHand->bet;
player->bustsPlayer++;

+ 1
- 0
src/main.cpp 查看文件

@@ -73,6 +73,7 @@ int main(int argc, char **argv) {
while (!dealer->finished()) {
dealer->deal(player);
if (player->actionRequired != PlayerActionRequired::None) {
unknownCommands = 0;
do {
if (unknownCommands++ > conf.max_incorrect_commands) {
std::cerr << "Too many unknown commands." << std::endl;

+ 1
- 1
src/stdinout.cpp 查看文件

@@ -34,7 +34,7 @@
StdInOut::StdInOut(void) {
}

void StdInOut::info(Info msg, int data) {
void StdInOut::info(Info msg, int p1, int p2) {
return;
}


+ 1
- 1
src/stdinout.h 查看文件

@@ -30,7 +30,7 @@ class StdInOut : public Player {
~StdInOut() { };
int play(void) override;
void info(Info = Info::None, int = 0) override;
void info(Info = Info::None, int = 0, int = 0) override;
private:
std::string input_buffer;

+ 78
- 57
src/tty.cpp 查看文件

@@ -80,20 +80,21 @@ Tty::Tty(Configuration &conf) {
return;
}

void Tty::info(Info msg, int p) {
void Tty::info(Info msg, int p1, int p2) {
std::string s;
bool render = false;
// TODO: choose utf8 or other representation
switch (msg) {

case Info::InvalidBet:
if (p < 0) {
if (p1 < 0) {
// s = "bet_negative";
s = "Your bet is negative (" + std::to_string(p) + ")";
} else if (p > 0) {
s = "Your bet is negative (" + std::to_string(p1) + ")";
} else if (p1 > 0) {
// s = "bet_maximum";
s = "Your bet is larger than the maximum allowed (" + std::to_string(p) + ")";
s = "Your bet is larger than the maximum allowed (" + std::to_string(p1) + ")";
} else {
// s = "bet_zero";
s = "Your bet is zero";
@@ -103,11 +104,12 @@ void Tty::info(Info msg, int p) {
case Info::NewHand:
// s = "new_hand";
std::cout << std::endl;
s = "Starting new hand, bankroll " + std::to_string(p);
s = "Starting new hand #" + std::to_string(p1) + " with bankroll " + std::to_string(1e-3*p2);
dealerHand.cards.clear();
break;
case Info::Shuffle:
// TODO: ask the user to cut
// s = "shuffle";
s = "Deck needs to be shuffled.";
break;
@@ -116,42 +118,41 @@ void Tty::info(Info msg, int p) {
switch (currentHand->cards.size()) {
case 1:
// s = "card_player_first";
s = "Player's first card is " + card[p].utf8();
s = "Player's first card is " + card[p1].utf8();
break;
case 2:
// s = "card_player_second";
s = "Player's second card is " + card[p].utf8();
s = "Player's second card is " + card[p1].utf8();
break;
default:
// s = "card_player";
s = "Player's card is " + card[p].utf8();
s = "Player's card is " + card[p1].utf8();
break;
}
break;
case Info::CardDealer:
if (p != -1) {
if (p1 > 0) {
switch (dealerHand.cards.size()) {
case 0:
// s = "card_dealer_up";
s = "Dealer's up card is " + card[p].utf8();
s = "Dealer's up card is " + card[p1].utf8();
break;
default:
// s = "card_dealer";
s = "Dealer's card is " + card[p].utf8();
s = "Dealer's card is " + card[p1].utf8();
break;
}
} else {
s = "Dealer's hole card is dealt";
}
dealerHand.cards.push_back(p);
dealerHand.cards.push_back(p1);
break;
case Info::CardDealerRevealsHole:
// s = "card_dealer_hole";
s = "Dealer's hole card was " + card[p].utf8();
*(++(dealerHand.cards.begin())) = p;
// renderTable();
s = "Dealer's hole card was " + card[p1].utf8();
*(++(dealerHand.cards.begin())) = p1;
break;
case Info::DealerBlackjack:
@@ -167,42 +168,43 @@ void Tty::info(Info msg, int p) {
case Info::PlayerBlackjackAlso:
// s = "player_blackjack_also";
s = "Player also has Blackjack";
renderTable();
render = true;
break;

case Info::PlayerNextHand:
// s = "player_pushes";
s = "Playing next hand #" + std::to_string(p);
renderTable();
// s = "player_next_hand";
s = "Playing next hand #" + std::to_string(p1);
render = true;
break;
case Info::PlayerPushes:
// s = "player_pushes";
s = "Player pushes";
renderTable();
s = "Player pushes " + std::to_string(1e-3*p1) + ((p2 > 0) ? (" with " + std::to_string(p2)) : "");
render = true;
break;
case Info::PlayerLosses:
// s = "player_losses";
s = "Player losses";
renderTable();
s = "Player losses " + std::to_string(1e-3*p1) + ((p2 > 0) ? (" with " + std::to_string(p2)) : "");
render = true;
break;
case Info::PlayerBlackjack:
// s = "blackjack_player";
s = "Player has Blackjack";
renderTable();
render = true;
break;
case Info::PlayerWins:
// s = "player_wins";
s = "Player wins " + std::to_string(p);
renderTable();
s = "Player wins " + std::to_string(1e-3*p1) + ((p2 > 0) ? (" with " + std::to_string(p2)) : "");
render = true;
break;
case Info::NoBlackjacks:
// s = "no_blackjacks";
s = "No blackjacks";
break;

/*
case Info::PlayerBustsAllHands:
// s = "player_busted_all_hands";
if (hands.size() == 1) {
@@ -212,11 +214,10 @@ void Tty::info(Info msg, int p) {
}
renderTable();
break;
*/
case Info::DealerBusts:
// s = "no_blackjacks";
s = "Dealer busts!";
renderTable();
s = "Dealer busts with " + std::to_string(p1);
break;
case Info::Help:
@@ -238,6 +239,10 @@ void Tty::info(Info msg, int p) {
std::this_thread::sleep_for(std::chrono::milliseconds(delay));
}
std::cout << green << s << reset << std::endl;

if (render) {
renderTable();
}
return;
}
@@ -287,6 +292,7 @@ int Tty::play() {

// TODO: better solution
std::string command = input_buffer;
free(input_buffer);
trim(command);
@@ -309,7 +315,7 @@ int Tty::play() {
switch (actionRequired) {

case PlayerActionRequired::Bet:
currentBet = std::stoi(input_buffer);
currentBet = std::stoi(command);
actionTaken = PlayerActionTaken::Bet;
break;

@@ -344,8 +350,6 @@ int Tty::play() {
}
}
free(input_buffer);
}
#else
@@ -383,63 +387,80 @@ void Tty::renderTable(void) {

void Tty::renderHand(Hand *hand) {

std::string ansiColor;
std::string ansiReset;
for (unsigned int i = 0; i < hand->cards.size(); i++) {
std::cout << " _____ ";
}
std::cout << std::endl;
unsigned int i = 0;
for (auto it : hand->cards) {
if (it >= 0) {
std::cout << "|" << card[it].getNumberASCII() << ((card[it].number != 10)?" ":"") << " | ";
for (auto c : hand->cards) {
if (color && (card[c].suit == Suit::Diamonds || card[c].suit == Suit::Hearts)) {
ansiColor = red;
ansiReset = reset;
} else {
ansiColor = "";
ansiReset = "";
}
if (c > 0) {
std::cout << "|" << ansiColor << card[c].getNumberASCII() << ((card[c].number != 10)?" ":"") << ansiReset << " | ";
} else {
std::cout << "|#####| ";
}
i++;
}
std::cout << std::endl;

i = 0;
for (auto it : hand->cards) {
if (it >= 0) {
for (auto c : hand->cards) {
if (c > 0) {
std::cout << "| | ";
} else {
std::cout << "|#####| ";
}
i++;
}
std::cout << std::endl;
i = 0;
for (auto it : hand->cards) {
if (it >= 0) {
std::cout << "| " << card[it].getSuitUTF8() << " | ";
for (auto c : hand->cards) {
if (color && (card[c].suit == Suit::Diamonds || card[c].suit == Suit::Hearts)) {
ansiColor = red;
ansiReset = reset;
} else {
ansiColor = "";
ansiReset = "";
}
if (c > 0) {
std::cout << "| " << ansiColor << card[c].getSuitUTF8() << ansiReset << " | ";
} else {
std::cout << "|#####| ";
}
i++;
}
std::cout << std::endl;
i = 0;
for (auto it : hand->cards) {
if (it >= 0) {
for (auto c : hand->cards) {
if (c > 0) {
std::cout << "| | ";
} else {
std::cout << "|#####| ";
}
i++;
}
std::cout << std::endl;

i = 0;
for (auto it : hand->cards) {
if (it >= 0) {
std::cout << "|___" << ((card[it].number != 10)?"_":"") << card[it].getNumberASCII() << "| ";
for (auto c : hand->cards) {
if (color && (card[c].suit == Suit::Diamonds || card[c].suit == Suit::Hearts)) {
ansiColor = red;
ansiReset = reset;
} else {
ansiColor = "";
ansiReset = "";
}
if (c > 0) {
std::cout << "|___" << ansiColor << ((card[c].number != 10)?"_":"") << card[c].getNumberASCII() << ansiReset<< "| ";
} else {
std::cout << "|#####| ";
}
i++;
}
std::cout << std::endl;

+ 1
- 1
src/tty.h 查看文件

@@ -37,7 +37,7 @@ class Tty : public Player {
~Tty() { };
int play() override;
void info(Info = Info::None, int = 0) override;
void info(Info = Info::None, int = 0, int = 0) override;

// for readline's autocompletion
static char *rl_command_generator(const char *, int);

正在加载...
取消
保存