← Retour au portfolio

SAE 1.01 : 421

Projet scolaire · Développement Java

Contexte

Premier projet de développement en équipe à l'IUT, réalisé en 2 semaines. L'objectif : programmer le jeu de dés 421 en Java et créer une intelligence artificielle capable de rivaliser avec un joueur humain.

Le jeu 421 : Deux joueurs s'affrontent en lançant 3 dés pour former des combinaisons (figures) qui valent des points. La meilleure combinaison possible est 4-2-1, d'où le nom du jeu. Les joueurs misent des jetons selon la qualité de leurs résultats.

Le défi technique : Au-delà de l'implémentation des règles, développer un algorithme de décision pour le bot : quand relancer les dés ? Quelles combinaisons conserver ? Comment optimiser les chances de victoire ?

Objectifs

  • Implémenter les règles complètes du jeu 421 en Java
  • Développer une interface utilisateur pour jouer contre le bot
  • Créer un système de décision intelligent pour le bot adversaire
  • Gérer les paris et les combinaisons de dés

Itérations & variantes

  • Version procédurale : règles et scoring codés en logique classique pour valider la mécanique de base.
  • Version POO : refonte avec dés, lancer, manche et parties modélisés en classes pour clarifier les responsabilités.
  • Version IA : bot amélioré avec heuristique de décision (garde/relance) pour maximiser les chances de figures fortes.

Technologies

À propos

J'ai pu, à travers ce projet, me familiariser avec les compétences suivantes :

  • Le développement efficace : structuration du code et optimisation des performances
  • Le développement d'applications : création d'une application fonctionnelle complète
  • La programmation technique : POO, algorithmes de jeu, gestion des états
  • Le suivi de projet et code : versioning avec GitLab, travail d'équipe, intégration continue

Réalisations techniques

  • Logique algorithmique : détection des figures, calcul des scores
  • Intelligence artificielle : bot prenant des décisions intelligentes basées sur l'analyse des situations de jeu
  • Interface utilisateur : développement d'une interface permettant de jouer contre le bot

Extrait de code : classe Joueur

Portion de l'implémentation Java gérant un joueur du 421 : état, nombre de jetons, coups joués et interactions avec le leader ou le bot.

/**
 * Définition
 * La classe Joueur permet de créer et manipuler des joueurs.
 *
 * Attributs d'une instance :
 * - Le numéro du joueur (entier)
 * - Le nombre de jetons du joueur (entier)
 * - Si le joueur est un humain ou non (un ordinateur) (booléen)
 * - Un triplet qui représente le résultat actuel du joueur (instance de Triplet)
 *
 * Comportement d'une instance :
 * - On peut créer un nouveau joueur (humain ou ordinateur) à partir d'un numéro, d'un nombre de jetons.
 * - On peut connaître le numéro d'un joueur.
 * - On peut savoir si le joueur possède encore au moins un jeton.
 * - On peut demander au joueur de donner des jetons à un autre joueur.
 * - On peut jouer un coup en relançant des dés.
 * - On peut décider, lorsqu'on est leader, si on souhaite jouer un nouveau coup/
 * - On peut faire choisir un jet au joueur.
 * - On peut effectuer le tour d'un joueur leader.
 * - On peut effectuer le tour d'un joueur non leader.
 */
public class Joueur {

  private final int num;
  private int nbJetonsInit;
  private final boolean jHum;
  private final Triplet resultat;
  private String nom;

  /**
   * Pré-requis : 1 <= num <= 2 et nbJetonsInit > 0
   * Action : construit un nouveau joueur à partir de son numéro, son nombre
   * de jetons et s'il est humain ou non. Le résultat actuel du joueur (son
   * triplet) est initialisé par le constructeur : il est vide au début
   */
  public Joueur(int num, int nbJetonsInit, boolean jHum, String nom) {
    this.num = num;
    this.nbJetonsInit = nbJetonsInit;
    this.jHum = jHum;
    this.resultat = new Triplet();
    this.nom = this.nom;
  }

  public String getNom() {
    return this.nom;
  }

  public void setNom(String nom) {
    this.nom = nom;
  }

  //Méthodes d'instance
  /**
   * Résultat : le numéro du joueur
   */
  public int getNumero() {
    return this.num;
  }

  /**
   * Résultat : une représentation du joueur "this" en une chaîne de
   * caractères. Exemple : si j est le joueur ayant le numéro 5 et 1 jeton
   * j.toString() -> la chaîne "Joueur 5 : 1 jeton." si j2 est le joueur ayant
   * le numéro 1 et 4 jetons j2.toString() -> la chaîne "Joueur 1 : 4 jetons."
   */
  @Override
  public String toString() {
    return this.nom + " : " + this.nbJetonsInit + " jeton" + (this.nbJetonsInit > 1 ? "s" : "") + ".";
  }


