需要帮助我的扫雷程序?

时间:2011-09-18 09:37:37

标签: java swing

我一直在研究我的扫雷工程,我似乎遇到了一些麻烦。我的程序编译,但我的问题是在我的网格上设置地雷。我使用随机生成器设置位置,但我不知道如何在我的网格上实现它。我希望程序做的是当一个带炸弹的块被击中时,它的可见性应该改变,并且应该出现一个黑色正方形。到目前为止,这是我的代码:

import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;

public class Minesweeper extends JFrame implements ActionListener {

    public int gridRows; // 
    public int gridColumns; //
    int mines;
    private int numMines;
    private int row, col;
    boolean secondTime;
    JMenuItem Expert, Intermediate, Easy;
    JButton[][] easyGrid; // 2d array for button grid.
    boolean[][] setMine = new boolean[row][col];
    int numberMine[][];

    public static void main(String[] args) {
        // creates frame
        Minesweeper gameWindow = new Minesweeper();
        gameWindow.setSize(400, 400);
        gameWindow.setVisible(true); // sets the visibility of the game board to true.
    }

    public Minesweeper() {
        super("Minesweeper");
    }

// class constructor.
    public void init() {

        // variables set the size of the playing board
        int rowsX = 9;
        int columnsY = 9;

        gridRows = rowsX;
        gridColumns = columnsY;

        setLayout(new GridLayout(rowsX, columnsY)); // creates and sets a grid format.
        easyGrid = new JButton[rowsX][columnsY]; // sets the grid size from the parameters given

        // loops through rows and columns to draw grid.
        for (int i = 0; i < columnsY; i++) {
            for (int j = 0; j < rowsX; j++) {
                row = i;
                col = j;
                easyGrid[i][j] = new JButton(""); //creates new button    
                easyGrid[i][j].addActionListener(this); // assigns an action to the grid buttons
                add(easyGrid[i][j]);  // adds buttons to the game board 
            }
        }


        JMenu gameMenu = new JMenu("GameOptions"); // creates menu option

        // creating each option under the JMenuBar (toolBar)
        JMenuItem easyChoice = new JMenuItem("Beginner(9x9)");
        easyChoice.addActionListener(this);
        gameMenu.add(easyChoice); // adds choice option to the drop down menu
        Easy = easyChoice;

        // button selects a 16 by 16 grid for intermediate players
        JMenuItem mediumChoice = new JMenuItem("Intermediate(16x16)");
        mediumChoice.addActionListener(this);
        gameMenu.add(mediumChoice); // adds choice option to the drop down menu
        Intermediate = mediumChoice;

        // button selects a 16 by 30 grid for more advanced players
        JMenuItem hardChoice = new JMenuItem("Advanced(16x30)");
        hardChoice.addActionListener(this);
        gameMenu.add(hardChoice); // adds choice option to the drop down menu
        Expert = hardChoice;

        JMenuBar toolBar = new JMenuBar();
        toolBar.add(gameMenu);
        setJMenuBar(toolBar);

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // sets the button for exiting the program.
        pack(); // set frame size.
    }

// lays out the mines on the grid.
    public void createMines() {
        java.util.Random rand = new java.util.Random();     // Random class 
        int rndm1;
        int rndm2; // gives the co-ordinates of the mine 


        for (int countBomb = 0; countBomb <= mines; countBomb++) {
            rndm1 = rand.nextInt(8) + 1; // pick a row (+1 for buffer compensation)
            rndm2 = rand.nextInt(8) + 1; // pick a col

            if (!easyGrid[gridRows][gridColumns].equals(setMine[rndm1][rndm2])) {
                setMine[rndm1][rndm2] = true;
                easyGrid[rndm1][rndm2].setVisible(true);
                // checks if there is no bomb present already.
            }
        }
    }

// this method redirects the user based on a selection made from the drop down menu
    public void actionPerformed(ActionEvent event) {


        if (event.getSource() instanceof JButton) {

            ((JButton) event.getSource()).setVisible(false);

        }

        if (event.getSource() == Easy) {
            gridRows = 30;
            gridColumns = 16;
            mines = 99;
            secondTime = true;
            init();
        } else if (event.getSource() == Intermediate) {
            gridColumns = gridRows = 16;
            mines = 40;
            secondTime = true;
            init();
        } else if (event.getSource() == Expert) {
            gridRows = gridColumns = 8;
            mines = 10;
            secondTime = true;
            init();
        }

    }
}

