Java : un Morpion en moins d'une heure

Krobignole2902

Pilier
Membre du personnel
Responsable
Inscrit
21/6/20
Messages
107
Points
290
Age
19
Localité
France
Site web
twitter.com
J'avais envie de consolider les acquis de cours en Java, et jme suis dis "Pourquoi pas faire un Morpion ?".

C'est ce que je viens de faire en moins d'une heure, et pour ne pas enterrer ce mini-projet trop vite, j'ai envie d'expliquer comment il a été fait, et comment il fonctionne.

Déjà jvais drop tout le code ça m'évitera de le mettre morceau par morceau :

classeMain.java
Java:
public class classeMain {
    static public void main(String args[]) {
        MaFenetre fen = new MaFenetre();   
    }
}
MaFenetre.java
Java:
import java.awt.Color;
import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.*;

public class MaFenetre extends JFrame implements ActionListener{

    public void VictoireFun() {
        replayButton.show();
        System.out.println(victoiretexte);
        victoireLabel.setText(victoiretexte);
        victoireLabel.setForeground(joueur);
        b1.setEnabled(false);
        b2.setEnabled(false);
        b3.setEnabled(false);
        b4.setEnabled(false);
        b5.setEnabled(false);
        b6.setEnabled(false);
        b7.setEnabled(false);
        b8.setEnabled(false);
        b9.setEnabled(false);
        replay.setText("On recommence ?");
    }
    public void EgaliteFun() {
        replayButton.show();
        System.out.println("Egalité");
        victoireLabel.setText("Egalité");
        victoireLabel.setForeground(null);
        replay.setText("On recommence ?");
    }
    public void ResetButton(JButton b) {
        replayButton.hide();
        b.setBackground(null);
        b.setEnabled(true);
        nbrtours = 1;
        tours.setText("Au tour des bleus");
        tours.setForeground(Color.BLUE);
    }
    int score1 = 0;
    int score2 = 0;
    int nbrtours = 1;
    Color joueur;
    JLabel victoireLabel;
    String victoiretexte;
    JLabel replay;
    JButton replayButton;
    
    JPanel jeu;
    JPanel score;
    JLabel tours;
    
