Merge branch 'master' into ints

This commit is contained in:
Karol Idaszak 2023-01-31 22:08:41 +01:00
commit da3cbdfd17
2 changed files with 331 additions and 15 deletions

311
FuzzyControlSystem.py Normal file
View File

@ -0,0 +1,311 @@
#!/usr/bin/env python
# coding: utf-8
# In[1]:
from simpful import *
import matplotlib.pyplot as plt
# ## Sterownik 1 - Decyzja o udziale w grze
# ##### Dane wejściowe:
# - Wartość żetonów
# - Liczba przegranych z rzędu
#
# ##### Dane wyjściowe:
# - Decyzja dot. udziału w grze
# In[27]:
def getStartDecision(chipVal, lossNum):
"""
Args:
chipVal (int): current value of the player's chips
lossNum (int): number of losses in a row
Returns:
str: decision
"""
FS = FuzzySystem(show_banner=False)
FS.add_linguistic_variable("chipValue", AutoTriangle(3, terms=['low', 'average', 'high'], universe_of_discourse=[0, 10]))
FS.add_linguistic_variable("numLossInRow", AutoTriangle(3, terms=['low', 'average', 'high'], universe_of_discourse=[0, 10]))
O1 = TriangleFuzzySet(0,0,13, term="surrender")
O2 = TriangleFuzzySet(0,13,25, term="hit")
O3 = TriangleFuzzySet(13,15,17, term="double_down")
O4 = TriangleFuzzySet(16,21,21, term="stand")
FS.add_linguistic_variable("decision", LinguisticVariable([O1, O2, O3, O4], universe_of_discourse=[0, 25]))
FS.add_rules([
"IF (numLossInRow IS average) AND (chipValue IS average) THEN (decision IS hit)",
"IF (numLossInRow IS high) OR (chipValue IS low) THEN (decision IS surrender)",
"IF (numLossInRow IS low) AND (chipValue IS average) THEN (decision IS double_down)",
"IF chipValue IS high THEN decision IS stand"
])
FS.set_variable("chipValue", chipVal)
FS.set_variable("numLossInRow", lossNum)
result = FS.inference()
decision_terms = [(i.get_term(), FS.get_fuzzy_set('decision', i.get_term()).get_value(result['decision'])) for i in FS.get_fuzzy_sets('decision')]
endDecision = max(decision_terms, key=lambda item:item[1])[0]
return endDecision
# In[28]:
getStartDecision(7, 7)
# In[1]:
# FS.plot_variable('chipValue')
# FS.plot_variable('numLossInRow')
# FS.plot_variable('decision')
# ## Sterownik 2 - Decyzja o strategii w przypadku pary
# ##### Dane wejściowe:
# - Wartość widocznej karty krupiera
# - Wartość karty gracza (jednej z pary)
#
# ##### Dane wyjściowe:
# - Decyzja dot. akcji w grze
# In[12]:
def getSplitDecision(dealerCard, playerCard):
"""
Args:
dealerCard (int): value of the dealer card
playerCard (int): value of the player card (one of the pair)
Returns:
str: decision
"""
FS = FuzzySystem(show_banner=False)
T1 = TriangleFuzzySet(0,0,6, term="low")
T2 = TriangleFuzzySet(4,6,8, term="average")
T3 = TriangleFuzzySet(6,11,11, term="high")
FS.add_linguistic_variable("dealerCardValue", LinguisticVariable([T1, T2, T3], universe_of_discourse=[0, 11]))
FS.add_linguistic_variable("playerCardValue", LinguisticVariable([T1, T2, T3], universe_of_discourse=[0, 11]))
O1 = TriangleFuzzySet(0,0,15, term="continue")
O2 = TriangleFuzzySet(11,25,25, term="split")
FS.add_linguistic_variable("decision", LinguisticVariable([O1, O2], universe_of_discourse=[0, 25]))
FS.add_rules([
"IF (playerCardValue IS high) THEN (decision IS split)",
"IF (playerCardValue IS average) AND (dealerCardValue IS average) THEN (decision IS split)",
"IF (playerCardValue IS average) AND (dealerCardValue IS low) THEN (decision IS split)",
"IF (playerCardValue IS low) AND (dealerCardValue IS high) THEN (decision IS continue)",
"IF (playerCardValue IS low) AND (dealerCardValue IS average) THEN (decision IS split)",
"IF (playerCardValue IS low) AND (dealerCardValue IS low) THEN (decision IS continue)",
"IF (playerCardValue IS low) AND (dealerCardValue IS high) THEN (decision IS continue)"
])
FS.set_variable("dealerCardValue", dealerCard)
FS.set_variable("playerCardValue", playerCard)
result = FS.inference()
decision_terms = [(i.get_term(), FS.get_fuzzy_set('decision', i.get_term()).get_value(result['decision'])) for i in FS.get_fuzzy_sets('decision')]
endDecision = max(decision_terms, key=lambda item:item[1])[0]
return endDecision
# In[13]:
getSplitDecision(5, 3)
# In[7]:
#FS.plot_variable('dealerCardValue')
#FS.plot_variable('playerCardValue')
#FS.plot_variable('decision')
# ## Sterownik 3 - Decyzja jaką akcję podjąć (gracz bez asa wśród dwóch kart)
# ##### Dane wejściowe:
# - Wartość widocznej karty krupiera
# - Suma kart gracza
# - Suma zliczonych kart
#
# ##### Dane wyjściowe:
# - Decyzja dot. akcji w grze
# In[29]:
def getHardHandDecision(dealerCard, playerCardsVal, countedCardsVal, playerCardsNum):
"""
Args:
dealerCard (int): value of the dealer card
playerCardsVal (int): sum of the players hand
countedCardsVal (int): value of the counted cards
playerCardsNum (int): number of cards in players hadn
Returns:
str: decision
"""
FS = FuzzySystem(show_banner=False)
FS.add_linguistic_variable("dealerCardValue", LinguisticVariable([
TriangleFuzzySet(0,0,6, term="low"),
TriangleFuzzySet(4,6,8, term="average"),
TriangleFuzzySet(6,11,11, term="high")],
universe_of_discourse=[0, 11]))
FS.add_linguistic_variable("playerCardsValue", LinguisticVariable([
TriangleFuzzySet(0,0,12, term="low"),
TriangleFuzzySet(11,14,17, term="average"),
TriangleFuzzySet(12,21,21, term="high")],
universe_of_discourse=[0, 21]))
FS.add_linguistic_variable("countedCardsValue", LinguisticVariable([
TriangleFuzzySet(-20,-20,0, term="low"),
TriangleFuzzySet(-5,0,5, term="average"),
TriangleFuzzySet(0,20,20, term="high")],
universe_of_discourse=[-20, 20]))
O1 = TriangleFuzzySet(0,0,13, term="double down")
O2 = TriangleFuzzySet(0,13,25, term="hit")
O3 = TriangleFuzzySet(13,25,25, term="stand")
FS.add_linguistic_variable("decision", LinguisticVariable([O1, O2, O3], universe_of_discourse=[0, 25]))
if playerCardsNum == 2:
FS.add_rules([
"IF (playerCardsValue IS low) THEN (decision IS double down)",
"IF (playerCardsValue IS average) AND (dealerCardValue IS high) THEN (decision IS double down)",
"IF (playerCardsValue IS high) THEN (decision IS stand)",
"IF (playerCardsValue IS average) AND (dealerCardValue IS average) THEN (decision IS stand)",
"IF (playerCardsValue IS average) AND (dealerCardValue IS average) THEN (decision IS double down)"
])
else:
FS.add_rules([
"IF (playerCardsValue IS high) THEN (decision IS stand)",
"IF (playerCardsValue IS low) THEN (decision IS hit)",
"IF (playerCardsValue IS average) AND (dealerCardValue IS low) THEN (decision IS stand)",
"IF (playerCardsValue IS average) AND (dealerCardValue IS high) THEN (decision IS hit)",
"IF (playerCardsValue IS average) AND (dealerCardValue IS average) AND (countedCardsValue IS low) THEN (decision IS hit)",
])
FS.set_variable("dealerCardValue", dealerCard)
FS.set_variable("playerCardsValue", playerCardsVal)
FS.set_variable("countedCardsValue", countedCardsVal)
result = FS.inference()
decision_terms = [(i.get_term(), FS.get_fuzzy_set('decision', i.get_term()).get_value(result['decision'])) for i in FS.get_fuzzy_sets('decision')]
endDecision = max(decision_terms, key=lambda item:item[1])[0]
return endDecision
# In[19]:
getHardHandDecision(4, 10, 0, 2)
# In[7]:
# FS.plot_variable('dealerCardValue')
# FS.plot_variable('playerCardsValue')
# FS.plot_variable('countedCardsValue')
# FS.plot_variable('decision')
# ## Sterownik 4 - Decyzja jaką akcję podjąć (gracz z asem wśród dwóch kart)
# ##### Dane wejściowe:
# - Wartość widocznej karty krupiera
# - Wartość drugiej karty gracza
# - Suma zliczonych kart
#
# ##### Dane wyjściowe:
# - Decyzja dot. akcji w grze
# In[25]:
def getSoftHandDecision(dealerCard, playerCardsVal, countedCardsVal, playerCardsNum):
FS = FuzzySystem(show_banner=False)
FS.add_linguistic_variable("dealerCardValue", LinguisticVariable([
TriangleFuzzySet(0,0,6, term="low"),
TriangleFuzzySet(4,6,8, term="average"),
TriangleFuzzySet(6,11,11, term="high")],
universe_of_discourse=[0, 11]))
FS.add_linguistic_variable("playerCardValue", LinguisticVariable([
TriangleFuzzySet(0,0,5, term="low"),
TriangleFuzzySet(4,6,8, term="average"),
TriangleFuzzySet(7,9,9, term="high")],
universe_of_discourse=[0, 9]))
FS.add_linguistic_variable("countedCardsValue", LinguisticVariable([
TriangleFuzzySet(-20,-20,0, term="low"),
TriangleFuzzySet(-5,0,5, term="average"),
TriangleFuzzySet(0,20,20, term="high")],
universe_of_discourse=[-20, 20]))
O1 = TriangleFuzzySet(0,0,13, term="double down")
O2 = TriangleFuzzySet(0,13,25, term="hit")
O3 = TriangleFuzzySet(13,25,25, term="stand")
FS.add_linguistic_variable("decision", LinguisticVariable([O1, O2, O3], universe_of_discourse=[0, 25]))
if playerCardsNum == 2:
FS.add_rules([
"IF (playerCardValue IS average) AND (dealerCardValue IS average) THEN (decision IS double down)",
"IF (playerCardValue IS high) THEN (decision IS Stand)",
"IF (playerCardValue IS average) AND (dealerCardValue IS high) THEN (decision IS hit)",
"IF (playerCardValue IS low) AND (dealerCardValue IS low) THEN (decision IS hit)",
])
else:
FS.add_rules([
"IF (playerCardValue IS high) THEN (decision IS Stand)",
"IF (playerCardValue IS low) THEN (decision IS hit)",
"IF (playerCardValue IS average) AND (dealerCardValue IS high) THEN (decision IS Hit)",
"IF (playerCardValue IS average) AND (dealerCardValue IS average) AND (countedCardsValue IS high) THEN (decision IS Stand)",
"IF (playerCardValue IS average) AND (dealerCardValue IS average) AND (countedCardsValue IS low) THEN (decision IS Hit)"
])
FS.set_variable("dealerCardValue", dealerCard)
FS.set_variable("playerCardValue", playerCardsVal)
FS.set_variable("countedCardsValue", playerCardsNum)
result = FS.inference()
decision_terms = [(i.get_term(), FS.get_fuzzy_set('decision', i.get_term()).get_value(result['decision'])) for i in FS.get_fuzzy_sets('decision')]
endDecision = max(decision_terms, key=lambda item:item[1])[0]
return endDecision
# In[26]:
getSoftHandDecision(2, 8, 0, 3)
# In[2]:
# FS.plot_variable('dealerCardValue')
# FS.plot_variable('playerCardValue')
# FS.plot_variable('countedCardsValue')
# FS.plot_variable('decision')

