2013-10-01 141 views
0

我創建了一個Java實現的Java樂趣,我試圖在你點擊一個池時填入所有的零。 (玩掃雷,看看我說的)遞歸掃雷「0填充」

這裏是我的遞歸調用:

private void revealZeros(int x, int y) { 

    if (board[y][x].revealed) 
     return; 
    board[y][x].revealed = true; 
    if (y > 0) { 
     if (x > 0) 
      if (!board[y - 1][x - 1].revealed && board[y - 1][x - 1].b == 0) 
       revealZeros(y - 1, x - 1); 
     if (x < 15) { 
      if (!board[y - 1][x + 1].revealed && board[y - 1][x + 1].b == 0) 
       revealZeros(y - 1, x + 1); 
     } 
     if (!board[y - 1][x].revealed && board[y - 1][x].b == 0) 
      revealZeros(y - 1, x); 
    } 
    if (x > 0) 
     if (!board[y][x - 1].revealed && board[y][x - 1].b == 0) 
      revealZeros(y, x - 1); 
    if (x < 15) 
     if (!board[y][x + 1].revealed && board[y][x + 1].b == 0) 
      revealZeros(y, x + 1); 
    if (y < 15) { 
     if (x > 0) 
      if (!board[y + 1][x - 1].revealed && board[y + 1][x - 1].b == 0) 
       revealZeros(y + 1, x - 1); 
     if (x < 15) 
      if (!board[y + 1][x + 1].revealed && board[y + 1][x + 1].b == 0) 
       revealZeros(y + 1, x + 1); 
     if (!board[y + 1][x].revealed && board[y + 1][x].b == 0) 
      revealZeros(y + 1, x); 
    } 

} 

通話不能正常工作。它顯示除0之外的塊,並且不顯示全部0塊。

Space.b =它周圍的炸彈數量
Space.revealed =是否顯示空間?

+0

迭代解決方案是不是更容易實現? – Tyler

+0

遞歸應該縮小你的代碼 - 以更多的內存使用爲代價使它更小更簡單。你的巨大代碼沒有意義。 –

+0

我不知道該怎麼做。我認爲這可能是遞歸地解決的 –

回答

0

哇!我能夠想到一個解決方案。很簡單。這裏是我的結束代碼:

private void revealZeros(int x, int y) { 
     if (x < 0 || x > 15 || y < 0 || y > 15) return; // check for bounds 

      if (board[y][x].b == 0 && !board[y][x].revealed) { 
       board[y][x].revealed = true; 
       revealZeros(x+1, y); 
       revealZeros(x-1, y); 
       revealZeros(x, y-1); 
       revealZeros(x, y+1); 
      } else { 
       return; 
      } 
     } 
+2

你也應該檢查4個角落。 –

+0

會增加,謝謝:) –

+0

其實,Worakarn:掃雷不檢查4個角落。 –

0

對不起,你的代碼顯然很瘋狂。遞歸應該簡化你的代碼,使代碼變得更小,更容易,而犧牲更多的內存使用。例如我在my MineSweeper implementation遞歸方法是:

private void zeroValuePress(int row, int col) { 
    int rMin = Math.max(row - 1, 0); 
    int cMin = Math.max(col - 1, 0); 
    int rMax = Math.min(row + 1, cellModelGrid.length - 1); 
    int cMax = Math.min(col + 1, cellModelGrid[row].length - 1); 
    for (int row2 = rMin; row2 <= rMax; row2++) { 
     for (int col2 = cMin; col2 <= cMax; col2++) { 
      cellModelGrid[row2][col2].pressedAction(); 
     } 
    } 
    } 

它不直接調用本身,而是要求它周圍的所有細胞的pressedAction方法,其中其狀態更改爲pressed。然後PropertyChangeListeners開始回到這個代碼。 MVC的美麗。

整體的PropertyChangeListener:

private class CellModelPropertyChangeListener implements 
     PropertyChangeListener { 

    public void propertyChange(PropertyChangeEvent evt) { 
    MineCellModel model = (MineCellModel) evt.getSource(); 
    int row = model.getRow(); 
    int col = model.getCol(); 

    if (evt.getPropertyName().equals(MineCellModel.BUTTON_PRESSED)) { 
     if (cellModelGrid[row][col].isMineBlown()) { 
      mineBlown(); 
     } else { 
      buttonsRemaining--; 
      if (buttonsRemaining <= 0) { 
       JOptionPane.showMessageDialog(null, "You've Won!!!", "Congratulations", JOptionPane.PLAIN_MESSAGE); 
      } 
      if (cellModelGrid[row][col].getValue() == 0) { 
       zeroValuePress(row, col); 
      } 
     } 
    } 
    } 

    private void mineBlown() { 
    for (int r = 0; r < cellModelGrid.length; r++) { 
     for (int c = 0; c < cellModelGrid[r].length; c++) { 
      MineCellModel model = cellModelGrid[r][c]; 
      if (model.isMined()) { 
       model.setMineBlown(true); 
      } 
     } 
    } 

    } 

    private void zeroValuePress(int row, int col) { 
    int rMin = Math.max(row - 1, 0); 
    int cMin = Math.max(col - 1, 0); 
    int rMax = Math.min(row + 1, cellModelGrid.length - 1); 
    int cMax = Math.min(col + 1, cellModelGrid[row].length - 1); 
    for (int row2 = rMin; row2 <= rMax; row2++) { 
     for (int col2 = cMin; col2 <= cMax; col2++) { 
      cellModelGrid[row2][col2].pressedAction(); 
     } 
    } 
    } 
} 
0

