首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >初学者扫雷游戏

初学者扫雷游戏
EN

Code Review用户
提问于 2015-05-02 15:32:51
回答 1查看 41.2K关注 0票数 11

我写了一个基本的扫雷游戏供练习。它由三个类别组成:

  • 主-仅作为发射器
  • 单细胞细胞控制行为
  • 细胞的董事会协调行为。

对我来说最难的部分是确定单个细胞的值(它周围有多少个地雷),并引发连锁反应,如果某个细胞是空的(值= 0) -它检查最近的细胞,如果它们有价值,它只是揭示它,如果它们是空的,它会在它们上重复过程。所以

我想知道我的解决方案是否合理(它有效,但看上去很吓人),如果有人对它进行审查,我会很棒的。

这是板类中的两种方法:setCellValues()scanForEmptyCells()。然而,我将感谢任何命令和建议,也包括OOP,代码结构和风格。

我发布了基本的工作GUI版本,如果有人想运行它。

主要班:

代码语言:javascript
复制
public class Main {
    public static void main(String[] args){
        Board board = new Board();
        board.setBoard();
    }
}

董事会级:

代码语言:javascript
复制
import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;

public class Board {
    private Cell[][] cells;
    private int cellID = 0;
    private int side = 8;
    private int limit = side-2;

    public void setBoard(){
        JFrame frame = new JFrame();
        frame.add(addCells());

        plantMines();
        setCellValues();

        frame.pack();
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }

    public JPanel addCells(){
        JPanel panel = new JPanel(new GridLayout(side,side));
        cells = new Cell[side][side];
        for(int i = 0; i< side; i++){
            for(int j = 0; j<side; j++){
                cells[i][j] = new Cell(this);
                cells[i][j].setId(getID());
                panel.add(cells[i][j].getButton());
            }
        }
        return panel;
    }

    public void plantMines(){
        ArrayList<Integer> loc = generateMinesLocation(10);
        for(int i : loc){
            getCell(i).setValue(-1);
        }
    }
    /*Choose rendom places for mines*/
    public ArrayList<Integer> generateMinesLocation(int q){
        ArrayList<Integer> loc = new ArrayList<Integer>();
        int random;
        for(int i = 0; i<q;){
            random = (int)(Math.random()* (side*side));
            if(!loc.contains(random)){
                loc.add(random);
                i++;
            }
        }
        return loc;
    }
    // MOST IMPORTANT PART/////////////////////////////////////////////////////
    /*This method count number of mines around particular cell and set its value*/
    public void setCellValues(){
        for(int i = 0; i<side; i++){
            for(int j = 0; j<side; j++){
                 if(cells[i][j].getValue() != -1){
                     if(j>=1 && cells[i][j-1].getValue() == -1) cells[i][j].incrementValue();
                     if(j<= limit && cells[i][j+1].getValue() == -1) cells[i][j].incrementValue();
                     if(i>=1 && cells[i-1][j].getValue() == -1) cells[i][j].incrementValue();
                     if(i<= limit && cells[i+1][j].getValue() == -1) cells[i][j].incrementValue();
                     if(i>=1 && j>= 1 && cells[i-1][j-1].getValue() == -1) cells[i][j].incrementValue();
                     if(i<= limit && j<= limit && cells[i+1][j+1].getValue() == -1) cells[i][j].incrementValue();
                     if(i>=1 && j<= limit && cells[i-1][j+1].getValue() == -1) cells[i][j].incrementValue();
                     if(i<= limit && j>= 1 && cells[i+1][j-1].getValue() == -1) cells[i][j].incrementValue();
                 }
            }
        }
    }
    /*This method starts chain reaction. When user click on particular cell, if cell is empty (value = 0) this
    method look for other empty cells next to activated one. If finds one, it call checkCell and in effect,
    start next scan on its closest area.
     */
    public void scanForEmptyCells(){
        for(int i = 0; i<side; i++){
            for(int j = 0; j<side; j++){
                if(!cells[i][j].isNotChecked()){
                    if(j>=1 && cells[i][j-1].isEmpty()) cells[i][j-1].checkCell();
                    if(j<= limit && cells[i][j+1].isEmpty()) cells[i][j+1].checkCell();
                    if(i>=1 && cells[i-1][j].isEmpty()) cells[i-1][j].checkCell();
                    if(i<= limit && cells[i+1][j].isEmpty()) cells[i+1][j].checkCell();
                    if(i>=1 && j>= 1 && cells[i-1][j-1].isEmpty()) cells[i-1][j-1].checkCell();
                    if(i<= limit && j<= limit && cells[i+1][j+1].isEmpty()) cells[i+1][j+1].checkCell();
                    if(i>=1 && j<= limit && cells[i-1][j+1].isEmpty()) cells[i-1][j+1].checkCell();
                    if(i<= limit && j>= 1 && cells[i+1][j-1].isEmpty()) cells[i+1][j-1].checkCell();
                }
            }
        }
    }
    //////////////////////////////////////////////////////////////////////////////////
    public int getID(){
        int id = cellID;
        cellID++;
        return id;
    }