    JButton b1;
    JButton b2;
    JButton b3;
    JButton b4;
    JButton b5;
    JButton b6;
    JButton b7;
    JButton b8;
    JButton b9;
    
    
    MaFenetre(){
        setSize(500,500);
        setTitle("Morpion");
        
        Container contenu = getContentPane();
        contenu.setLayout(new GridLayout(2,1));
        
        
        
        jeu = new JPanel();
        jeu.setLayout(new GridLayout(3,3));
        b1 = new JButton("Case 1");
        b2 = new JButton("Case 2");
        b3 = new JButton("Case 3");
        b4 = new JButton("Case 4");
        b5 = new JButton("Case 5");
        b6 = new JButton("Case 6");
        b7 = new JButton("Case 7");
        b8 = new JButton("Case 8");
        b9 = new JButton("Case 9");
        
        jeu.add(b1);
        jeu.add(b2);
        jeu.add(b3);
        jeu.add(b4);
        jeu.add(b5);
        jeu.add(b6);
        jeu.add(b7);
        jeu.add(b8);
        jeu.add(b9);
        
        b1.addActionListener(this);
        b2.addActionListener(this);
        b3.addActionListener(this);
        b4.addActionListener(this);
        b5.addActionListener(this);
        b6.addActionListener(this);
        b7.addActionListener(this);
        b8.addActionListener(this);
        b9.addActionListener(this);
        
        contenu.add(jeu);

        score = new JPanel();
        score.setLayout(new FlowLayout(FlowLayout.CENTER,500,10));
        tours = new JLabel();
        tours.setText("Au tour des bleus");
        tours.setHorizontalAlignment(JLabel.CENTER);
        tours.setForeground(Color.BLUE);
        
        victoireLabel = new JLabel();
        replay = new JLabel();
        
        replayButton = new JButton("Rejouer");
        replayButton.addActionListener(   
                new ActionListener()
                {
                    public void actionPerformed(ActionEvent e) {
                        ResetButton(b1);
                        ResetButton(b2);
                        ResetButton(b3);
                        ResetButton(b4);
                        ResetButton(b5);
                        ResetButton(b6);
                        ResetButton(b7);
                        ResetButton(b8);
                        ResetButton(b9);   
                        victoireLabel.setText(null);
                        replay.setText(null);
                    }
                }       
        );
        
        score.add(tours);
        score.add(victoireLabel);
        score.add(replay);
        score.add(replayButton);
        replayButton.hide();
        contenu.add(score);

        setVisible(true);
    }
    

    
    @Override
    public void actionPerformed(ActionEvent e) {
        
        if(nbrtours % 2 == 0) {
            joueur = Color.red;
            tours.setText("Au tour des bleus");
            tours.setForeground(Color.blue);
            victoiretexte = "C'est une victoire pour les rouges";
            
        }
        else {
            joueur = Color.blue;
            tours.setText("Au tour des rouges");
            tours.setForeground(Color.red);
            victoiretexte = "C'est une victoire pour les bleus";
        }
        
        switch(e.getActionCommand()) {
        
        case "Case 1":
            b1.setEnabled(false);
            b1.setBackground(joueur);
            break;
        case "Case 2":
            b2.setEnabled(false);
            b2.setBackground(joueur);
            break;
        case "Case 3":
            b3.setEnabled(false);
            b3.setBackground(joueur);
            break;
        case "Case 4":
            b4.setEnabled(false);
            b4.setBackground(joueur);
            break;
        case "Case 5":
            b5.setEnabled(false);
            b5.setBackground(joueur);
            break;
        case "Case 6":
            b6.setEnabled(false);
            b6.setBackground(joueur);
            break;
        case "Case 7":
            b7.setEnabled(false);
            b7.setBackground(joueur);
            break;
        case "Case 8":
            b8.setEnabled(false);
            b8.setBackground(joueur);
            break;
        case "Case 9":
            b9.setEnabled(false);
            b9.setBackground(joueur);
            break;
        }
        
        if(b1.isEnabled() == false && b2.isEnabled() == false && b3.isEnabled() == false) {
            if(b1.getBackground() == joueur && b2.getBackground() == joueur && b3.getBackground() == joueur) {
                VictoireFun();
            }
        }
        if(b4.isEnabled() == false && b5.isEnabled() == false && b6.isEnabled() == false) {
            if(b4.getBackground() == joueur && b5.getBackground() == joueur && b6.getBackground() == joueur) {
                VictoireFun();
            }
        }
        if(b7.isEnabled() == false && b8.isEnabled() == false && b9.isEnabled() == false) {
            if(b7.getBackground() == joueur && b8.getBackground() == joueur && b9.getBackground() == joueur) {
                VictoireFun();
            }
        }
        if(b1.isEnabled() == false && b4.isEnabled() == false && b7.isEnabled() == false) {
            if(b1.getBackground() == joueur && b4.getBackground() == joueur && b7.getBackground() == joueur) {
                VictoireFun();
            }
        }
        if(b2.isEnabled() == false && b5.isEnabled() == false && b8.isEnabled() == false) {
            if(b2.getBackground() == joueur && b5.getBackground() == joueur && b8.getBackground() == joueur) {
                VictoireFun();
            }
        }
        if(b3.isEnabled() == false && b6.isEnabled() == false && b9.isEnabled() == false) {
            if(b3.getBackground() == joueur && b6.getBackground() == joueur && b9.getBackground() == joueur) {
                VictoireFun();
            }
        }
        if(b1.isEnabled() == false && b5.isEnabled() == false && b9.isEnabled() == false) {
            if(b1.getBackground() == joueur && b5.getBackground() == joueur && b9.getBackground() == joueur) {
                VictoireFun();
            }
        }
        if(b3.isEnabled() == false && b5.isEnabled() == false && b7.isEnabled() == false) {
            if(b3.getBackground() == joueur && b5.getBackground() == joueur && b7.getBackground() == joueur) {
                VictoireFun();
            }
        }
    
        nbrtours++;
        if(nbrtours == 10) {
            EgaliteFun();
        }
        
    }
}
Jvais aussi faire une mini introduction sur le Java, parce que pour ceux qui n'avait pas compris, oui le programme fonctionne avec deux fichiers :

Le Java et la POO :

Pour faire cours, le Java c'est un langage de programmation orientée objets. J'ai pas l'exacte définition en tête, et voir une définition en ligne serai surement le plus approprié ici vu le nombre de notions que ça implique, mais grosse modo la POO permet de créer des objets, c'est-à-dire des fichiers qui contiennent des fonctions, des donnée membres, qu'on va pouvoir ensuite utiliser à notre guise dans le code principal.