在我們大學的合作伙伴工作中,我們使用了下面的遞歸方法。 擁有2個2D陣列,一個擁有解決方案,另一個擁有用戶輸出(控制檯)的可視區域。

它還打開零字段旁邊的任何數字字段(如ms掃雷)。 它得到1000×1000左右字段(計算器)雜亂 - 但是這將是一個相當長的戲反正...

private void openSurroundingFields(int i, int e) { 
    for (int j=i-1;j<i+2;j++)    
    for (int h=e-1;h<e+2;h++) 
     if ((j>-1) && (j<field.length) && (h>-1) && (h<field[0].length) && (field[j][h] != ZERO_SYMBOL)){ 
      if (mineField[j][h] == 0){ 
       field[j][h] = ZERO_SYMBOL; 
       openSurroundingFields(j, h); 
      } 
      else if (mineField[j][h] != -1) 
       field[j][h] = Integer.toString(mineField[j][h]).charAt(0);  
     } 
} 
0

威爾舍伍德的答案可能會提供一些小變化的解決方案,但解釋這些變化口頭說明,令人費解。因此,我實施了以下UI和算法:

public class Minesweeper extends JFrame implements MouseListener { 

    // I assume that the grid has to be square (LENGTH*LENGTH) 
    private static final int LENGTH = 10, MINE_NUM = 10; 
    private static Button[][] buttons = new Button[LENGTH][LENGTH]; 
    // Stores whether a box holds a mine or not 
    private static boolean[][] places; 
    // Stores indicator numbers that show how many mines around the box 
    private static int[][] indicators; 

    public static void main(String[] args) { 
     Minesweeper ms = new Minesweeper(LENGTH, LENGTH); 
     ms.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     ms.pack(); 
     ms.setVisible(true); 

     places = getLocationOfMines(LENGTH, MINE_NUM); 
     setMineIndicators(places); 
    } 

    public Minesweeper(int rows, int cols) { 
     Container pane = getContentPane(); 
     pane.setLayout(new GridLayout(rows, cols)); 
     for (int i = 0; i < rows; i++) { 
      for (int j = 0; j < cols; j++) { 
       buttons[i][j] = new Button(); 
       buttons[i][j].addMouseListener(this); 
       buttons[i][j].setPreferredSize(new Dimension(30, 30)); 
       buttons[i][j].setBackground(Color.LIGHT_GRAY); 
       pane.add(buttons[i][j]); 
      } 
     } 
    } 

    private static boolean[][] getLocationOfMines(int length, int mineNum) { 

     boolean[][] places = new boolean [length][length]; 
     ArrayList<Integer> listX = new ArrayList<Integer>(); 
     ArrayList<Integer> listY = new ArrayList<Integer>(); 
     for (int i = 0; i < length; i++) { 
      listX.add(new Integer(i)); 
      listY.add(new Integer(i)); 
     } 

     // Get randomized X, Y indices for hidden mines 
     Collections.shuffle(listX); 
     Collections.shuffle(listY); 
     for (int i = 0; i < mineNum; i++) { 
      places[listX.get(i)][listY.get(i)] = true; 
     } 

     return places; 
    } 

    private static int[] getButtonIndices(Button button) { 
     int[] indices = new int[2]; 
     for (int i = 0; i < buttons.length; i++) { 
      for (int j = 0; j < buttons[i].length; j++) { 
       if (buttons[i][j] == button) 
       { 
        indices[0] = i; 
        indices[1] = j; 
        return indices; 
       } 
      } 
     } 
     return null; 
    } 

