commit 30c2482ec277b10c4ae2966faa3a86a4a6a63043 Author: Laureηt Date: Tue Jun 20 21:05:21 2023 +0200 init diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..36195cc --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,7 @@ +{ + "java.project.referencedLibraries": [ + "lib/**/*.jar", + "/usr/share/java/junit.jar", + "/usr/share/java/hamcrest-core.jar" + ] +} \ No newline at end of file diff --git a/LISEZ-MOI.txt b/LISEZ-MOI.txt new file mode 100644 index 0000000..79d3f03 --- /dev/null +++ b/LISEZ-MOI.txt @@ -0,0 +1,65 @@ +Nom : Fainsin +Prénom : Laurent +Groupe TP : I + +Les « ... » indiquent les endroits à compléter. + +=====[ Temps passé ]============================================================ + +Ces informations de temps sont demandées à titre indicatif et ne sont pas +prises en compte dans la notation du projet. + +Toutes les durées sont à saisir en heures. Par exemple, si vous avez passé +1h45, il faudra indiquer 1.75. Si vous avez passé 2h30, il faudra indiquer +2.5. + +* Temps passé sur la V1 (en h) : 7.5 +* Temps passé sur la V2 (en h) : 0.5 + + +=====[ Questions ]============================================================== + +-------------------------------------------------------------------------------- +Pourquoi l'exception OperationInterditeException ne peut pas être définie +comme vérifiée par le compilateur ? +-------------------------------------------------------------------------------- + +PartieSafe.retirer doit lever l'exception OperationInterditeException, mais on ne +peut pas (à cause de l'override) lui faire lever plus d'exceptions que +CoupInvalideException. Il faut alors que OperationInterditeException ne soit pas +vérifié à la compilation, on construit alors OperationInterditeException comme +héritant de RuntimeException. + + +-------------------------------------------------------------------------------- +Expliquer ce qu'il faut faire pour ajouter un nouveau niveau de jeu, par +exemple la stratégie lente (C13). Pour plus de précision, on numérotera +les étapes à faire. +-------------------------------------------------------------------------------- + +1. Créer une nouvelle Classe implémentant l'interface Stratégie +2. Définir sa méthode nbPrise +3. Ajouter son identifiant (nom) dans le switch de Jouer.parsePlayer() +4. Dans le cas de sa sélection (case), affecter à strat la stratégie (constructeur) + + +-------------------------------------------------------------------------------- +Expliquer ce qui permet, dans votre conception, de changer dynamiquement +(en cours d'exécution du programme) la stratégie d'un joueur (C14). +-------------------------------------------------------------------------------- + +La stratégie du joueur est un attribut (de la classe) on peut donc la ré-attribuer en +cours de partie. +On peut créer la méthode de classe setStrat(Stratégie) dans cet unique but. + + +=====[ Explications ]=========================================================== + +-------------------------------------------------------------------------------- +Donner ici les explications supplémentaires utiles à la compréhension du +travail rendu. +-------------------------------------------------------------------------------- + +Utiliser un Tab size de 4 pour avoir une lecture correcte. + +-------------------------------------------------------------------------------- diff --git a/allumettes/Arbitre.java b/allumettes/Arbitre.java new file mode 100644 index 0000000..fd0335c --- /dev/null +++ b/allumettes/Arbitre.java @@ -0,0 +1,125 @@ +package allumettes; + +public class Arbitre { + + // Attributs + + /** Joueurs de la partie */ + private Joueur j1; + private Joueur j2; + + /** Joueur jouant actuellement */ + private Joueur courant; + + /** Détermine si l'arbitre vérifie la triche */ + private Boolean confiant = false; + + // Constructeurs + + /** + * Construire un arbitre à partir de deux joueurs. + * + * @param j1 Joueur n°1 + * @param j2 Joueur n°2 + */ + public Arbitre(Joueur j1, Joueur j2) throws ConfigurationException { + if (j1 == null) { + throw new ConfigurationException("j1 n'existe pas"); + } else if (j2 == null) { + throw new ConfigurationException("j2 n'existe pas"); + } else { + this.j1 = j1; + this.j2 = j2; + this.courant = j1; + } + } + + // GETS + + /** + * Déterminer quel joueur ne joue pas actuellement. + */ + private Joueur getAutre() { + if (this.courant == j1) { + return this.j2; + } else { + return this.j1; + } + } + + // SETs + + public void setConfiant(Boolean confiant) { + this.confiant = confiant; + } + + /** + * Permet de changer le joueur courant de la partie + */ + private void swapCourant() { + if (this.courant == this.j1) { + this.courant = this.j2; + } else { + this.courant = this.j1; + } + } + + // Méthodes + + /** + * Arbitrer un jeu d'allumettes. + * + * @param game Jeu que l'on arbitre + */ + public void arbitrer(Jeu game) { + while (true) { + int nbPrise; + System.out.format("Nombre d'allumettes restantes : %d\n", game.getNombreAllumettes()); + try { + + // le joueur choisit sont coup + if (this.confiant) { + nbPrise = this.courant.getPrise(game); + } else { + nbPrise = this.courant.getPrise(new PartieSafe(game)); + } + + // l'arbitre énonce le coup + if (nbPrise == 1 || nbPrise == 0 || nbPrise == -1) { + System.out.format("%s prend %d allumette.\n", this.courant.getNom(), nbPrise); + } else { + System.out.format("%s prend %d allumettes.\n", this.courant.getNom(), nbPrise); + } + + // l'arbitre vérifie la validité du coup + if (nbPrise > game.getNombreAllumettes()) { + throw new CoupInvalideException(nbPrise, String.format("> %d", game.getNombreAllumettes())); + } else if (nbPrise > Jeu.PRISE_MAX) { + throw new CoupInvalideException(nbPrise, String.format("> %d", Jeu.PRISE_MAX)); + } else { + game.retirer(nbPrise); + } + + // l'arbitre passe la main + this.swapCourant(); + System.out.println(); + break; + + } catch (OperationInterditeException e) { + System.out.format("Abandon de la partie car %s triche !\n", this.courant.getNom()); + throw e; + } catch (CoupInvalideException e) { + System.out.format("Impossible ! %s\n\n", e.getMessage()); + } + } + } + + /** + * Déterminer le vainqueur en fin de partie. + */ + public void afficherGagnant() { + System.out.format("%s perd !\n", this.getAutre().getNom()); + System.out.format("%s gagne !\n", this.courant.getNom()); + } + +} diff --git a/allumettes/ConfigurationException.java b/allumettes/ConfigurationException.java new file mode 100644 index 0000000..9f8d9f2 --- /dev/null +++ b/allumettes/ConfigurationException.java @@ -0,0 +1,16 @@ +package allumettes; + +/** Exception qui indique que la configuration d'une partie est incorrecte. + * @author Xavier Crégut + * @version 1.4 + */ +public class ConfigurationException extends RuntimeException { + + /** Initaliser une ConfigurationException avec le message précisé. + * @param message le message explicatif + */ + public ConfigurationException(String message) { + super(message); + } + +} diff --git a/allumettes/CoupInvalideException.java b/allumettes/CoupInvalideException.java new file mode 100644 index 0000000..92f1f38 --- /dev/null +++ b/allumettes/CoupInvalideException.java @@ -0,0 +1,29 @@ +package allumettes; + +/** Exception qui indique qu'un coup invalide est joué. + * @author Xavier Crégut + * @version $Revision: 1.3 $ + */ +public class CoupInvalideException extends Exception { + + /** Nombre d'allumettes prises. */ + private int nbAllumettes; + + /** Initialiser CoupInvalideException à partir du nombre d'allumettes + * prises et le problème constaté. Par exemple, on peut avoir nombre + * d'allumettes qui vaut 0 et le problème "< 1". + * @param nb le nombre d'allumettes prises + * @param probleme le problème sur le nombre d'allumettes + */ + public CoupInvalideException(int nb, String probleme) { + super("Nombre d'allumettes invalide : " + nb + " (" + probleme + ")"); + this.nbAllumettes = nb; + } + + /** Indiquer le nombre d'allumettes qu'un joueur a voulu prendre. + * @return le nombre d'allumettes qu'un joueur a voulu prendre. */ + public int getNombreAllumettes() { + return this.nbAllumettes; + } + +} diff --git a/allumettes/Expert.java b/allumettes/Expert.java new file mode 100644 index 0000000..6f405aa --- /dev/null +++ b/allumettes/Expert.java @@ -0,0 +1,25 @@ +package allumettes; + +public class Expert implements Strategie { + + // TODO: à généraliser ? + + @Override + public int nbPrise(Jeu game, String nom) { + int prise = 0; + switch (game.getNombreAllumettes() % 4) { + case 0: + prise = 3; + break; + case 1: + case 2: + prise = 1; + break; + case 3: + prise = 2; + break; + } + return prise; + } + +} diff --git a/allumettes/Humain.java b/allumettes/Humain.java new file mode 100644 index 0000000..add24aa --- /dev/null +++ b/allumettes/Humain.java @@ -0,0 +1,34 @@ +package allumettes; + +import java.util.Scanner; + +public class Humain implements Strategie { + + /** + * Scanner qui permet de récupérer les entrées des joueurs humains sc est static + * car avoir plus d'un scanner ouvert à la fois semble faire bugger la lecture. + */ + private static Scanner sc = new Scanner(System.in); + + @Override + public int nbPrise(Jeu game, String nom) throws CoupInvalideException { + int prise = 1; + while (true) { + try { + System.out.printf("%s, combien d'allumettes ? ", nom); + String input = sc.nextLine(); + if (input.equals("triche")) { + game.retirer(1); + System.out.format("[Une allumette en moins, plus que %d. Chut !]\n", game.getNombreAllumettes()); + } else { + prise = Integer.parseInt(input); + break; + } + } catch (java.lang.NumberFormatException e) { + System.out.println("Vous devez donner un entier."); + } + } + return prise; + } + +} diff --git a/allumettes/Jeu.java b/allumettes/Jeu.java new file mode 100644 index 0000000..4d1ce55 --- /dev/null +++ b/allumettes/Jeu.java @@ -0,0 +1,21 @@ +package allumettes; + +public interface Jeu { + + /** Nombre maximal d'allumettes pouvant être prises. */ + int PRISE_MAX = 3; + + /** Obtenir le nombre d'allumettes encore en jeu. + * @return nombre d'allumettes encore en jeu + */ + int getNombreAllumettes(); + + /** Retirer des allumettes. Le nombre d'allumettes doit être compris + * entre 1 et PRISE_MAX, dans la limite du nombre d'allumettes encore + * en jeu. + * @param nbPrises nombre d'allumettes prises. + * @throws CoupInvalideException tentative de prendre un nombre invalide d'alumettes + */ + void retirer(int nbPrises) throws CoupInvalideException; + +} diff --git a/allumettes/Jouer.java b/allumettes/Jouer.java new file mode 100644 index 0000000..3b2d7d3 --- /dev/null +++ b/allumettes/Jouer.java @@ -0,0 +1,130 @@ +package allumettes; + +/** + * Lance une partie du jeu des allumettes en fonction des arguments fournis sur + * la ligne de commande. + * + * @author Xavier Crégut + * @version $Revision: 1.5$ + */ +public class Jouer { + + /** + * Lancer une partie. En argument sont donnés les deux joueurs sous la forme + * nom@stratégie. + * + * @param args la description des deux joueurs + */ + public static void main(String[] args) { + + Joueur j1 = null; + Joueur j2 = null; + Arbitre arbitre = null; + Jeu game = null; + + try { + + verifierNombreArguments(args); + + if (args.length > 2) { + j1 = parsePlayer(args[1]); + j2 = parsePlayer(args[2]); + } else { + j1 = parsePlayer(args[0]); + j2 = parsePlayer(args[1]); + } + + arbitre = new Arbitre(j1, j2); + arbitre.setConfiant(args[0].equals("-confiant")); + game = new Partie(); + + } catch (ConfigurationException e) { + System.out.println("\nErreur : " + e.getMessage()); + afficherUsage(); + System.exit(1); + } + + try { + while (game.getNombreAllumettes() > 0) { + arbitre.arbitrer(game); + } + arbitre.afficherGagnant(); + } finally { + System.exit(0); + } + + } + + /** + * Créer un joueur à partir d'une chaine de caractères. + * + * @param arg chaine de caractère permettant de créer le joueur + * @throws ConfigurationException si le joueur ne peut pas être créé + */ + private static Joueur parsePlayer(String arg) throws ConfigurationException { + String[] pre = arg.split("@"); + if (pre.length != 2) { + throw new ConfigurationException("Configuration d'un joueur invalide"); + } + + String nom = pre[0]; + + Strategie strat; + switch (pre[1].toLowerCase()) { + case "naif": + strat = new Naif(); + break; + case "rapide": + strat = new Rapide(); + break; + case "expert": + strat = new Expert(); + break; + case "humain": + strat = new Humain(); + break; + case "lente": + strat = new Lente(); + break; + case "tricheur": + strat = new Tricheur(); + break; + default: + throw new ConfigurationException(String.format("Stratégie de %s invalide", nom)); + } + return new Joueur(nom, strat); + } + + /** + * Vérifier si le nombre d'arguments fournis dans la ligne de commande est + * cohérent. + * + * @param args arguments de la ligne de commande + * @throws ConfigurationException si les argument ne sont pas correctes + */ + private static void verifierNombreArguments(String[] args) throws ConfigurationException { + final int nbJoueurs = 2; + if (args.length < nbJoueurs) { + throw new ConfigurationException("Trop peu d'arguments : " + args.length); + } + if (args.length > nbJoueurs + 1) { + throw new ConfigurationException("Trop d'arguments : " + args.length); + } + } + + /** + * Afficher des indications sur la manière d'exécuter cette classe. + */ + public static void afficherUsage() { + System.out.println("\n" + + "Usage :" + + "\n\t" + "java allumettes.Jouer joueur1 joueur2" + + "\n\t\t" + "joueur est de la forme nom@stratégie" + + "\n\t\t" + "strategie = naif | rapide | expert | humain | tricheur | lente" + + + "\n\n\t" + "Exemple :" + + "\n\t\t" + "java allumettes.Jouer Xavier@humain Ordinateur@naif" + + "\n"); + } + +} diff --git a/allumettes/Joueur.java b/allumettes/Joueur.java new file mode 100644 index 0000000..5802a62 --- /dev/null +++ b/allumettes/Joueur.java @@ -0,0 +1,75 @@ +package allumettes; + +public class Joueur { + + // Attributs + + /** Le nom du joueur */ + private String nom; + + /** Stratégie adoptée par le joueur */ + private Strategie strat; + + // Constructeurs + + /** + * Construire un joueur à partir de son nom et du nom de sa stratégie. + * + * @param nom nom du joueur + * @param strat stratégie à adopter + */ + public Joueur(String nom, Strategie strat) { + + if (nom == null) { + throw new ConfigurationException("Un joueur n'a pas de nom"); + } else if (strat == null) { + throw new ConfigurationException(this.nom + " n'a pas de stratégie"); + } else { + this.nom = nom; + this.strat = strat; + } + } + + // GETs + + public String getNom() { + return this.nom; + } + + // SETs + + public void setNom(String nom) throws ConfigurationException { + if (nom == null) { + throw new ConfigurationException(this.nom + "doit avoir un nouveau nom valide"); + } else { + this.nom = nom; + } + } + + public void setStrat(Strategie strat) throws ConfigurationException { + if (strat == null) { + throw new ConfigurationException(this.nom + "doit avoir une stratégie valide"); + } else { + this.strat = strat; + } + } + + // Méthodes + + /** + * Obtenir le nombre d'allumettes que le joueur prends. + * + * @param game Le jeu auquel on prend des allumettes + * @return le nombre d'allumettes que le joueur prends + * @throws CoupInvalideException si le coup + * @throws ConfigurationException si le jeu fournis est null + */ + public int getPrise(Jeu game) throws CoupInvalideException, ConfigurationException { + if (game == null) { + throw new ConfigurationException(this.nom + " ne trouve pas la partie"); + } else { + return this.strat.nbPrise(game, this.nom); + } + } + +} diff --git a/allumettes/Lente.java b/allumettes/Lente.java new file mode 100644 index 0000000..e8da1ef --- /dev/null +++ b/allumettes/Lente.java @@ -0,0 +1,10 @@ +package allumettes; + +public class Lente implements Strategie { + + @Override + public int nbPrise(Jeu game, String nom) { + return 1; + } + +} diff --git a/allumettes/Naif.java b/allumettes/Naif.java new file mode 100644 index 0000000..52f99ec --- /dev/null +++ b/allumettes/Naif.java @@ -0,0 +1,21 @@ +package allumettes; + +import java.util.Random; + +public class Naif implements Strategie { + + /** Générateur de nombres aléatoire */ + private Random random = new Random(); + + @Override + public int nbPrise(Jeu game, String nom) { + int rd = random.nextInt(Jeu.PRISE_MAX) + 1; + int nb = game.getNombreAllumettes(); + if (rd > nb) { + return nb; + } else { + return rd; + } + } + +} diff --git a/allumettes/OperationInterditeException.java b/allumettes/OperationInterditeException.java new file mode 100644 index 0000000..c298dfb --- /dev/null +++ b/allumettes/OperationInterditeException.java @@ -0,0 +1,5 @@ +package allumettes; + +public class OperationInterditeException extends RuntimeException { + +} diff --git a/allumettes/Partie.java b/allumettes/Partie.java new file mode 100644 index 0000000..8d46260 --- /dev/null +++ b/allumettes/Partie.java @@ -0,0 +1,48 @@ +package allumettes; + +public class Partie implements Jeu { + + // Attributs + + /** variable stockant le nombre d'allumettes encore en jeu */ + private int nbAllumettes; + + // Constructeurs + + /** Constructeur par défaut de la classe Partie. */ + public Partie() { + this.nbAllumettes = 13; + } + + /** + * Constructeur de la classe Partie. + * + * @param nbAllumettes nombre d'allumettes initiales ( > 0 ) + */ + public Partie(int nbAllumettes) { + if (nbAllumettes < 1) { + throw new ConfigurationException("Nombre d'allumettes initiales incorrectes ( < 1 )"); + } else { + this.nbAllumettes = nbAllumettes; + } + } + + // GETs + + @Override + public int getNombreAllumettes() { + return this.nbAllumettes; + } + + // Méthodes + + @Override + public void retirer(int nbPrises) throws CoupInvalideException { + if (nbPrises < 1) { + throw new CoupInvalideException(nbPrises, "< 1"); + } else { + this.nbAllumettes -= nbPrises; + } + } + +} diff --git a/allumettes/PartieSafe.java b/allumettes/PartieSafe.java new file mode 100644 index 0000000..14533c5 --- /dev/null +++ b/allumettes/PartieSafe.java @@ -0,0 +1,32 @@ +package allumettes; + +public class PartieSafe implements Jeu { + + // ATTRIBUTS + + Jeu vraiGame; + + // CONSTRUCTEUR + + /** + * Constructeur d'une partie dont le nombre d'allumettes ne peut être modifié. + * + * @param game Jeu que l'on utilise pour créer le proxy + */ + public PartieSafe(Jeu game) { + this.vraiGame = game; + } + + // MÉTHODES + + @Override + public void retirer(int nbPrises) { + throw new OperationInterditeException(); + } + + @Override + public int getNombreAllumettes() { + return vraiGame.getNombreAllumettes(); + } + +} diff --git a/allumettes/Rapide.java b/allumettes/Rapide.java new file mode 100644 index 0000000..9b8c6fb --- /dev/null +++ b/allumettes/Rapide.java @@ -0,0 +1,15 @@ +package allumettes; + +public class Rapide implements Strategie { + + @Override + public int nbPrise(Jeu game, String nom) { + int nb = game.getNombreAllumettes(); + if (nb > Jeu.PRISE_MAX) { + return Jeu.PRISE_MAX; + } else { + return nb; + } + } + +} diff --git a/allumettes/Strategie.java b/allumettes/Strategie.java new file mode 100644 index 0000000..030deb1 --- /dev/null +++ b/allumettes/Strategie.java @@ -0,0 +1,14 @@ +package allumettes; + +public interface Strategie { + + /** + * Renvoyer le nombre d'allumettes que le joueur doit prendre. + * + * @param nb nombre d'allumettes encore en jeu + * @param nom nom du joueur + * @return nombre d'allumettes à prendre + */ + int nbPrise(Jeu game, String nom) throws CoupInvalideException; + +} diff --git a/allumettes/TestArbitre.java b/allumettes/TestArbitre.java new file mode 100644 index 0000000..74d66af --- /dev/null +++ b/allumettes/TestArbitre.java @@ -0,0 +1,41 @@ +package allumettes; + +import org.junit.*; + +public class TestArbitre { + + Partie game = new Partie(100); + + Joueur j1 = new Joueur("j1", new Rapide()); + Joueur j2 = new Joueur("j2", new Lente()); + Joueur j3 = new Joueur("j3", new Tricheur()); + + @Test + public void TestConstructeur() { + Arbitre a1 = new Arbitre(j1, j2); + Arbitre a2 = new Arbitre(j1, j2); + a1.setConfiant(true); + a2.setConfiant(false); + } + + @Test + public void TestArbitrer() { + Arbitre a1 = new Arbitre(j1, j2); + a1.setConfiant(false); + a1.arbitrer(game); + } + + @Test(expected = OperationInterditeException.class) + public void TestArbitrerTricheur() { + Arbitre a1 = new Arbitre(j3, j2); + a1.arbitrer(game); + } + + @Test + public void TestArbitrerTricheurConfiant() { + Arbitre a1 = new Arbitre(j3, j2); + a1.setConfiant(true); + a1.arbitrer(game); + } + +} diff --git a/allumettes/TestLente.java b/allumettes/TestLente.java new file mode 100644 index 0000000..5278708 --- /dev/null +++ b/allumettes/TestLente.java @@ -0,0 +1,26 @@ +package allumettes; + +import static org.junit.Assert.assertEquals; + +import java.util.Random; + +import org.junit.*; + +public class TestLente { + + Strategie strat = new Lente(); + + @Test + public void TestRetirer() throws CoupInvalideException { + + Random rd = new Random(); + + for (int i = 0; i < 100; i++) { + Partie game = new Partie(rd.nextInt(100) + 1); + int nb = strat.nbPrise(game, "nom"); + assertEquals(nb, 1); + } + + } + +} diff --git a/allumettes/TestPartie.java b/allumettes/TestPartie.java new file mode 100644 index 0000000..94ed463 --- /dev/null +++ b/allumettes/TestPartie.java @@ -0,0 +1,48 @@ +package allumettes; + +import org.junit.*; +import static org.junit.Assert.assertEquals; + +public class TestPartie { + + @Test(expected = ConfigurationException.class) + public void TestConstructeurNegatif() { + new Partie(-1); + } + + @Test(expected = ConfigurationException.class) + public void TestConstructeurNul() { + new Partie(0); + } + + @Test + public void TestConstructeurPositif() { + new Partie(1); + } + + @Test(expected = CoupInvalideException.class) + public void TestRetirerNegatif() throws CoupInvalideException { + new Partie(1).retirer(-1); + } + + @Test(expected = CoupInvalideException.class) + public void TestRetirerNul() throws CoupInvalideException { + new Partie(1).retirer(0); + } + + @Test + public void TestRetirerPositif() throws CoupInvalideException { + Partie game = new Partie(20); + game.retirer(1); + assertEquals(game.getNombreAllumettes(), 19); + game.retirer(2); + assertEquals(game.getNombreAllumettes(), 17); + game.retirer(3); + assertEquals(game.getNombreAllumettes(), 14); + game.retirer(4); + assertEquals(game.getNombreAllumettes(), 10); + game.retirer(10); + assertEquals(game.getNombreAllumettes(), 0); + } + +} diff --git a/allumettes/TestPartieSafe.java b/allumettes/TestPartieSafe.java new file mode 100644 index 0000000..2be9e31 --- /dev/null +++ b/allumettes/TestPartieSafe.java @@ -0,0 +1,24 @@ +package allumettes; + +import org.junit.*; + +public class TestPartieSafe { + + PartieSafe game = new PartieSafe(new Partie(10)); + + @Test(expected = OperationInterditeException.class) + public void TestRetirerNegatif() throws CoupInvalideException { + game.retirer(-1); + } + + @Test(expected = OperationInterditeException.class) + public void TestRetirerNul() throws CoupInvalideException { + game.retirer(0); + } + + @Test(expected = OperationInterditeException.class) + public void TestRetirerPositif() throws CoupInvalideException { + game.retirer(1); + } + +} diff --git a/allumettes/TestRapide.java b/allumettes/TestRapide.java new file mode 100644 index 0000000..1f95a5d --- /dev/null +++ b/allumettes/TestRapide.java @@ -0,0 +1,54 @@ +package allumettes; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; + +import java.util.Random; + +import org.junit.*; + +public class TestRapide { + + Strategie strat = new Rapide(); + + @Test + public void TestSuperieur() throws CoupInvalideException { + + Random rd = new Random(); + + for (int i = 0; i < 100; i++) { + Partie game = new Partie(rd.nextInt(1000) + Jeu.PRISE_MAX); + int nb = strat.nbPrise(game, "nom"); + assertEquals(nb, Jeu.PRISE_MAX); + } + } + + @Test + public void TestInferieur() throws CoupInvalideException { + + for (int i = 1; i < Jeu.PRISE_MAX; i++) { + Partie game = new Partie(i); + int nb = strat.nbPrise(game, "nom"); + assertNotEquals(nb, Jeu.PRISE_MAX); + assertEquals(nb, i); + } + + } + + @Test + public void TestArbitre() throws CoupInvalideException { + + Joueur j1 = new Joueur("j1", new Rapide()); + Joueur j2 = new Joueur("j2", new Rapide()); + Arbitre arbitre = new Arbitre(j1, j2); + + for (int i = 1; i < 100; i++) { + Partie game = new Partie(i); + while (game.getNombreAllumettes() > 0) { + arbitre.arbitrer(game); + } + } + + } + +} diff --git a/allumettes/Tricheur.java b/allumettes/Tricheur.java new file mode 100644 index 0000000..eed9910 --- /dev/null +++ b/allumettes/Tricheur.java @@ -0,0 +1,13 @@ +package allumettes; + +public class Tricheur implements Strategie { + + @Override + public int nbPrise(Jeu game, String nom) throws CoupInvalideException { + System.out.println("[Je triche...]"); + game.retirer(game.getNombreAllumettes() - 2); + System.out.format("[Allumettes restantes : %d]\n", game.getNombreAllumettes()); + return 1; + } + +} diff --git a/testeur.sh b/testeur.sh new file mode 100644 index 0000000..a46d121 --- /dev/null +++ b/testeur.sh @@ -0,0 +1,104 @@ +#!/bin/bash + +# ------------------------------------------------------- +# Programme de test en boîte noire pour les 13 allumettes +# ------------------------------------------------------- + +usage() { + echo "Erreur : $1" + echo + echo "Usage : sh testeur.sh [-d dossier] fichier.run..." + exit 1 +} + +warning() { + echo "**** $1" 1>&2 +} + +mainClass=allumettes.Jouer +mainFile=`echo $mainClass | tr . /`.java + +# Déterminer si l'option -enconding latin1 est nécessaire +javacOpt= +if file -i $mainFile | grep iso-8859 > /dev/null 2>&1 ; then + echo "Le fichier $mainClass est en latin1. Utilisation de l'option -encoding latin1 de javac" + javacOpt="-encoding latin1" +fi + +# Traiter les arguments de la ligne de commande +# | Un seul argument possible -d pour déterminer le dossier dans lequel +# | mettre les résutlats du test (.computed et .diff) +if [ "$1" = "-d" ] ; then + shift + testdiropt="$1" + shift + [ -d "$testdiropt" ] || mkdir "$testdiropt" + if [ ! -d "$testdiropt" ] ; then + usage "$testdiropt n'est pas un dossier" + elif [ ! -w "$testdiropt" ] ; then + usage "impossible d'écrire dans $testdiropt" + fi +fi + +if [ ! -z "$testdiropt" ] ; then + echo "Les résultats seront dans $testdiropt" +fi + + +# Jouer les tests +if javac $javacOpt $mainFile ; then + while [ "$1" ] ; do + test="$1" + shift + + if [ ! -f "$test" ] ; then + warning "Fichier de test inexitant : $test" + continue + elif [ ! -r "$test" ] ; then + warning "Fichier de test interdit en lecture : $test" + continue + fi + + testName=$(basename $test .run) + outputDir=${testdiropt:-$(dirname $test)} + + if [ "$testName" = "$(basename $test)" ] ; then + warning "Test ignoré (le suffixe doit être .run) : $test" + continue + fi + + + # Définir les noms de fichiers utilisés + computed=$outputDir/$testName.computed + expected=${test%.run}.expected + diff=$outputDir/$testName.diff + + + if [ ! -r "$expected" ] ; then + warning "Fichier de résultat absent ou interdit en lecture : $expected" + continue + fi + + # Lancer le test + sh $test > $computed 2>&1 + + # Transformer le résultat en utf8 (si nécessaire) + if file -i $computed | grep iso-8859 > /dev/null 2>&1 ; then + echo "Résultat en latin1. Je transforme en utf8." + recode latin1..utf8 $computed + fi + + # Afficher le résultat + echo -n "$testName : " + if diff -Bbw $computed $expected > $diff 2>&1 ; then + echo "ok" + else + echo "ERREUR" + cat $diff + echo "" + fi + done +else + echo "Erreur de compilation !" +fi + diff --git a/to-1sn-2020-pr-02-sujet.pdf b/to-1sn-2020-pr-02-sujet.pdf new file mode 100644 index 0000000..d0e2efc Binary files /dev/null and b/to-1sn-2020-pr-02-sujet.pdf differ