我写了一个基本的扫雷游戏供练习。它由三个类别组成:
对我来说最难的部分是确定单个细胞的值(它周围有多少个地雷),并引发连锁反应,如果某个细胞是空的(值= 0) -它检查最近的细胞,如果它们有价值,它只是揭示它,如果它们是空的,它会在它们上重复过程。所以
我想知道我的解决方案是否合理(它有效,但看上去很吓人),如果有人对它进行审查,我会很棒的。
这是板类中的两种方法:setCellValues()和scanForEmptyCells()。然而,我将感谢任何命令和建议,也包括OOP,代码结构和风格。
我发布了基本的工作GUI版本,如果有人想运行它。
主要班:
public class Main {
public static void main(String[] args){
Board board = new Board();
board.setBoard();
}
}董事会级:
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:
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();
}
}发布于 2015-05-04 15:13:53
Random类:Random rand = new Random();
...
random = rand.nextInt(side * side);i和j,什么是行,什么是列?for(int i = 0; i<side; i++){
for(int j = 0; j<side; j++){
if(cells[i][j].getValue() != -1){通过查看这些行,我完全不知道什么是x,什么是y。我强烈建议您将变量重命名为x和y,或者改为row和col。
getCell是slow当前正在遍历单元格,直到找到与id匹配的单元格为止。太慢了。因为这只从generateMinesLocation调用,所以您可以让generateMinesLocation返回一个List<Cell>。或者更好:Set<Cell>使loc.contains查找速度快得多,因为:
这两个条件使它成为Set<Cell> loc = new HashSet<>();的完美选择
这将消除对id在Cell上的需求。
value == -1意味着它是一个矿井很久以前,我还用了一个特殊的值来表示一个细胞是一个地雷。后来我意识到了我的错误。对于是否是地雷的属性,使用额外的boolean确实要好得多。您肯定应该包括一个boolean isMine()函数。
这不仅使代码更简洁,而且还允许将来的模式,在这种模式下,Cell可以同时成为数字和地雷。(相信我,可能性是无限的!)
notCheckedpublic boolean isNotChecked(){
return notChecked;
}省去一些麻烦,把它重命名为checked和isChecked()。甚至更好的是:clicked和isClicked()。
编写if (!cell.isClicked())比if (cell.isNotClicked())要好得多
https://codereview.stackexchange.com/questions/88636
复制相似问题