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