Présentation
Le démineur est un jeu de réflexion dont le but est de localiser des mines cachées dans un champ virtuel avec pour seule indication le nombre de mines dans les zones adjacentes. Le champ de mine est représenté par une grille, qui peut avoir différentes formes : deux ou trois dimensions, pavage rectangulaire ou non, etc.
Chaque case de la grille peut soit cacher une mine, soit être vide. Le but du jeu est de découvrir toutes les cases libres sans faire exploser les mines, c’est-à-dire sans cliquer sur les cases qui les dissimulent.
Lorsque le joueur clique sur une case libre et que toutes les cases adjacentes le sont également, une case vide est affichée. Si en revanche au moins l’une des cases avoisinantes contient une mine, un chiffre apparaît, indiquant le nombre de cases adjacentes contenant une mine. En comparant les différentes informations récoltées, le joueur peut ainsi progresser dans le déminage du terrain. S’il se trompe et clique sur une mine, il a perdu.
Nous avons là l’essentiel utile pour nous attaquer à l’exercice, je vous encourage cependant à lire la définition complète sur Wikipedia car les algorithmes de placement des bombes et pour trouver les valeurs des cases y sont proposés.
Le code Javascript
// variables var canvas, ctx, posX, posY, T, C, N,F,i,images,tuiles,voisins; // quand la page est chargée window.onload = function() { canvas = document.getElementById('canvas'); ctx = canvas.getContext('2d'); canvas.width = 480; canvas.height = 480; posX = canvas.offsetLeft; posY = canvas.offsetTop; T = 32; C = 480/T; loadImages(3); } // chargement des images function loadImages(nbImg){ images = []; for(i=1; i<nbImg+1; i++){ var b = new Image(); b.src = "assets/tuile"+i+".jpg"; b.onload = function() { images.push(this); if(--nbImg==0) init(); }; } } // initialisation du jeu function init() { tuiles = []; voisins = []; N = 20; F = C*C-N; // placer les tuiles for (i=0;i<C*C;i++){ var t = {}; t.x = parseInt(i%C)*T; t.y = parseInt(i/C)*T; t.width = t.height = T; t.id = i; t.frame = 1; t.val = 0; tuiles.push(t); voisins.push([]); } // placer les bombes while(N) { var n = parseInt(Math.random()*tuiles.length); var p = tuiles[n]; if(p.val!=9) { p.val=9; N--; trouveValeurs(n,p.x/T,p.y/T,C-1); } } render(); canvas.addEventListener("click", action, false); } // cliquer sur une case function action(e){ i = parseInt((e.clientX-posX)/T)+parseInt((e.clientY-posY)/T)*C; if(tuiles[i].frame==1) tuiles[i].frame=2, F--; if(tuiles[i].val==9) { tuiles[i].frame=3; finPartie(); return; } if(!tuiles[i].val) decouvre(i); if(F==0) finPartie(3); render(); } // trouver les valeurs des cases function trouveValeurs(i,X,Y,L){ if(Y<L && tuiles[i+C].val != 9) tuiles[i+C].val++; if(Y>0 && tuiles[i-C].val != 9) tuiles[i-C].val++; if(X<L && tuiles[i+1].val != 9) tuiles[i+1].val++; if(X>0 && tuiles[i-1].val != 9) tuiles[i-1].val++; if(X<L && Y>0 && tuiles[i-C+1].val != 9) tuiles[i-C+1].val++; if(X>0 && Y>0 && tuiles[i-C-1].val != 9) tuiles[i-C-1].val++; if(X<L && Y<L && tuiles[i+C+1].val != 9) tuiles[i+C+1].val++; if(X>0 && Y<L && tuiles[i+C-1].val != 9) tuiles[i+C-1].val++; } // découvrir les cases vides function decouvre(n){ trouveVoisin(n,tuiles[n].x/T,tuiles[n].y/T,C-1); for (var h = 0; h<voisins[n].length; h++){ if (voisins[n][h].frame==1) { if(!F--) finPartie(); voisins[n][h].frame = 2; decouvre(voisins[n][h].id); } } } // trouver les cases vides voisines function trouveVoisin(i,X,Y,L){ if(X>0 && !tuiles[i-1].val) voisins[i].push(tuiles[i-1]); if(X<L && !tuiles[i+1].val) voisins[i].push(tuiles[i+1]); if(Y>0 && !tuiles[i-C].val) voisins[i].push(tuiles[i-C]); if(Y<L && !tuiles[i+C].val) voisins[i].push(tuiles[i+C]); } // fin de partie function finPartie(){ render(); alert("Fin de partie, cliquez pour rejouer."); init(); } // Dessine le jeu function render() { for(var i=0; i<tuiles.length; i++){ ctx.drawImage(images[tuiles[i].frame-1], tuiles[i].x, tuiles[i].y); if(tuiles[i].val && tuiles[i].frame==2) afficheValeur(tuiles[i]); } } // Affiche la valeur de la pièce function afficheValeur(p) { ctx.fillStyle = "white"; ctx.font = "16px Arial"; ctx.textAlign = "center"; ctx.fillText(p.val, p.x+p.width/2, p.y+p.height/2+4); }