Morpion

Description

Bon c un morpion classique: on peut jouer à deux ou seul contre l'ordinateur avec deux niveaux de difficulté(neuneu et kasparov)

Un programme assez simple dans le principe général, mais qui demande juste un peu de recherche pour réussir à faire jouer l'ordinateur correctement contre un humain.

On part d'une grille de neuf cases :

1 2 3
4 5 6
7 8 9

on note qu'il existe alors huit possibilités pour gagner. Aligner les case 123, 456, 789, 147, 258, 369, 159 ou 357. Le but va donc consister à enregistrer, pour chaque joueur, les case cochées pour chaque combinaison. Par exemple, pour cette grille :

x x o
o x
o

On aura les valeurs suivantes dans le tableau :

Combinaison Joueur 1 Joueur 2
123 2 1
456 1 1
789 0 1
147 1 1
258 2 1
369 0 1
159 2 0
357 1 1

Si le joueur 1 coche la case 9, la valeur de la combinaison '159' pour ce joueur passe alors à 3. Il remporte donc la partie.
Ainsi, toute la gestion du jeu est basé sur ce tableau. Dès qu'une combinaison atteint 3 pour un joueur, cela indique qu'il a gagné. Pour faire jouer l'ordinateur (en mode 'Kasparov'), on étudie donc le tableau en regardant s'il est possible d'atteindre cette valeur pour chaque combinaison. Sinon, on vérifie que l'adversaire humain ne puisse pas le faire. Enfin, si rien de tout cela n'est possible, on amène l'ordinateur à cocher une case d'une combinaison qui ne soit pas déjà bloqué. C'est-à-dire qu'il faut que cette combinaison n'ait pas déjà été entamée par l'adversaire (donc, qu'il y ait bien 0 de l'autre côté du tableau).

En espérant que ces explications soient suffisantes et assez claires...

Source / Exemple :


Option Explicit
' Variable pour indiquer la fin de la partie
Dim blFin As Boolean
' Donne le tour de jeu courant (0 pour le joueur 1, 1 pour le joueur 2)
Dim inTour As Integer
' Nombre total de coups joués
Dim inCoup As Integer
' Indique le tour de l'ordinateur
Dim inOrdiTour As Integer
' Tableau des coups joués pour chaque joueur
Dim TabSol(8, 1) As Integer
' Tableau des solutions possibles
Dim Sol(8) As Long

Private Sub Form_Load()
' Création du tableau des 8 uniques possibilités de gagner la partie
Sol(1) = 132
Sol(2) = 465
Sol(3) = 798
Sol(4) = 174
Sol(5) = 285
Sol(6) = 396
Sol(7) = 375
Sol(8) = 195
End Sub

Private Sub mnu1Joueur_Click()
' Menu 1 joueur, coche la ligne correspondante,
mnu1Joueur.Checked = True
' et enlève la coche sur l'autre.
mnu2Joueurs.Checked = False
' Rend inaccessible la zone de texte du joueur 1 et mets l'ordinateur dedans.
txtJoueur1.Enabled = False
txtJoueur1.Text = "Ordinateur"
' Autorise le choix du niveau d'intelligence de l'ordinateur.
mnuNiveau.Enabled = True
End Sub

Private Sub mnu2Joueurs_Click()
' Menu 2 joueurs, coche la ligne correspondante,
mnu2Joueurs.Checked = True
' et enlève la coche sur l'autre.
mnu1Joueur.Checked = False
' Rend inaccessible la zone de texte du joueur 1.
txtJoueur1.Enabled = True
txtJoueur1.Text = "Humain"
' Enlève le choix du niveau d'intelligence de l'ordinateur.
mnuNiveau.Enabled = False
End Sub

Private Sub mnuKasparov_Click()
' Coche le niveau Kasparov pour l'ordinateur
mnuKasparov.Checked = True
mnuNeuneu.Checked = False
End Sub

Private Sub mnuNeuneu_Click()
' Coche le niveau Neuneu pour l'ordinateur
mnuNeuneu.Checked = True
mnuKasparov.Checked = False
End Sub

Private Sub mnuNouvellePartie_Click()
' Commence une nouvelle partie
Dim i As Integer
Dim stTMP As String
Dim picTMP As Object
' Initialisation des variables
inCoup = 0
blFin = False
inTour = 0
For i = 1 To 8
    TabSol(i, 0) = 0
    TabSol(i, 1) = 0
Next i
' Efface le terrain de jeu
For i = 1 To 9
    picTab(i).Enabled = True
    picTab(i).Picture = Nothing