  /**
   * Résultat : true si le joueur possède au moins un jeton, false sinon.
   */
  public boolean aAuMoinsUnJeton() {
    return (this.nbJetonsInit > 0);
  }

  /**
   * Action : this donne des jetons à autreJoueur sachant que le nombre de
   * points obtenue par this pour sa figure est nbPoints.
   */
  public void donneJetons(int nbPoints, Joueur autreJoueur) {
    this.nbJetonsInit -= nbPoints;
    autreJoueur.nbJetonsInit += nbPoints;
  }

  /**
   * Action : Relance les dés indiqués par le Jet jet passé en paramètre sur
   * le résultat actuel du joueur puis affiche le nouveau résultat obtenu. Le
   * numéro de coup est seulement utilisé pour l'affichage.
   */
  public void jouerCoup(int numeroDeCoup, Jet jet) {
    this.resultat.lancerDes(jet);
    Ut.afficherSL("Coup " + numeroDeCoup + " : " + this.resultat.toString());
  }

  /**
   * Action : demande à this, qui est le joueur leader, s'il veut jouer un
   * nouveau coup (avec re-saisie éventuelle de sa réponse jusqu'à ce qu'elle
   * soit correcte) s'il est humain, sinon le choix est fait d'après la
   * stratégie de la classe Strategie. Résultat : vrai si this veut jouer un
   * nouveau coup et faux sinon.
   */
  public boolean leaderVeutJouerNouveauCoup() {
    return this.jHum ? JeuUt.premierChoix("Voulez-vous jouer un nouveau coup ? ", "O", "N") : IntelligenceArtificielle.leaderRejoue(this.resultat.getFigure());
  }

  /**
   * Action : si this est humain, lui demande de choisir les dés à relancer
   * (avec re-saisie éventuelle de sa réponse jusqu'à ce qu'elle soit
   * correcte). Résultat : le jet choisi par this s'il est humain, un jet
   * choisi d'après la stratégie de la classe Strategie sinon.
   */
  public Jet jetChoisiParJoueur() {
    return this.jHum ? Jet.jetChoisiParHumain() : IntelligenceArtificielle.meilleurCoup(this.resultat.getFigure());
  }

  /**
   * Action : joue un tour du joueur leader. On annonce le début et la fin du
   * tour du joueur avec son numéro. Pour chaque coup à partir du 2ème coup du
   * tour du joueur, celui-ci commence par choisir les dés à relancer. Après
   * chaque coup, on affiche le numéro du coup et le résultat obtenu. On
   * rappelle que le joueur leader peut relacer des dés 1 ou 2 fois (3 coups
   * maximum). Résultat : un ResultatLeader contenant la figure obtenue par
   * this à l'issue de ce tour et le nombre de coups effectués.
   */
  public ResultatLeader jouerTourLeader() {
    Ut.afficherSL("Début du tour du joueur leader, " + this.nom);
    int nbCoups = 1;
    Jet jet = new Jet(true, true, true);
    jouerCoup(nbCoups++, jet);

    while (nbCoups < 3 && leaderVeutJouerNouveauCoup()) {
      jet = jetChoisiParJoueur();
      jouerCoup(nbCoups, jet);
      nbCoups++;
    }

    Ut.afficherSL("Fin du tour du joueur leader, " + this.nom);
    return new ResultatLeader(this.resultat.getFigure(), nbCoups);
  }

  /**
   * Action : joue un tour du joueur non leader en connaisant les resultats du
   * leader (et donc son nombre de coups). On annonce le début et la fin du
   * tour du joueur avec son numéro. Pour chaque coup à partir du 2ème coup du
   * tour du joueur, celui-ci commence par choisir les dés à relancer. Après
   * chaque coup, on affiche le numéro du coup et le résultat obtenu. Résultat
   * : la figure obtenue par this à l'issue de ce tour.
   */
  public Figure jouerTourNonLeader(ResultatLeader resultatLeader) {
    Ut.afficherSL("Début du tour du joueur non leader, " + this.nom);
    int nbCoups = 1;
    Jet jet = jetChoisiParJoueur();

    while (nbCoups <= resultatLeader.getNbCoups()) {
      jouerCoup(nbCoups, jet);
      jet = jetChoisiParJoueur();
      nbCoups++;
    }

    Ut.afficherSL("Fin du tour du joueur non leader, " + this.nom);
    return this.resultat.getFigure();
  }
}

Galerie & Rendu

Galerie en cours de préparation