Yes
Yes

Reputation: 31

How to save scores of a poker "program" in a json file

I'm having a little issue with saving scores. My idea was to saving all scores into PokerScores.json and then, every end of the match, add points to the winner. Also, the user could reset the saved scores after the deck shuffle (in countinue playing), but if he decide to maintain the score, the terminal would pick the saved data from the json file. But the problem is that the terminal keeps to telling me there is an error (it's surely one of the functions I've created, because the rest fo the code regarding game was working) and I'm not undestranding what I've written wrong. Thanks in advance

import random, time, json
from random import shuffle
from collections import Counter
from enum import Enum

class CardSuits(Enum):
    Hearts = "Hearts"
    Diamonds = "Diamonds"
    Clubs = "Clubs"
    Spades = "Spades"

class CardValues(Enum):
    Two = 2
    Three = 3
    Four = 4
    Five = 5
    Six = 6
    Seven = 7
    Eight = 8
    Nine = 9
    Ten = 10
    Jack = "J"
    Queen = "Q"
    King = "K"
    Ace = "A"


class Card:

    _symbols = {"Hearts": "♥️", "Diamonds": "♦️", "Clubs": "♣️", "Spades": "♠"}

    def __init__(self, suit: CardSuits, value: CardValues) -> None:
        self.suit = suit
        self.value = value

    def __str__(self) -> str:
        return f"{self.value.value}{self._symbols[self.suit.name]}"

    def __repr__(self) -> str:
        return f"{self.value.value}{self._symbols[self.suit.name]}"


#LOAD SCORE
def load_scores():
    try:
        with open("PokerScores.json", "r") as file:
            json.load(file)
    except FileNotFoundError:
        return [0, 0, 0]
#SAVING SCORE
def save_scores(scores):
    with open("PokerScores.json", "w") as file:
        json.dump(scores, file)

