2013-10-01 96 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中使用此算法。对于那个很抱歉。