2013-10-01 2 views
0

재미있는 Java 구현 자바를 만들고 있는데, 그 중 하나를 클릭하면 모두 0으로 채워 넣으려고합니다. 호출이 제대로 작동하지 않을재귀 지뢰 찾기 "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

사실, 워 라칸 : 지뢰 찾기는 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(); 
     } 
    } 
    } 

그것은 바로 자신을 호출 아니라 pressed 자신의 상태를 변경 주위의 모든 세포의 pressedAction 메소드를 호출하지 않습니다. 그런 다음 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

우리 대학의 파트너 작업에서 우리는 다음과 같은 재귀 적 방법을 사용했습니다. 두 개의 2D 어레이가 있습니다. 하나는 솔루션을 보유하고 다른 하나는 사용자 출력 (콘솔)에 대해 보이는 필드입니다.

또한 제로 필드 옆에 숫자 필드가 열립니다 (ms minesweeper에서와 같이). 그것은 1000x1000 필드 (유래)의 주위에 지저분 -하지만 어쨌든 꽤 긴 재생 될 것이다 ...

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

Microsoft의 지뢰 찾기와 마찬가지로 게임을 할 수 있습니다. 광산 슬롯을 표시하려면 마우스 오른쪽 버튼을 클릭하고 (클릭 한 버튼은 녹색) 슬롯을 열려면 왼쪽 버튼을 클릭하십시오. 슬롯에 광산이 있으면 빨간색이됩니다. 그렇지 않으면 황색 (표시기가없는 경우) 또는 주황색 (슬롯에 해당 슬롯 주위의 광산 수를 나타내는 표시기 번호가있는 경우)이됩니다. 일부는 하드 코드 될 수 있으며 코드를보다 효율적으로 만들 수는 있지만,이 알고리즘을 UI와 함께 즉시 사용할 수있는 방법을 보여줍니다. 미안합니다.