#GAME START
def start():
    scores = load_scores()
    play = input("You wanna play? ")
    if play.lower() in ("yes", "sure", "yeah"):
        all_cards = [Card(suits, value) for suits in CardSuits for value in CardValues]
        shuffle(all_cards)
        unique_cards = set()
        while len(unique_cards) < 5:
            unique_cards.add(random.choice(all_cards))
        cards = list(unique_cards)
        print("Your cards are:", ", ".join(str(card) for card in cards))
        time.sleep(4)

        #CHANGE PHASE
        while True:
            change_cards = input("Want to change cards? ")
            if change_cards.lower() == "yes":
                quantity = input("Which cards? ")
                card_input_index = ["first", "second", "third", "fourth", "fifth"]

                if quantity.lower() == "none":
                    break

                elif quantity.lower() in card_input_index:
                    index = card_input_index.index(quantity.lower())
                    cards[index] = random.choice(all_cards)
                    print("Your new cards are:", ", ".join(str(card) for card in cards))
                    break

                elif " " in quantity:
                    change_indices = quantity.lower().split()
                    if all(index in card_input_index for index in change_indices):
                    #controlla se tutti gli indici dati dall'utente siano presenti in card_input_index
                    #in questo modo non si ha più il problema che salta il passaggio del cambio delle
                    #carte se si scrive una parola a caso con uno spazio
                        for index in change_indices:
                            if index in card_input_index:
                                card_index = card_input_index.index(index)
                                cards[card_index] = random.choice(all_cards)
                        print("Your new cards are: ", ", ".join(str(card) for card in cards))
                        break
                    else:
                        print("Invalid cards selected")

                elif quantity.lower() == "all":
                    unique_cards = set()
                    while len(unique_cards) < 5:
                        unique_cards.add(random.choice(all_cards))
                    cards = list(unique_cards)
                    print("Your new cards are:", ", ".join(str(card) for card in cards))
                    break  
                            
                else:
                    print("Invalid cards selected")
            elif change_cards.lower() == "no":    
                break     
        
        #OPPONENTS CARD CREATION
        # First opponent
        unique_cards = set()
        while len(unique_cards) < 5:
            unique_cards.add(random.choice(all_cards))
        first_opponent_cards = list(unique_cards)
        # Second
        unique_cards = set()
        while len(unique_cards) < 5:
            unique_cards.add(random.choice(all_cards))
            second_opponent_cards = list(unique_cards)

        #CHECKING PHASE
        def checking_phase(cards):
            # dictionary for card values definition
            custom_value_order = {
                CardValues.Two : 2,
                CardValues.Three : 3,
                CardValues.Four : 4,
                CardValues.Five : 5,
                CardValues.Six : 6,
                CardValues.Seven : 7,
                CardValues.Eight : 8,
                CardValues.Nine : 9,
                CardValues.Ten : 10,
                CardValues.Jack : 11,
                CardValues.Queen : 12,
                CardValues.King : 13,
                CardValues.Ace : 14
                }  
            
            #Straight
            sorted_card_values = [custom_value_order[card.value] for card in cards]
            sorted_card_values.sort()
            is_straight = (max(sorted_card_values) - min(sorted_card_values) + 1) == len(cards)
            #Flush
            is_flush = len(set(card.suit for card in cards)) == 1
            #Straight Flush
            is_straight_flush = all([is_straight, is_flush])   # La funzione all() richiede un iterabile come argomento, come una lista, una tupla o un altro tipo di sequenza. Tuttavia, is_straight e is_flush sono valori booleani singoli, non un iterabile di valori, quindi bisogna usare le parentesi quadre per prenderli come singoli
                #oppure is_straight_flush = is_straight and is_flush     
            #Royal Flush
            max_straight = [CardValues.Ace, CardValues.King, CardValues.Queen, CardValues.Jack, CardValues.Ten]
            is_royal_flush = is_straight_flush and all(card.value in max_straight for card in cards)
            #Other combinations
            cards_values_only = [card.value for card in cards]
            cards_count = Counter(cards_values_only)
            counts = list(cards_count.values())
            counts.sort(reverse=True)
            High_Card, Pair, Two_Pair, Three_of_a_Kind, Straight, Flush, Full, Four_of_a_Kind, Straight_Flush, Royal_Flush = ("High Card", "Pair", "Two Pair", "Three of a Kind", "Straight", "Flush", "Full", "Four of a Kind", "Straight Flush", "Royal Flush")
            
            if is_royal_flush:
                return Royal_Flush
            elif is_straight_flush:
                return Straight_Flush
            elif counts == [4, 1]:
                return Four_of_a_Kind
            elif counts == [3, 2]:
                return Full
            elif is_flush:
                return Flush
            elif is_straight:
                return Straight
            elif counts == [3, 1, 1]:
                return Three_of_a_Kind
            elif counts == [2, 2, 1]:
                return Two_Pair
            elif counts == [2, 1, 1, 1]:
                return Pair
            else:
                return High_Card

        time.sleep(2)

        user_hand = checking_phase(cards)
        first_opponent_hand = checking_phase(first_opponent_cards)
        second_opponent_hand = checking_phase(second_opponent_cards)

        #SE AVVERSARI HANNO CARTA ALTA COME COMBINAZIONE, C'È UNA POSSIBILITÀ DEL 50% CHE CAMBINO TUTTE LE CARTE       
        if first_opponent_hand == "High Card":
            change_chance = ["yes", "no"]
            yes_or_no = random.choice(change_chance)
            if yes_or_no == "yes":
                unique_cards = set()
                while len(unique_cards) < 5:
                    unique_cards.add(random.choice(all_cards))
                first_opponent_cards = list(unique_cards)
                first_opponent_hand = checking_phase(first_opponent_cards)
        if second_opponent_hand == "High Card":
            yes_or_no = random.choice(change_chance)
            if yes_or_no == "yes":
                unique_cards = set()
                while len(unique_cards) <5:
                    unique_cards.add(random.choice(all_cards))
                second_opponent_cards = list(unique_cards)
                second_opponent_hand = checking_phase(second_opponent_cards)

        print(f"""
        Your hand: {user_hand}
        1st Opponent hand: {first_opponent_hand}            ( {", ".join(str(card) for card in first_opponent_cards)} )
        2nd Opponent hand: {second_opponent_hand}           ( {", ".join(str(card) for card in second_opponent_cards)} )   
            """)      
        
        #SCORE DASHBOARD
        players = [user_hand, first_opponent_hand, second_opponent_hand]
        scores = [0, 0, 0]
        # Determina il giocatore con la combinazione più alta
        max_hand_index = max(range(len(players)), key=lambda i: players[i])
        # Incrementa il punteggio del giocatore con la combinazione più alta
        scores[max_hand_index] += 1
        save_scores(scores)
        winning_player = ["You", "First opponent", "Second opponent"]
        if winning_player[max_hand_index] == "You":
            print("You won!")
        else:
            print(f"{winning_player[max_hand_index]} won. May you'll be luckier next time")

        score_phrase = """
        SCORE:          User: {}   |   First opponent: {}   |   Second opponent: {}   """
        print(score_phrase.format(scores[0], scores[1], scores[2]))

        time.sleep(5) 
        
        #CONTINUE PLAYING
        while True:        
            continue_playing = input("You want to keep playing? ")
            if continue_playing.lower() == "yes":
                wanna_shuffle = input("Wanna shuffle the deck? ")
                if wanna_shuffle.lower() == "yes":
                    shuffle(all_cards)
                    print("Deck shuffled")
                    break
                elif wanna_shuffle.lower() == "no":
                    break
                else:
                    continue
            elif continue_playing.lower() == "no":
                exit()
            score_reset = input("Want to maintain the score or reset it? ")
            if score_reset.lower() in ("reset", "reset it"):
                test_file = open("PokerScores.json", "w")
                test_file.write(json.dumps([0, 0, 0]))
                test_file.close()
                break
            elif score_reset.lower() in ("maintain", "maintain it"):
                break       
        start()   
                
    else:
        exit()
    
