commit 086b2affcf6cd491a7ad3c29a9c074975950c65a Author: karoel2 Date: Tue Jan 10 08:29:28 2023 +0100 init diff --git a/cards.py b/cards.py new file mode 100644 index 0000000..7ab0021 --- /dev/null +++ b/cards.py @@ -0,0 +1,172 @@ +# 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) < 18: + return 'hit' + else: + return 'stand' + ### temp + +def blackjack(shoe: iter, 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 decision == 'hit': + player_hand.append(next(shoe)) + elif decision == 'double down': + player_hand.append(next(shoe)) + elif decision == 'split': + #test if works + #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 dealer_value > 21: + return 'player win' + elif player_value > dealer_value: + return 'player win' + elif player_value == dealer_value: + return 'push' #keep money, no win no lose 0$ + else: + return 'dealer win' + #TODO: add adidtional return with wager value like +10$ or -20$ + +def game_loop() -> None: + stats = 0 + shoe_iter = iter(shoe(10)) + while True: + #round start + try: + result = blackjack(shoe_iter) + except StopIteration: + break + if result == 'player win': + stats += 1 + elif result == 'dealer win': + stats -= 1 + elif result == 'push': + stats += 0 + return stats + +if __name__ == '__main__': + print(game_loop()) + +# if __name__ == '__main__': +# import time +# #don't use time.time() for counting code execution time! +# start = time.perf_counter() +# for i in range(1000): +# game_loop() + +# end = time.perf_counter() +# result = end - start +# print(result) \ No newline at end of file