Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Customizable Texas Hold 'Em Source Code

38 views
Skip to first unread message

B.H.

unread,
Jul 28, 2022, 5:13:04 PM7/28/22
to

Hi everyone,

For the purpose of job interviewing, I am posting my C++ source code; I am starting to think that the malware that I believe my parents put on my computers can be controlled by the CIA over the internet, since there were a ton of small typo errors in my code at first.

The code is a bit draft-y, more than I had expected. I haven't tested it on any rules input files, but it looks "close enough to correct that a competent coder could fix it within a few hours." I'm not answering replies on this thread, and will link to this thread on Twitter.

I've checked it sort of well, but it's not guaranteed to work perfectly yet; I can only access the online C++ compiler linked to on my Twitter, and I can't contrl typos.

The code follows my signature.

-Philip White (philip...@yahoo.com)

============


// Customizable Texas Hold 'Em Poker
// by Philip White, philip...@yahoo.com

// The rules in this program are read in from a file, and written as poker-related commands with boolean/arithmetic evaluation in "prefix with immediate operation attention reading from the right," where, e.g., ++345 is not legal and must be written as +5+34 instead.
// Taken as a binary tree, these prefix strings must have leaf nodes as precisely the set of non-operation commands, and non-leaf nodes as precisely the set of operation commands. This is required for simplicity in writing this program to interpret the rule strings.

#include <iostream>
#include <vector>
#include <string>
#include <cstdlib>
#include <fstream>

using namespace std;

struct deck;
struct game;
struct player;
struct chip_stack;
struct blinds;
struct bet;
struct card;
struct hand;
struct table_cards;
struct rule;


struct chip_stack
{
int numChips;
};


struct blinds
{
int small;
int big;
};


struct bet
{
int betSize;
};


struct card
{
int ID;
int suit; // clubs(=1), diamonds(=2), hearts(=3), spades(=4)
int rank; // A(=1), 2-10, J(=11), Q(=12), K(=13)
};


struct deck
{
vector <card> allCards;
};


struct hand
{
vector <card> theHand;
};


struct table_cards
{
hand table;
};


struct token
{
char t; // legal tokens: 0 (for binary index), 1 (for binary index), e (=end_step_and_goto_step((step) index)), i (=if), +, -, / (integer division),
// *, > (=greater_than), & (=and), !(=not), | (=or), d(=deal_card_to((player) index)), a (=add_chips((player) index), h (deal card to table),
// s (=subtract_chips((player) index, (int --chip count--) index)), w (=set_winner), f (=finish_game), c (=close_if—open_if is implied),
// # (=separator for pre-fix) , A-U (=data members of game, in the struct, in order shown below) , r (=recreate deck and shuffle) ,
// l (=set small blinds) , g (=set big blinds) , z (=clear hand of currPlayer) .
};

// Order of A-U data members:

// currPlayer:ID, currPlayer:numChips, currPlayer:currBet, currPlayer:currHandCard1suit, currPlayer:currHandCard1rank, currPlayer::currHandCard2suit, currPlayer::currHandCard2rank, smallblind, bigblind, hands_count, whichStep, table_card1suit, table_card1rank,
// table_card2suit, table_card2rank, table_card3suit, table_card3rank, table_card4suit, table_card4rank, table_card5suit, table_card5rank


struct rule
{
string tokens;
};


struct hands_count
{
int num;
};


struct step
{
int ID;
};


struct player
{
int ID; // could be used to determine position in the game
chip_stack C;
bet currBet;
hand currHand;
bool hasWon;
};


struct game
{
deck D;
vector <player> allPlayers;
blinds B;
vector <rule> allRules;
vector <step> allSteps;
hands_count h;
bool isGameOver;
int whoseTurn;
int whichStep;
table_cards t;
};


game InitiateGame();

vector <rule> ReadRulesFromFile(string filename);

game ProcessRules(game g);

string DisplayAndGetUserInput(game g);

deck Shuffle(deck D);

void PlayPoker();

int binstrToInt(string str);

string intToBinstr(int num);

int strToDecInt(string str);

void processRuleSubset(game & g, string subset, string & result);


int main()
{
srand(time(0));
PlayPoker();
return 0;
}


