📜 ⬆️ ⬇️

How it is done: we write "Minesweeper" in 4 minutes

image

From the translator: this post is a translation of the original article by Maki Chiz, an experienced coder who not only writes cool programs, but also demonstrates the capabilities of various languages ​​to his colleagues, both beginners and professionals.

Minesweeper is a fun game, many of us play it. Maybe you want to do the "Sapper" yourself?

Skillbox recommends: Educational online course "Profession Web Developer . "
')
We remind: for all readers of "Habr" - a discount of 10,000 rubles when recording for any Skillbox course on the promotional code "Habr".
The uniqueness of the game is that it is very simple and at the same time very exciting. In Minesweeper, there is no clever gameplay mechanics, you just click on the squares, hoping that there are no mines under them.

I suggest trying to write "Sapper" in Processing. This is a great tool that allows you to create graphic applications in Java. Link to it here .

Before you begin, I will say that this tutorial is designed for those who already know Java. Experience with Processing is optional.

So here we go. The first step is to determine the state of the game. I decided to implement it like this.

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 

Everything here seems to make sense, except for this section: int [] [] mines . Why is the mine grid an integer, not a boolean? The fact is that it makes it easy to calculate how many mines are near a certain 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; } 

This code determines how many mines are located near a specific site. After we remove the exceptions, we get something like this:

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

The main task of the game itself is to reveal the squares, starting from the 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); } 

As a result, we have the following algorithm:


In principle, the rest of the game is the same. The full code can be found by clicking on this link .

If you want to learn about visualization, read on.

Visualization

Everything should be clear here, but I will explain the difficult parts.

So, we have the variable cellSize, which determines the number of pixels in each square.

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

Thus, we create a field with gridW x gridH sides, where the dimensions of each square will be equal to the cellSize value.

Then we return the variables to their original state.

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

To initialize the field:
 //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; } } } 

And then turn on the response to clicks with the mouse.

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

And the display function, we call it once for each frame.

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

And that's it, that's our “Minesweeper”.

The game looks simple, but in general it is fully functional. And remember: "Minesweeper" is addictive!

Skillbox recommends:

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


All Articles