J'ai fait la même chose ici, le gros code est un "objet", tandis que l'autre fichier contient la méthode principale, celle qui exécute le code.

On pourrait tout mettre dans un même fichier, mais c'est nul.

Une interface graphique :

Pour la plupart des gens qui ont déjà fait de la programmation en école, vous avez très rarement, voire jamais, manipulé une interface graphique. Cependant pour un morpion c'est toujours mieux d'avoir une interface graphique :

  • Pour sélectionner la case qu'on joue
  • Pour afficher le vainqueur
  • Pour demander si on rejoue
  • Pour d'autres trucs dites moi parce que là j'ai plus d'idée..

On pourrait le faire en ligne de commandes, c'est pas impossible, mais ce serai déguelasse.

Enfin, tout ça pour dire qu'on va utiliser une interface graphique pour que ce soit jolie, et surtout jouable.

Java:
import java.awt.Color;
import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
On importe les différentes classes qui vont permettent la création de l'interface graphique.

Pour expliquer rapidement, on a de quoi faire des boutons, sélectionner des couleurs (dans le code), arranger l'agencement des éléments, etc ...

Je passe sur les notions avancées pour la création de l'interface graphique parce que c'est peu inintéressant de l'expliquer + on est surtout ici pour expliquer le fonctionnement du jeu. J'ai pas dit que j'allais rien expliquer par contre.

On peut résumer l'ajout d'un élément dans l'interface graphique en 4-5 étapes :

1)
On créé l'élément (définition + instanciation avec le constructeur (VOUS VOYEZ QUE J'UTILISE DES TERMES DEJA TROP AVANCEES))
Java:
JButton b1;
Définition dans la classe
Java:
b1 = new JButton("Case 1");
Instantiation dans le constructeur
2)
On pimp l'élément (la police d'écriture, la taille, la couleur)
Java:
b1.setBackground(Color.red);
3)
On l'ajoute à la fenêtre/Container
Java:
jeu.add(b1);
4)
Il s'affiche quand on affiche la fenêtre/Container
Java:
setVisible(true);
5) Modification pour la suite

Pour le morpion, j'ai décidé de faire comme ça :

  • On découpe la fenêtre en deux parties
    • Le jeu
    • Un descriptif
  • Dans le "jeu" on clique sur les cases pour jouer
  • Dans le "descriptif", on annonce quel joueur doit jouer, la victoire du joueur, et l'apparition d'un bouton pour rejouer

Le jeu :

C'est la partie la plus longue à faire, et ça pour une simple raison.

Quand on joue au Morpion,
la victoire est concédé au joueur qui aligne 3 cercles ou 3 croix. Normalement ça se remarque d'un coup d'œil si un joueur à gagné ou non. Cependant ici c'est un programme qui exécute le jeu, et il ne sait pas ce qu'est un morpion, ni les conditions de victoires, il faut donc programmer le jeu soit même, en n'oubliant aucun détail :

  • L'alternance entre les deux joueurs
  • Ne pas rejouer deux fois la même case
  • Les conditions de victoires
  • Recommencer le jeu