    public Cell getCell(int id){
        for(Cell[] a : cells){
            for(Cell b : a){
                if(b.getId() == id) return b;

            }
        }
        return null;
    }

    public void fail(){
        for(Cell[] a : cells){
            for(Cell b : a){
                b.reveal();
            }
        }
    }
}

细胞Clas:

代码语言:javascript
复制
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class Cell implements ActionListener{
    private JButton button;
    private Board board;
    private int value;
    private int id;
    private boolean notChecked;

    public Cell(Board board){
        button = new JButton();
        button.addActionListener(this);
        button.setPreferredSize(new Dimension(20,20));
        button.setMargin(new Insets(0,0,0,0));
        this.board = board;
        notChecked = true;
    }

    public JButton getButton() {
        return button;
    }

    public int getValue() {
        return value;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

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

    public void displayValue(){
        if(value==-1){
            button.setText("\u2600");
            button.setBackground(Color.RED);
        }else if(value!=0){
            button.setText(String.valueOf(value));
        }
    }

    public void checkCell(){
        button.setEnabled(false);
        displayValue();
        notChecked = false;
        if(value == 0) board.scanForEmptyCells();
        if(value == -1) board.fail();
    }

    public void incrementValue(){
        value++;
    }

    public boolean isNotChecked(){
        return notChecked;
    }

    public boolean isEmpty(){
        return isNotChecked() && value==0;
    }

    public void reveal(){
        displayValue();
        button.setEnabled(false);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        checkCell();
    }

}
EN

回答 1

Code Review用户

发布于 2015-05-04 15:13:53

使用Random类:

代码语言:javascript
复制
Random rand = new Random();
...
random = rand.nextInt(side * side);

ij,什么是行,什么是列?

代码语言:javascript
复制
for(int i = 0; i<side; i++){
    for(int j = 0; j<side; j++){
         if(cells[i][j].getValue() != -1){

通过查看这些行,我完全不知道什么是x,什么是y。我强烈建议您将变量重命名为xy,或者改为rowcol

getCell是slow

当前正在遍历单元格,直到找到与id匹配的单元格为止。太慢了。因为这只从generateMinesLocation调用,所以您可以让generateMinesLocation返回一个List<Cell>。或者更好:Set<Cell>使loc.contains查找速度快得多,因为:

  • 命令不重要
  • 不应该有重复的

这两个条件使它成为Set<Cell> loc = new HashSet<>();的完美选择

这将消除对idCell上的需求。

value == -1意味着它是一个矿井

很久以前,我还用了一个特殊的值来表示一个细胞是一个地雷。后来我意识到了我的错误。对于是否是地雷的属性,使用额外的boolean确实要好得多。您肯定应该包括一个boolean isMine()函数。

这不仅使代码更简洁,而且还允许将来的模式,在这种模式下,Cell可以同时成为数字和地雷。(相信我,可能性是无限的!)

notChecked

代码语言:javascript
复制
public boolean isNotChecked(){
    return notChecked;
}

省去一些麻烦,把它重命名为checkedisChecked()。甚至更好的是:clickedisClicked()

编写if (!cell.isClicked())if (cell.isNotClicked())要好得多

票数 8
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/88636

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档