我正在创建Java的java实现以获得乐趣,并且当您单击它们的池时我正在尝试填充所有零。 (玩Minesweeper看看我在说什么)
这是我的递归电话:
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 :(得分:2)
哇!!我能够想到一个解决方案。非常简单。这是我的结束代码:
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;
}
}
答案 1 :(得分: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();
}
}
}
它不会直接调用自身,而是调用其周围所有单元格的pressedAction方法,将其状态更改为pressed
。然后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();
}
}
}
}
答案 2 :(得分:0)
在我们大学的合作伙伴工作中,我们使用了以下递归方法。 有2个2D阵列,一个拿着解决方案,另一个拿着用户输出的可见字段(控制台)。
它还会打开零字段旁边的任何数字字段(如ms minesweeper中所示)。 它在1000x1000字段(stackoverflow)附近变得混乱 - 但不管怎样这将是一个很长的游戏......
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);
}
}
答案 3 :(得分:0)
Sherwood的回答可能会提供一些有一些细微变化的解决方案,但口头解释这些变化会令人困惑。因此,我实现了以下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) {
}
}
你可以像微软的扫雷一样玩游戏。右键单击以标记矿井槽(单击的按钮将为绿色),然后单击鼠标左键以打开槽。如果插槽有矿,它将是红色的。否则,它将是黄色(如果没有指示器)或橙色(如果插槽有一个指示器编号,显示该插槽周围有多少个地雷)。某些部分可能是硬编码的,并且可以轻松地使代码更高效,但我只是展示了如何在运行中使用此算法和UI。对不起。