Bonjour chers lecteurs,
Aujourd’hui nous vous proposons un article sous forme d’atelier pratique. Toutefois, il est conseillé d’avoir suivi tous nous autres articles concernant le JAVA avant de tenter de réaliser cet atelier.
En effet nous allons réaliser un prototype un peu moins avancé du célèbre jeu Windows :
J’ai nommé « Le démineur ».
Nous allons traiter uniquement la partie remplissage de la carte et ne nous occupons donc pas de la partie saisie.
Tout d’abord je vais vous rappeler les règles de ce jeu. Lorsque vous appuyez sur une case, celle-ci nous indique le contenu de la case. Il peut s’agir de chiffres qui indiquent le nombre de bombes avec lesquelles la case choisie est en contact, ceci vaut pour les huit directions possibles : nord, nord-est, est, sud-est, sud, sud-ouest, ouest et nord-ouest.
Deuxièmement, il peut s’agir d’une bombe. Si vous en touchez une, la partie est terminée.
Finalement, la case peut être neutre et donc vide.
Afin de réaliser notre mini-Démineur, il est primordial d’analyser le problème en tenant compte des règles citées précédemment.
Bien je vais vous laisser chercher par vous mêmes, la solution se trouve ci-dessous.
Comment allons-nous procéder ?
Nous devons avant tout initialiser un certain nombre de variables qui nous serviront tout au long de notre programme, puis nous générerons la carte en y plaçant un certain nombre de bombes. Ce nombre sera stocké dans une variable, afin de pouvoir le modifier dans le cas où nous envisageons d’ajouter un degré de difficulté à notre jeu.Finalement, nous irons saisir pour chaque case, le nombre de bombes qui entourent celle-ci.
Vous êtes toujours motivés j’espère, au boulot !
De quoi avons-nous besoin ?
Pour réaliser ce tutoriel nous allons devoir employer toutes les notions vues jusqu’ici en matière de Java. Commençons par initialiser nous variables et notre carte qui n'est autre qu'une matrice.
Nous partions du principe que les cases vides sont représentes par des 0 et les bombes par des 9.
// Signe de la bombe public static final char bombe = 9; //Fonction main public static void main(String[] args) { Scanner sc = new Scanner(System.in); //déclarationde variables int randLigne, randCollone, cpt; //variables de génération du tableau int maxLigne = 10; //Nombre de lignes pour notre carte int maxCollone = 10; //Nombre de Collones pour notre Carte int nbrBombes = 10; //Nombre de bombes dans la carte // Initialisation de la matrice qui nous servira de Carte int tableau[][] = new int[maxLigne][maxCollone];
COMMENT PLACER LES BOMBES ?
Maintenant que nous avons toutes les variables et notre matrice, il s'agit d'initialiser le tout ensemble en y plaçant les bombes. Nous procédons en tirant une ligne au sort et une colonne au sort puis nous plaçons notre bombe. Seul petit détail à prendre en compte est qu'il ne faut pas placer une bombe dans une case qui en contient déjà une.System.out.println("BIENVENU AU SUPER MINI-DEMINEUR !!!"); System.out.println(); //PLACEMENT DES BOMBES cpt = 0; while (cpt < nbrBombes) { //Création aléatoire de l'endroit où nous plaçons nos bombes randLigne = (int) (Math.random() * (maxLigne)); randCollone = (int) (Math.random() * (maxCollone)); // Si la case ne contien pas de bombe on en met une puis on incrémente notre compteur de bombes if (tableau[randLigne][randCollone] != bombe) { tableau[randLigne][randCollone] = bombe; cpt++; } }
COMMENT REMPLIR LES INDICATEURS
Nous avons maintenant une carte avec des bombes, mais celle-ci ne nous dit pas combien de bombes il y a autour de chaque case.
Vous ne le savez peut-être encore, mais nous sommes confrontés à un problème. Nous devons en effet aller contrôler toutes les cases qui entourent chaque case.
Si je prends l'exemple de la case 2, nous devons contrôler s'il y a une bombe ou pas dans les cases,
un, trois, quatre, cinq et six. Toutefois, vous l'aurez remarqué les trois cases ou c'est écrit "RIEN" n’existent pas et donc le compilateur va crasher si vous essayez de connaitre leur contenu. Nous constatons donc que de connaitre l'emplacement de la case que nous remplissons est crucial si nous voulons que notre code s’exécute sans erreurs et gère tous les cas.
Nous allons créer une méthode qui s'occupera de remplir chaque champ. Elle commencera par situer la case, puis déterminera dans un premier temps si les différentes cases qui l'entourent existent, si c'est le cas nous contrôlons alors dans un deuxième temps si la case adjacente en question contient une bombe, puis finalement si c'est le cas nous incrémenterons notre résultat de bombe avant de contrôler la prochaine direction possible. Une fois les huit directions contrôlées nous retournons le contenu de notre variable résultat à notre fonction main. Elle sauvegarde ainsi le nombre de bombes qui entourent la cellule concernée.
Les fonctions "minimum", "estAdjacentBombe" et "calculCellules" sont des fonctions auxiliaires à la fonction remplir champ. Elles sont documentées dans le code ci-dessous.
/* * Fonction qui situe puis controle si la case existe si c'est le cas on incremente une variable resultat qui retourne le nombre de bombes qui adjacente une case. * @ prend en parametre des int et une matrice tableau * @ retourn le nombre de bombes qui entourent la case */ public static int remplirChamp(int ligne, int maxLigne, int collone, int maxCollone, int[][] tableau) { // variables locales int resultat = 0; int droite, gauche, bas, haut, hautGauche, hautDroite, basGauche,basDroite; // Nous situons notre case par rapport à toutes les directions, c'est à dire combien //de cases il y a à gauche , droite , haut , bas etc par rapport à la matrice. droite= calculCellules(collone + 1, maxCollone, true); gauche = calculCellules(collone + 1, maxCollone, false); bas = calculCellules(ligne + 1, maxLigne, true); haut = calculCellules(ligne + 1, maxLigne, false); // Nous définissons le minimum entre directions pour avoir la limite de //jusqu'ou on peut aller dans la direction donnée hautGauche=minimum(haut,gauche); hautDroite=minimum(haut,droite); basGauche=minimum(bas,gauche); basDroite=minimum(bas,droite); //Nous controllons qu'il y aie des cases qui existent à gauche if (gauche > 0 ) { // Nous controlons s'il y a une bombe à gauche à l'aide de la méthode "estAdjacentBombe" if (estAdjacentBombe(ligne, 0, collone, -1, tableau)) { //Si la bombe existe nous incrémentons la valeur résultat resultat++; } } //Même principe que la portion de code "Gauche" if (droite > 0 ) { if (estAdjacentBombe(ligne, 0, collone, 1, tableau)) { resultat++; } } //Même principe que la portion de code "Gauche" if (bas > 0 ) { if (estAdjacentBombe(ligne, 1, collone, 0, tableau)) { resultat++; } } //Même principe que la portion de code "Gauche" if (haut > 0 ) { if (estAdjacentBombe(ligne, -1, collone, 0, tableau)) { resultat++; } } //Même principe que la portion de code "Gauche" if (hautGauche > 0 ) { if (estAdjacentBombe(ligne, -1, collone, -1, tableau)) { resultat++; } } //Même principe que la portion de code "Gauche" if (hautDroite > 0 ) { if (estAdjacentBombe(ligne, -1, collone, 1, tableau)) { resultat++; } } //Même principe que la portion de code "Gauche" if (basDroite > 0 ) { if (estAdjacentBombe(ligne, 1, collone, 1, tableau)) { resultat++; } } //Même principe que la portion de code "Gauche" if (basGauche > 0 ) { if (estAdjacentBombe(ligne, 1, collone, -1, tableau)) { resultat++; } } return resultat; } /* * Fonction qui controle si la case située a * @ prend en parametre les coordonnées de base de la cellule, puis les coordonnées de la * cellule qu'on doit controler et finalement le tableau à deux dimentions * @ retourn un boolean qui indique si la case visée contient ou pas une bombe */ public static boolean estAdjacentBombe(int xBase, int positionX, int yBase, int positionY, int[][] tableau) { boolean boolAdjacent = false; // Nous changeons la valeur de booladjacent à true si la case visée contient une bombe if(tableau[((int) (xBase + positionX))][(int) (yBase + positionY)]==bombe){ boolAdjacent=true; } //Nous retournons le résultat du controle return boolAdjacent; } /* * Fonction qui défini le minimum entre une variable A et une variable B * @ prend en parametre des valeurs entieres * @ retourn la valeur plus petite */ public static int minimum(int a, int b) { int min = 0; if (a < b) { min = a; } else { min = b; } // retourne la valeur la plus petite des deux valeurs entre a et b return min; }; /* * Fonction qui retourne le nombre de collones ou lignes par rapport aux bords * */ public static int calculCellules(int currentCol, int nbrCol, boolean positif) { //Initialisation de la variable local int nbrCollones = 0; // J'entends par positif la droite pour les collones ou le bas pour les lignes if (positif) { nbrCollones = nbrCol - currentCol; } else { nbrCollones = nbrCol - (nbrCol - currentCol); if (nbrCollones >= 0) { nbrCollones--; } } //Nous retournons notre valeur final return nbrCollones; } };
REMPLIR TOUTES LES CELLULES
Maintenant que nous avons une méthode "remplirCellules" qui traite chaque cellule il nous suffit de les parcourir toutes à l'aide de deux boucles for imbriquées. Toutefois, nous devons faire attention à ne pas écraser les bombes lorsque les cases en contiennent . C'est pourquoi il est important de contrôler le contenu de la cellule avant de lui affecter un résultat.
//REMPLISSAGE DES INDICATEURS DE BOMBES //Boucle sur les lignes for (int li = 0; li < maxLigne; li++) { //Boucle sur les collones for (int col = 0; col < maxCollone; col++) { //ON controle que la case ne contienne déja une bombe if (tableau[li][col] != bombe) { tableau[li][col] = remplirChamp(li, maxLigne, col, maxCollone, tableau); } }; };
AFFICHER LE RÉSULTAT FINAL
Nous voilà à la fin de notre mini-démineur. Maintenant que vous avez rempli toutes les cases il vous suffit de les parcourir en affichant l'intégral du tableau à l'aide de deux boucles imbriquées for.
Voici le code:
//AFFICHAGE DU RESULTAT //Boucle sur les lignes for (int li = 0; li < maxLigne; li++) { //Boucles sur les collones for (int col = 0; col < maxCollone; col++) { //Nous affichons un * s'il s'agit d'une bombe if(tableau[li][col]==bombe){ System.out.print('*'); }else{ System.out.print(tableau[li][col]); } }; //Retour a la ligne lorsqu'on change de ligne System.out.println(); }; //Notre mini-démineur est poli System.out.println("En vous souhaitant une bonne journée !!!"); }// ferme la fonction main
Voilà nous espérons que ce premier atelier pratique vous aura plu. Vous pouvez accéder à l'ensemble du code en suivant ce lien.
Voici un petit aperçu du résultat final.
Voici un petit aperçu du résultat final.