This commit is contained in:
Laureηt 2023-06-20 21:05:21 +02:00
commit 30c2482ec2
Signed by: Laurent
SSH key fingerprint: SHA256:kZEpW8cMJ54PDeCvOhzreNr4FSh6R13CMGH/POoO8DI
25 changed files with 982 additions and 0 deletions

7
.vscode/settings.json vendored Normal file
View file

@ -0,0 +1,7 @@
{
"java.project.referencedLibraries": [
"lib/**/*.jar",
"/usr/share/java/junit.jar",
"/usr/share/java/hamcrest-core.jar"
]
}

65
LISEZ-MOI.txt Normal file
View file

@ -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.
--------------------------------------------------------------------------------

125
allumettes/Arbitre.java Normal file
View file

@ -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());
}
}

View file

@ -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);
}
}

View file

@ -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;
}
}

25
allumettes/Expert.java Normal file
View file

@ -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;
}
}

34
allumettes/Humain.java Normal file
View file

@ -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;
}
}

21
allumettes/Jeu.java Normal file
View file

@ -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;
}

130
allumettes/Jouer.java Normal file
View file

@ -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");
}
}

75
allumettes/Joueur.java Normal file
View file

@ -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);
}
}
}

10
allumettes/Lente.java Normal file
View file

@ -0,0 +1,10 @@
package allumettes;
public class Lente implements Strategie {
@Override
public int nbPrise(Jeu game, String nom) {
return 1;
}
}

21
allumettes/Naif.java Normal file
View file

@ -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;
}
}
}

View file

@ -0,0 +1,5 @@
package allumettes;
public class OperationInterditeException extends RuntimeException {
}

48
allumettes/Partie.java Normal file
View file

@ -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;
}
}
}

View file

@ -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();
}
}

15
allumettes/Rapide.java Normal file
View file

@ -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;
}
}
}

14
allumettes/Strategie.java Normal file
View file

@ -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;
}

View file

@ -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);
}
}

26
allumettes/TestLente.java Normal file
View file

@ -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);
}
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}
}
}

13
allumettes/Tricheur.java Normal file
View file

@ -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;
}
}

104
testeur.sh Normal file
View file

@ -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

BIN
to-1sn-2020-pr-02-sujet.pdf Normal file

Binary file not shown.