Files
Acrybot/BlackJack.py
2023-07-19 14:13:53 +10:00

296 lines
8.0 KiB
Python

import random
from Ledger import Ledger
# Game States
INIT = 0
PLAYERTURN = 1
DEALERTURN = 2
FINISHED = 3
OVER = 5
"""
Class which describes playing cards
"""
class Card():
"""
A joker card has value 0 and suit 0
"""
HEARTS = 1
DIAMONDS = 2
SPADES = 3
CLUBS = 4
def __init__(self, value, suit) -> None:
self.value = value
self.suit = suit
self.hidden = False
def turn_card(self):
# XOR to flip hidden element
self.hidden = self.hidden != True
def get_value(self):
return self.value
def get_suit(self):
return self.suit
def __str__(self) -> str:
suits = ["J", "", "", "", ""]
special_cards = {1: "A", 11: "J", 12: "Q", 13: "K"}
strValue = ""
if self.value in special_cards.keys():
strValue = special_cards[self.value]
else:
strValue = str(self.value)
string = ""
string = f"{suits[self.suit]}{strValue}"
if self.hidden:
string = "??"
return string
def __repr__(self) -> str:
return str(self)
"""
Class for interacting with a deck of cards
"""
class Deck():
def __init__(self, joker = False) -> None:
self.deck = []
self.discard = []
self.joker = joker
self.deck.extend([Card(x, Card.HEARTS) for x in range(1, 13)])
self.deck.extend([Card(x, Card.DIAMONDS) for x in range(1, 13)])
self.deck.extend([Card(x, Card.SPADES) for x in range(1, 13)])
self.deck.extend([Card(x, Card.CLUBS) for x in range(1, 13)])
if joker:
self.deck.append(Card(0, 0))
def shuffle(self):
random.shuffle(self.deck)
def sort(self):
self.deck.sort()
def take_from_deck(self):
card = self.deck.pop()
return card
def return_to_deck_top(self, card):
self.deck.insert(0, card)
def returnToDeckBottom(self, card):
self.deck.append(card)
def addToDiscard(self, card):
self.discard.insert(0, card)
def returnFromDiscard(self):
self.returnToDeckTop(self.discard.pop())
def return_all_from_discard(self):
self.deck.extend(self.discard)
self.discard = []
def __str__(self) -> str:
string = ""
for card in self.deck:
string += str(card)
return string
def __len__(self):
return len(self.deck)
class Hand():
def __init__(self) -> None:
self.hand = []
def sortHand(self):
self.hand.sort()
def add_to_hand(self, card):
self.hand.append(card)
def remove_from_hand(self, index):
return self.hand.pop(index)
def hide_card(self, index):
card = self.remove_from_hand(index)
card.turn_card()
self.add_to_hand(card)
def __len__(self):
return len(self.hand)
def __str__(self) -> str:
string = ""
for card in self.hand:
string += str(card)
string += " "
return string
def __repr__(self) -> str:
value = 0
aces = 0
# Add static values
for card in self.hand:
if card.value == 1:
aces += 1
continue
if card.value > 10:
card.value = 10
value += card.value
# Dynamically add ace value based on ideal rules
card = 11
for _ in range(aces):
if value <= 10:
card = 11
if value > 10:
card = 1
value += card
return str(value)
def __iter__(self):
self.iter = iter(self.hand)
return self.iter
def __next__(self):
return next(self.iter)
class BlackJack:
def __init__(self) -> None:
self.deck = Deck()
self.playerHand = Hand()
self.dealerHand = Hand()
self.ledger = Ledger()
def deal_card(self, hand):
hand.add_to_hand(self.deck.take_from_deck())
def game_setup(self):
# Deal cards in alternate order
self.deck.shuffle()
for _ in range(2):
self.deal_card(self.playerHand)
self.deal_card(self.dealerHand)
# Hide one of the dealers cards
self.dealerHand.hide_card(1)
def discard_hand(self, hand):
for _ in range(len(hand)):
card = hand.remove_from_hand(0)
self.deck.addToDiscard(card)
async def show_cards(self, send, displayDealerScore=False):
# Show Cards to player
string = f"Player Hand = {repr(self.playerHand)}: {self.playerHand}\nDealer Hand = ??: {self.dealerHand}"
if displayDealerScore:
string = f"Player Hand = {repr(self.playerHand)}: {self.playerHand}\nDealer Hand = {repr(self.dealerHand)}: {self.dealerHand}"
await send(string)
async def play_game(self, recv, send):
gameState = INIT
while gameState != OVER:
if gameState == INIT:
# TODO: Load player statistics
self.game_setup()
gameState = PLAYERTURN
if gameState == PLAYERTURN:
await self.show_cards(send)
playerHit = await recv("Hit or Stand?")
if playerHit:
self.deal_card(self.playerHand)
else:
self.dealerHand.hide_card(1)
gameState = DEALERTURN
if int(repr(self.playerHand)) >= 21:
self.dealerHand.hide_card(1)
gameState = FINISHED
if gameState == DEALERTURN:
self.deal_card(self.dealerHand)
if int(repr(self.dealerHand)) >= 17:
gameState = FINISHED
if gameState == FINISHED:
playerBlackJack = False
dealerBlackJack = False
playerBust = False
dealerBust = False
playerHigher = False
dealerHigher = False
tie = False
playerScore = int(repr(self.playerHand))
dealerScore = int(repr(self.dealerHand))
await self.show_cards(send, True)
if playerScore == 21:
playerBlackJack = True
if dealerScore == 21:
dealerBlackJack = True
if playerScore > 21:
playerBust = True
if dealerScore > 21:
dealerBust = True
if dealerScore > playerScore:
dealerHigher = True
elif playerScore > dealerScore:
playerHigher = True
else:
tie = True
self.discard_hand(self.playerHand)
self.discard_hand(self.dealerHand)
if tie:
await send("You tied")
elif playerBlackJack:
await send("You reached BlackJack!")
elif dealerBlackJack:
await send("The dealer reached BlackJack!")
elif playerBust:
await send("You busted!")
elif dealerBust:
await send("The dealer busted!")
elif playerHigher:
await send("You won!")
elif dealerHigher:
await send("You lost!")
else:
await send("Report this game to my creator!")
if len(self.deck) < 0.25 * 51:
self.deck.return_all_from_discard()
self.deck.shuffle()
await send("Everyday I'm shuffling")
gameState = OVER
def main():
game = BlackJack()
trueFalseInput = lambda x: input(x) == "h"
game.play_game(recv=trueFalseInput, send=print)
if __name__ == "__main__":
main()