Comment ça on peut coder des IA qui apprennent en Python en 1ère ? C’est pas censé être un truc ultra pointu ? Eh bien en fait c’est relativement facile à faire pour des jeux aux règles simples comme l’Hexapawn.
Sommaire
- 1 Un Hexapawn, quésaco
- 2 Particularités du jeu
- 3 Commencer le projet : les Libraries nécessaires
- 4 Configuration de la fenêtre
- 5 Création des variables
- 6 Configuration des boites
- 7 Mise en place des Labels
- 8 Premières fonctions: fonctions de navigation
- 9 Personnalisation des couleurs
- 10 Mise en place du plateau de jeu
- 11 Les possibilités de déplacement
- 12 L’IA
- 13 Gagnant, perdant ou ex æquo
- 14 L’affichage
- 15 Captures d’écran
- 16 Articles similaires
Un Hexapawn, quésaco
Il s’agit d’un jeu d’échec miniature, qui se joue sur un plateau de jeu constitué de 9 cases (3×3), et dans lequel chaque joueur possède 3 pions – d’où le nom: hexa, six et pawn, pion en anglais.
Les règles du jeu sont simples: les pions se déplacent comme des pions d’échec:
- Ils ne se déplacent que d’une case à la fois et uniquement vers l’avant
- Ils ne peuvent manger qu’en diagonale, là aussi dans un rayon d’une case
Le but est de réussir à amener l’un de ses pions de l’autre côté du plateau ou d’éliminer la totalité des pions adverses.
Dans le cas ou aucun pion ne peut plus bouger, il y a égalité
Ce projet a été inspiré par une vidéo de Vsauce2, une chaîne présentant divers jeux ayant lien avec les mathématiques ou la logique.
Particularités du jeu
Comme les règles de l’Hexapawn sont très simples, il suffit simplement d’empêcher l’ordi de refaire des mouvements qui l’ont amené à perdre afin de le faire s’améliorer au fur et a mesure qu’il joue.
La principale difficulté dans la réalisation de ce projet a été de devoir prendre en compte toutes les possibilités de jeu, ce qui rend au final le script assez long.
En bonus, on s’est dit que ce serait sympa d’ajouter un menu afin de personnaliser les couleurs de l’interface
Commencer le projet : les Libraries nécessaires
Ce jeu a été entièrement codé en Python, et en Python, la première chose à faire lorsqu’on commence quelque chose est d’importer les Libraries (programmes externes) nécessaires pour sa réalisation.
#les différentes libraries nécessaires from tkinter import * import tkinter as tk from functools import partial from random import * import webbrowser
Les différentes libraries que nous avons choisi d’utiliser sont les suivantes :
- tkinter (abrégé de ToolKit Interface) qui permet de créer une interface graphique,
- la fonction partial de la library functools, qui va nous être utile lors de la création des différents boutons,
- random, qui va permettre d’ajouter de l’aléatoire dans certaines actions,
- webbrowser, qui va permettre d’ouvrir des pages web.
Maintenant que l’on a importé tous les modules nécessaires, on va pouvoir commencer à coder le projet en lui-même.
Configuration de la fenêtre
Comme l’on utilise tkinter afin de pouvoir donner une interface graphique à notre jeu, on va commencer par configurer notre fenêtre (taille, titre, couleur de fond etc…)
couleur = "#424242" #mise en place de la fenêtre window = Tk() window.title("♟ Hexapawn ♟") window.geometry("1080x720") window.config(bg=couleur)
Ici on a donc une fenêtre de couleur grise, dont le titre est « ♟ Hexapawn ♟ » et dont la taille est de 1080 x 720 pixels
Création des variables
Une fois la fenêtre créée, on configure les variables qui seront utilisées par le script (le nombre de points de chacun, l’état des cases -vides au début-, les différentes variables à afficher…)
#définition de certaines variables couleur_texte = "#666666" couleur_selection = "#cccccc" couleur_ordi = "#000000" couleur_joueur = "#ffffff" tour = 0 pions_joueur = 3 pions_ordi = 3 pions_bloques = 0 resultat = "" coups_perdants = [] coups_gagnants = [] jeu = "" a1 = "" a2 = "" a3 = "" b1 = "" b2 = "" b3 = "" c1 = "" c2 = "" c3 = "" ordi_gagne = False joueur_gagne = False egalite = False points_ordi = 0 points_joueur = 0
Tkinter ne peut pas afficher des variables classiques dans les fenêtres, c’est pourquoi il est nécessaire de créer des variables spéciales que l’on déclare comme ceci :
#définition des variables qui seront affichées dans l'interface tkinter a1_display = tk.StringVar() a2_display = tk.StringVar() a3_display = tk.StringVar() b1_display = tk.StringVar() b2_display = tk.StringVar() b3_display = tk.StringVar() c1_display = tk.StringVar() c2_display = tk.StringVar() c3_display = tk.StringVar() resultat_display = tk.StringVar() score_ordi_display = tk.IntVar() score_joueur_display = tk.IntVar() valeur = tk.StringVar() contour_texte = tk.StringVar() contour_texte.set(''' ⎟ ⎟ ⎟ ⎟ ⎟ ⎟ ⎟ ⎟ ⎟ ⎟ ⎟ ⎟ ''')
Comme la majorité de ces variables tkinter sont associées à des variables classiques, nous avons décidé d’ajouter « _display » à la fin de leur nom pour pouvoir plus facilement les différencier.
Par exemple, la variable a1 sera associée à la variable tkinter a1_display qui sera actualisée dans le script à chaque fois que a1 change de valeur
Configuration des boites
Maintenant on crée les différentes boites. Elles permettront d’afficher les différents éléments qu’elles contiennent quand elles seront appelées (la boite menu, règle etc…) ou de ne plus les afficher lorsqu’elles seront oubliées.
#mise en place des différentes boites boite_titre = Frame(window, bg=couleur) boite_menu = Frame(window, bg=couleur) boite_regles = Frame(window, bg=couleur) boite_jeu = Frame(window, bg=couleur) boite_ordi = Frame(window, bg=couleur) boite_resultat = Frame(window, bg=couleur) boite_couleurs = Frame(window, bg=couleur) boite_couleurs2 = Frame(window, bg=couleur)
Mise en place des Labels
Afin d’avoir une interface claire, il est important d’ajouter des éléments textuels: titre, règles du jeu etc.
Dans tkinter, les éléments textuels sont nommés labels. On les déclare comme ceci:
#mise en place des différents éléments textuels titre = Label(boite_titre, text = ''' .----------------. .----------------. .----------------. .----------------. .----------------. .----------------. .----------------. .-----------------. | .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. | | | ____ ____ | || | _________ | || | ____ ____ | || | __ | || | ______ | || | __ | || | _____ _____ | || | ____ _____ | | | | |_ || _| | || | |_ ___ | | || | |_ _||_ _| | || | / \ | || | |_ __ \ | || | / \ | || ||_ _||_ _|| || ||_ \|_ _| | | | | | |__| | | || | | |_ \_| | || | \ \ / / | || | / /\ \ | || | | |__) | | || | / /\ \ | || | | | /\ | | | || | | \ | | | | | | | __ | | || | | _| _ | || | > `' < | || | / ____ \ | || | | ___/ | || | / ____ \ | || | | |/ \| | | || | | |\ \| | | | | | _| | | |_ | || | _| |___/ | | || | _/ /'`\ \_ | || | _/ / \ \_ | || | _| |_ | || | _/ / \ \_ | || | | /\ | | || | _| |_\ |_ | | | | |____||____| | || | |_________| | || | |____||____| | || ||____| |____|| || | |_____| | || ||____| |____|| || | |__/ \__| | || ||_____|\____| | | | | | || | | || | | || | | || | | || | | || | | || | | | | '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' | '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' ''', font=("consolas",7), bg = couleur, fg = couleur_texte) sep = Label(boite_titre, text = "."*200, font=("consolas",7), bg = couleur, fg = couleur_texte) regles_label = Label(boite_regles, text = ''' Regles du jeu: Vous possédez 3 pions, qui peuvent se déplacer comme des pions aux échecs: -ils ne peuvent que se déplacer vers l'avant -ils ne peuvent se déplacer que d'une case à la fois -ils ne peuvent "manger" un pion adverse qu'en diagonale 2 conditions de victoire possibles: -l'adversaire ne possède plus aucun pion -vous parvenez à amener un pion à l'autre bout du plateau Pour déplacer un pion, cliquez sur lui puis sur la case vers laquelle vous voulez qu'il aille. Lorsque vous avez joué, cliquez sur le bouton sous l'échéquier ''' , font=("consolas",15), bg = couleur, fg = couleur_texte) resultat_Label = Label(boite_resultat, text = "", font=("consolas",15), bg = couleur, fg = couleur_texte) scores = Label(boite_resultat, text = "%s à %s" %(score_joueur_display.get(),score_ordi_display.get()), font=("consolas",15), bg = couleur, fg = couleur_texte) retour_selection = Label(boite_couleurs, text = "", font=("consolas",10), bg = couleur, fg = couleur_texte) contour1 = Label(boite_menu, text = contour_texte.get(), font=("consolas",7), bg = couleur, fg = couleur_texte) contour2 = Label(boite_menu, text = contour_texte.get(), font=("consolas",7), bg = couleur, fg = couleur_texte) contour3 = Label(boite_menu, text = contour_texte.get(), font=("consolas",7), bg = couleur, fg = couleur_texte) contour4 = Label(boite_menu, text = contour_texte.get(), font=("consolas",7), bg = couleur, fg = couleur_texte) contour5 = Label(boite_menu, text = contour_texte.get(), font=("consolas",7), bg = couleur, fg = couleur_texte) contour6 = Label(boite_menu, text = contour_texte.get(), font=("consolas",7), bg = couleur, fg = couleur_texte)
Pour le titre, nous avons décidé de l’écrire en ASCII à l’aide de ce générateur
Chaque Label possède plusieurs attributs: la boîte dans lequel il va apparaître, le texte qu’il contient, la police et la taille d’écriture, la couleur de fond et enfin la couleur de l’écriture.
Comme vous pouvez le constater, certains de ces Labels font appel à des variables tkinter qui nous avons précédemment définies comme celui-ci par exemple:
scores = Label(boite_resultat, text = "%s à %s" %(score_joueur_display.get(),score_ordi_display.get()), font=("consolas",15), bg = couleur, fg = couleur_texte)
Pour appeler ces variables, il suffit d’écrire leur nom suivi de .get()
Maintenant que l’on a défini les éléments texte, on va pouvoir s’attaquer aux différentes fonctions du script.
Comme l’on a décidé d’utiliser une ineterface graphique pour ce projet, la plupart des fonctions seront appelées à l’aide de boutons.
#commande permettant d'afficher les règles du jeu def command_regles(): boite_menu.pack_forget() boite_regles.pack(pady = 25)
Cette fonction par exemple permettra d’afficher les règles du jeu. Il suffit d’ajouter .pack() à la fin du nom d’une boite pour la faire apparaître, et .pack_forget() pour la faire disparaître.
Ainsi, lorsque cette fonction sera appelée, les éléments de la boite_menu disparaîtront pour laisser place à ceux de la boite_regles
Cette fonction sera associée à un bouton de la manière suivante :
b_regles = Button(boite_menu, text = "Règles du jeu", font = ("consolas", 15), bg = couleur_texte, fg = couleur, command = command_regles)
On créé un nouvel élément nommé b_regles: un bouton (Button) à qui on donne différents attributs: une boite, un texte, une police et une taille, une couleur de fond, une couleur de texte, et surtout une fonction (l’attribut command) qui sera appelée en cas de clic.
Lorsque l’on cliquera sur ce bouton, la fonction command_regles sera exécutée, ce qui aura pour effet d’afficher les règles du jeu.
On procède de même avec les autres fonctions qui vont nous permettre de naviguer dans notre fenêtre :
#commande pour retourner au menu depuis les règles def command_retour_regles(): boite_menu.pack(pady = 25) boite_regles.pack_forget() #commande pour afficher le menu de personnalisation des couleurs def command_personnaliser(): boite_menu.pack_forget() boite_couleurs.pack(pady = 25) boite_couleurs2.pack() #commande pour retourner au menu principal depuis celui de personnalisation des couleurs def command_retour_personnaliser(): boite_menu.pack(pady = 25) boite_couleurs.pack_forget() boite_couleurs2.pack_forget()
Ainsi qu’avec leurs boutons respectifs
b_retour_regles = Button(boite_regles, text = "Retour", font = ("consolas", 15), bg = couleur_texte, fg = couleur, command = command_retour_regles) b_personnaliser = Button(boite_menu, text = "Personnaliser", font = ("consolas", 15), bg = couleur_texte, fg = couleur, command = command_personnaliser) b_retour_personnaliser = Button(boite_couleurs2, text = "Retour", font = ("consolas", 15), bg = couleur_texte, fg = couleur, command = command_retour_personnaliser)
Personnalisation des couleurs
Grâce au menu de personnalisation des couleurs, les utilisateurs du script pourront choisir les couleurs qui leur plait ainsi créant des mélanges uniques.
Ce menu est constitué de plusieurs boutons :
b_couleur1 = Button(boite_couleurs2, text = "Changer la couleur principale ", font = ("consolas", 15), bg = couleur_texte, fg = couleur, command = partial(changer_couleur,0)) b_couleur2 = Button(boite_couleurs2, text = "Changer la couleur secondaire ", font = ("consolas", 15), bg = couleur_texte, fg = couleur, command = partial(changer_couleur,1)) b_couleur3 = Button(boite_couleurs2, text = "Changer la couleur de selection", font = ("consolas", 15), bg = couleur_texte, fg = couleur, command = partial(changer_couleur,2)) b_couleur_joueur = Button(boite_couleurs2, text = " Changer la couleur du joueur ", font = ("consolas", 15), bg = couleur_texte, fg = couleur, command = partial(changer_couleur,3)) b_couleur_ordi = Button(boite_couleurs2, text = " Changer la couleur de l'ordi ", font = ("consolas", 15), bg = couleur_texte, fg = couleur, command = partial(changer_couleur,4)) b_personnaliser = Button(boite_menu, text = "Personnaliser", font = ("consolas", 15), bg = couleur_texte, fg = couleur, command = command_personnaliser) couleur_entry = Entry(boite_couleurs, text = "#", textvariable=valeur, font=("Helvetica",15) , bg="white", fg="black") b_ok = Button(boite_couleurs, text = "Cliquez pour appliquer", font = ("consolas", 15), bg = couleur_texte, fg = couleur, command = rien)
C’est ici que la fonction partial que nous avons importée va nous être utile: en effet, tous les boutons de ce menu vont exécuter la même fonction, mais avec un paramètre différent, ce qui nous permet de n’écrire qu’une seule fonction au lieu de 5 différentes.
def changer_couleur(test): b_ok.config(command = partial(appliquer,test)) if test == 0: retour_selection.config(text = "couleur principale") elif test == 1: retour_selection.config(text = "couleur secondaire") elif test == 2: retour_selection.config(text = "couleur de sélection") elif test == 3: retour_selection.config(text = "couleur du joueur") elif test == 4: retour_selection.config(text = "couleur de l'ordi") def appliquer(test): global couleur, couleur_texte, couleur_selection, couleur_joueur, couleur_ordi if test == 0: couleur = str(valeur.get()) elif test == 1: couleur_texte = str(valeur.get()) elif test == 2: couleur_selection = str(valeur.get()) elif test == 3: couleur_joueur = str(valeur.get()) elif test == 4: couleur_ordi = str(valeur.get()) window.config(bg = couleur) titre.config(bg = couleur, fg = couleur_texte) sep.config(bg = couleur, fg = couleur_texte) boite_titre.config(bg = couleur) boite_menu.config(bg = couleur) boite_regles.config(bg = couleur) boite_jeu.config(bg = couleur) boite_ordi.config(bg = couleur) boite_resultat.config(bg = couleur) boite_couleurs.config(bg = couleur) boite_couleurs2.config(bg = couleur) b_a1.config(bg = couleur_texte) b_a2.config(bg = couleur) b_a3.config(bg = couleur_texte) b_b1.config(bg = couleur) b_b2.config(bg = couleur_texte) b_b3.config(bg = couleur) b_c1.config(bg = couleur_texte) b_c2.config(bg = couleur) b_c3.config(bg = couleur_texte) b_jouer.config(bg = couleur_texte, fg = couleur) b_regles.config(bg = couleur_texte, fg = couleur) b_retour_regles.config(bg = couleur_texte, fg = couleur) b_personnaliser.config(bg = couleur_texte, fg = couleur) b_retour_personnaliser.config(bg = couleur_texte, fg = couleur) b_couleur1.config(bg = couleur_texte, fg = couleur) b_couleur2.config(bg = couleur_texte, fg = couleur) b_couleur3.config(bg = couleur_texte, fg = couleur) b_couleur_ordi.config(bg = couleur_texte, fg = couleur) b_couleur_joueur.config(bg = couleur_texte, fg = couleur) b_rejouer.config(bg = couleur_texte, fg = couleur) b_ordi.config(bg = couleur_texte, fg = couleur) b_trouver_hex.config(bg = couleur_texte, fg = couleur) b_ok.config(bg = couleur_texte, fg = couleur) regles_label.config(bg = couleur, fg = couleur_texte) b_retour_jeu.config(bg = couleur_texte, fg = couleur) scores.config(bg = couleur, fg = couleur_texte) resultat_Label.config(bg = couleur, fg = couleur_texte) retour_selection.config(bg = couleur, fg = couleur_texte) contour1.config(bg = couleur, fg = couleur_texte) contour2.config(bg = couleur, fg = couleur_texte) contour3.config(bg = couleur, fg = couleur_texte) contour4.config(bg = couleur, fg = couleur_texte) contour5.config(bg = couleur, fg = couleur_texte) contour6.config(bg = couleur, fg = couleur_texte)
Lorsque le bouton « Cliquez pour appliquer » est cliqué la fonction appliquer est exécutée avec un paramètre différent en fonction du bouton sélectionné auparavant.
La fonction change la couleur demandée puis rafraîchit tous les éléments différents afin que le changement de couleur apparaisse.
Il est à noter que le script ne comprend que certains noms de couleur en anglais ou les couleurs données en hexadécimal
Ce menu comporte aussi un bouton permettant d’ouvrir une page web avec un panneau pour sélectionner la couleur de son choix et avoir son code en hexadécimal :
b_trouver_hex = Button(boite_couleurs2, text = " Trouver des couleurs ", font = ("consolas", 15), bg = couleur_texte, fg = couleur, command = pick_hex)
L’ouverture de la page depuis le script est faite grâce a la Library webbrowser
def pick_hex(): webbrowser.open_new("https://www.google.com/search?client=opera-gx&q=color+picker&sourceid=opera&ie=UTF-8&oe=UTF-8")
Mise en place du plateau de jeu
Après avoir lu les règles du jeu et modifié les couleurs si nécessaire on peut enfin jouer.
En cliquant sur le bouton jouer on exécute la commande suivante :
def command_jouer(): boite_resultat.pack_forget() boite_jeu.pack(pady = 25) boite_ordi.pack(pady = 25) boite_menu.pack_forget() global a1 , a2 , a3 , b1 , b2 , b3 , c1 , c2 , c3 , pions_ordi, pions_joueur, pions_bloques, ordi_gagne, egalite, joueur_gagne, tour, couleur_ordi, couleur_joueur, jeu jeu = "" a1 , a2 , a3 , b1 , b2 , b3 , c1 , c2 , c3 = "♟" , "♟" , "♟" , " " , " " , " " , "♙" , "♙" , "♙" a1_display.set(a1) a2_display.set(a2) a3_display.set(a3) b1_display.set(b1) b2_display.set(b2) b3_display.set(b3) c1_display.set(c1) c2_display.set(c2) c3_display.set(c3) b_a1.config(text = a1_display.get(), fg = couleur_ordi) b_a2.config(text = a2_display.get(), fg = couleur_ordi ) b_a3.config(text = a3_display.get(), fg = couleur_ordi ) b_b1.config(text = b1_display.get() ) b_b2.config(text = b2_display.get() ) b_b3.config(text = b3_display.get() ) b_c1.config(text = c1_display.get(), fg = couleur_joueur ) b_c2.config(text = c2_display.get(), fg = couleur_joueur ) b_c3.config(text = c3_display.get(), fg = couleur_joueur ) pions_ordi = 3 pions_joueur = 3 pions_bloques = 0 joueur_gagne = False ordi_gagne = False egalite = False tour = 0 tester_cases_selectionnables()
Elle permet de mettre en place le plateau de jeu en faisant apparaître les boites boite_jeu et boite_ordi et en faisant disparaître les autres.
Ensuite les pions sont placés sur le plateau et le compteur de tours, et ceux des pions sont mis à leurs valurs initiales
Enfin, le script teste les cases à partir desquelles l’on peut bouger nos pions à l’aide de la fonction tester_cases_selectionnables().
Les possibilités de déplacement
La fonction « tester_cases_selectionnables() » teste les cases sur lesquels se trouve les pions du joueur et permet au joueur de cliquer le bouton si jamais un de ses pions y est présent.
def tester_cases_selectionnables(): if c1 == "♙": b_c1.config(command = partial(selected,"c1"), fg = couleur_joueur ) if c2 == "♙": b_c2.config(command = partial(selected,"c2"), fg = couleur_joueur ) if c3 == "♙": b_c3.config(command = partial(selected,"c3"), fg = couleur_joueur ) if b1 == "♙": b_b1.config(command = partial(selected,"b1"), fg = couleur_joueur ) if b2 == "♙": b_b2.config(command = partial(selected,"b2"), fg = couleur_joueur ) if b3 == "♙": b_b3.config(command = partial(selected,"b3"), fg = couleur_joueur )
Ensuite, selon la case sélectionnée le script étudie les mouvements possibles et modifie les commandes éxécutées en cas de clic sur la case en conséquence :
def selected(case): global a1, a2, a3, b1, b2, b3, c1, c2, c3 global tour if tour == 0 : if case == "c1": b_b1.config(command = partial(jouer_vers,"c1","b1")) b_b2.config( command = rien) b_b3.config(command = rien) b_c1.config(fg=couleur_selection) b_c2.config(fg=couleur_joueur) b_c3.config(fg=couleur_joueur) b_b2.config(command = rien) b_b3.config(command = rien) elif case == "c2": b_b2.config(command = partial(jouer_vers,"c2","b2")) b_c2.config(fg=couleur_selection) b_c1.config(fg=couleur_joueur) b_c3.config(fg=couleur_joueur) b_b1.config(command = rien) b_b3.config(command = rien) #et ainsi de suite avec les autres cases elif tour >= 2: if case == "c1": reset_commandes() tester_cases_selectionnables() b_c1.config(fg=couleur_selection) if b1 == " ": b_b1.config(command = partial(jouer_vers,"c1","b1")) if b2 == "♟": b_b2.config(command = partial(jouer_vers,"c1","b2")) elif case == "c2": reset_commandes() tester_cases_selectionnables() b_c2.config(fg=couleur_selection) if b2 == " ": b_b2.config(command = partial(jouer_vers,"c2","b2")) if b1 == "♟": b_b1.config(command = partial(jouer_vers,"c2","b1")) if b3 == "♟": b_b3.config(command = partial(jouer_vers,"c2","b3")) #etc...
Après avoir choisi le pion qu’il souhaitait déplacer, le joueur va cliquer sur la case vers laquelle il veut que le pion se déplace.
La fonction jouer_vers va alors être exécutée avec en paramètres la case de départ et la case d’arrivée du pion.
La fonction va rendre vide la case de départ du pion et va mettre un pion blanc dans la case d’arrivée
def jouer_vers(case1, case2): global tour, jeu global a1, a2, a3, b1, b2, b3, c1, c2, c3 global pions_ordi, ordi_gagne if tour / 2 == tour // 2 and not ordi_gagne: if case1 == "c1": c1 = " " c1_display.set(c1) b_c1.config(text = c1_display.get()) elif case1 == "c2": c2 = " " c2_display.set(c2) b_c2.config(text = c2_display.get()) #etc... if case2 == "b1": if b1 == "♟": pions_ordi -= 1 b1 = "♙" b1_display.set(b1) b_b1.config(text = b1_display.get(), fg = couleur_joueur) jeu += case2 elif case2 == "b2": if b2 == "♟": pions_ordi -= 1 b2 = "♙" b2_display.set(b2) b_b2.config(text = b2_display.get(), fg = couleur_joueur) jeu += case2 #etc...
Si le joueur a réussi à amener l’un de ses pions de l’autre côté, il gagne un point et le résultat de la partie est affiché avec les scores.
Sinon, c’est à l’ordi de jouer.
elif case2 == "a3": a3 = "♙" a3_display.set(a3) b_a3.config(text = a3_display.get(), fg = couleur_joueur) joueur_gagne = True coups_perdants.append(jeu) tour += 1 if pions_joueur == 0: ordi_gagne = True if ordi_gagne : boite_jeu.pack_forget() resultat = "Défaite" resultat_display.set(resultat) resultat_Label.config(text = resultat_display.get()) boite_resultat.pack() else: pass
L’IA
Les mouvements possible de l’ordinateur sont étudiés par la fonction « ordi() ».
#début de la fonction ordi() def ordi(): global tour global a1, a2, a3, b1, b2, b3, c1, c2, c3 global pions_joueur, points_joueur, ordi_gagne, points_ordi, pions_ordi, joueur_gagne, pions_bloques, resultat, egalite, coups_gagnants, coups_perdants, jeu, couleur_ordi
Elle étudie tout d’abord si il y a un vainqueur ou une égalité ( grâce à la fonction « tester_tie() » expliquée un peu plus plus loin ) .
if pions_ordi == 0: joueur_gagne = True if pions_joueur == 0: ordi_gagne = True tester_tie() if pions_bloques == pions_ordi: egalite = Tr
Si il n’y a pas de vainqueur ou d’égalité et que c’est au tour de l’ordi de jouer, le script analyse les mouvements possibles de l’ordinateur. si il s’aperçoit qu’un mouvement l’a amené à perdre dans une configuration similaire, il ne l’inclura pas dans la liste des mouvements possibles.
Si, au contraire un des mouvements l’a fait gagner précédemment, il le mettra dans une liste spéciale
elif tour/2 != tour//2 and not joueur_gagne and not ordi_gagne : mvt_possibles = [] mvt_gagnants = [] if a1 == "♟": if b1 == " " and jeu + "a1b1" not in coups_perdants : mvt_possibles.append("a1b1") if jeu + "a1b1" in coups_gagnants: mvt_gagnants.append("a1b1") if b2 == "♙" and jeu + "a1b2" not in coups_perdants: mvt_possibles.append("a1b2") if jeu + "a1b2" in coups_gagnants: mvt_gagnants.append("a1b2") if a2 == "♟": if b1 == "♙" and jeu + "a2b1" not in coups_perdants : mvt_possibles.append("a2b1") if jeu + "a2b1" in coups_gagnants: mvt_gagnants.append("a2b1") if b2 == " " and jeu + "a2b2" not in coups_perdants: mvt_possibles.append("a2b2") if jeu + "a2b2" in coups_gagnants: mvt_gagnants.append("a2b2") if b3 == "♙" and jeu + "a2b3" not in coups_perdants: mvt_possibles.append("a2b3") if jeu + "a2b3" in coups_gagnants: mvt_gagnants.append("a2b3") #et ainsi de suite avec toutes les cases...
Ensuite, la fonction teste si des mouvements possibles peuvent amener l’ordi à gagner à coup sûr. Si c’est le cas, un mouvement aléatoire est pioché parmi la liste mvt_gagnants.
Sinon, l’ordi choisit un mouvement aléatoire parmi les mouvements possibles.
if mvt_gagnants != []: mvt_ordi = mvt_gagnants[randint(0,len(mvt_gagnants)-1)] else: mvt_ordi = mvt_possibles[randint(0,len(mvt_possibles)-1)]
Le mouvement choisi est ensuite « joué »
if mvt_ordi == "a1b1": a1 = " " a1_display.set(a1) b_a1.config(text = a1_display.get()) b1 = "♟" b1_display.set(b1) b_b1.config(text = b1_display.get(), fg = couleur_ordi) elif mvt_ordi == "a1b2": a1 = " " a1_display.set(a1) b_a1.config(text = a1_display.get()) b2 = "♟" b2_display.set(b2) b_b2.config(text = b2_display.get(), fg = couleur_ordi) pions_joueur -= 1 #etc... elif mvt_ordi == "b1c1": b1 = " " b1_display.set(b1) b_b1.config(text = b1_display.get()) c1 = "♟" c1_display.set(c1) b_c1.config(text = c1_display.get(), fg = couleur_ordi) ordi_gagne = True
Le coup joué est ensuite ajouté à la variable jeu.
Si le mouvement amène l’ordi à prendre un pion, le nombre de pions du joueur est décrémenté de 1
Si l’ordi a amené l’un de ses pions de l’autre côté, la variable ordi_gagne devient « vraie » (True)
jeu += mvt_ordi
Si l’ordi a gagné, c’est à dire si ordi_gagne est True, son score est incrémenté, la variable « jeu » est ajouté à la liste des coups gagnants et le score ainsi que le résultat de la partie sont affichés
if ordi_gagne: coups_gagnants.append(jeu) reset_commandes() boite_ordi.pack_forget() points_ordi += 1 resultat = "Défaite" resultat_display.set(resultat) resultat_Label.config(text = resultat_display.get()) score_ordi_display.set(points_ordi) score_joueur_display.set(points_joueur) scores.config(text = "%s à %s" %(score_joueur_display.get(), score_ordi_display.get()) ) boite_resultat.pack()
Ensuite, on passe au tour suivant.
Si le joueur avait déjà gagné au début du tour (l’ordi n’a donc pas joué) ou s’il y a égalité le score est incrémenté en conséquence et l’issue de la partie est affichée
Si aucune de ces conditions n’est vérifiées, c’est au tour du joueur de jouer.
tour +=1 reset_commandes() tester_cases_selectionnables() tester_tie() if pions_bloques == pions_ordi: egalite = True if egalite: reset_commandes() boite_ordi.pack_forget() resultat = "Egalité" resultat_display.set(resultat) resultat_Label.config(text = resultat_display.get()) boite_resultat.pack() elif joueur_gagne: coups_perdants.append(jeu) reset_commandes() boite_ordi.pack_forget() points_joueur += 1 resultat = "Victoire" resultat_display.set(resultat) resultat_Label.config(text = resultat_display.get()) score_ordi_display.set(points_ordi) score_joueur_display.set(points_joueur) scores.config(text = "%s à %s" %(score_joueur_display.get(), score_ordi_display.get()) ) boite_resultat.pack() else: pass
Gagnant, perdant ou ex æquo
Plisieurs conditions peuvent mettre fin à la partie
- Le joueur ou l’ordi amène l’un de ses pions de l’autre côté du plateau
- le joueur ou l’ordi ne possèdent plus de pions
- Tous les pions sont bloqués
Les deux premières conditions sont facilement vérifiables et sont déjà testées directement dans les fonctions ordi() et jouer_vers()
On teste donc s’il y a égalité à l’aide de la fonction tester_tie(), appelée à l’interieur de la fonction ordi() comme vu précédemment.
Cette fonction teste tout simplement pour chaque case si le pion présent n’a plus de possibilités de mouvement, et ajoute au compteur de pions bloqués 1 si jamais le pion ne peut plus bouger.
def tester_tie(): global a1, a2, a3, b1, b2, b3, c1, c2, c3, pions_bloques pions_bloques = 0 if a1 == "♟": if b1 == "♙": if b2 == "♟" or b2 == " ": pions_bloques += 1 else: pass else: pass if a2 == "♟": if b2 == "♙": if b1 == "♟" or b1 == " ": if b3 == "♟" or b3 == " ": pions_bloques += 1 else: pass else: pass else: pass if a3 == "♟": if b3 == "♙": if b2 == "♟" or b2 == " ": pions_bloques += 1 else: pass else: pass if b1 == "♟": if c1 == "♙": if c2 == "♟" or c2 == " ": pions_bloques += 1 else: pass else: pass if b2 == "♟": if c2 == "♙": if c1 == "♟" or c1 == " ": if c3 == "♟" or c3 == " ": pions_bloques += 1 else: pass else: pass else: pass if b3 == "♟": if c3 == "♙": if c2 == "♟" or c2 == " ": pions_bloques += 1 else: pass else: pass
Si jamais tous les pions de l’ordi sont bloqués il y a égalité
if pions_bloques == pions_ordi: egalite = True if egalite: reset_commandes() boite_ordi.pack_forget() resultat = "Egalité" resultat_display.set(resultat) resultat_Label.config(text = resultat_display.get()) boite_resultat.pack()
L’affichage
Maintenant que toutes les fonction sont définies, il faut afficher tous les différents éléments de la fenêtre:
titre.pack() sep.pack() contour1.grid(row = 0, column = 1 , sticky = W, padx = 100, pady = 0) contour2.grid(row = 1, column = 1 , sticky = W, padx = 100, pady = 0) contour3.grid(row = 2, column = 1 , sticky = W, padx = 100, pady = 0) b_jouer.grid(row = 0, column = 2 , sticky = W, pady = 0) b_regles.grid(row = 1, column = 2 , sticky = W, pady = 0) b_personnaliser.grid(row = 2, column = 2 , sticky = W, pady = 0) contour4.grid(row = 0, column = 3 , sticky = W, padx = 100, pady = 0) contour5.grid(row = 1, column = 3 , sticky = W, padx = 100, pady = 0) contour6.grid(row = 2, column = 3 , sticky = W, padx = 100, pady = 0) regles_label.pack() b_retour_regles.pack() b_a1.grid(row = 0, column = 0, sticky = W) b_a2.grid(row = 0, column = 1, sticky = W) b_a3.grid(row = 0, column = 2, sticky = W) b_b1.grid(row = 1, column = 0, sticky = W) b_b2.grid(row = 1, column = 1, sticky = W) b_b3.grid(row = 1, column = 2, sticky = W) b_c1.grid(row = 2, column = 0, sticky = W) b_c2.grid(row = 2, column = 1, sticky = W) b_c3.grid(row = 2, column = 2, sticky = W) b_ordi.pack(pady = 15) b_retour_jeu.pack(pady = 15) resultat_Label.pack(pady = 15) scores.pack(pady = 15) b_rejouer.pack(pady = 15) boite_titre.pack() boite_menu.pack(pady = 25) retour_selection.pack(pady = 10) couleur_entry.pack(pady = 15) b_ok.pack(pady = 10) b_couleur1.grid(row = 0, column = 0, sticky = W, pady = 5, padx = 5) b_couleur2.grid(row = 0, column = 1, sticky = W, pady = 5, padx = 5) b_couleur3.grid(row = 0, column = 2, sticky = W, pady = 5, padx = 5) b_couleur_joueur.grid(row = 1, column = 0, sticky = W, pady = 5, padx = 5) b_couleur_ordi.grid(row = 1, column = 1, sticky = W, pady = 5, padx = 5) b_trouver_hex.grid(row = 1, column = 2, sticky = N, pady = 5, padx = 5) b_retour_personnaliser.grid(row = 2, column = 1, sticky = N, pady = 10, padx = 5)
Et surtout ne pas oublier d’ouvrir la fenêtre en cas d’exéction du script
window.mainloop()
Captures d’écran
Si vous souhaitez vous mesurer à cette IA et vérifier qu’elle apprend bel et bien de ses erreurs, vous pourrez télécharger le script du projet (défi : dépasser un score de 17!).
Cet article a été écrit par des élèves du lycée Louis Pasteur.
Ils étudiaient alors la spécialité NSI, en classe de 1ère.
Promotion 2021 – 2021