Comment ça se passe: on écrit "Démineur" en 4 minutes

image

D'un traducteur: ce poste est une traduction de l' article original de Maki Chiz, un codeur expérimenté qui non seulement écrit de grands programmes, mais démontre également les capacités de différentes langues à ses collègues, débutants et professionnels.

Démineur est un jeu amusant, beaucoup d'entre nous y jouent. Peut-être que vous voulez fabriquer vous-même un démineur?

Skillbox recommande: La profession en ligne «Profession de développeur Web» .

Nous vous rappelons: pour tous les lecteurs de «Habr» - une remise de 10 000 roubles lors de l'inscription à un cours Skillbox en utilisant le code promo «Habr».
Le caractère unique du jeu est qu'il est très simple et en même temps très excitant. Il n'y a pas de mécanique de jeu astucieuse dans Démineur, il vous suffit de cliquer sur les cases, en espérant qu'il n'y ait pas de mines en dessous.

Je suggère d'essayer d'écrire "Démineur" sur le traitement. Il s'agit d'un excellent outil qui vous permet de créer des applications graphiques en Java. Lien ici .

Avant de commencer, je dirai que ce tutoriel est destiné à ceux qui connaissent déjà Java. L'expérience du traitement est facultative.

Alors c'est parti. La première étape consiste à déterminer l'état du jeu. J'ai décidé de l'implémenter comme ça.

int gridW; // grid width int gridH; // grid height int numMines; // number of mines on the board int[][] mines; // entry is 1 for having a mine and 0 for not boolean[][] flags; // entry is true if you have flagged that spot boolean[][] revealed; // entry is true if that spot is revealed 

Tout semble avoir du sens ici, à l'exception de cette section: int [] [] mines . Pourquoi le réseau minier est-il un entier et non un booléen? Le fait est que cela permet de calculer facilement combien de mines sont proches d'une certaine position.

 int calcNear(int x, int y) { int i=0; for (int offsetX=-1; offsetX<=1; offsetX++) { for (int offsetY=-1; offsetY<=1; offsetY++) { i+=mines[offsetX+x][offsetY+y]; } } return i; } 

Ce code détermine le nombre de mines situées à proximité d'un site spécifique. Après avoir supprimé les exceptions, nous obtenons quelque chose de similaire à ceci:

 boolean outBounds(int x,int y){ return x<0||y<0||x>=gridW||y>=gridH; } int calcNear(int x, int y) { if(outBounds(x,y))return 0; int i=0; for (int offsetX=-1; offsetX<=1; offsetX++) { for (int offsetY=-1; offsetY<=1; offsetY++) { if (outBounds(offsetX+x, offsetY+y))continue; i+=mines[offsetX+x][offsetY+y]; } } return i; } 

La tâche principale du jeu lui-même est de révéler les carrés commençant au point x, y.

 void reveal(int x, int y){ if(outBounds(x,y))return; if(revealed[x][y])return; revealed[x][y]=true; if(calcNear(x,y)!=0)return; reveal(x-1,y-1); reveal(x-1,y+1); reveal(x+1,y-1); reveal(x+1,y+1); reveal(x-1,y); reveal(x+1,y); reveal(x,y-1); reveal(x,y+1); } 

En conséquence, nous avons l'algorithme suivant:

  • Si la position est en dehors du champ, terminez;
  • Si le poste est divulgué, mettez fin;
  • Nous ouvrons la position actuelle;
  • Si nous avons une bombe près de la position actuelle, finissons;
  • Si nous avons atteint ce point lors de l'exécution de la fonction, la position actuelle dans le terrain de jeu a été trouvée et il n'y a pas de bombes à côté, ouvrez des carrés adjacents.

Fondamentalement, le reste du jeu est le même. Le code complet peut être trouvé en cliquant sur ce lien .

Si vous voulez en savoir plus sur la visualisation, lisez la suite.

Visualisation

Tout doit être clair ici, mais je vais expliquer les parties difficiles.

Nous avons donc une variable cellSize, qui détermine le nombre de pixels dans chaque carré.

 void settings(){ size(gridW*cellSize, gridH*cellSize); } 

Ainsi, nous créons un champ avec les côtés gridW x gridH, où les tailles de chaque carré seront égales à la valeur de cellSize.

Ensuite, nous retournons les variables à leur état d'origine.

 void setup(){ //initialize and clear the arrays mines=new int[gridW][gridH]; flags=new boolean[gridW][gridH]; revealed=new boolean[gridW][gridH]; for(int x=0;x<gridW;x++){ for(int y=0;y<gridH;y++){ mines[x][y]=0; flags[x][y]=false; revealed[x][y]=false; } } } 

Pour initialiser un champ:
 //Place numMines mines on the grid void placeMines(){ int i=0; while(i<numMines){//We don't want mines to overlap, so while loop int x=int(random(gridW)); int y=int(random(gridH)); if(mines[x][y]==1)continue; mines[x][y]=1; i++; } } //Clear the mines void clearMines() { for (int x=0; x<gridW; x++) { for (int y=0; y<gridH; y++) { mines[x][y]=0; } } } 

Et puis activez la réponse aux clics de souris.

 //We don't want the first click to be a mine boolean firstClick=true; void mousePressed() { int x=int(mouseX/cellSize); int y=int(mouseY/cellSize); //Right-click is flagging or de-flagging a square if (mouseButton==RIGHT) { flags[x][y]=!flags[x][y]; return; } else {//left-click //Avoid making the first click a mine if (firstClick) { firstClick=false; do { clearMines(); placeMines(); } while (calcNear(x,y)!=0); } //Check for game loss if (mines[x][y]!=0) { println("Dang!"); exit(); } else {//If game not lost, reveal starting from that square reveal(x, y); } } } 

Et la fonction d'affichage, nous l'appelons une fois pour chaque image.

 void draw() { background(0); //For each cell for (int x=0; x<gridW; x++) { for (int y=0; y<gridH; y++) { //The colors alternate for texture color col1=color(2*255/5); color col2=color(3*255/5); color txtColor=color(0); int near=calcNear(x, y); if (flags[x][y]) { col1=color(255, 0, 0); col2=color(4*255/5, 255/5, 255/5); } else if (revealed[x][y]) { col1=color(255/2); col2=color(255/2); } if (near==1)txtColor=color(255*1/4, 255*1/4, 255*3/4); if (near==2)txtColor=color(255*1/4, 255*3/4, 155*1/4); if (near==3)txtColor=color(255, 0, 0); if (near==4)txtColor=color(0, 0, 255); if (near==5)txtColor=color(255, 0, 0); boolean alternate=(x+y)%2==0; if (alternate) { fill(col2); stroke(col2); } else { fill(col1); stroke(col1); } //if(mines[x][y]>0){ //fill(0,255,0); //stroke(0,255,0); //} rect(x*cellSize, y*cellSize, cellSize, cellSize); //If there is a mine near this spot and it is revealed if (near>0&&revealed[x][y]) { fill(txtColor); noStroke(); textAlign(LEFT, TOP); textSize(cellSize); text(""+near, x*cellSize, y*cellSize); } } } } 

Et c'est tout, voici notre Démineur.

Le jeu semble simple, mais dans l'ensemble, il est entièrement fonctionnel. Et rappelez-vous: le démineur crée une dépendance!

Skillbox recommande:

Source: https://habr.com/ru/post/fr425317/


All Articles