2016-12-10 23 views
1

我正在爲掃雷創建一個簡單的9x9網格。這個遊戲的主要功能之一是有一個遞歸檢查所有的側面,當瓷磚點擊沒有炸彈包圍它。在下面的代碼中,我可以創建一個函數來檢查瓷磚的上部和左側。如果我添加更多方向,例如下方和右側,程序將崩潰並且不能正確顯示切片。 (檢查方法下線//MY MAIN PROBLEMGUI中的遞歸錯誤

//顯示主GUI 包Minesweeper4;

public class mainFrame { 

public static void main(String[] args) { 
    new Grid().setVisible(true); 
} 

} 

//主代碼

package Minesweeper4; 

import java.awt.*; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.util.ArrayList; 
import java.util.Random; 
import javax.swing.*; 

public class Grid extends JFrame implements ActionListener { 

    private JPanel mainGrid; 
    private JButton button1, button2; 
    private JButton[][] buttons = new JButton[9][9]; 
    private String[][] mines = new String[9][9]; 
    private ArrayList<ParentSquare> parentSquare = new ArrayList<ParentSquare>(); 

    Random rand = new Random(); 

    NumberSquare numberSquare = new NumberSquare(); 
    MineSquare mineSquare = new MineSquare(); 

    public void addMines() { 
     for (int j = 0; j < 9; j++) { 
      for (int k = 0; k < 9; k++) { 
       mines[j][k] = "."; 
      } 
     } 
     for (int i = 0; i < 3; i++) { 
      int temp_x = rand.nextInt(9); 
      int temp_y = rand.nextInt(9); 
      mines[temp_x][temp_y] = "x"; 
     } 
    } 

    public void showMines() { 
     for (int x = 0; x < 9; x++) { 
      for (int y = 0; y < 9; y++) { 
       String temp = mines[x][y]; 
       if (temp.equals("x")) { 
        System.out.println("X: " + (x + 1) + " Y: " + (y + 1) + " Value: " + temp); 
       } 
      } 
     } 
    } 

    public Grid() { 
     this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     this.setSize(500, 500); 
     this.setTitle("Minesweeper 1.0"); 

     mainGrid = new JPanel(); 
     mainGrid.setLayout(new GridLayout(9, 9)); 
     this.add(mainGrid); 

     button1 = new JButton("Boop"); 
     button2 = new JButton("Poop"); 

     for (int i = 0; i < 9; i++) { 
      for (int j = 0; j < 9; j++) { 
       buttons[i][j] = new JButton(""); 
       buttons[i][j].addActionListener(this); 
       buttons[i][j].setBackground(Color.GRAY); 
      } 
     } 

     for (int k = 0; k < 9; k++) { 
      for (int l = 0; l < 9; l++) { 
       mainGrid.add(buttons[k][l]); 
      } 
     } 

     addMines(); 
     showMines(); 

    } 

    public void countBorders(int x, int y) { 
     int UL = 0, UU = 0, UR = 0, LL = 0, RR = 0, DL = 0, DD = 0, DR = 0, SUM = 0; 

     if (x > 0) { 
      UU = checkTile(x - 1, y); 
     } 
     if (y > 0) { 
      LL = checkTile(x, y - 1); 
     } 
     if (y < 8) { 
      RR = checkTile(x, y + 1); 
     } 
     if (x < 8) { 
      DD = checkTile(x + 1, y); 
     } 
     if ((x > 0) && (y > 0)) { 
      UL = checkTile(x - 1, y - 1); 
     } 

     if ((x > 0) && (y < 8)) { 
      UR = checkTile(x - 1, y + 1); 
     } 

     if ((x < 8) && (y > 0)) { 
      DL = checkTile(x + 1, y - 1); 
     } 

     if ((x < 8) && (y < 8)) { 
      DR = checkTile(x + 1, y + 1); 
     } 

     SUM = UL + UU + UR + LL + RR + DL + DD + DR; 

     printTile(x, y, SUM); 

     if (SUM == 0) { //MY MAIN PROBLEM 

//   if ((x > 0) && (y > 0)) {countBorders(x-1, y-1);}    //Upper left 
      if (x > 0) { 
       countBorders(x - 1, y); 
      }     //Upper 
//   if ((x > 0) && (y < 8)) {countBorders(x-1, y+1);}    //Upper right 
      if (y > 0) { 
       countBorders(x, y - 1); 
      }     //Left 
//   if (y < 8)    {countBorders(x, y+1);}     //Right 
//   if ((x < 8) && (y > 0)) {countBorders(x+1, y-1);}    //Down Left 
//   if (x < 8)    {countBorders(x+1, y);}     //Down 
//   if ((x < 8) && (y < 8)) {countBorders(x+1, y+1);}    //Down Right 
     } 

    } 

    public void printTile(int x, int y, int SUM) { 
     String text = Integer.toString(SUM); 
     buttons[x][y].setText(text); 
     buttons[x][y].setBackground(Color.CYAN); 
    } 

    public int checkTile(int x, int y) { 
     String c = mines[x][y]; 
     if (c.equals("x")) { 
      return 1; 
     } else { 
      return 0; 
     } 
    } 

    public void click(int x, int y) { 
     String mine = mines[x][y]; 
     if (mine.equals("x")) { 
      System.out.println("Bomb!!!"); 
      buttons[x][y].setText("!"); 
      buttons[x][y].setBackground(Color.RED); 
     } else { 
      countBorders(x, y); 
      System.out.println("Safe!!!"); 
//   buttons[x][y].setText("√"); 
//   buttons[x][y].setBackground(Color.WHITE); 
     } 

    } 

    @Override 
    public void actionPerformed(ActionEvent e) { 
     for (int i = 0; i < 9; i++) { 
      for (int j = 0; j < 9; j++) { 
       if (e.getSource() == buttons[i][j]) { 
        System.out.println("Clicked Tile X: " + (i + 1) + " Y: " + (j + 1)); 
        //buttons[i][j].setText("!"); 
        click(i, j); 
       } 
      } 
     } 
    } 

} 

是否有關於如何解決這個遞歸問題的方法嗎? 預先感謝您,我真的很想學習Java。祝你今天愉快!

+2

爲了幫助我們更好地理解您的問題,您應該特別告訴我們該程序「崩潰」時會發生什麼。它會凍結嗎?你是否看到任何異常?如果是這樣,**總是**發佈異常的整個堆棧跟蹤,併爲我們指出涉及哪條線。 –

+3

由於我們無法訪問的類依賴關係,您的代碼也無法編譯。我們不希望看到整個程序的所有代碼,但是您應該考慮簡化代碼並將其作爲代碼格式的文本(如上所述)發佈到有效的[mcve] - 一個小的可編譯和可運行的程序,爲我們展示你的問題。 –

回答

4

您導致錯誤的遞歸沒有可以找到的停止邏輯,您需要做的是以某種方式檢查以確保單元格在重新計數之前尚未被計數或按下。否則,代碼可能會引發堆棧溢出錯誤。這將需要給細胞計數一些狀態,告訴你這些信息,它會告訴你細胞是否已經被計數。

對於一個成功完成此邏輯的程序示例,請隨時查看我的5年前創建的Swing GUI示例。在這段代碼中,我有一個MineCellModel類,它爲單個掃雷器單元提供了邏輯(不是GUI),並且該類包含一個布爾字段,按下,直到單元格被按下「,或者通過用戶按下相應的按鈕,或者在模型的邏輯中遞歸地進行。如果單元格被按下,如果布爾值爲真,遞歸會停止在該單元格中。

您可以在這裏找到代碼:Minesweeper Action Events。這是一箇舊程序,所以我對任何可能關閉的概念或代碼表示歉意。

運行代碼的結果是:

enter image description here

這裏是存在於單個文件中的代碼:

import java.awt.CardLayout; 
import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.Font; 
import java.awt.GridLayout; 
import java.awt.Insets; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.awt.event.KeyEvent; 
import java.awt.event.MouseAdapter; 
import java.awt.event.MouseEvent; 
import java.beans.PropertyChangeEvent; 
import java.beans.PropertyChangeListener; 
import java.util.ArrayList; 
import java.util.Collections; 
import java.util.List; 

import javax.swing.BoxLayout; 
import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JOptionPane; 
import javax.swing.JPanel; 
import javax.swing.JSeparator; 
import javax.swing.SwingConstants; 
import javax.swing.event.SwingPropertyChangeSupport; 

@SuppressWarnings("serial") 
public class MineSweeper { 
    private JPanel mainPanel = new JPanel(); 
    private MineCellGrid mineCellGrid; 
    private JButton resetButton = new JButton("Reset"); 

    public MineSweeper(int rows, int cols, int mineTotal) { 
     mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.PAGE_AXIS)); 
     mineCellGrid = new MineCellGrid(rows, cols, mineTotal); 

     resetButton.setMnemonic(KeyEvent.VK_R); 
     resetButton.addActionListener(new ActionListener() { 
      public void actionPerformed(ActionEvent e) { 
       mineCellGrid.reset(); 
      } 
     }); 

     mainPanel.add(mineCellGrid); 
     mainPanel.add(new JSeparator()); 
     mainPanel.add(new JPanel() { 
      { 
       add(resetButton); 
      } 
     }); 
    } 

    private JPanel getMainPanel() { 
     return mainPanel; 
    } 

    private static void createAndShowUI() { 
     JFrame frame = new JFrame("MineSweeper"); 
     // frame.getContentPane().add(new MineSweeper(20, 20, 
     // 44).getMainPanel()); 
     frame.getContentPane().add(new MineSweeper(12, 12, 13).getMainPanel()); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.pack(); 
     frame.setLocationRelativeTo(null); 
     frame.setVisible(true); 
    } 

    public static void main(String[] args) { 
     java.awt.EventQueue.invokeLater(new Runnable() { 
      public void run() { 
       createAndShowUI(); 
      } 
     }); 
    } 
} 

