296 lines
8.0 KiB
Python
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()
|
|
|
|
|