Java:
public void actionPerformed(ActionEvent e) {

        if(nbrtours % 2 == 0) {
            joueur = Color.red;
            tours.setText("Au tour des bleus");
            tours.setForeground(Color.blue);
            victoiretexte = "C'est une victoire pour les rouges";
            
        }
        else {
            joueur = Color.blue;
            tours.setText("Au tour des rouges");
            tours.setForeground(Color.red);
            victoiretexte = "C'est une victoire pour les bleus";
        }
        
        switch(e.getActionCommand()) {
        
        case "Case 1":
            b1.setEnabled(false);
            b1.setBackground(joueur);
            break;
        case "Case 2":
            b2.setEnabled(false);
            b2.setBackground(joueur);
            break;
        case "Case 3":
            b3.setEnabled(false);
            b3.setBackground(joueur);
            break;
        case "Case 4":
            b4.setEnabled(false);
            b4.setBackground(joueur);
            break;
        case "Case 5":
            b5.setEnabled(false);
            b5.setBackground(joueur);
            break;
        case "Case 6":
            b6.setEnabled(false);
            b6.setBackground(joueur);
            break;
        case "Case 7":
            b7.setEnabled(false);
            b7.setBackground(joueur);
            break;
        case "Case 8":
            b8.setEnabled(false);
            b8.setBackground(joueur);
            break;
        case "Case 9":
            b9.setEnabled(false);
            b9.setBackground(joueur);
            break;
        }
        
        if(b1.isEnabled() == false && b2.isEnabled() == false && b3.isEnabled() == false) {
            if(b1.getBackground() == joueur && b2.getBackground() == joueur && b3.getBackground() == joueur) {
                VictoireFun();
            }
        }
        if(b4.isEnabled() == false && b5.isEnabled() == false && b6.isEnabled() == false) {
            if(b4.getBackground() == joueur && b5.getBackground() == joueur && b6.getBackground() == joueur) {
                VictoireFun();
            }
        }
        if(b7.isEnabled() == false && b8.isEnabled() == false && b9.isEnabled() == false) {
            if(b7.getBackground() == joueur && b8.getBackground() == joueur && b9.getBackground() == joueur) {
                VictoireFun();
            }
        }
        if(b1.isEnabled() == false && b4.isEnabled() == false && b7.isEnabled() == false) {
            if(b1.getBackground() == joueur && b4.getBackground() == joueur && b7.getBackground() == joueur) {
                VictoireFun();
            }
        }
        if(b2.isEnabled() == false && b5.isEnabled() == false && b8.isEnabled() == false) {
            if(b2.getBackground() == joueur && b5.getBackground() == joueur && b8.getBackground() == joueur) {
                VictoireFun();
            }
        }
        if(b3.isEnabled() == false && b6.isEnabled() == false && b9.isEnabled() == false) {
            if(b3.getBackground() == joueur && b6.getBackground() == joueur && b9.getBackground() == joueur) {
                VictoireFun();
            }
        }
        if(b1.isEnabled() == false && b5.isEnabled() == false && b9.isEnabled() == false) {
            if(b1.getBackground() == joueur && b5.getBackground() == joueur && b9.getBackground() == joueur) {
                VictoireFun();
            }
        }
        if(b3.isEnabled() == false && b5.isEnabled() == false && b7.isEnabled() == false) {
            if(b3.getBackground() == joueur && b5.getBackground() == joueur && b7.getBackground() == joueur) {
                VictoireFun();
            }
        }
    
        nbrtours++;
        if(nbrtours == 10) {
            EgaliteFun();
        }
    }
Java:
public void VictoireFun() {
        replayButton.show();
        System.out.println(victoiretexte);
        victoireLabel.setText(victoiretexte);
        victoireLabel.setForeground(joueur);
        b1.setEnabled(false);
        b2.setEnabled(false);
        b3.setEnabled(false);
        b4.setEnabled(false);
        b5.setEnabled(false);
        b6.setEnabled(false);
        b7.setEnabled(false);
        b8.setEnabled(false);
        b9.setEnabled(false);
        replay.setText("On recommence ?");
    }
Java:
public void EgaliteFun() {
        replayButton.show();        
        System.out.println("Egalité");
        victoireLabel.setText("Egalité");
        victoireLabel.setForeground(null);
        b1.setEnabled(false);
        b2.setEnabled(false);
        b3.setEnabled(false);
        b4.setEnabled(false);
        b5.setEnabled(false);
        b6.setEnabled(false);
        b7.setEnabled(false);
        b8.setEnabled(false);
        b9.setEnabled(false);
        replay.setText("On recommence ?");
    }
Y'a beaucoup de code certes, mais c'est assez simple de comprendre.
Le premier code est une fonction qui s'exécute quand on clique sur une case, à partir de là, pas mal de choses se passe :

  • Déjà on va déterminer c'est le tour de qui, ce qui permet d'afficher "C'est au tour de ...", à l'écran, mais surtout de colorier la case d'une certaine couleur quand on clique dessus.
  • Ensuite, la case sélectionné ne sera plus jouable, à l'aide d'un "setEnabled(false), qui permet de rendre le bouton inutilisable

Le Morpion peut se finir de deux façon, la plus commune est l'égalité entre les deux joueurs.

Cette situation arrive quand "nbrtours" arrive à 10. "nbrtours" est un compteur auquel on ajoute 1 à chaque tours entre les deux joueurs, il commence à 1, et après 9 tours, fini à 10.

Quand l'égalité arrive, on exécute la fonction EgaliteFun(), qui affiche un texte pour annoncer l'égalité, et un bouton pour réactiver tout les boutons, et les remettre à la couleur de base.

Maintenant on passe à la partie la plus chiante, quand y'a une victoire.

