diff --git a/FuzzyControlSystem.py b/FuzzyControlSystem.py index 6aef14a..a65fac5 100644 --- a/FuzzyControlSystem.py +++ b/FuzzyControlSystem.py @@ -72,7 +72,7 @@ getStartDecision(7, 7) # ## Sterownik 2 - Decyzja o strategii w przypadku pary # ##### Dane wejściowe: # - Wartość widocznej karty krupiera -# - Wartość karty gracza (jednej z pary) +# - Wartość kart gracza # # ##### Dane wyjściowe: # - Decyzja dot. akcji w grze @@ -80,22 +80,27 @@ getStartDecision(7, 7) # In[12]: -def getSplitDecision(dealerCard, playerCard): +def getSplitDecision(dealerCard, playerCardsVal): """ Args: dealerCard (int): value of the dealer card - playerCard (int): value of the player card (one of the pair) + playerCardsVal (int): sum of the player cards 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])) + FS.add_linguistic_variable("dealerCardValue", LinguisticVariable([ + FuzzySet([[0,1], [6,1], [7,0]], term='low'), + FuzzySet([[6,0], [7,1], [7.5,0]], term='high'), + FuzzySet([[7,0], [8,1]], term='very_high') + ], universe_of_discourse=[0, 11])) + + FS.add_linguistic_variable('splitValue', LinguisticVariable([ + FuzzySet([[0,1], [2,1], [3,0], [9,0], [10,1]], term='high'), + FuzzySet([[2,0], [3,1], [4.5,1], [5,0], [5.5,1], [9,1], [9,1], [10,0]], term='low'), + ], universe_of_discourse=[0, 20])) O1 = TriangleFuzzySet(0,0,15, term="continue") @@ -103,17 +108,14 @@ def getSplitDecision(dealerCard, playerCard): 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)" + "IF (splitValue IS high) THEN (decision IS split)", + "IF (splitValue IS low) AND (dealerCardValue IS low) THEN (decision IS split)", + "IF (splitValue IS low) AND (dealerCardValue IS high) THEN (decision IS continue)", + "IF (splitValue IS low) AND (dealerCardValue IS very_high) THEN (decision IS continue)", ]) FS.set_variable("dealerCardValue", dealerCard) - FS.set_variable("playerCardValue", playerCard) + FS.set_variable("splitValue", playerCardsVal) 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')] @@ -121,11 +123,6 @@ def getSplitDecision(dealerCard, playerCard): return endDecision -# In[13]: - - -getSplitDecision(5, 3) - # In[7]: @@ -135,11 +132,11 @@ getSplitDecision(5, 3) #FS.plot_variable('decision') -# ## Sterownik 3 - Decyzja jaką akcję podjąć (gracz bez asa wśród dwóch kart) +# ## Sterownik 3 - Decyzja jaką akcję podjąć (twarda ręka) # ##### Dane wejściowe: # - Wartość widocznej karty krupiera # - Suma kart gracza -# - Suma zliczonych kart +# - Liczba kart gracza # # ##### Dane wyjściowe: # - Decyzja dot. akcji w grze @@ -147,12 +144,11 @@ getSplitDecision(5, 3) # In[29]: -def getHardHandDecision(dealerCard, playerCardsVal, countedCardsVal, playerCardsNum): +def getHardHandDecision(dealerCard, playerCardsVal, 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 @@ -161,22 +157,27 @@ def getHardHandDecision(dealerCard, playerCardsVal, countedCardsVal, playerCards 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])) + FuzzySet([[0,1], [6,1], [7,0]], term='low'), + FuzzySet([[6,0], [7,1], [7.5,0]], term='high'), + FuzzySet([[7,0], [8,1]], term='very_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])) + FuzzySet([[0,1], [11,1], [12,0]], term='low'), + FuzzySet([[11,0], [12,1], [16,1], [17, 0]], term='medium'), + FuzzySet([[16,0], [17,1], [18,0]], term='high'), + FuzzySet([[17,0], [18,1]], term='very_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])) +# FS.add_linguistic_variable('splitValue', LinguisticVariable([ +# FuzzySet([[0,1], [2,1], [3,0], [9,0], [10,1]], term='split_high'), +# FuzzySet([[2,0], [3,1], [4.5,1], [5,0], [5.5,1], [9,1], [9,1], [10,0]], term='split_low'), +# ], universe_of_discourse=[0, 20])) + + FS.add_linguistic_variable('doubleValue', LinguisticVariable([ + FuzzySet([[7,0], [8,1], [9,1], [10,0]], term='low'), + FuzzySet([[9,0], [10,1], [11,1], [12,0]], term='high'), + ], universe_of_discourse=[0, 21])) O1 = TriangleFuzzySet(0,0,13, term="double down") @@ -185,40 +186,36 @@ def getHardHandDecision(dealerCard, playerCardsVal, countedCardsVal, playerCards FS.add_linguistic_variable("decision", LinguisticVariable([O1, O2, O3], universe_of_discourse=[0, 25])) - if playerCardsNum == 2: + if playerCardsNum == 2: # gdy początek rozgrywki 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)" + "IF (doubleValue IS high) THEN (decision IS double down)", + "IF (doubleValue IS low) AND (dealerCardValue IS low) THEN (decision IS double down)", + "IF (playerCardsValue IS low) THEN (decision IS hit)", + "IF (playerCardsValue IS medium) AND (dealerCardValue IS high) THEN (decision IS hit)", + "IF (playerCardsValue IS medium) AND (dealerCardValue IS very_high) THEN (decision IS hit)", + "IF (playerCardsValue IS high) AND (dealerCardValue IS very_high) THEN (decision IS hit)", ]) 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)", + "IF (playerCardsValue IS medium) AND (dealerCardValue IS high) THEN (decision IS hit)", + "IF (playerCardsValue IS medium) AND (dealerCardValue IS very_high) THEN (decision IS hit)", + "IF (playerCardsValue IS high) AND (dealerCardValue IS very_high) THEN (decision IS hit)", ]) FS.set_variable("dealerCardValue", dealerCard) FS.set_variable("playerCardsValue", playerCardsVal) - FS.set_variable("countedCardsValue", countedCardsVal) + FS.set_variable("doubleValue", playerCardsVal) 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]: @@ -229,11 +226,11 @@ getHardHandDecision(4, 10, 0, 2) # FS.plot_variable('decision') -# ## Sterownik 4 - Decyzja jaką akcję podjąć (gracz z asem wśród dwóch kart) +# ## Sterownik 4 - Decyzja jaką akcję podjąć (miękka ręka) # ##### Dane wejściowe: # - Wartość widocznej karty krupiera -# - Wartość drugiej karty gracza -# - Suma zliczonych kart +# - Wartość kart gracza +# - Liczba kart gracza # # ##### Dane wyjściowe: # - Decyzja dot. akcji w grze @@ -241,27 +238,40 @@ getHardHandDecision(4, 10, 0, 2) # In[25]: -def getSoftHandDecision(dealerCard, playerCardsVal, countedCardsVal, playerCardsNum): +def getSoftHandDecision(dealerCard, playerCardsVal, playerCardsNum): + """ + Args: + dealerCard (int): value of the dealer card + playerCardsVal (int): sum of the players hand + 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])) + FuzzySet([[0,1], [6,1], [7,0]], term='low'), + FuzzySet([[6,0], [7,1], [7.5,0]], term='high'), + FuzzySet([[7,0], [8,1]], term='very_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])) + FuzzySet([[0,1], [11,1], [12,0]], term='low'), + FuzzySet([[11,0], [12,1], [16,1], [17, 0]], term='medium'), + FuzzySet([[16,0], [17,1], [18,0]], term='high'), + FuzzySet([[17,0], [18,1]], term='very_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])) +# FS.add_linguistic_variable('splitValue', LinguisticVariable([ +# FuzzySet([[0,1], [2,1], [3,0], [9,0], [10,1]], term='split_high'), +# FuzzySet([[2,0], [3,1], [4.5,1], [5,0], [5.5,1], [9,1], [9,1], [10,0]], term='split_low'), +# ], universe_of_discourse=[0, 20])) + + FS.add_linguistic_variable('doubleValue', LinguisticVariable([ + FuzzySet([[12,0], [13,1], [16,1], [17,0]], term='low'), + FuzzySet([[16,0], [17,1], [18,0]], term='high'), + ], universe_of_discourse=[0, 21])) O1 = TriangleFuzzySet(0,0,13, term="double down") @@ -269,38 +279,37 @@ def getSoftHandDecision(dealerCard, playerCardsVal, countedCardsVal, playerCards O3 = TriangleFuzzySet(13,25,25, term="stand") FS.add_linguistic_variable("decision", LinguisticVariable([O1, O2, O3], universe_of_discourse=[0, 25])) - if playerCardsNum == 2: + + if playerCardsNum == 2: # gdy początek rozgrywki FS.add_rules([ - "IF (playerCardsValue IS average) AND (dealerCardValue IS average) THEN (decision IS double down)", - "IF (playerCardsValue IS high) THEN (decision IS stand)", - "IF (playerCardsValue IS average) AND (dealerCardValue IS high) THEN (decision IS hit)", - "IF (playerCardValue IS low) AND (dealerCardValue IS low) THEN (decision IS hit)", + "IF (doubleValue IS high) THEN (decision IS double down)", + "IF (doubleValue IS low) AND (dealerCardValue IS low) THEN (decision IS double down)", + "IF (playerCardsValue IS low) THEN (decision IS hit)", + "IF (playerCardsValue IS medium) AND (dealerCardValue IS high) THEN (decision IS hit)", + "IF (playerCardsValue IS medium) AND (dealerCardValue IS very_high) THEN (decision IS hit)", + "IF (playerCardsValue IS high) AND (dealerCardValue IS very_high) THEN (decision IS hit)", ]) + 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 high) THEN (decision IS Hit)", - "IF (playerCardsValue IS average) AND (dealerCardValue IS average) AND (countedCardsValue IS high) THEN (decision IS stand)", - "IF (playerCardsValue IS average) AND (dealerCardValue IS average) AND (countedCardsValue IS low) THEN (decision IS Hit)" + "IF (playerCardsValue IS medium) AND (dealerCardValue IS high) THEN (decision IS hit)", + "IF (playerCardsValue IS medium) AND (dealerCardValue IS very_high) THEN (decision IS hit)", + "IF (playerCardsValue IS high) AND (dealerCardValue IS very_high) THEN (decision IS hit)", ]) + FS.set_variable("dealerCardValue", dealerCard) FS.set_variable("playerCardsValue", playerCardsVal) - FS.set_variable("countedCardsValue", playerCardsVal) + FS.set_variable("doubleValue", playerCardsVal) 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]: @@ -309,3 +318,40 @@ getSoftHandDecision(2, 8, 0, 3) # FS.plot_variable('countedCardsValue') # FS.plot_variable('decision') + + +# ## Funkcja do obsługi sterowników +# ##### Dane wejściowe: +# - Wartość widocznej karty krupiera +# - Lista kart gracza +# - Flaga określająca czt jest para (ustawiona na 1 tylko gdy kest para i gdy jest to początek rozgrywki!) +# +# ##### Dane wyjściowe: +# - Decyzja dot. akcji w grze + +# In[25]: + +def getDecision(dealerCard, playerCards, isPair): + """ + Args: + dealerCard (int): value of the dealer card + playerCards (list): list of player cards + isPair (int): is pair in players hand - 1 only at the beggining of the game + Returns: + str: decision + """ + + playerCardsNum = len(playerCards) + if 1 in playerCards: # soft hand + playerCardsVal = sum([x if x != 1 else 10 for x in playerCards]) + if sum(playerCards) == 2: # is pair of aces + return 'split' + else: # controller for soft hand + return getSoftHandDecision(dealerCard, playerCardsVal, playerCardsNum) + + else: # hard hand + playerCardsVal = sum(playerCards) + if isPair and getSplitDecision(dealerCard, playerCardsVal) != 'continue': # if pair - controller for splitting + return 'split' + else: # controller for hard hand + return getHardHandDecision(dealerCard, playerCardsVal, playerCardsNum) diff --git a/cards.py b/cards.py index a083f81..72213d9 100644 --- a/cards.py +++ b/cards.py @@ -1,5 +1,5 @@ import random -from FuzzyControlSystem import getStartDecision, getSplitDecision, getHardHandDecision, getSoftHandDecision +from FuzzyControlSystem import getStartDecision, getSplitDecision, getHardHandDecision, getSoftHandDecision, getDecision def shoe(n_of_decks: int = 1) -> list: """Create shuffled shoe of n decks of cards @@ -81,6 +81,8 @@ def AI(hand: list, face_up: str, losses_in_row: int) -> str: Returns: list: player decision """ + vals = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10] + cards_count = len(hand) highlow = count_highlow(hand) @@ -90,11 +92,9 @@ def AI(hand: list, face_up: str, losses_in_row: int) -> str: evaluation = evaluation[1] else: evaluation = evaluation[0] + is_pair = any([hand.count(val) > 1 for val in vals]) decision = '' - if 'ace' in hand: - decision = getSoftHandDecision(face_up, evaluation, highlow,cards_count) - else: - decision = getHardHandDecision(face_up, evaluation, highlow,cards_count) + decision = getDecision(face_up, hand, is_pair) return decision def show_game_state(player_hand: list, dealer_hand: list, splited: bool, decision: str='') -> None: