Le jeu du morpion en java

Fermé
joseph.t - Modifié le 26 juin 2017 à 10:30
KX Messages postés 16733 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 31 janvier 2024 - 26 juin 2017 à 11:21
Bonjour,

je dois réaliser un morpion en java pour mon école. J'ai commencé à réaliser la base graphique, c'est à dire une fenêtre avec 9 boutons, et à tour de rôle s'affiche une croix ou un rond. J'ai cru comprendre qu'il fallait faire un tableau pour gérer la victoire d'un joueur après avoir aligner 3 croix ou rond. Seulement je ne vois pas vraiment comment faire pour l'adapter à mon programme que j'ai déjà commencé :

import javax.swing.*;
import java.awt.event.*;
import java.awt.*;


public class Morpion extends JFrame {
  JButton case1, case2, case3, case4, case5, case6, case7, case8, case9;
  String croix = "X";
  String rond = "O";
  boolean Joueur=false;
  
  Morpion(){
    initialisation();
    this.pack();
    this.setVisible(true);
  }
  
  
  void initialisation(){
    // propriété de la fenetre
    setTitle("Morpion"); //On donne un titre à l'application
    setSize(800,800);             //On donne une taille à notre fenêtre
    setLocationRelativeTo(null);          //On centre la fenêtre sur l'écran
    setResizable(true);            //On permet le redimensionnement
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);     //On dit à l'application de se fermer lors du clic sur la croix
    
    
    // widgets
    case1 = new JButton();
    case2 = new JButton();
    case3 = new JButton();
    case4 = new JButton();
    case5 = new JButton();
    case6 = new JButton();
    case7 = new JButton();
    case8 = new JButton();
    case9 = new JButton();
    
    // initialisation des widgets
    
    
   
    
    // regroupement en panels selon certains layout

    JPanel grilleDonnees= new JPanel(); 
    grilleDonnees.setLayout(new GridLayout(3,3));
    grilleDonnees.add(case1);
    grilleDonnees.add(case2);
    grilleDonnees.add(case3);
    grilleDonnees.add(case4);
    grilleDonnees.add(case5);
    grilleDonnees.add(case6);
    grilleDonnees.add(case7);
    grilleDonnees.add(case8);
    grilleDonnees.add(case9);
    Container cpane=this.getContentPane();
    cpane.setLayout(new BoxLayout(cpane,BoxLayout.X_AXIS));
    cpane.add(grilleDonnees);
    
    ButtonListener button1= new ButtonListener(case1);
    ButtonListener button2= new ButtonListener(case2);
    ButtonListener button3= new ButtonListener(case3);
    ButtonListener button4= new ButtonListener(case4);
    ButtonListener button5= new ButtonListener(case5);
    ButtonListener button6= new ButtonListener(case6);
    ButtonListener button7= new ButtonListener(case7);
    ButtonListener button8= new ButtonListener(case8);
    ButtonListener button9= new ButtonListener(case9);
    case1.addActionListener(button1);
    case2.addActionListener(button2);
    case3.addActionListener(button3);
    case4.addActionListener(button1);
    case5.addActionListener(button2);
    case6.addActionListener(button3);
    case7.addActionListener(button1);
    case8.addActionListener(button2);
    case9.addActionListener(button3);

    
 
    
  }
  
  
  // classe interne pour gérer les évènements des boutons
  class ButtonListener implements ActionListener {
    JButton tb;
    public ButtonListener(JButton b) {
      tb = b;
    }
    
    @Override
    public void actionPerformed(ActionEvent e) {
      // on récupère le slider sur lequel on agit
      JButton b1 = (JButton)e.getSource();
      if(Joueur){  
        if (b1==case1 || b1==case2 || b1==case3 || b1==case4 || b1==case5 || b1==case6 || b1==case7 || b1==case8 || b1==case9){
          b1.setText(croix);
          Joueur = !Joueur;
        }
      }
      else{
        if (b1==case1 || b1==case2 || b1==case3 || b1==case4 || b1==case5 || b1==case6 || b1==case7 || b1==case8 || b1==case9){
          b1.setText(rond);
          Joueur = !Joueur;
      }
 
 }
  }
  }

 // main
 public static void main(String args[]){
   
   new Morpion();
 }
 
 
 }
A voir également:

2 réponses

KX Messages postés 16733 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 31 janvier 2024 3 015
Modifié le 26 juin 2017 à 10:12
Bonjour,

