Mini-jeu du Morpion en Java: Tic-Tac-Toe

Mini-jeu du Morpion en Java: Tic-Tac-Toe

Tu en as marre de coder des « Hello World » ? Tu veux créer un vrai petit jeu qui fonctionne, avec des boutons qui clignotent (enfin, presque), et une logique qui tient la route ? Alors installe-toi confortablement, on va créer un jeu de morpion en Java avec NetBeans !

Ce projet est idéal si tu apprends Java, si tu veux maîtriser Swing (la bibliothèque graphique de Java) et comprendre comment séparer la logique du jeu de l’interface graphique. Ce sont des compétences utiles, que tu sois étudiant, développeur en herbe, ou juste curieux.

🛠️ 1. Mise en place du projet dans NetBeans

Étape 1 : Création de l’application

  1. Ouvre NetBeans.
  2. Crée un nouveau projet Java Application nommé TicTacToe.
  3. Dans le dossier Source Packages, ajoute un nouveau package :
com.myapp.tictactoe

Étape 2 : Ajout des classes

Crée deux fichiers Java dans ce package :

  • GameModel.java : pour la logique du jeu.
  • GameView.java : pour l’interface graphique et les interactions.

💡 2. GameModel.java – Le cerveau du jeu

Ici, on code toute la logique du jeu : qui joue, qui gagne, si la partie est finie, etc.

package com.myapp.tictactoe;

public class GameModel {
    public enum Player { X, O, NONE }
    private Player[] board = new Player[9];
    private Player currentPlayer = Player.X;
    private boolean gameOver = false;

    public GameModel() { reset(); }

    public void reset() {
        for (int i = 0; i < 9; i++) board[i] = Player.NONE;
        currentPlayer = Player.X;
        gameOver = false;
    }

    public Player getCurrentPlayer() { return currentPlayer; }
    public Player getCell(int idx) { return board[idx]; }
    public boolean isGameOver() { return gameOver; }

    public Player playMove(int idx) {
        if (gameOver || board[idx] != Player.NONE) return null;
        board[idx] = currentPlayer;
        Player winner = checkWinner();
        if (winner != Player.NONE) {
            gameOver = true;
            return winner;
        }
        if (isBoardFull()) {
            gameOver = true;
            return Player.NONE; // match nul
        }
        currentPlayer = (currentPlayer == Player.X) ? Player.O : Player.X;
        return null;
    }

    private boolean isBoardFull() {
        for (Player p : board)
            if (p == Player.NONE) return false;
        return true;
    }

    private Player checkWinner() {
        int[][] lines = {
            {0,1,2},{3,4,5},{6,7,8},
            {0,3,6},{1,4,7},{2,5,8},
            {0,4,8},{2,4,6}
        };
        for (int[] line : lines) {
            Player a = board[line[0]], b = board[line[1]], c = board[line[2]];
            if (a != Player.NONE && a == b && b == c) return a;
        }
        return Player.NONE;
    }
}

Explication simple :

  • La classe GameModel représente le plateau (un tableau de 9 cases).
  • Elle gère le joueur actuel, vérifie s’il y a un gagnant et gère les changements de tour.
  • La méthode playMove() est l’arbitre : elle accepte ou refuse un coup, et annonce si quelqu’un a gagné (ou s’il y a égalité).

Et oui, ici pas de triche : si la case est déjà prise, le joueur ne peut pas rejouer. Fair-play avant tout !


🖼️ 3. GameView.java – L’interface graphique Swing

Maintenant qu’on a le cerveau, il nous faut le corps : l’interface graphique que les joueurs vont utiliser pour poser leurs X ou O.

package com.myapp.tictactoe;

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

public class GameView extends JFrame {
    private GameModel model = new GameModel();
    private JButton[] cells = new JButton[9];
    private JLabel statusLabel = new JLabel("Au tour de X");
    private JButton resetBtn = new JButton("Recommencer");

    public GameView() {
        super("Morpion");
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setLayout(new BorderLayout(10,10));
        JPanel grid = new JPanel(new GridLayout(3,3,5,5));
        for (int i = 0; i < 9; i++) {
            final int idx = i;
            cells[i] = new JButton("");
            cells[i].setFont(new Font(Font.SANS_SERIF, Font.BOLD, 48));
            cells[i].addActionListener(e -> handleClick(idx));
            grid.add(cells[i]);
        }
        JPanel bottom = new JPanel();
        bottom.add(statusLabel);
        bottom.add(resetBtn);
        resetBtn.addActionListener(e -> initGame());

        add(grid, BorderLayout.CENTER);
        add(bottom, BorderLayout.SOUTH);
        pack();
        setLocationRelativeTo(null);
        setVisible(true);
    }

    private void initGame() {
        model.reset();
        statusLabel.setText("Au tour de X");
        for (JButton b : cells) {
            b.setText("");
            b.setEnabled(true);
        }
    }

    private void handleClick(int idx) {
        GameModel.Player winner = model.playMove(idx);
        GameModel.Player p = model.getCell(idx);
        cells[idx].setText(p == GameModel.Player.X ? "X" : "O");
        if (winner != null) {
            if (winner == GameModel.Player.NONE) {
                statusLabel.setText("Match nul.");
            } else {
                statusLabel.setText("Le joueur " + winner + " a gagné !");
            }
            disableAll();
        } else {
            statusLabel.setText("Au tour de " + model.getCurrentPlayer());
        }
    }

    private void disableAll() {
        for (JButton b : cells) b.setEnabled(false);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(GameView::new);
    }
}

Détails intéressants :

  • On utilise un JPanel en GridLayout pour dessiner les 9 boutons (3×3).
  • Chaque bouton représente une case du plateau. Quand on clique, il appelle la méthode handleClick() qui interagit avec le modèle (GameModel).
  • Le bouton « Recommencer » remet le jeu à zéro : très utile pour éviter les disputes sur qui a gagné.

Quelques points techniques utiles à comprendre

  • Enum Player est utilisé ici pour distinguer facilement les joueurs (X, O, ou NONE).
  • MVC simplifié : on sépare la logique (GameModel) de l’affichage (GameView). C’est une bonne habitude pour tout projet !
  • SwingUtilities.invokeLater() : lance l’interface sur le thread d’interface graphique. C’est la bonne manière de faire avec Swing.

Résultat final

Quand tu exécutes l’application, une jolie fenêtre apparaît avec :

  • Un plateau 3×3,
  • Des X et des O qui s’affichent à chaque clic,
  • Un message indiquant le vainqueur ou l’égalité,
  • Un bouton pour tout recommencer.

Comments

No comments yet. Why don’t you start the discussion?

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *