# 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) -> 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: 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) while max(evaluation) <= 17: #solve soft 17 hand.append(next(shoe)) evaluation = cards_eval(hand) 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) if max(evaluation) <= 17: return 'hit' else: return 'stand' ### temp def blackjack(shoe: iter, money:int, dealer_hand: list=[], player_hand: list =[]) -> 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) if cards_eval(player_hand)[0] > 21:\ print(f"dealer: {cards_eval(dealer_hand)}, player: {cards_eval(player_hand)}, fail") else: print(f"dealer: {cards_eval(dealer_hand)}, player: {cards_eval(player_hand)}, decision: {decision}") if decision == 'hit': player_hand.append(next(shoe)) elif decision == 'double down': 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)#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)) # print(dealer_value, player_value) #debug #round end if player_value > 21: return 'dealer win', money elif dealer_value > 21: return 'player win', money elif player_value > dealer_value: return 'player win', money elif player_value == dealer_value: return 'push', money #keep money, no win no lose 0$ else: return 'dealer win', money #TODO: add adidtional return with wager value like +10$ or -20$ def game_loop() -> None: stats = [0, 0] #wins, loses money = 500 #100$ start money shoe_iter = iter(shoe(10)) while True: #round start try: result, money = blackjack(shoe_iter, money) except StopIteration: break if result == 'player win': stats[0] += 1 elif result == 'dealer win': stats[1] += 1 # elif result == 'push': # stats[0] += 0 # stats[1] += 1 print("---------------------") stats.append(money) return stats # if __name__ == '__main__': # print(game_loop()) if __name__ == '__main__': statistics = [0, 0] money_sum = 0 import time #don't use time.time() for counting code execution time! start = time.perf_counter() for i in range(1000): wins, loses, money = game_loop() statistics[0] += wins statistics[1] += loses money_sum += money end = time.perf_counter() result = end - start print(f'time: {round(result, 3)} seconds') print(f'wins: {statistics[0]} | losses: {statistics[1]}') print(f'win {round((statistics[0]/sum(statistics)*100), 2)}%') print(f'moeny return {round((money_sum/500)*100, 2)}%')