game InitiateGame()
// Precondition: The external file "rules.txt" must contain well-formed rules, in accordance with the language as specified in all comments in this file (preceded by "//"), and as could be inferred from the comment in the definition of the token struct .
// Postcondition: The poker game will have appropriate variables filled into the starting state of the game g, and the game will be ready to be played by users and processed with rules.
{
game g;

card temp;
int counter = 1;
for (int i = 1; i <= 4; i++)
{
for (int j = 1; j <= 13; j++)
{
temp.suit = i;
temp.rank = j;
temp.ID = counter++;
}
g.D.allCards.push_back(temp);
}

g.D = Shuffle(g.D);

player temp2;
counter = 1;
g.allPlayers.resize(0);
for (int k = 1; k <= 9; k++)
{
temp2.ID = counter++;
temp2.C.numChips = 1000;
temp2.currBet.betSize = 0;
temp2.currHand.theHand.resize(0);
temp2.hasWon = false;
g.allPlayers.push_back(temp2);
}

g.B.small = 1;
g.B.big = 2;
g.allRules = ReadRulesFromFile("rules.txt");
g.allSteps.resize(8); // the typical number of steps in a hand of poker

for (int l = 0; l < g.allSteps.size(); l++)
{
g.allSteps[l].ID = l + 1;
}

g.h.num = 0;
g.isGameOver = false;
g.whoseTurn = 1;
g.whichStep = 1;

return g;
}


void PlayPoker()
// Precondition: The user(s) must type in all input commands formatted properly, and comply with the precondition of InitiateGame() and ProcessRules() .
// Postcondition: The poker game will be finished, and the winner of the tournament-style poker game will be displayed to the screen with cout .
{
game g = InitiateGame();
string UserChoice;
do
{
UserChoice = DisplayAndGetUserInput(g);
if (UserChoice == "F")
{
g.whoseTurn++;
if (g.whoseTurn > g.allPlayers.size())
{
g.whoseTurn = 1;
}
}
else if (UserChoice[0] == 'B' && UserChoice[1] == '-')
{
g.allPlayers[g.whoseTurn-1].currBet.betSize = strToDecInt(UserChoice.substr(2,UserChoice.size()-2));
g.whoseTurn++;
if (g.whoseTurn > g.allPlayers.size())
{
g.whoseTurn = 1;
}
}
else
{
cout << "ERROR, bad input";
exit(0);
}
g = ProcessRules(g);
g.h.num++;
} while (g.isGameOver == false);

cout << "\n\nThe winner was: ";
for (int i = 0; i < g.allPlayers.size(); i++)
{
if (g.allPlayers[i].hasWon == true)
{
cout << "Player " << i << endl;
}
}
}


deck Shuffle(deck D)
// Precondition: The deck D must have 52 cards in it, in any order, with all conventional cards (in physical card decks) represented in accordance with the card struct . Each must have a unique ID integer .
// Postcondition: The deck will have been shuffled, re-ordering all of the cards in it at random .
{
deck d2;
d2.allCards.resize(D.allCards.size());
for (int i = 0; i < d2.allCards.size(); i++)
{
d2.allCards[i].ID = -1; // non-card ID, to indicate an empty slot
}

int index = 0;
int oldDeckIndex;
while (D.allCards.size() > 0)
{
oldDeckIndex = rand() % D.allCards.size();
d2.allCards[index] = D.allCards[oldDeckIndex];
for (int j = oldDeckIndex; j < D.allCards.size() - 1; j++)
{
D.allCards[j] = D.allCards[j+1];
}
D.allCards.resize(D.allCards.size()-1);
index++;
}

return d2;
}


string DisplayAndGetUserInput(game g)
// Precondition: The game must be in an appropriate state of poker, as designated by the user's rules in "rules.txt" . All cards must be valid, as one example.
// Postcondition: The game state will be displayed, including the current player's cards, and user inputted will have been collected from the keyboard and returned.
{
cout << "\n\nHands Played: " << g.h.num << endl;
cout << "Blinds: Small=" << g.B.small << " ; Big=" << g.B.big << endl << endl;
cout << "All Players:\n\n";
for (int i = 0; i < g.allPlayers.size(); i++)
{
cout << g.allPlayers[i].ID << ", ";
}
cout << "\n\nThis is Step: " << g.whichStep;
cout << "\n\nTable Cards Currently Include: ";
if (g.t.table.theHand.size() == 0)
{
cout << "(none)";
}
else
{
for (int j = 0; j < g.t.table.theHand.size(); j++)
{
switch (g.allPlayers[g.whoseTurn-1].currHand.theHand[0].rank)
{
case 1:
cout << "Ace of ";
break;
case 11:
cout << "Jack of ";
break;
case 12:
cout << "Queen of ";
break;
case 13:
cout << "King of ";
break;
default:
cout << g.allPlayers[g.whoseTurn-1].currHand.theHand[0].rank << " of ";
}
switch (g.allPlayers[g.whoseTurn-1].currHand.theHand[0].suit)
{
case 1:
cout << "Clubs";
break;
case 2:
cout << "Diamonds";
break;
case 3:
cout << "Hearts";
break;
default:
cout << "Spades";
}
}
}
cout << "\n\nAction is to Player: " << g.whoseTurn;

cout << "Player " << g.whoseTurn << " , your hand is: \n\n";
switch (g.allPlayers[g.whoseTurn-1].currHand.theHand[0].rank)
{
case 1:
cout << "Ace of ";
break;
case 11:
cout << "Jack of ";
break;
case 12:
cout << "Queen of ";
break;
case 13:
cout << "King of ";
break;
default:
cout << g.allPlayers[g.whoseTurn-1].currHand.theHand[0].rank << " of ";
}
switch (g.allPlayers[g.whoseTurn-1].currHand.theHand[0].suit)
{
case 1:
cout << "Clubs";
break;
case 2:
cout << "Diamonds";
break;
case 3:
cout << "Hearts";
break;
default:
cout << "Spades";
}

cout << "\n\nPlayer " << g.whoseTurn << " , please input your choice of what to do (\"B-NUM\" to bet NUM chips total (to include previously bet chips as part of the total), or \"F\" for fold; \"B-[same bet as before]\" checks:\n\n";

string input;
cin >> input;

return input;
}