@SuppressWarnings("serial") 
class MineCellGrid extends JPanel { 
    private MineCellGridModel model; 
    private List<MineCell> mineCells = new ArrayList<MineCell>(); 

    public MineCellGrid(final int maxRows, final int maxCols, int mineNumber) { 
     model = new MineCellGridModel(maxRows, maxCols, mineNumber); 
     setLayout(new GridLayout(maxRows, maxCols)); 

     for (int row = 0; row < maxRows; row++) { 
      for (int col = 0; col < maxCols; col++) { 
       MineCell mineCell = new MineCell(row, col); 
       add(mineCell); 
       mineCells.add(mineCell); 
       model.add(mineCell.getModel(), row, col); 
      } 
     } 

     reset(); 
    } 

    public void reset() { 
     model.reset(); 
     for (MineCell mineCell : mineCells) { 
      mineCell.reset(); 
     } 
    } 
} 

class MineCellGridModel { 
    private MineCellModel[][] cellModelGrid; 
    private List<Boolean> mineList = new ArrayList<Boolean>(); 
    private CellModelPropertyChangeListener cellModelPropChangeListener = new CellModelPropertyChangeListener(); 
    private int maxRows; 
    private int maxCols; 
    private int mineNumber; 
    private int buttonsRemaining; 

    public MineCellGridModel(final int maxRows, final int maxCols, int mineNumber) { 
     this.maxRows = maxRows; 
     this.maxCols = maxCols; 
     this.mineNumber = mineNumber; 
     for (int i = 0; i < maxRows * maxCols; i++) { 
      mineList.add((i < mineNumber) ? true : false); 
     } 
     cellModelGrid = new MineCellModel[maxRows][maxCols]; 
     buttonsRemaining = (maxRows * maxCols) - mineNumber; 
    } 

