mercredi 26 avril 2023

ValueError: empty range for randrange() (0, 0, 0) | slider keeps returning 0 as a value Python Tkinter

So, I'm making a mine sweeper as a school project and I struggle through setting a settings window.

My biggest problem right now is that I have a slider which allows the player to change the size of the terrain by changing the number of rows and columns to one same number to then multiply them and have a terrain which is the square of the number received from the slider.

However, the slider does not seem to work in the way it is intended as he keeps sending back the value "0", as if he was never updating the value when moving the slider.

So I end up with the error :

  File "D:\MiniConda\lib\random.py", line 316, in randrange
    raise ValueError("empty range for randrange() (%d, %d, %d)" % (istart, istop, width))

ValueError: empty range for randrange() (0, 0, 0)

Here is my entire code, I put a commentary at the line where I believe the problem comes from :


from tkinter import *
from tkinter import ttk as ttk
import random
#module permettant l'importation d'images
from PIL import Image, ImageTk 
#module permettant la création de boutons avec plus de choix esthétiques
import customtkinter
#module permettant de fermer le programme
import sys


#Crée la fenêtre de prévention
def PreventionDemineur():

    preventionfenetre = Tk()    
    
    #Assigne pour titre à la fenêtre "Paramètres du Jeu du Démineur"
    preventionfenetre.title(" ATTENTION ") 

    #Affiche le texte de prévention avec ses caractéristiques
    TextePrevention = Label(preventionfenetre, text="Détails à lire !", font=("helvetica", 25, "bold"))
    
    #Gère la position du message de prévention
    TextePrevention.place(relx=0.5, rely=0.1, anchor=CENTER)

    #Affiche le texte de prévention avec ses caractéristiques
    ContenuPrevention = Label(preventionfenetre, text="- Prenez le temps de changer les paramètres du jeu, sinon \n il démarrera avec ses paramètres par défaut.", font=("helvetica", 10))
    
    #Gère la position du message de prévention
    ContenuPrevention.place(relx=0.5, rely=0.3, anchor=CENTER)
    
    #Change la taille afin que la fenêtre puisse tout afficher
    preventionfenetre.minsize(400, 400)
    preventionfenetre.maxsize(400, 400)
    
    #Place la fenêtre au centre de l'écran
    preventionfenetre.eval('tk::PlaceWindow . center')

    # Attend que la fenêtre se ferme pour continuer le code
    preventionfenetre.wait_window(preventionfenetre)
PreventionDemineur()
    