vector <rule> ReadRulesFromFile(string filename)
// Precondition: The file "rules.txt" must exist and contain whitespace-separated properly formatted rules, which will all be enforced every step of the game, for how the 9 users will play poker.
// Postcondition: none
{
ifstream inFile(filename.c_str());
if (!inFile.is_open())
{
cout << "ERROR, rules.txt not found.";
exit(0);
}
vector <rule> allRules;
rule currRule;
allRules.resize(0);
while (inFile)
{
inFile >> currRule.tokens;
allRules.push_back(currRule);
}
return allRules;
}


void processRuleSubset(game & g, string subset, string & result)
// Precondition: All rules must be properly formatted, in accordance with all comments in this file (preceded by //). InitiateGame must have been called.
// Postcondition: none
{
string storedVar1;
string storedVar2;
int tempVar;
bool flag;
card temp;
int counter;
string temp2 = "";
bool skip;
vector <char> stack;
stack.resize(0);
for (int j = 0; j < subset.size(); j++)
{
switch( subset[j] )
{
// We use prefix notation here.

case '&':
case '|':
case '!':
case '+':
case '-':
case '*':
case '/':
case '>':
case 'a':
case 'd':
case 'w':
case 'f':
case 's':
case 'e':
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
case 'H':
case 'I':
case 'J':
case 'K':
case 'L':
case 'M':
case 'N':
case 'O':
case 'P':
case 'Q':
case 'R':
case 'S':
case 'T':
case 'U':
case 'l':
case 'g':
case 'z':
case '#':
case '0':
case '1':
case 'i':
stack.push_back( subset[j] );
break;


// When popping, go backwards and find the root of the statement: boolean condition of if statement , formed arithmetic index in poker command.
// Store a value corresponding to what has been popped off the stack.
// Every boolean expression based on numerical comparisons will resolve to true or false in the expression and can be stored as such.

// Also, every rule must end with a 'c' character.

case 'c': // 'c' closes out both if statement conditions and if statement commands that would be within curly brackets in C++; each 'i' is followed by two 'c's, eventually
// First, run a routine to see if this is part of an if statement that evaluates to false; if so, don't proceed, and skip to the beginning of that if statement.
for (int m = j-1; m >= 0; m = m - 1)
{
if (subset[m] == 'c')
{
for (int n = m-1; n >= 0; n = n - 1)
{
if (subset[n] == 'i')
{
processRuleSubset(g,subset.substr(n+1,m-1 - (n+1) + 1),temp2);
if (temp2 != "T")
{
skip = true;
}
else
{
skip = false;
}
break;
}
}
break;
}
}

if (skip == true)
{
while (stack[stack.size()-1] != 'c')
{
stack.pop_back();
}
while (stack[stack.size()-1] != 'i')
{
stack.pop_back();
}
stack.pop_back();
break;
}


storedVar1 = storedVar2 = "";
do
{
flag = false;
tempVar = stack[stack.size()-1];
stack.pop_back();
switch(tempVar)
{
case '&':
if (storedVar1 == "T" && storedVar2 == "T")
{
storedVar1 = "T";
storedVar2 = "";
}
else
{
storedVar1 = "F";
storedVar2 = "";
}
break;
case '|':
if (storedVar1 == "T" || storedVar2 == "T")
{
storedVar1 = "T";
storedVar2 = "";
}
else
{
storedVar1 = "F";
storedVar2 = "";
}
break;
case '!':
if (storedVar1 == "T")
{
storedVar1 = "F";
}
else
{
storedVar1 = "T";
}
break;

case '>':
if (binstrToInt(storedVar1) > binstrToInt(storedVar2))
{
storedVar1 = "T";
storedVar2 = "";
}
else
{
storedVar1 = "F";
storedVar2 = "";
}
break;

case '+':
storedVar1 = intToBinstr(binstrToInt(storedVar1) + binstrToInt(storedVar2));
storedVar2 = "";
break;

case '-':
storedVar1 = intToBinstr(binstrToInt(storedVar1) - binstrToInt(storedVar2));
storedVar2 = "";
break;

case '*':
storedVar1 = intToBinstr(binstrToInt(storedVar1) * binstrToInt(storedVar2));
storedVar2 = "";
break;

case '/':
storedVar1 = intToBinstr(binstrToInt(storedVar1) / binstrToInt(storedVar2));
storedVar2 = "";
break;


case 'A':
if (storedVar1 == "")
{
storedVar1 = g.whoseTurn;
}
else
{
storedVar2 = g.whoseTurn;
}
break;
case 'B':
if (storedVar1 == "")
{
storedVar1 = g.allPlayers[g.whoseTurn-1].C.numChips; // if InitiateGame was called properly, the player ID is equal to the index + 1
}
else
{
storedVar2 = g.allPlayers[g.whoseTurn-1].C.numChips;
}
break;
case 'C':
if (storedVar1 == "")
{
storedVar1 = g.allPlayers[g.whoseTurn-1].currBet.betSize;
}
else
{
storedVar2 = g.allPlayers[g.whoseTurn-1].currBet.betSize;
}
break;
case 'D':
if (storedVar1 == "")
{
storedVar1 = g.allPlayers[g.whoseTurn-1].currHand.theHand[0].suit;
}
else
{
storedVar2 = g.allPlayers[g.whoseTurn-1].currHand.theHand[0].suit;
}
break;
case 'E':
if (storedVar1 == "")
{
storedVar1 = g.allPlayers[g.whoseTurn-1].currHand.theHand[0].rank;
}
else
{
storedVar2 = g.allPlayers[g.whoseTurn-1].currHand.theHand[0].rank;
}
break;
case 'F':
if (storedVar1 == "")
{
storedVar1 = g.allPlayers[g.whoseTurn-1].currHand.theHand[1].suit;
}
else
{
storedVar2 = g.allPlayers[g.whoseTurn-1].currHand.theHand[1].suit;
}
break;
case 'G':
if (storedVar1 == "")
{
storedVar1 = g.allPlayers[g.whoseTurn-1].currHand.theHand[1].rank;
}
else
{
storedVar2 = g.allPlayers[g.whoseTurn-1].currHand.theHand[1].rank;
}
break;
case 'H':
if (storedVar1 == "")
{
storedVar1 = g.B.small;
}
else
{
storedVar2 = g.B.small;
}
break;
case 'I':
if (storedVar1 == "")
{
storedVar1 = g.B.big;
}
else
{
storedVar2 = g.B.big;
}
break;
case 'J':
if (storedVar1 == "")
{
storedVar1 = g.h.num;
}
else
{
storedVar2 = g.h.num;
}
break;
case 'K':
if (storedVar1 == "")
{
storedVar1 = g.whichStep;
}
else
{
storedVar2 = g.whichStep;
}
break;
case 'L':
if (storedVar1 == "")
{
storedVar1 = g.t.table.theHand[0].suit;
}
else
{
storedVar2 = g.t.table.theHand[0].suit;
}
break;
case 'M':
if (storedVar1 == "")
{
storedVar1 = g.t.table.theHand[0].rank;
}
else
{
storedVar2 = g.t.table.theHand[0].rank;
}
break;
case 'N':
if (storedVar1 == "")
{
storedVar1 = g.t.table.theHand[1].suit;
}
else
{
storedVar2 = g.t.table.theHand[1].suit;
}
break;
case 'O':
if (storedVar1 == "")
{
storedVar1 = g.t.table.theHand[1].rank;
}
else
{
storedVar2 = g.t.table.theHand[1].rank;
}
break;
case 'P':
if (storedVar1 == "")
{
storedVar1 = g.t.table.theHand[2].suit;
}
else
{
storedVar2 = g.t.table.theHand[2].suit;
}
break;
case 'Q':
if (storedVar1 == "")
{
storedVar1 = g.t.table.theHand[2].rank;
}
else
{
storedVar2 = g.t.table.theHand[2].rank;
}
break;
case 'R':
if (storedVar1 == "")
{
storedVar1 = g.t.table.theHand[3].suit;
}
else
{
storedVar2 = g.t.table.theHand[3].suit;
}
break;
case 'S':
if (storedVar1 == "")
{
storedVar1 = g.t.table.theHand[3].rank;
}
else
{
storedVar2 = g.t.table.theHand[3].rank;
}
break;
case 'T':
if (storedVar1 == "")
{
storedVar1 = g.t.table.theHand[4].suit;
}
else
{
storedVar2 = g.t.table.theHand[4].suit;
}
break;
case 'U':
if (storedVar1 == "")
{
storedVar1 = g.t.table.theHand[4].rank;
}
else
{
storedVar2 = g.t.table.theHand[4].suit;
}
break;
case 'a':
for (int k = 0; k < g.allPlayers.size(); k++)
{
if (g.allPlayers[k].ID == binstrToInt(storedVar1))
{
g.allPlayers[k].C.numChips += binstrToInt(storedVar2);
}
}
break;

case 'h':
g.t.table.theHand.push_back(g.D.allCards[g.D.allCards.size()-1]);
g.D.allCards.pop_back();
break;

case 'z':
g.allPlayers[g.whoseTurn-1].currHand.theHand.resize(0);
break;

case 'd':
for (int k = 0; k < g.allPlayers.size(); k++)
{
if (g.allPlayers[k].ID == binstrToInt(storedVar1))
{
g.allPlayers[k].currHand.theHand.push_back(g.D.allCards[g.D.allCards.size()-1]);
g.D.allCards.pop_back();
}
}
break;

case 'w':
for (int k = 0; k < g.allPlayers.size(); k++)
{
if (g.allPlayers[k].ID == binstrToInt(storedVar1))
{
g.allPlayers[k].hasWon = true;
}
}
break;

case 'f':
g.isGameOver = true;
break;

case 's':
for (int k = 0; k < g.allPlayers.size(); k++)
{
if (g.allPlayers[k].ID == binstrToInt(storedVar1))
{
g.allPlayers[k].C.numChips -= binstrToInt(storedVar2);
}
}

case 'e':
g.whichStep = binstrToInt(storedVar1);
break;

case 'l':
g.B.small = binstrToInt(storedVar1);
break;

case 'g':
g.B.big = binstrToInt(storedVar1);
break;

case 'c':
flag = true;
break;

case 'r':
counter = 1;
for (int i = 1; i <= 4; i++)
{
for (int j = 1; j <= 13; j++)
{
temp.suit = i;
temp.rank = j;
temp.ID = counter++;
}
g.D.allCards.push_back(temp);
}
g.D = Shuffle(g.D);

break;

case '#':
// Move stored var 1 to stored var 2 and clear out stored var 1.
storedVar2 = storedVar1;
storedVar1 = "";
break;

case 'i':
flag = true;
break;

case '0':
storedVar1 += "0";
break;
case '1':
storedVar1 += "1";
break;
default:
cout << "ERROR, unhandled token case.";
exit(0);
}
} while (flag == false);
storedVar1 = storedVar2 = "";
break;

default:
cout << "ERROR, unhandled token character in rule string.\n\n";
exit(0);
}
}
result = storedVar1;
}







game ProcessRules(game g)
// Precondition: All rules must be properly formatted, in accordance with all comments in this file (preceded by //). InitiateGame must have been called.
// Postcondition: none
{
string temp;
for (int i = 0; i < g.allRules.size(); i++)
{
processRuleSubset(g,g.allRules[i].tokens,temp);
}
return g;
}


int binstrToInt(string str)
// Precondition: str is a binary string < 32768 and >= 0 .
// Postcondition: none
{
int num = 0;
do
{
num *= 2;
num += str[str.size()-1] - '0';
str.pop_back();
} while (str != "");
return num;
}


string intToBinstr(int num)
// Precondition: num is a positive integer < 32768 .
// Postcondition: none
{
string str = "";
do
{
str.push_back(num % 2 + '0');
num = num / 2;
} while (num != 0);
if (str == "")
{
str = "0";
}
return str;
}


int strToDecInt(string str)
// Precondition: str is a decimal string < 32768 and >= 0 .
// Postcondition: none
{
int num = 0;
do
{
num *= 10;
num += str[str.size()-1] - '0';
str.pop_back();
} while (str != "");
return num;
}
0 new messages