    public void add(MineCellModel model, int row, int col) { 
     cellModelGrid[row][col] = model; 
     model.addPropertyChangeListener(cellModelPropChangeListener); 
    } 

    public void reset() { 
     buttonsRemaining = (maxRows * maxCols) - mineNumber; 

     // randomize the mine location 
     Collections.shuffle(mineList); 
     // reset the model grid and set mines 
     for (int r = 0; r < cellModelGrid.length; r++) { 
      for (int c = 0; c < cellModelGrid[r].length; c++) { 
       cellModelGrid[r][c].reset(); 
       cellModelGrid[r][c].setMined(mineList.get(r * cellModelGrid[r].length + c)); 
      } 
     } 
     // advance value property of all neighbors of a mined cell 
     for (int r = 0; r < cellModelGrid.length; r++) { 
      for (int c = 0; c < cellModelGrid[r].length; c++) { 
       if (cellModelGrid[r][c].isMined()) { 
        int rMin = Math.max(r - 1, 0); 
        int cMin = Math.max(c - 1, 0); 
        int rMax = Math.min(r + 1, cellModelGrid.length - 1); 
        int cMax = Math.min(c + 1, cellModelGrid[r].length - 1); 
        for (int row2 = rMin; row2 <= rMax; row2++) { 
         for (int col2 = cMin; col2 <= cMax; col2++) { 
          cellModelGrid[row2][col2].incrementValue(); 
         } 
        } 
       } 
      } 
     } 
    } 

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

@SuppressWarnings("serial") 
class MineCell extends JPanel { 
    private static final String LABEL = "label"; 
    private static final String BUTTON = "button"; 
    private static final int PS_WIDTH = 24; 
    private static final int PS_HEIGHT = PS_WIDTH; 
    private static final float LABEL_FONT_SIZE = (float) (24 * PS_WIDTH)/30f; 
    private static final float BUTTON_FONT_SIZE = (float) (14 * PS_WIDTH)/30f; 
    private JButton button = new JButton(); 
    private JLabel label = new JLabel(" ", SwingConstants.CENTER); 
    private CardLayout cardLayout = new CardLayout(); 
    private MineCellModel model; 