start()

Upvotes: 0

Views: 106

Answers (1)

Laura Montes
Laura Montes

Reputation: 193

Next time, it would be more helpful to put the error that you get instead of the whole code.

The issue you are getting is probably caused by the if condition in line 206. If the program enters that block without having entered the previous if block first, an error will occur because the variable change_chance is not set.

The solution is to set this variable outside the if-else structure like this:

...

    #SE AVVERSARI HANNO CARTA ALTA COME COMBINAZIONE, C'È UNA POSSIBILITÀ DEL 50% CHE CAMBINO TUTTE LE CARTE       
        change_chance = ["yes", "no"]
        if first_opponent_hand == "High Card":
            yes_or_no = random.choice(change_chance)
            if yes_or_no == "yes":
                unique_cards = set()
                while len(unique_cards) < 5:
                    unique_cards.add(random.choice(all_cards))
                first_opponent_cards = list(unique_cards)
                first_opponent_hand = checking_phase(first_opponent_cards)
        if second_opponent_hand == "High Card":
            yes_or_no = random.choice(change_chance)
            if yes_or_no == "yes":
                unique_cards = set()
                while len(unique_cards) <5:
                    unique_cards.add(random.choice(all_cards))
                second_opponent_cards = list(unique_cards)
                second_opponent_hand = checking_phase(second_opponent_cards)
...

Regarding the punctuation system, you are constantly overwriting the contents of PokerScores.json. I understand that you want to accumulate the scores until the user decides to reset, so you need to read the JSON file if it exists, sum the results and then write them back into the JSON file. Here is a way to do it:

def save_scores(score):
    import os
    filename = "PokerScores.json"
    old_score = None
    
    # We check if the file exists and if it is empty
    if os.path.exists(filename) and os.path.getsize(filename) > 0:
        # If it exists, we read the existing score
        with open(filename, 'r') as file:
            old_score = json.load(file)

    if old_score:
        # If there are previous scores, we make a sum of the previous and the new
        score = [existing + new for existing, new in zip(old_score, score)]
        
    # Write the scores back to the JSON file
    with open(filename, 'w') as file:
        json.dump(score, file)

You can add the import os line to the top of the file if you wish. Just remember to use the puntuation in the file each time you start the game so that the punctuation is shown correclty.

Another issue is that you load the scores but do not return them, so you should change your load_scores method, like this:

#LOAD SCORE
def load_scores():
    try:
        with open("PokerScores.json", "r") as file:
            return json.load(file)
    except FileNotFoundError:
        return [0, 0, 0]

Finally, if you don't want the scores to be overwritten each round, you have to remove the line that sets the scores back to 0 here:

        #SCORE DASHBOARD
        players = [user_hand, first_opponent_hand, second_opponent_hand]
        scores = [0, 0, 0]
        # Determina il giocatore con la combinazione più alta
        max_hand_index = max(range(len(players)), key=lambda i: players[i])
        # Incrementa il punteggio del giocatore con la combinazione più alta
        scores[max_hand_index] += 1
        save_scores(scores)

You could set the scores to [0,0,0] if the scores variable does not exist, with something similar to this (just a suggestion):

scores = [0, 0, 0] if not scores else scores

but you should play around until you find the behaviour you want.

Upvotes: 1

Related Questions