# Crée la fenêtre des paramètres du démineur
def parDemineur():

    parfenetre = Tk()    
    
    #Assigne pour titre à la fenêtre "Paramètres du Jeu du Démineur"
    parfenetre.title("Paramètres du Jeu du démineur") 
    
    #Image du démineur
    Pardemineursource = ImageTk.PhotoImage(master=parfenetre, file='ParDemineur.png')

    #Affiche l'image
    Pardemineurimg = Label(parfenetre, image = Pardemineursource)
    
    #Gère la position du message de prévention
    Pardemineurimg.pack()

    #Change la taille afin que la fenêtre puisse tout afficher
    parfenetre.minsize(400, 900)
    parfenetre.maxsize(400, 400)

    # Gère la création de la fenêtre avec sa largeur, sa hauteur, son fond)
    canvas = Canvas(parfenetre , width =750, height=500 , background='white')
    canvas.pack()
    
    #Place la fenêtre au centre de l'écran
    parfenetre.eval('tk::PlaceWindow . center')
    
    # Utilise CTkButton à la place du bouton de Tkinter, permettant plus de personnalisation. Le bouton une fois appuyé, permet de fermer la fenêtre des paramètres.
    boutonstart = customtkinter.CTkButton(master=parfenetre, text="Commencer à jouer !", font=("helvetica", 20, "bold"), command=parfenetre.destroy)
    
    #Situe le bouton dans la fenêtre ainsi que sa taille
    boutonstart.place(relx=0.5, rely=0.9,relheight=0.125, relwidth=0.3, anchor=CENTER)

    # Utilise CTkButton à la place du bouton de Tkinter, permettant plus de personnalisation. Le bouton une fois appuyé, permet de fermer la fenêtre des paramètres.
    boutonfermer = customtkinter.CTkButton(parfenetre, text="Quitter",fg_color="red", font=("helvetica", 20, "bold"), command=sys.exit)
    
    #Situe le bouton dans la fenêtre ainsi que sa taille
    boutonfermer.place(relx=0.94, rely=0.08,relheight=0.05, relwidth=0.08, anchor=CENTER)

    #Affiche le texte de prévention avec ses caractéristiques
    ContenuPar = Label(parfenetre, text="Choix de la taille du terrain", font=("helvetica", 10, "bold"))
 
    #Gère la position du message de difficulté
    ContenuPar.place(x=650, y=350, anchor=CENTER)   
    
    #THE PROBLEM STARTS BELOW THIS---------------------------------------------------------
    
 
    #Slider pour la taille du terrain
    # slider valeur actuelle
    valeur_actuelle = IntVar()


    def obtenir_valeur_actuelle():
        valeur = format(valeur_actuelle.get())
        return format(valeur_actuelle.get())


    def changement_slider(event):
        valeur_label.configure(text=obtenir_valeur_actuelle())


    # slider
    slider = ttk.Scale(parfenetre,from_=2,to=10,orient='horizontal',command=changement_slider,variable=valeur_actuelle)
    slider.place(x=650, y=375, anchor=CENTER) 


    # label du texte Valeur Actuelle
    valeur_actuelle_label = ttk.Label(parfenetre,text='Valeur Actuelle:')
    valeur_actuelle_label.place(x=650, y=425, anchor=CENTER) 
    
    # label de la valeur en elle même
    valeur_label = ttk.Label(parfenetre,text=obtenir_valeur_actuelle())
    valeur_label.place(x=700, y=425, anchor=CENTER) 
    valeur = int(obtenir_valeur_actuelle())
    print(valeur)
    
    
    
 
    #importation de l'image de défaite
    imagePerdant=Image.open("Game_Over.png") 

    #importation de l'image de victoire
    imageGagnant=Image.open("Victory.jpg") 

    #le terme miner veut dire creuser
    terrainMines = []   
    nombre_colonne = valeur
    nombre_ligne = valeur
    Blocs_miner =  0
    nombre_tnt = 5
    Blocs_à_miner = nombre_colonne * nombre_ligne - nombre_tnt
    nbr_col_ligne = nombre_colonne * nombre_ligne
 
    #Force la fenêtre à être ouverte en pleine écran
    parfenetre.attributes('-fullscreen', True)

    # Attend que la fenêtre se ferme pour continuer le code
    parfenetre.wait_window(parfenetre)

    #création du terrain miné

    # permet de creer une liste qui pour chaque bloc (rangée et colonne) entre des nombres aleatoires.
    def CreeTerrainMine(nombre_colonne, nombre_ligne): 
        terrainMines = [[0 for colonne in range(nombre_colonne)]for ligne in range(nombre_ligne)]
        TNT=[]
        while len(TNT)<nombre_tnt:
        
        
            # calcul un nombre aleatoire   
            n = random.randint(0,nbr_col_ligne-1) 
            if not n in TNT:
                TNT.append(n)
                ligne=n//nombre_ligne
                colonne=n% nombre_colonne
            
                # positionne la tnt
                terrainMines[ligne][colonne]="TNT" 
            
            #permet de calculer les tnt voisines
            for i in range (nombre_ligne):
                for j in range (nombre_colonne):
            
                    #on regarde les 8 cases voisines et on ajoute 1 car il y a une tnt 
                    if terrainMines[i][j]=="TNT":
                        for ii in range(i-1,i+2):
                     
                            #on ajoute 2 car le 2 est exclus du cadre
                            for jj in range(j-1,j+2): 
                                if 0<=ii<nombre_ligne and 0<jj<nombre_colonne and terrainMines[ii][jj]!="TNT":
                                    terrainMines[ii][jj]=terrainMines[ii][jj]+1
                        for iii in terrainMines:
                            print(iii)
        return terrainMines


    #action du boutton + Affichage des blocs sur l'écran
    def bouton(Cadre, terrainMines): 
        for nombre_Rangee in range(nombre_ligne):
            for nombre_colonnes in range(nombre_colonne):
                bloc = Button(Cadre, text=terrainMines[nombre_Rangee][nombre_colonnes], font=("Courier", 15),height=2, width=5, fg="#008737",bg="#008737", activebackground="#008737",activeforeground="#008737")  
                bloc.grid(row = nombre_Rangee, column = nombre_colonnes ) 
            
                #permet de lier la fonction boutonClic au clic gauche de la souris
                bloc.bind ("<Button-1>", Clic) 
                bloc.bind ("<Button-3>", Drapeau)    
    def Clic(event): 
        bouton = event.widget 
        Explosion(bouton)
    
    
    def Drapeau(event):
        bouton = event.widget
        Pose_Drapeau(bouton)


    
    def Pose_Drapeau(bouton):
        bouton.configure(disabledforeground="#153D3A",bg='#153D3A')
        if (bouton['state'] == "normal"):
            bouton['state'] = "disabled"
        else:
            bouton['state'] = "normal"
            bouton.configure(fg="#008737",bg='#008737')
 
    # avec les valeurs des blocs, cela cherche si le jeu doit continuer ou s'il doit s'arrêter
    def Explosion(bouton): 
    
        # permet de récupérer la valeur du bloc (le texte)
        valeurBouton = bouton.cget("text")  
    
        #affiche la valeur du bloc et une tnt est repéré 
        if (valeurBouton == "TNT"): 
    
            #change la couleur du bloc en rouge
            bouton.configure(fg="white",bg='#78020e')  
        
            # affichage de l'image de défaite
            imagePerdant.show()
            exit(1)
        
        # aucune tnt n'est repéré
        else:
    
            #permet de récupérer la couleur du texte du bloc
            couleurPolice = bouton.cget("fg")
        
            # si la couleur reste la meme cela veut dire que le bloc n'a pas été miné
            if (couleurPolice == '#008737'): 
            
                # l'instruction global informe que la variable qui est utilisée à l'intérieur de la fonction est la même que celle qui est définie à l'extérieur de la fonction
                global Blocs_miner 
             
                # augmente le nombre de clic
                Blocs_miner += 1 
             
                # change la couleur de la police afin de pouvoir voir le chiffre et change le fond du bloc pour montré que le bloc est miné
                bouton.configure(foreground="white",bg='#66370E')  
                # tous les blocs sans tnt sont creusés
                if (Blocs_miner == Blocs_à_miner): 
            
                    # affiche l'image de victoire
                    imageGagnant.show()
                    exit(0)
           
  
    def jouerDemineur():

        fenetre = Tk() 
        fenetre.eval('tk::PlaceWindow . center')
    
        #affiche un titre à la fenêtre
        fenetre.title("Jeu du démineur")  
    
        #Force la fenêtre à être ouverte en pleine écran
        fenetre.attributes('-fullscreen', True)
 
    
        #le widget frame est utile pour le regrouppement et l'organisation d'autres widget
        Cadre = Frame(fenetre, borderwidth=100, bg="#153D3A") 
        Cadre.pack(expand=1)
        terrainMine = CreeTerrainMine(nombre_colonne, nombre_ligne)
        bouton(Cadre,terrainMine)
        Cadre.bind('<Button-3>', Drapeau)
        
        # Utilise CTkButton à la place du bouton de Tkinter, permettant plus de personnalisation. Le bouton une fois appuyé, permet de fermer la fenêtre des paramètres.
        boutonfermer2 = customtkinter.CTkButton(master=fenetre, text="Quitter",fg_color="red", font=("helvetica", 20, "bold"), command=fenetre.destroy)
    
        #Gère la position du message de difficulté
        boutonfermer2.place(relx=0.95, rely=0.05, anchor=CENTER)

    jouerDemineur()

    fenetre.mainloop()

parDemineur()

When I got the error I tried to use print(valeur) to see what was wrong with it since this is the problematic value and that's when I saw that even when putting the slider at 10, it always returned me "0".

I tried searching in the code but I couldn't find anything.

I would be really grateful if someone could help me as I'm clearly no professionnal in python.




Aucun commentaire:

Enregistrer un commentaire