    public MineCell(final boolean mined, int row, int col) { 
     model = new MineCellModel(mined, row, col); 
     model.addPropertyChangeListener(new MyPCListener()); 
     label.setFont(label.getFont().deriveFont(Font.BOLD, LABEL_FONT_SIZE)); 
     button.setFont(button.getFont().deriveFont(Font.PLAIN, BUTTON_FONT_SIZE)); 
     button.setMargin(new Insets(1, 1, 1, 1)); 
     setLayout(cardLayout); 

     add(button, BUTTON); 
     add(label, LABEL); 

     button.addActionListener(new ActionListener() { 
      public void actionPerformed(ActionEvent e) { 
       pressedAction(); 
      } 
     }); 
     button.addMouseListener(new MouseAdapter() { 
      @Override 
      public void mousePressed(MouseEvent e) { 
       if (e.getButton() == MouseEvent.BUTTON3) { 
        model.upDateButtonFlag(); 
       } 
      } 
     }); 
    } 

    public MineCell(int row, int col) { 
     this(false, row, col); 
    } 

    @Override 
    public Dimension getPreferredSize() { 
     return new Dimension(PS_WIDTH, PS_HEIGHT); 
    } 

    public void pressedAction() { 
     if (model.isFlagged()) { 
      return; 
     } 
     model.pressedAction(); 
    } 

    public void showCard(String cardConstant) { 
     cardLayout.show(this, cardConstant); 
    } 

    // TODO: have this change the button's icon 
    public void setFlag(boolean flag) { 
     if (flag) { 
      button.setBackground(Color.yellow); 
      button.setForeground(Color.red); 
      button.setText("f"); 
     } else { 
      button.setBackground(null); 
      button.setForeground(null); 
      button.setText(""); 
     } 
    } 

    private void setMineBlown(boolean mineBlown) { 
     if (mineBlown) { 
      label.setBackground(Color.red); 
      label.setOpaque(true); 
      showCard(LABEL); 
     } else { 
      label.setBackground(null); 
     } 
    } 

    public MineCellModel getModel() { 
     return model; 
    } 

    public void addPropertyChangeListener(PropertyChangeListener listener) { 
     model.addPropertyChangeListener(listener); 
    } 

    public void removePropertyChangeListener(PropertyChangeListener listener) { 
     model.removePropertyChangeListener(listener); 
    } 

    private class MyPCListener implements PropertyChangeListener { 
     public void propertyChange(PropertyChangeEvent evt) { 
      String propName = evt.getPropertyName(); 
      if (propName.equals(MineCellModel.MINE_BLOWN)) { 
       setMineBlown(true); 
      } else if (propName.equals(MineCellModel.FLAG_CHANGE)) { 
       setFlag(model.isFlagged()); 
      } else if (propName.equals(MineCellModel.BUTTON_PRESSED)) { 
       if (model.isMineBlown()) { 
        setMineBlown(true); 
       } else { 
        String labelText = (model.getValue() == 0) ? "" : String.valueOf(model 
          .getValue()); 
        label.setText(labelText); 
       } 
       showCard(LABEL); 
      } 
     } 
    } 

    public void reset() { 
     setFlag(false); 
     setMineBlown(false); 
     showCard(BUTTON); 
     label.setText(""); 
    } 

} 

class MineCellModel { 
    public static final String FLAG_CHANGE = "Flag Change"; 
    public static final String BUTTON_PRESSED = "Button Pressed"; 
    public static final String MINE_BLOWN = "Mine Blown"; 
    private int row; 
    private int col; 
    private int value = 0; 
    private boolean mined = false;; 
    private boolean flagged = false; 
    private SwingPropertyChangeSupport pcSupport = new SwingPropertyChangeSupport(this); 
    private boolean pressed = false; 
    private boolean mineBlown = false; 

