# import itertools import random def shoe(n_of_decks: int = 1) -> list: """Create shuffled shoe of n decks of cards Args: n_of_decks (int, optional): number of decks. Defaults to 1. Returns: list: shoe- shuffled decks of cards """ vals = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'jack', 'queen', 'king', 'ace'] suits = ['spades', 'clubs', 'hearts', 'diamonds'] deck = [] for _ in range(n_of_decks): for _ in suits: deck.extend(vals) # deck.extend(itertools.product(vals, suits)) random.shuffle(deck) return deck def cards_eval(hand: list, agent: str) -> list: """Evaluate hand value. Will return two values if there is an ace in the hand and both values are below 21. Args: hand (list): list of cards Returns: list: returns a list of values of the hand """ evaluation = [0, 0] for value in hand: print(f"{agent} : {value}") if value in ['jack', 'queen', 'king']: evaluation[0] += 10 evaluation[1] += 10 elif value == 'ace': evaluation[0] += 1 evaluation[1] += 11 else: evaluation[0] += int(value) evaluation[1] += int(value) if evaluation[0] == evaluation[1]: return [evaluation[0]] elif evaluation[1] > 21: return [evaluation[0]] else: return evaluation # both values returned def dealer(hand: list, shoe: iter) -> int: """Dealer hand resolution Args: hand (list): dealer hand shoe (iter): iterator of shoe Returns: int: dealer hand value """ evaluation = cards_eval(hand, "dealer") while max(evaluation) <= 17: #solve soft 17 hand.append(next(shoe)) evaluation = cards_eval(hand, "dealer") return max(evaluation) def AI(hand: list, face_up: str) -> str: #TODO: add fuzzy logic """Fuzzy AI possible player decision: 'hit', 'double down', 'split', 'surrender', 'stand' Args: hand (list): player hand face_up (str): dealer face up card Returns: list: player decision """ ### temp # if face_up == 'ace': # return 'surrender' # else: evaluation = cards_eval(hand, "player") if max(evaluation) == 11: return 'double down' if max(evaluation) <= 17: return 'hit' else: return 'stand' ### temp def has_blackjack_occured(hand: list): """Method assumes that hand value == 21 """ if len(hand) != 2: return False if "ace" in hand and any([value in hand for value in ['jack', 'queen', 'king']]): return True return False def blackjack(shoe: iter, dealer_hand: list=[], player_hand: list =[], bet: int =10) -> str: """Single blackjack round Args: shoe (iter): shoe iterator dealer_hand (list, optional): dealer hand. Should be non empty only in SPLIT. player_hand (list, optional): player hand. Should be non empty only in SPLIT. Returns: str: game result """ if dealer_hand == [] and player_hand == []: dealer_hand = [next(shoe), next(shoe)] player_hand = [next(shoe), next(shoe)] face_up = dealer_hand[0] decision = '' while decision != 'stand' or decision != 'surrender': decision = AI(player_hand, face_up) print(f"Decision: {decision}") if decision == 'hit': player_hand.append(next(shoe)) elif decision == 'double down': bet *= 2 player_hand.append(next(shoe)) elif decision == 'split': #this wont work! #it will need to # dealer_value = dealer(dealer_hand, shoe) #be calculated before and passed to blackjack() #so both wager have the same dealer_value! ##this will work reccursevly player_hand = player_hand[0] blackjack(shoe, dealer_hand, player_hand, bet)#new wager start #old wager continue elif decision == 'surrender': break elif decision == 'stand': break #dealer turn dealer_value = dealer(dealer_hand, shoe) player_value = max(cards_eval(player_hand, "player")) # print(dealer_value, player_value) #debug #round end print(f"Dealer's deck value: {dealer_value}") print(f"Player's deck value: {player_value}") if player_value == 21 and has_blackjack_occured(player_hand): return 'player blackjack', bet elif player_value > 21: return 'dealer win', bet elif dealer_value > 21: return 'player win', bet elif player_value > dealer_value: return 'player win', bet elif player_value == dealer_value: return 'push', bet #keep money, no win no lose 0$ else: return 'dealer win', bet #TODO: add adidtional return with wager value like +10$ or -20$ def game_loop(balance, bet) -> None: wins, losses, draws = 0, 0, 0 player_blackjack = 0 shoe_iter = iter(shoe(10)) notable_results = ['player win', 'dealer win', 'player blackjack'] while True: #round start try: balance -= bet result, game_bet = blackjack(shoe_iter, bet=bet) except StopIteration: break if result == 'player win': wins += 1 balance += (2*game_bet) elif result == 'player blackjack': wins += 1 player_blackjack += 1 balance += (2*game_bet) + (game_bet/2) elif result == 'dealer win': losses += 1 elif result == 'push': balance += game_bet draws += 1 if result in notable_results: print(result) print("===="*10) return wins, losses, draws, balance, player_blackjack def calculate_bet(wins, losses, hand): pass # if __name__ == '__main__': # print(game_loop()) if __name__ == '__main__': total_wins, total_losses, total_draws = 0, 0, 0 total_p_blackjack = 0 balance = 0 bet = 10 import time #don't use time.time() for counting code execution time! start = time.perf_counter() for i in range(100): wins, loses, draws, balance, p_blackjack = game_loop(balance, bet) total_wins += wins total_losses += loses total_draws += draws total_p_blackjack += p_blackjack end = time.perf_counter() result = end - start print(result) print(f"Wins: {total_wins}, Losses: {total_losses}, Draws: {total_draws}") print(f"Wins/Losses ratio: {total_wins/sum([total_wins, total_losses])}") print(f"Balance: {balance}") print(f"Times player hit blackjack: {total_p_blackjack}")