Next i
lblComment.Caption = ""
' Ne permet plus de changer le nom des joueurs...
txtJoueur1.Enabled = False
txtJoueur2.Enabled = False
' ...et les options
mnuOptions.Enabled = False
' Demande qui commence
If MsgBox("Est-ce que " & txtJoueur1.Text & " commence ?", _
          vbQuestion + vbYesNo, "Choix du joueur") <> vbYes Then
' Si c'est le joueur 2, on échange les propriétés
    stTMP = txtJoueur1.Text
    Set picTMP = picJoueur1.Picture
    txtJoueur1.Text = txtJoueur2.Text
    picJoueur1.Picture = picJoueur2.Picture
    txtJoueur2.Text = stTMP
    picJoueur2.Picture = picTMP
End If
If mnu1Joueur.Checked Then
' Si c'est une partie contre l'ordinateur, on regarde qui commence
    inOrdiTour = 0
' Si c'est l'ordinateur qui joue le premier on appelle la fonction correspondante
    If txtJoueur1.Text = "Ordinateur" Then OrdiJoue Else inOrdiTour = 1
End If
End Sub

Private Sub mnuQuitter_Click()
' Quitte l'application
Unload frmMorpion
End
End Sub

Private Sub picTab_Click(Index As Integer)
Dim i As Integer
' Si la case courante n'a pas d'image, c'est qu'elle n'a pas été cochée.
If picTab(Index).Picture = 0 Then
' En fonction de son index, on remplit le tableau des solutions du joueur.
    Select Case Index
        Case 1
            blFin = Not (RemplirTabSol(1) And RemplirTabSol(4) And RemplirTabSol(8))
        Case 2
            blFin = Not (RemplirTabSol(1) And RemplirTabSol(5))
        Case 3
            blFin = Not (RemplirTabSol(1) And RemplirTabSol(6) And RemplirTabSol(7))
        Case 4
            blFin = Not (RemplirTabSol(2) And RemplirTabSol(4))
        Case 5
            blFin = Not (RemplirTabSol(2) And RemplirTabSol(5) _
                         And RemplirTabSol(7) And RemplirTabSol(8))
        Case 6
            blFin = Not (RemplirTabSol(2) And RemplirTabSol(6))
        Case 7
            blFin = Not (RemplirTabSol(3) And RemplirTabSol(4) And RemplirTabSol(7))
        Case 8
            blFin = Not (RemplirTabSol(3) And RemplirTabSol(5))
        Case 9
            blFin = Not (RemplirTabSol(3) And RemplirTabSol(6) And RemplirTabSol(8))
    End Select
' En fonction du joueur courant, on place son symbole dans la case cochée
    If inTour = 0 Then
        picTab(Index).Picture = picJoueur1.Picture
    Else
        picTab(Index).Picture = picJoueur2.Picture
    End If
' Change de joueur courant, si inTour=0 alors inTour devient 1, sinon devient 0
    inTour = (inTour * (-1)) + 1
' Un coup de plus
    inCoup = inCoup + 1
' C'est la fin de la partie, un joueur a gagné ou il n'y a plus de case disponible
    If blFin Or inCoup = 9 Then
' Si on a fait 9 coups sans que la partie soit réellement finie, c'est alors un match nul
        If inCoup = 9 Then lblComment.Caption = "Partie Terminée - Match Nul"
' On vérouille les cases
        For i = 1 To 9
            picTab(i).Enabled = False
        Next i
' On ne rend accessible les zones que si elle ne représentent pas le nom de l'ordinateur
        txtJoueur1.Enabled = (txtJoueur1.Text <> "Ordinateur")
        txtJoueur2.Enabled = (txtJoueur2.Text <> "Ordinateur")
' Et on rend de nouveau disponible les options
        mnuOptions.Enabled = True
    ElseIf ((mnu1Joueur.Checked) And (inTour = inOrdiTour)) Then
' Si c'est une partie contre l'ordinateur et que
' c'est à lui de jouer, on appelle la fonction
        Call OrdiJoue
    End If
End If
End Sub

Public Sub JoueSolution(Solution As Integer)
Dim i As Integer, j As Integer, k As Integer
' On extrait les index des différentes cases composant la solution trouvée
i = Sol(Solution) \ 100 ' première case
j = (Sol(Solution) - (i * 100)) \ 10 ' deuxième case
k = (Sol(Solution) - (i * 100) - (j * 10)) ' troisième et dernière case
' Si la première case n'est pas cochée,
If picTab(i).Picture = 0 Then
' on s'en occupe,
    Call picTab_Click(i)
' sinon, on cherche à cocher la seconde
ElseIf picTab(j).Picture = 0 Then
    Call picTab_Click(j)