    public MineCellModel(boolean mined, int row, int col) { 
     this.mined = mined; 
     this.row = row; 
     this.col = col; 
    } 

    public void incrementValue() { 
     int temp = value + 1; 
     setValue(temp); 
    } 

    public void setValue(int value) { 
     this.value = value; 
    } 

    public int getValue() { 
     return value; 
    } 

    public void setMineBlown(boolean mineBlown) { 
     this.mineBlown = mineBlown; 
     PropertyChangeEvent evt = new PropertyChangeEvent(this, MINE_BLOWN, false, true); 
     pcSupport.firePropertyChange(evt); 
    } 

    public boolean isMineBlown() { 
     return mineBlown; 
    } 

    public void setMined(boolean mined) { 
     this.mined = mined; 
    } 

    public void setFlagged(boolean flagged) { 
     this.flagged = flagged; 
    } 

    public int getRow() { 
     return row; 
    } 

    public int getCol() { 
     return col; 
    } 

    public boolean isMined() { 
     return mined; 
    } 

    public boolean isFlagged() { 
     return flagged; 
    } 

    public void pressedAction() { 
     if (pressed) { 
      return; 
     } 
     pressed = true; 
     if (mined) { 
      setMineBlown(true); 
     } 

     PropertyChangeEvent evt = new PropertyChangeEvent(this, BUTTON_PRESSED, -1, value); 
     pcSupport.firePropertyChange(evt); 
    } 

    public void upDateButtonFlag() { 
     boolean oldValue = flagged; 
     setFlagged(!flagged); 
     PropertyChangeEvent evt = new PropertyChangeEvent(this, FLAG_CHANGE, oldValue, flagged); 
     pcSupport.firePropertyChange(evt); 
    } 

    public void reset() { 
     mined = false; 
     flagged = false; 
     pressed = false; 
     mineBlown = false; 
     value = 0; 
    } 

    public void addPropertyChangeListener(PropertyChangeListener listener) { 
     pcSupport.addPropertyChangeListener(listener); 
    } 

    public void removePropertyChangeListener(PropertyChangeListener listener) { 
     pcSupport.removePropertyChangeListener(listener); 
    } 
} 

編輯關於遞歸

我的代碼使用遞歸n,但具有間接級別,因爲它基於模型 - 視圖 - 控制器類型的設計模式,並且遞歸在偵聽器的通知內。請注意,每個GUI MineCell對象都擁有自己的MineCellModel對象,後者保存MineCell的狀態。當MineCell對象內保存的GUI的JButton被按下時,它的ActionListener調用同一類的pressed()方法:

button.addActionListener(new ActionListener() { 
    public void actionPerformed(ActionEvent e) { 
     pressedAction(); 
    } 
}); 

此方法首先檢查相應的MineCellModel,看它是否已被「標記」,如果被標記的布爾是true。如果是這樣,這意味着用戶右鍵單擊該按鈕,並且它不是活動的,並且方法返回。否則,MineCellModel的pressedAction()方法被調用,

public void pressedAction() { 
    if (model.isFlagged()) { 
     return; 
    } 
    model.pressedAction(); 
} 

,這裏是遞歸開始的地方,它通過一個觀察者設計模式這樣做:

// within MineCellModel 
public void pressedAction() { 
    if (pressed) { 
     // if the button's already been pressed -- return, do nothing 
     return; 
    } 

    // otherwise make pressed true 
    pressed = true; 

    // if we've hit a mine -- blow it! 
    if (mined) { 
     setMineBlown(true); 
    } 

    // *** Here's the key *** notify all listeners that this button has been pressed 
    PropertyChangeEvent evt = new PropertyChangeEvent(this, BUTTON_PRESSED, -1, value); 
    pcSupport.firePropertyChange(evt); 
} 

的兩行代碼底部通知任何這個模型的監聽者的BUTTON_PRESSED狀態已經被改變,它將MineCellModel的value發送給所有監聽者。值int是關鍵,因爲它具有地雷的鄰居數量。那麼,聽MineCellModel的是什麼?那麼,一個關鍵對象是MineCellGridModel,它是表示整個網格狀態的模型。它有一個CellModelPropertyChangeListener的類,它的實際聽,這個類中是下面的代碼:

private class CellModelPropertyChangeListener implements PropertyChangeListener { 

