Minesweeper BombCounts

Aug 28 2020

मेरे पास एक ऐसा तरीका है जो इसके सभी चौकों की जाँच करता है और इसके चारों ओर बमों की संख्या लौटाता है। लेकिन यह वास्तव में लंबा कोड है और बदसूरत है, तो क्या इसे छोटा किया जा सकता है?

final int MINE =10

for (int x = 0; x < counts.length; x++) {
    for (int y = 0; y < counts[0].length; y++) {
    if (counts[x][y] != MINE) {
    int Minesearch = 0;
    if (x > 0 && y > 0 && counts[x-1][y-1] == MINE) {//up left
        Minesearch++;
    }
    if (y > 0 && counts[x][y-1] == MINE) {//up
        Minesearch++;
    }
    if (x < counts.length - 1 && y > 0 && counts[x+1][y-1] == MINE) {//up right
        Minesearch++;
    }
    if (x > 0 && counts[x-1][y] == MINE) {//left
        Minesearch++;
    }
    if (x < counts.length - 1 && counts[x+1][y] == MINE) {//right
        Minesearch++;
    }
    if (x > 0 && y < counts[0].length - 1 && counts[x-1][y+1] == MINE) {//down left
        Minesearch++;
    }
    if (y < counts[0].length - 1 && counts[x][y+1] == MINE) {//down
        Minesearch++;
    }
    if (x < counts.length - 1 && y < counts[0].length - 1 && counts[x+1][y+1] == MINE) {//down right
        Minesearch++;
    }
    counts[x][y] = Minesearch;
    }
    }
}
}

जवाब

12 TorbenPutkonen Aug 28 2020 at 12:28

इसे सीमित करके और "सौंदर्यकृत" किया जा सकता है, जो कि साइकेट्रिंग और खदानों की आंतरिक विधि से जाँच करके बनाया गया है:

private boolean isWithinBounds(int x, int y) {
    return x >= 0 && y >= 0 && x < width && y < height;
}

private boolean isMine(int x, int y) {
    return field[x][y] == MINE;
}

फिर खदान की गिनती तुच्छ हो जाती है (हम मान सकते हैं कि 3x3 वर्ग के केंद्र में खदान नहीं है, अन्यथा खिलाड़ी विस्फोट हो जाता और खेल समाप्त हो जाता):

