From 6e80036ba79bc53718e6e333bf2e8e0dc475035b Mon Sep 17 00:00:00 2001 From: BigGamerGary Date: Mon, 12 Jun 2023 12:32:36 +1000 Subject: [PATCH] Blackjack is a state machine --- Acronymbot.py | 2 +- BlackJack.py | 193 ++++++++++++++++---------- __pycache__/BlackJack.cpython-310.pyc | Bin 5540 -> 6091 bytes ledger.db | Bin 8192 -> 8192 bytes 4 files changed, 119 insertions(+), 76 deletions(-) diff --git a/Acronymbot.py b/Acronymbot.py index 01d7c0a..26e9fa5 100644 --- a/Acronymbot.py +++ b/Acronymbot.py @@ -85,7 +85,7 @@ async def bj(interaction: discord.Interaction): discinput = lambda m: discordInput(interaction, m) discoutput = lambda m: discordOutput(interaction, m) await interaction.response.send_message("Let's play Black Jack!") - await blackJack.play_game(interaction.user.id, interaction.message, discinput, discoutput) + await blackJack.play_game(interaction.user.id, 100, discinput, discoutput) async def discordInput(interaction: discord.Interaction, message:str): response = HitOrStand() diff --git a/BlackJack.py b/BlackJack.py index 702230b..24f1f5e 100644 --- a/BlackJack.py +++ b/BlackJack.py @@ -1,6 +1,16 @@ import random import Ledger +# Game States +INIT = 0 +PLAYING = 1 +ENDING = 2 +FINISHED = 3 +OVER = 5 +CHECKING = 6 + + + def convertNumberToCard(cardNumber): # Cards index from 0 i.e ace is 0, and the highest card value is 51 if cardNumber <= 12: @@ -49,13 +59,21 @@ def handNumbersToCards(hand): def getHandTotal(hand): cardValue = lambda c: min(c % 13 + 1, 10) i = 0 + aces = 0 for card in hand: card = cardValue(card) - if (card == 1) and (i < 20): + if card == 1: + aces += 1 + else: + i += card + + while aces > 0: + if i < 20: card = 11 if (i + card) > 21: card = 1 i += card + aces -= 1 return i def showDeck(deck): @@ -66,6 +84,7 @@ def showDeck(deck): class BlackJack: def __init__(self): + self.gameState = INIT self.playerTurn = True self.deck = generateDeck() random.shuffle(self.deck) @@ -118,11 +137,12 @@ class BlackJack: else: return "c" - def dealerHitLogic(self, hand): - total = getHandTotal() + def dealerHitLogic(self): + total = getHandTotal(self.dealerHand) if total > 17: self.stand() - elif total <= 16: + return True + else: self.hit() @@ -133,78 +153,101 @@ class BlackJack: elif state == "l": gameOver = True return gameOver + + def compareHands(self): + dealerTotal = getHandTotal(self.dealerHand) + playerTotal = getHandTotal(self.playerHand) + if dealerTotal < playerTotal: + return "l" + else: + return "w" async def play_game(self, ID, bet, recv, send): - gameOver = False - playerStats = self.ledger.read(ID) - if playerStats is None: - self.ledger.write(ID) - playerStats = self.ledger.read(ID) - - self.deal() - while not gameOver: - play = None - playerStood = False - validInput = False - - playerWinState = self.checkHandState(self.playerHand) - dealerWinState = self.checkHandState(self.dealerHand) - gameOver = self.checkGameOver(playerWinState) or self.checkGameOver(dealerWinState) - if gameOver: - continue - - await send("Players hand = " + str(getHandTotal(self.playerHand)) + ": " + handNumbersToCards( - self.playerHand) + "\n" + "Dealers hand = ??: " + convertNumberToCard(self.dealerHand[0]) + "??") - play = await recv("Hit or Stand? (h/s)") - while not validInput: - if play == "h": - self.hit() - validInput = True - elif play == "s": - self.stand() - validInput = True - playerStood = True - - playerWinState = self.checkHandState(self.playerHand) - if self.checkGameOver(playerWinState): - continue - - # Dealers turn - if playerStood: - while dealerWinState == 'c': - # Dealer hits - self.hit() - # Player stands - self.stand() - # Loop ends when game is over - dealerWinState = self.checkHandState(self.dealerHand) - else: - self.hit() - dealerWinState = self.checkHandState(self.dealerHand) - - if self.checkGameOver(dealerWinState): - continue - await send("Players hand = " + str(getHandTotal(self.playerHand)) + ": " + handNumbersToCards(self.playerHand) + - "\n" + "Dealers hand = " + str(getHandTotal(self.dealerHand)) + ": " + handNumbersToCards(self.dealerHand)) - if playerWinState == "w": - await send("You won!") - win = (2*bet, 1, 0, ID) - self.ledger.update(ID, win) - elif playerWinState == "l": - await send("You busted!") - loss = (-bet, 0, 1, ID) - self.ledger.update(ID, loss) - elif dealerWinState == "w": - await send("The Dealer reached 21 before you!") - loss = (-bet, 0, 1, ID) - self.ledger.update(ID, loss) - elif dealerWinState == "l": - await send("The Dealer busted before you!") - win = (2*bet, 1, 0, ID) - self.ledger.update(ID, win) + while self.gameState != OVER: - self.returnCards() - if len(self.deck) < 0.25 * 52: - await send("Shuffling Deck") - self.shuffle() + if self.gameState == INIT: + + gameOver = False + playerStats = self.ledger.read(ID) + if playerStats is None: + self.ledger.write(ID) + playerStats = self.ledger.read(ID) + self.deal() + + play = None + playerStood = False + dealerStood = False + validInput = False + self.gameState = PLAYING + + elif self.gameState == PLAYING: + + await send("Players hand = " + str(getHandTotal(self.playerHand)) + ": " + handNumbersToCards( + self.playerHand) + "\n" + "Dealers hand = ??: " + convertNumberToCard(self.dealerHand[0]) + "??") + play = await recv("Hit or Stand? (h/s)") + while not validInput: + if play == "h": + self.hit() + validInput = True + elif play == "s": + self.stand() + playerStood = True + validInput = True + + self.dealerHitLogic() + playerWinState = self.checkHandState(self.playerHand) + dealerWinState = self.checkHandState(self.dealerHand) + self.gameState = CHECKING + + elif self.gameState == ENDING: + + # Players turn + self.stand() + # Dealers turn + dealerStood = self.dealerHitLogic() + # Loop ends when game is over + dealerWinState = self.checkHandState(self.dealerHand) + if dealerStood: + + if dealerWinState == "c": + + dealerWinState = self.compareHands() + self.gameState = CHECKING + + elif self.gameState == CHECKING: + + if self.checkGameOver(playerWinState) or self.checkGameOver(dealerWinState): + self.gameState = FINISHED + elif playerStood: + self.gameState = ENDING + else: + self.gameState = PLAYING + + elif self.gameState == FINISHED: + + await send("Players hand = " + str(getHandTotal(self.playerHand)) + ": " + handNumbersToCards(self.playerHand) + + "\n" + "Dealers hand = " + str(getHandTotal(self.dealerHand)) + ": " + handNumbersToCards(self.dealerHand)) + if playerWinState == "w": + await send("You won!") + win = (2*bet, 1, 0, ID) + self.ledger.update(ID, win) + elif playerWinState == "l": + await send("You busted!") + loss = (-bet, 0, 1, ID) + self.ledger.update(ID, loss) + elif dealerWinState == "w": + await send("The Dealer reached 21 before you!") + loss = (-bet, 0, 1, ID) + self.ledger.update(ID, loss) + elif dealerWinState == "l": + await send("The Dealer busted before you!") + win = (2*bet, 1, 0, ID) + self.ledger.update(ID, win) + + self.returnCards() + if len(self.deck) < 0.25 * 52: + await send("Shuffling Deck") + self.shuffle() + + self.gameState = OVER diff --git a/__pycache__/BlackJack.cpython-310.pyc b/__pycache__/BlackJack.cpython-310.pyc index 557540f4f64098ae811d7cd723ca135285619978..ff9eb03386b80046d84cec81b0e3ab02785eb798 100644 GIT binary patch literal 6091 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 YJjXXm_M{~NruT$r`8G&!y+YajA7<-exBvhE diff --git a/ledger.db b/ledger.db index f820787f2e5864524e36652ea47849c9f3a094ae..7fac1818f3161de2cd189fb12ddc7d8ffbefc628 100644 GIT binary patch delta 87 zcmZp0XmFSy%_uif#+gxWW5PmyZUzPhCjJ`?{5SaDY!(#Q%|9`K!%%^ZiIanId;DY} lMm7dECPqdOJF0NO n