Déjà faut savoir que y'a 8 façons possibles d'arracher la victoire aux morpions, 3 lignes horizontales, 3 lignes verticales et 2 diagonales. Disons que on dispose des boutons b1,b2,b3,...b9, et qu'ils sont disposer comme les touches sur un téléphone, la victoire est obtenue si :
  • b1,b2 et b3 sont alignés --> Ligne horizontale
  • b4,b5 et b6 sont alignés --> Ligne horizontale
  • b7,b8 et b9 sont alignés --> Ligne horizontale
  • b1,b4 et b7 sont alignés --> Ligne verticale
  • b2,b5 et b8 sont alignés --> Ligne verticale
  • b3,b6 et b9 sont alignés --> Ligne verticale
  • b1,b5 et b9 sont alignés --> Diagonale
  • b3,b5 et b7 sont alignés --> Diagonale

Il faut donc faire en sorte de détecter quand un joueur parvient à une de ces possibilités. Alors étant donnée que y'a pas une fonction magique pour détecter ça, il faut donc un peu se casser la tête.

Revenons sur ce qui a été fait,
lorsqu'une case est sélectionné, elle devient inutilisable et change de couleur, on va se servir de ça :

Disons que par exemple,
si les 3 cases du hauts sont inutilisables et de la même couleur, alors un joueur a gagné, est ce que c'est possible ? Oui.

Si vous regardez toujours le premier bout de code, on peut voir beaucoup de "if" qui permet de poser une condition

  • Si les cases sont inutilisables
  • Si les cases de la même couleur
Attention, il faut impérativement que les cases soit inutilisable, supposons que cette fonctionnalité ne soit pas implémenté, il se passerai quoi ?

Et bien juste après avoir cliqué sur une première case, une victoire sera annoncé, car il y aurait des cases alignés pour remplir la condition d'une victoire. Le fait de voir si oui on non elles sont inutilisables permet justement de palier à ce problème. Une fois que la victoire est obtenue, la fonction "VictoireFun()" se lance, pour annoncer le vainqueur est proposer de rejouer

On arrive au bout, c'est la partie la plus longue à faire, mais ensuite le reste devient plus simple.

Un descriptif :

Ici je vais principalement expliqué comment le jeu se relance. Oui il y a un texte pour annoncer le tour de tel joueur, mais c'est pas très compliqué (et puis merde jvais expliquer) ...

A chaque tour, la case de colorise en bleu ou en rouge. On reprend cette logique pour afficher un texte différent à chaque tour (et de la bonne couleur également)

Après une dure partie de Morpion, on a bien envie d'en refaire une. On affiche donc un bouton "Rejouer", qui se cache et s'affiche à l'aide des méthodes "hide()" et "show()" (alors il semblerait que ces méthodes ne soit pas très appréciés, je sais pas pourquoi mais mon IDE les déconseillaient mais j'avais pas le choix)

Java:
replayButton.addActionListener(   
                new ActionListener()
                {
                    public void actionPerformed(ActionEvent e) {
                        ResetButton(b1);
                        ResetButton(b2);
                        ResetButton(b3);
                        ResetButton(b4);
                        ResetButton(b5);
                        ResetButton(b6);
                        ResetButton(b7);
                        ResetButton(b8);
                        ResetButton(b9);   
                        victoireLabel.setText(null);
                        replay.setText(null);
                        replayButton.hide();
                        nbrtours = 1;
                        tours.setText("Au tour des bleus");
                        tours.setForeground(Color.BLUE);
                    }
                }       
        );
Java:
public void ResetButton(JButton b) {
        b.setBackground(null);
        b.setEnabled(true);
    }
Quand on clique sur le bouton "Rejouer", on lance la fonction "ResetButton" que j'ai faite, et qui permet de réactiver les boutons et de remettre la couleur de base.

Ensuite, on enlève le texte de victoire (ou d'égalité), on remet le compteurs de tours à 1, puis à la fin on cache ce fameux bouton pour recommencer.

Des ajouts ?

Pendant que j'écrivais la discussion, je me demandais si je pouvais faire en sorte de choisir ses couleurs au début de la partie. Alors oui c'est possible, il faudra juste créer un menu pour choisir sa propre couleur.

La présentation arrive à son terme, si jamais vous voulez des détails supplémentaires / me corriger sur une explication, vous pouvez (pas ez).

Nan bien sur n'hésitez pas à faire des retours si besoin, en espérant que c'était cool à lire

biz

 
Haut