Cara melakukannya: kita menulis "Minesweeper" dalam 4 menit

gambar

Dari seorang penerjemah: posting ini adalah terjemahan dari artikel asli oleh Maki Chiz, seorang pembuat kode berpengalaman yang tidak hanya menulis program yang hebat, tetapi juga menunjukkan kemampuan berbagai bahasa kepada rekan-rekannya, baik pemula maupun profesional.

Minesweeper adalah permainan yang menyenangkan, banyak dari kita yang memainkannya. Mungkin Anda ingin membuat Minesweeper sendiri?

Skillbox merekomendasikan: Profesi online "Profesi Pengembang Web" .

Kami mengingatkan Anda: untuk semua pembaca "Habr" - diskon 10.000 rubel saat mendaftar untuk kursus Skillbox apa pun menggunakan kode promosi "Habr".
Keunikan permainan ini adalah sangat sederhana dan pada saat yang sama sangat menarik. Tidak ada mekanisme permainan yang licik di Minesweeper, Anda cukup mengklik kotak, berharap tidak ada ranjau di bawah mereka.

Saya sarankan mencoba menulis "Minesweeper" pada Pemrosesan. Ini adalah alat yang hebat yang memungkinkan Anda untuk membuat aplikasi grafis di Java. Tautkan ke sini .

Sebelum memulai, saya akan mengatakan bahwa tutorial ini ditujukan untuk mereka yang sudah mengenal Java. Pengalaman dengan Pemrosesan adalah opsional.

Jadi di sini kita mulai. Langkah pertama adalah menentukan kondisi permainan. Saya memutuskan untuk mengimplementasikannya seperti ini.

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 

Segalanya tampak masuk akal di sini, kecuali untuk bagian ini: int [] [] ranjau . Mengapa grid tambang bilangan bulat dan bukan boolean? Faktanya adalah ini membuatnya mudah untuk menghitung berapa banyak ranjau yang dekat dengan posisi tertentu.

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

Kode ini menentukan berapa banyak ranjau yang terletak di dekat situs tertentu. Setelah kami menghapus pengecualian, kami mendapatkan sesuatu yang mirip dengan ini:

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

Tugas utama permainan itu sendiri adalah untuk mengungkapkan kotak mulai dari titik 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); } 

Hasilnya, kami memiliki algoritme berikut:

  • Jika posisi di luar bidang, akhiri;
  • Jika posisi diungkapkan, akhiri;
  • Kami membuka posisi saat ini;
  • Jika kita memiliki bom di dekat posisi saat ini, akhiri;
  • Jika kami mencapai titik ini selama pelaksanaan fungsi, posisi saat ini dalam lapangan bermain ditemukan dan tidak ada bom di sebelahnya, buka kotak yang berdekatan.

Pada dasarnya, sisa permainannya sama. Kode lengkap dapat ditemukan dengan mengklik tautan ini .

Jika Anda ingin tahu tentang visualisasi, baca terus.

Visualisasi

Semuanya harus jelas di sini, tetapi saya akan menjelaskan bagian yang sulit.

Jadi, kami memiliki cellSize variabel, yang menentukan jumlah piksel di setiap kotak.

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

Jadi, kita membuat bidang dengan sisi-sisi gridW x gridH, di mana ukuran setiap kotak akan sama dengan nilai cellSize.

Kemudian kita mengembalikan variabel ke keadaan semula.

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

Untuk menginisialisasi bidang:
 //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; } } } 

Dan kemudian nyalakan respons terhadap klik 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); } } } 

Dan fungsi tampilan, kami menyebutnya sekali untuk setiap 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); } } } } 

Dan itu saja, ini Minesweeper kami.

Gim ini terlihat sederhana, tetapi secara keseluruhan berfungsi penuh. Dan ingat: Minesweeper membuat kecanduan!

Skillbox merekomendasikan:

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


All Articles