    public void propertyChange(PropertyChangeEvent evt) { 
     // first get the MineCellModel for the cell that triggered this notification 
     MineCellModel model = (MineCellModel) evt.getSource(); 
     int row = model.getRow(); 
     int col = model.getCol(); 

     // if the event is a button pressed event 
     if (evt.getPropertyName().equals(MineCellModel.BUTTON_PRESSED)) { 
      // first check if a mine was hit, and if so, call mineBlown() 
      if (cellModelGrid[row][col].isMineBlown()) { 
       mineBlown(); // this method iterates through all cells and blows all mines 
      } else { 
       // here we check for a winner 
       buttonsRemaining--; 
       if (buttonsRemaining <= 0) { 
        JOptionPane.showMessageDialog(null, "You've Won!!!", "Congratulations", 
          JOptionPane.PLAIN_MESSAGE); 
       } 

       // here is the key spot -- if cell's value is 0, call the zeroValuePress method 
       if (cellModelGrid[row][col].getValue() == 0) { 
        zeroValuePress(row, col); 
       } 
      } 
     } 
    } 

    private void mineBlown() { 
     // ... code to blow all the un-blown mines 
    } 

    // this code is called if a button pressed has 0 value -- no mine neighbors 
    private void zeroValuePress(int row, int col) { 

     // find the boundaries of the neighbors 
     int rMin = Math.max(row - 1, 0); // check for the top edge 
     int cMin = Math.max(col - 1, 0); // check for the left edge 
     int rMax = Math.min(row + 1, cellModelGrid.length - 1); // check for the bottom edge 
     int cMax = Math.min(col + 1, cellModelGrid[row].length - 1); // check for right edge 

     // iterate through the neighbors 
     for (int row2 = rMin; row2 <= rMax; row2++) { 
      for (int col2 = cMin; col2 <= cMax; col2++) { 
       // *** Here's the recursion *** 
       // call pressedAction on all the neighbors 
       cellModelGrid[row2][col2].pressedAction(); 
      } 
     } 
    } 
} 

因此在上面的監聽器的主要手段是zeroValuePress(...)方法。它首先找到當前礦區周圍鄰居的邊界,使用Math.min(...)Math.max(...)注意不要超出網格的右側,左側或頂部或底部邊界。然後它通過在這個網格所擁有的鄰居MineCellModel的每一個上調用pressedAction()的單元鄰居進行迭代。如你所知,pressedAction()方法將檢查單元是否已被按下,如果不是,則更改其狀態,然後通知該同一個監聽器,從而導致遞歸。

+2

我之前可能已經說過這個,但*愛*你的動畫截圖! :) –

+1

@AndrewThompson:謝謝! –

+0

@HovercraftFullOfEels只是想知道,你是否使用遞歸來實現你的掃雷機? (幾次掃描你的代碼,但沒有看到)我也在幾年前創建了一個,但我使用了遞歸。 – user3437460

2

這個遊戲的主要功能之一是有一個遞歸來檢查所有的側面時,瓷磚點擊沒有炸彈包圍它。

看起來像是你需要根據周圍炸彈的數量更新單元格的部分。

這些都是你的東西拿筆記:

  1. 要在細胞更新的數字,有無需使用遞歸。我使用遞歸的唯一部分是當用戶點擊value == 0(踩在空格子上)的單元格時。

  2. 檢查所有8個方向可以很容易地完成,無需編寫大量的if-conditions。所有你需要的是一對嵌套for-loop。只需遍歷3x3網格就像一個二維數組(請參見下圖)。

  3. 在循環中,設置條件以確保您在讀取當前網格值(參見下面的代碼)之前處於(3x3矩陣的)範圍內。

enter image description here

遍歷3x3矩陣如該圖所示,我們可以使用一對嵌套循環:

for(int x=(coordX-1); x<=(coordX+1); x++) 
    for(int y=(coordY-1); y<=(coordY+1); y++) 
     if(x!=-1 && y!= -1 && x! = ROWS && y! = COLS && map[x][y] != 'B') 
      if(map[x][y] == '.') 
       map[x][y] = '1'; 
      else 
       map[x][y] += 1; 

if-condition防止陣列元件上的工作,其超出範圍的。