Corrigé EVA programmeur 2010, langage Java.

Transcription

Corrigé EVA programmeur 2010, langage Java.
MINISTÈRE DE L’ÉCOLOGIE, DU DÉVELOPPEMENT DURABLE,
DES TRANSPORTS ET DU LOGEMENT
EXAMEN PROFESSIONNEL DE VÉRIFICATION
D’APTIDUDE AUX FONCTIONS DE
PROGRAMMEUR
___________
Session 2010
Correction langage Java
Langage: Java
Durée :
5 heures
Coefficient:
4
Notation:
sur 20
Nombre de pages du sujet
:
4 (y compris cette page)
Remarques générales
1 – le sujet comporte deux parties
:
•
un sujet général commun aux différents langages noté sur 6 (temps estimé
1h30)
•
un sujet spécifique au langage choisi noté sur 14 (temps estimé 3h30)
2 – si éventuellement il vous manquait des informations particulières pour
développer votre sujet, il vous revient de retenir les hypothèses adaptées à votre
solution, en les explicitant clairement.
3 – aucun document ou matériel électronique (calculette, ordinateur …) n’est
autorisé.
EVA Programmeur 2010- Corrigé du sujet Java
page 1/11
1ère partie
1. Sujet commun
L'algorithme proposé est le suivant :
1. Calcul de la longueur L du mot de passe.
2. Remplissage aléatoire dans le mot de passe des caractères requis :
- A minuscules.
- B majuscules.
- C chiffres.
- D caractères spéciaux.
3. Remplissage aléatoire des caractères restants en utilisant l'ensemble de l'alphabet
donné.
Le détail de cet algorithme est donné ci-dessous.
PRÉALABLE
Les variables suivantes seront utilisés dans l'algorithme :
- P : mot de passe calculé, sous forme d'un tableau de caractères.
- L : Longueur du mot de passe P.
- MINUSCULES[] : tableau de 26 caractères contenant les minuscules.
- MAJUSCULES[] : tableau de 26 caractères contenant les majuscules.
- CHIFFRES[] : tableau de 10 caractères contenant les chiffres.
- SPECIAUX[] : tableau de S caractères contenant les caractères spéciaux.
- TOUS[] : tableau de tous caractères possibles (concaténation des tableaux ci-dessus).
Conventions de notation prises :
- Un tableau de taille N est indexé de 0 à N-1.
- La valeur d'un tableau T à l'emplacement I est noté T[i].
DÉTAIL DU CALCUL DE LA LONGUEUR L DU MOT DE PASSE
La longueur doit satisfaire aux critères suivants :
- L est d'une longueur aléatoire entre Lmin et Lmax.
- L doit valoir au minimum de A+B+C+D.
- L doit valoir au maximum de Lmax.
Elle est calculée comme suit :
L = Lmin +randN(Lmax - Lmin +1)
Si L < A+B+C+D alors L = A+B+C+D.
Où :
randN(n) désigne une fonction qui renvoi un nombre entier aléatoire entre 0 inclus et n exclus
:
Fonction randN(n : entier) : int
randN(n) = Partie_Entiere(n.rand())
DÉTAIL DU REMPLISSAGEALÉATOIRE DANS LE MOT DE PASSE DES CARACTÈRESREQUIS
L'insertion des caractères obligatoires se fait comme suit :
Initialiser P avec des valeurs nulles.
ajouterAleatoirement(A, MINUSCULES[]).
ajouterAleatoirement(B, MAJUSCULES[]).
ajouterAleatoirement(C, CHIFFRES[]).
ajouterAleatoirement(D, SPECIAUX[]).
Où :
La fonction ajouterAleatoirement(n, alphabet) ajoute aléatoirement n caractères à P,
EVA Programmeur 2010- Corrigé du sujet Java
page 2/11
parmi ceux fournis dans le tableau "alphabet".
Fonction ajouterAleatoirement(n : entier, alphabet : tableau de caractères) : void
Pour i=1 à n :
Prendre une position j libre au hasard dans P : j = libreAleatoire().
Prendre un caractère c au hasard dans alphabet : c = randA(alphabet)
Affecter à P le caractère trouvé à la position trouvée : P[j] = c.
Où :
La fonction libreAleatoire() recherche un emplacement libre, au hasard, dans P. Pour
cela un indice est pris au hasard dans P et l'on boucle sur P depuis cet indice jusqu'à
trouver une valeur nulle (disponible).
Fonction libreAleatoire() : int
Tirer une position i au hasard dans P : i = randN(L).
Créer indice iter = 0 pour ne pas parcourir plus d'une fois le tableau
Tant que P[i] non nul (déjà pris) et iter<L :
iter = iter + 1
Si i = L-1 alors :
i = 0 (retourner en début de tableau une fois au bout).
Sinon :
i = i+1
Si P[i] est nul (emplacement libre trouvé) Alors :
Renvoyer i.
Sinon :
!!Indice libre non trouvé, Erreur (ne se produit pas car A+B+C+D ≤ L.)!!
La fonction randA(alphabet) tire un caractère au hasard dans le tableau alphabet.
Fonction randA(alphabet : tableau de caractères) : char
Tirer une position au hasard dans alphabet : i = randN(longeur(alphabet))
Renvoyer alphabet[i]
DÉTAIL DU REMPLISSAGE ALÉATOIRE DES CARACTÈRES RESTANTS
C'est l'étape la plus simple. Il suffit de parcourir le tableau P à la recherche des éléments
non remplis (nuls) et d'y affecter un élément quelconque sur l'alphabet complet (TOUS[])
du mot de passe :
Pour i=0 à L-1
Si P[i] est nul Alors :
P[i] = randA(TOUS[])
ALGORITHME COMPLET
En reprenant les éléments ci-dessus, l'algorithme général est :
// Longueur du mot de passe
L = Lmin +randN(Lmax - Lmin +1)
Si L < A+B+C+D alors L = A+B+C+D.
// Caractères requis
Pour i=1 à A:
Prendre une positionj libre au hasard dans P j: = libreAleatoire().
Prendre une minuscule au hasard : c = randA(MINUSCULES[])
P[j] = c.
Pour i=1 à B:
EVA Programmeur 2010- Corrigé du sujet Java
page 3/11
Prendre une positionj libre au hasard dans P j: = libreAleatoire().
Prendre une majuscule au hasard : c = randA(MAJUSCULES[])
P[j] = c.
Pour i=1 à C:
Prendre une positionj libre au hasard dans P j: = libreAleatoire().
Prendre un chiffre au hasard : c = randA(CHIFFRES[])
P[j] = c.
Pour i=1 à D:
Prendre une positionj libre au hasard dans P j: = libreAleatoire().
Prendre un caractère spécial au hasard : c = randA(SPECIAUX[])
P[j] = c.
// Caractères restants
Pour i=0 à L-1
Si P[i] est nul Alors :
P[i] = randA(TOUS[])
(les fonctions randA et libreAleatoire ne sont re-détaillées pour plus de lisibilité.).
EVA Programmeur 2010- Corrigé du sujet Java
page 4/11
2ème partie
1. Questions de syntaxe
1.1 Une variable système, ou d'environnement, Java peut être définie au démarrage d'une
application comme argument de la machine virtuelle Java, sous la forme
-DmaVariable=maValeur,
où maVariable et maValeur représentent respectivement la variable et sa valeur:
java -DmaVariable=maValeur
<autres arguments>
.
1.2 Oui, il suffit de n'utiliser que des directives compatibles avec la version 1.4 du langage et de
compiler cette classe avec les options
-source
"
1.4 -target 1.4
"
1.3 Une variable de type ThreadLocal est accessible et modifiable par l'ensemble des objets
instanciés dans un thread java. Sa portée est celle du thread courant, chaque thread ayant sa
propre valeur de cette variable. Elle permet par exemple de partager une valeur entre tous les
objets d'un même thread sans avoir à la transmettre en argument ni à la référencer
explicitement.
1.4 Cet extrait de code initialise un objet de type Propriété (liste de clé/valeurs) par lecture du
fichier app.cfg dans le classpath de l'application. Le caractère '/' signifie que ce fichier est à la
racine du classpath.
2. Problème: Le sudoku
2.0 PRÉALABLE: MODÉLISATIONGÉNÉRALEDE LA CLASSE SUDOKU
Le problème posé conduit à la conception de la classe Sudoku, dont la structure générale est la
suivante en Java.
Sudoku
// valeurs courantes du sudoku
- sudoku : int[][] = new int[9][9];
+ litSudoku(fichier : string) : void
+ valeurPermise(k : int, x : int, y : int) : boolean
+ valeursPermises(x : int, y : int) : boolean[]
+ resoudSudoku(): bolean
+ ecritSudoku(fichier : string) : void
La gestion des exceptions sera simplifiée et réduite aux seules exigences de l'énoncé.
2.1 LECTURE DU FICHIER CONTENANTLE SUDOKU NON RÉSOLU
Le format de fichier retenu est simple : un fichier de 9 lignes à 9 chiffres, ces chiffres allant de 0
à 9.
Dans l'exemple fourni, les deux premières lignes du fichier sont les suivantes
:
006095047
701040000
L'algorithme de lecture est le suivant
:
Fonction lireSudoku(fichier
:Fichier): void
Ouvrir le fichier
Pour chaque ligne d'indice y du fichier
:
Lire chaque caractère d'indice x et l'enregistrer dans sudoku[x][y]
EVA Programmeur 2010- Corrigé du sujet Java
page 5/11
!!Erreur si caractères non compris dans [0-9]
!!
!!Erreur si plus ou moins de 9 caractères.
!!
!!Erreur si plus ou moins de 9 lignes.
!!
Fermer le fichier.
Implémentation Java:
public void litSudoku(String fichier) throws Exception {
String ligne; // la ligne courante
int y = 0;
// la colonne courante
BufferedReader in = null;
try {
in = new BufferedReader(new FileReader(fichier));
while ((ligne = in.readLine()) != null) {
char[] valeurs = ligne.toCharArray();
if(valeurs.length != 9) {
throw new Exception("Nombre de colonnes incorrect");
}
for (int x=0; x<9; x++) {
try {
sudoku[x][y] = Integer.parseInt(
Character.toString(valeurs[x]));
} catch (NumberFormatException e) {
throw new Exception("valeur invalide");
}
}
y++;
}
if(y != 9) {
throw new Exception("Nombre de ligne incorrect");
}
} finally {
in.close();
}
}
2.2 TEST DE LA VALEUR K À L'EMPLACEMENT(X,Y)
L'algorithme consiste à parcourir la colonne x et la ligne y à la recherche de la valeur k.
Si non trouvée, il faut ensuite parcourir la région (carré 3x3) associée à cette case.
Fonction valeurPermise(k: int, x : int, y : int) : boolean
// recherche sur la colonne x et la ligne y
EVA Programmeur 2010- Corrigé du sujet Java
page 6/11
Pour i=1 à 9:
Si sudoku[x][i] = k ou sudoku [i][y] =: k
Retourner faux (sortie).
// recherche dans la région, coordonnées du coin supérieur gauche
bx = 3 * PartieEntiere(x/3)
by = 3 * PartieEntiere(y/3)
Pour i=1 à 9:
Pour j = 1 à 9:
Si sudoku [i][y] = k Alors:
Retourner faux (sortie)
Retourner vrai
Implémentation Java:
private boolean valeurPermise(int k, int x, int y) {
// parcours de la colonne x et de la ligne y
for (int i = 0; i < 9; i++) {
if((sudoku[x][i] == k) || (sudoku[i][y] == k)) {
return false;
}
}
// parcours région : bx, by coin supérieur gauche du carré
int bx = 3 * (x / 3), by = 3 * (y / 3);
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if(sudoku[bx + i][by + j] == k) {
return false;
}
}
}
return true;
}
2.3 RECHERCHE DE TOUTES LES VALEURS POSSIBLES À UNE POSITION (X,Y)
Une solution rapide, non optimale, est de tester toutes les valeurs de 0 à 9 à l'aide de la fonction
précédente
Fonction valeursPermises(x
: int, y : int) : boolean[] (solution 1, non optimale)
V : tableau à 10 élements de boolean. V[i] = vrai si i est possible, V[i] = faux sinon.
Pour i =0 à 9:
V[i] = estPermis(i, x, y)
Retourner V
Une solution plus optimale consiste à remplir le tableau de valeurs permises directement durant
la recherche de contraintes sur une valeur k (fusion des questions 2.2 et 2.3).
Fonction valeursPermises(x
: int, y : int) : boolean[] (solution 2, optimisé)
EVA Programmeur 2010- Corrigé du sujet Java
page 7/11
V : tableau à 10 élements de boolean. V[i] = vrai si i est possible, V[i] = faux sinon.
Pour i= 0 à 9:
V[i] = vrai // par défaut toute valeur est supposée permise
// recherche ligne et colonne
Pour i = 1 à 9:
V[sudoku[x][i]] = faux // valeur sudoku[x][i] prise sur la colonne x
V[sudoku[i][y]] = faux // valeur sudoku[i][y] prise sur la ligne y
// recherche région
Calculer les coordonnées du coin supérieur gauche de la région de :(x,y)
bx = 3 * PartieEntiere(x/3)
by = 3 * PartieEntiere(y/3)
Pour i=1 à 9:
Pour j = 1 à 9:
V[sudoku[bx + i][by + j]] = faux // valeur à cet emplacement prise
Retourner V
Implémentation Java
private boolean[] valeursPermises(int x, int{ y)
// tableau indiquant si une valeur, par son indice, est permise.
boolean permis[] = new boolean[10];
// par défaut toutesles valeurs sont permises
for (int i = 0; i < 10; i++) {
permis[i] = true;
}
// parcours de la colonne x et de la ligne y
for (int i = 0; i < 9; i++) {
permis[sudoku[x][i]] = false;
permis[sudoku[i][y]] = false;
}
// bx, by coin supérieur gauche du carré contenant x, y
int bx = 3 * (x / 3), by = 3 * (y / 3);
// Mise à jour de digits pour le carré
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
permis[sudoku[bx + i][by + j]] = false;
}
}
return permis;
}
2.4 RÉSOLUTION DU SUDOKU
EVA Programmeur 2010- Corrigé du sujet Java
page 8/11
La méthode retenue ici pour résoudre le sudoku passe par la récursivité
:
Fonction resoudSudoku(): void
[R] Rechercher la première case libre (égale à 0) du sudoku
S'il existe une valeur possible sur la case trouvée
:
Placer la première valeur de valeursPermises sur cette case.
Passer en récursivité depuis [R] avec les nouvelles valeurs du sudoku.
Sinon :
Revenir une étape en arrière avec la valeur permise suivante.
Implémentation Java:
public boolean resoudSudoku()
{
int coord[] =chercheCaseVide ();
int x = coord[0];
int y = coord[1];
if (x == -1) {
// toutes les cases sont remplies : sudoku résolu.
return true;
}
boolean[] possibilites = valeursPermises(x, y);
// On essaye pour la case x, y les valeurs possibles de 1 à 9
for (int i = 1; i <= 9; i++) {
if (possibilites[i]) {
sudoku[x][y] = i;
// On tente la résolution avec cette valeur sur la case x, y
if (resoudSudoku()) {
return true;
} else {
// pas de solution possible : revenir en arrière
sudoku[x][y] = 0;
}
}
}
return false;
}
Ce code fait appel à la méthode chercheCaseVide() qui donne les coordonnées de la première
case vide (égale à 0) par parcours direct du tableau. Si aucune case n'est trouvée, cette
méthode retourne (-1,-1) :
private int[] chercheCaseVide()
{
for (int x = 0; x < 9; x++) {
EVA Programmeur 2010- Corrigé du sujet Java
page 9/11
for (int y = 0; y < 9; y++) {
if (sudoku[x][y] == 0) {
return new int[]{x, y};
}
}
}
return new int[]{-1, -1};
}
Le programme général demandé dans cette question est alors :
Sudoku sudoku = new Sudoku()
;
sudoku.litSudoku();
sudoku.resoudSudoku();
sudoku.ecritSudoku();
La méthode ecritSudoku() est décrite ci-après.
2.5 ÉCRITURE DU SODOKU DANS UN FICHIER
Il s'agit de l'opération inverse à la lecture du fichier
:
Fonction ecrireSudoku(fichier
: Fichier): void
Ouvrir le fichier
Pour chaque ligne y=1 à 9 du sudoku
Pour chaque colonne x=1 à 9 du sudoku
:
Écrire sudoku[x][y] dans le fichier.
Écrire saut de ligne
Fermer le fichier
Implémentation Java:
public void ecritSudoku(String fichier) throws Exception
{
BufferedWriter out = null;
try {
out = new BufferedWriter(new FileWriter(fichier));
for (int y = 0; y < 9; y++) {
for (int x = 0; x < 9; x++) {
out.append("" + sudoku[x][y]);
}
out.append("\n");
}
out.append("\n");
} finally {
out.close();
}
EVA Programmeur 2010- Corrigé du sujet Java
page 10/11
}
♦♦♦
♦
EVA Programmeur 2010- Corrigé du sujet Java
page 11/11