La structure de tableau c'est pour éviter d'avoir du code répétitif comme tes
case1, case2, case3, case4, case5, case6, case7, case8, case9;

Heureusement que tu ne fais pas un puissance 4...

Il est plus pertinent de faire un tableau de cases, à deux dimensions, pour représenter ta grille 3x3, tu n'a alors qu'une seule variable à manipuler.
JButton[][] cases = new JButton[3][3];


Remarque : le choix du JButton n'est pas forcément le plus judicieux, un Component personnalisé avec des attributs personnalisé relatif à l'état de la case serait plus pertinent.
De plus la manière dont tu as fait ton ActionListener est pas terrible, il vaut mieux avoir un Listener dédié à chaque case, plutôt qu'un Listener commun obligé de calculer à quel composant il appartient.

PS. une fois une valeur choisie (rond ou carré) pour une case on ne peut pas la remplacer par une autre, il faudra désactiver cette possibilité.
La confiance n'exclut pas le contrôle
0
Tout d'abord, merci pour votre réponse rapide. Que voulez-vous dire par "De plus la manière dont tu as fait ton ActionListener est pas terrible, il vaut mieux avoir un Listener dédié à chaque case, plutôt qu'un Listener commun obligé de calculer à quel composant il appartient. " ? Il faut une classe ButtonListener pour chaque bouton? Désolé, on commence à peine la partie graphique de java avec les boutons et les listener, donc je suis pas encore super calé...
0
KX Messages postés 16733 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 31 janvier 2024 3 015
Modifié le 26 juin 2017 à 11:22
"il vaut mieux avoir un Listener dédié à chaque case, plutôt qu'un Listener commun obligé de calculer à quel composant il appartient"
Cela signifie que tu n'auras pas à faire
JButton b1 = (JButton)e.getSource();
      if(Joueur){  
        if (b1==case1 || b1==case2 || b1==case3 || b1==case4 || b1==case5 || b1==case6 || b1==case7 || b1==case8 || b1==case9){

En effet, le Listener sera lié à un seul bouton, par exemple la case 4, donc il n'y a pas besoin de tester quelle est la source pour savoir quoi faire avec tel ou tel bouton, ce sera toujours la case 4 qui sera associé à ce bouton, donc tous les traitements ne concerneront que ce bouton et on n'a pas à s'occuper des autres.

"Il faut une classe ButtonListener pour chaque bouton?"
Non, juste un objet différent, mais ça peut être la même classe - qui ne s'occupera que d'un seul bouton.

Ci-dessous un exemple de code corrigé, ça fait toujours plus ou moins la même chose, mais avec des pratiques différentes.

import java.awt.*;
import javax.swing.*;

public class Morpion extends JFrame {
    private final Case[][] cases;
    private boolean joueur = false;

    public Morpion() {
        super("Morpion");
        setSize(300, 300);
        setLocationRelativeTo(null);
        setDefaultCloseOperation(EXIT_ON_CLOSE);

        setLayout(new GridLayout(3, 3));
        cases = new Case[3][3];

        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                add(cases[i][j] = new Case());
            }
        }

        setVisible(true);
    }

    private void choixCase(Case c) {
        if (c.getEtat() != Etat.VIDE) {
            return;
        }

        c.setEtat(joueur ? Etat.ROND : Etat.CROIX);

        joueur = !joueur;

        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                if (cases[i][j].getEtat() == Etat.VIDE) {
                    return;
                }
            }
        }

        JOptionPane.showMessageDialog(this, "Partie terminée !");

        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                cases[i][j].setEtat(Etat.VIDE);
            }
        }
    }

    private enum Etat {
        VIDE, ROND, CROIX
    };

    private class Case extends JButton {
        private Etat etat;

        public Case() {
            setEtat(Etat.VIDE);
            addActionListener(e -> choixCase(this));
        }

        public Etat getEtat() {
            return etat;
        }

        public void setEtat(Etat etat) {
            this.etat = etat;

            switch (etat) {
            case VIDE:
                setText("");
                setBackground(Color.LIGHT_GRAY);
                break;
            case ROND:
                setText("O");
                setBackground(Color.ORANGE);
                break;
            case CROIX:
                setText("X");
                setBackground(Color.PINK);
                break;
            }
        }
    }

    public static void main(String[] args) {
        new Morpion();
    }
}
1