怎么做:我们在4分钟内写下“扫雷”

图片

译者的话:这篇文章是Maki Chiz的原始文章的翻译,Maki Chiz是一位经验丰富的编码人员,他不仅编写出色的程序,还向他的初学者和专业人士展示了多种语言的功能。

扫雷是一个有趣的游戏,我们很多人都玩。 也许您想自己做扫雷车?

Skillbox建议:在线职业“ Web开发人员职业”

我们提醒您: 对于所有“ Habr”读者来说,使用“ Habr”促销代码注册任何Skillbox课程时均可享受10,000卢布的折扣。
游戏的独特之处在于它非常简单,同时又非常令人兴奋。 在《扫雷》中没有狡猾的游戏机制,您只需单击方块,希望它们下方没有地雷。

我建议尝试在“处理”上写“ Minesweeper”。 这是一个很棒的工具,可让您使用Java创建图形应用程序。 链接到这里

在开始之前,我会说本教程是为那些已经了解Java的人准备的。 处理经验是可选的。

所以我们开始。 第一步是确定游戏状态。 我决定像这样实现它。

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 

除了本节之外,这里的所有内容似乎都有意义: int [] [] mines 。 为什么矿井网格是整数而不是布尔值? 事实是,这使计算某个位置附近的地雷数变得容易。

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

该代码确定特定地点附近有多少座地雷。 删除异常后,我们得到类似于以下内容的信息:

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

游戏本身的主要任务是揭示从点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); } 

结果,我们有以下算法:

  • 如果位置不在字段中,请结束;
  • 如果公开了职位,请结束;
  • 我们打开当前位置;
  • 如果我们在当前位置附近有炸弹,请结束;
  • 如果我们在执行该功能期间达到了这一点,则在运动场中找到了当前位置,并且旁边没有炸弹,打开了相邻的方块。

基本上,其余的游戏都是一样的。 单击此链接可以找到完整的代码。

如果您想了解可视化,请继续阅读。

可视化

这里的一切应该都清楚了,但是我将解释一些困难的部分。

因此,我们有一个变量cellSize,它确定每个正方形中的像素数。

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

因此,我们创建一个边为gridW x gridH的字段,其中每个正方形的大小将等于cellSize的值。

然后,我们将变量恢复为原始状态。

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

要初始化字段:
 //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; } } } 

然后打开对鼠标单击的响应。

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

而显示功能,我们每帧调用一次。

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

仅此而已,这是我们的扫雷车。

游戏看起来很简单,但是总体来说它功能齐全。 请记住:扫雷器会上瘾!

Skillbox建议:

Source: https://habr.com/ru/post/zh-CN425317/


All Articles