261 lines
6.9 KiB
Python
261 lines
6.9 KiB
Python
from common.inputChecking.boolInput import boolInput
|
|
|
|
from os import get_terminal_size, system
|
|
from math import ceil
|
|
import random
|
|
|
|
class Card:
|
|
def __init__(self, cardId, color):
|
|
"""
|
|
cardId goes from 1 to 1 where 1 is A and 13 is K
|
|
"""
|
|
|
|
self.id = cardId
|
|
self.color = color
|
|
|
|
cardNums = ['A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K']
|
|
cardSyms = {
|
|
'spade': '♠',
|
|
'heart': '♥',
|
|
'diamond': '♦',
|
|
'club': '♣'
|
|
}
|
|
|
|
self.num = cardNums[cardId-1]
|
|
self.sym = cardSyms[color]
|
|
|
|
WIDTH = 11
|
|
|
|
def __str__(self):
|
|
return f"""┌─────────┐
|
|
│{self.num}{' ' if self.id != 10 else ''} │
|
|
│ │
|
|
│ │
|
|
│ {self.sym} │
|
|
│ │
|
|
│ │
|
|
│ {' ' if self.id != 10 else ''}{self.num}│
|
|
└─────────┘"""
|
|
|
|
def value(self, aceValue):
|
|
cardValues = {
|
|
'A': aceValue,
|
|
'2': 2,
|
|
'3': 3,
|
|
'4': 4,
|
|
'5': 5,
|
|
'6': 6,
|
|
'7': 7,
|
|
'8': 8,
|
|
'9': 9,
|
|
'10': 10,
|
|
'J': 10,
|
|
'Q': 10,
|
|
'K': 10
|
|
}
|
|
return cardValues[self.num]
|
|
|
|
class CardHandler:
|
|
def __init__(self, cards, printSep=5, aceValue = 1):
|
|
self.cards = cards
|
|
self.printSeparator = printSep
|
|
self.aceValue = aceValue
|
|
|
|
def addCard(self, card):
|
|
self.cards.append(card)
|
|
|
|
def generateNewCard(self):
|
|
cardTypes = range(1,14)
|
|
cardColors = ['spade', 'heart', 'diamond', 'club']
|
|
self.addCard(Card(random.choice(cardTypes), random.choice(cardColors)))
|
|
|
|
def _concatenateCards(self, cards):
|
|
"""
|
|
Concatenate several card objects into an list of sublists
|
|
where each sublist contains the strings for the cards to be
|
|
printed for a specific horizontal line.
|
|
"""
|
|
|
|
cardStringLists = [(str(card)).split('\n') for card in cards]
|
|
cardHeight = len(cardStringLists[0])
|
|
linesToPrint = [[] for line in range(cardHeight)]
|
|
|
|
for cardStringList in cardStringLists:
|
|
[linesToPrint[line].append(cardStringList[line]) for line in range(cardHeight)]
|
|
return linesToPrint
|
|
|
|
|
|
def printCards(self, cardsPerLine):
|
|
"""
|
|
Print <cardsPerLine> cards per line, horizontally aligned
|
|
"""
|
|
|
|
splitCards =[[] for _ in range(ceil(len(self.cards)/cardsPerLine))]
|
|
|
|
for i, card in enumerate(self.cards):
|
|
splitCards[i // cardsPerLine].append(card)
|
|
|
|
SplitCardStrings = [self._concatenateCards(cardList) for cardList in splitCards]
|
|
printCardList = lambda cardList: print('\n'.join([ (' ' * self.printSeparator).join(line) for line in cardList ]))
|
|
[ printCardList(SplitCardString) for SplitCardString in SplitCardStrings ]
|
|
|
|
|
|
def safePrintCards(self):
|
|
"""
|
|
Print the amount of cards that there is room for depending on the terminal width
|
|
"""
|
|
cardWidth = Card.WIDTH
|
|
extendedCardWidth = (cardWidth + self.printSeparator)
|
|
terminalWidth = get_terminal_size().columns
|
|
|
|
isRoomForExtraCard = terminalWidth % extendedCardWidth >= cardWidth
|
|
cardsPerLine = terminalWidth // extendedCardWidth + (1 if isRoomForExtraCard else 0)
|
|
|
|
self.printCards(cardsPerLine)
|
|
|
|
|
|
@property
|
|
def cardSum(self):
|
|
|
|
return sum([card.value(aceValue=self.aceValue) for card in self.cards])
|
|
|
|
@property
|
|
def containsAce(self):
|
|
return any([True for card in self.cards if card.id == 1])
|
|
|
|
@property
|
|
def containsBlackJack(self):
|
|
return any([True for card in self.cards if card.num == 'A']) \
|
|
and any([True for card in self.cards if card.value(self.aceValue) == 10])
|
|
|
|
|
|
def emptyCard():
|
|
result = Card(1,'spade')
|
|
result.num = '?'
|
|
result.sym = '?'
|
|
return result
|
|
|
|
|
|
class Blackjack:
|
|
def __init__(self):
|
|
self.handler = CardHandler([])
|
|
self.emptyHandler = CardHandler([emptyCard(), emptyCard()])
|
|
self.dealerHandler = CardHandler([])
|
|
self.gameResults = [0,0]
|
|
self.reset()
|
|
|
|
def generateNewCards(self):
|
|
self.dealerHandler.cards = []
|
|
self.handler.cards = []
|
|
for _ in range(2):
|
|
self.dealerHandler.generateNewCard()
|
|
self.handler.generateNewCard()
|
|
self.emptyHandler.cards[0] = self.dealerHandler.cards[0]
|
|
|
|
def determineAceValue(self):
|
|
if self.handler.cardSum < 11 and self.handler.containsAce: # 11 + 1 = 12, 11 + 11 = 22
|
|
self.handler.aceValue = self.dealerHandler.aceValue = 11
|
|
else:
|
|
self.handler.aceValue = self.dealerHandler.aceValue = 1
|
|
|
|
def reset(self):
|
|
self.generateNewCards()
|
|
self.determineAceValue()
|
|
|
|
def youWin(self):
|
|
self.gameResults[0] += 1
|
|
print("""
|
|
__ __
|
|
/\ \ /\ \ __
|
|
\ `\`\\\\/'/ ___ __ __ __ __ __/\_\ ___
|
|
`\ `\ /' / __`\/\ \/\ \ /\ \/\ \/\ \/\ \ /' _ `\
|
|
`\ \ \/\ \L\ \ \ \_\ \\ \\ \ \_/ \_/ \ \ \/\ \/\ \
|
|
\ \_\ \____/\ \____/ \ \___x___/'\ \_\ \_\ \_\\
|
|
\/_/\/___/ \/___/ \/__//__/ \/_/\/_/\/_/
|
|
""")
|
|
|
|
def youLose(self):
|
|
self.gameResults[1] += 1
|
|
print("""
|
|
__ __ ___
|
|
/\ \ /\ \ /\_ \
|
|
\ `\`\\\\/'/ ___ __ __ \//\ \ ___ ____ __
|
|
`\ `\ /' / __`\/\ \/\ \ \ \ \ / __`\ /',__\ /'__`\
|
|
`\ \ \/\ \L\ \ \ \_\ \ \_\ \_/\ \L\ \/\__, `\/\ __/
|
|
\ \_\ \____/\ \____/ /\____\ \____/\/\____/\ \____\\
|
|
\/_/\/___/ \/___/ \/____/\/___/ \/___/ \/____/
|
|
""")
|
|
|
|
def gameOver(self, gameWon):
|
|
system('clear')
|
|
|
|
print('\nDEALERS CARDS\n')
|
|
self.dealerHandler.safePrintCards()
|
|
print('\nYOUR CARDS\n')
|
|
self.handler.safePrintCards()
|
|
print()
|
|
print('Ace value is', self.handler.aceValue)
|
|
|
|
if gameWon:
|
|
self.youWin()
|
|
else:
|
|
self.youLose()
|
|
print()
|
|
|
|
print(f'Wins: {self.gameResults[0]} Losses: {self.gameResults[1]}')
|
|
if boolInput(
|
|
'Do you want to play again? [y/n]: ',
|
|
yesNoLetters=['y','n'],
|
|
error=''
|
|
):
|
|
self.reset()
|
|
else:
|
|
exit(0)
|
|
|
|
def checkIfLost(self):
|
|
|
|
winningConditions = [
|
|
self.handler.containsBlackJack and not self.dealerHandler.containsBlackJack,
|
|
self.dealerHandler.cardSum > 21
|
|
]
|
|
|
|
losingConditions = [
|
|
self.handler.cardSum > 21
|
|
]
|
|
|
|
if any(losingConditions):
|
|
self.gameOver(gameWon=False)
|
|
return True
|
|
elif any(winningConditions):
|
|
self.gameOver(gameWon=True)
|
|
return True
|
|
return False
|
|
|
|
|
|
def update(self):
|
|
system('clear')
|
|
|
|
print('\nDEALERS CARDS\n')
|
|
self.emptyHandler.safePrintCards()
|
|
print('\nYOUR CARDS\n')
|
|
self.handler.safePrintCards()
|
|
print()
|
|
print('Ace value is', self.handler.aceValue)
|
|
print()
|
|
|
|
if not self.checkIfLost():
|
|
if not boolInput('Continue? [y/n]: ', yesNoLetters=('y','n')):
|
|
gameWon = self.dealerHandler.cardSum < self.handler.cardSum
|
|
self.gameOver(gameWon=gameWon)
|
|
return
|
|
self.handler.generateNewCard()
|
|
|
|
def loop(self):
|
|
while True:
|
|
self.update()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
game = Blackjack()
|
|
game.loop()
|