3 个答案:

答案 0 :(得分:4)

看起来你正试图在一个类中实现你的程序,我强烈建议你不要这样做,而是将代码细分为几个按自然划分划分的类。

当我自己完成此操作时,我首先创建了两个“模型”非GUI类及其各自的GUI类,以尝试将逻辑从显示中分离出来。

您可以在此处查看我的代码:minesweeper-action-events

例如,一个类被称为MineCellModel,它具有三个绑定的布尔属性或状态,标记(用户右键单击它以“标记”它并且按钮不能被按下),按下,和mineBlown,以及一个非绑定财产/州:开采。后者没有约束,因为它在游戏过程中不会改变,因此在游戏过程中不需要使用PropertyChangeListener来监听它。

此模型随后由MineCell对象使用,该类扩展JPanel并保存JLabel(用于保存基础数字)和最初显示的JButton。它为它的模型添加了一个PropertyChangeListener来监听状态的变化,并通过改变它的显示来响应状态的变化。例如,如果标记状态变为true,则MineCell将在JButton上显示标记图像,该按钮将对按钮按下无响应。我使用CardLayout取得了很好的成功,以便最好地交换矿井电池的显示效果。例如,所有单元格最初都可以显示一个JButton,其Icon可以通过鼠标单击鼠标右键单击进行交换。然后当用鼠标左键单击按钮(使用ActionListener)时,我使用CardLayout显示一个JLabel,它有一个我的图像图标或显示一个数字。

还有一个MineCellGridModel,它保存整个网格的非GUI逻辑。它包含一个MineCellModel对象的二维数组以及一个地雷的ArrayList。它还将PropertyChangeListener添加到它保存的所有MineCellModel中,以检查按钮按下事件。如果它们发生,它会检查游戏是否获胜。在这里它也会对矿井爆炸事件或游戏丢失做出反应,并有网格显示所有爆炸的地雷。最后它对按钮按下做出反应,其中矿井单元模型的值为0(它没有邻居是地雷)并且在这种情况下它递归地调用围绕它的所有采矿单元模型上的pressedAction,导致级联的冷却效果按钮按下有时会从网格上清除大量按钮。

然后是一个MineCellGrid,网格的GUI视图类,它使用上面的类作为模型,最后是一个MineSweeper类,它将整个shebang放在一起并在JFrame中显示。

关于随机化地雷,我的每个类都有一个reset()方法,将其设置回其起始状态,这包括MineCellGridModel类,该类随机化一个ArrayList,该ArrayList包含一个布尔数组列表,每个类别一个网格中的单元格。它只是简化了arraylist,然后遍历使用数组列表分配地雷的cellModelGrid。然后我再次遍历cellModelGrid并且如果我找到一个已经挖掘的单元格,我会增加其直接邻居的“值” - 跟踪挖掘了多少邻居的数字:

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

答案 1 :(得分:2)

因为它实现了一个双状态按钮,JToggleButton可能是一个有用的替代方案。您可以从相关的game获得一些想法。

答案 2 :(得分:1)

修改 我刚刚意识到JButton有一个图标字段,您可以将其用于图标。

也许有一个for循环来创建一个方形图像按钮网格,可以找到一种方法来制作图像按钮here,尽管你可能会发现很多带有现成gui元素的库。

我会使用2d数组来存储按钮。每个按钮都有一些字段,例如:

boolean revealed = false; //default value
boolean isMine = false;   //default value

然后你可以改变按钮图形来显示我的/旗帜或其他什么,由鼠标点击事件处理程序调用。