blackjack-fuzzy/cards.py

194 lines
5.7 KiB
Python
Raw Normal View History

2023-01-10 08:29:28 +01:00
# 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)
2023-01-10 12:15:53 +01:00
while max(evaluation) <= 17: #solve soft 17
2023-01-10 08:29:28 +01:00
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)
2023-01-10 12:15:53 +01:00
if max(evaluation) <= 17:
2023-01-10 08:29:28 +01:00
return 'hit'
else:
return 'stand'
### temp
2023-01-31 19:54:38 +01:00
def blackjack(shoe: iter, money:int, dealer_hand: list=[], player_hand: list =[]) -> str:
2023-01-10 08:29:28 +01:00
"""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)
2023-01-31 19:54:38 +01:00
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}")
2023-01-10 08:29:28 +01:00
if decision == 'hit':
player_hand.append(next(shoe))
elif decision == 'double down':
player_hand.append(next(shoe))
elif decision == 'split':
2023-01-10 12:15:53 +01:00
#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
2023-01-10 08:29:28 +01:00
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
2023-01-10 12:15:53 +01:00
if player_value > 21:
2023-01-31 19:54:38 +01:00
return 'dealer win', money
2023-01-10 12:15:53 +01:00
elif dealer_value > 21:
2023-01-31 19:54:38 +01:00
return 'player win', money
2023-01-10 08:29:28 +01:00
elif player_value > dealer_value:
2023-01-31 19:54:38 +01:00
return 'player win', money
2023-01-10 08:29:28 +01:00
elif player_value == dealer_value:
2023-01-31 19:54:38 +01:00
return 'push', money #keep money, no win no lose 0$
2023-01-10 08:29:28 +01:00
else:
2023-01-31 19:54:38 +01:00
return 'dealer win', money
2023-01-10 08:29:28 +01:00
#TODO: add adidtional return with wager value like +10$ or -20$
def game_loop() -> None:
2023-01-10 12:15:53 +01:00
stats = [0, 0] #wins, loses
2023-01-31 19:54:38 +01:00
money = 500 #100$ start money
2023-01-10 08:29:28 +01:00
shoe_iter = iter(shoe(10))
while True:
#round start
try:
2023-01-31 19:54:38 +01:00
result, money = blackjack(shoe_iter, money)
2023-01-10 08:29:28 +01:00
except StopIteration:
break
if result == 'player win':
2023-01-10 12:15:53 +01:00
stats[0] += 1
2023-01-10 08:29:28 +01:00
elif result == 'dealer win':
2023-01-10 12:15:53 +01:00
stats[1] += 1
# elif result == 'push':
# stats[0] += 0
# stats[1] += 1
2023-01-31 19:54:38 +01:00
print("---------------------")
stats.append(money)
2023-01-10 08:29:28 +01:00
return stats
# if __name__ == '__main__':
2023-01-10 12:15:53 +01:00
# print(game_loop())
if __name__ == '__main__':
statistics = [0, 0]
2023-01-31 19:54:38 +01:00
money_sum = 0
2023-01-10 12:15:53 +01:00
import time
#don't use time.time() for counting code execution time!
start = time.perf_counter()
for i in range(1000):
2023-01-31 19:54:38 +01:00
wins, loses, money = game_loop()
2023-01-10 12:15:53 +01:00
statistics[0] += wins
statistics[1] += loses
2023-01-31 19:54:38 +01:00
money_sum += money
2023-01-10 12:15:53 +01:00
end = time.perf_counter()
result = end - start
2023-01-31 19:54:38 +01:00
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)}%')