    // Calculates how many mines around the box 
    private static void setMineIndicators(boolean[][] places) { 
     indicators = new int[places.length][places.length]; 
     int mineCount = 0; 
     for(int i = 0; i < indicators.length; i++) { 
      for (int j = 0; j < indicators[i].length; j++) { 
       // 00 10 20 
       // 01 11 21 
       // 02 12 22 
       if (i-1 > -1 && j-1 > -1 && places[i-1][j-1]) { 
        mineCount++; 
       } 
       if (j-1 > -1 && places[i][j-1]) { 
        mineCount++; 
       } 
       if (i+1 < indicators.length && j-1 > -1 && places[i+1][j-1]) { 
        mineCount++; 
       } 
       if (i-1 > -1 && places[i-1][j]) { 
        mineCount++; 
       } 
       if (i+1 < indicators.length && places[i+1][j]) { 
        mineCount++; 
       } 
       if (i-1 > -1 && j+1 < indicators.length && places[i-1][j+1]) { 
        mineCount++; 
       } 
       if (j+1 < indicators.length && places[i][j+1]) { 
        mineCount++; 
       } 
       if (i+1 < indicators.length && j+1 < indicators.length && places[i+1][j+1]) { 
        mineCount++; 
       } 

       indicators[i][j] = mineCount; 
       mineCount = 0; 
      } 
     } 
    } 

    private static void activateMineChain(int x, int y) { 
     if (x < 0 || x > LENGTH - 1 || y < 0 || y > LENGTH - 1 || places[x][y] || buttons[x][y].getBackground() == Color.GREEN || indicators[x][y] == -1) { 
      return; 
     } 

     if (indicators[x][y] != 0) { 

      buttons[x][y].setLabel("" + indicators[x][y]); 
      buttons[x][y].setBackground(Color.ORANGE); 

      // If an indicator is visited, do not visit it again 
      indicators[x][y] = -1; 
      return; 
     } 

     else if (indicators[x][y] == 0) { 
      buttons[x][y].setBackground(Color.YELLOW); 
      indicators[x][y] = -1; 

      activateMineChain(x, y-1); 
      activateMineChain(x-1, y); 
      activateMineChain(x+1, y); 
      activateMineChain(x, y+1); 

      // Diagonals 
      activateMineChain(x-1, y-1); 
      activateMineChain(x+1, y-1); 
      activateMineChain(x-1, y+1); 
      activateMineChain(x+1, y+1); 

      return; 
     } 
     else { 
      return; 
     } 

    } 

    // Check the player is going to win or not (after each green "there is a mine" mark) 
    private boolean checkWin() { 
     for (int i = 0; i < LENGTH; i++) { 
      for (int j = 0; j < LENGTH; j++) { 
       if(places[i][j] && !(buttons[i][j].getBackground() == Color.GREEN)) { 
        return false; 
       } 
      } 
     } 
     System.out.println("YOU WIN!"); 
     for (int i = 0; i < LENGTH; i++) { 
      for (int j = 0; j < LENGTH; j++) { 
       buttons[i][j].removeMouseListener(this); 
      } 
     } 
     return true; 
    } 

    @Override 
    public void mouseClicked(MouseEvent me) { 

    } 

    @Override 
    public void mousePressed(MouseEvent me) { 
     if (me.getSource() instanceof Button) { 
      int[] indices = getButtonIndices((Button) me.getSource()); 
      if (places[indices[0]][indices[1]] && buttons[indices[0]][indices[1]].getBackground() != Color.GREEN) 
      { 
       buttons[indices[0]][indices[1]].setBackground(Color.RED); 
       System.out.println("YOU LOST!"); 
       for (int i = 0; i < LENGTH; i++) { 
        for (int j = 0; j < LENGTH; j++) { 
         buttons[i][j].removeMouseListener(this); 
        } 
       } 
      } 

      else { 
       activateMineChain(indices[0], indices[1]); 
      } 
     } 
    } 

    // To handle "there is a mine" situation 
    @Override 
    public void mouseReleased(MouseEvent me) { 
     if(SwingUtilities.isRightMouseButton(me)){ 
      int[] indices = getButtonIndices((Button) me.getSource()); 

      if (buttons[indices[0]][indices[1]].getBackground() != Color.GREEN) { 
       buttons[indices[0]][indices[1]].setBackground(Color.GREEN); 
       checkWin(); 
      } 
      else { 
       buttons[indices[0]][indices[1]].setBackground(Color.LIGHT_GRAY); 
      } 
     } 
    } 

    @Override 
    public void mouseEntered(MouseEvent me) { 
    } 

    @Override 
    public void mouseExited(MouseEvent me) { 
    } 
} 

您可以像微軟的掃雷一樣玩遊戲。右鍵點擊標記礦井(點擊的按鈕將變成綠色),然後左鍵點擊以打開插槽。如果插槽有地雷,它會變成紅色。否則,它會變成黃色(如果沒有指示器)或橙色(如果插槽的指示器號碼顯示該插槽周圍有多少個地雷)。某些部分可能是硬編碼的,並且可以使代碼更加高效,但我只是展示瞭如何在動態UI中使用此算法。對於那個很抱歉。