Skip to content

Commit afc3bd2

Browse files
Merge pull request exercism#174 from stkent/minesweeper
minesweeper: add to track
2 parents 5f83bc9 + d15f926 commit afc3bd2

File tree

6 files changed

+436
-1
lines changed

6 files changed

+436
-1
lines changed

config.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@
4545
"beer-song",
4646
"difference-of-squares",
4747
"largest-series-product",
48-
"queen-attack"
48+
"queen-attack",
49+
"minesweeper"
4950
],
5051
"exercises": [
5152
{
@@ -257,6 +258,11 @@
257258
"slug": "queen-attack",
258259
"difficulty": 1,
259260
"topics": []
261+
},
262+
{
263+
"slug": "minesweeper",
264+
"difficulty": 1,
265+
"topics": []
260266
}
261267
],
262268
"deprecated": [

exercises/minesweeper/build.gradle

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
apply plugin: "java"
2+
apply plugin: "eclipse"
3+
apply plugin: "idea"
4+
5+
repositories {
6+
mavenCentral()
7+
}
8+
9+
dependencies {
10+
testCompile "junit:junit:4.12"
11+
}
12+
test {
13+
testLogging {
14+
exceptionFormat = 'full'
15+
events = ["passed", "failed", "skipped"]
16+
}
17+
}
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
import java.util.ArrayList;
2+
import java.util.List;
3+
import java.util.Set;
4+
import java.util.stream.Collectors;
5+
6+
final class MinesweeperBoard {
7+
8+
private static final char MINE_CHAR = '*';
9+
10+
private static final char SPACE_CHAR = ' ';
11+
12+
private final List<String> rawRepresentation;
13+
14+
private final int numberOfRows;
15+
16+
private final int numberOfColumns;
17+
18+
MinesweeperBoard(final List<String> rawRepresentation) {
19+
validateInputBoard(rawRepresentation);
20+
this.rawRepresentation = rawRepresentation;
21+
this.numberOfRows = rawRepresentation.size();
22+
this.numberOfColumns = rawRepresentation.isEmpty() ? 0 : rawRepresentation.get(0).length();
23+
}
24+
25+
List<String> getAnnotatedRepresentation() throws IllegalArgumentException {
26+
final List<String> result = new ArrayList<>();
27+
28+
for (int rowNumber = 0; rowNumber < numberOfRows; rowNumber++) {
29+
result.add(getAnnotatedRow(rowNumber));
30+
}
31+
32+
return result;
33+
}
34+
35+
private String getAnnotatedRow(final int rowNumber) {
36+
String result = "";
37+
38+
for (int columnNumber = 0; columnNumber < numberOfColumns; columnNumber++) {
39+
result += getCellAnnotation(rowNumber, columnNumber);
40+
}
41+
42+
return result;
43+
}
44+
45+
private char getCellAnnotation(final int rowNumber, final int columnNumber) {
46+
// If (rowNumber, columnNumber) is a mine, we're done.
47+
if (rawRepresentation.get(rowNumber).charAt(columnNumber) == MINE_CHAR) {
48+
return MINE_CHAR;
49+
}
50+
51+
final int mineCount = computeMineCountAround(rowNumber, columnNumber);
52+
53+
// If computed count is positive, add it to the annotated row. Otherwise, add a blank space.
54+
return mineCount > 0 ? Character.forDigit(mineCount, 10) : SPACE_CHAR;
55+
}
56+
57+
private int computeMineCountAround(final int rowNumber, final int columnNumber) {
58+
int result = 0;
59+
60+
// Compute row and column ranges to inspect (respecting board edges).
61+
final int minRowToInspect = Math.max(rowNumber - 1, 0);
62+
final int maxRowToInspect = Math.min(rowNumber + 1, numberOfRows - 1);
63+
final int minColToInspect = Math.max(columnNumber - 1, 0);
64+
final int maxColToInspect = Math.min(columnNumber + 1, numberOfColumns - 1);
65+
66+
// Count mines in the cells surrounding (row, col).
67+
for (int rowToInspect = minRowToInspect; rowToInspect <= maxRowToInspect; rowToInspect++) {
68+
for (int colToInspect = minColToInspect; colToInspect <= maxColToInspect; colToInspect++) {
69+
if (rawRepresentation.get(rowToInspect).charAt(colToInspect) == MINE_CHAR) {
70+
result += 1;
71+
}
72+
}
73+
}
74+
75+
return result;
76+
}
77+
78+
private void validateInputBoard(final List<String> inputBoard) throws IllegalArgumentException {
79+
validateInputBoardIsNotNull(inputBoard);
80+
81+
if (inputBoard.isEmpty()) {
82+
return;
83+
}
84+
85+
validateInputBoardCharacters(inputBoard);
86+
validateInputBoardColumnCounts(inputBoard);
87+
}
88+
89+
private void validateInputBoardIsNotNull(final List<String> inputBoard) throws IllegalArgumentException {
90+
if (inputBoard == null) {
91+
throw new IllegalArgumentException("Input board may not be null.");
92+
}
93+
}
94+
95+
private void validateInputBoardCharacters(final List<String> inputBoard) throws IllegalArgumentException {
96+
final String allBoardCharacters = String.join("", inputBoard);
97+
98+
if (!allBoardCharacters.matches("^[ *]*$")) {
99+
throw new IllegalArgumentException("Input board can only contain the characters ' ' and '*'.");
100+
}
101+
}
102+
103+
private void validateInputBoardColumnCounts(final List<String> inputBoard) throws IllegalArgumentException {
104+
final Set<Integer> setOfColumnCounts = inputBoard.stream().map(String::length).collect(Collectors.toSet());
105+
106+
if (setOfColumnCounts.size() > 1) {
107+
throw new IllegalArgumentException("Input board rows must all have the same number of columns.");
108+
}
109+
}
110+
111+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
public final class MinesweeperBoard {
2+
3+
4+
5+
}

0 commit comments

Comments
 (0)