for (int x1 = x - 1; x1 <= x + 1; x1++) {
    for (int y1 = y - 1; y1 <= y + 1; y1++) {
        if (isWithinBounds(x1, y1) && isMine(x1, y1) {
            mineCount++;
        }
    }
}

हमने जो किया है वह कोड को तरीकों में तोड़ रहा है, जिनमें से प्रत्येक एक छोटे और अच्छी तरह से परिभाषित फ़ंक्शन को लागू करता है। क्योंकि प्रत्येक विधि बिल्कुल एक काम करती है, इसलिए उन्हें समझना, बनाए रखना और परीक्षण करना आसान हो जाता है।

आपको जावा नामकरण सम्मेलनों की जांच करनी चाहिए । चर नाम में होना चाहिए camelCase, startingWithSmallLetter।

चर और विधि के नाम का कारण कोड मौजूद होने के कारण का वर्णन करना चाहिए। उदाहरण mineSearchभ्रमित कर रहा है क्योंकि चर खानों की खोज नहीं करता है, यह सिर्फ उनकी गिनती रखता है। इस प्रकार mineCountएक बेहतर विकल्प है।

Countsयह भी भ्रामक है क्योंकि इसमें एक मान होता है जिसका नाम MINEस्पष्ट रूप से एक सेल होता है जिसमें मेरा होता है लेकिन इसमें आसपास की खान मायने भी रखती है। मैंने एक बार एक माइन्सवेपर क्लोन (या वास्तव में एक माइन्सवेपर सॉल्वर) किया था और मैंने सेल-ऑब्जेक्ट्स वाले एक सरणी का उपयोग किया था। सेल ऑब्जेक्ट ने सेल की स्थिति (स्टेप्ड, फ्लैग्ड, अनजान) और आसपास की खानों की संख्या को क्वेरी करने के लिए विधियाँ प्रदान की हैं, यदि इसे स्टेप किया गया हो।

1 TimothyTruckle Aug 29 2020 at 20:29

जबकि @TorbenPutkonen का उत्तर सही है यह समस्या का एक प्रक्रियात्मक दृष्टिकोण है।

इस तरह के प्रक्रियात्मक दृष्टिकोणों के साथ कुछ भी गलत नहीं है , लेकिन चूंकि जावा एक वस्तु उन्मुख भाषा है, जिसके बदले हम ओओ-दृष्टिकोणों की तलाश कर सकते हैं ...

मैं पड़ोसी की जाँच enumइस तरह से करूँगा :

enum Direction {
  NORTH{
     boolean isBomb(inx x, int y, boolean[] field){
       if(0 < x)
         return BOMB == field(x-1, y);
       else
         return false;
     }
  },
  NORTH_WEST{
     boolean isBomb(inx x, int y, boolean[] field){
       if(0 < x && 0 < y)
         return BOMB == field(x-1, y-1);
       else
         return false;
     }
  },
  SOUTH{
     boolean isBomb(inx x, int y, boolean[] field){
       if(field.length-1 > x)
         return BOMB == field(x+1, y);
       else
         return false;
     }
  },
  SOUTH_EAST{
     boolean isBomb(inx x, int y, boolean[] field){
       if(field.length-1 > x && field[0].length-1>y)
         return BOMB == field(x+1, y+1);
       else
         return false;
     }
  }
  // other directions following same pattern

  abstract boolean isBomb(inx x, int y, boolean[] field);
}

लाभ यह है कि यह एनम अपनी फ़ाइल में रह सकता है और इसकी बहुत सीमित जिम्मेदारी है। इसका मतलब है कि यह समझना आसान है कि क्या होता है, क्या नहीं?

अपनी गणना पद्धति में आप बस enumइस प्रकार स्थिरांक पर पुनरावृति कर सकते हैं :

for (int x = 0; x < counts.length; x++) {
  for (int y = 0; y < counts[0].length; y++) {
    int mineCount =0;
    for(Direction direction : Direction.values()) {
       if (direction.isBomb(x, y, counts) ) {
            mineCount++;
       }
    }
  }
}

अगले कदम के रूप में, मैं "हस्ताक्षर, आवेदन मत पूछो" सिद्धांत को विधि हस्ताक्षर को बदलकर लागू करेगा:

abstract int getBombValueOf(inx x, int y, boolean[] field);

कार्यान्वयन enumइस तरह से बदल जाएगा:

     int getBombValueOf(inx x, int y, boolean[] field){
       if(0 < x && BOMB == field(x-1, y))
         return 1;
       else
         return 0;
     },

इसे "एल्विस ऑपरेटर" के लिए सरलीकृत किया जा सकता है:

     int getBombValueOf(inx x, int y, boolean[] field){
       return (0 < x && BOMB == field(x-1, y))
         ? 1 
         : 0;
     },

और उपयोग इसके लिए बदल जाएगा:

for (int x = 0; x < counts.length; x++) {
  for (int y = 0; y < counts[0].length; y++) {
    int mineCount =0;
    for(Direction direction : Direction.values()) {
       mineCount += 
           direction.getBombValueOf(x, y, counts) );
    }
  }
}

हम एक FunctionalInterfaceऔर एक सरल संग्रह का उपयोग करके एक ही प्राप्त कर सकते हैं (पड़ोसी की गणना को किसी अन्य फ़ाइल में स्थानांतरित करना) :

@FunctionalInterface
interface Direction{
  int getBombValueOf(inx x, int y, boolean[] field);
}

private final Collection<Direction> directions = new HashSet<>();

// in constructor
   directions.add(new Direction() { // old style anonymous inner class
         int getBombValueOf(inx x, int y, boolean[] field){
           return (0 < x && BOMB == field(x-1, y))
             ? 1 
             : 0;           
         }
    };
   directions.add((x, y, field)-> { // Java8 Lambda 
           return (0 < x && 0 < y &&BOMB == field(x-1, y-1))
             ? 1 
             : 0;
    };
    // more following same pattern

// in your method
    for (int x = 0; x < counts.length; x++) {
      for (int y = 0; y < counts[0].length; y++) {
        int mineCount =0;
        for(Direction direction : directions) {
           mineCount += 
               direction.getBombValueOf(x, y, counts) );
        }
      }
    }

अगर हम खेल के क्षेत्र में प्राथमिकताओं की एक सरणी नहीं बल्कि वस्तुओं का एक संग्रह होगा तो OO सिद्धांतों से बहुत अधिक लाभ उठा सकते हैं । लेकिन यह एक और जवाब के लिए सामान हो सकता है ...; ओ)