diff --git a/puzzles files/minesweeper/5x5 Minesweeper Easy/Minesweeper 5x5 easy 1 b/puzzles files/minesweeper/5x5 Minesweeper Easy/Minesweeper 5x5 easy 1
new file mode 100644
index 000000000..39d212b8e
--- /dev/null
+++ b/puzzles files/minesweeper/5x5 Minesweeper Easy/Minesweeper 5x5 easy 1
@@ -0,0 +1,24 @@
+
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
+
\ No newline at end of file
diff --git a/puzzles files/minesweeper/5x5 Minesweeper Easy/Minesweeper 5x5 easy 2 b/puzzles files/minesweeper/5x5 Minesweeper Easy/Minesweeper 5x5 easy 2
new file mode 100644
index 000000000..8df5704d0
--- /dev/null
+++ b/puzzles files/minesweeper/5x5 Minesweeper Easy/Minesweeper 5x5 easy 2
@@ -0,0 +1,26 @@
+
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
+
\ No newline at end of file
diff --git a/puzzles files/minesweeper/5x5 Minesweeper Easy/Minesweeper 5x5 easy 3 b/puzzles files/minesweeper/5x5 Minesweeper Easy/Minesweeper 5x5 easy 3
new file mode 100644
index 000000000..5ed05d383
--- /dev/null
+++ b/puzzles files/minesweeper/5x5 Minesweeper Easy/Minesweeper 5x5 easy 3
@@ -0,0 +1,25 @@
+
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
+
\ No newline at end of file
diff --git a/puzzles files/minesweeper/7x7 Minesweeper Easy/Minesweeper 7x7 easy1.txt b/puzzles files/minesweeper/7x7 Minesweeper Easy/Minesweeper 7x7 easy1.txt
new file mode 100644
index 000000000..13d9c56a3
--- /dev/null
+++ b/puzzles files/minesweeper/7x7 Minesweeper Easy/Minesweeper 7x7 easy1.txt
@@ -0,0 +1,41 @@
+
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
+
\ No newline at end of file
diff --git a/puzzles files/minesweeper/7x7 Minesweeper Easy/Minesweeper 7x7 easy2.txt b/puzzles files/minesweeper/7x7 Minesweeper Easy/Minesweeper 7x7 easy2.txt
new file mode 100644
index 000000000..e99df19e0
--- /dev/null
+++ b/puzzles files/minesweeper/7x7 Minesweeper Easy/Minesweeper 7x7 easy2.txt
@@ -0,0 +1,37 @@
+
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
+
\ No newline at end of file
diff --git a/puzzles files/minesweeper/7x7 Minesweeper Easy/Minesweeper 7x7 easy3.txt b/puzzles files/minesweeper/7x7 Minesweeper Easy/Minesweeper 7x7 easy3.txt
new file mode 100644
index 000000000..d2815ab6a
--- /dev/null
+++ b/puzzles files/minesweeper/7x7 Minesweeper Easy/Minesweeper 7x7 easy3.txt
@@ -0,0 +1,41 @@
+
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
+
\ No newline at end of file
diff --git a/puzzles files/minesweeper/7x7 Minesweeper Medium/Minesweeper 7x7 medium1.txt b/puzzles files/minesweeper/7x7 Minesweeper Medium/Minesweeper 7x7 medium1.txt
new file mode 100644
index 000000000..8e7591261
--- /dev/null
+++ b/puzzles files/minesweeper/7x7 Minesweeper Medium/Minesweeper 7x7 medium1.txt
@@ -0,0 +1,59 @@
+
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
+
\ No newline at end of file
diff --git a/puzzles files/minesweeper/7x7 Minesweeper Medium/Minesweeper 7x7 medium2.txt b/puzzles files/minesweeper/7x7 Minesweeper Medium/Minesweeper 7x7 medium2.txt
new file mode 100644
index 000000000..ff77ea677
--- /dev/null
+++ b/puzzles files/minesweeper/7x7 Minesweeper Medium/Minesweeper 7x7 medium2.txt
@@ -0,0 +1,24 @@
+
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
+
\ No newline at end of file
diff --git a/puzzles files/minesweeper/7x7 Minesweeper Medium/Minesweeper 7x7 medium3.txt b/puzzles files/minesweeper/7x7 Minesweeper Medium/Minesweeper 7x7 medium3.txt
new file mode 100644
index 000000000..cbb8113a0
--- /dev/null
+++ b/puzzles files/minesweeper/7x7 Minesweeper Medium/Minesweeper 7x7 medium3.txt
@@ -0,0 +1,30 @@
+
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
+
\ No newline at end of file
diff --git a/puzzles files/skyscrapers/5x5 Skyscrapers Easy1 b/puzzles files/skyscrapers/5x5 Skyscrapers Easy1
index 1e3f1851c..b8e168e70 100644
--- a/puzzles files/skyscrapers/5x5 Skyscrapers Easy1
+++ b/puzzles files/skyscrapers/5x5 Skyscrapers Easy1
@@ -1,9 +1,8 @@
+
-
-
-
+
@@ -20,5 +19,21 @@
+
+
+
+
+ |
+
+
+
+
+ |
+
+
+
+
+
-
\ No newline at end of file
+
+
diff --git a/src/main/java/edu/rpi/legup/model/Puzzle.java b/src/main/java/edu/rpi/legup/model/Puzzle.java
index 8fb615d1f..18334999e 100644
--- a/src/main/java/edu/rpi/legup/model/Puzzle.java
+++ b/src/main/java/edu/rpi/legup/model/Puzzle.java
@@ -383,6 +383,7 @@ public void removeDirectRule(DirectRule rule) {
/**
* Accessor method for the puzzle UUID
+ *
* @return returns the puzzle UUID tag
*/
public String getTag() {
@@ -391,6 +392,7 @@ public String getTag() {
/**
* Modifier method to override the puzzle persistent UUID
+ *
* @param tag String to overwrite the current puzzle UUID
*/
public void setTag(String tag) {
diff --git a/src/main/java/edu/rpi/legup/model/PuzzleExporter.java b/src/main/java/edu/rpi/legup/model/PuzzleExporter.java
index dc8fa14a5..2f9402110 100644
--- a/src/main/java/edu/rpi/legup/model/PuzzleExporter.java
+++ b/src/main/java/edu/rpi/legup/model/PuzzleExporter.java
@@ -41,11 +41,12 @@ public PuzzleExporter(Puzzle puzzle) {
this.puzzle = puzzle;
}
- public static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+ public static final DateTimeFormatter DATE_FORMAT =
+ DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
/**
- * Takes the puzzle state and the current date/time to obfuscate
- * the solved state with an onto function to prevent cheating
+ * Takes the puzzle state and the current date/time to obfuscate the solved state with an onto
+ * function to prevent cheating
*
* @param solved the solved state of the board, true if solved
* @param date the current date and time, passed during export
@@ -58,8 +59,8 @@ public static int obfHash(boolean solved, String date) {
}
/**
- * Deobfuscates the solved state of the board from hash value using
- * the time provided in the puzzle xml-style export
+ * Deobfuscates the solved state of the board from hash value using the time provided in the
+ * puzzle xml-style export
*
* @param hash the hash value saved to the export
* @param date the date/time value saved to the export
@@ -74,9 +75,9 @@ public static Boolean inverseHash(int hash, String date) {
timestamp = -1;
}
- if ((true+":"+timestamp+";").hashCode() == hash) {
+ if ((true + ":" + timestamp + ";").hashCode() == hash) {
return Boolean.TRUE;
- } else if ((false+":"+timestamp+";").hashCode() == hash) {
+ } else if ((false + ":" + timestamp + ";").hashCode() == hash) {
return Boolean.FALSE;
}
return null;
@@ -103,7 +104,10 @@ public void exportPuzzle(String fileName) throws ExportFileException {
newDocument.appendChild(legupElement);
org.w3c.dom.Element puzzleElement = newDocument.createElement("puzzle");
- String idStr = puzzle.getTag().isEmpty() ? fileName.substring(fileName.lastIndexOf("\\") + 1) : puzzle.getTag();
+ String idStr =
+ puzzle.getTag().isEmpty()
+ ? fileName.substring(fileName.lastIndexOf("\\") + 1)
+ : puzzle.getTag();
puzzleElement.setAttribute("tag", idStr);
puzzleElement.setAttribute("name", puzzle.getName());
legupElement.appendChild(puzzleElement);
@@ -119,7 +123,7 @@ public void exportPuzzle(String fileName) throws ExportFileException {
String time = dateTime.format(DATE_FORMAT);
statusElement.setAttribute("lastSaved", time);
int hashedState = obfHash(puzzle.isPuzzleComplete(), time);
- statusElement.setAttribute("isSolved", hashedState+"");
+ statusElement.setAttribute("isSolved", hashedState + "");
legupElement.appendChild(statusElement);
TransformerFactory transformerFactory = TransformerFactory.newInstance();
diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/Minesweeper.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/Minesweeper.java
index ed8066f39..d07f097ec 100644
--- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/Minesweeper.java
+++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/Minesweeper.java
@@ -45,7 +45,7 @@ public boolean isBoardComplete(@NotNull Board board) {
}
for (PuzzleElement> data : minesweeperBoard.getPuzzleElements()) {
final MinesweeperCell cell = (MinesweeperCell) data;
- if (cell.getData().equals(MinesweeperTileData.empty())) {
+ if (cell.getData().equals(MinesweeperTileData.unset())) {
return false;
}
}
diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperBoard.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperBoard.java
index bef317ab5..bc9f4a652 100644
--- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperBoard.java
+++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperBoard.java
@@ -1,6 +1,7 @@
package edu.rpi.legup.puzzle.minesweeper;
import edu.rpi.legup.model.gameboard.GridBoard;
+import edu.rpi.legup.model.gameboard.PuzzleElement;
public class MinesweeperBoard extends GridBoard {
@@ -31,6 +32,9 @@ public MinesweeperBoard copy() {
newMinesweeperBoard.setCell(x, y, getCell(x, y).copy());
}
}
+ for (PuzzleElement e : modifiedData) {
+ newMinesweeperBoard.getPuzzleElement(e).setModifiable(false);
+ }
return newMinesweeperBoard;
}
}
diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperCell.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperCell.java
index 325e42b7b..89a8a3be8 100644
--- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperCell.java
+++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperCell.java
@@ -26,11 +26,11 @@ public MinesweeperCell(@NotNull MinesweeperTileData value, @NotNull Point locati
/** Sets this cell's data to the value specified by {@link Element#getElementID()} */
public void setType(@NotNull Element element, @NotNull MouseEvent event) {
switch (element.getElementID()) {
- case MinesweeperElementIdentifiers.BOMB -> {
- this.data = MinesweeperTileData.bomb();
+ case MinesweeperElementIdentifiers.MINE -> {
+ this.data = MinesweeperTileData.mine();
break;
}
- case MinesweeperElementIdentifiers.FLAG -> {
+ case MinesweeperElementIdentifiers.NUMBER -> {
final int currentData = super.data.data();
switch (event.getButton()) {
case MouseEvent.BUTTON1 -> {
@@ -38,7 +38,7 @@ public void setType(@NotNull Element element, @NotNull MouseEvent event) {
this.data = MinesweeperTileData.empty();
return;
}
- this.data = MinesweeperTileData.flag(currentData + 1);
+ this.data = MinesweeperTileData.number(currentData + 1);
return;
}
case MouseEvent.BUTTON2, MouseEvent.BUTTON3 -> {
@@ -46,7 +46,7 @@ public void setType(@NotNull Element element, @NotNull MouseEvent event) {
this.data = MinesweeperTileData.empty();
return;
}
- this.data = MinesweeperTileData.flag(currentData - 1);
+ this.data = MinesweeperTileData.number(currentData - 1);
return;
}
}
diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperCellFactory.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperCellFactory.java
index 5fe6096a9..077cd38c6 100644
--- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperCellFactory.java
+++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperCellFactory.java
@@ -15,7 +15,7 @@
public class MinesweeperCellFactory extends ElementFactory {
/** The key of the data used in {@link NamedNodeMap} */
- private static final String DATA_ATTRIBUTE = "data";
+ private static final String DATA_ATTRIBUTE = "value";
/** The key of the x position used in {@link NamedNodeMap} */
private static final String X_ATTRIBUTE = "x";
@@ -66,6 +66,9 @@ private MinesweeperCellFactory() {}
final MinesweeperCell cell =
new MinesweeperCell(MinesweeperTileData.fromData(value), new Point(x, y));
cell.setIndex(y * height + x);
+ if (value != -2) {
+ cell.setModifiable(false);
+ }
return cell;
} catch (NumberFormatException e) {
throw new InvalidFileFormatException(
diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperController.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperController.java
index aaf061704..610bda73b 100644
--- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperController.java
+++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperController.java
@@ -22,12 +22,27 @@ public class MinesweeperController extends ElementController {
public static @NotNull MinesweeperTileData getNewCellDataOnClick(
@NotNull MouseEvent event, @NotNull MinesweeperTileData current) {
final int numberData = current.data();
- return switch (event.getButton()) {
- case MouseEvent.BUTTON1 -> MinesweeperTileData.fromData(numberData + 1);
- case MouseEvent.BUTTON2, MouseEvent.BUTTON3 ->
- MinesweeperTileData.fromData(numberData - 1);
- default -> MinesweeperTileData.empty();
- };
+ switch (event.getButton()) { // git?
+ case MouseEvent.BUTTON1:
+ if (numberData >= 1 && numberData <= 8) {
+ return MinesweeperTileData.fromData(numberData);
+ }
+ if (numberData == 0) {
+ return MinesweeperTileData.fromData(-2);
+ }
+ return MinesweeperTileData.fromData(numberData + 1);
+
+ case MouseEvent.BUTTON2, MouseEvent.BUTTON3:
+ if (numberData >= 1 && numberData <= 8) {
+ return MinesweeperTileData.fromData(numberData);
+ }
+ if (numberData == -2) {
+ return MinesweeperTileData.fromData(0);
+ }
+ return MinesweeperTileData.fromData(numberData - 1);
+ default:
+ return MinesweeperTileData.empty();
+ }
}
/**
diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperElementIdentifiers.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperElementIdentifiers.java
index 77e490f7e..8e5a86bca 100644
--- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperElementIdentifiers.java
+++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperElementIdentifiers.java
@@ -5,12 +5,12 @@ public class MinesweeperElementIdentifiers {
/** ID for unset Minesweeper elements */
public static final String UNSET = "MINESWEEPER-UNSET";
- /** ID for bomb Minesweeper elements */
- public static final String BOMB = "MINESWEEPER-BOMB";
+ /** ID for mine Minesweeper elements */
+ public static final String MINE = "MINESWEEPER-MINE";
/** ID for empty Minesweeper elements */
public static final String EMPTY = "MINESWEEPER-EMPTY";
- /** ID for flag Minesweeper elements */
- public static final String FLAG = "MINESWEEPER-FLAG";
+ /** ID for number Minesweeper elements */
+ public static final String NUMBER = "MINESWEEPER-NUMBER";
}
diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperElementView.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperElementView.java
index 1bfc0d698..e2cf3b1bc 100644
--- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperElementView.java
+++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperElementView.java
@@ -25,18 +25,44 @@ public MinesweeperElementView(@NotNull MinesweeperCell cell) {
public void drawElement(@NotNull Graphics2D graphics2D) {
final MinesweeperCell cell = (MinesweeperCell) puzzleElement;
final MinesweeperTileType type = cell.getTileType();
- if (type == MinesweeperTileType.FLAG) {
+ if (type == MinesweeperTileType.NUMBER) {
graphics2D.setStroke(new BasicStroke(1));
graphics2D.setColor(Color.WHITE);
graphics2D.fillRect(location.x, location.y, size.width, size.height);
graphics2D.setColor(Color.BLACK);
graphics2D.drawRect(location.x, location.y, size.width, size.height);
+ int intValue = ((MinesweeperCell) puzzleElement).getData().data();
+
+ final String value = String.valueOf(intValue);
+ if (intValue == 1) {
+ Color MSBLUE = new Color(7, 3, 251);
+ graphics2D.setColor(MSBLUE);
+ } else if (intValue == 2) {
+ Color MSGREEN = new Color(7, 123, 3);
+ graphics2D.setColor(MSGREEN);
+ } else if (intValue == 3) {
+ Color MSRED = new Color(255, 3, 3);
+ graphics2D.setColor(MSRED);
+ } else if (intValue == 4) {
+ Color MSDARKBLUE = new Color(0, 0, 125);
+ graphics2D.setColor(MSDARKBLUE);
+ } else if (intValue == 5) {
+ Color MSMAROON = new Color(135, 3, 3);
+ graphics2D.setColor(MSMAROON);
+ } else if (intValue == 6) {
+ Color MSCYAN = new Color(7, 131, 131);
+ graphics2D.setColor(MSCYAN);
+ } else if (intValue == 7) {
+ Color MSDARKGRAY = new Color(7, 3, 3);
+ graphics2D.setColor(MSDARKGRAY);
+ } else {
+ Color MSLIGHTGRAY = new Color(135, 131, 131);
+ graphics2D.setColor(MSLIGHTGRAY);
+ }
- graphics2D.setColor(FONT_COLOR);
graphics2D.setFont(FONT);
final FontMetrics metrics = graphics2D.getFontMetrics(FONT);
- final String value = String.valueOf(((MinesweeperCell) puzzleElement).getData().data());
final int xText = location.x + (size.width - metrics.stringWidth(value)) / 2;
final int yText =
location.y + ((size.height - metrics.getHeight()) / 2) + metrics.getAscent();
@@ -65,11 +91,11 @@ public void drawElement(@NotNull Graphics2D graphics2D) {
graphics2D.setColor(Color.BLACK);
graphics2D.drawRect(location.x, location.y, size.width, size.height);
}
- if (type == MinesweeperTileType.BOMB) {
+ if (type == MinesweeperTileType.MINE) {
graphics2D.setColor(Color.LIGHT_GRAY);
graphics2D.fillRect(location.x, location.y, size.width, size.height);
graphics2D.drawImage(
- MinesweeperView.BOMB_IMAGE,
+ MinesweeperView.MINE_IMAGE,
location.x,
location.y,
size.width,
diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperImporter.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperImporter.java
index 419a69247..6e1daf2c0 100644
--- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperImporter.java
+++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperImporter.java
@@ -72,7 +72,7 @@ public void initializeBoard(@NotNull Node node) throws InvalidFileFormatExceptio
puzzle.getFactory()
.importCell(elementDataList.item(i), minesweeperBoard);
final Point loc = cell.getLocation();
- if (MinesweeperTileData.unset().equals(cell.getData())) {
+ if (cell.getTileNumber() > 0) {
cell.setModifiable(false);
cell.setGiven(true);
}
diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperTileData.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperTileData.java
index 5296cf057..f18ebbdfe 100644
--- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperTileData.java
+++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperTileData.java
@@ -8,7 +8,7 @@
public record MinesweeperTileData(MinesweeperTileType type, int data) {
public static final int UNSET_DATA = -2;
- public static final int BOMB_DATA = -1;
+ public static final int MINE_DATA = -1;
public static final int EMPTY_DATA = 0;
/**
@@ -19,10 +19,10 @@ public record MinesweeperTileData(MinesweeperTileType type, int data) {
new MinesweeperTileData(MinesweeperTileType.UNSET, UNSET_DATA);
/**
- * Always has a type of {@link MinesweeperTileType#BOMB}, and a data value of {@value BOMB_DATA}
+ * Always has a type of {@link MinesweeperTileType#MINE}, and a data value of {@value MINE_DATA}
*/
- private static final MinesweeperTileData BOMB =
- new MinesweeperTileData(MinesweeperTileType.BOMB, BOMB_DATA);
+ private static final MinesweeperTileData MINE =
+ new MinesweeperTileData(MinesweeperTileType.MINE, MINE_DATA);
/**
* Always has a type of {@link MinesweeperTileType#EMPTY}, and a data value of {@value
@@ -32,34 +32,34 @@ public record MinesweeperTileData(MinesweeperTileType type, int data) {
new MinesweeperTileData(MinesweeperTileType.EMPTY, EMPTY_DATA);
/**
- * @param count how many bombs are near the flag
+ * @param count how many mines are near the number
* @return a new {@link MinesweeperTileData} with a {@link MinesweeperTileData#type} of {@link
- * MinesweeperTileType#FLAG} and a {@link MinesweeperTileData#data} of {@code count}
+ * MinesweeperTileType#NUMBER} and a {@link MinesweeperTileData#data} of {@code count}
*/
@Contract(pure = true)
- public static @NotNull MinesweeperTileData flag(int count) {
- return new MinesweeperTileData(MinesweeperTileType.FLAG, count);
+ public static @NotNull MinesweeperTileData number(int count) {
+ return new MinesweeperTileData(MinesweeperTileType.NUMBER, count);
}
/**
* @param data Determines what type of {@link MinesweeperTileData} to return.
* @return If {@code data} is one of {@link MinesweeperTileData#UNSET_DATA}, {@link
- * MinesweeperTileData#BOMB_DATA}, or {@link MinesweeperTileData#EMPTY_DATA}, it will return
+ * MinesweeperTileData#MINE_DATA}, or {@link MinesweeperTileData#EMPTY_DATA}, it will return
* that data. If {@code data} is less than any of the values, or greater than 8, it will
* return {@link MinesweeperTileData#UNSET_DATA}. Otherwise, it returns {@link
- * MinesweeperTileData#flag(int)} and passes {@code data} as the parameter.
+ * MinesweeperTileData#number(int)} and passes {@code data} as the parameter.
*/
@Contract(pure = true)
public static @NotNull MinesweeperTileData fromData(int data) {
return switch (data) {
case UNSET_DATA -> unset();
- case BOMB_DATA -> bomb();
+ case MINE_DATA -> mine();
case EMPTY_DATA -> empty();
default -> {
- if (data <= -2 || data > 8) {
+ if (data <= -2) {
yield unset();
}
- yield flag(data);
+ yield number(data);
}
};
}
@@ -68,8 +68,8 @@ public record MinesweeperTileData(MinesweeperTileType type, int data) {
return UNSET;
}
- public static @NotNull MinesweeperTileData bomb() {
- return BOMB;
+ public static @NotNull MinesweeperTileData mine() {
+ return MINE;
}
public static @NotNull MinesweeperTileData empty() {
@@ -80,15 +80,15 @@ public boolean isUnset() {
return this.data == UNSET_DATA;
}
- public boolean isBomb() {
- return this.data == BOMB_DATA;
+ public boolean isMine() {
+ return this.data == MINE_DATA;
}
public boolean isEmpty() {
return this.data == EMPTY_DATA;
}
- public boolean isFlag() {
+ public boolean isNumber() {
return this.data > 0 && this.data <= 8;
}
diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperTileType.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperTileType.java
index a682da5e5..b5d4afc05 100644
--- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperTileType.java
+++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperTileType.java
@@ -2,13 +2,12 @@
public enum MinesweeperTileType {
- /** A cell with nothing */
+ /** A cell that is unknown by the user, value = -2 */
UNSET,
-
- /** Represents a cell with no bombs in it */
+ /** Represents a cell with no mine in it, value = 0 */
EMPTY,
- /** A flag has values 1-8 representing how many bombs are touching it */
- FLAG,
- /** A bomb tile that should be marked by nearby flags */
- BOMB
+ /** A number cell has values 1-8 representing how many mines are touching it, 1 <= value <= 8 */
+ NUMBER,
+ /** A mine cell that should be marked by nearby numbers, value = -1 */
+ MINE
}
diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperUtilities.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperUtilities.java
index d38460ac8..9a4014aa1 100644
--- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperUtilities.java
+++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperUtilities.java
@@ -1,6 +1,5 @@
package edu.rpi.legup.puzzle.minesweeper;
-import edu.rpi.legup.puzzle.minesweeper.rules.LessBombsThanFlagContradictionRule;
import java.awt.*;
import java.util.*;
import java.util.Objects;
@@ -47,15 +46,15 @@ public static int countSurroundingType(
return (int)
(switch (type) {
case UNSET -> stream.filter(MinesweeperTileData::isUnset);
- case BOMB -> stream.filter(MinesweeperTileData::isBomb);
+ case MINE -> stream.filter(MinesweeperTileData::isMine);
case EMPTY -> stream.filter(MinesweeperTileData::isEmpty);
- case FLAG -> stream.filter(MinesweeperTileData::isFlag);
+ case NUMBER -> stream.filter(MinesweeperTileData::isNumber);
})
.count();
}
- public static int countSurroundingBombs(MinesweeperBoard board, MinesweeperCell cell) {
- return countSurroundingType(board, cell, MinesweeperTileType.BOMB);
+ public static int countSurroundingMines(MinesweeperBoard board, MinesweeperCell cell) {
+ return countSurroundingType(board, cell, MinesweeperTileType.MINE);
}
public static int countSurroundingUnset(MinesweeperBoard board, MinesweeperCell cell) {
@@ -66,19 +65,19 @@ public static int countSurroundingEmpty(MinesweeperBoard board, MinesweeperCell
return countSurroundingType(board, cell, MinesweeperTileType.EMPTY);
}
- public static int countSurroundingFlags(MinesweeperBoard board, MinesweeperCell cell) {
- return countSurroundingType(board, cell, MinesweeperTileType.FLAG);
+ public static int countSurroundingNumbers(MinesweeperBoard board, MinesweeperCell cell) {
+ return countSurroundingType(board, cell, MinesweeperTileType.NUMBER);
}
/**
- * @return how many bombs are left that need to be placed around {@code cell} which must be a
+ * @return how many mines are left that need to be placed around {@code cell} which must be a
* flag
*/
- public int countNeededBombsFromFlag(MinesweeperBoard board, MinesweeperCell cell) {
- if (!cell.getData().isFlag()) {
- throw new IllegalArgumentException("Bombs are only needed surrounding flags");
+ public int countNeededminesFromNumber(MinesweeperBoard board, MinesweeperCell cell) {
+ if (!cell.getData().isNumber()) {
+ throw new IllegalArgumentException("mines are only needed surrounding numbers");
}
- return cell.getData().data() - countSurroundingBombs(board, cell);
+ return cell.getData().data() - countSurroundingMines(board, cell);
}
public static boolean hasEmptyAdjacent(MinesweeperBoard board, MinesweeperCell cell) {
@@ -153,16 +152,273 @@ private static void recurseCombinations(
recurseCombinations(result, curIndex + 1, maxBlack, numBlack, len, workingArray);
}
- public static boolean isForcedBomb(MinesweeperBoard board, MinesweeperCell cell) {
+ // checks if the current cell is forced to be a mine by checking if any of its adjacent cells
+ // are a number cell that can only be satisfied if the current cell is a mine
+ public static boolean isForcedMine(MinesweeperBoard board, MinesweeperCell cell) {
+ MinesweeperBoard emptyCaseBoard = board.copy();
+ MinesweeperCell emptyCell = (MinesweeperCell) emptyCaseBoard.getPuzzleElement(cell);
+ emptyCell.setCellType(MinesweeperTileData.mine());
+ ArrayList adjCells = getAdjacentCells(emptyCaseBoard, emptyCell);
+ int numMines;
+ int numUnset;
+ int cellNum;
+ for (MinesweeperCell adjCell : adjCells) {
+ cellNum = adjCell.getTileNumber();
+ if (cellNum <= 0) {
+ continue;
+ }
+ numMines = 0;
+ numUnset = 0;
+ ArrayList curAdjCells =
+ MinesweeperUtilities.getAdjacentCells(emptyCaseBoard, adjCell);
+ for (MinesweeperCell curAdjCell : curAdjCells) {
+ if (curAdjCell.getTileType() == MinesweeperTileType.MINE) {
+ numMines++;
+ }
+ if (curAdjCell.getTileType() == MinesweeperTileType.UNSET) {
+ numUnset++;
+ }
+ }
+ if (cellNum == numUnset + numMines) {
+ return true;
+ }
+ }
+ return false;
+ }
- LessBombsThanFlagContradictionRule tooManyBombs = new LessBombsThanFlagContradictionRule();
+ // checks if the current cell is forced to be empty by checking if any of its adjacent cells
+ // are a number cell that can only be satisfied if the current cell is empty
+ public static boolean isForcedEmpty(MinesweeperBoard board, MinesweeperCell cell) {
MinesweeperBoard emptyCaseBoard = board.copy();
MinesweeperCell emptyCell = (MinesweeperCell) emptyCaseBoard.getPuzzleElement(cell);
emptyCell.setCellType(MinesweeperTileData.empty());
ArrayList adjCells = getAdjacentCells(emptyCaseBoard, emptyCell);
+ int mineCount;
+ int adjCellNum;
+ int emptyCells = 0;
for (MinesweeperCell adjCell : adjCells) {
- if (tooManyBombs.checkContradictionAt(emptyCaseBoard, adjCell) == null) {
- return true;
+ mineCount = 0;
+ adjCellNum = adjCell.getTileNumber();
+ if (adjCellNum >= 1) {
+ ArrayList adjAdjCells = getAdjacentCells(emptyCaseBoard, adjCell);
+ for (MinesweeperCell adjAdjCell : adjAdjCells) {
+ if (adjAdjCell.getTileType() == MinesweeperTileType.MINE) {
+ mineCount++;
+ }
+ }
+ if (mineCount == adjCellNum) {
+ return true;
+ }
+ } else {
+ emptyCells++;
+ }
+ }
+ return emptyCells == adjCells.size();
+ }
+
+ public static boolean nonTouchingSharedIsMine(MinesweeperBoard board, MinesweeperCell cell) {
+ MinesweeperBoard emptyCaseBoard = board.copy();
+ MinesweeperCell emptyCell = (MinesweeperCell) emptyCaseBoard.getPuzzleElement(cell);
+ int x = emptyCell.getLocation().x;
+ int y = emptyCell.getLocation().y;
+ int height = emptyCaseBoard.getHeight();
+ int width = emptyCaseBoard.getWidth();
+ int numFar;
+ int numClose;
+
+ // Goes through all possible positions that horizontally adjacent number cells
+ // could be in that could force the current cell to be a mine. If one possibility
+ // actually has the number cells that force the current cell to be a mine, return true
+ for (int i = -1; i <= 1; i += 2) {
+ for (int j = -1; j <= 1; j++) {
+ if (x + (2 * i) >= 0 && x + (2 * i) < width && y + j >= 0 && y + j < height) {
+ numClose = emptyCaseBoard.getCell(x + i, y + j).getTileNumber();
+ numFar = emptyCaseBoard.getCell(x + (2 * i), y + j).getTileNumber();
+ if (j != -1
+ && y + 1 < height
+ && emptyCaseBoard.getCell(x, y + 1).getTileNumber() <= -1) {
+ numClose--;
+ }
+ if (j != 1
+ && y - 1 >= 0
+ && emptyCaseBoard.getCell(x, y - 1).getTileNumber() <= -1) {
+ numClose--;
+ }
+ if (j != 0
+ && y + (2 * j) < height
+ && y + (2 * j) >= 0
+ && emptyCaseBoard.getCell(x, y + (2 * j)).getTileNumber() <= -1) {
+ numClose--;
+ }
+ if (x + (3 * i) >= 0 && x + (3 * i) < width) {
+ if (emptyCaseBoard.getCell(x + (3 * i), y + j).getTileNumber() == -1) {
+ numFar--;
+ }
+ if (y + j + 1 < emptyCaseBoard.getHeight()
+ && emptyCaseBoard.getCell(x + (3 * i), y + j + 1).getTileNumber()
+ == -1) {
+ numFar--;
+ }
+ if (y + j - 1 >= 0
+ && emptyCaseBoard.getCell(x + (3 * i), y + j - 1).getTileNumber()
+ == -1) {
+ numFar--;
+ }
+ }
+ if (numClose >= 1 && numFar + 1 == numClose) {
+ return true;
+ }
+ }
+ }
+ }
+
+ // Goes through all possible positions that vertically adjacent number cells
+ // could be in that could force the current cell to be a mine. If one possibility
+ // actually has the number cells that force the current cell to be a mine, return true
+ for (int i = -1; i <= 1; i += 2) {
+ for (int j = -1; j <= 1; j++) {
+ if (x + j >= 0 && x + j < width && y + (2 * i) >= 0 && y + (2 * i) < height) {
+ numClose = emptyCaseBoard.getCell(x + j, y + i).getTileNumber();
+ numFar = emptyCaseBoard.getCell(x + j, y + (2 * i)).getTileNumber();
+ if (j != -1
+ && x + 1 < width
+ && emptyCaseBoard.getCell(x + 1, y).getTileNumber() <= -1) {
+ numClose--;
+ }
+ if (j != 1
+ && x - 1 >= 0
+ && emptyCaseBoard.getCell(x - 1, y).getTileNumber() <= -1) {
+ numClose--;
+ }
+ if (j != 0
+ && x + (2 * j) < width
+ && x + (2 * j) >= 0
+ && emptyCaseBoard.getCell(x + (2 * j), y).getTileNumber() <= -1) {
+ numClose--;
+ }
+ if (y + (3 * i) >= 0 && y + (3 * i) < height) {
+ if (emptyCaseBoard.getCell(x + j, y + (3 * i)).getTileNumber() == -1) {
+ numFar--;
+ }
+ if (x + j + 1 < width
+ && emptyCaseBoard.getCell(x + j + 1, y + (3 * i)).getTileNumber()
+ == -1) {
+ numFar--;
+ }
+ if (x + j - 1 >= 0
+ && emptyCaseBoard.getCell(x + j - 1, y + (3 * i)).getTileNumber()
+ == -1) {
+ numFar--;
+ }
+ }
+ if (numClose >= 1 && numFar + 1 == numClose) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ public static boolean nonTouchingSharedIsEmpty(MinesweeperBoard board, MinesweeperCell cell) {
+ MinesweeperBoard emptyCaseBoard = board.copy();
+ MinesweeperCell emptyCell = (MinesweeperCell) emptyCaseBoard.getPuzzleElement(cell);
+ int x = emptyCell.getLocation().x;
+ int y = emptyCell.getLocation().y;
+ int height = emptyCaseBoard.getHeight();
+ int width = emptyCaseBoard.getWidth();
+ int numClose;
+ int numFar;
+
+ // Goes through all possible positions that horizontally adjacent number cells
+ // could be in that could force the current cell to be empty. If one possibility
+ // actually has the number cells that force the current cell to be empty, return true
+ for (int i = -1; i <= 1; i += 2) {
+ for (int j = -1; j <= 1; j++) {
+ if (x + (2 * i) >= 0 && x + (2 * i) < width && y + j >= 0 && y + j < height) {
+ numFar = emptyCaseBoard.getCell(x + i, y + j).getTileNumber();
+ numClose = emptyCaseBoard.getCell(x + (2 * i), y + j).getTileNumber();
+ if (j != -1
+ && y + 1 < height
+ && emptyCaseBoard.getCell(x, y + 1).getTileNumber() == -1) {
+ numFar--;
+ }
+ if (j != 1
+ && y - 1 >= 0
+ && emptyCaseBoard.getCell(x, y - 1).getTileNumber() == -1) {
+ numFar--;
+ }
+ if (j != 0
+ && y + (2 * j) < height
+ && y + (2 * j) >= 0
+ && emptyCaseBoard.getCell(x, y + (2 * j)).getTileNumber() == -1) {
+ numFar--;
+ }
+ if (x + (3 * i) >= 0 && x + (3 * i) < width) {
+ if (emptyCaseBoard.getCell(x + (3 * i), y + j).getTileNumber() <= -1) {
+ numClose--;
+ }
+ if (y + j + 1 < emptyCaseBoard.getHeight()
+ && emptyCaseBoard.getCell(x + (3 * i), y + j + 1).getTileNumber()
+ <= -1) {
+ numClose--;
+ }
+ if (y + j - 1 >= 0
+ && emptyCaseBoard.getCell(x + (3 * i), y + j - 1).getTileNumber()
+ <= -1) {
+ numClose--;
+ }
+ }
+ if (numFar >= 1 && numClose == numFar) {
+ return true;
+ }
+ }
+ }
+ }
+
+ // Goes through all possible positions that vertically adjacent number cells
+ // could be in that could force the current cell to be empty. If one possibility
+ // actually has the number cells that force the current cell to beempty, return true
+ for (int i = -1; i <= 1; i += 2) {
+ for (int j = -1; j <= 1; j++) {
+ if (x + j >= 0 && x + j < width && y + (2 * i) >= 0 && y + (2 * i) < height) {
+ numFar = emptyCaseBoard.getCell(x + j, y + i).getTileNumber();
+ numClose = emptyCaseBoard.getCell(x + j, y + (2 * i)).getTileNumber();
+ if (j != -1
+ && x + 1 < width
+ && emptyCaseBoard.getCell(x + 1, y).getTileNumber() == -1) {
+ numFar--;
+ }
+ if (j != 1
+ && x - 1 >= 0
+ && emptyCaseBoard.getCell(x - 1, y).getTileNumber() == -1) {
+ numFar--;
+ }
+ if (j != 0
+ && x + (2 * j) < width
+ && x + (2 * j) >= 0
+ && emptyCaseBoard.getCell(x + (2 * j), y).getTileNumber() == -1) {
+ numFar--;
+ }
+ if (y + (3 * i) >= 0 && y + (3 * i) < height) {
+ if (emptyCaseBoard.getCell(x + j, y + (3 * i)).getTileNumber() <= -1) {
+ numClose--;
+ }
+ if (x + j + 1 < width
+ && emptyCaseBoard.getCell(x + j + 1, y + (3 * i)).getTileNumber()
+ <= -1) {
+ numClose--;
+ }
+ if (x + j - 1 >= 0
+ && emptyCaseBoard.getCell(x + j - 1, y + (3 * i)).getTileNumber()
+ <= -1) {
+ numClose--;
+ }
+ }
+ if (numFar >= 1 && numClose == numFar) {
+ return true;
+ }
+ }
}
}
return false;
diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperView.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperView.java
index e8ab8dfcb..b80efd7d2 100644
--- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperView.java
+++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperView.java
@@ -14,23 +14,23 @@
public class MinesweeperView extends GridBoardView {
private static final Logger LOGGER = LogManager.getLogger(MinesweeperView.class.getName());
- public static final Image BOMB_IMAGE;
+ public static final Image MINE_IMAGE;
public static final Image EMPTY_IMAGE;
static {
- Image tempBombImage = null;
+ Image tempMineImage = null;
try {
- tempBombImage =
+ tempMineImage =
ImageIO.read(
Objects.requireNonNull(
ClassLoader.getSystemClassLoader()
.getResource(
- "edu/rpi/legup/images/minesweeper/tiles/Bomb.png")));
+ "edu/rpi/legup/images/minesweeper/tiles/Mine.png")));
} catch (IOException e) {
LOGGER.error("Failed to open Minesweeper images");
}
- BOMB_IMAGE = tempBombImage;
+ MINE_IMAGE = tempMineImage;
}
static {
diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/BombTile.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/BombTile.java
deleted file mode 100644
index cd5577eeb..000000000
--- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/BombTile.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package edu.rpi.legup.puzzle.minesweeper.elements;
-
-import edu.rpi.legup.model.elements.PlaceableElement;
-
-public class BombTile extends PlaceableElement {
- public BombTile() {
- super(
- "MINE-UNPL-0001",
- "Bomb",
- "A bomb",
- "edu/rpi/legup/images/minesweeper/tiles/Bomb.png");
- }
-}
diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/FlagTile.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/FlagTile.java
deleted file mode 100644
index 0bbca81f9..000000000
--- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/FlagTile.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package edu.rpi.legup.puzzle.minesweeper.elements;
-
-import edu.rpi.legup.model.elements.PlaceableElement;
-
-public class FlagTile extends PlaceableElement {
- public FlagTile() {
- super(
- "MINE-PLAC-0001",
- "Flag",
- "The flag",
- "edu/rpi/legup/images/nurikabe/tiles/BlackTile.png");
- }
-}
diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/MineTile.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/MineTile.java
new file mode 100644
index 000000000..66f5ace2d
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/MineTile.java
@@ -0,0 +1,13 @@
+package edu.rpi.legup.puzzle.minesweeper.elements;
+
+import edu.rpi.legup.model.elements.PlaceableElement;
+
+public class MineTile extends PlaceableElement {
+ public MineTile() {
+ super(
+ "MINE-UNPL-0001",
+ "Mine",
+ "A mine",
+ "edu/rpi/legup/images/minesweeper/tiles/Mine.png");
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/NumberTile.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/NumberTile.java
new file mode 100644
index 000000000..0bf07e9a8
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/NumberTile.java
@@ -0,0 +1,13 @@
+package edu.rpi.legup.puzzle.minesweeper.elements;
+
+import edu.rpi.legup.model.elements.PlaceableElement;
+
+public class NumberTile extends PlaceableElement {
+ public NumberTile() {
+ super(
+ "MINE-PLAC-0001",
+ "Number",
+ "A number",
+ "edu/rpi/legup/images/minesweeper/tiles/Unset.png");
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/minesweeper_elements_reference_sheet.txt b/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/minesweeper_elements_reference_sheet.txt
index 08ce23f59..b9e474a9c 100644
--- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/minesweeper_elements_reference_sheet.txt
+++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/minesweeper_elements_reference_sheet.txt
@@ -1,4 +1,4 @@
-MINE-UNPL-0001 : BombTile
-MINE-PLAC-0001 : FlagTile
+MINE-UNPL-0001 : MineTile
+MINE-PLAC-0001 : NumberTile
MINE-PLAC-0002 : EmptyTile
MINE-UNPL-0002 : UnsetTile
\ No newline at end of file
diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/FinishWithBombsDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/FinishWithEmptyDirectRule.java
similarity index 74%
rename from src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/FinishWithBombsDirectRule.java
rename to src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/FinishWithEmptyDirectRule.java
index e85008d23..96b50a0e7 100644
--- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/FinishWithBombsDirectRule.java
+++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/FinishWithEmptyDirectRule.java
@@ -7,13 +7,13 @@
import edu.rpi.legup.model.tree.TreeTransition;
import edu.rpi.legup.puzzle.minesweeper.*;
-public class FinishWithBombsDirectRule extends DirectRule {
- public FinishWithBombsDirectRule() {
+public class FinishWithEmptyDirectRule extends DirectRule {
+ public FinishWithEmptyDirectRule() {
super(
- "MINE-BASC-0001",
- "Finish with Bombs",
- "The remaining unknowns around a flag must be bombs to satisfy the number",
- "edu/rpi/legup/images/minesweeper/direct/Fill_Bombs.jpg");
+ "MINE-BASC-0002",
+ "Finish With Empty",
+ "There exists a number around this cell that can only be satisfied if this cell is empty",
+ "edu/rpi/legup/images/minesweeper/direct/FinishWithEmpty.png");
}
@Override
@@ -24,15 +24,16 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem
MinesweeperCell parentCell = (MinesweeperCell) parentBoard.getPuzzleElement(puzzleElement);
if (!(parentCell.getTileType() == MinesweeperTileType.UNSET
- && cell.getTileType() == MinesweeperTileType.BOMB)) {
+ && cell.getTileType() == MinesweeperTileType.EMPTY)) {
+
return super.getInvalidUseOfRuleMessage()
- + ": This cell must be black to be applicable with this rule.";
+ + ": This cell must be empty to be applicable with this rule.";
}
- if (MinesweeperUtilities.isForcedBomb(parentBoard, cell)) {
+ if (MinesweeperUtilities.isForcedEmpty(parentBoard, cell)) {
return null;
} else {
- return super.getInvalidUseOfRuleMessage() + ": This cell is not forced to be black";
+ return super.getInvalidUseOfRuleMessage() + ": This cell is not forced to be empty";
}
}
@@ -49,9 +50,9 @@ public Board getDefaultBoard(TreeNode node) {
for (PuzzleElement element : minesweeperBoard.getPuzzleElements()) {
MinesweeperCell cell = (MinesweeperCell) element;
if (cell.getTileType() == MinesweeperTileType.UNSET
- && MinesweeperUtilities.isForcedBomb(
+ && MinesweeperUtilities.isForcedMine(
(MinesweeperBoard) node.getBoard(), cell)) {
- cell.setCellType(MinesweeperTileData.bomb());
+ cell.setCellType(MinesweeperTileData.mine());
minesweeperBoard.addModifiedData(cell);
}
}
diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/FinishWithMinesDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/FinishWithMinesDirectRule.java
new file mode 100644
index 000000000..b327683c9
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/FinishWithMinesDirectRule.java
@@ -0,0 +1,66 @@
+package edu.rpi.legup.puzzle.minesweeper.rules;
+
+import edu.rpi.legup.model.gameboard.Board;
+import edu.rpi.legup.model.gameboard.PuzzleElement;
+import edu.rpi.legup.model.rules.DirectRule;
+import edu.rpi.legup.model.tree.TreeNode;
+import edu.rpi.legup.model.tree.TreeTransition;
+import edu.rpi.legup.puzzle.minesweeper.*;
+
+public class FinishWithMinesDirectRule extends DirectRule {
+ public FinishWithMinesDirectRule() {
+ super(
+ "MINE-BASC-0001",
+ "Finish With Mines",
+ "There exists a number around this cell that can only be satisfied if this cell contains a mine",
+ "edu/rpi/legup/images/minesweeper/direct/FinishWithMines.png");
+ }
+
+ @Override
+ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) {
+ MinesweeperBoard board = (MinesweeperBoard) transition.getBoard();
+ MinesweeperBoard parentBoard = (MinesweeperBoard) transition.getParents().get(0).getBoard();
+ MinesweeperCell cell = (MinesweeperCell) board.getPuzzleElement(puzzleElement);
+ MinesweeperCell parentCell = (MinesweeperCell) parentBoard.getPuzzleElement(puzzleElement);
+
+ if (!(parentCell.getTileType() == MinesweeperTileType.UNSET
+ && cell.getTileType() == MinesweeperTileType.MINE)) {
+
+ return super.getInvalidUseOfRuleMessage()
+ + ": This cell must be a mine to be applicable with this rule.";
+ }
+
+ if (MinesweeperUtilities.isForcedMine(parentBoard, cell)) {
+ return null;
+ } else {
+ return super.getInvalidUseOfRuleMessage() + ": This cell is not forced to be a mine";
+ }
+ }
+
+ /**
+ * Creates a transition {@link Board} that has this rule applied to it using the {@link
+ * TreeNode}.
+ *
+ * @param node tree node used to create default transition board
+ * @return default board or null if this rule cannot be applied to this tree node
+ */
+ @Override
+ public Board getDefaultBoard(TreeNode node) {
+ MinesweeperBoard minesweeperBoard = (MinesweeperBoard) node.getBoard().copy();
+ for (PuzzleElement element : minesweeperBoard.getPuzzleElements()) {
+ MinesweeperCell cell = (MinesweeperCell) element;
+ if (cell.getTileType() == MinesweeperTileType.UNSET
+ && MinesweeperUtilities.isForcedMine(
+ (MinesweeperBoard) node.getBoard(), cell)) {
+ cell.setCellType(MinesweeperTileData.mine());
+ cell.setModifiable(false);
+ minesweeperBoard.addModifiedData(cell);
+ }
+ }
+ if (minesweeperBoard.getModifiedData().isEmpty()) {
+ return null;
+ } else {
+ return minesweeperBoard;
+ }
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/IsolateMineContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/IsolateMineContradictionRule.java
new file mode 100644
index 000000000..75fe933bd
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/IsolateMineContradictionRule.java
@@ -0,0 +1,48 @@
+package edu.rpi.legup.puzzle.minesweeper.rules;
+
+import edu.rpi.legup.model.gameboard.Board;
+import edu.rpi.legup.model.gameboard.PuzzleElement;
+import edu.rpi.legup.model.rules.ContradictionRule;
+import edu.rpi.legup.puzzle.minesweeper.MinesweeperBoard;
+import edu.rpi.legup.puzzle.minesweeper.MinesweeperCell;
+import edu.rpi.legup.puzzle.minesweeper.MinesweeperTileType;
+import edu.rpi.legup.puzzle.minesweeper.MinesweeperUtilities;
+import java.util.ArrayList;
+
+public class IsolateMineContradictionRule extends ContradictionRule {
+
+ public IsolateMineContradictionRule() {
+ super(
+ "MINE-CONT-0002",
+ "Isolate Mine",
+ "A mine cell must see a number cell",
+ "edu/rpi/legup/images/minesweeper/contradictions/IsolateMine.png");
+ }
+
+ /**
+ * Checks whether the transition has a contradiction at the specific puzzleElement index using
+ * this rule
+ *
+ * @param board board to check contradiction
+ * @param puzzleElement equivalent puzzleElement
+ * @return null if the transition contains a contradiction at the specified puzzleElement,
+ * otherwise error message
+ */
+ @Override
+ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) {
+ MinesweeperBoard minesweeperBoard = (MinesweeperBoard) board;
+ MinesweeperCell cell = (MinesweeperCell) minesweeperBoard.getPuzzleElement(puzzleElement);
+
+ if (cell.getTileNumber() != -1) {
+ return super.getNoContradictionMessage();
+ }
+ ArrayList adjCells =
+ MinesweeperUtilities.getAdjacentCells(minesweeperBoard, cell);
+ for (MinesweeperCell adjCell : adjCells) {
+ if (adjCell.getTileType() == MinesweeperTileType.NUMBER) {
+ return super.getNoContradictionMessage();
+ }
+ }
+ return null;
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/BombOrFilledCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/MineOrEmptyCaseRule.java
similarity index 83%
rename from src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/BombOrFilledCaseRule.java
rename to src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/MineOrEmptyCaseRule.java
index a1ef97928..66278e750 100644
--- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/BombOrFilledCaseRule.java
+++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/MineOrEmptyCaseRule.java
@@ -11,14 +11,14 @@
import java.util.ArrayList;
import java.util.List;
-public class BombOrFilledCaseRule extends CaseRule {
+public class MineOrEmptyCaseRule extends CaseRule {
- public BombOrFilledCaseRule() {
+ public MineOrEmptyCaseRule() {
super(
"MINE-CASE-0001",
- "Bomb Or Filled",
- "A cell can either be a bomb or filled.\n",
- "edu/rpi/legup/images/minesweeper/cases/BombOrFilled.jpg");
+ "Mine or Empty",
+ "An unset cell can either be a mine or empty.",
+ "edu/rpi/legup/images/minesweeper/cases/MineOrEmpty.png");
}
@Override
@@ -36,17 +36,19 @@ public CaseBoard getCaseBoard(Board board) {
}
@Override
- public List getCases(Board board, PuzzleElement puzzleElement) {
+ public ArrayList getCases(Board board, PuzzleElement puzzleElement) {
ArrayList cases = new ArrayList<>();
Board case1 = board.copy();
MinesweeperCell cell1 = (MinesweeperCell) case1.getPuzzleElement(puzzleElement);
- cell1.setData(MinesweeperTileData.bomb());
+ cell1.setModifiable(false);
+ cell1.setData(MinesweeperTileData.mine());
case1.addModifiedData(cell1);
cases.add(case1);
Board case2 = board.copy();
MinesweeperCell cell2 = (MinesweeperCell) case2.getPuzzleElement(puzzleElement);
+ cell2.setModifiable(false);
cell2.setData(MinesweeperTileData.empty());
case2.addModifiedData(cell2);
cases.add(case2);
@@ -77,10 +79,10 @@ public String checkRuleRaw(TreeTransition transition) {
+ ": This case rule must modify the same cell for each case.";
}
- if (!((mod1.getData().isBomb() && mod2.getData().isEmpty())
- || (mod2.getData().isBomb() && mod1.getData().isEmpty()))) {
+ if (!((mod1.getData().isMine() && mod2.getData().isEmpty())
+ || (mod2.getData().isMine() && mod1.getData().isEmpty()))) {
return super.getInvalidUseOfRuleMessage()
- + ": This case rule must an empty cell and a bomb cell.";
+ + ": This case rule must an empty cell and a mine cell.";
}
return null;
diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/NonTouchingSharedEmptyDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/NonTouchingSharedEmptyDirectRule.java
new file mode 100644
index 000000000..c6f6ed4df
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/NonTouchingSharedEmptyDirectRule.java
@@ -0,0 +1,66 @@
+package edu.rpi.legup.puzzle.minesweeper.rules;
+
+import edu.rpi.legup.model.gameboard.Board;
+import edu.rpi.legup.model.gameboard.PuzzleElement;
+import edu.rpi.legup.model.rules.DirectRule;
+import edu.rpi.legup.model.tree.TreeNode;
+import edu.rpi.legup.model.tree.TreeTransition;
+import edu.rpi.legup.puzzle.minesweeper.*;
+
+public class NonTouchingSharedEmptyDirectRule extends DirectRule {
+ public NonTouchingSharedEmptyDirectRule() {
+ super(
+ "MINE-BASC-0003",
+ "Non Shared Empty",
+ "Adjacent cells with numbers have the same difference in mine in their unshared\n"
+ + " regions as the difference in their numbers",
+ "edu/rpi/legup/images/minesweeper/direct/NonSharedEmpty.png");
+ }
+
+ @Override
+ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) {
+ MinesweeperBoard board = (MinesweeperBoard) transition.getBoard();
+ MinesweeperBoard parentBoard = (MinesweeperBoard) transition.getParents().get(0).getBoard();
+ MinesweeperCell cell = (MinesweeperCell) board.getPuzzleElement(puzzleElement);
+ MinesweeperCell parentCell = (MinesweeperCell) parentBoard.getPuzzleElement(puzzleElement);
+
+ if (!(parentCell.getTileType() == MinesweeperTileType.UNSET
+ && cell.getTileType() == MinesweeperTileType.EMPTY)) {
+
+ return super.getInvalidUseOfRuleMessage()
+ + ": This cell must be a mine to be applicable with this rule.";
+ }
+
+ if (MinesweeperUtilities.nonTouchingSharedIsEmpty(parentBoard, cell)) {
+ return null;
+ } else {
+ return super.getInvalidUseOfRuleMessage() + ": This cell is not forced to be a mine";
+ }
+ }
+
+ /**
+ * Creates a transition {@link Board} that has this rule applied to it using the {@link
+ * TreeNode}.
+ *
+ * @param node tree node used to create default transition board
+ * @return default board or null if this rule cannot be applied to this tree node
+ */
+ @Override
+ public Board getDefaultBoard(TreeNode node) {
+ MinesweeperBoard minesweeperBoard = (MinesweeperBoard) node.getBoard().copy();
+ for (PuzzleElement element : minesweeperBoard.getPuzzleElements()) {
+ MinesweeperCell cell = (MinesweeperCell) element;
+ if (cell.getTileType() == MinesweeperTileType.UNSET
+ && MinesweeperUtilities.isForcedEmpty(
+ (MinesweeperBoard) node.getBoard(), cell)) {
+ cell.setCellType(MinesweeperTileData.empty());
+ minesweeperBoard.addModifiedData(cell);
+ }
+ }
+ if (minesweeperBoard.getModifiedData().isEmpty()) {
+ return null;
+ } else {
+ return minesweeperBoard;
+ }
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/NonTouchingSharedMineDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/NonTouchingSharedMineDirectRule.java
new file mode 100644
index 000000000..df25b407a
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/NonTouchingSharedMineDirectRule.java
@@ -0,0 +1,66 @@
+package edu.rpi.legup.puzzle.minesweeper.rules;
+
+import edu.rpi.legup.model.gameboard.Board;
+import edu.rpi.legup.model.gameboard.PuzzleElement;
+import edu.rpi.legup.model.rules.DirectRule;
+import edu.rpi.legup.model.tree.TreeNode;
+import edu.rpi.legup.model.tree.TreeTransition;
+import edu.rpi.legup.puzzle.minesweeper.*;
+
+public class NonTouchingSharedMineDirectRule extends DirectRule {
+ public NonTouchingSharedMineDirectRule() {
+ super(
+ "MINE-BASC-0003",
+ "Non Shared Mine",
+ "Adjacent cells with numbers have the same difference in mine in their unshared\n"
+ + "regions as the difference in their numbers",
+ "edu/rpi/legup/images/minesweeper/direct/NonSharedMine.png");
+ }
+
+ @Override
+ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) {
+ MinesweeperBoard board = (MinesweeperBoard) transition.getBoard();
+ MinesweeperBoard parentBoard = (MinesweeperBoard) transition.getParents().get(0).getBoard();
+ MinesweeperCell cell = (MinesweeperCell) board.getPuzzleElement(puzzleElement);
+ MinesweeperCell parentCell = (MinesweeperCell) parentBoard.getPuzzleElement(puzzleElement);
+
+ if (!(parentCell.getTileType() == MinesweeperTileType.UNSET
+ && cell.getTileType() == MinesweeperTileType.MINE)) {
+
+ return super.getInvalidUseOfRuleMessage()
+ + ": This cell must be a mine to be applicable with this rule.";
+ }
+
+ if (MinesweeperUtilities.nonTouchingSharedIsMine(parentBoard, cell)) {
+ return null;
+ } else {
+ return super.getInvalidUseOfRuleMessage() + ": This cell is not forced to be a mine";
+ }
+ }
+
+ /**
+ * Creates a transition {@link Board} that has this rule applied to it using the {@link
+ * TreeNode}.
+ *
+ * @param node tree node used to create default transition board
+ * @return default board or null if this rule cannot be applied to this tree node
+ */
+ @Override
+ public Board getDefaultBoard(TreeNode node) {
+ MinesweeperBoard minesweeperBoard = (MinesweeperBoard) node.getBoard().copy();
+ for (PuzzleElement element : minesweeperBoard.getPuzzleElements()) {
+ MinesweeperCell cell = (MinesweeperCell) element;
+ if (cell.getTileType() == MinesweeperTileType.UNSET
+ && MinesweeperUtilities.isForcedMine(
+ (MinesweeperBoard) node.getBoard(), cell)) {
+ cell.setCellType(MinesweeperTileData.mine());
+ minesweeperBoard.addModifiedData(cell);
+ }
+ }
+ if (minesweeperBoard.getModifiedData().isEmpty()) {
+ return null;
+ } else {
+ return minesweeperBoard;
+ }
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/SatisfyFlagCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/SatisfyNumberCaseRule.java
similarity index 93%
rename from src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/SatisfyFlagCaseRule.java
rename to src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/SatisfyNumberCaseRule.java
index a59369b7a..004ea2640 100644
--- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/SatisfyFlagCaseRule.java
+++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/SatisfyNumberCaseRule.java
@@ -11,13 +11,13 @@
import java.util.*;
import java.util.List;
-public class SatisfyFlagCaseRule extends CaseRule {
- public SatisfyFlagCaseRule() {
+public class SatisfyNumberCaseRule extends CaseRule {
+ public SatisfyNumberCaseRule() {
super(
"MINE-CASE-0002",
- "Satisfy Flag",
- "Create a different path for each valid way to mark bombs and filled cells around a flag",
- "edu/rpi/legup/images/minesweeper/cases/Satisfy_Flag.png");
+ "Satisfy Number",
+ "Create a different path for each valid way to mark mines and empty cells around a number cell",
+ "edu/rpi/legup/images/minesweeper/cases/SatisfyNumber.png");
}
@Override
@@ -49,14 +49,14 @@ public ArrayList getCases(Board board, PuzzleElement puzzleElement) {
}
// find number of black & unset squares
- int cellNumBomb = 0;
+ int cellNummine = 0;
int cellNumUnset = 0;
ArrayList unsetCells = new ArrayList();
ArrayList adjCells =
MinesweeperUtilities.getAdjacentCells(minesweeperBoard, cell);
for (MinesweeperCell adjCell : adjCells) {
- if (adjCell.getTileType() == MinesweeperTileType.BOMB) {
- cellNumBomb++;
+ if (adjCell.getTileType() == MinesweeperTileType.MINE) {
+ cellNummine++;
}
if (adjCell.getTileType() == MinesweeperTileType.UNSET) {
cellNumUnset++;
@@ -64,21 +64,21 @@ public ArrayList getCases(Board board, PuzzleElement puzzleElement) {
}
}
// no cases if no empty or if too many black already
- if (cellNumBomb >= cellMaxBlack || cellNumUnset == 0) {
+ if (cellNummine >= cellMaxBlack || cellNumUnset == 0) {
return cases;
}
// generate all cases as boolean expressions
ArrayList combinations;
combinations =
- MinesweeperUtilities.getCombinations(cellMaxBlack - cellNumBomb, cellNumUnset);
+ MinesweeperUtilities.getCombinations(cellMaxBlack - cellNummine, cellNumUnset);
for (int i = 0; i < combinations.size(); i++) {
Board case_ = board.copy();
for (int j = 0; j < combinations.get(i).length; j++) {
cell = (MinesweeperCell) case_.getPuzzleElement(unsetCells.get(j));
if (combinations.get(i)[j]) {
- cell.setCellType(MinesweeperTileData.bomb());
+ cell.setCellType(MinesweeperTileData.mine());
} else {
cell.setCellType(MinesweeperTileData.empty());
}
@@ -162,7 +162,7 @@ public String checkRuleRaw(TreeTransition transition) {
int maxBlack = possibleCenter.getTileNumber();
for (MinesweeperCell adjCell :
MinesweeperUtilities.getAdjacentCells(board, possibleCenter)) {
- if (adjCell.getTileType() == MinesweeperTileType.BOMB) {
+ if (adjCell.getTileType() == MinesweeperTileType.MINE) {
numBlack++;
}
if (adjCell.getTileType() == MinesweeperTileType.UNSET) {
@@ -192,7 +192,7 @@ public String checkRuleRaw(TreeTransition transition) {
boolean[] translatedModCells = new boolean[transModCells.size()];
for (int i = 0; i < transModCells.size(); i++) {
- if (transModCells.get(i).getTileType() == MinesweeperTileType.BOMB) {
+ if (transModCells.get(i).getTileType() == MinesweeperTileType.MINE) {
translatedModCells[i] = true;
} else {
translatedModCells[i] = false;
diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/LessBombsThanFlagContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/TooFewMinesContradictionRule.java
similarity index 55%
rename from src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/LessBombsThanFlagContradictionRule.java
rename to src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/TooFewMinesContradictionRule.java
index c9919343f..5685c87ec 100644
--- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/LessBombsThanFlagContradictionRule.java
+++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/TooFewMinesContradictionRule.java
@@ -6,19 +6,28 @@
import edu.rpi.legup.puzzle.minesweeper.*;
import java.util.ArrayList;
-public class LessBombsThanFlagContradictionRule extends ContradictionRule {
+public class TooFewMinesContradictionRule extends ContradictionRule {
private final String NO_CONTRADICTION_MESSAGE =
"Does not contain a contradiction at this index";
private final String INVALID_USE_MESSAGE = "Contradiction must be a region";
- public LessBombsThanFlagContradictionRule() {
+ public TooFewMinesContradictionRule() {
super(
"MINE-CONT-0000",
- "Less Bombs Than Flag",
- "There can not be less then the number of Bombs around a flag then the specified number\n",
- "edu/rpi/legup/images/nurikabe/contradictions/NoNumber.png");
+ "Too Few Mines",
+ "A number cell can not have less than it's number of mines around it\n",
+ "edu/rpi/legup/images/minesweeper/contradictions/TooFewMines.png");
}
+ /**
+ * Checks whether the transition has a contradiction at the specific puzzleElement index using
+ * this rule
+ *
+ * @param board board to check contradiction
+ * @param puzzleElement equivalent puzzleElement
+ * @return null if the transition contains a contradiction at the specified puzzleElement,
+ * otherwise error message
+ */
@Override
public String checkContradictionAt(Board board, PuzzleElement puzzleElement) {
MinesweeperBoard minesweeperBoard = (MinesweeperBoard) board;
@@ -28,20 +37,20 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) {
if (cellNum <= 0 || cellNum >= 9) {
return super.getNoContradictionMessage();
}
- int numEmpty = 0;
- int numAdj = 0;
+ int numMines = 0;
+ int numUnset = 0;
ArrayList adjCells =
MinesweeperUtilities.getAdjacentCells(minesweeperBoard, cell);
for (MinesweeperCell adjCell : adjCells) {
- numAdj++;
- if (adjCell.getTileType() == MinesweeperTileType.EMPTY && adjCell != cell) {
- numEmpty++;
+ if (adjCell.getTileType() == MinesweeperTileType.MINE) {
+ numMines++;
+ }
+ if (adjCell.getTileType() == MinesweeperTileType.UNSET) {
+ numUnset++;
}
}
- System.out.println(numEmpty);
- System.out.println(numAdj);
- System.out.println(cellNum);
- if (numEmpty > (numAdj - cellNum)) {
+
+ if (cellNum > numUnset + numMines) {
return null;
}
diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/MoreBombsThanFlagContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/TooManyMinesContradictionRule.java
similarity index 77%
rename from src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/MoreBombsThanFlagContradictionRule.java
rename to src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/TooManyMinesContradictionRule.java
index ecfdbad66..551dead1e 100644
--- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/MoreBombsThanFlagContradictionRule.java
+++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/TooManyMinesContradictionRule.java
@@ -9,14 +9,14 @@
import edu.rpi.legup.puzzle.minesweeper.MinesweeperUtilities;
import java.util.ArrayList;
-public class MoreBombsThanFlagContradictionRule extends ContradictionRule {
+public class TooManyMinesContradictionRule extends ContradictionRule {
- public MoreBombsThanFlagContradictionRule() {
+ public TooManyMinesContradictionRule() {
super(
"MINE-CONT-0001",
- "More Bombs Than Flag",
- "There can not be more Bombs around a flag than the specified number\n",
- "edu/rpi/legup/images/minesweeper/contradictions/Bomb_Surplus.jpg");
+ "Too Many Mines",
+ "A number cell can not have more than it's number of mines around it\n",
+ "edu/rpi/legup/images/minesweeper/contradictions/TooManyMines.png");
}
/**
@@ -34,18 +34,19 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) {
MinesweeperCell cell = (MinesweeperCell) minesweeperBoard.getPuzzleElement(puzzleElement);
int cellNum = cell.getTileNumber();
- if (cellNum < 0 || cellNum >= 10) {
+ if (cellNum <= 0 || cellNum >= 9) {
return super.getNoContradictionMessage();
}
- int numBlack = 0;
+ int numMines = 0;
ArrayList adjCells =
MinesweeperUtilities.getAdjacentCells(minesweeperBoard, cell);
for (MinesweeperCell adjCell : adjCells) {
- if (adjCell.getTileType() == MinesweeperTileType.BOMB) {
- numBlack++;
+ if (adjCell.getTileType() == MinesweeperTileType.MINE) {
+ numMines++;
}
}
- if (numBlack > cellNum) {
+
+ if (cellNum < numMines) {
return null;
}
diff --git a/src/main/java/edu/rpi/legup/ui/HomePanel.java b/src/main/java/edu/rpi/legup/ui/HomePanel.java
index a2c280c45..7b2bf6d60 100644
--- a/src/main/java/edu/rpi/legup/ui/HomePanel.java
+++ b/src/main/java/edu/rpi/legup/ui/HomePanel.java
@@ -22,7 +22,6 @@
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
-
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.w3c.dom.Document;
@@ -228,64 +227,69 @@ public void openBatchGraderMenu() {
batchGraderOptions.add(gradePanel, BorderLayout.SOUTH);
// Action listeners for the buttons
- gradeAllIDsCheckbox.addActionListener(e -> puzzleIdField.setEnabled(!gradeAllIDsCheckbox.isSelected()));
- gradeAllTagsCheckbox.addActionListener(e -> puzzleTypeField.setEnabled(!gradeAllTagsCheckbox.isSelected()));
-
- browseButton.addActionListener(e -> {
- JFileChooser folderBrowser = new JFileChooser();
- folderBrowser.setCurrentDirectory(new File(LegupPreferences.WORK_DIRECTORY));
- folderBrowser.setDialogTitle("Select Directory");
- folderBrowser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
- folderBrowser.setAcceptAllFileFilterUsed(false);
- folderBrowser.setSelectedFile(null);
- folderBrowser.setVisible(true);
-
- int result = folderBrowser.showOpenDialog(frame);
- if (result == JFileChooser.APPROVE_OPTION) {
- directoryField.setText(folderBrowser.getSelectedFile().getAbsolutePath());
- }
- });
+ gradeAllIDsCheckbox.addActionListener(
+ e -> puzzleIdField.setEnabled(!gradeAllIDsCheckbox.isSelected()));
+ gradeAllTagsCheckbox.addActionListener(
+ e -> puzzleTypeField.setEnabled(!gradeAllTagsCheckbox.isSelected()));
+
+ browseButton.addActionListener(
+ e -> {
+ JFileChooser folderBrowser = new JFileChooser();
+ folderBrowser.setCurrentDirectory(new File(LegupPreferences.WORK_DIRECTORY));
+ folderBrowser.setDialogTitle("Select Directory");
+ folderBrowser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
+ folderBrowser.setAcceptAllFileFilterUsed(false);
+ folderBrowser.setSelectedFile(null);
+ folderBrowser.setVisible(true);
+
+ int result = folderBrowser.showOpenDialog(frame);
+ if (result == JFileChooser.APPROVE_OPTION) {
+ directoryField.setText(folderBrowser.getSelectedFile().getAbsolutePath());
+ }
+ });
- gradeButton.addActionListener(e -> {
- String directoryPath = directoryField.getText();
- String puzzleTags = puzzleIdField.getText();
- String puzzleTypes = puzzleTypeField.getText();
+ gradeButton.addActionListener(
+ e -> {
+ String directoryPath = directoryField.getText();
+ String puzzleTags = puzzleIdField.getText();
+ String puzzleTypes = puzzleTypeField.getText();
- _tagsToGrade.clear();
- if (!puzzleTags.isEmpty()) {
- Pattern pattern = Pattern.compile("\"(.*?)\"");
- Matcher matcher = pattern.matcher(puzzleTags);
+ _tagsToGrade.clear();
+ if (!puzzleTags.isEmpty()) {
+ Pattern pattern = Pattern.compile("\"(.*?)\"");
+ Matcher matcher = pattern.matcher(puzzleTags);
- while (matcher.find()) {
- _tagsToGrade.add(matcher.group(1));
- }
- }
- _typesToGrade.clear();
- if (!puzzleTypes.isEmpty()) {
- Pattern pattern = Pattern.compile("\"(.*?)\"");
- Matcher matcher = pattern.matcher(puzzleTypes);
-
- while (matcher.find()) {
- _typesToGrade.add(matcher.group(1));
- }
- }
+ while (matcher.find()) {
+ _tagsToGrade.add(matcher.group(1));
+ }
+ }
+ _typesToGrade.clear();
+ if (!puzzleTypes.isEmpty()) {
+ Pattern pattern = Pattern.compile("\"(.*?)\"");
+ Matcher matcher = pattern.matcher(puzzleTypes);
+
+ while (matcher.find()) {
+ _typesToGrade.add(matcher.group(1));
+ }
+ }
- try {
- File dir = new File(directoryPath);
- use_xml_to_check(dir);
- } catch (Exception ex) {
- throw new RuntimeException(ex);
- }
- LOGGER.debug("Finished autograding");
+ try {
+ File dir = new File(directoryPath);
+ use_xml_to_check(dir);
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
+ LOGGER.debug("Finished autograding");
- batchGraderOptions.dispose();
- });
+ batchGraderOptions.dispose();
+ });
- updateButton.addActionListener(e -> {
- recursiveUpdater(new File(directoryField.getText()));
- JOptionPane.showMessageDialog(null, "Updating complete.");
- batchGraderOptions.dispose();
- });
+ updateButton.addActionListener(
+ e -> {
+ recursiveUpdater(new File(directoryField.getText()));
+ JOptionPane.showMessageDialog(null, "Updating complete.");
+ batchGraderOptions.dispose();
+ });
// Center the dialog on the screen
batchGraderOptions.setLocationRelativeTo(null);
@@ -367,7 +371,8 @@ private void parsePuzzle(Document doc, BufferedWriter writer) throws IOException
}
/**
- * Reads the hashed solved state and export timestamp, unhashes information and prints out to csv
+ * Reads the hashed solved state and export timestamp, unhashes information and prints out to
+ * csv
*
* @param doc - the parsed file currently being graded
* @param writer - write to .csv
@@ -438,22 +443,30 @@ private void recursive_parser(File folder, BufferedWriter writer, String path)
}
Document doc;
- if ( (doc = isxmlfile(fileEntry)) == null) {
+ if ((doc = isxmlfile(fileEntry)) == null) {
LOGGER.debug("{} is not a '.xml' file", fName);
- writer.write(fName+",Not an xml file!\n");
+ writer.write(fName + ",Not an xml file!\n");
continue;
}
NodeList puzzleNodes = doc.getElementsByTagName("puzzle");
Element puzzleElement = (Element) puzzleNodes.item(0);
String puzzleTag = puzzleElement.getAttribute("tag");
- if (!_tagsToGrade.isEmpty() && _tagsToGrade.stream().noneMatch(puzzleTag::contains)) {
- LOGGER.debug("'{}' is not graded with tag '{}'", puzzleElement.getAttribute("name"), puzzleTag);
+ if (!_tagsToGrade.isEmpty()
+ && _tagsToGrade.stream().noneMatch(puzzleTag::contains)) {
+ LOGGER.debug(
+ "'{}' is not graded with tag '{}'",
+ puzzleElement.getAttribute("name"),
+ puzzleTag);
continue;
}
String puzzleType = puzzleElement.getAttribute("name");
- if (!_typesToGrade.isEmpty() && _typesToGrade.stream().noneMatch(puzzleType::contains)) {
- LOGGER.debug("'{}' is not graded with type '{}'", puzzleElement.getAttribute("name"), puzzleType);
+ if (!_typesToGrade.isEmpty()
+ && _typesToGrade.stream().noneMatch(puzzleType::contains)) {
+ LOGGER.debug(
+ "'{}' is not graded with type '{}'",
+ puzzleElement.getAttribute("name"),
+ puzzleType);
continue;
}
@@ -484,7 +497,7 @@ private void recursiveUpdater(File folder) {
LOGGER.debug("Empty directory");
return;
}
- for(File fileEntry : Objects.requireNonNull(folder.listFiles())) {
+ for (File fileEntry : Objects.requireNonNull(folder.listFiles())) {
if (fileEntry.isDirectory()) {
recursiveUpdater(fileEntry);
continue;
@@ -492,7 +505,7 @@ private void recursiveUpdater(File folder) {
String fName = fileEntry.getName();
Document doc;
- if ( (doc = isxmlfile(fileEntry)) == null) {
+ if ((doc = isxmlfile(fileEntry)) == null) {
LOGGER.debug("{} is not a '.xml' file", fileEntry.getName());
continue;
}
@@ -523,7 +536,9 @@ private void recursiveUpdater(File folder) {
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
DOMSource source = new DOMSource(doc);
- StreamResult result = new StreamResult(new File(folder.getAbsolutePath() + File.separator + fName));
+ StreamResult result =
+ new StreamResult(
+ new File(folder.getAbsolutePath() + File.separator + fName));
transformer.transform(source, result);
} catch (TransformerException e) {
diff --git a/src/main/resources/edu/rpi/legup/images/minesweeper/cases/MineOrEmpty.png b/src/main/resources/edu/rpi/legup/images/minesweeper/cases/MineOrEmpty.png
new file mode 100644
index 000000000..00ab7dfd5
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/minesweeper/cases/MineOrEmpty.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/minesweeper/cases/SatisfyNumber.png b/src/main/resources/edu/rpi/legup/images/minesweeper/cases/SatisfyNumber.png
new file mode 100644
index 000000000..e4458d16d
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/minesweeper/cases/SatisfyNumber.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/minesweeper/contradictions/IsolateMine.png b/src/main/resources/edu/rpi/legup/images/minesweeper/contradictions/IsolateMine.png
new file mode 100644
index 000000000..0b720c2f7
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/minesweeper/contradictions/IsolateMine.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/minesweeper/contradictions/TooFewMines.png b/src/main/resources/edu/rpi/legup/images/minesweeper/contradictions/TooFewMines.png
new file mode 100644
index 000000000..547b1d1c9
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/minesweeper/contradictions/TooFewMines.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/minesweeper/contradictions/TooManyMines.png b/src/main/resources/edu/rpi/legup/images/minesweeper/contradictions/TooManyMines.png
new file mode 100644
index 000000000..6c061a104
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/minesweeper/contradictions/TooManyMines.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/minesweeper/direct/FinishWithEmpty.png b/src/main/resources/edu/rpi/legup/images/minesweeper/direct/FinishWithEmpty.png
new file mode 100644
index 000000000..7988679a2
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/minesweeper/direct/FinishWithEmpty.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/minesweeper/direct/FinishWithMines.png b/src/main/resources/edu/rpi/legup/images/minesweeper/direct/FinishWithMines.png
new file mode 100644
index 000000000..3268ea697
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/minesweeper/direct/FinishWithMines.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/minesweeper/direct/NonSharedEmpty.png b/src/main/resources/edu/rpi/legup/images/minesweeper/direct/NonSharedEmpty.png
new file mode 100644
index 000000000..b8d982f19
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/minesweeper/direct/NonSharedEmpty.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/minesweeper/direct/NonSharedMine.png b/src/main/resources/edu/rpi/legup/images/minesweeper/direct/NonSharedMine.png
new file mode 100644
index 000000000..ab6242606
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/minesweeper/direct/NonSharedMine.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/minesweeper/tiles/Bomb.png b/src/main/resources/edu/rpi/legup/images/minesweeper/tiles/Mine.png
similarity index 100%
rename from src/main/resources/edu/rpi/legup/images/minesweeper/tiles/Bomb.png
rename to src/main/resources/edu/rpi/legup/images/minesweeper/tiles/Mine.png
diff --git a/src/main/resources/edu/rpi/legup/images/minesweeper/tiles/Unset.png b/src/main/resources/edu/rpi/legup/images/minesweeper/tiles/Unset.png
new file mode 100644
index 000000000..7e269c7cf
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/minesweeper/tiles/Unset.png differ
diff --git a/src/test/java/legup/TestRunner.java b/src/test/java/legup/TestRunner.java
index 5486a0353..e5619681e 100644
--- a/src/test/java/legup/TestRunner.java
+++ b/src/test/java/legup/TestRunner.java
@@ -30,7 +30,7 @@ public static void main(String[] args) {
printTestResults(result6);
Result result7 = JUnitCore.runClasses(FinishWithBulbsDirectRuleTest.class);
printTestResults(result7);
- Result result8 = JUnitCore.runClasses(FinishWithEmptyDirectRuleTest.class);
+ Result result8 = JUnitCore.runClasses(FinishWithEmptyDirectRuleDirectRuleTest.class);
printTestResults(result8);
Result result9 = JUnitCore.runClasses(LightOrEmptyCaseRuleTest.class);
printTestResults(result9);
diff --git a/src/test/java/puzzles/lightup/rules/FinishWithEmptyDirectRuleTest.java b/src/test/java/puzzles/lightup/rules/FinishWithEmptyDirectRuleDirectRuleTest.java
similarity index 98%
rename from src/test/java/puzzles/lightup/rules/FinishWithEmptyDirectRuleTest.java
rename to src/test/java/puzzles/lightup/rules/FinishWithEmptyDirectRuleDirectRuleTest.java
index 079641ee7..f80db6625 100644
--- a/src/test/java/puzzles/lightup/rules/FinishWithEmptyDirectRuleTest.java
+++ b/src/test/java/puzzles/lightup/rules/FinishWithEmptyDirectRuleDirectRuleTest.java
@@ -13,7 +13,7 @@
import org.junit.BeforeClass;
import org.junit.Test;
-public class FinishWithEmptyDirectRuleTest {
+public class FinishWithEmptyDirectRuleDirectRuleTest {
private static final FinishWithEmptyDirectRule RULE = new FinishWithEmptyDirectRule();
private static LightUp lightUp;
diff --git a/src/test/java/puzzles/minesweeper/FinishWithEmptyDirectRuleTest.java b/src/test/java/puzzles/minesweeper/FinishWithEmptyDirectRuleTest.java
new file mode 100644
index 000000000..2bcfd2fc0
--- /dev/null
+++ b/src/test/java/puzzles/minesweeper/FinishWithEmptyDirectRuleTest.java
@@ -0,0 +1,268 @@
+package puzzles.minesweeper;
+
+import edu.rpi.legup.model.tree.TreeNode;
+import edu.rpi.legup.model.tree.TreeTransition;
+import edu.rpi.legup.puzzle.minesweeper.Minesweeper;
+import edu.rpi.legup.puzzle.minesweeper.MinesweeperBoard;
+import edu.rpi.legup.puzzle.minesweeper.MinesweeperCell;
+import edu.rpi.legup.puzzle.minesweeper.MinesweeperTileData;
+import edu.rpi.legup.puzzle.minesweeper.rules.FinishWithEmptyDirectRule;
+import edu.rpi.legup.save.InvalidFileFormatException;
+import java.awt.*;
+import legup.MockGameBoardFacade;
+import legup.TestUtilities;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class FinishWithEmptyDirectRuleTest {
+
+ public static final FinishWithEmptyDirectRule RULE = new FinishWithEmptyDirectRule();
+ private static Minesweeper minesweeper;
+
+ @BeforeClass
+ public static void setUp() {
+ MockGameBoardFacade.getInstance();
+ minesweeper = new Minesweeper();
+ }
+
+ // tests the finish with empty direct rule is many different cases
+
+ @Test
+ public void FinishWithEmptyDirectRule_OneUnsetOneEmptyOneNumberTest1()
+ throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/minesweeper/rules/3x3test8.txt", minesweeper);
+ TreeNode rootNode = minesweeper.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ MinesweeperBoard board = (MinesweeperBoard) transition.getBoard();
+
+ MinesweeperCell cell1 = board.getCell(1, 0);
+ cell1.setData(MinesweeperTileData.empty());
+
+ board.addModifiedData(cell1);
+
+ Assert.assertNull(RULE.checkRule(transition));
+
+ for (int i = 0; i < board.getHeight(); i++) {
+ for (int k = 0; k < board.getWidth(); k++) {
+ Point point = new Point(k, i);
+ if (point.equals(cell1.getLocation())) {
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ } else {
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ }
+ }
+ }
+ }
+
+ @Test
+ public void FinishWithEmptyDirectRule_FiveUnsetOneEmptyOneNumberTest2()
+ throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/minesweeper/rules/3x3test9.txt", minesweeper);
+ TreeNode rootNode = minesweeper.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ MinesweeperBoard board = (MinesweeperBoard) transition.getBoard();
+
+ MinesweeperCell cell1 = board.getCell(1, 0);
+ cell1.setData(MinesweeperTileData.empty());
+
+ board.addModifiedData(cell1);
+
+ Assert.assertNull(RULE.checkRule(transition));
+
+ for (int i = 0; i < board.getHeight(); i++) {
+ for (int k = 0; k < board.getWidth(); k++) {
+ Point point = new Point(k, i);
+ if (point.equals(cell1.getLocation())) {
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ } else {
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ }
+ }
+ }
+ }
+
+ @Test
+ public void FinishWithEmptyDirectRule_NineUnsetOneEmptyZeroNumbersTest3()
+ throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/minesweeper/rules/3x3test", minesweeper);
+ TreeNode rootNode = minesweeper.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ MinesweeperBoard board = (MinesweeperBoard) transition.getBoard();
+
+ MinesweeperCell cell1 = board.getCell(1, 1);
+ cell1.setData(MinesweeperTileData.empty());
+
+ board.addModifiedData(cell1);
+
+ Assert.assertNull(RULE.checkRule(transition));
+
+ for (int i = 0; i < board.getHeight(); i++) {
+ for (int k = 0; k < board.getWidth(); k++) {
+ Point point = new Point(k, i);
+ if (point.equals(cell1.getLocation())) {
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ } else {
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ }
+ }
+ }
+ }
+
+ @Test
+ public void FinishWithEmptyDirectRule_NineUnsetNineEmptyZeroNumbersTest4()
+ throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/minesweeper/rules/3x3test", minesweeper);
+ TreeNode rootNode = minesweeper.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ MinesweeperBoard board = (MinesweeperBoard) transition.getBoard();
+
+ MinesweeperCell cell1 = board.getCell(0, 0);
+ cell1.setData(MinesweeperTileData.empty());
+ MinesweeperCell cell2 = board.getCell(1, 0);
+ cell2.setData(MinesweeperTileData.empty());
+ MinesweeperCell cell3 = board.getCell(2, 0);
+ cell3.setData(MinesweeperTileData.empty());
+ MinesweeperCell cell4 = board.getCell(0, 1);
+ cell4.setData(MinesweeperTileData.empty());
+ MinesweeperCell cell5 = board.getCell(1, 1);
+ cell5.setData(MinesweeperTileData.empty());
+ MinesweeperCell cell6 = board.getCell(2, 1);
+ cell6.setData(MinesweeperTileData.empty());
+ MinesweeperCell cell7 = board.getCell(0, 2);
+ cell7.setData(MinesweeperTileData.empty());
+ MinesweeperCell cell8 = board.getCell(1, 2);
+ cell8.setData(MinesweeperTileData.empty());
+ MinesweeperCell cell9 = board.getCell(2, 2);
+ cell9.setData(MinesweeperTileData.empty());
+
+ board.addModifiedData(cell1);
+ board.addModifiedData(cell2);
+ board.addModifiedData(cell3);
+ board.addModifiedData(cell4);
+ board.addModifiedData(cell5);
+ board.addModifiedData(cell6);
+ board.addModifiedData(cell7);
+ board.addModifiedData(cell8);
+ board.addModifiedData(cell9);
+
+ Assert.assertNull(RULE.checkRule(transition));
+
+ for (int i = 0; i < board.getHeight(); i++) {
+ for (int k = 0; k < board.getWidth(); k++) {
+ Point point = new Point(k, i);
+ if (point.equals(cell1.getLocation())
+ || point.equals(cell2.getLocation())
+ || point.equals(cell3.getLocation())
+ || point.equals(cell4.getLocation())
+ || point.equals(cell5.getLocation())
+ || point.equals(cell6.getLocation())
+ || point.equals(cell7.getLocation())
+ || point.equals(cell8.getLocation())
+ || point.equals(cell9.getLocation())) {
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ } else {
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ }
+ }
+ }
+ }
+
+ @Test
+ public void FinishWithEmptyDirectRule_OneUnsetOneEmptyThreeNumbersTest5()
+ throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/minesweeper/rules/3x3test10.txt", minesweeper);
+ TreeNode rootNode = minesweeper.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ MinesweeperBoard board = (MinesweeperBoard) transition.getBoard();
+
+ MinesweeperCell cell1 = board.getCell(1, 2);
+ cell1.setData(MinesweeperTileData.empty());
+
+ board.addModifiedData(cell1);
+
+ Assert.assertNull(RULE.checkRule(transition));
+
+ for (int i = 0; i < board.getHeight(); i++) {
+ for (int k = 0; k < board.getWidth(); k++) {
+ Point point = new Point(k, i);
+ if (point.equals(cell1.getLocation())) {
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ } else {
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ }
+ }
+ }
+ }
+
+ @Test
+ public void FinishWithEmptyDirectRule_OneUnsetOneEmptyThreeNumbersTest6()
+ throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/minesweeper/rules/3x3test11.txt", minesweeper);
+ TreeNode rootNode = minesweeper.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ MinesweeperBoard board = (MinesweeperBoard) transition.getBoard();
+
+ MinesweeperCell cell1 = board.getCell(1, 1);
+ cell1.setData(MinesweeperTileData.empty());
+
+ board.addModifiedData(cell1);
+
+ Assert.assertNull(RULE.checkRule(transition));
+
+ for (int i = 0; i < board.getHeight(); i++) {
+ for (int k = 0; k < board.getWidth(); k++) {
+ Point point = new Point(k, i);
+ if (point.equals(cell1.getLocation())) {
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ } else {
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ }
+ }
+ }
+ }
+
+ @Test
+ public void FinishWithEmptyDirectRule_FiveUnsetTwoEmptyTwoNumbersTest7()
+ throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/minesweeper/rules/3x3test12.txt", minesweeper);
+ TreeNode rootNode = minesweeper.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ MinesweeperBoard board = (MinesweeperBoard) transition.getBoard();
+
+ MinesweeperCell cell1 = board.getCell(0, 2);
+ cell1.setData(MinesweeperTileData.empty());
+ MinesweeperCell cell2 = board.getCell(2, 2);
+ cell2.setData(MinesweeperTileData.empty());
+
+ board.addModifiedData(cell1);
+ board.addModifiedData(cell2);
+
+ Assert.assertNull(RULE.checkRule(transition));
+
+ for (int i = 0; i < board.getHeight(); i++) {
+ for (int k = 0; k < board.getWidth(); k++) {
+ Point point = new Point(k, i);
+ if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) {
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ } else {
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ }
+ }
+ }
+ }
+}
diff --git a/src/test/java/puzzles/minesweeper/FinishWithMinesDirectRuleTest.java b/src/test/java/puzzles/minesweeper/FinishWithMinesDirectRuleTest.java
new file mode 100644
index 000000000..5e0246cb5
--- /dev/null
+++ b/src/test/java/puzzles/minesweeper/FinishWithMinesDirectRuleTest.java
@@ -0,0 +1,273 @@
+package puzzles.minesweeper;
+
+import edu.rpi.legup.model.tree.TreeNode;
+import edu.rpi.legup.model.tree.TreeTransition;
+import edu.rpi.legup.puzzle.minesweeper.*;
+import edu.rpi.legup.puzzle.minesweeper.rules.FinishWithMinesDirectRule;
+import edu.rpi.legup.save.InvalidFileFormatException;
+import java.awt.*;
+import legup.MockGameBoardFacade;
+import legup.TestUtilities;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class FinishWithMinesDirectRuleTest {
+
+ public static final FinishWithMinesDirectRule RULE = new FinishWithMinesDirectRule();
+ private static Minesweeper minesweeper;
+
+ @BeforeClass
+ public static void setUp() {
+ MockGameBoardFacade.getInstance();
+ minesweeper = new Minesweeper();
+ }
+
+ // tests the finish with mines direct rule is many different cases
+
+ @Test
+ public void FinishWithMinesDirectRule_OneUnsetOneBombOneNumberTest1()
+ throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/minesweeper/rules/3x3test2.txt", minesweeper);
+ TreeNode rootNode = minesweeper.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ MinesweeperBoard board = (MinesweeperBoard) transition.getBoard();
+
+ MinesweeperCell cell1 = board.getCell(1, 0);
+ cell1.setData(MinesweeperTileData.mine());
+
+ board.addModifiedData(cell1);
+
+ Assert.assertNull(RULE.checkRule(transition));
+
+ for (int i = 0; i < board.getHeight(); i++) {
+ for (int k = 0; k < board.getWidth(); k++) {
+ Point point = new Point(k, i);
+ if (point.equals(cell1.getLocation())) {
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ } else {
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ }
+ }
+ }
+ }
+
+ @Test
+ public void FinishWithMinesDirectRule_FourUnsetOneBombOneNumberTest2()
+ throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/minesweeper/rules/3x3test3.txt", minesweeper);
+ TreeNode rootNode = minesweeper.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ MinesweeperBoard board = (MinesweeperBoard) transition.getBoard();
+
+ MinesweeperCell cell1 = board.getCell(0, 1);
+ cell1.setData(MinesweeperTileData.mine());
+
+ board.addModifiedData(cell1);
+
+ Assert.assertNull(RULE.checkRule(transition));
+
+ for (int i = 0; i < board.getHeight(); i++) {
+ for (int k = 0; k < board.getWidth(); k++) {
+ Point point = new Point(k, i);
+ if (point.equals(cell1.getLocation())) {
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ } else {
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ }
+ }
+ }
+ }
+
+ @Test
+ public void FinishWithMinesDirectRule_FourUnsetFourBombsOneNumberTest3()
+ throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/minesweeper/rules/3x3test3.txt", minesweeper);
+ TreeNode rootNode = minesweeper.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ MinesweeperBoard board = (MinesweeperBoard) transition.getBoard();
+
+ MinesweeperCell cell1 = board.getCell(1, 0);
+ cell1.setData(MinesweeperTileData.mine());
+ MinesweeperCell cell2 = board.getCell(2, 0);
+ cell2.setData(MinesweeperTileData.mine());
+ MinesweeperCell cell3 = board.getCell(0, 1);
+ cell3.setData(MinesweeperTileData.mine());
+ MinesweeperCell cell4 = board.getCell(0, 2);
+ cell4.setData(MinesweeperTileData.mine());
+
+ board.addModifiedData(cell1);
+ board.addModifiedData(cell2);
+ board.addModifiedData(cell3);
+ board.addModifiedData(cell4);
+
+ Assert.assertNull(RULE.checkRule(transition));
+
+ for (int i = 0; i < board.getHeight(); i++) {
+ for (int k = 0; k < board.getWidth(); k++) {
+ Point point = new Point(k, i);
+ if (point.equals(cell1.getLocation())
+ || point.equals(cell2.getLocation())
+ || point.equals(cell3.getLocation())
+ || point.equals(cell4.getLocation())) {
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ } else {
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ }
+ }
+ }
+ }
+
+ @Test
+ public void FinishWithMinesDirectRule_EightUnsetEightBombsOneNumberTest4()
+ throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/minesweeper/rules/3x3test4.txt", minesweeper);
+ TreeNode rootNode = minesweeper.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ MinesweeperBoard board = (MinesweeperBoard) transition.getBoard();
+
+ MinesweeperCell cell1 = board.getCell(0, 0);
+ cell1.setData(MinesweeperTileData.mine());
+ MinesweeperCell cell2 = board.getCell(1, 0);
+ cell2.setData(MinesweeperTileData.mine());
+ MinesweeperCell cell3 = board.getCell(2, 0);
+ cell3.setData(MinesweeperTileData.mine());
+ MinesweeperCell cell4 = board.getCell(0, 1);
+ cell4.setData(MinesweeperTileData.mine());
+ MinesweeperCell cell5 = board.getCell(2, 1);
+ cell5.setData(MinesweeperTileData.mine());
+ MinesweeperCell cell6 = board.getCell(0, 2);
+ cell6.setData(MinesweeperTileData.mine());
+ MinesweeperCell cell7 = board.getCell(1, 2);
+ cell7.setData(MinesweeperTileData.mine());
+ MinesweeperCell cell8 = board.getCell(2, 2);
+ cell8.setData(MinesweeperTileData.mine());
+
+ board.addModifiedData(cell1);
+ board.addModifiedData(cell2);
+ board.addModifiedData(cell3);
+ board.addModifiedData(cell4);
+ board.addModifiedData(cell5);
+ board.addModifiedData(cell6);
+ board.addModifiedData(cell7);
+ board.addModifiedData(cell8);
+
+ Assert.assertNull(RULE.checkRule(transition));
+
+ for (int i = 0; i < board.getHeight(); i++) {
+ for (int k = 0; k < board.getWidth(); k++) {
+ Point point = new Point(k, i);
+ if (point.equals(cell1.getLocation())
+ || point.equals(cell2.getLocation())
+ || point.equals(cell3.getLocation())
+ || point.equals(cell4.getLocation())
+ || point.equals(cell5.getLocation())
+ || point.equals(cell6.getLocation())
+ || point.equals(cell7.getLocation())
+ || point.equals(cell8.getLocation())) {
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ } else {
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ }
+ }
+ }
+ }
+
+ @Test
+ public void FinishWithMinesDirectRule_OneUnsetOneBombFourNumbersTest5()
+ throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/minesweeper/rules/3x3test5.txt", minesweeper);
+ TreeNode rootNode = minesweeper.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ MinesweeperBoard board = (MinesweeperBoard) transition.getBoard();
+
+ MinesweeperCell cell1 = board.getCell(1, 1);
+ cell1.setData(MinesweeperTileData.mine());
+
+ board.addModifiedData(cell1);
+
+ Assert.assertNull(RULE.checkRule(transition));
+
+ for (int i = 0; i < board.getHeight(); i++) {
+ for (int k = 0; k < board.getWidth(); k++) {
+ Point point = new Point(k, i);
+ if (point.equals(cell1.getLocation())) {
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ } else {
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ }
+ }
+ }
+ }
+
+ @Test
+ public void FinishWithMinesDirectRule_TwoUnsetTwoBombsTwoNumbersTest6()
+ throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/minesweeper/rules/3x3test6.txt", minesweeper);
+ TreeNode rootNode = minesweeper.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ MinesweeperBoard board = (MinesweeperBoard) transition.getBoard();
+
+ MinesweeperCell cell1 = board.getCell(0, 1);
+ cell1.setData(MinesweeperTileData.mine());
+ MinesweeperCell cell2 = board.getCell(2, 1);
+ cell2.setData(MinesweeperTileData.mine());
+
+ board.addModifiedData(cell1);
+ board.addModifiedData(cell2);
+
+ Assert.assertNull(RULE.checkRule(transition));
+
+ for (int i = 0; i < board.getHeight(); i++) {
+ for (int k = 0; k < board.getWidth(); k++) {
+ Point point = new Point(k, i);
+ if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) {
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ } else {
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ }
+ }
+ }
+ }
+
+ @Test
+ public void FinishWithMinesDirectRule_ThreeUnsetOneBombTwoNumbersTest7()
+ throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/minesweeper/rules/3x3test7.txt", minesweeper);
+ TreeNode rootNode = minesweeper.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ MinesweeperBoard board = (MinesweeperBoard) transition.getBoard();
+
+ MinesweeperCell cell1 = board.getCell(1, 1);
+ cell1.setData(MinesweeperTileData.mine());
+
+ board.addModifiedData(cell1);
+
+ Assert.assertNull(RULE.checkRule(transition));
+
+ for (int i = 0; i < board.getHeight(); i++) {
+ for (int k = 0; k < board.getWidth(); k++) {
+ Point point = new Point(k, i);
+ if (point.equals(cell1.getLocation())) {
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ } else {
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ }
+ }
+ }
+ }
+}
diff --git a/src/test/java/puzzles/minesweeper/IsolateMineContradictionRuleTest.java b/src/test/java/puzzles/minesweeper/IsolateMineContradictionRuleTest.java
new file mode 100644
index 000000000..05d5615db
--- /dev/null
+++ b/src/test/java/puzzles/minesweeper/IsolateMineContradictionRuleTest.java
@@ -0,0 +1,92 @@
+package puzzles.minesweeper;
+
+import edu.rpi.legup.model.tree.TreeNode;
+import edu.rpi.legup.model.tree.TreeTransition;
+import edu.rpi.legup.puzzle.minesweeper.Minesweeper;
+import edu.rpi.legup.puzzle.minesweeper.MinesweeperBoard;
+import edu.rpi.legup.puzzle.minesweeper.rules.IsolateMineContradictionRule;
+import edu.rpi.legup.save.InvalidFileFormatException;
+import legup.TestUtilities;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class IsolateMineContradictionRuleTest {
+ private static final IsolateMineContradictionRule RULE = new IsolateMineContradictionRule();
+ private static Minesweeper minesweeper;
+
+ @BeforeClass
+ public static void setUp() {
+ minesweeper = new Minesweeper();
+ }
+
+ @Test
+ // tests a 3x3 board with a mine in the center surrounded by empty cells
+ public void IsolateMineTest1() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/minesweeper/rules/IsolateMine1.txt", minesweeper);
+ TreeNode rootNode = minesweeper.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ MinesweeperBoard board = (MinesweeperBoard) transition.getBoard();
+
+ // confirm it is impossible to satisfy up the center square
+ Assert.assertNull(RULE.checkContradictionAt(board, board.getCell(1, 1)));
+
+ // every square except the center
+ Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(0, 0)));
+ Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(1, 0)));
+ Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(2, 0)));
+ Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(0, 1)));
+ Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(2, 1)));
+ Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(0, 2)));
+ Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(1, 2)));
+ Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(2, 2)));
+ }
+
+ @Test
+ // tests a 3x3 board with a mine in the center surrounded by unset cells
+ public void IsolateMineTest2() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/minesweeper/rules/IsolateMine2.txt", minesweeper);
+ TreeNode rootNode = minesweeper.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ MinesweeperBoard board = (MinesweeperBoard) transition.getBoard();
+
+ // confirm it is impossible to satisfy up the center square
+ Assert.assertNull(RULE.checkContradictionAt(board, board.getCell(1, 1)));
+
+ // every square except the center
+ Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(0, 0)));
+ Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(1, 0)));
+ Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(2, 0)));
+ Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(0, 1)));
+ Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(2, 1)));
+ Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(0, 2)));
+ Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(1, 2)));
+ Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(2, 2)));
+ }
+
+ @Test
+ // tests a 3x3 board full of mines only
+ public void IsolateMineTest3() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/minesweeper/rules/IsolateMine3.txt", minesweeper);
+ TreeNode rootNode = minesweeper.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ MinesweeperBoard board = (MinesweeperBoard) transition.getBoard();
+
+ // confirm it is impossible to satisfy any of the squares
+ Assert.assertNull(RULE.checkContradictionAt(board, board.getCell(1, 1)));
+ Assert.assertNull(RULE.checkContradictionAt(board, board.getCell(0, 0)));
+ Assert.assertNull(RULE.checkContradictionAt(board, board.getCell(1, 0)));
+ Assert.assertNull(RULE.checkContradictionAt(board, board.getCell(2, 0)));
+ Assert.assertNull(RULE.checkContradictionAt(board, board.getCell(0, 1)));
+ Assert.assertNull(RULE.checkContradictionAt(board, board.getCell(2, 1)));
+ Assert.assertNull(RULE.checkContradictionAt(board, board.getCell(0, 2)));
+ Assert.assertNull(RULE.checkContradictionAt(board, board.getCell(1, 2)));
+ Assert.assertNull(RULE.checkContradictionAt(board, board.getCell(2, 2)));
+ }
+}
diff --git a/src/test/java/puzzles/minesweeper/MineOrEmptyCaseRuleTest.java b/src/test/java/puzzles/minesweeper/MineOrEmptyCaseRuleTest.java
new file mode 100644
index 000000000..d476e8fdf
--- /dev/null
+++ b/src/test/java/puzzles/minesweeper/MineOrEmptyCaseRuleTest.java
@@ -0,0 +1,74 @@
+package puzzles.minesweeper;
+
+import edu.rpi.legup.model.gameboard.Board;
+import edu.rpi.legup.model.tree.TreeNode;
+import edu.rpi.legup.model.tree.TreeTransition;
+import edu.rpi.legup.puzzle.minesweeper.Minesweeper;
+import edu.rpi.legup.puzzle.minesweeper.MinesweeperBoard;
+import edu.rpi.legup.puzzle.minesweeper.MinesweeperCell;
+import edu.rpi.legup.puzzle.minesweeper.MinesweeperTileData;
+import edu.rpi.legup.puzzle.minesweeper.rules.MineOrEmptyCaseRule;
+import edu.rpi.legup.save.InvalidFileFormatException;
+import java.awt.*;
+import java.util.ArrayList;
+import legup.MockGameBoardFacade;
+import legup.TestUtilities;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class MineOrEmptyCaseRuleTest {
+
+ private static final MineOrEmptyCaseRule RULE = new MineOrEmptyCaseRule();
+ private static Minesweeper minesweeper;
+
+ @BeforeClass
+ public static void setUp() {
+ MockGameBoardFacade.getInstance();
+ minesweeper = new Minesweeper();
+ }
+
+ /**
+ * Tests the Mine or Empty case rule by ensuring that it results in two children, that contain a
+ * modified cell that is either mine or empty
+ */
+ @Test
+ public void MineOrEmptyCaseRuleTest1() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/minesweeper/rules/MineOrEmpty.txt", minesweeper);
+ TreeNode rootNode = minesweeper.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ MinesweeperBoard board = (MinesweeperBoard) transition.getBoard();
+ MinesweeperCell cell = board.getCell(0, 0);
+ ArrayList cases = RULE.getCases(board, cell);
+
+ Assert.assertEquals(2, cases.size());
+
+ MinesweeperBoard caseBoard = (MinesweeperBoard) cases.get(0);
+ MinesweeperBoard caseBoard2 = (MinesweeperBoard) cases.get(1);
+
+ MinesweeperTileData board1Type = caseBoard.getCell(0, 0).getData();
+ MinesweeperTileData board2Type = caseBoard2.getCell(0, 0).getData();
+
+ Assert.assertTrue(
+ ((board1Type.equals(MinesweeperTileData.mine())
+ || board1Type.equals(MinesweeperTileData.empty())))
+ && (board2Type.equals(MinesweeperTileData.mine())
+ || board2Type.equals(MinesweeperTileData.empty())));
+ Assert.assertFalse(board1Type.equals(board2Type));
+
+ Assert.assertEquals(caseBoard.getHeight(), caseBoard2.getHeight(), board.getHeight());
+ Assert.assertEquals(caseBoard.getWidth(), caseBoard2.getWidth(), board.getWidth());
+
+ for (int i = 0; i < caseBoard.getHeight(); i++) {
+ for (int k = 0; k < caseBoard.getWidth(); k++) {
+ Point point = new Point(k, i);
+ if (point.equals(caseBoard.getCell(k, i).getLocation())) {
+ continue;
+ }
+ Assert.assertTrue(caseBoard.getCell(k, i).equals(caseBoard2.getCell(k, i)));
+ }
+ }
+ }
+}
diff --git a/src/test/java/puzzles/minesweeper/NonTouchingSharedEmptyDirectRuleTest.java b/src/test/java/puzzles/minesweeper/NonTouchingSharedEmptyDirectRuleTest.java
new file mode 100644
index 000000000..f1cc0a03c
--- /dev/null
+++ b/src/test/java/puzzles/minesweeper/NonTouchingSharedEmptyDirectRuleTest.java
@@ -0,0 +1,165 @@
+package puzzles.minesweeper;
+
+import edu.rpi.legup.model.tree.TreeNode;
+import edu.rpi.legup.model.tree.TreeTransition;
+import edu.rpi.legup.puzzle.minesweeper.Minesweeper;
+import edu.rpi.legup.puzzle.minesweeper.MinesweeperBoard;
+import edu.rpi.legup.puzzle.minesweeper.MinesweeperCell;
+import edu.rpi.legup.puzzle.minesweeper.MinesweeperTileData;
+import edu.rpi.legup.puzzle.minesweeper.rules.NonTouchingSharedEmptyDirectRule;
+import edu.rpi.legup.save.InvalidFileFormatException;
+import java.awt.*;
+import legup.MockGameBoardFacade;
+import legup.TestUtilities;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class NonTouchingSharedEmptyDirectRuleTest {
+
+ public static final NonTouchingSharedEmptyDirectRule RULE =
+ new NonTouchingSharedEmptyDirectRule();
+ private static Minesweeper minesweeper;
+
+ @BeforeClass
+ public static void setUp() {
+ MockGameBoardFacade.getInstance();
+ minesweeper = new Minesweeper();
+ }
+
+ // Horizontal/vertical tests means the adjacent number cells are adjacent
+ // horizontally/vertically
+
+ @Test
+ public void NonTouchingSharedEmptyDirectRule_HorizontalTest1()
+ throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/minesweeper/rules/3x3test15.txt", minesweeper);
+ TreeNode rootNode = minesweeper.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ MinesweeperBoard board = (MinesweeperBoard) transition.getBoard();
+
+ MinesweeperCell cell1 = board.getCell(2, 1);
+ cell1.setData(MinesweeperTileData.empty());
+
+ board.addModifiedData(cell1);
+
+ Assert.assertNull(RULE.checkRule(transition));
+
+ for (int i = 0; i < board.getHeight(); i++) {
+ for (int k = 0; k < board.getWidth(); k++) {
+ Point point = new Point(k, i);
+ if (point.equals(cell1.getLocation())) {
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ } else {
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ }
+ }
+ }
+ }
+
+ @Test
+ public void NonTouchingSharedEmptyDirectRule_HorizontalTest2()
+ throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/minesweeper/rules/4x4test4.txt", minesweeper);
+ TreeNode rootNode = minesweeper.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ MinesweeperBoard board = (MinesweeperBoard) transition.getBoard();
+
+ MinesweeperCell cell1 = board.getCell(0, 0);
+ cell1.setData(MinesweeperTileData.empty());
+ MinesweeperCell cell2 = board.getCell(0, 1);
+ cell2.setData(MinesweeperTileData.empty());
+ MinesweeperCell cell3 = board.getCell(0, 2);
+ cell3.setData(MinesweeperTileData.empty());
+
+ board.addModifiedData(cell1);
+ board.addModifiedData(cell2);
+ board.addModifiedData(cell3);
+
+ Assert.assertNull(RULE.checkRule(transition));
+
+ for (int i = 0; i < board.getHeight(); i++) {
+ for (int k = 0; k < board.getWidth(); k++) {
+ Point point = new Point(k, i);
+ if (point.equals(cell1.getLocation())
+ || point.equals(cell2.getLocation())
+ || point.equals(cell3.getLocation())) {
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ } else {
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ }
+ }
+ }
+ }
+
+ @Test
+ public void NonTouchingSharedEmptyDirectRule_VerticalTest1() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/minesweeper/rules/4x4test5.txt", minesweeper);
+ TreeNode rootNode = minesweeper.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ MinesweeperBoard board = (MinesweeperBoard) transition.getBoard();
+
+ MinesweeperCell cell1 = board.getCell(1, 0);
+ cell1.setData(MinesweeperTileData.empty());
+ MinesweeperCell cell2 = board.getCell(2, 0);
+ cell2.setData(MinesweeperTileData.empty());
+
+ board.addModifiedData(cell1);
+ board.addModifiedData(cell2);
+
+ Assert.assertNull(RULE.checkRule(transition));
+
+ for (int i = 0; i < board.getHeight(); i++) {
+ for (int k = 0; k < board.getWidth(); k++) {
+ Point point = new Point(k, i);
+ if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) {
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ } else {
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ }
+ }
+ }
+ }
+
+ @Test
+ public void NonTouchingSharedEmptyDirectRule_VerticalTest2() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/minesweeper/rules/4x4test6.txt", minesweeper);
+ TreeNode rootNode = minesweeper.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ MinesweeperBoard board = (MinesweeperBoard) transition.getBoard();
+
+ MinesweeperCell cell1 = board.getCell(1, 3);
+ cell1.setData(MinesweeperTileData.empty());
+ MinesweeperCell cell2 = board.getCell(2, 3);
+ cell2.setData(MinesweeperTileData.empty());
+ MinesweeperCell cell3 = board.getCell(3, 3);
+ cell3.setData(MinesweeperTileData.empty());
+
+ board.addModifiedData(cell1);
+ board.addModifiedData(cell2);
+ board.addModifiedData(cell3);
+
+ Assert.assertNull(RULE.checkRule(transition));
+
+ for (int i = 0; i < board.getHeight(); i++) {
+ for (int k = 0; k < board.getWidth(); k++) {
+ Point point = new Point(k, i);
+ if (point.equals(cell1.getLocation())
+ || point.equals(cell2.getLocation())
+ || point.equals(cell3.getLocation())) {
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ } else {
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ }
+ }
+ }
+ }
+}
diff --git a/src/test/java/puzzles/minesweeper/NonTouchingSharedMineDirectRuleTest.java b/src/test/java/puzzles/minesweeper/NonTouchingSharedMineDirectRuleTest.java
new file mode 100644
index 000000000..e7e0b7d7f
--- /dev/null
+++ b/src/test/java/puzzles/minesweeper/NonTouchingSharedMineDirectRuleTest.java
@@ -0,0 +1,186 @@
+package puzzles.minesweeper;
+
+import edu.rpi.legup.model.tree.TreeNode;
+import edu.rpi.legup.model.tree.TreeTransition;
+import edu.rpi.legup.puzzle.minesweeper.Minesweeper;
+import edu.rpi.legup.puzzle.minesweeper.MinesweeperBoard;
+import edu.rpi.legup.puzzle.minesweeper.MinesweeperCell;
+import edu.rpi.legup.puzzle.minesweeper.MinesweeperTileData;
+import edu.rpi.legup.puzzle.minesweeper.rules.NonTouchingSharedMineDirectRule;
+import edu.rpi.legup.save.InvalidFileFormatException;
+import java.awt.*;
+import legup.MockGameBoardFacade;
+import legup.TestUtilities;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class NonTouchingSharedMineDirectRuleTest {
+
+ public static final NonTouchingSharedMineDirectRule RULE =
+ new NonTouchingSharedMineDirectRule();
+ private static Minesweeper minesweeper;
+
+ @BeforeClass
+ public static void setUp() {
+ MockGameBoardFacade.getInstance();
+ minesweeper = new Minesweeper();
+ }
+
+ // Horizontal/vertical tests means the adjacent number cells are adjacent
+ // horizontally/vertically
+
+ @Test
+ public void NonTouchingSharedMineDirectRule_HorizontalTest1()
+ throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/minesweeper/rules/3x3test13.txt", minesweeper);
+ TreeNode rootNode = minesweeper.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ MinesweeperBoard board = (MinesweeperBoard) transition.getBoard();
+
+ MinesweeperCell cell1 = board.getCell(2, 1);
+ cell1.setData(MinesweeperTileData.mine());
+
+ board.addModifiedData(cell1);
+
+ Assert.assertNull(RULE.checkRule(transition));
+
+ for (int i = 0; i < board.getHeight(); i++) {
+ for (int k = 0; k < board.getWidth(); k++) {
+ Point point = new Point(k, i);
+ if (point.equals(cell1.getLocation())) {
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ } else {
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ }
+ }
+ }
+ }
+
+ @Test
+ public void NonTouchingSharedMineDirectRule_HorizontalTest2()
+ throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/minesweeper/rules/4x4test1.txt", minesweeper);
+ TreeNode rootNode = minesweeper.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ MinesweeperBoard board = (MinesweeperBoard) transition.getBoard();
+
+ MinesweeperCell cell1 = board.getCell(3, 1);
+ cell1.setData(MinesweeperTileData.mine());
+
+ board.addModifiedData(cell1);
+
+ Assert.assertNull(RULE.checkRule(transition));
+
+ for (int i = 0; i < board.getHeight(); i++) {
+ for (int k = 0; k < board.getWidth(); k++) {
+ Point point = new Point(k, i);
+ if (point.equals(cell1.getLocation())) {
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ } else {
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ }
+ }
+ }
+ }
+
+ @Test
+ public void NonTouchingSharedMineDirectRule_HorizontalTest3()
+ throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/minesweeper/rules/4x4test2.txt", minesweeper);
+ TreeNode rootNode = minesweeper.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ MinesweeperBoard board = (MinesweeperBoard) transition.getBoard();
+
+ MinesweeperCell cell1 = board.getCell(0, 0);
+ cell1.setData(MinesweeperTileData.mine());
+ MinesweeperCell cell2 = board.getCell(0, 2);
+ cell2.setData(MinesweeperTileData.mine());
+
+ board.addModifiedData(cell1);
+ board.addModifiedData(cell2);
+
+ Assert.assertNull(RULE.checkRule(transition));
+
+ for (int i = 0; i < board.getHeight(); i++) {
+ for (int k = 0; k < board.getWidth(); k++) {
+ Point point = new Point(k, i);
+ if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) {
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ } else {
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ }
+ }
+ }
+ }
+
+ @Test
+ public void NonTouchingSharedMineDirectRule_VerticalTest1() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/minesweeper/rules/3x3test14.txt", minesweeper);
+ TreeNode rootNode = minesweeper.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ MinesweeperBoard board = (MinesweeperBoard) transition.getBoard();
+
+ MinesweeperCell cell1 = board.getCell(1, 0);
+ cell1.setData(MinesweeperTileData.mine());
+
+ board.addModifiedData(cell1);
+
+ Assert.assertNull(RULE.checkRule(transition));
+
+ for (int i = 0; i < board.getHeight(); i++) {
+ for (int k = 0; k < board.getWidth(); k++) {
+ Point point = new Point(k, i);
+ if (point.equals(cell1.getLocation())) {
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ } else {
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ }
+ }
+ }
+ }
+
+ @Test
+ public void NonTouchingSharedMineDirectRule_VerticalTest2() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/minesweeper/rules/4x4test3.txt", minesweeper);
+ TreeNode rootNode = minesweeper.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ MinesweeperBoard board = (MinesweeperBoard) transition.getBoard();
+
+ MinesweeperCell cell1 = board.getCell(1, 3);
+ cell1.setData(MinesweeperTileData.mine());
+ MinesweeperCell cell2 = board.getCell(2, 3);
+ cell2.setData(MinesweeperTileData.mine());
+ MinesweeperCell cell3 = board.getCell(3, 3);
+ cell3.setData(MinesweeperTileData.mine());
+
+ board.addModifiedData(cell1);
+ board.addModifiedData(cell2);
+ board.addModifiedData(cell3);
+
+ Assert.assertNull(RULE.checkRule(transition));
+
+ for (int i = 0; i < board.getHeight(); i++) {
+ for (int k = 0; k < board.getWidth(); k++) {
+ Point point = new Point(k, i);
+ if (point.equals(cell1.getLocation())
+ || point.equals(cell2.getLocation())
+ || point.equals(cell3.getLocation())) {
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ } else {
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ }
+ }
+ }
+ }
+}
diff --git a/src/test/java/puzzles/minesweeper/SatisfyNumberCaseRuleTest.java b/src/test/java/puzzles/minesweeper/SatisfyNumberCaseRuleTest.java
new file mode 100644
index 000000000..a5c65ef0f
--- /dev/null
+++ b/src/test/java/puzzles/minesweeper/SatisfyNumberCaseRuleTest.java
@@ -0,0 +1,115 @@
+package puzzles.minesweeper;
+
+import edu.rpi.legup.model.gameboard.Board;
+import edu.rpi.legup.model.tree.TreeNode;
+import edu.rpi.legup.model.tree.TreeTransition;
+import edu.rpi.legup.puzzle.minesweeper.Minesweeper;
+import edu.rpi.legup.puzzle.minesweeper.MinesweeperBoard;
+import edu.rpi.legup.puzzle.minesweeper.MinesweeperCell;
+import edu.rpi.legup.puzzle.minesweeper.MinesweeperTileData;
+import edu.rpi.legup.puzzle.minesweeper.rules.SatisfyNumberCaseRule;
+import edu.rpi.legup.save.InvalidFileFormatException;
+import java.awt.*;
+import java.util.ArrayList;
+import legup.MockGameBoardFacade;
+import legup.TestUtilities;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class SatisfyNumberCaseRuleTest {
+
+ private static final SatisfyNumberCaseRule RULE = new SatisfyNumberCaseRule();
+ private static Minesweeper minesweeper;
+
+ @BeforeClass
+ public static void setUp() {
+ MockGameBoardFacade.getInstance();
+ minesweeper = new Minesweeper();
+ }
+
+ /**
+ * Tests the Satisfy Number case rule by ensuring that it results in all possibilities for the
+ * number. This case tests a number 2 with three unset cells around it, so each case must
+ * replace the unset tiles with a different arrangement of two bombs and one empty.
+ */
+ @Test
+ public void SatisfyNumberCaseRuleTest1() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/minesweeper/rules/SatisfyNumber.txt", minesweeper);
+ TreeNode rootNode = minesweeper.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ MinesweeperBoard board = (MinesweeperBoard) transition.getBoard();
+ MinesweeperCell cell = board.getCell(1, 1);
+ ArrayList cases = RULE.getCases(board, cell);
+
+ Assert.assertEquals(3, cases.size());
+
+ MinesweeperBoard caseBoard = (MinesweeperBoard) cases.get(0);
+ MinesweeperBoard caseBoard2 = (MinesweeperBoard) cases.get(1);
+ MinesweeperBoard caseBoard3 = (MinesweeperBoard) cases.get(2);
+
+ MinesweeperTileData board1Tile1 = caseBoard.getCell(0, 1).getData();
+ MinesweeperTileData board1Tile2 = caseBoard.getCell(2, 1).getData();
+ MinesweeperTileData board1Tile3 = caseBoard.getCell(1, 2).getData();
+ MinesweeperTileData board2Tile1 = caseBoard2.getCell(0, 1).getData();
+ MinesweeperTileData board2Tile2 = caseBoard2.getCell(2, 1).getData();
+ MinesweeperTileData board2Tile3 = caseBoard2.getCell(1, 2).getData();
+ MinesweeperTileData board3Tile1 = caseBoard3.getCell(0, 1).getData();
+ MinesweeperTileData board3Tile2 = caseBoard3.getCell(2, 1).getData();
+ MinesweeperTileData board3Tile3 = caseBoard3.getCell(1, 2).getData();
+
+ Assert.assertTrue(
+ (board1Tile1.equals(MinesweeperTileData.mine())
+ && board1Tile2.equals(MinesweeperTileData.mine())
+ && board1Tile3.equals(MinesweeperTileData.empty()))
+ || (board1Tile1.equals(MinesweeperTileData.mine())
+ && board1Tile2.equals(MinesweeperTileData.empty())
+ && board1Tile3.equals(MinesweeperTileData.mine()))
+ || ((board1Tile1.equals(MinesweeperTileData.empty())
+ && board1Tile2.equals(MinesweeperTileData.mine())
+ && board1Tile3.equals(MinesweeperTileData.mine()))));
+
+ Assert.assertTrue(
+ (board2Tile1.equals(MinesweeperTileData.mine())
+ && board2Tile2.equals(MinesweeperTileData.mine())
+ && board2Tile3.equals(MinesweeperTileData.empty()))
+ || (board2Tile1.equals(MinesweeperTileData.mine())
+ && board2Tile2.equals(MinesweeperTileData.empty())
+ && board2Tile3.equals(MinesweeperTileData.mine()))
+ || ((board2Tile1.equals(MinesweeperTileData.empty())
+ && board2Tile2.equals(MinesweeperTileData.mine())
+ && board2Tile3.equals(MinesweeperTileData.mine()))));
+
+ Assert.assertTrue(
+ (board3Tile1.equals(MinesweeperTileData.mine())
+ && board3Tile2.equals(MinesweeperTileData.mine())
+ && board3Tile3.equals(MinesweeperTileData.empty()))
+ || (board3Tile1.equals(MinesweeperTileData.mine())
+ && board3Tile2.equals(MinesweeperTileData.empty())
+ && board3Tile3.equals(MinesweeperTileData.mine()))
+ || ((board3Tile1.equals(MinesweeperTileData.empty())
+ && board3Tile2.equals(MinesweeperTileData.mine())
+ && board3Tile3.equals(MinesweeperTileData.mine()))));
+
+ Assert.assertFalse(board1Tile1.equals(board2Tile1) && board1Tile1.equals(board3Tile1));
+ Assert.assertFalse(board1Tile2.equals(board2Tile2) && board1Tile2.equals(board3Tile2));
+ Assert.assertFalse(board1Tile3.equals(board2Tile3) && board1Tile3.equals(board3Tile3));
+
+ Assert.assertEquals(caseBoard.getHeight(), caseBoard2.getHeight(), caseBoard3.getHeight());
+ Assert.assertEquals(caseBoard.getHeight(), board.getHeight());
+ Assert.assertEquals(caseBoard.getWidth(), caseBoard2.getWidth(), caseBoard3.getWidth());
+ Assert.assertEquals(caseBoard.getWidth(), board.getWidth());
+
+ for (int i = 0; i < caseBoard.getHeight(); i++) {
+ for (int k = 0; k < caseBoard.getWidth(); k++) {
+ Point point = new Point(k, i);
+ if (point.equals(caseBoard.getCell(k, i).getLocation())) {
+ continue;
+ }
+ Assert.assertTrue(caseBoard.getCell(k, i).equals(caseBoard2.getCell(k, i)));
+ }
+ }
+ }
+}
diff --git a/src/test/java/puzzles/minesweeper/TooFewMinesContradictionRuleTest.java b/src/test/java/puzzles/minesweeper/TooFewMinesContradictionRuleTest.java
new file mode 100644
index 000000000..00234207a
--- /dev/null
+++ b/src/test/java/puzzles/minesweeper/TooFewMinesContradictionRuleTest.java
@@ -0,0 +1,70 @@
+package puzzles.minesweeper;
+
+import edu.rpi.legup.model.tree.TreeNode;
+import edu.rpi.legup.model.tree.TreeTransition;
+import edu.rpi.legup.puzzle.minesweeper.Minesweeper;
+import edu.rpi.legup.puzzle.minesweeper.MinesweeperBoard;
+import edu.rpi.legup.puzzle.minesweeper.rules.TooFewMinesContradictionRule;
+import edu.rpi.legup.save.InvalidFileFormatException;
+import legup.TestUtilities;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class TooFewMinesContradictionRuleTest {
+ private static final TooFewMinesContradictionRule RULE = new TooFewMinesContradictionRule();
+ private static Minesweeper minesweeper;
+
+ @BeforeClass
+ public static void setUp() {
+ minesweeper = new Minesweeper();
+ }
+
+ @Test
+ // tests a 3x3 board with a 3 in the center surrounded by 2 mines and 6 empty
+ public void TooManyMinesTest1() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/minesweeper/rules/TooFewMines1.txt", minesweeper);
+ TreeNode rootNode = minesweeper.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ MinesweeperBoard board = (MinesweeperBoard) transition.getBoard();
+
+ // confirm it is impossible to satisfy up the center square
+ Assert.assertNull(RULE.checkContradictionAt(board, board.getCell(1, 1)));
+
+ // every square except the center
+ Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(0, 0)));
+ Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(1, 0)));
+ Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(2, 0)));
+ Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(0, 1)));
+ Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(2, 1)));
+ Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(0, 2)));
+ Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(1, 2)));
+ Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(2, 1)));
+ }
+
+ @Test
+ // tests a 3x3 board with a 3 in the center surrounded by 2 unset and 6 empty
+ public void TooManyMinesTest2() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/minesweeper/rules/TooFewMines2.txt", minesweeper);
+ TreeNode rootNode = minesweeper.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ MinesweeperBoard board = (MinesweeperBoard) transition.getBoard();
+
+ // confirm it is impossible to satisfy up the center square
+ Assert.assertNull(RULE.checkContradictionAt(board, board.getCell(1, 1)));
+
+ // every square except the center
+ Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(0, 0)));
+ Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(1, 0)));
+ Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(2, 0)));
+ Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(0, 1)));
+ Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(2, 1)));
+ Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(0, 2)));
+ Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(1, 2)));
+ Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(2, 1)));
+ }
+}
diff --git a/src/test/java/puzzles/minesweeper/TooManyMinesContradictionRuleTest.java b/src/test/java/puzzles/minesweeper/TooManyMinesContradictionRuleTest.java
new file mode 100644
index 000000000..c328dae43
--- /dev/null
+++ b/src/test/java/puzzles/minesweeper/TooManyMinesContradictionRuleTest.java
@@ -0,0 +1,46 @@
+package puzzles.minesweeper;
+
+import edu.rpi.legup.model.tree.TreeNode;
+import edu.rpi.legup.model.tree.TreeTransition;
+import edu.rpi.legup.puzzle.minesweeper.Minesweeper;
+import edu.rpi.legup.puzzle.minesweeper.MinesweeperBoard;
+import edu.rpi.legup.puzzle.minesweeper.rules.TooManyMinesContradictionRule;
+import edu.rpi.legup.save.InvalidFileFormatException;
+import legup.TestUtilities;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class TooManyMinesContradictionRuleTest {
+ private static final TooManyMinesContradictionRule RULE = new TooManyMinesContradictionRule();
+ private static Minesweeper minesweeper;
+
+ @BeforeClass
+ public static void setUp() {
+ minesweeper = new Minesweeper();
+ }
+
+ @Test
+ // tests a 3x3 board with a 3 in the center and 4 surrounding mines
+ public void TooManyMinesTest1() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/minesweeper/rules/TooManyMines.txt", minesweeper);
+ TreeNode rootNode = minesweeper.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ MinesweeperBoard board = (MinesweeperBoard) transition.getBoard();
+
+ // confirm it is impossible to satisfy up the center square
+ Assert.assertNull(RULE.checkContradictionAt(board, board.getCell(1, 1)));
+
+ // every square except the center
+ Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(0, 0)));
+ Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(1, 0)));
+ Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(2, 0)));
+ Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(0, 1)));
+ Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(2, 1)));
+ Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(0, 2)));
+ Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(1, 2)));
+ Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(2, 2)));
+ }
+}
diff --git a/src/test/resources/puzzles/minesweeper/rules/3x3test b/src/test/resources/puzzles/minesweeper/rules/3x3test
new file mode 100644
index 000000000..2bf4f5c3b
--- /dev/null
+++ b/src/test/resources/puzzles/minesweeper/rules/3x3test
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/minesweeper/rules/3x3test10.txt b/src/test/resources/puzzles/minesweeper/rules/3x3test10.txt
new file mode 100644
index 000000000..dcfae59b0
--- /dev/null
+++ b/src/test/resources/puzzles/minesweeper/rules/3x3test10.txt
@@ -0,0 +1,19 @@
+
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/minesweeper/rules/3x3test11.txt b/src/test/resources/puzzles/minesweeper/rules/3x3test11.txt
new file mode 100644
index 000000000..c9ac90ef7
--- /dev/null
+++ b/src/test/resources/puzzles/minesweeper/rules/3x3test11.txt
@@ -0,0 +1,19 @@
+
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/minesweeper/rules/3x3test12.txt b/src/test/resources/puzzles/minesweeper/rules/3x3test12.txt
new file mode 100644
index 000000000..946ed7502
--- /dev/null
+++ b/src/test/resources/puzzles/minesweeper/rules/3x3test12.txt
@@ -0,0 +1,19 @@
+
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/minesweeper/rules/3x3test13.txt b/src/test/resources/puzzles/minesweeper/rules/3x3test13.txt
new file mode 100644
index 000000000..0f3761e47
--- /dev/null
+++ b/src/test/resources/puzzles/minesweeper/rules/3x3test13.txt
@@ -0,0 +1,19 @@
+
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/minesweeper/rules/3x3test14.txt b/src/test/resources/puzzles/minesweeper/rules/3x3test14.txt
new file mode 100644
index 000000000..1f38acd3d
--- /dev/null
+++ b/src/test/resources/puzzles/minesweeper/rules/3x3test14.txt
@@ -0,0 +1,19 @@
+
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/minesweeper/rules/3x3test15.txt b/src/test/resources/puzzles/minesweeper/rules/3x3test15.txt
new file mode 100644
index 000000000..29fd5d0ea
--- /dev/null
+++ b/src/test/resources/puzzles/minesweeper/rules/3x3test15.txt
@@ -0,0 +1,19 @@
+
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/minesweeper/rules/3x3test2.txt b/src/test/resources/puzzles/minesweeper/rules/3x3test2.txt
new file mode 100644
index 000000000..86640ebfa
--- /dev/null
+++ b/src/test/resources/puzzles/minesweeper/rules/3x3test2.txt
@@ -0,0 +1,19 @@
+
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/minesweeper/rules/3x3test3.txt b/src/test/resources/puzzles/minesweeper/rules/3x3test3.txt
new file mode 100644
index 000000000..cbe32bc31
--- /dev/null
+++ b/src/test/resources/puzzles/minesweeper/rules/3x3test3.txt
@@ -0,0 +1,19 @@
+
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/minesweeper/rules/3x3test4.txt b/src/test/resources/puzzles/minesweeper/rules/3x3test4.txt
new file mode 100644
index 000000000..12bbd62c9
--- /dev/null
+++ b/src/test/resources/puzzles/minesweeper/rules/3x3test4.txt
@@ -0,0 +1,19 @@
+
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/minesweeper/rules/3x3test5.txt b/src/test/resources/puzzles/minesweeper/rules/3x3test5.txt
new file mode 100644
index 000000000..0cfa02d64
--- /dev/null
+++ b/src/test/resources/puzzles/minesweeper/rules/3x3test5.txt
@@ -0,0 +1,19 @@
+
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/minesweeper/rules/3x3test6.txt b/src/test/resources/puzzles/minesweeper/rules/3x3test6.txt
new file mode 100644
index 000000000..8f3975aa1
--- /dev/null
+++ b/src/test/resources/puzzles/minesweeper/rules/3x3test6.txt
@@ -0,0 +1,19 @@
+
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/minesweeper/rules/3x3test7.txt b/src/test/resources/puzzles/minesweeper/rules/3x3test7.txt
new file mode 100644
index 000000000..a0c611136
--- /dev/null
+++ b/src/test/resources/puzzles/minesweeper/rules/3x3test7.txt
@@ -0,0 +1,19 @@
+
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/minesweeper/rules/3x3test8.txt b/src/test/resources/puzzles/minesweeper/rules/3x3test8.txt
new file mode 100644
index 000000000..c420ddad2
--- /dev/null
+++ b/src/test/resources/puzzles/minesweeper/rules/3x3test8.txt
@@ -0,0 +1,19 @@
+
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/minesweeper/rules/3x3test9.txt b/src/test/resources/puzzles/minesweeper/rules/3x3test9.txt
new file mode 100644
index 000000000..a6f029af0
--- /dev/null
+++ b/src/test/resources/puzzles/minesweeper/rules/3x3test9.txt
@@ -0,0 +1,19 @@
+
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/minesweeper/rules/4x4test1.txt b/src/test/resources/puzzles/minesweeper/rules/4x4test1.txt
new file mode 100644
index 000000000..3138dde84
--- /dev/null
+++ b/src/test/resources/puzzles/minesweeper/rules/4x4test1.txt
@@ -0,0 +1,22 @@
+
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/minesweeper/rules/4x4test2.txt b/src/test/resources/puzzles/minesweeper/rules/4x4test2.txt
new file mode 100644
index 000000000..56aabc927
--- /dev/null
+++ b/src/test/resources/puzzles/minesweeper/rules/4x4test2.txt
@@ -0,0 +1,22 @@
+
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/minesweeper/rules/4x4test3.txt b/src/test/resources/puzzles/minesweeper/rules/4x4test3.txt
new file mode 100644
index 000000000..90a7384c9
--- /dev/null
+++ b/src/test/resources/puzzles/minesweeper/rules/4x4test3.txt
@@ -0,0 +1,26 @@
+
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/minesweeper/rules/4x4test4.txt b/src/test/resources/puzzles/minesweeper/rules/4x4test4.txt
new file mode 100644
index 000000000..caa8a1e41
--- /dev/null
+++ b/src/test/resources/puzzles/minesweeper/rules/4x4test4.txt
@@ -0,0 +1,26 @@
+
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/minesweeper/rules/4x4test5.txt b/src/test/resources/puzzles/minesweeper/rules/4x4test5.txt
new file mode 100644
index 000000000..34b0816f9
--- /dev/null
+++ b/src/test/resources/puzzles/minesweeper/rules/4x4test5.txt
@@ -0,0 +1,26 @@
+
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/minesweeper/rules/4x4test6.txt b/src/test/resources/puzzles/minesweeper/rules/4x4test6.txt
new file mode 100644
index 000000000..0c5fdb320
--- /dev/null
+++ b/src/test/resources/puzzles/minesweeper/rules/4x4test6.txt
@@ -0,0 +1,26 @@
+
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/minesweeper/rules/IsolateMine1.txt b/src/test/resources/puzzles/minesweeper/rules/IsolateMine1.txt
new file mode 100644
index 000000000..997cf24c1
--- /dev/null
+++ b/src/test/resources/puzzles/minesweeper/rules/IsolateMine1.txt
@@ -0,0 +1,19 @@
+
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/minesweeper/rules/IsolateMine2.txt b/src/test/resources/puzzles/minesweeper/rules/IsolateMine2.txt
new file mode 100644
index 000000000..bd87398ee
--- /dev/null
+++ b/src/test/resources/puzzles/minesweeper/rules/IsolateMine2.txt
@@ -0,0 +1,19 @@
+
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/minesweeper/rules/IsolateMine3.txt b/src/test/resources/puzzles/minesweeper/rules/IsolateMine3.txt
new file mode 100644
index 000000000..9aea60eed
--- /dev/null
+++ b/src/test/resources/puzzles/minesweeper/rules/IsolateMine3.txt
@@ -0,0 +1,19 @@
+
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/minesweeper/rules/MineOrEmpty.txt b/src/test/resources/puzzles/minesweeper/rules/MineOrEmpty.txt
new file mode 100644
index 000000000..6e2b88422
--- /dev/null
+++ b/src/test/resources/puzzles/minesweeper/rules/MineOrEmpty.txt
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/minesweeper/rules/SatisfyNumber.txt b/src/test/resources/puzzles/minesweeper/rules/SatisfyNumber.txt
new file mode 100644
index 000000000..85795ddc2
--- /dev/null
+++ b/src/test/resources/puzzles/minesweeper/rules/SatisfyNumber.txt
@@ -0,0 +1,19 @@
+
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/minesweeper/rules/TooFewMines1.txt b/src/test/resources/puzzles/minesweeper/rules/TooFewMines1.txt
new file mode 100644
index 000000000..a817ad6bb
--- /dev/null
+++ b/src/test/resources/puzzles/minesweeper/rules/TooFewMines1.txt
@@ -0,0 +1,19 @@
+
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/minesweeper/rules/TooFewMines2.txt b/src/test/resources/puzzles/minesweeper/rules/TooFewMines2.txt
new file mode 100644
index 000000000..b1bade015
--- /dev/null
+++ b/src/test/resources/puzzles/minesweeper/rules/TooFewMines2.txt
@@ -0,0 +1,19 @@
+
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/minesweeper/rules/TooManyMines.txt b/src/test/resources/puzzles/minesweeper/rules/TooManyMines.txt
new file mode 100644
index 000000000..bba206653
--- /dev/null
+++ b/src/test/resources/puzzles/minesweeper/rules/TooManyMines.txt
@@ -0,0 +1,19 @@
+
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
+
\ No newline at end of file