View File

@ -1,5 +1,5 @@
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
@ -58,7 +58,7 @@ def dealer(hand: list, shoe: iter) -> int:
evaluation = cards_eval(hand)
return max(evaluation)
def AI(hand: list, face_up: str, splited) -> str:
def AI(hand: list, face_up: str, losses_in_row: int) -> str:
#TODO: add fuzzy logic
"""Fuzzy AI
possible player decision:
@ -66,7 +66,7 @@ def AI(hand: list, face_up: str, splited) -> str:
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
"""
@ -74,12 +74,12 @@ def AI(hand: list, face_up: str, splited) -> str:
# if face_up == 'ace':
# return 'surrender'
# else:
evaluation = cards_eval(hand)
if len(hand) == 2 and hand[0] == hand[1] and not splited:
return 'split'
if max(evaluation) == 11:
evaluation = max(cards_eval(hand))
decision = getStartDecision(evaluation, losses_in_row)
print(evaluation, decision)
if evaluation == 11:
return 'double down'
if max(evaluation) <= 17:
if evaluation <= 17:
return 'hit'
else:
return 'stand'
@ -105,25 +105,24 @@ def show_game_state(player_hand: list, dealer_hand: list, splited: bool, decisio
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) -> str:
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
splited_ai = False #temp
if dealer_hand == [] and player_hand == []:
dealer_hand = [next(shoe), next(shoe)]
player_hand = [next(shoe), next(shoe)]
else:
splited = True
splited_ai = True #temp
#dealer turn
face_up = dealer_hand[0]
@ -131,7 +130,7 @@ def blackjack(shoe: iter, dealer_hand: list=[], player_hand: list=[], bet: int=1
decision = ''
while decision != 'stand' or decision != 'surrender':
decision = AI(player_hand, face_up, splited_ai)
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))
@ -175,25 +174,31 @@ def blackjack(shoe: iter, dealer_hand: list=[], player_hand: list=[], bet: int=1
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)
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