268 lines
8.5 KiB
Python
268 lines
8.5 KiB
Python
import random
|
|
from FuzzyControlSystem import getStartDecision, getSplitDecision, getHardHandDecision, getSoftHandDecision
|
|
|
|
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 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10]
|
|
suits = ['spades', 'clubs', 'hearts', 'diamonds']
|
|
|
|
deck = []
|
|
for _ in range(n_of_decks):
|
|
for _ in suits:
|
|
deck.extend(vals)
|
|
|
|
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 = [sum(hand), sum(hand)]
|
|
for value in hand:
|
|
if value == 1:
|
|
evaluation[1] += 10
|
|
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 count_highlow(hand: list) -> int:
|
|
highlow = 0
|
|
low_cards = [1, 2, 3, 4, 5, 6, 7]
|
|
|
|
for card in hand:
|
|
if card in low_cards:
|
|
highlow -= 1
|
|
elif card == 10:
|
|
highlow += 1
|
|
return highlow
|
|
|
|
def AI(hand: list, face_up: str, losses_in_row: int) -> 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
|
|
losses_in_row: number of losses in row in the current game
|
|
Returns:
|
|
list: player decision
|
|
"""
|
|
cards_count = len(hand)
|
|
|
|
evaluation = cards_eval(hand)
|
|
if len(evaluation) != 1:
|
|
evaluation = evaluation[1]
|
|
else:
|
|
evaluation = evaluation[0]
|
|
decision = ''
|
|
if 'ace' in hand:
|
|
decision = getSoftHandDecision(face_up, evaluation, cards_count)
|
|
else:
|
|
decision = getHardHandDecision(face_up, evaluation, cards_count)
|
|
|
|
breakpoint()
|
|
return decision
|
|
|
|
def show_game_state(player_hand: list, dealer_hand: list, splited: bool, decision: str='') -> None:
|
|
"""Print dealer and player card values and player decision
|
|
|
|
Args:
|
|
player_hand (list): List of cards in player hand
|
|
dealer_hand (list): List of cards in dealer hand
|
|
splited (bool): True if it is subprocess by spliting
|
|
decision (str, optional): Player decision. Will not be printed if defaults to ''.
|
|
|
|
"""
|
|
if decision and cards_eval(player_hand)[0] > 21:
|
|
print("split| " if splited else '', end='')
|
|
print(f"dealer: {cards_eval(dealer_hand)} player: {cards_eval(player_hand)} fail")
|
|
elif decision:
|
|
print("split| " if splited else '', end='')
|
|
print(f"dealer: {cards_eval(dealer_hand)} player: {cards_eval(player_hand)} decision: {decision}")
|
|
elif not cards_eval(player_hand)[0] > 21:
|
|
print("split| " if splited else '', end='')
|
|
print(f"dealer: {cards_eval(dealer_hand)} player: {cards_eval(player_hand)}")
|
|
|
|
def blackjack(shoe: iter, dealer_hand: list=[], player_hand: list=[], bet: int=10, losses_in_row: int=0) -> 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.
|
|
bet: amount of money the player betted
|
|
losses_in_row: number of losses in row in the current game
|
|
Returns:
|
|
str: game result
|
|
"""
|
|
splited = False
|
|
if dealer_hand == [] and player_hand == []:
|
|
dealer_hand = [next(shoe), next(shoe)]
|
|
player_hand = [next(shoe), next(shoe)]
|
|
else:
|
|
splited = True
|
|
|
|
#dealer turn
|
|
face_up = dealer_hand[0]
|
|
dealer_value = dealer(dealer_hand, shoe)
|
|
|
|
decision = ''
|
|
while decision != 'stand' or decision != 'surrender':
|
|
decision = AI(player_hand, face_up, losses_in_row)
|
|
show_game_state(player_hand, [face_up], splited, decision)
|
|
if decision == 'hit':
|
|
player_hand.append(next(shoe))
|
|
elif decision == 'double down':
|
|
bet *= 2
|
|
player_hand.append(next(shoe))
|
|
elif decision == 'split':
|
|
#this work reccursevly
|
|
player_hand = [player_hand[0]]
|
|
splited_ai = True #temp
|
|
blackjack(shoe, dealer_hand, player_hand.copy(), bet)#new wager start
|
|
#old wager continue
|
|
elif decision == 'surrender':
|
|
break
|
|
elif decision == 'stand':
|
|
break
|
|
|
|
player_value = max(cards_eval(player_hand))
|
|
|
|
show_game_state(player_hand, dealer_hand, splited)
|
|
print("split| " if splited else '', end='')
|
|
if player_value == 21 and 1 in player_hand:
|
|
print('player blackjack', "="*50, sep='\n')
|
|
return 'player blackjack', bet
|
|
elif player_value > 21:
|
|
print('dealer win', "="*50, sep='\n')
|
|
return 'dealer win', bet
|
|
elif dealer_value > 21:
|
|
print('player win', "="*50, sep='\n')
|
|
return 'player win', bet
|
|
elif player_value > dealer_value:
|
|
print('player win', "="*50, sep='\n')
|
|
return 'player win', bet
|
|
elif player_value == dealer_value:
|
|
print('push', "="*50, sep='\n')
|
|
return 'push', bet #keep money, no win no lose 0$
|
|
else:
|
|
print('dealer win', "="*50, sep='\n')
|
|
return 'dealer win', bet
|
|
|
|
def game_loop(balance, bet) -> None:
|
|
wins, losses, draws = 0, 0, 0
|
|
player_blackjack = 0
|
|
shoe_iter = iter(shoe(10))
|
|
losses_in_row = 0
|
|
notable_results = ['player win', 'dealer win', 'player blackjack']
|
|
while True:
|
|
#round start
|
|
try:
|
|
balance -= bet
|
|
result, game_bet = blackjack(shoe_iter, bet=bet, losses_in_row=losses_in_row)
|
|
except StopIteration:
|
|
break
|
|
if result == 'player win':
|
|
wins += 1
|
|
balance += (2*game_bet)
|
|
losses_in_row = 0
|
|
|
|
elif result == 'player blackjack':
|
|
wins += 1
|
|
# player_blackjack += 1
|
|
balance += (2*game_bet) + (game_bet/2)
|
|
losses_in_row = 0
|
|
|
|
elif result == 'dealer win':
|
|
losses += 1
|
|
losses_in_row += 1
|
|
|
|
elif result == 'push':
|
|
balance += game_bet
|
|
draws += 1
|
|
return wins, losses, draws, balance #player_blackjack
|
|
|
|
def calculate_bet(wins, losses, hand):
|
|
pass
|
|
|
|
# if __name__ == '__main__':
|
|
# print(game_loop())
|
|
|
|
if __name__ == '__main__':
|
|
statistics = [0, 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(10):
|
|
wins, loses, draws, money = game_loop(0, 10)
|
|
statistics[0] += wins
|
|
statistics[1] += loses
|
|
statistics[2] += draws
|
|
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]} | draws: {statistics[2]}')
|
|
print(f'win {round((statistics[0]/sum(statistics)*100), 2)}%')
|
|
print(f'balance: {money_sum}')
|
|
|
|
# print(f'moeny return {round((money_sum)*100, 2)}%')
|
|
# 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}")
|