For minesweeper algorithm, instead of the most obvious BFS or DFS solution, I want a O(1) space solution.
First of all, I'll explain how the program works. I will pass in a 2D array, with 1 represent mine and 0 represent blank space. The program return true if the map can be opened with single click. Return false if it cannot. Example:
0, 0, 0, 1, 0
0, 1, 1, 1, 1
0, 0, 0, 0, 1
0, 1, 1, 0, 1
0, 0, 1, 0, 1
should return false
0, 0, 0, 0, 0
0, 1, 1, 1, 1
0, 0, 0, 0, 1
0, 1, 1, 0, 1
0, 0, 1, 0, 1
should return true
My algorithm is to visit each 0s and mark as 2. Than from that point, I continue to visit all the 0s and mark as 2. When there's no more 0s, I will visit 2s and then mark 2s as 3s. In the end, all 0s should be marked as 3 if they are inter-connected. Example:
0, 0, 1
0, 1, 1
0, 0, 1
|
v
2, 0, 1
0, 1, 1
0, 0, 1
|
v
2, 2, 1
0, 1, 1
0, 0, 1
|
v
2, 3, 1
0, 1, 1
0, 0, 1
|
v
2, 3, 1
2, 1, 1
0, 0, 1
|
v
2, 3, 1
2, 1, 1
2, 0, 1
|
v
2, 3, 1
2, 1, 1
2, 2, 1
|
v
2, 3, 1
2, 1, 1
2, 3, 1
|
v
2, 3, 1
2, 1, 1
3, 3, 1
|
v
2, 3, 1
3, 1, 1
3, 3, 1
|
v
3, 3, 1
3, 1, 1
3, 3, 1
|
v
return true, since there's no more 0 in the graph
This is my code followed by 3 test cases. Kindly help me review the coding structure/styles or tell me if I have considered all possible test cases. Thanks!
import java.util.ArrayList;
import java.util.List;
public class MineSweeperAlgorithm {
// this minesweeper algorithm uses O(1) space complexity
// set verbose to false to hide the step-by-step loggging
private static final boolean verbose = true;
private static int stepCount = 1;
public static void main(String[] args) {
MineSweeperAlgorithm ins = new MineSweeperAlgorithm();
int[][] matrix;
// make a test case
stepCount = 1;
matrix = new int[5][];
matrix[0] = new int[]{0, 0, 0, 1, 0};
matrix[1] = new int[]{0, 1, 1, 1, 1};
matrix[2] = new int[]{0, 0, 0, 0, 1};
matrix[3] = new int[]{0, 1, 1, 0, 1};
matrix[4] = new int[]{0, 0, 1, 0, 1};
// run the test
System.out.println("Result is " +
ins.validate(matrix, matrix.length, matrix[0].length));
System.out.println();
// make another test case
stepCount = 1;
matrix = new int[5][];
matrix[0] = new int[]{0, 0, 0, 1, 0};
matrix[1] = new int[]{0, 1, 0, 1, 0};
matrix[2] = new int[]{0, 1, 0, 1, 0};
matrix[3] = new int[]{0, 1, 0, 1, 0};
matrix[4] = new int[]{0, 1, 0, 0, 0};
// run the test
System.out.println("Result is " +
ins.validate(matrix, matrix.length, matrix[0].length));
System.out.println();
// make another test case
stepCount = 1;
matrix = new int[5][];
matrix[0] = new int[]{0, 0, 0, 1, 0};
matrix[1] = new int[]{0, 1, 1, 1, 0};
matrix[2] = new int[]{0, 1, 0, 1, 0};
matrix[3] = new int[]{0, 0, 0, 1, 0};
matrix[4] = new int[]{0, 1, 0, 0, 0};
// run the test
System.out.println("Result is " +
ins.validate(matrix, matrix.length, matrix[0].length));
System.out.println();
}
public boolean validate(int[][] matrix, int m, int n) {
Pos nextStep = findZero(matrix, m, n);
if (nextStep == null) {
// the matrix deos not contain 0
return false;
}
// visit the first position, and go from there
matrix[nextStep.x][nextStep.y] = 2;
while (nextStep != null) {
nextStep = step(matrix, nextStep, m, n);
}
// after visiting all positions, check if there is remaining 0s
return findZero(matrix, m, n) == null;
}
Pos step(int[][] matrix, Pos cur, int m, int n) {
// Now cur is located at a pos with value = 2
// print matrix in "verbose" mode
if (verbose) {
System.out.println("Step #" + stepCount++);
for (int[] array : matrix) {
for (int num : array) {
System.out.print(num + " ");
}
System.out.println();
}
System.out.println();
}
// make a list of valid neighbors, for the convenience of checking
List<Pos> neighbors = new ArrayList<Pos>();
neighbors.add(new Pos(cur.x - 1, cur.y));
neighbors.add(new Pos(cur.x + 1, cur.y));
neighbors.add(new Pos(cur.x, cur.y - 1));
neighbors.add(new Pos(cur.x, cur.y + 1));
for (int i = neighbors.size() - 1; i >= 0; i--) {
if (!isValidPos(neighbors.get(i), m, n)) {
neighbors.remove(i);
}
}
// check if there is adjacent 0,
// if there is, mark 0 as 2 and return that position
for (Pos neighbor : neighbors) {
if (matrix[neighbor.x][neighbor.y] == 0) {
matrix[neighbor.x][neighbor.y] = 2;
return neighbor;
}
}
// if no adjacent 0, then check if there is adjacent 2.
// if there is, mark current as 3 and then return that position
for (Pos neighbor : neighbors) {
if (matrix[neighbor.x][neighbor.y] == 2) {
matrix[cur.x][cur.y] = 3;
return neighbor;
}
}
//if no adjacent 0 and no adjacent 2, mark current as 3 and return null
matrix[cur.x][cur.y] = 3;
return null;
}
boolean isValidPos(Pos p, int m, int n) {
return p.x >= 0 && p.x < m && p.y >= 0 && p.y < n;
}
Pos findZero(int[][] matrix, int m, int n) {
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (matrix[i][j] == 0) {
return new Pos(i, j);
}
}
}
return null;
}
class Pos {
int x;
int y;
public Pos(int a, int b) {
x = a;
y = b;
}
}
}
The code is also available online for viewing or checking execution result at http://ideone.com/wmryWn