' en enfin la troisième.
ElseIf picTab(k).Picture = 0 Then
    Call picTab_Click(k)
End If
End Sub

Public Function RemplirTabSol(Solution As Integer) As Boolean
' Remplit le tableau des solutions d'un joueur et indique si celui-ci a gagné
If TabSol(Solution, inTour) = 2 Then
' Si la valeur du tableau est déjà à 2, pas la peine
' d'aller plus loin, car il a coché la troisième case.
' Le joueur à qui s'était le tour est vainqueur
    If (inTour = 1) Then
        lblComment.Caption = "Gagné ! " & txtJoueur2.Text & " vainqueur..."
    Else
        lblComment.Caption = "Gagné ! " & txtJoueur1.Text & " vainqueur..."
    End If
' Indique que l'on a pas remplit le tableau, car nous avons un gagnant
    RemplirTabSol = False
Else
' C'est pas encore gagné, on augmente la valeur du tableau
    TabSol(Solution, inTour) = TabSol(Solution, inTour) + 1
' Oui, on a remplit le tableau
    RemplirTabSol = True
End If
End Function

Public Sub OrdiJoue()
' Fait jouer l'ordinateur
Dim i As Integer
Dim tabTmp(8) As Integer
If mnuNeuneu.Checked Then
' Niveau Neuneu pour l'ordinateur - Random...
    Randomize
    Do
' Coche au hasard une des neuf cases
        Call picTab_Click(Int(Rnd * 9) + 1)
    Loop Until (inTour <> inOrdiTour)
Else
' Niveau Kasparov pour l'ordinateur - Un peu plus de réflexion...
    If inCoup = 0 Then
' L'ordinateur commence dans ce mode en débutant toujours par la plaque du milieu (5),
' celle qui donne le plus de chance pour le reste de la partie.
        Call picTab_Click(5)
    Else
        i = 1
' On commence par chercher un endroit ou il ne reste plus
' qu'une seule case à cocher pour gagner.
' Une réponse du type (2 - 0) signifie que l'on à coché
' déjà 2 cases d'une solution et que l'adversaire aucune,
' c'est donc une victoire!
        Do While ((i < 8) And ((TabSol(i, inOrdiTour) - TabSol(i, (inOrdiTour * (-1)) + 1)) <> 2))
            i = i + 1
        Loop
' Si on a trouvé une solution, on la joue.
        If ((TabSol(i, inOrdiTour) - TabSol(i, (inOrdiTour * (-1)) + 1)) = 2) Then
            Call JoueSolution(i)
        Else
            i = 1
' Maintenant on vérifie que l'adversaire humain ne rique
' pas de gagner en faisant l'opération inverse.
' Une réponse du type (0 - 2) signifie que joueur humain peut gagner.
            Do While ((i < 8) And ((TabSol(i, inOrdiTour) - TabSol(i, (inOrdiTour * (-1)) + 1)) <> -2))
                i = i + 1
            Loop
' Si on a trouvé une réponse, on empêche alors notre adversaire de gagner.
            If ((TabSol(i, inOrdiTour) - TabSol(i, (inOrdiTour * (-1)) + 1)) = -2) Then
                Call JoueSolution(i)
            Else
' On va enfin rechercher les meilleures positions pour pouvoir jouer le prochain coup.
' Il faut dans tous les cas que l'adversaire n'ait pas déjà entamé la solution.
                For i = 1 To 8
                    If (TabSol(i, inOrdiTour) * TabSol(i, (inOrdiTour * (-1)) + 1) = 0) Then
                        tabTmp(i) = TabSol(i, inOrdiTour) - TabSol(i, (inOrdiTour * (-1)) + 1)
                    Else
                        tabTmp(i) = 2
                    End If
                Next i
' Si on n'est pas encore rendu au dernier coup on tente notre coup au hasard.
                If inCoup < 8 Then
                    Randomize
                    Do
' Un nombre au hasard dans les 8 solutions possibles
                        i = Int(Rnd * 8) + 1
                        Debug.Print i
' Si c'est un bon coup potentiel, on le joue.
                        If (tabTmp(i) <> 2) Then Call JoueSolution(i)
                    Loop Until (inTour <> inOrdiTour)
                Else
' sinon, on joue les trois premières solutions, cela nous amènera
' à cocher forcement la dernière case qui reste
                    For i = 1 To 3
                        Call JoueSolution(i)
                    Next i
                End If
            End If
        End If
    End If
End If
End Sub

Conclusion :


je n ai remarqué aucun bug alors si vous en voyez 1 n hésitez surtout pas a me le dire!! mci
laissez moi vos commantaires!!

Codes Sources

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.