كيف يتم ذلك: نكتب "كاسحة الألغام" في 4 دقائق

الصورة

من مترجم: هذا المنشور هو ترجمة للمقال الأصلي من قبل ماكي تشيز ، المبرمج المتمرس الذي لا يكتب برامج رائعة فحسب ، بل يوضح أيضًا قدرات اللغات المختلفة لزملائه ، سواء المبتدئين والمحترفين.

كاسحة ألغام هي لعبة ممتعة ، كثير منا لعبها. ربما تريد أن تجعل كاسحة الألغام بنفسك؟

توصي Skillbox: المهنة عبر الإنترنت "مهنة مطوري الويب" .

نذكرك: لجميع قراء "هبر" - خصم 10000 روبل عند التسجيل في أي دورة من دورات Skillbox باستخدام الرمز الترويجي "Habr".
تميز اللعبة هو أنها بسيطة للغاية وفي نفس الوقت مثيرة للغاية. لا توجد آليات لعب ماكرة في Meepweeper ، ما عليك سوى النقر على المربعات ، على أمل عدم وجود ألغام تحتها.

أقترح محاولة كتابة "كاسحة الألغام" على المعالجة. هذه أداة رائعة تسمح لك بإنشاء تطبيقات رسومية في 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 [] [] الألغام . لماذا شبكة المنجم عدد صحيح وليس منطقية؟ والحقيقة هي أن هذا يجعل من السهل حساب عدد الألغام القريبة من موقع معين.

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

نتيجة لذلك ، لدينا الخوارزمية التالية:

  • إذا كان الموقف خارج الميدان ، فأنهى ؛
  • إذا تم الكشف عن الموقف ، ينتهي ؛
  • نفتح الموقف الحالي.
  • إذا كان لدينا قنبلة بالقرب من الموقع الحالي ، تنتهي ؛
  • إذا وصلنا إلى هذه النقطة أثناء تنفيذ الوظيفة ، تم العثور على الموقع الحالي داخل الملعب ولا توجد قنابل بجواره ، افتح المربعات المجاورة.

في الأساس ، بقية اللعبة هي نفسها. يمكن العثور على الرمز الكامل بالنقر على هذا الرابط .

إذا كنت تريد أن تعرف عن التصور ، تابع القراءة.

التصور

يجب أن يكون كل شيء واضحًا هنا ، لكنني سأشرح الأجزاء الصعبة.

لذلك ، لدينا حجم خلية متغير ، والذي يحدد عدد البكسل في كل مربع.

 void settings(){ size(gridW*cellSize, 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/ar425317/


All Articles