Besoin d'aide pour un jeu "Morpion" en python

a marqué ce sujet comme résolu.

Bonjour, je suis actuellement en première et je dois programmer un morpion en python. J’ai quasiment fini mais je n’arrive pas à faire terminer le jeu, il continue malgré les fonctions qui permettent d’y mettre fin. J’ai également reçu de l’aide de mon professeur qui m’a donné des pistes, mais je n’arrive toujours pas à voir la faute. ( ci-joint le message de mon professeur et le code ).

PS : Les commentaires sont en anglais car je travaille avec une anglophone.`py

#import
import random
import sys
#grid declaration
line1 =["00","01","02"]
line2 =["10","11","12"]
line3 =["20","21","22"]
grid=[line1, line2, line3]
#function to show the grid
def showGrid() :
    print(line1[0], line1[1], line1[2])
    print(line2[0], line2[1] ,line2[2])
    print(line3[0], line3[1], line3[2])
#function with the whole game
def turn() :
    showGrid()
#The player choose what case he wants to play
    playerChoice=input("What case do you want to play ( you'll play the crosses) : ")
#Three loops, one for each line, to put the "X" at the chosen spot
    n=0
    for case in line1:
        if case == playerChoice:
            line1[n] = "X"
        n+=1
    o=0
    for case in line2:
        if case == playerChoice:
            line2[o] = "X"
        o+=1
    p=0
    for case in line3:
        if case == playerChoice:
            line3[p] = "X"
        p+=1
#The "A.I." choose randomly a case among the "aiGrid" list
    aiGrid=["00", "01", "02", "10", "11", "12", "20", "21", "22"]
    played = False
    while played == False:
        aiChoice= random.choice(aiGrid)
        if grid[int(aiChoice[0])][int(aiChoice[1])] != "O" and grid[int(aiChoice[0])][int(aiChoice[1])] != "X":
            grid[int(aiChoice[0])][int(aiChoice[1])] = "O"
            played = True
        else:
            played = False
#function to detect if the player wins
def playerWin(gameFinished):
#lines and columns 
    for i in range(3):
        if all("X" == grid[i][j] for j in range(3)) or all(
            "X" == grid[j][i] for j in range(3)
        ):
            gameFinished = True
            break
# diagonals
        if (
            not gameFinished
            and all("X" == grid[i][i] for i in range(3))
            or all("X" == grid[i][2 - i] for i in range(3))):
            gameFinished = True
            print("Bravo !")
            
    return gameFinished
#function to detect if the player wins         
def aiWin(gameFinished1):
#lines and columns
    for i in range(3):
        if all("O" == grid[i][j] for j in range(3)) or all(
            "O" == grid[j][i] for j in range(3)
        ):
            gameFinished = True
            break
#diagonals
        if (
            gameFinished == False
            and all("O" == grid[i][i] for i in range(3))
            or all("O" == grid[i][2 - i] for i in range(3))
        ):
            gameFinished1 = True
            print("Dommage !")
    return gameFinished
#gameFinished is for the player and gameFinished for the A.I.
gameFinished=False
#Main loop
while gameFinished == False or gameFinished1 == False:
    turn()
    gamefinished=playerWin(gameFinished)
    gamefinished=aiWin(gameFinished)
sys.exit()
+0 -0

et gameFinished1 est une erreur, j’ai oublié de l’enlever sur cette ligne mais ce n’est pas la source du probleme.

Ben peut être bien que si puisqu’il fait partie de ta condition de sortie…

+0 -0

Il ya un problème dans la boucle de finale:

while gameFinished == False: # or gameFinished1 == False:
    turn()
    gamefinished=playerWin(gameFinished)
    gamefinished=aiWin(gameFinished)

Pour que cette boucle se termine il faut que ce soit l’IA qui gagne parce que la variable gamefinished a toujours la valeur de aiWin lors du passage par le while, et il manque aussi le cas du match nul.

Edit: Le cas des diagonales n’est bien traité.

+0 -0

Bonsoir,

Pourquoi ces "00", "01", "..", … ?

Heureusement que pour showGrid, on a que trois lignes :D

Pourquoi le morpion est représenté sur 3 lignes distinctes (ligne 5 à 7) alors que par la suite on le représente sur 1 ligne ?

Ligne 21 à 34, c’est quand même très ressemblant :o

Les conditions sont trop longues, par exemple ligne 40

Je vois deux gros problèmes,

  1. La conception (elle n’est pas assez posée sur papier avant l’écriture du code)
  2. L’algorithme trop complexe

Et un autre, dans le sens qu’on utilise pas assez la force du langage pour faire ce genre d’exercice.

Par exemple, la fonction showGrid aurait pu être représentée comme ci-dessous.

aiGrid=['_' for _ in range(9)]


def showGrid(grid, column):
    for i, char in enumerate(aiGrid, start=1):
        print(f'[{char}]', end='')
        if i % column == 0:
            print('\n')


showGrid(aiGrid, 3)  # découpage de la ligne en lignes contenant 3 colonnes

Mais faut avoir chercher ce qu’est enumerate, savoir utiliser l’opérateur modulo (%) et avoir un minimum de connaissance dans les chaînes de caractères et leur formatage. En ce qui me concerne, ça reste dans les bases du langage que tu apprends. Si tu prends le tutoriel officiel, tu ne les trouveras pas très loin de son départ.

Le jeu ne peut pas finir, la variable du while de Main loop est gameFinished, par contre dans les test de fin (lignes 86, 87) la variable est renommée en gamefinished, les majuscules ou minuscules sont importantes, de plus au 10eme tour l’IA ne peut pas jouer et donc restera indéfiniment dans sa boucle while de la fonction turn, cela revient à résoudre le cas "Match nul".

Pour simplifier ton code suis le conseil de @Angelo et fait une seule fonction dans la quelle tu passeras en paramètre le type de joueur avec X ou O par exemple. La boucle de fin pourrait devenir:

while gameFinished == False :
    turn()
    gameFinished = playerWin('X') or playerWin('O')
+0 -0

Voici un example de debut de la fonction playerWin qui permet ensuite d’utiliser les symboles X et O lors de l’appel de la fonction dans la boucle de fin:

def playerWin(mark): # Nota 1
    gameFinished = False # Cf Nota 2

    #lines and columns 
    for i in range(3): # Cf Nota 1
        if all(mark == grid[i][j] for j in range(3)) or all(
            mark == grid[j][i] for j in range(3)
        ):

Nota 1: Dans la declaration de fonction on n’utilise pas des chaines mais des variables, ici je la nome mark, tu peux ensuite dans la boucle finale l’utiliser en faisant playerWin('X')

Nota 2: la variable gameFinished ne sert a rien dans l’appel de la fonction, il faut juste l’initialiser au debut la fonction pour éviter UnboundLocalError: local variable 'gameFinished' referenced before assignment.

PS: Je te conseille fortement de lire le Tutoriel python de zds et en particulier la partie 5 sur les fonctions.

Salut,

je ne sais pas si tu as déjà vu les dictionnaires, mais je pense qu’ils t’aideraient pour ta grille. chiffres de 1 à 9 en clef et l’un des trois suivants ["empty", "circle", "x"] en valeur. Rien que la création se ferait en une simple ligne: case = {i+1:"empty" for i in range(9)}

Avec ça tu peux transformer ta fonction show_grid() comme ceci:

def show_grid():
    print(f"| {case[1]=} | {case[2]=} | {case[3]=} |")
    #je n'écris pas les deux autres lignes.

NOTE: ceci ne marche que depuis python3.8 pas avant. Avant tu devras utiliser: print(f"| case[1]={case[1]} | case[2]={case[2]} | case[3]={case[3]} |"). Si ta version est encore plus ancienne que 3.6 tu devras utiliser la fonction formate. Si elle est encore plus ancienne, il faudra demander à Fred Pierrafeu :P

pour mettre ton dictionnaire que je nommé "case" tu procèdes comme ceci:

playerChoice=input("What case do you want to play ( you'll play the crosses) : ")
case[playerChoice]="x"

Pour l’IA qui prend un chiffre au hasard, vérifie qu’il soit empty et mets à jour la case. Si la case est non empty reste dans ta boucle de choix.

lignes 37 et 38 j’aurais fait le contraire:

played = True
while played:
    #tout le reste

ou change played par is_playing si tu veux :) quoi qu’il en soit ce que j’essaye de te dire c’est que ça t’aurais fait économiser des touches XD

Je te laisse voir par toi même comment adapter tes vérifications aux dictionnaires. Je ne voudrais pas te priver de ce plaisir.

Bon WE

Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte