From 5f1b13ed24aa2097361b9daa04e0bf4707f9d82f Mon Sep 17 00:00:00 2001 From: vockek Date: Fri, 16 Feb 2024 16:08:59 -0500 Subject: [PATCH 01/21] Revert "Create 123456" This reverts commit ace712290986aead21470839844001c3eb9a582d. --- puzzles files/minesweeper/5x5 Minesweeper Easy/123456 | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 puzzles files/minesweeper/5x5 Minesweeper Easy/123456 diff --git a/puzzles files/minesweeper/5x5 Minesweeper Easy/123456 b/puzzles files/minesweeper/5x5 Minesweeper Easy/123456 deleted file mode 100644 index 2aa0b46ab..000000000 --- a/puzzles files/minesweeper/5x5 Minesweeper Easy/123456 +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file From eb5c8a0501f4c8df7dfda6d5ac1b14762a7a0456 Mon Sep 17 00:00:00 2001 From: vockek Date: Fri, 16 Feb 2024 16:40:42 -0500 Subject: [PATCH 02/21] Created Bomb or Filled Case Rule --- .../puzzle/minesweeper/MinesweeperCell.java | 5 ++ .../rules/BombOrFilledCaseRule.java | 88 ++++++++++++++++++- .../LessBombsThanFlagContradictionRule.java | 1 - 3 files changed, 92 insertions(+), 2 deletions(-) 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 faf787111..bbc1542aa 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperCell.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperCell.java @@ -2,6 +2,7 @@ import edu.rpi.legup.model.elements.Element; import edu.rpi.legup.model.gameboard.GridCell; +import edu.rpi.legup.puzzle.fillapix.FillapixCellType; import org.jetbrains.annotations.NotNull; import java.awt.*; @@ -17,6 +18,10 @@ public MinesweeperCell(@NotNull MinesweeperTileData value, @NotNull Point locati return super.data.type(); } + public void setCellType(MinesweeperTileData type) { + data = type; + } + @Override public void setType(@NotNull Element element, @NotNull MouseEvent event) { switch (element.getElementID()) { diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/BombOrFilledCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/BombOrFilledCaseRule.java index 65faef5bd..b4d4edbcc 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/BombOrFilledCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/BombOrFilledCaseRule.java @@ -1,4 +1,90 @@ package edu.rpi.legup.puzzle.minesweeper.rules; -public class BombOrFilledCaseRule { +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.CaseBoard; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.CaseRule; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.fillapix.FillapixCell; +import edu.rpi.legup.puzzle.fillapix.FillapixCellType; +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.MinesweeperTileType; + +import java.util.ArrayList; +import java.util.List; +public class BombOrFilledCaseRule extends CaseRule{ + public BombOrFilledCaseRule() { + super("MINE-CASE-0001", + "Bomb or Filled", + "Each cell is either bomb or filled.", + "edu/rpi/legup/images/fillapix/cases/BlackOrWhite.png"); + } + + @Override + public CaseBoard getCaseBoard(Board board) { + MinesweeperBoard minesweeperBoard = (MinesweeperBoard) board.copy(); + CaseBoard caseBoard = new CaseBoard(minesweeperBoard, this); + minesweeperBoard.setModifiable(false); + for (PuzzleElement data : minesweeperBoard.getPuzzleElements()) { + MinesweeperCell cell = (MinesweeperCell) data; + if (cell.getTileType() == MinesweeperTileType.UNSET) { + caseBoard.addPickableElement(data); + } + } + return caseBoard; + } + + @Override + public ArrayList getCases(Board board, PuzzleElement puzzleElement) { + ArrayList cases = new ArrayList<>(); + + Board case1 = board.copy(); + MinesweeperCell cell1 = (MinesweeperCell) case1.getPuzzleElement(puzzleElement); + cell1.setCellType(MinesweeperTileData.bomb()); + case1.addModifiedData(cell1); + cases.add(case1); + + Board case2 = board.copy(); + MinesweeperCell cell2 = (MinesweeperCell) case2.getPuzzleElement(puzzleElement); + cell2.setCellType(MinesweeperTileData.bomb()); + case2.addModifiedData(cell2); + cases.add(case2); + + return cases; + } + + @Override + public String checkRuleRaw(TreeTransition transition) { + List childTransitions = transition.getParents().get(0).getChildren(); + if (childTransitions.size() != 2) { + return super.getInvalidUseOfRuleMessage() + ": This case rule must have 2 children."; + } + + TreeTransition case1 = childTransitions.get(0); + TreeTransition case2 = childTransitions.get(1); + if (case1.getBoard().getModifiedData().size() != 1 || + case2.getBoard().getModifiedData().size() != 1) { + return super.getInvalidUseOfRuleMessage() + ": This case rule must have 1 modified cell for each case."; + } + + MinesweeperCell mod1 = (MinesweeperCell) case1.getBoard().getModifiedData().iterator().next(); + MinesweeperCell mod2 = (MinesweeperCell) case2.getBoard().getModifiedData().iterator().next(); + if (!mod1.getLocation().equals(mod2.getLocation())) { + return super.getInvalidUseOfRuleMessage() + ": This case rule must modify the same cell for each case."; + } + + if (!((mod1.getTileType() == MinesweeperTileType.BOMB && mod2.getTileType() == MinesweeperTileType.EMPTY) + || (mod2.getTileType() == MinesweeperTileType.BOMB && mod1.getTileType() == MinesweeperTileType.EMPTY))) { + return super.getInvalidUseOfRuleMessage() + ": This case rule must an empty cell and a lit cell."; + } + + return null; + } + + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + return null; + } } diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/LessBombsThanFlagContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/LessBombsThanFlagContradictionRule.java index e76129d04..302d767a5 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/LessBombsThanFlagContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/LessBombsThanFlagContradictionRule.java @@ -27,6 +27,5 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { } - } } From f521daad54ded0e70dbe346fb328be7fe731a499 Mon Sep 17 00:00:00 2001 From: vockek Date: Fri, 16 Feb 2024 16:44:50 -0500 Subject: [PATCH 03/21] Update BombOrFilledCaseRule.java removed fillapix imports --- .../legup/puzzle/minesweeper/rules/BombOrFilledCaseRule.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/BombOrFilledCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/BombOrFilledCaseRule.java index b4d4edbcc..94cbdcaa8 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/BombOrFilledCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/BombOrFilledCaseRule.java @@ -5,8 +5,6 @@ import edu.rpi.legup.model.gameboard.PuzzleElement; import edu.rpi.legup.model.rules.CaseRule; import edu.rpi.legup.model.tree.TreeTransition; -import edu.rpi.legup.puzzle.fillapix.FillapixCell; -import edu.rpi.legup.puzzle.fillapix.FillapixCellType; import edu.rpi.legup.puzzle.minesweeper.MinesweeperBoard; import edu.rpi.legup.puzzle.minesweeper.MinesweeperCell; import edu.rpi.legup.puzzle.minesweeper.MinesweeperTileData; From d662452275d89085b95ac7d2a43f77d790b5b388 Mon Sep 17 00:00:00 2001 From: vockek Date: Fri, 16 Feb 2024 17:28:56 -0500 Subject: [PATCH 04/21] Various additions Added the unset puzzle element, added the minesweeper board copy function, fixed the bomb or filled case rule --- .../puzzle/minesweeper/MinesweeperBoard.java | 21 +++++++++++++++++++ .../puzzle/minesweeper/elements/Unset.java | 9 ++++++++ .../rules/BombOrFilledCaseRule.java | 2 +- 3 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/Unset.java 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 199805b6d..e1e801b43 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,8 @@ package edu.rpi.legup.puzzle.minesweeper; import edu.rpi.legup.model.gameboard.GridBoard; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.puzzle.fillapix.FillapixBoard; public class MinesweeperBoard extends GridBoard { @@ -11,4 +13,23 @@ public MinesweeperBoard(int width, int height) { public MinesweeperBoard(int size) { super(size); } + + /** + * Performs a deep copy of the Board + * + * @return a new copy of the board that is independent of this one + */ + @Override + public MinesweeperBoard copy() { + MinesweeperBoard copy = new MinesweeperBoard(dimension.width, dimension.height); + for (int x = 0; x < this.dimension.width; x++) { + for (int y = 0; y < this.dimension.height; y++) { + copy.setCell(x, y, getCell(x, y).copy()); + } + } + for (PuzzleElement e : modifiedData) { + copy.getPuzzleElement(e).setModifiable(false); + } + return copy; + } } diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/Unset.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/Unset.java new file mode 100644 index 000000000..62f5b824f --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/Unset.java @@ -0,0 +1,9 @@ +package edu.rpi.legup.puzzle.minesweeper.elements; + +import edu.rpi.legup.model.elements.NonPlaceableElement; + +public class Unset extends NonPlaceableElement { + public Unset() { + super("MINE-UNPL-0002", "Unset", "A blank tile", "edu/rpi/legup/images/fillapix/tiles/UnknownTile.png"); + } +} \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/BombOrFilledCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/BombOrFilledCaseRule.java index 94cbdcaa8..ab5b7b32d 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/BombOrFilledCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/BombOrFilledCaseRule.java @@ -46,7 +46,7 @@ public ArrayList getCases(Board board, PuzzleElement puzzleElement) { Board case2 = board.copy(); MinesweeperCell cell2 = (MinesweeperCell) case2.getPuzzleElement(puzzleElement); - cell2.setCellType(MinesweeperTileData.bomb()); + cell2.setCellType(MinesweeperTileData.empty()); case2.addModifiedData(cell2); cases.add(case2); From 99d0ecff88ca0267d58ddd5ca5ac083b927a5fac Mon Sep 17 00:00:00 2001 From: vockek Date: Fri, 16 Feb 2024 17:37:45 -0500 Subject: [PATCH 05/21] Revert "Create 123456" This reverts commit ace712290986aead21470839844001c3eb9a582d. --- puzzles files/minesweeper/5x5 Minesweeper Easy/123456 | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 puzzles files/minesweeper/5x5 Minesweeper Easy/123456 diff --git a/puzzles files/minesweeper/5x5 Minesweeper Easy/123456 b/puzzles files/minesweeper/5x5 Minesweeper Easy/123456 deleted file mode 100644 index 2aa0b46ab..000000000 --- a/puzzles files/minesweeper/5x5 Minesweeper Easy/123456 +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file From 294814f3acd1429ad18abd6033b6f750bb4631e5 Mon Sep 17 00:00:00 2001 From: vockek Date: Fri, 23 Feb 2024 17:03:57 -0500 Subject: [PATCH 06/21] Added helper functions to utilities class Added helper functions used for getting cells adjacent to flag, as well as combinations of possible bomb tiles. --- .../minesweeper/minesweeperUtilities.java | 70 ++++++++++++++++--- 1 file changed, 62 insertions(+), 8 deletions(-) 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 6b4e56728..81a7694ec 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/minesweeperUtilities.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/minesweeperUtilities.java @@ -1,13 +1,67 @@ package edu.rpi.legup.puzzle.minesweeper; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.utility.DisjointSets; - import java.awt.*; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.Set; +import java.util.*; + +public class MinesweeperUtilities { + public static boolean hasEmptyAdjacent(MinesweeperBoard board, MinesweeperCell cell) { + ArrayList adjCells = getAdjacentCells(board, cell); + for (MinesweeperCell adjCell : adjCells) { + if (adjCell.getTileType() == MinesweeperTileType.UNSET) { + return true; + } + } + return false; + } + + public static ArrayList getAdjacentCells(MinesweeperBoard board, MinesweeperCell cell) { + ArrayList adjCells = new ArrayList(); + Point cellLoc = cell.getLocation(); + for (int i=-1; i <= 1; i++) { + for (int j=-1; j <= 1; j++) { + if (cellLoc.getX() + i < 0 || cellLoc.y + j < 0 || cellLoc.x + i >= board.getWidth() || cellLoc.y + j >= board.getHeight()) { + continue; + } + MinesweeperCell adjCell = (MinesweeperCell) board.getCell(cellLoc.x + i, cellLoc.y + j); + if (adjCell == null) { + continue; + } + adjCells.add(adjCell); + } + } + return adjCells; + } + + public static ArrayList getCombinations(int chosenNumItems, int totalNumItems) { + ArrayList combinations = new ArrayList(); + + // calculate all combinations + boolean[] array = new boolean[totalNumItems]; + recurseCombinations(combinations, 0, chosenNumItems, 0, totalNumItems, array); + + return combinations; + } + + private static void recurseCombinations(ArrayList result, int curIndex, int maxBlack, int numBlack, int len, boolean[] workingArray) { + if (curIndex == len) { + // complete, but not valid solution + if (numBlack != maxBlack) { + return; + } + // complete and valid solution + result.add(workingArray.clone()); + return; + } + // there is no chance of completing the required number of solutions, so quit + if (len - curIndex < maxBlack - numBlack) { + return; + } -public class minesweeperUtilities { + if (numBlack < maxBlack) { + workingArray[curIndex] = true; + recurseCombinations(result, curIndex+1, maxBlack, numBlack+1, len, workingArray); + } + workingArray[curIndex] = false; + recurseCombinations(result, curIndex+1, maxBlack, numBlack, len, workingArray); + } } From 6b1f812cbbef0b2a11de26f31ff87bed297bb53a Mon Sep 17 00:00:00 2001 From: vockek Date: Fri, 23 Feb 2024 17:04:42 -0500 Subject: [PATCH 07/21] Added function to retrieve a tile's number --- .../edu/rpi/legup/puzzle/minesweeper/MinesweeperCell.java | 4 ++++ 1 file changed, 4 insertions(+) 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 bbc1542aa..8969d94eb 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperCell.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperCell.java @@ -18,6 +18,10 @@ public MinesweeperCell(@NotNull MinesweeperTileData value, @NotNull Point locati return super.data.type(); } + public @NotNull int getTileNumber() { + return super.data.data(); + } + public void setCellType(MinesweeperTileData type) { data = type; } From 69aaf17b89a0b6b1b30f0cd3d7d2c19e8c3f73ae Mon Sep 17 00:00:00 2001 From: vockek Date: Fri, 23 Feb 2024 17:05:05 -0500 Subject: [PATCH 08/21] Create SatisfyFlagCaseRule.java --- .../rules/SatisfyFlagCaseRule.java | 232 ++++++++++++++++++ 1 file changed, 232 insertions(+) create mode 100644 src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/SatisfyFlagCaseRule.java diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/SatisfyFlagCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/SatisfyFlagCaseRule.java new file mode 100644 index 000000000..da9bc8c28 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/SatisfyFlagCaseRule.java @@ -0,0 +1,232 @@ +package edu.rpi.legup.puzzle.minesweeper.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.CaseBoard; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.CaseRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +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.MinesweeperTileType; +import edu.rpi.legup.puzzle.minesweeper.MinesweeperUtilities; + +import java.awt.*; +import java.util.*; +import java.util.List; + +public class SatisfyFlagCaseRule extends CaseRule{ + public SatisfyFlagCaseRule() { + 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/fillapix/cases/BlackOrWhite.png"); + } + + @Override + public CaseBoard getCaseBoard(Board board) { + MinesweeperBoard minesweeperBoard = (MinesweeperBoard) board.copy(); + CaseBoard caseBoard = new CaseBoard(minesweeperBoard, this); + minesweeperBoard.setModifiable(false); + for (PuzzleElement data : minesweeperBoard.getPuzzleElements()) { + MinesweeperCell cell = (MinesweeperCell) data; + if (cell.getTileNumber() >= 0 && cell.getTileNumber() <= 8 && MinesweeperUtilities.hasEmptyAdjacent(minesweeperBoard, cell)) { + caseBoard.addPickableElement(data); + } + } + return caseBoard; + } + + @Override + public ArrayList getCases(Board board, PuzzleElement puzzleElement) { + ArrayList cases = new ArrayList(); + + // get value of cell + MinesweeperBoard minesweeperBoard = (MinesweeperBoard) board.copy(); + MinesweeperCell cell = (MinesweeperCell) minesweeperBoard.getPuzzleElement(puzzleElement); + int cellMaxBlack = cell.getTileNumber(); + if (cellMaxBlack < 0 || cellMaxBlack > 8) { // cell is not valid cell + return null; + } + + // find number of black & empty squares + int cellNumBomb = 0; + int cellNumEmpty = 0; + ArrayList emptyCells = new ArrayList(); + ArrayList adjCells = MinesweeperUtilities.getAdjacentCells(minesweeperBoard, cell); + for (MinesweeperCell adjCell : adjCells) { + if (adjCell.getTileType() == MinesweeperTileType.BOMB) { + cellNumBomb++; + } + if (adjCell.getTileType() == MinesweeperTileType.EMPTY) { + cellNumEmpty++; + emptyCells.add(adjCell); + } + } + // no cases if no empty or if too many black already + if (cellNumBomb > cellMaxBlack || cellNumEmpty == 0) { + return cases; + } + + // generate all cases as boolean expressions + ArrayList combinations; + combinations = MinesweeperUtilities.getCombinations(cellMaxBlack - cellNumBomb, cellNumEmpty); + + 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(emptyCells.get(j)); + if (combinations.get(i)[j]) { + cell.setCellType(MinesweeperTileData.bomb()); + } + else { + cell.setCellType(MinesweeperTileData.empty()); + } + case_.addModifiedData(cell); + } + cases.add(case_); + } + + return cases; + } + + @Override + public String checkRuleRaw(TreeTransition transition) { + TreeNode parent = transition.getParents().get(0); + List childTransitions = parent.getChildren(); + + /* + * In order for the transition to be valid, it can only be applied to + * one cell, thus: + * * there must be modified cells + * * all modified cells must share at least one common adjacent + * cell + * * all modified cells must fit within a 3X3 square + * * the center of one of the possible squaress must be a cell + * with a number + * * that cells possible combinations must match the transitions + * If all the above is verified, then the transition is valid + */ + + + /* ensure there are modified cells */ + Set modCells = transition.getBoard().getModifiedData(); + if (modCells.size() <= 0) { + return super.getInvalidUseOfRuleMessage(); + } + + + /* ensure modified cells occur within a 3X3 square */ + int minVertLoc = Integer.MAX_VALUE, maxVertLoc = Integer.MIN_VALUE; + int minHorzLoc = Integer.MAX_VALUE, maxHorzLoc = Integer.MIN_VALUE; + for (PuzzleElement modCell : modCells) { + Point loc = ((MinesweeperCell) modCell).getLocation(); + if (loc.x < minHorzLoc) { + minHorzLoc = loc.x; + } + if (loc.x > maxHorzLoc) { + maxHorzLoc = loc.x; + } + if (loc.y < minVertLoc) { + minVertLoc = loc.y; + } + if (loc.y > maxVertLoc) { + maxVertLoc = loc.y; + } + } + if (maxVertLoc - minVertLoc > 3 || maxHorzLoc - minHorzLoc > 3) { + return super.getInvalidUseOfRuleMessage(); + } + + + /* get the center of all possible 3X3 squares, + * and collect all that have numbers */ + MinesweeperBoard board = (MinesweeperBoard) transition.getParents().get(0).getBoard(); + Set possibleCenters = new TreeSet(); + possibleCenters.addAll(MinesweeperUtilities.getAdjacentCells(board, (MinesweeperCell) modCells.iterator().next())); + for (PuzzleElement modCell : modCells) { + possibleCenters.retainAll((MinesweeperUtilities.getAdjacentCells(board, (MinesweeperCell) modCell))); + } + // removing all elements without a valid number + possibleCenters.removeIf(x -> x.getTileNumber() < 0 || x.getTileNumber() >= 9); + if (possibleCenters.isEmpty()) { + return super.getInvalidUseOfRuleMessage(); + } + + + /* Now go through the remaining centers, and check if their combinations + * match the transitions */ + for (MinesweeperCell possibleCenter : possibleCenters) { + int numBlack = 0; + int numEmpty = 0; + int maxBlack = possibleCenter.getTileNumber(); + for (MinesweeperCell adjCell : MinesweeperUtilities.getAdjacentCells(board, possibleCenter)) { + if (adjCell.getTileType() == MinesweeperTileType.BOMB) { + numBlack++; + } + if (adjCell.getTileType() == MinesweeperTileType.UNSET) { + numEmpty++; + } + } + if (numEmpty <= 0 || numBlack > maxBlack) { + // this cell has no cases (no empty) or is already broken (too many black) + continue; + } + + ArrayList combinations = MinesweeperUtilities.getCombinations(maxBlack - numBlack, numEmpty); + if (combinations.size() != childTransitions.size()) { + // not this center because combinations do not match transitions + continue; + } + boolean quitEarly = false; + for (TreeTransition trans : childTransitions) { + /* convert the transition board into boolean format, so that it + * can be compared to the combinations */ + MinesweeperBoard transBoard = (MinesweeperBoard) trans.getBoard(); + ArrayList transModCells = new ArrayList(); + for (PuzzleElement modCell : modCells) { + transModCells.add((MinesweeperCell) transBoard.getPuzzleElement(modCell)); + } + + boolean[] translatedModCells = new boolean[transModCells.size()]; + for (int i=0; i < transModCells.size(); i++) { + if (transModCells.get(i).getTileType() == MinesweeperTileType.BOMB) { + translatedModCells[i] = true; + } + else { + translatedModCells[i] = false; + } + } + + // try to find the above state in the combinations, remove if found + boolean removed = false; + for (boolean[] combination : combinations) { + if (Arrays.equals(combination, translatedModCells)) { + combinations.remove(combination); + removed = true; + break; + } + } + // if combination not found, no need to check further, just quit + if (!removed) { + quitEarly = true; + break; + } + } + + /* we found a center that is valid */ + if (combinations.isEmpty() && !quitEarly) { + return null; + } + } + + return super.getInvalidUseOfRuleMessage(); + } + + + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + return null; + } +} From e59a94eac6d577987220a61d78d1c4b631245008 Mon Sep 17 00:00:00 2001 From: vockek Date: Fri, 23 Feb 2024 17:10:21 -0500 Subject: [PATCH 09/21] Fixed "bomb or filled" case rule's picture --- .../minesweeper/rules/BombOrFilledCaseRule.java | 2 +- .../images/minesweeper/cases/BombOrFilled.jpg | Bin 0 -> 6037 bytes 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 src/main/resources/edu/rpi/legup/images/minesweeper/cases/BombOrFilled.jpg diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/BombOrFilledCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/BombOrFilledCaseRule.java index ab5b7b32d..42d90e02c 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/BombOrFilledCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/BombOrFilledCaseRule.java @@ -17,7 +17,7 @@ public BombOrFilledCaseRule() { super("MINE-CASE-0001", "Bomb or Filled", "Each cell is either bomb or filled.", - "edu/rpi/legup/images/fillapix/cases/BlackOrWhite.png"); + "edu/rpi/legup/images/minesweeper/cases/BombOrFilled.jpg"); } @Override diff --git a/src/main/resources/edu/rpi/legup/images/minesweeper/cases/BombOrFilled.jpg b/src/main/resources/edu/rpi/legup/images/minesweeper/cases/BombOrFilled.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ce7c7418a76349a8a02177ffd42839c2296973e3 GIT binary patch literal 6037 zcmeHLc|25Y-@nETW8e2}6rn6xiewo}hzJoyl8_Lx6`D*4DNEK$G9<|!B~qCzkrrFF zkUje{Bg=kr)T12V`1a{FE{8d;9>-I zpc@Y30(4w3I2R0R1SkMt^faj3Xn$`oI@%f;kc>>sEVK@loPZ7nhtnb8+pDJazDoNJ z5M1=!JCyYpc&wa}JNOfDq*TxPM=&w-3kV7c?~<00-Mweuel_(2 z8V3yy85$WMHZirfIc{rr;-tNctJ^vE^B$f7fkBrp2Zw}4UXO~7xeFmd|Qze{{ zS3fDIypBmy^%#NgtbYeHztq0bUBqo@zajhAfJOYbko^tVAGrDfD;!2s9-IrH0mV9- z?iw?Y1^-t!_@u80wF}D`h!zh{G$1V1KTvNJK9>|M-+SyO(Y-J0+;T^Y5+%VrTcCMJ zqbax*FsPIF-+4E@xnpxLRRBw=(?$LdpGDUjIR=WxoEn@MX0v2^bQnDh%)XrEIeLaz zyFO687d{WyO43Dnw8M1i0WYxp>lue? z`HK}hY7jXZay#RT51xqt$UZoxikGukVWr1IpaWvzV^>~Ii> z2l#VuR7WOiVr~RE9vyGOaaTSSaUe!N$sQccs?ka%p(4@5~WDX06T&Uzq9l(cu%KoB@y{f_kQlFi);NS4sd^t zj8xjN^k+9!2J4BDXvFJX1cADzB;R^r-@b**_ex72`>M=t2CPq2r~Z(N3y~rm+zuBm z{|1>xwy-wR)Y}?lBc9n)N0@jt#k=&p{dFU``y$T=6Y_IbSs4*Zb;n=`PBwrkXQ&#t z=u;aL*~{5hK-Q(;j@($NtS|8^B$+VPH~TY~t=&{YT=UUYGNLO2SG`6dz&Vp8-yvTa zFJSqiJFuuP{fgIs#-XR5g@jm(nGh%|U16I)(a7I3zqlOHc6N*AWj#Py|yq%Q)ZPtu^f2!_`0#DyGkm3 z1*QFk^%=dcs0r>c5~^zrp$9sZgy!gdIEM3T!s1bn2Rwweuj{ioh#a`?ryu#SFaa#B z%It%c{At_4=s&-_2fNyN=#ONL0zBaiQ+ zV{1hnO?&Ov>%08z2UG6Ubegm_i>COlpKz6JZO;~)ip2WhBTs7+QQ?7X0`L4By>ygL zhBcqHyYM2}=+WKM)Z5OtpUM`7oI@$}IX;WB2^Y?>+(90xN)@#z1EFw3YW$mt3O<^vxf71 zgG7S=Zhn(rz}cqHv%O8yEtTZfYl6+6XUScbS&M@}#3{00;+Sm-QL=7m&lk+)5=T$- zqQzJ{6a0}#nY+UK&N^=#7Tjs5#i{@c3`?PY9_At&64ghg;|oa54ZT!8;)9y2iT0hV zEXGx?uXN!if@fei^EvI@ljs(qzAFpF_{J=}YD@ zx#JW8iyo}Expxo?i^KQC(aCg6N8RKF8S5^Xgpw9T?l4Xx)4WN^WBuSTN$<5f1oYQZ zAaIQn0>u4!i79K{nlWUFArT1VTrq*bTShD?LteZ;{~`pgi!@+Y_IjX6Fb)Xt7)B1* zEXt52s3NEziZiI+UUC_RA1_=nLysZ}!xWZ&3o0;xK%>o!*I<>rKBjbC0~bqWA*?vD zX`Pt-gUii--jv`SA_dq4hCrRgrnC-i;M~XHz@=qC4w9=`Nch-@sk6#5+R4g^7^WNoj>7*qJuV zlAV~=%Y=r>%liw6{Yu&U^~}sGy(B-?Dq}7a?$oDMc2>HC6wPf`)SMvs8itn!v9#+U zUA;b(s;F}x6s4J~b*O63+s>jrvyb>=b0_g|j3rUAD9@2(J1gc?hh`r>E_}r^Bkoo} zP=0*_+EukV)v@_It4SX_Q(aknT4++iyyV_*>*%7~v@=D{k{MkOvsBai1x(i*$Vscd z2`h8nk|Vvb7cSKCr`L+Vj^I4?lJP|{{YI=50V$On+S_Lxw}a&n)wZ#x#6fIN+VMwU zXHXR}e%((Qp z_{EZDoO9L1ONwyf?zy;c?~77nnatc07)%7) zDv!8h{O8SkU*(i+DP#6*30${G)UrL>Q!5eNKj2l*t0**|ECm%ELiIcA1r`H&EY4!Kd7i%`kP3lB%8=+O={)trb zMIf3ST$(1>q?M%A8(R?9xD{Gv8>&8^LrX3y2?5l`&om-9>|AWok=|Trsq`}|gmIW6 z)^xNeNf4Om4->`qiK8h@Mdxvulc*(bZT}}fB7Rz~yWH5)hDfat1p2=ELg3MzAa3nX z`K0Mh(+ZvW-&0IIlUoJL5V(b(Sgl;zlF6{6X09@K%6yu_vg)|vglc7GAiz*76dcoZ z@b0j0p8fM8_KW9I$>l~ITSs-c$F&1MFjE>B0 zMQd`FFPDtB$nko0SOr`|c1rp9qE7Pnb@nC$rZuQxL#rr zt%1FXT|Po~p+)LPAV85$j(iwHOd1ONfLiu)LZau*JMb&f!c%Aq2k`>kU;A2HmZy*O zW6c->DIO$0+R$K{)k>E<3=6o6eSLWKLvHI&whPZJqlw3dSSHG83U;lCRZJ-l-&Z`>Ydi3biwt z655SpV}DsBZcTc6c+-F_0GD5qXp`;y(}U89r!viBLbfC!(DIyo00K|7u$w%#9q0qi z5co|3ZU4FiUVi51??)*GS5YnO{@}@?*dH1Lrpgz(N%14va$_;!m2J#kR?jm|mwEO) zo0kk_n4YzOrCxiRr2@2gY}-1y&hCs5@IBJWIR#KSRms%WXiGOY!^6%VZCPn+gAC$?Hr(%(acExU};bKs0 z$V8fx_Z*TXPbpQrGwECXaOuE)X8FCrvQMwn8OA)Z@(;=^ZMA+kysVBg(dPT=1CB>?l1snWgb@2!x;Bi*&qWc@dX&6HEtgS_sP)r2?MttBxINNZtN9)u z9x*02@baGN;9;TKlerpj(Q&B=_|fLH#5#(f;i*1v;+<*{m{S?uIMQ1X?jCVN_- zBUU(7{*iKh@a3CqJRyTjtEuFA_n-+C9eC1$;u&f~8dX*D-R5vJmOJ=}L#HGqv+}%a zm%O5Uk1;VJL0@R6E359E+v@J(T>-+@EqOx2cQ@_UFofEIk;H2_HjG9|KPAS#gRJ`4 zW4&kSY|BI&U$Ni&`>AOcRFcx9L@ypLZY$De{#9HPiHx(9Db(R4srwR#M}6yuSxKhj zYgf91m{zXrdhYcEKb#h4zM-9fV&0b)3^G+q=xJy3}w%Ln>W zH7)K=QX6qUV*cT^u@d&I#YO{_$0@;S#k;?a%71WM1i5$7Mv8QzfZXS Kx1V6p*M9?uqEs0G literal 0 HcmV?d00001 From 7989d80ee4864b44125bd71ec32d8eda3d1f4a7a Mon Sep 17 00:00:00 2001 From: vockek Date: Fri, 23 Feb 2024 17:12:32 -0500 Subject: [PATCH 10/21] Fixed "satisfy flag" case rule's picture --- .../minesweeper/rules/SatisfyFlagCaseRule.java | 2 +- .../images/minesweeper/cases/SatisfyFlag.jpg | Bin 0 -> 21869 bytes 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 src/main/resources/edu/rpi/legup/images/minesweeper/cases/SatisfyFlag.jpg diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/SatisfyFlagCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/SatisfyFlagCaseRule.java index da9bc8c28..9bc16a139 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/SatisfyFlagCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/SatisfyFlagCaseRule.java @@ -21,7 +21,7 @@ public SatisfyFlagCaseRule() { 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/fillapix/cases/BlackOrWhite.png"); + "edu/rpi/legup/images/minesweeper/cases/SatisfyFlag.jpg"); } @Override diff --git a/src/main/resources/edu/rpi/legup/images/minesweeper/cases/SatisfyFlag.jpg b/src/main/resources/edu/rpi/legup/images/minesweeper/cases/SatisfyFlag.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ae575bd8c2f0aae43caeabfe6e15fdbb06e24993 GIT binary patch literal 21869 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 T4m5G=xBr(PMLzNj>fQKXPAN_w literal 0 HcmV?d00001 From b4c8ed9b91fe5ba822df71799c68c017dd42f074 Mon Sep 17 00:00:00 2001 From: vockek Date: Tue, 12 Mar 2024 16:37:24 -0400 Subject: [PATCH 11/21] temp --- .../minesweeper/MinesweeperUtilities.java | 113 ++++++++---------- 1 file changed, 51 insertions(+), 62 deletions(-) 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 26e2704f1..81a7694ec 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperUtilities.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperUtilities.java @@ -1,78 +1,67 @@ package edu.rpi.legup.puzzle.minesweeper; import java.awt.*; -import java.util.Objects; -import java.util.stream.IntStream; -import java.util.stream.Stream; +import java.util.*; -public final class MinesweeperUtilities { - - private static final int SURROUNDING_CELL_MIN_INDEX = 0; - private static final int SURROUNDING_CELL_MAX_INDEX = 9; - - public static Stream getSurroundingCells(MinesweeperBoard board, MinesweeperCell cell) { - final Point loc = cell.getLocation(); - final int height = board.getHeight(); - final int width = board.getWidth(); - final int x = (int) loc.getX(); - final int y = (int) loc.getY(); - // IntStream of 0-9 to represent 2D matrix of surrounding elements, - // this maps from 0,0 to 2,2 so everything needs to be shifted - // left 1 and up 1 to become - // -1,1 to 1,1 - // and 5 is skipped because we want to ignore 1,1 - return IntStream.range(SURROUNDING_CELL_MIN_INDEX, SURROUNDING_CELL_MAX_INDEX) - // skip 0,0 element - .filter(i -> i != (SURROUNDING_CELL_MAX_INDEX - SURROUNDING_CELL_MIN_INDEX) / 2) - .mapToObj(index -> { - final int newX = index / 3 - 1 + x; - final int newY = index % 3 - 1 + y; - // only keep valid locations - if (newX < 0 || newY < 0 || newX >= width || newY >= height) { - return null; - } - return board.getCell(newX, newY); - }) - .filter(Objects::nonNull); +public class MinesweeperUtilities { + public static boolean hasEmptyAdjacent(MinesweeperBoard board, MinesweeperCell cell) { + ArrayList adjCells = getAdjacentCells(board, cell); + for (MinesweeperCell adjCell : adjCells) { + if (adjCell.getTileType() == MinesweeperTileType.UNSET) { + return true; + } + } + return false; } - public static int countSurroundingType(MinesweeperBoard board, MinesweeperCell cell, MinesweeperTileType type) { - final Stream stream = getSurroundingCells(board, cell) - .map(MinesweeperCell::getData); - return (int) (switch (type) { - case UNSET -> stream.filter(MinesweeperTileData::isUnset); - case BOMB -> stream.filter(MinesweeperTileData::isBomb); - case EMPTY -> stream.filter(MinesweeperTileData::isEmpty); - case FLAG -> stream.filter(MinesweeperTileData::isFlag); - }).count(); + public static ArrayList getAdjacentCells(MinesweeperBoard board, MinesweeperCell cell) { + ArrayList adjCells = new ArrayList(); + Point cellLoc = cell.getLocation(); + for (int i=-1; i <= 1; i++) { + for (int j=-1; j <= 1; j++) { + if (cellLoc.getX() + i < 0 || cellLoc.y + j < 0 || cellLoc.x + i >= board.getWidth() || cellLoc.y + j >= board.getHeight()) { + continue; + } + MinesweeperCell adjCell = (MinesweeperCell) board.getCell(cellLoc.x + i, cellLoc.y + j); + if (adjCell == null) { + continue; + } + adjCells.add(adjCell); + } + } + return adjCells; } - public static int countSurroundingBombs(MinesweeperBoard board, MinesweeperCell cell) { - return countSurroundingType(board, cell, MinesweeperTileType.BOMB); - } + public static ArrayList getCombinations(int chosenNumItems, int totalNumItems) { + ArrayList combinations = new ArrayList(); - public static int countSurroundingUnset(MinesweeperBoard board, MinesweeperCell cell) { - return countSurroundingType(board, cell, MinesweeperTileType.UNSET); - } + // calculate all combinations + boolean[] array = new boolean[totalNumItems]; + recurseCombinations(combinations, 0, chosenNumItems, 0, totalNumItems, array); - public static int countSurroundingEmpty(MinesweeperBoard board, MinesweeperCell cell) { - return countSurroundingType(board, cell, MinesweeperTileType.EMPTY); + return combinations; } - public static int countSurroundingFlags(MinesweeperBoard board, MinesweeperCell cell) { - return countSurroundingType(board, cell, MinesweeperTileType.FLAG); - } + private static void recurseCombinations(ArrayList result, int curIndex, int maxBlack, int numBlack, int len, boolean[] workingArray) { + if (curIndex == len) { + // complete, but not valid solution + if (numBlack != maxBlack) { + return; + } + // complete and valid solution + result.add(workingArray.clone()); + return; + } + // there is no chance of completing the required number of solutions, so quit + if (len - curIndex < maxBlack - numBlack) { + return; + } - /** - * - * @return how many bombs 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"); + if (numBlack < maxBlack) { + workingArray[curIndex] = true; + recurseCombinations(result, curIndex+1, maxBlack, numBlack+1, len, workingArray); } - return cell.getData().data() - countSurroundingBombs(board, cell); + workingArray[curIndex] = false; + recurseCombinations(result, curIndex+1, maxBlack, numBlack, len, workingArray); } - } From ee4b707a3fa86fe72a38d3576b873c918cbad16a Mon Sep 17 00:00:00 2001 From: vockek Date: Tue, 12 Mar 2024 17:01:34 -0400 Subject: [PATCH 12/21] Revert "temp" This reverts commit b4c8ed9b91fe5ba822df71799c68c017dd42f074. --- .../minesweeper/MinesweeperUtilities.java | 113 ++++++++++-------- 1 file changed, 62 insertions(+), 51 deletions(-) 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 81a7694ec..26e2704f1 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperUtilities.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperUtilities.java @@ -1,67 +1,78 @@ package edu.rpi.legup.puzzle.minesweeper; import java.awt.*; -import java.util.*; +import java.util.Objects; +import java.util.stream.IntStream; +import java.util.stream.Stream; -public class MinesweeperUtilities { - public static boolean hasEmptyAdjacent(MinesweeperBoard board, MinesweeperCell cell) { - ArrayList adjCells = getAdjacentCells(board, cell); - for (MinesweeperCell adjCell : adjCells) { - if (adjCell.getTileType() == MinesweeperTileType.UNSET) { - return true; - } - } - return false; +public final class MinesweeperUtilities { + + private static final int SURROUNDING_CELL_MIN_INDEX = 0; + private static final int SURROUNDING_CELL_MAX_INDEX = 9; + + public static Stream getSurroundingCells(MinesweeperBoard board, MinesweeperCell cell) { + final Point loc = cell.getLocation(); + final int height = board.getHeight(); + final int width = board.getWidth(); + final int x = (int) loc.getX(); + final int y = (int) loc.getY(); + // IntStream of 0-9 to represent 2D matrix of surrounding elements, + // this maps from 0,0 to 2,2 so everything needs to be shifted + // left 1 and up 1 to become + // -1,1 to 1,1 + // and 5 is skipped because we want to ignore 1,1 + return IntStream.range(SURROUNDING_CELL_MIN_INDEX, SURROUNDING_CELL_MAX_INDEX) + // skip 0,0 element + .filter(i -> i != (SURROUNDING_CELL_MAX_INDEX - SURROUNDING_CELL_MIN_INDEX) / 2) + .mapToObj(index -> { + final int newX = index / 3 - 1 + x; + final int newY = index % 3 - 1 + y; + // only keep valid locations + if (newX < 0 || newY < 0 || newX >= width || newY >= height) { + return null; + } + return board.getCell(newX, newY); + }) + .filter(Objects::nonNull); } - public static ArrayList getAdjacentCells(MinesweeperBoard board, MinesweeperCell cell) { - ArrayList adjCells = new ArrayList(); - Point cellLoc = cell.getLocation(); - for (int i=-1; i <= 1; i++) { - for (int j=-1; j <= 1; j++) { - if (cellLoc.getX() + i < 0 || cellLoc.y + j < 0 || cellLoc.x + i >= board.getWidth() || cellLoc.y + j >= board.getHeight()) { - continue; - } - MinesweeperCell adjCell = (MinesweeperCell) board.getCell(cellLoc.x + i, cellLoc.y + j); - if (adjCell == null) { - continue; - } - adjCells.add(adjCell); - } - } - return adjCells; + public static int countSurroundingType(MinesweeperBoard board, MinesweeperCell cell, MinesweeperTileType type) { + final Stream stream = getSurroundingCells(board, cell) + .map(MinesweeperCell::getData); + return (int) (switch (type) { + case UNSET -> stream.filter(MinesweeperTileData::isUnset); + case BOMB -> stream.filter(MinesweeperTileData::isBomb); + case EMPTY -> stream.filter(MinesweeperTileData::isEmpty); + case FLAG -> stream.filter(MinesweeperTileData::isFlag); + }).count(); } - public static ArrayList getCombinations(int chosenNumItems, int totalNumItems) { - ArrayList combinations = new ArrayList(); + public static int countSurroundingBombs(MinesweeperBoard board, MinesweeperCell cell) { + return countSurroundingType(board, cell, MinesweeperTileType.BOMB); + } - // calculate all combinations - boolean[] array = new boolean[totalNumItems]; - recurseCombinations(combinations, 0, chosenNumItems, 0, totalNumItems, array); + public static int countSurroundingUnset(MinesweeperBoard board, MinesweeperCell cell) { + return countSurroundingType(board, cell, MinesweeperTileType.UNSET); + } - return combinations; + public static int countSurroundingEmpty(MinesweeperBoard board, MinesweeperCell cell) { + return countSurroundingType(board, cell, MinesweeperTileType.EMPTY); } - private static void recurseCombinations(ArrayList result, int curIndex, int maxBlack, int numBlack, int len, boolean[] workingArray) { - if (curIndex == len) { - // complete, but not valid solution - if (numBlack != maxBlack) { - return; - } - // complete and valid solution - result.add(workingArray.clone()); - return; - } - // there is no chance of completing the required number of solutions, so quit - if (len - curIndex < maxBlack - numBlack) { - return; - } + public static int countSurroundingFlags(MinesweeperBoard board, MinesweeperCell cell) { + return countSurroundingType(board, cell, MinesweeperTileType.FLAG); + } - if (numBlack < maxBlack) { - workingArray[curIndex] = true; - recurseCombinations(result, curIndex+1, maxBlack, numBlack+1, len, workingArray); + /** + * + * @return how many bombs 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"); } - workingArray[curIndex] = false; - recurseCombinations(result, curIndex+1, maxBlack, numBlack, len, workingArray); + return cell.getData().data() - countSurroundingBombs(board, cell); } + } From d8e27aa4ad4e585e55b1c43c7b568d06d2d58a91 Mon Sep 17 00:00:00 2001 From: vockek Date: Tue, 12 Mar 2024 17:08:03 -0400 Subject: [PATCH 13/21] Update minesweeperUtilities.java --- .../minesweeper/minesweeperUtilities.java | 113 ++++++++++-------- 1 file changed, 62 insertions(+), 51 deletions(-) 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 81a7694ec..26e2704f1 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/minesweeperUtilities.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/minesweeperUtilities.java @@ -1,67 +1,78 @@ package edu.rpi.legup.puzzle.minesweeper; import java.awt.*; -import java.util.*; +import java.util.Objects; +import java.util.stream.IntStream; +import java.util.stream.Stream; -public class MinesweeperUtilities { - public static boolean hasEmptyAdjacent(MinesweeperBoard board, MinesweeperCell cell) { - ArrayList adjCells = getAdjacentCells(board, cell); - for (MinesweeperCell adjCell : adjCells) { - if (adjCell.getTileType() == MinesweeperTileType.UNSET) { - return true; - } - } - return false; +public final class MinesweeperUtilities { + + private static final int SURROUNDING_CELL_MIN_INDEX = 0; + private static final int SURROUNDING_CELL_MAX_INDEX = 9; + + public static Stream getSurroundingCells(MinesweeperBoard board, MinesweeperCell cell) { + final Point loc = cell.getLocation(); + final int height = board.getHeight(); + final int width = board.getWidth(); + final int x = (int) loc.getX(); + final int y = (int) loc.getY(); + // IntStream of 0-9 to represent 2D matrix of surrounding elements, + // this maps from 0,0 to 2,2 so everything needs to be shifted + // left 1 and up 1 to become + // -1,1 to 1,1 + // and 5 is skipped because we want to ignore 1,1 + return IntStream.range(SURROUNDING_CELL_MIN_INDEX, SURROUNDING_CELL_MAX_INDEX) + // skip 0,0 element + .filter(i -> i != (SURROUNDING_CELL_MAX_INDEX - SURROUNDING_CELL_MIN_INDEX) / 2) + .mapToObj(index -> { + final int newX = index / 3 - 1 + x; + final int newY = index % 3 - 1 + y; + // only keep valid locations + if (newX < 0 || newY < 0 || newX >= width || newY >= height) { + return null; + } + return board.getCell(newX, newY); + }) + .filter(Objects::nonNull); } - public static ArrayList getAdjacentCells(MinesweeperBoard board, MinesweeperCell cell) { - ArrayList adjCells = new ArrayList(); - Point cellLoc = cell.getLocation(); - for (int i=-1; i <= 1; i++) { - for (int j=-1; j <= 1; j++) { - if (cellLoc.getX() + i < 0 || cellLoc.y + j < 0 || cellLoc.x + i >= board.getWidth() || cellLoc.y + j >= board.getHeight()) { - continue; - } - MinesweeperCell adjCell = (MinesweeperCell) board.getCell(cellLoc.x + i, cellLoc.y + j); - if (adjCell == null) { - continue; - } - adjCells.add(adjCell); - } - } - return adjCells; + public static int countSurroundingType(MinesweeperBoard board, MinesweeperCell cell, MinesweeperTileType type) { + final Stream stream = getSurroundingCells(board, cell) + .map(MinesweeperCell::getData); + return (int) (switch (type) { + case UNSET -> stream.filter(MinesweeperTileData::isUnset); + case BOMB -> stream.filter(MinesweeperTileData::isBomb); + case EMPTY -> stream.filter(MinesweeperTileData::isEmpty); + case FLAG -> stream.filter(MinesweeperTileData::isFlag); + }).count(); } - public static ArrayList getCombinations(int chosenNumItems, int totalNumItems) { - ArrayList combinations = new ArrayList(); + public static int countSurroundingBombs(MinesweeperBoard board, MinesweeperCell cell) { + return countSurroundingType(board, cell, MinesweeperTileType.BOMB); + } - // calculate all combinations - boolean[] array = new boolean[totalNumItems]; - recurseCombinations(combinations, 0, chosenNumItems, 0, totalNumItems, array); + public static int countSurroundingUnset(MinesweeperBoard board, MinesweeperCell cell) { + return countSurroundingType(board, cell, MinesweeperTileType.UNSET); + } - return combinations; + public static int countSurroundingEmpty(MinesweeperBoard board, MinesweeperCell cell) { + return countSurroundingType(board, cell, MinesweeperTileType.EMPTY); } - private static void recurseCombinations(ArrayList result, int curIndex, int maxBlack, int numBlack, int len, boolean[] workingArray) { - if (curIndex == len) { - // complete, but not valid solution - if (numBlack != maxBlack) { - return; - } - // complete and valid solution - result.add(workingArray.clone()); - return; - } - // there is no chance of completing the required number of solutions, so quit - if (len - curIndex < maxBlack - numBlack) { - return; - } + public static int countSurroundingFlags(MinesweeperBoard board, MinesweeperCell cell) { + return countSurroundingType(board, cell, MinesweeperTileType.FLAG); + } - if (numBlack < maxBlack) { - workingArray[curIndex] = true; - recurseCombinations(result, curIndex+1, maxBlack, numBlack+1, len, workingArray); + /** + * + * @return how many bombs 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"); } - workingArray[curIndex] = false; - recurseCombinations(result, curIndex+1, maxBlack, numBlack, len, workingArray); + return cell.getData().data() - countSurroundingBombs(board, cell); } + } From 3a1cee218e8abf06d64a0bda575415ee334b5473 Mon Sep 17 00:00:00 2001 From: vockek Date: Tue, 19 Mar 2024 17:47:35 -0400 Subject: [PATCH 14/21] Added Minesweeper Utility Functions -Fixed Bomb or Filled case rule picture -Added getTileNumber and setCellType functions -added 5x5 test puzzle --- .../minesweeper/5x5 Minesweeper Easy/123456 | 11 ++++ .../puzzle/minesweeper/MinesweeperCell.java | 8 +++ .../minesweeper/MinesweeperUtilities.java | 63 +++++++++++++++++++ .../rules/BombOrFilledCaseRule.java | 4 +- 4 files changed, 84 insertions(+), 2 deletions(-) create mode 100644 puzzles files/minesweeper/5x5 Minesweeper Easy/123456 diff --git a/puzzles files/minesweeper/5x5 Minesweeper Easy/123456 b/puzzles files/minesweeper/5x5 Minesweeper Easy/123456 new file mode 100644 index 000000000..2aa0b46ab --- /dev/null +++ b/puzzles files/minesweeper/5x5 Minesweeper Easy/123456 @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file 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 50ab32393..6770e5263 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperCell.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperCell.java @@ -18,6 +18,10 @@ public MinesweeperCell(@NotNull MinesweeperTileData value, @NotNull Point locati return super.data.type(); } + public @NotNull int getTileNumber() { + return super.data.data(); + } + @Override @Contract(pure = false) /** @@ -56,6 +60,10 @@ public void setType(@NotNull Element element, @NotNull MouseEvent event) { } } + public void setCellType(MinesweeperTileData type){ + this.data = type; + } + @Override @Contract(pure = true) public @NotNull MinesweeperCell copy() { 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 26e2704f1..e74979e19 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperUtilities.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperUtilities.java @@ -4,6 +4,7 @@ import java.util.Objects; import java.util.stream.IntStream; import java.util.stream.Stream; +import java.util.*; public final class MinesweeperUtilities { @@ -75,4 +76,66 @@ public int countNeededBombsFromFlag(MinesweeperBoard board, MinesweeperCell cell return cell.getData().data() - countSurroundingBombs(board, cell); } + public static boolean hasEmptyAdjacent(MinesweeperBoard board, MinesweeperCell cell) { + ArrayList adjCells = getAdjacentCells(board, cell); + for (MinesweeperCell adjCell : adjCells) { + if (adjCell.getTileType() == MinesweeperTileType.UNSET) { + return true; + } + } + return false; + } + + public static ArrayList getAdjacentCells(MinesweeperBoard board, MinesweeperCell cell) { + ArrayList adjCells = new ArrayList(); + Point cellLoc = cell.getLocation(); + for (int i=-1; i <= 1; i++) { + for (int j=-1; j <= 1; j++) { + if (cellLoc.getX() + i < 0 || cellLoc.y + j < 0 || cellLoc.x + i >= board.getWidth() || cellLoc.y + j >= board.getHeight()) { + continue; + } + MinesweeperCell adjCell = (MinesweeperCell) board.getCell(cellLoc.x + i, cellLoc.y + j); + if (adjCell == null) { + continue; + } + adjCells.add(adjCell); + } + } + return adjCells; + } + + public static ArrayList getCombinations(int chosenNumItems, int totalNumItems) { + ArrayList combinations = new ArrayList(); + + // calculate all combinations + boolean[] array = new boolean[totalNumItems]; + recurseCombinations(combinations, 0, chosenNumItems, 0, totalNumItems, array); + + return combinations; + } + + private static void recurseCombinations(ArrayList result, int curIndex, int maxBlack, int numBlack, int len, boolean[] workingArray) { + if (curIndex == len) { + // complete, but not valid solution + if (numBlack != maxBlack) { + return; + } + // complete and valid solution + result.add(workingArray.clone()); + return; + } + // there is no chance of completing the required number of solutions, so quit + if (len - curIndex < maxBlack - numBlack) { + return; + } + + if (numBlack < maxBlack) { + workingArray[curIndex] = true; + recurseCombinations(result, curIndex+1, maxBlack, numBlack+1, len, workingArray); + } + workingArray[curIndex] = false; + recurseCombinations(result, curIndex+1, maxBlack, numBlack, len, workingArray); + } + + } diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/BombOrFilledCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/BombOrFilledCaseRule.java index bad89b4a4..4bba7ff32 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/BombOrFilledCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/BombOrFilledCaseRule.java @@ -16,9 +16,9 @@ public class BombOrFilledCaseRule extends CaseRule { public BombOrFilledCaseRule() { - super("MINE-CASE-0000", "Bomb Or Filled", + 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"); } @Override From 3022d8605188ae6da176c4987872d243e92e23cd Mon Sep 17 00:00:00 2001 From: vockek Date: Fri, 22 Mar 2024 17:41:01 -0400 Subject: [PATCH 15/21] Fixed "satisfy flag" case rule --- .../rules/SatisfyFlagCaseRule.java | 39 +++++++++---------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/SatisfyFlagCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/SatisfyFlagCaseRule.java index 9bc16a139..cb2250ddf 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/SatisfyFlagCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/SatisfyFlagCaseRule.java @@ -6,11 +6,7 @@ import edu.rpi.legup.model.rules.CaseRule; import edu.rpi.legup.model.tree.TreeNode; import edu.rpi.legup.model.tree.TreeTransition; -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.MinesweeperTileType; -import edu.rpi.legup.puzzle.minesweeper.MinesweeperUtilities; +import edu.rpi.legup.puzzle.minesweeper.*; import java.awt.*; import java.util.*; @@ -46,37 +42,37 @@ public ArrayList getCases(Board board, PuzzleElement puzzleElement) { MinesweeperBoard minesweeperBoard = (MinesweeperBoard) board.copy(); MinesweeperCell cell = (MinesweeperCell) minesweeperBoard.getPuzzleElement(puzzleElement); int cellMaxBlack = cell.getTileNumber(); - if (cellMaxBlack < 0 || cellMaxBlack > 8) { // cell is not valid cell + if (cellMaxBlack <= 0 || cellMaxBlack > 8) { // cell is not valid cell return null; } - // find number of black & empty squares + // find number of black & unset squares int cellNumBomb = 0; - int cellNumEmpty = 0; - ArrayList emptyCells = new ArrayList(); + 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.EMPTY) { - cellNumEmpty++; - emptyCells.add(adjCell); + if (adjCell.getTileType() == MinesweeperTileType.UNSET) { + cellNumUnset++; + unsetCells.add(adjCell); } } // no cases if no empty or if too many black already - if (cellNumBomb > cellMaxBlack || cellNumEmpty == 0) { + if (cellNumBomb >= cellMaxBlack || cellNumUnset == 0) { return cases; } // generate all cases as boolean expressions ArrayList combinations; - combinations = MinesweeperUtilities.getCombinations(cellMaxBlack - cellNumBomb, cellNumEmpty); + combinations = MinesweeperUtilities.getCombinations(cellMaxBlack - cellNumBomb, 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(emptyCells.get(j)); + cell = (MinesweeperCell) case_.getPuzzleElement(unsetCells.get(j)); if (combinations.get(i)[j]) { cell.setCellType(MinesweeperTileData.bomb()); } @@ -103,7 +99,7 @@ public String checkRuleRaw(TreeTransition transition) { * * all modified cells must share at least one common adjacent * cell * * all modified cells must fit within a 3X3 square - * * the center of one of the possible squaress must be a cell + * * the center of one of the possible squares must be a cell * with a number * * that cells possible combinations must match the transitions * If all the above is verified, then the transition is valid @@ -143,13 +139,16 @@ public String checkRuleRaw(TreeTransition transition) { /* get the center of all possible 3X3 squares, * and collect all that have numbers */ MinesweeperBoard board = (MinesweeperBoard) transition.getParents().get(0).getBoard(); - Set possibleCenters = new TreeSet(); - possibleCenters.addAll(MinesweeperUtilities.getAdjacentCells(board, (MinesweeperCell) modCells.iterator().next())); + ArrayList possibleCenters = new ArrayList(); for (PuzzleElement modCell : modCells) { - possibleCenters.retainAll((MinesweeperUtilities.getAdjacentCells(board, (MinesweeperCell) modCell))); + ArrayList adjacentCells = MinesweeperUtilities.getAdjacentCells(board, (MinesweeperCell) modCell); + for (MinesweeperCell cell : adjacentCells) { + possibleCenters.add(cell); + } } + // removing all elements without a valid number - possibleCenters.removeIf(x -> x.getTileNumber() < 0 || x.getTileNumber() >= 9); + possibleCenters.removeIf(x -> x.getTileNumber() <= 0 || x.getTileNumber() >= 9); if (possibleCenters.isEmpty()) { return super.getInvalidUseOfRuleMessage(); } From f9d52a3eb0c5fe522beb33635816a2a3154c88ed Mon Sep 17 00:00:00 2001 From: Bram van Heuveln Date: Fri, 22 Mar 2024 21:48:49 +0000 Subject: [PATCH 16/21] Automated Java code formatting changes --- .../legup/puzzle/minesweeper/Minesweeper.java | 131 +++++----- .../puzzle/minesweeper/MinesweeperBoard.java | 72 ++--- .../puzzle/minesweeper/MinesweeperCell.java | 149 ++++++----- .../minesweeper/MinesweeperCellFactory.java | 211 +++++++-------- .../minesweeper/MinesweeperController.java | 120 ++++----- .../MinesweeperElementIdentifiers.java | 38 ++- .../minesweeper/MinesweeperElementView.java | 153 ++++++----- .../minesweeper/MinesweeperExporter.java | 88 +++---- .../minesweeper/MinesweeperImporter.java | 247 +++++++++--------- .../minesweeper/MinesweeperTileData.java | 213 +++++++-------- .../minesweeper/MinesweeperTileType.java | 38 +-- .../minesweeper/MinesweeperUtilities.java | 79 +++--- .../puzzle/minesweeper/MinesweeperView.java | 96 +++---- .../puzzle/minesweeper/elements/BombTile.java | 9 +- .../minesweeper/elements/EmptyTile.java | 6 +- .../puzzle/minesweeper/elements/FlagTile.java | 9 +- .../puzzle/minesweeper/elements/Unset.java | 8 +- .../minesweeper/elements/UnsetTile.java | 7 +- .../rules/BombOrFilledCaseRule.java | 12 +- .../LessBombsThanFlagContradictionRule.java | 17 +- .../rules/SatisfyFlagCaseRule.java | 42 +-- .../minesweeper/MinesweeperUtilitiesTest.java | 26 +- 22 files changed, 883 insertions(+), 888 deletions(-) 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 dd457f3d2..ed8066f39 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/Minesweeper.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/Minesweeper.java @@ -1,67 +1,64 @@ -package edu.rpi.legup.puzzle.minesweeper; - -import edu.rpi.legup.model.Puzzle; -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.ContradictionRule; -import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public class Minesweeper extends Puzzle { - - public static final String NAME = "Minesweeper"; - - public Minesweeper() { - this.name = NAME; - this.importer = new MinesweeperImporter(this); - this.exporter = new MinesweeperExporter(this); - this.factory = MinesweeperCellFactory.INSTANCE; - } - - @Override - @Contract(pure = false) - public void initializeView() { - this.boardView = new MinesweeperView((MinesweeperBoard) this.currentBoard); - this.boardView.setBoard(this.currentBoard); - addBoardListener(boardView); - } - - @Override - @Contract("_ -> null") - public @Nullable Board generatePuzzle(int difficulty) { - return null; - } - - @Override - @Contract(pure = true) - public boolean isBoardComplete(@NotNull Board board) { - MinesweeperBoard minesweeperBoard = (MinesweeperBoard) board; - - for (ContradictionRule rule : contradictionRules) { - if (rule.checkContradiction(minesweeperBoard) == null) { - return false; - } - } - for (PuzzleElement data : minesweeperBoard.getPuzzleElements()) { - final MinesweeperCell cell = (MinesweeperCell) data; - if (cell.getData().equals(MinesweeperTileData.empty())) { - return false; - } - } - return true; - } - - @Override - @Contract(pure = true) - public void onBoardChange(@NotNull Board board) { - - } - - @Override - @Contract(pure = true) - public boolean isValidDimensions(int rows, int columns) { - return rows >= 1 && columns >= 1; - } - -} +package edu.rpi.legup.puzzle.minesweeper; + +import edu.rpi.legup.model.Puzzle; +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.ContradictionRule; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class Minesweeper extends Puzzle { + + public static final String NAME = "Minesweeper"; + + public Minesweeper() { + this.name = NAME; + this.importer = new MinesweeperImporter(this); + this.exporter = new MinesweeperExporter(this); + this.factory = MinesweeperCellFactory.INSTANCE; + } + + @Override + @Contract(pure = false) + public void initializeView() { + this.boardView = new MinesweeperView((MinesweeperBoard) this.currentBoard); + this.boardView.setBoard(this.currentBoard); + addBoardListener(boardView); + } + + @Override + @Contract("_ -> null") + public @Nullable Board generatePuzzle(int difficulty) { + return null; + } + + @Override + @Contract(pure = true) + public boolean isBoardComplete(@NotNull Board board) { + MinesweeperBoard minesweeperBoard = (MinesweeperBoard) board; + + for (ContradictionRule rule : contradictionRules) { + if (rule.checkContradiction(minesweeperBoard) == null) { + return false; + } + } + for (PuzzleElement data : minesweeperBoard.getPuzzleElements()) { + final MinesweeperCell cell = (MinesweeperCell) data; + if (cell.getData().equals(MinesweeperTileData.empty())) { + return false; + } + } + return true; + } + + @Override + @Contract(pure = true) + public void onBoardChange(@NotNull Board board) {} + + @Override + @Contract(pure = true) + public boolean isValidDimensions(int rows, int columns) { + return rows >= 1 && columns >= 1; + } +} 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 ea6f560e1..bef317ab5 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperBoard.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperBoard.java @@ -1,36 +1,36 @@ -package edu.rpi.legup.puzzle.minesweeper; - -import edu.rpi.legup.model.gameboard.GridBoard; - -public class MinesweeperBoard extends GridBoard { - - public MinesweeperBoard(int width, int height) { - super(width, height); - } - - public MinesweeperBoard(int size) { - super(size); - } - - @Override - public MinesweeperCell getCell(int x, int y) { - return (MinesweeperCell) super.getCell(x, y); - } - - - /** - * Performs a deep copy of the Board - * - * @return a new copy of the board that is independent of this one - */ - @Override - public MinesweeperBoard copy() { - MinesweeperBoard newMinesweeperBoard = new MinesweeperBoard(this.dimension.width, this.dimension.height); - for (int x = 0; x < this.dimension.width; x++) { - for (int y = 0; y < this.dimension.height; y++) { - newMinesweeperBoard.setCell(x, y, getCell(x, y).copy()); - } - } - return newMinesweeperBoard; - } -} +package edu.rpi.legup.puzzle.minesweeper; + +import edu.rpi.legup.model.gameboard.GridBoard; + +public class MinesweeperBoard extends GridBoard { + + public MinesweeperBoard(int width, int height) { + super(width, height); + } + + public MinesweeperBoard(int size) { + super(size); + } + + @Override + public MinesweeperCell getCell(int x, int y) { + return (MinesweeperCell) super.getCell(x, y); + } + + /** + * Performs a deep copy of the Board + * + * @return a new copy of the board that is independent of this one + */ + @Override + public MinesweeperBoard copy() { + MinesweeperBoard newMinesweeperBoard = + new MinesweeperBoard(this.dimension.width, this.dimension.height); + for (int x = 0; x < this.dimension.width; x++) { + for (int y = 0; y < this.dimension.height; y++) { + newMinesweeperBoard.setCell(x, y, getCell(x, y).copy()); + } + } + 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 6770e5263..325e42b7b 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperCell.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperCell.java @@ -1,76 +1,73 @@ -package edu.rpi.legup.puzzle.minesweeper; - -import edu.rpi.legup.model.elements.Element; -import edu.rpi.legup.model.gameboard.GridCell; -import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; - -import java.awt.*; -import java.awt.event.MouseEvent; - -public class MinesweeperCell extends GridCell { - - public MinesweeperCell(@NotNull MinesweeperTileData value, @NotNull Point location) { - super(value, location); - } - - public @NotNull MinesweeperTileType getTileType() { - return super.data.type(); - } - - public @NotNull int getTileNumber() { - return super.data.data(); - } - - @Override - @Contract(pure = false) - /** - * 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(); - break; - } - case MinesweeperElementIdentifiers.FLAG -> { - final int currentData = super.data.data(); - switch (event.getButton()) { - case MouseEvent.BUTTON1 -> { - if (currentData >= 8) { - this.data = MinesweeperTileData.empty(); - return; - } - this.data = MinesweeperTileData.flag(currentData + 1); - return; - } - case MouseEvent.BUTTON2, MouseEvent.BUTTON3 -> { - if (currentData <= 0) { - this.data = MinesweeperTileData.empty(); - return; - } - this.data = MinesweeperTileData.flag(currentData - 1); - return; - } - } - } - default -> { - this.data = MinesweeperTileData.empty(); - } - } - } - - public void setCellType(MinesweeperTileData type){ - this.data = type; - } - - @Override - @Contract(pure = true) - public @NotNull MinesweeperCell copy() { - MinesweeperCell copy = new MinesweeperCell(data, (Point) location.clone()); - copy.setIndex(index); - copy.setModifiable(isModifiable); - copy.setGiven(isGiven); - return copy; - } -} +package edu.rpi.legup.puzzle.minesweeper; + +import edu.rpi.legup.model.elements.Element; +import edu.rpi.legup.model.gameboard.GridCell; +import java.awt.*; +import java.awt.event.MouseEvent; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; + +public class MinesweeperCell extends GridCell { + + public MinesweeperCell(@NotNull MinesweeperTileData value, @NotNull Point location) { + super(value, location); + } + + public @NotNull MinesweeperTileType getTileType() { + return super.data.type(); + } + + public @NotNull int getTileNumber() { + return super.data.data(); + } + + @Override + @Contract(pure = false) + /** 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(); + break; + } + case MinesweeperElementIdentifiers.FLAG -> { + final int currentData = super.data.data(); + switch (event.getButton()) { + case MouseEvent.BUTTON1 -> { + if (currentData >= 8) { + this.data = MinesweeperTileData.empty(); + return; + } + this.data = MinesweeperTileData.flag(currentData + 1); + return; + } + case MouseEvent.BUTTON2, MouseEvent.BUTTON3 -> { + if (currentData <= 0) { + this.data = MinesweeperTileData.empty(); + return; + } + this.data = MinesweeperTileData.flag(currentData - 1); + return; + } + } + } + default -> { + this.data = MinesweeperTileData.empty(); + } + } + } + + public void setCellType(MinesweeperTileData type) { + this.data = type; + } + + @Override + @Contract(pure = true) + public @NotNull MinesweeperCell copy() { + MinesweeperCell copy = new MinesweeperCell(data, (Point) location.clone()); + copy.setIndex(index); + copy.setModifiable(isModifiable); + copy.setGiven(isGiven); + return copy; + } +} 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 45957cb82..5fe6096a9 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperCellFactory.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperCellFactory.java @@ -1,110 +1,101 @@ -package edu.rpi.legup.puzzle.minesweeper; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.ElementFactory; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.save.InvalidFileFormatException; -import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NamedNodeMap; -import org.w3c.dom.Node; - -import java.awt.*; - -public class MinesweeperCellFactory extends ElementFactory { - - /** - * The key of the data used in {@link NamedNodeMap} - */ - private static final String DATA_ATTRIBUTE = "data"; - /** - * The key of the x position used in {@link NamedNodeMap} - */ - private static final String X_ATTRIBUTE = "x"; - /** - * The key of the y position used in {@link NamedNodeMap} - */ - private static final String Y_ATTRIBUTE = "y"; - - - private MinesweeperCellFactory() { - } - - public static final MinesweeperCellFactory INSTANCE = new MinesweeperCellFactory(); - - /** - * - * @param node node that represents the puzzleElement - * @param board Board to use to verify the newly created {@link MinesweeperCell} - * is valid - * @return a new {@link MinesweeperCell} - * @throws InvalidFileFormatException If the node name is not "cell" - * @throws NumberFormatException If the {@link #X_ATTRIBUTE} or {@link #Y_ATTRIBUTE} - * is not a number - * @throws NullPointerException If one of {@link #DATA_ATTRIBUTE}, {@link #X_ATTRIBUTE} or {@link #Y_ATTRIBUTE} - * does not exist. - */ - @Override - @Contract(pure = false) - public @NotNull PuzzleElement importCell( - @NotNull Node node, - @NotNull Board board - ) throws InvalidFileFormatException { - try { - if (!node.getNodeName().equalsIgnoreCase("cell")) { - throw new InvalidFileFormatException("Minesweeper Factory: unknown puzzleElement puzzleElement"); - } - - MinesweeperBoard minesweeperBoard = (MinesweeperBoard) board; - final int width = minesweeperBoard.getWidth(); - final int height = minesweeperBoard.getHeight(); - - final NamedNodeMap attributeList = node.getAttributes(); - final int value = Integer.parseInt(attributeList.getNamedItem(DATA_ATTRIBUTE).getNodeValue()); - final int x = Integer.parseInt(attributeList.getNamedItem(X_ATTRIBUTE).getNodeValue()); - final int y = Integer.parseInt(attributeList.getNamedItem(Y_ATTRIBUTE).getNodeValue()); - if (x >= width || y >= height) { - throw new InvalidFileFormatException("Minesweeper Factory: cell location out of bounds"); - } - if (value < -2) { - throw new InvalidFileFormatException("Minesweeper Factory: cell unknown value"); - } - final MinesweeperCell cell = new MinesweeperCell(MinesweeperTileData.fromData(value), new Point(x, y)); - cell.setIndex(y * height + x); - return cell; - } - catch (NumberFormatException e) { - throw new InvalidFileFormatException("Minesweeper Factory: unknown value where integer expected"); - } - catch (NullPointerException e) { - throw new InvalidFileFormatException("Minesweeper Factory: could not find attribute(s)"); - } - } - - /** - * - * @param document Document used to create the element - * @param puzzleElement PuzzleElement cell - * @return a {@link Element} that contains the {@link #DATA_ATTRIBUTE}, - * {@link #X_ATTRIBUTE}, and {@link #Y_ATTRIBUTE} - */ - @Override - @Contract(pure = false) - public @NotNull Element exportCell( - @NotNull Document document, - @SuppressWarnings("rawtypes") @NotNull PuzzleElement puzzleElement - ) { - org.w3c.dom.Element cellElement = document.createElement("cell"); - - MinesweeperCell cell = (MinesweeperCell) puzzleElement; - Point loc = cell.getLocation(); - - cellElement.setAttribute(DATA_ATTRIBUTE, String.valueOf(cell.getData())); - cellElement.setAttribute(X_ATTRIBUTE, String.valueOf(loc.x)); - cellElement.setAttribute(Y_ATTRIBUTE, String.valueOf(loc.y)); - - return cellElement; - } -} +package edu.rpi.legup.puzzle.minesweeper; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.ElementFactory; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.save.InvalidFileFormatException; +import java.awt.*; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; + +public class MinesweeperCellFactory extends ElementFactory { + + /** The key of the data used in {@link NamedNodeMap} */ + private static final String DATA_ATTRIBUTE = "data"; + + /** The key of the x position used in {@link NamedNodeMap} */ + private static final String X_ATTRIBUTE = "x"; + + /** The key of the y position used in {@link NamedNodeMap} */ + private static final String Y_ATTRIBUTE = "y"; + + private MinesweeperCellFactory() {} + + public static final MinesweeperCellFactory INSTANCE = new MinesweeperCellFactory(); + + /** + * @param node node that represents the puzzleElement + * @param board Board to use to verify the newly created {@link MinesweeperCell} is valid + * @return a new {@link MinesweeperCell} + * @throws InvalidFileFormatException If the node name is not "cell" + * @throws NumberFormatException If the {@link #X_ATTRIBUTE} or {@link #Y_ATTRIBUTE} is not a + * number + * @throws NullPointerException If one of {@link #DATA_ATTRIBUTE}, {@link #X_ATTRIBUTE} or + * {@link #Y_ATTRIBUTE} does not exist. + */ + @Override + @Contract(pure = false) + public @NotNull PuzzleElement importCell( + @NotNull Node node, @NotNull Board board) throws InvalidFileFormatException { + try { + if (!node.getNodeName().equalsIgnoreCase("cell")) { + throw new InvalidFileFormatException( + "Minesweeper Factory: unknown puzzleElement puzzleElement"); + } + + MinesweeperBoard minesweeperBoard = (MinesweeperBoard) board; + final int width = minesweeperBoard.getWidth(); + final int height = minesweeperBoard.getHeight(); + + final NamedNodeMap attributeList = node.getAttributes(); + final int value = + Integer.parseInt(attributeList.getNamedItem(DATA_ATTRIBUTE).getNodeValue()); + final int x = Integer.parseInt(attributeList.getNamedItem(X_ATTRIBUTE).getNodeValue()); + final int y = Integer.parseInt(attributeList.getNamedItem(Y_ATTRIBUTE).getNodeValue()); + if (x >= width || y >= height) { + throw new InvalidFileFormatException( + "Minesweeper Factory: cell location out of bounds"); + } + if (value < -2) { + throw new InvalidFileFormatException("Minesweeper Factory: cell unknown value"); + } + final MinesweeperCell cell = + new MinesweeperCell(MinesweeperTileData.fromData(value), new Point(x, y)); + cell.setIndex(y * height + x); + return cell; + } catch (NumberFormatException e) { + throw new InvalidFileFormatException( + "Minesweeper Factory: unknown value where integer expected"); + } catch (NullPointerException e) { + throw new InvalidFileFormatException( + "Minesweeper Factory: could not find attribute(s)"); + } + } + + /** + * @param document Document used to create the element + * @param puzzleElement PuzzleElement cell + * @return a {@link Element} that contains the {@link #DATA_ATTRIBUTE}, {@link #X_ATTRIBUTE}, + * and {@link #Y_ATTRIBUTE} + */ + @Override + @Contract(pure = false) + public @NotNull Element exportCell( + @NotNull Document document, + @SuppressWarnings("rawtypes") @NotNull PuzzleElement puzzleElement) { + org.w3c.dom.Element cellElement = document.createElement("cell"); + + MinesweeperCell cell = (MinesweeperCell) puzzleElement; + Point loc = cell.getLocation(); + + cellElement.setAttribute(DATA_ATTRIBUTE, String.valueOf(cell.getData())); + cellElement.setAttribute(X_ATTRIBUTE, String.valueOf(loc.x)); + cellElement.setAttribute(Y_ATTRIBUTE, String.valueOf(loc.y)); + + return cellElement; + } +} 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 7289c349c..aaf061704 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperController.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperController.java @@ -1,63 +1,57 @@ -package edu.rpi.legup.puzzle.minesweeper; - -import edu.rpi.legup.controller.ElementController; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; - -import java.awt.event.MouseEvent; - -public class MinesweeperController extends ElementController { - - /** - * If the button clicked was button 1, then {@link MinesweeperTileData#fromData(int)} - * is called with a value of {@code current.data() + 1}. - * If the button clicked was button 2 or 3, then {@link MinesweeperTileData#fromData(int)} - * is called with a value of {@code currentData() - 1} - * Otherwise {@link MinesweeperTileData#empty()} is returned. - * - * @param event The user's click data - * @param current The current data at the cell they clicked on - * @return A different cell data depending on what the current data is - */ - @Contract(pure = true) - 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(); - }; - } - - /** - * @see #getNewCellDataOnClick(MouseEvent, MinesweeperTileData) - * @param event The user's click data - * @param data The current data at the cell they clicked on - */ - @Override - @SuppressWarnings("unchecked") - @Contract(pure = false) - public void changeCell( - @NotNull MouseEvent event, - @SuppressWarnings("rawtypes") @NotNull PuzzleElement data - ) { - final MinesweeperCell cell = (MinesweeperCell) data; - if (event.isControlDown()) { - this.boardView.getSelectionPopupMenu().show( - boardView, - this.boardView.getCanvas().getX() + event.getX(), - this.boardView.getCanvas().getY() + event.getY() - ); - return; - } - - final MinesweeperTileData newData = getNewCellDataOnClick(event, cell.getData()); - data.setData(newData); - } -} - +package edu.rpi.legup.puzzle.minesweeper; + +import edu.rpi.legup.controller.ElementController; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import java.awt.event.MouseEvent; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; + +public class MinesweeperController extends ElementController { + + /** + * If the button clicked was button 1, then {@link MinesweeperTileData#fromData(int)} is called + * with a value of {@code current.data() + 1}. If the button clicked was button 2 or 3, then + * {@link MinesweeperTileData#fromData(int)} is called with a value of {@code currentData() - 1} + * Otherwise {@link MinesweeperTileData#empty()} is returned. + * + * @param event The user's click data + * @param current The current data at the cell they clicked on + * @return A different cell data depending on what the current data is + */ + @Contract(pure = true) + 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(); + }; + } + + /** + * @see #getNewCellDataOnClick(MouseEvent, MinesweeperTileData) + * @param event The user's click data + * @param data The current data at the cell they clicked on + */ + @Override + @SuppressWarnings("unchecked") + @Contract(pure = false) + public void changeCell( + @NotNull MouseEvent event, @SuppressWarnings("rawtypes") @NotNull PuzzleElement data) { + final MinesweeperCell cell = (MinesweeperCell) data; + if (event.isControlDown()) { + this.boardView + .getSelectionPopupMenu() + .show( + boardView, + this.boardView.getCanvas().getX() + event.getX(), + this.boardView.getCanvas().getY() + event.getY()); + return; + } + + final MinesweeperTileData newData = getNewCellDataOnClick(event, cell.getData()); + data.setData(newData); + } +} 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 1b626a33b..77e490f7e 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperElementIdentifiers.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperElementIdentifiers.java @@ -1,22 +1,16 @@ -package edu.rpi.legup.puzzle.minesweeper; - -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 empty Minesweeper elements - */ - public static final String EMPTY = "MINESWEEPER-EMPTY"; - /** - * ID for flag Minesweeper elements - */ - public static final String FLAG = "MINESWEEPER-FLAG"; - -} +package edu.rpi.legup.puzzle.minesweeper; + +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 empty Minesweeper elements */ + public static final String EMPTY = "MINESWEEPER-EMPTY"; + + /** ID for flag Minesweeper elements */ + public static final String FLAG = "MINESWEEPER-FLAG"; +} 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 e9658a077..fd5d73928 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperElementView.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperElementView.java @@ -1,77 +1,76 @@ -package edu.rpi.legup.puzzle.minesweeper; - -import edu.rpi.legup.puzzle.lightup.LightUpView; -import edu.rpi.legup.ui.boardview.GridElementView; -import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; - -import java.awt.*; - -public class MinesweeperElementView extends GridElementView { - - private static final Font FONT = new Font("TimesRoman", Font.BOLD, 16); - private static final Color FONT_COLOR = Color.BLACK; - - public MinesweeperElementView(@NotNull MinesweeperCell cell) { - super(cell); - } - - @Override - public @NotNull MinesweeperCell getPuzzleElement() { - return (MinesweeperCell) super.getPuzzleElement(); - } - - @Override - @SuppressWarnings("Duplicates") - @Contract(pure = true) - public void drawElement(@NotNull Graphics2D graphics2D) { - final MinesweeperCell cell = (MinesweeperCell) puzzleElement; - final MinesweeperTileType type = cell.getTileType(); - if (type == MinesweeperTileType.FLAG) { - 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); - - 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(); - graphics2D.drawString(value, xText, yText); - return; - } - if (type == MinesweeperTileType.UNSET) { - graphics2D.setStroke(new BasicStroke(1)); - graphics2D.setColor(Color.BLACK); - graphics2D.drawRect(location.x, location.y, size.width, size.height); - graphics2D.setColor(Color.DARK_GRAY); - graphics2D.fillRect(location.x, location.y, size.width, size.height); - return; - } - if (type == MinesweeperTileType.EMPTY) { - graphics2D.setStroke(new BasicStroke(1)); - graphics2D.setColor(Color.BLACK); - graphics2D.drawRect(location.x, location.y, size.width, size.height); - graphics2D.setColor(Color.GRAY); - graphics2D.fillRect(location.x, location.y, size.width, size.height); - } - if (type == MinesweeperTileType.BOMB) { - graphics2D.setColor(Color.LIGHT_GRAY); - graphics2D.fillRect(location.x, location.y, size.width, size.height); - graphics2D.drawImage( - MinesweeperView.BOMB_IMAGE, - location.x, - location.y, - size.width, - size.height, - Color.GRAY, - null); - graphics2D.setColor(Color.BLACK); - graphics2D.drawRect(location.x, location.y, size.width, size.height); - } - } -} +package edu.rpi.legup.puzzle.minesweeper; + +import edu.rpi.legup.ui.boardview.GridElementView; +import java.awt.*; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; + +public class MinesweeperElementView extends GridElementView { + + private static final Font FONT = new Font("TimesRoman", Font.BOLD, 16); + private static final Color FONT_COLOR = Color.BLACK; + + public MinesweeperElementView(@NotNull MinesweeperCell cell) { + super(cell); + } + + @Override + public @NotNull MinesweeperCell getPuzzleElement() { + return (MinesweeperCell) super.getPuzzleElement(); + } + + @Override + @SuppressWarnings("Duplicates") + @Contract(pure = true) + public void drawElement(@NotNull Graphics2D graphics2D) { + final MinesweeperCell cell = (MinesweeperCell) puzzleElement; + final MinesweeperTileType type = cell.getTileType(); + if (type == MinesweeperTileType.FLAG) { + 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); + + 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(); + graphics2D.drawString(value, xText, yText); + return; + } + if (type == MinesweeperTileType.UNSET) { + graphics2D.setStroke(new BasicStroke(1)); + graphics2D.setColor(Color.BLACK); + graphics2D.drawRect(location.x, location.y, size.width, size.height); + graphics2D.setColor(Color.DARK_GRAY); + graphics2D.fillRect(location.x, location.y, size.width, size.height); + return; + } + if (type == MinesweeperTileType.EMPTY) { + graphics2D.setStroke(new BasicStroke(1)); + graphics2D.setColor(Color.BLACK); + graphics2D.drawRect(location.x, location.y, size.width, size.height); + graphics2D.setColor(Color.GRAY); + graphics2D.fillRect(location.x, location.y, size.width, size.height); + } + if (type == MinesweeperTileType.BOMB) { + graphics2D.setColor(Color.LIGHT_GRAY); + graphics2D.fillRect(location.x, location.y, size.width, size.height); + graphics2D.drawImage( + MinesweeperView.BOMB_IMAGE, + location.x, + location.y, + size.width, + size.height, + Color.GRAY, + null); + graphics2D.setColor(Color.BLACK); + graphics2D.drawRect(location.x, location.y, size.width, size.height); + } + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperExporter.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperExporter.java index 0a4f69fd6..8ae9c5a9a 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperExporter.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperExporter.java @@ -1,44 +1,44 @@ -package edu.rpi.legup.puzzle.minesweeper; - -import edu.rpi.legup.model.Puzzle; -import edu.rpi.legup.model.PuzzleExporter; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; -import org.w3c.dom.Document; -import org.w3c.dom.Element; - -public class MinesweeperExporter extends PuzzleExporter { - - public MinesweeperExporter(@NotNull Puzzle puzzle) { - super(puzzle); - } - - @Override - @Contract(pure = true) - protected @NotNull Element createBoardElement(@NotNull Document newDocument) { - MinesweeperBoard board; - if (puzzle.getTree() != null) { - board = (MinesweeperBoard) puzzle.getTree().getRootNode().getBoard(); - } - else { - board = (MinesweeperBoard) puzzle.getBoardView().getBoard(); - } - - final org.w3c.dom.Element boardElement = newDocument.createElement("board"); - boardElement.setAttribute("width", String.valueOf(board.getWidth())); - boardElement.setAttribute("height", String.valueOf(board.getHeight())); - - final org.w3c.dom.Element cellsElement = newDocument.createElement("cells"); - for (PuzzleElement puzzleElement : board.getPuzzleElements()) { - final MinesweeperCell cell = (MinesweeperCell) puzzleElement; - if (!MinesweeperTileData.unset().equals(cell.getData())) { - final org.w3c.dom.Element cellElement = puzzle.getFactory().exportCell(newDocument, puzzleElement); - cellsElement.appendChild(cellElement); - } - } - - boardElement.appendChild(cellsElement); - return boardElement; - } -} +package edu.rpi.legup.puzzle.minesweeper; + +import edu.rpi.legup.model.Puzzle; +import edu.rpi.legup.model.PuzzleExporter; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +public class MinesweeperExporter extends PuzzleExporter { + + public MinesweeperExporter(@NotNull Puzzle puzzle) { + super(puzzle); + } + + @Override + @Contract(pure = true) + protected @NotNull Element createBoardElement(@NotNull Document newDocument) { + MinesweeperBoard board; + if (puzzle.getTree() != null) { + board = (MinesweeperBoard) puzzle.getTree().getRootNode().getBoard(); + } else { + board = (MinesweeperBoard) puzzle.getBoardView().getBoard(); + } + + final org.w3c.dom.Element boardElement = newDocument.createElement("board"); + boardElement.setAttribute("width", String.valueOf(board.getWidth())); + boardElement.setAttribute("height", String.valueOf(board.getHeight())); + + final org.w3c.dom.Element cellsElement = newDocument.createElement("cells"); + for (PuzzleElement puzzleElement : board.getPuzzleElements()) { + final MinesweeperCell cell = (MinesweeperCell) puzzleElement; + if (!MinesweeperTileData.unset().equals(cell.getData())) { + final org.w3c.dom.Element cellElement = + puzzle.getFactory().exportCell(newDocument, puzzleElement); + cellsElement.appendChild(cellElement); + } + } + + boardElement.appendChild(cellsElement); + return boardElement; + } +} 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 8dc7037f9..419a69247 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperImporter.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperImporter.java @@ -1,119 +1,128 @@ -package edu.rpi.legup.puzzle.minesweeper; - -import edu.rpi.legup.model.PuzzleImporter; -import edu.rpi.legup.save.InvalidFileFormatException; -import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - -import java.awt.*; - -public class MinesweeperImporter extends PuzzleImporter { - - public MinesweeperImporter(@NotNull Minesweeper minesweeper) { - super(minesweeper); - } - - @Override - @Contract(pure = true, value = "-> true") - public boolean acceptsRowsAndColumnsInput() { - return true; - } - - @Override - @Contract(pure = true, value = "-> false") - public boolean acceptsTextInput() { - return false; - } - - @Override - @Contract(pure = false) - public void initializeBoard(int rows, int columns) { - MinesweeperBoard minesweeperBoard = new MinesweeperBoard(columns, rows); - - for (int y = 0; y < rows; y++) { - for (int x = 0; x < columns; x++) { - MinesweeperCell cell = new MinesweeperCell(MinesweeperTileData.unset(), new Point(x, y)); - cell.setIndex(y * columns + x); - cell.setModifiable(true); - minesweeperBoard.setCell(x, y, cell); - } - } - puzzle.setCurrentBoard(minesweeperBoard); - } - - @Override - @Contract(pure = false) - public void initializeBoard(@NotNull Node node) throws InvalidFileFormatException { - try { - if (!node.getNodeName().equalsIgnoreCase("board")) { - throw new InvalidFileFormatException("Minesweeper Importer: cannot find board puzzleElement"); - } - final Element boardElement = (Element) node; - if (boardElement.getElementsByTagName("cells").getLength() == 0) { - throw new InvalidFileFormatException("Minesweeper Importer: no puzzleElement found for board"); - } - final Element dataElement = (Element) boardElement.getElementsByTagName("cells").item(0); - final NodeList elementDataList = dataElement.getElementsByTagName("cell"); - - final MinesweeperBoard minesweeperBoard = getMinesweeperBoard(boardElement); - - final int width = minesweeperBoard.getWidth(); - final int height = minesweeperBoard.getHeight(); - - for (int i = 0; i < elementDataList.getLength(); i++) { - final MinesweeperCell cell = (MinesweeperCell) puzzle.getFactory().importCell(elementDataList.item(i), minesweeperBoard); - final Point loc = cell.getLocation(); - if (MinesweeperTileData.unset().equals(cell.getData())) { - cell.setModifiable(false); - cell.setGiven(true); - } - minesweeperBoard.setCell(loc.x, loc.y, cell); - } - - for (int y = 0; y < height; y++) { - for (int x = 0; x < width; x++) { - if (minesweeperBoard.getCell(x, y) == null) { - final MinesweeperCell cell = new MinesweeperCell(MinesweeperTileData.unset(), new Point(x, y)); - cell.setIndex(y * height + x); - cell.setModifiable(true); - minesweeperBoard.setCell(x, y, cell); - } - } - } - puzzle.setCurrentBoard(minesweeperBoard); - } - catch (NumberFormatException e) { - throw new InvalidFileFormatException("Minesweeper Importer: unknown value where integer expected"); - } - } - - @Contract(pure = true) - private static @NotNull MinesweeperBoard getMinesweeperBoard(@NotNull Element boardElement) throws InvalidFileFormatException { - MinesweeperBoard minesweeperBoard = null; - if (!boardElement.getAttribute("size").isEmpty()) { - final int size = Integer.parseInt(boardElement.getAttribute("size")); - minesweeperBoard = new MinesweeperBoard(size); - } - else { - if (!boardElement.getAttribute("width").isEmpty() && !boardElement.getAttribute("height").isEmpty()) { - final int width = Integer.parseInt(boardElement.getAttribute("width")); - final int height = Integer.parseInt(boardElement.getAttribute("height")); - minesweeperBoard = new MinesweeperBoard(width, height); - } - } - - if (minesweeperBoard == null) { - throw new InvalidFileFormatException("Minesweeper Importer: invalid board dimensions"); - } - return minesweeperBoard; - } - - @Override - @Contract(value = "_ -> fail", pure = false) - public void initializeBoard(@NotNull String[] statements) throws UnsupportedOperationException, IllegalArgumentException { - throw new UnsupportedOperationException("Minesweeper does not support text input."); - } -} +package edu.rpi.legup.puzzle.minesweeper; + +import edu.rpi.legup.model.PuzzleImporter; +import edu.rpi.legup.save.InvalidFileFormatException; +import java.awt.*; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +public class MinesweeperImporter extends PuzzleImporter { + + public MinesweeperImporter(@NotNull Minesweeper minesweeper) { + super(minesweeper); + } + + @Override + @Contract(pure = true, value = "-> true") + public boolean acceptsRowsAndColumnsInput() { + return true; + } + + @Override + @Contract(pure = true, value = "-> false") + public boolean acceptsTextInput() { + return false; + } + + @Override + @Contract(pure = false) + public void initializeBoard(int rows, int columns) { + MinesweeperBoard minesweeperBoard = new MinesweeperBoard(columns, rows); + + for (int y = 0; y < rows; y++) { + for (int x = 0; x < columns; x++) { + MinesweeperCell cell = + new MinesweeperCell(MinesweeperTileData.unset(), new Point(x, y)); + cell.setIndex(y * columns + x); + cell.setModifiable(true); + minesweeperBoard.setCell(x, y, cell); + } + } + puzzle.setCurrentBoard(minesweeperBoard); + } + + @Override + @Contract(pure = false) + public void initializeBoard(@NotNull Node node) throws InvalidFileFormatException { + try { + if (!node.getNodeName().equalsIgnoreCase("board")) { + throw new InvalidFileFormatException( + "Minesweeper Importer: cannot find board puzzleElement"); + } + final Element boardElement = (Element) node; + if (boardElement.getElementsByTagName("cells").getLength() == 0) { + throw new InvalidFileFormatException( + "Minesweeper Importer: no puzzleElement found for board"); + } + final Element dataElement = + (Element) boardElement.getElementsByTagName("cells").item(0); + final NodeList elementDataList = dataElement.getElementsByTagName("cell"); + + final MinesweeperBoard minesweeperBoard = getMinesweeperBoard(boardElement); + + final int width = minesweeperBoard.getWidth(); + final int height = minesweeperBoard.getHeight(); + + for (int i = 0; i < elementDataList.getLength(); i++) { + final MinesweeperCell cell = + (MinesweeperCell) + puzzle.getFactory() + .importCell(elementDataList.item(i), minesweeperBoard); + final Point loc = cell.getLocation(); + if (MinesweeperTileData.unset().equals(cell.getData())) { + cell.setModifiable(false); + cell.setGiven(true); + } + minesweeperBoard.setCell(loc.x, loc.y, cell); + } + + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + if (minesweeperBoard.getCell(x, y) == null) { + final MinesweeperCell cell = + new MinesweeperCell(MinesweeperTileData.unset(), new Point(x, y)); + cell.setIndex(y * height + x); + cell.setModifiable(true); + minesweeperBoard.setCell(x, y, cell); + } + } + } + puzzle.setCurrentBoard(minesweeperBoard); + } catch (NumberFormatException e) { + throw new InvalidFileFormatException( + "Minesweeper Importer: unknown value where integer expected"); + } + } + + @Contract(pure = true) + private static @NotNull MinesweeperBoard getMinesweeperBoard(@NotNull Element boardElement) + throws InvalidFileFormatException { + MinesweeperBoard minesweeperBoard = null; + if (!boardElement.getAttribute("size").isEmpty()) { + final int size = Integer.parseInt(boardElement.getAttribute("size")); + minesweeperBoard = new MinesweeperBoard(size); + } else { + if (!boardElement.getAttribute("width").isEmpty() + && !boardElement.getAttribute("height").isEmpty()) { + final int width = Integer.parseInt(boardElement.getAttribute("width")); + final int height = Integer.parseInt(boardElement.getAttribute("height")); + minesweeperBoard = new MinesweeperBoard(width, height); + } + } + + if (minesweeperBoard == null) { + throw new InvalidFileFormatException("Minesweeper Importer: invalid board dimensions"); + } + return minesweeperBoard; + } + + @Override + @Contract(value = "_ -> fail", pure = false) + public void initializeBoard(@NotNull String[] statements) + throws UnsupportedOperationException, IllegalArgumentException { + throw new UnsupportedOperationException("Minesweeper does not support text input."); + } +} 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 79666c243..5296cf057 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperTileData.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperTileData.java @@ -1,106 +1,107 @@ -package edu.rpi.legup.puzzle.minesweeper; - -import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Objects; - -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 EMPTY_DATA = 0; - - /** - * Always has a type of {@link MinesweeperTileType#UNSET}, and a data value of - * {@value UNSET_DATA} - */ - private static final MinesweeperTileData UNSET = new MinesweeperTileData(MinesweeperTileType.UNSET, UNSET_DATA); - /** - * Always has a type of {@link MinesweeperTileType#BOMB}, and a data value of - * {@value BOMB_DATA} - */ - private static final MinesweeperTileData BOMB = new MinesweeperTileData(MinesweeperTileType.BOMB, BOMB_DATA); - /** - * Always has a type of {@link MinesweeperTileType#EMPTY}, and a data value of - * {@value EMPTY_DATA} - */ - private static final MinesweeperTileData EMPTY = new MinesweeperTileData(MinesweeperTileType.EMPTY, EMPTY_DATA); - - /** - * @param count how many bombs are near the flag - * @return a new {@link MinesweeperTileData} with a {@link MinesweeperTileData#type} of {@link MinesweeperTileType#FLAG} - * and a {@link MinesweeperTileData#data} of {@code count} - */ - @Contract(pure = true) - public static @NotNull MinesweeperTileData flag(int count) { - return new MinesweeperTileData(MinesweeperTileType.FLAG, 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 - * 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. - */ - @Contract(pure = true) - public static @NotNull MinesweeperTileData fromData(int data) { - return switch (data) { - case UNSET_DATA -> unset(); - case BOMB_DATA -> bomb(); - case EMPTY_DATA -> empty(); - default -> { - if (data <= -2 || data > 8) { - yield unset(); - } - yield flag(data); - } - }; - } - - public static @NotNull MinesweeperTileData unset() { - return UNSET; - } - - public static @NotNull MinesweeperTileData bomb() { - return BOMB; - } - - public static @NotNull MinesweeperTileData empty() { - return EMPTY; - } - - public boolean isUnset() { - return this.data == UNSET_DATA; - } - - public boolean isBomb() { - return this.data == BOMB_DATA; - } - - public boolean isEmpty() { - return this.data == EMPTY_DATA; - } - - public boolean isFlag() { - return this.data > 0 && this.data <= 8; - } - - @Override - public boolean equals(@Nullable Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - MinesweeperTileData that = (MinesweeperTileData) o; - return data == that.data && type == that.type; - } - - @Override - public int hashCode() { - return Objects.hash(type, data); - } -} +package edu.rpi.legup.puzzle.minesweeper; + +import java.util.Objects; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +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 EMPTY_DATA = 0; + + /** + * Always has a type of {@link MinesweeperTileType#UNSET}, and a data value of {@value + * UNSET_DATA} + */ + private static final MinesweeperTileData UNSET = + new MinesweeperTileData(MinesweeperTileType.UNSET, UNSET_DATA); + + /** + * Always has a type of {@link MinesweeperTileType#BOMB}, and a data value of {@value BOMB_DATA} + */ + private static final MinesweeperTileData BOMB = + new MinesweeperTileData(MinesweeperTileType.BOMB, BOMB_DATA); + + /** + * Always has a type of {@link MinesweeperTileType#EMPTY}, and a data value of {@value + * EMPTY_DATA} + */ + private static final MinesweeperTileData EMPTY = + new MinesweeperTileData(MinesweeperTileType.EMPTY, EMPTY_DATA); + + /** + * @param count how many bombs are near the flag + * @return a new {@link MinesweeperTileData} with a {@link MinesweeperTileData#type} of {@link + * MinesweeperTileType#FLAG} and a {@link MinesweeperTileData#data} of {@code count} + */ + @Contract(pure = true) + public static @NotNull MinesweeperTileData flag(int count) { + return new MinesweeperTileData(MinesweeperTileType.FLAG, 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 + * 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. + */ + @Contract(pure = true) + public static @NotNull MinesweeperTileData fromData(int data) { + return switch (data) { + case UNSET_DATA -> unset(); + case BOMB_DATA -> bomb(); + case EMPTY_DATA -> empty(); + default -> { + if (data <= -2 || data > 8) { + yield unset(); + } + yield flag(data); + } + }; + } + + public static @NotNull MinesweeperTileData unset() { + return UNSET; + } + + public static @NotNull MinesweeperTileData bomb() { + return BOMB; + } + + public static @NotNull MinesweeperTileData empty() { + return EMPTY; + } + + public boolean isUnset() { + return this.data == UNSET_DATA; + } + + public boolean isBomb() { + return this.data == BOMB_DATA; + } + + public boolean isEmpty() { + return this.data == EMPTY_DATA; + } + + public boolean isFlag() { + return this.data > 0 && this.data <= 8; + } + + @Override + public boolean equals(@Nullable Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + MinesweeperTileData that = (MinesweeperTileData) o; + return data == that.data && type == that.type; + } + + @Override + public int hashCode() { + return Objects.hash(type, data); + } +} 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 9d5dabd69..a682da5e5 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperTileType.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperTileType.java @@ -1,24 +1,14 @@ -package edu.rpi.legup.puzzle.minesweeper; - -public enum MinesweeperTileType { - - - /** - * A cell with nothing - */ - UNSET, - - /** - * Represents a cell with no bombs in it - */ - 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 - -} +package edu.rpi.legup.puzzle.minesweeper; + +public enum MinesweeperTileType { + + /** A cell with nothing */ + UNSET, + + /** Represents a cell with no bombs in it */ + 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 +} 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 e74979e19..375692095 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperUtilities.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperUtilities.java @@ -1,17 +1,18 @@ package edu.rpi.legup.puzzle.minesweeper; import java.awt.*; +import java.util.*; import java.util.Objects; import java.util.stream.IntStream; import java.util.stream.Stream; -import java.util.*; public final class MinesweeperUtilities { private static final int SURROUNDING_CELL_MIN_INDEX = 0; private static final int SURROUNDING_CELL_MAX_INDEX = 9; - public static Stream getSurroundingCells(MinesweeperBoard board, MinesweeperCell cell) { + public static Stream getSurroundingCells( + MinesweeperBoard board, MinesweeperCell cell) { final Point loc = cell.getLocation(); final int height = board.getHeight(); final int width = board.getWidth(); @@ -25,27 +26,31 @@ public static Stream getSurroundingCells(MinesweeperBoard board return IntStream.range(SURROUNDING_CELL_MIN_INDEX, SURROUNDING_CELL_MAX_INDEX) // skip 0,0 element .filter(i -> i != (SURROUNDING_CELL_MAX_INDEX - SURROUNDING_CELL_MIN_INDEX) / 2) - .mapToObj(index -> { - final int newX = index / 3 - 1 + x; - final int newY = index % 3 - 1 + y; - // only keep valid locations - if (newX < 0 || newY < 0 || newX >= width || newY >= height) { - return null; - } - return board.getCell(newX, newY); - }) + .mapToObj( + index -> { + final int newX = index / 3 - 1 + x; + final int newY = index % 3 - 1 + y; + // only keep valid locations + if (newX < 0 || newY < 0 || newX >= width || newY >= height) { + return null; + } + return board.getCell(newX, newY); + }) .filter(Objects::nonNull); } - public static int countSurroundingType(MinesweeperBoard board, MinesweeperCell cell, MinesweeperTileType type) { - final Stream stream = getSurroundingCells(board, cell) - .map(MinesweeperCell::getData); - return (int) (switch (type) { - case UNSET -> stream.filter(MinesweeperTileData::isUnset); - case BOMB -> stream.filter(MinesweeperTileData::isBomb); - case EMPTY -> stream.filter(MinesweeperTileData::isEmpty); - case FLAG -> stream.filter(MinesweeperTileData::isFlag); - }).count(); + public static int countSurroundingType( + MinesweeperBoard board, MinesweeperCell cell, MinesweeperTileType type) { + final Stream stream = + getSurroundingCells(board, cell).map(MinesweeperCell::getData); + return (int) + (switch (type) { + case UNSET -> stream.filter(MinesweeperTileData::isUnset); + case BOMB -> stream.filter(MinesweeperTileData::isBomb); + case EMPTY -> stream.filter(MinesweeperTileData::isEmpty); + case FLAG -> stream.filter(MinesweeperTileData::isFlag); + }) + .count(); } public static int countSurroundingBombs(MinesweeperBoard board, MinesweeperCell cell) { @@ -65,9 +70,8 @@ public static int countSurroundingFlags(MinesweeperBoard board, MinesweeperCell } /** - * - * @return how many bombs are left that need to be placed - * around {@code cell} which must be a flag + * @return how many bombs 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()) { @@ -86,15 +90,20 @@ public static boolean hasEmptyAdjacent(MinesweeperBoard board, MinesweeperCell c return false; } - public static ArrayList getAdjacentCells(MinesweeperBoard board, MinesweeperCell cell) { + public static ArrayList getAdjacentCells( + MinesweeperBoard board, MinesweeperCell cell) { ArrayList adjCells = new ArrayList(); Point cellLoc = cell.getLocation(); - for (int i=-1; i <= 1; i++) { - for (int j=-1; j <= 1; j++) { - if (cellLoc.getX() + i < 0 || cellLoc.y + j < 0 || cellLoc.x + i >= board.getWidth() || cellLoc.y + j >= board.getHeight()) { + for (int i = -1; i <= 1; i++) { + for (int j = -1; j <= 1; j++) { + if (cellLoc.getX() + i < 0 + || cellLoc.y + j < 0 + || cellLoc.x + i >= board.getWidth() + || cellLoc.y + j >= board.getHeight()) { continue; } - MinesweeperCell adjCell = (MinesweeperCell) board.getCell(cellLoc.x + i, cellLoc.y + j); + MinesweeperCell adjCell = + (MinesweeperCell) board.getCell(cellLoc.x + i, cellLoc.y + j); if (adjCell == null) { continue; } @@ -114,7 +123,13 @@ public static ArrayList getCombinations(int chosenNumItems, int total return combinations; } - private static void recurseCombinations(ArrayList result, int curIndex, int maxBlack, int numBlack, int len, boolean[] workingArray) { + private static void recurseCombinations( + ArrayList result, + int curIndex, + int maxBlack, + int numBlack, + int len, + boolean[] workingArray) { if (curIndex == len) { // complete, but not valid solution if (numBlack != maxBlack) { @@ -131,11 +146,9 @@ private static void recurseCombinations(ArrayList result, int curInde if (numBlack < maxBlack) { workingArray[curIndex] = true; - recurseCombinations(result, curIndex+1, maxBlack, numBlack+1, len, workingArray); + recurseCombinations(result, curIndex + 1, maxBlack, numBlack + 1, len, workingArray); } workingArray[curIndex] = false; - recurseCombinations(result, curIndex+1, maxBlack, numBlack, len, workingArray); + recurseCombinations(result, curIndex + 1, maxBlack, numBlack, len, workingArray); } - - } 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 ca9214416..f18fdab82 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperView.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperView.java @@ -1,48 +1,48 @@ -package edu.rpi.legup.puzzle.minesweeper; - -import edu.rpi.legup.controller.BoardController; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.puzzle.lightup.LightUpView; -import edu.rpi.legup.ui.boardview.GridBoardView; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.jetbrains.annotations.NotNull; - -import javax.imageio.ImageIO; -import java.awt.*; -import java.io.IOException; -import java.util.Objects; - -public class MinesweeperView extends GridBoardView { - - private static final Logger LOGGER = LogManager.getLogger(MinesweeperView.class.getName()); - public static final Image BOMB_IMAGE; - - static { - Image tempBombImage = null; - try { - tempBombImage = - ImageIO.read( - Objects.requireNonNull(ClassLoader.getSystemClassLoader() - .getResource("edu/rpi/legup/images/minesweeper/tiles/Bomb.png"))); - } catch (IOException e) { - LOGGER.error("Failed to open Minesweeper images"); - } - BOMB_IMAGE = tempBombImage; - } - - - public MinesweeperView(@NotNull MinesweeperBoard board) { - super(new BoardController(), new MinesweeperController(), board.getDimension()); - - for (PuzzleElement puzzleElement : board.getPuzzleElements()) { - final MinesweeperCell cell = (MinesweeperCell) puzzleElement; - final Point loc = cell.getLocation(); - final MinesweeperElementView elementView = new MinesweeperElementView(cell); - elementView.setIndex(cell.getIndex()); - elementView.setSize(elementSize); - elementView.setLocation(new Point(loc.x * elementSize.width, loc.y * elementSize.height)); - elementViews.add(elementView); - } - } -} +package edu.rpi.legup.puzzle.minesweeper; + +import edu.rpi.legup.controller.BoardController; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.ui.boardview.GridBoardView; +import java.awt.*; +import java.io.IOException; +import java.util.Objects; +import javax.imageio.ImageIO; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.NotNull; + +public class MinesweeperView extends GridBoardView { + + private static final Logger LOGGER = LogManager.getLogger(MinesweeperView.class.getName()); + public static final Image BOMB_IMAGE; + + static { + Image tempBombImage = null; + try { + tempBombImage = + ImageIO.read( + Objects.requireNonNull( + ClassLoader.getSystemClassLoader() + .getResource( + "edu/rpi/legup/images/minesweeper/tiles/Bomb.png"))); + } catch (IOException e) { + LOGGER.error("Failed to open Minesweeper images"); + } + BOMB_IMAGE = tempBombImage; + } + + public MinesweeperView(@NotNull MinesweeperBoard board) { + super(new BoardController(), new MinesweeperController(), board.getDimension()); + + for (PuzzleElement puzzleElement : board.getPuzzleElements()) { + final MinesweeperCell cell = (MinesweeperCell) puzzleElement; + final Point loc = cell.getLocation(); + final MinesweeperElementView elementView = new MinesweeperElementView(cell); + elementView.setIndex(cell.getIndex()); + elementView.setSize(elementSize); + elementView.setLocation( + new Point(loc.x * elementSize.width, loc.y * elementSize.height)); + elementViews.add(elementView); + } + } +} 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 index 90bd8fb90..78a5d320c 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/BombTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/BombTile.java @@ -1,8 +1,13 @@ package edu.rpi.legup.puzzle.minesweeper.elements; import edu.rpi.legup.model.elements.NonPlaceableElement; -public class BombTile extends NonPlaceableElement{ + +public class BombTile extends NonPlaceableElement { public BombTile() { - super("MINE-UNPL-0001", "Bomb", "A bomb", "edu/rpi/legup/images/minesweeper/tiles/Bomb.png"); + 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/EmptyTile.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/EmptyTile.java index dad1593ca..7149bfa6a 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/EmptyTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/EmptyTile.java @@ -5,6 +5,10 @@ public class EmptyTile extends PlaceableElement { public EmptyTile() { - super("MINE-PLAC-0002", "Empty", "An empty tile", "edu/rpi/legup/images/minesweeper/tiles/Empty.png"); + super( + "MINE-PLAC-0002", + "Empty", + "An empty tile", + "edu/rpi/legup/images/minesweeper/tiles/Empty.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 index b6d44d11a..0bbca81f9 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/FlagTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/FlagTile.java @@ -1,8 +1,13 @@ package edu.rpi.legup.puzzle.minesweeper.elements; import edu.rpi.legup.model.elements.PlaceableElement; -public class FlagTile extends PlaceableElement{ + +public class FlagTile extends PlaceableElement { public FlagTile() { - super("MINE-PLAC-0001", "Flag", "The flag", "edu/rpi/legup/images/nurikabe/tiles/BlackTile.png"); + 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/Unset.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/Unset.java index 62f5b824f..71ce1881f 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/Unset.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/Unset.java @@ -4,6 +4,10 @@ public class Unset extends NonPlaceableElement { public Unset() { - super("MINE-UNPL-0002", "Unset", "A blank tile", "edu/rpi/legup/images/fillapix/tiles/UnknownTile.png"); + super( + "MINE-UNPL-0002", + "Unset", + "A blank tile", + "edu/rpi/legup/images/fillapix/tiles/UnknownTile.png"); } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/UnsetTile.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/UnsetTile.java index 1899a4fd5..447e2840c 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/UnsetTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/UnsetTile.java @@ -5,7 +5,10 @@ public class UnsetTile extends NonPlaceableElement { public UnsetTile() { - super("MINE-UNPL-0002", "Unset", "An unset tile", "edu/rpi/legup/images/minesweeper/tiles/Unset.png"); + super( + "MINE-UNPL-0002", + "Unset", + "An unset tile", + "edu/rpi/legup/images/minesweeper/tiles/Unset.png"); } - } diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/BombOrFilledCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/BombOrFilledCaseRule.java index 4bba7ff32..a1ef97928 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/BombOrFilledCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/BombOrFilledCaseRule.java @@ -8,15 +8,15 @@ 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.MinesweeperTileType; - import java.util.ArrayList; import java.util.List; public class BombOrFilledCaseRule extends CaseRule { public BombOrFilledCaseRule() { - super("MINE-CASE-0001", "Bomb Or Filled", + 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"); } @@ -68,8 +68,10 @@ public String checkRuleRaw(TreeTransition transition) { + ": This case rule must have 1 modified cell for each case."; } - MinesweeperCell mod1 = (MinesweeperCell) case1.getBoard().getModifiedData().iterator().next(); - MinesweeperCell mod2 = (MinesweeperCell) case2.getBoard().getModifiedData().iterator().next(); + MinesweeperCell mod1 = + (MinesweeperCell) case1.getBoard().getModifiedData().iterator().next(); + MinesweeperCell mod2 = + (MinesweeperCell) case2.getBoard().getModifiedData().iterator().next(); if (!mod1.getLocation().equals(mod2.getLocation())) { return super.getInvalidUseOfRuleMessage() + ": This case rule must modify the same cell for each case."; diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/LessBombsThanFlagContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/LessBombsThanFlagContradictionRule.java index 0cc1f6324..76212f6da 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/LessBombsThanFlagContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/LessBombsThanFlagContradictionRule.java @@ -3,20 +3,16 @@ 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.nurikabe.NurikabeBoard; -import edu.rpi.legup.puzzle.nurikabe.NurikabeCell; -import edu.rpi.legup.puzzle.nurikabe.NurikabeType; -import edu.rpi.legup.puzzle.nurikabe.NurikabeUtilities; -import edu.rpi.legup.utility.DisjointSets; - -import java.util.Set; public class LessBombsThanFlagContradictionRule extends ContradictionRule { - private final String NO_CONTRADICTION_MESSAGE = "Does not contain a contradiction at this index"; + 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() { - super("MINE-CONT-0000", "Less Bombs Than Flag", + 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"); } @@ -26,7 +22,4 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { return null; } - - } - diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/SatisfyFlagCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/SatisfyFlagCaseRule.java index cb2250ddf..cecd5a588 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/SatisfyFlagCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/SatisfyFlagCaseRule.java @@ -7,14 +7,14 @@ import edu.rpi.legup.model.tree.TreeNode; import edu.rpi.legup.model.tree.TreeTransition; import edu.rpi.legup.puzzle.minesweeper.*; - import java.awt.*; import java.util.*; import java.util.List; -public class SatisfyFlagCaseRule extends CaseRule{ +public class SatisfyFlagCaseRule extends CaseRule { public SatisfyFlagCaseRule() { - super("MINE-CASE-0002", + 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/SatisfyFlag.jpg"); @@ -27,7 +27,9 @@ public CaseBoard getCaseBoard(Board board) { minesweeperBoard.setModifiable(false); for (PuzzleElement data : minesweeperBoard.getPuzzleElements()) { MinesweeperCell cell = (MinesweeperCell) data; - if (cell.getTileNumber() >= 0 && cell.getTileNumber() <= 8 && MinesweeperUtilities.hasEmptyAdjacent(minesweeperBoard, cell)) { + if (cell.getTileNumber() >= 0 + && cell.getTileNumber() <= 8 + && MinesweeperUtilities.hasEmptyAdjacent(minesweeperBoard, cell)) { caseBoard.addPickableElement(data); } } @@ -50,7 +52,8 @@ public ArrayList getCases(Board board, PuzzleElement puzzleElement) { int cellNumBomb = 0; int cellNumUnset = 0; ArrayList unsetCells = new ArrayList(); - ArrayList adjCells = MinesweeperUtilities.getAdjacentCells(minesweeperBoard, cell); + ArrayList adjCells = + MinesweeperUtilities.getAdjacentCells(minesweeperBoard, cell); for (MinesweeperCell adjCell : adjCells) { if (adjCell.getTileType() == MinesweeperTileType.BOMB) { cellNumBomb++; @@ -67,16 +70,16 @@ public ArrayList getCases(Board board, PuzzleElement puzzleElement) { // generate all cases as boolean expressions ArrayList combinations; - combinations = MinesweeperUtilities.getCombinations(cellMaxBlack - cellNumBomb, cellNumUnset); + combinations = + MinesweeperUtilities.getCombinations(cellMaxBlack - cellNumBomb, cellNumUnset); - for (int i=0; i < combinations.size(); i++) { + for (int i = 0; i < combinations.size(); i++) { Board case_ = board.copy(); - for (int j=0; j < combinations.get(i).length; j++) { + 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()); - } - else { + } else { cell.setCellType(MinesweeperTileData.empty()); } case_.addModifiedData(cell); @@ -105,14 +108,12 @@ public String checkRuleRaw(TreeTransition transition) { * If all the above is verified, then the transition is valid */ - /* ensure there are modified cells */ Set modCells = transition.getBoard().getModifiedData(); if (modCells.size() <= 0) { return super.getInvalidUseOfRuleMessage(); } - /* ensure modified cells occur within a 3X3 square */ int minVertLoc = Integer.MAX_VALUE, maxVertLoc = Integer.MIN_VALUE; int minHorzLoc = Integer.MAX_VALUE, maxHorzLoc = Integer.MIN_VALUE; @@ -135,13 +136,13 @@ public String checkRuleRaw(TreeTransition transition) { return super.getInvalidUseOfRuleMessage(); } - /* get the center of all possible 3X3 squares, * and collect all that have numbers */ MinesweeperBoard board = (MinesweeperBoard) transition.getParents().get(0).getBoard(); ArrayList possibleCenters = new ArrayList(); for (PuzzleElement modCell : modCells) { - ArrayList adjacentCells = MinesweeperUtilities.getAdjacentCells(board, (MinesweeperCell) modCell); + ArrayList adjacentCells = + MinesweeperUtilities.getAdjacentCells(board, (MinesweeperCell) modCell); for (MinesweeperCell cell : adjacentCells) { possibleCenters.add(cell); } @@ -153,14 +154,14 @@ public String checkRuleRaw(TreeTransition transition) { return super.getInvalidUseOfRuleMessage(); } - /* Now go through the remaining centers, and check if their combinations * match the transitions */ for (MinesweeperCell possibleCenter : possibleCenters) { int numBlack = 0; int numEmpty = 0; int maxBlack = possibleCenter.getTileNumber(); - for (MinesweeperCell adjCell : MinesweeperUtilities.getAdjacentCells(board, possibleCenter)) { + for (MinesweeperCell adjCell : + MinesweeperUtilities.getAdjacentCells(board, possibleCenter)) { if (adjCell.getTileType() == MinesweeperTileType.BOMB) { numBlack++; } @@ -173,7 +174,8 @@ public String checkRuleRaw(TreeTransition transition) { continue; } - ArrayList combinations = MinesweeperUtilities.getCombinations(maxBlack - numBlack, numEmpty); + ArrayList combinations = + MinesweeperUtilities.getCombinations(maxBlack - numBlack, numEmpty); if (combinations.size() != childTransitions.size()) { // not this center because combinations do not match transitions continue; @@ -189,11 +191,10 @@ public String checkRuleRaw(TreeTransition transition) { } boolean[] translatedModCells = new boolean[transModCells.size()]; - for (int i=0; i < transModCells.size(); i++) { + for (int i = 0; i < transModCells.size(); i++) { if (transModCells.get(i).getTileType() == MinesweeperTileType.BOMB) { translatedModCells[i] = true; - } - else { + } else { translatedModCells[i] = false; } } @@ -223,7 +224,6 @@ public String checkRuleRaw(TreeTransition transition) { return super.getInvalidUseOfRuleMessage(); } - @Override public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { return null; diff --git a/src/test/java/puzzles/minesweeper/MinesweeperUtilitiesTest.java b/src/test/java/puzzles/minesweeper/MinesweeperUtilitiesTest.java index 4b1b450c8..0e0112040 100644 --- a/src/test/java/puzzles/minesweeper/MinesweeperUtilitiesTest.java +++ b/src/test/java/puzzles/minesweeper/MinesweeperUtilitiesTest.java @@ -5,14 +5,13 @@ import edu.rpi.legup.puzzle.minesweeper.MinesweeperCell; import edu.rpi.legup.puzzle.minesweeper.MinesweeperUtilities; import edu.rpi.legup.save.InvalidFileFormatException; +import java.util.stream.Stream; import legup.MockGameBoardFacade; import legup.TestUtilities; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; -import java.util.stream.Stream; - public class MinesweeperUtilitiesTest { private static Minesweeper minesweeper; @@ -24,11 +23,10 @@ public static void setUp() { } @Test - public void getSurroundingCellsSizeThreeByThreeAtOneXOneTest() throws InvalidFileFormatException { + public void getSurroundingCellsSizeThreeByThreeAtOneXOneTest() + throws InvalidFileFormatException { - TestUtilities.importTestBoard( - "puzzles/minesweeper/utilities/3x3test", - minesweeper); + TestUtilities.importTestBoard("puzzles/minesweeper/utilities/3x3test", minesweeper); final MinesweeperBoard board = (MinesweeperBoard) minesweeper.getCurrentBoard(); MinesweeperCell cell = board.getCell(1, 1); @@ -40,11 +38,10 @@ public void getSurroundingCellsSizeThreeByThreeAtOneXOneTest() throws InvalidFil } @Test - public void getSurroundingCellsSizeThreeByThreeAtZeroXZeroTest() throws InvalidFileFormatException { + public void getSurroundingCellsSizeThreeByThreeAtZeroXZeroTest() + throws InvalidFileFormatException { - TestUtilities.importTestBoard( - "puzzles/minesweeper/utilities/3x3test", - minesweeper); + TestUtilities.importTestBoard("puzzles/minesweeper/utilities/3x3test", minesweeper); final MinesweeperBoard board = (MinesweeperBoard) minesweeper.getCurrentBoard(); MinesweeperCell cell = board.getCell(0, 0); @@ -56,11 +53,10 @@ public void getSurroundingCellsSizeThreeByThreeAtZeroXZeroTest() throws InvalidF } @Test - public void getSurroundingCellsSizeThreeByThreeAtZeroXOneTest() throws InvalidFileFormatException { + public void getSurroundingCellsSizeThreeByThreeAtZeroXOneTest() + throws InvalidFileFormatException { - TestUtilities.importTestBoard( - "puzzles/minesweeper/utilities/3x3test", - minesweeper); + TestUtilities.importTestBoard("puzzles/minesweeper/utilities/3x3test", minesweeper); final MinesweeperBoard board = (MinesweeperBoard) minesweeper.getCurrentBoard(); MinesweeperCell cell = board.getCell(0, 1); @@ -70,6 +66,4 @@ public void getSurroundingCellsSizeThreeByThreeAtZeroXOneTest() throws InvalidFi final long count = cells.count(); Assert.assertEquals(count, 5); } - - } From 62b3c712abfccae39e19b567b8cd6aa259513b24 Mon Sep 17 00:00:00 2001 From: vockek Date: Fri, 22 Mar 2024 18:30:51 -0400 Subject: [PATCH 17/21] Revert "Automated Java code formatting changes" This reverts commit f9d52a3eb0c5fe522beb33635816a2a3154c88ed. --- .../legup/puzzle/minesweeper/Minesweeper.java | 131 +++++----- .../puzzle/minesweeper/MinesweeperBoard.java | 72 ++--- .../puzzle/minesweeper/MinesweeperCell.java | 149 +++++------ .../minesweeper/MinesweeperCellFactory.java | 211 ++++++++------- .../minesweeper/MinesweeperController.java | 120 +++++---- .../MinesweeperElementIdentifiers.java | 38 +-- .../minesweeper/MinesweeperElementView.java | 153 +++++------ .../minesweeper/MinesweeperExporter.java | 88 +++---- .../minesweeper/MinesweeperImporter.java | 247 +++++++++--------- .../minesweeper/MinesweeperTileData.java | 213 ++++++++------- .../minesweeper/MinesweeperTileType.java | 38 ++- .../minesweeper/MinesweeperUtilities.java | 79 +++--- .../puzzle/minesweeper/MinesweeperView.java | 96 +++---- .../puzzle/minesweeper/elements/BombTile.java | 9 +- .../minesweeper/elements/EmptyTile.java | 6 +- .../puzzle/minesweeper/elements/FlagTile.java | 9 +- .../puzzle/minesweeper/elements/Unset.java | 8 +- .../minesweeper/elements/UnsetTile.java | 7 +- .../rules/BombOrFilledCaseRule.java | 12 +- .../LessBombsThanFlagContradictionRule.java | 17 +- .../rules/SatisfyFlagCaseRule.java | 42 +-- .../minesweeper/MinesweeperUtilitiesTest.java | 26 +- 22 files changed, 888 insertions(+), 883 deletions(-) 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..dd457f3d2 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/Minesweeper.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/Minesweeper.java @@ -1,64 +1,67 @@ -package edu.rpi.legup.puzzle.minesweeper; - -import edu.rpi.legup.model.Puzzle; -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.ContradictionRule; -import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public class Minesweeper extends Puzzle { - - public static final String NAME = "Minesweeper"; - - public Minesweeper() { - this.name = NAME; - this.importer = new MinesweeperImporter(this); - this.exporter = new MinesweeperExporter(this); - this.factory = MinesweeperCellFactory.INSTANCE; - } - - @Override - @Contract(pure = false) - public void initializeView() { - this.boardView = new MinesweeperView((MinesweeperBoard) this.currentBoard); - this.boardView.setBoard(this.currentBoard); - addBoardListener(boardView); - } - - @Override - @Contract("_ -> null") - public @Nullable Board generatePuzzle(int difficulty) { - return null; - } - - @Override - @Contract(pure = true) - public boolean isBoardComplete(@NotNull Board board) { - MinesweeperBoard minesweeperBoard = (MinesweeperBoard) board; - - for (ContradictionRule rule : contradictionRules) { - if (rule.checkContradiction(minesweeperBoard) == null) { - return false; - } - } - for (PuzzleElement data : minesweeperBoard.getPuzzleElements()) { - final MinesweeperCell cell = (MinesweeperCell) data; - if (cell.getData().equals(MinesweeperTileData.empty())) { - return false; - } - } - return true; - } - - @Override - @Contract(pure = true) - public void onBoardChange(@NotNull Board board) {} - - @Override - @Contract(pure = true) - public boolean isValidDimensions(int rows, int columns) { - return rows >= 1 && columns >= 1; - } -} +package edu.rpi.legup.puzzle.minesweeper; + +import edu.rpi.legup.model.Puzzle; +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.ContradictionRule; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class Minesweeper extends Puzzle { + + public static final String NAME = "Minesweeper"; + + public Minesweeper() { + this.name = NAME; + this.importer = new MinesweeperImporter(this); + this.exporter = new MinesweeperExporter(this); + this.factory = MinesweeperCellFactory.INSTANCE; + } + + @Override + @Contract(pure = false) + public void initializeView() { + this.boardView = new MinesweeperView((MinesweeperBoard) this.currentBoard); + this.boardView.setBoard(this.currentBoard); + addBoardListener(boardView); + } + + @Override + @Contract("_ -> null") + public @Nullable Board generatePuzzle(int difficulty) { + return null; + } + + @Override + @Contract(pure = true) + public boolean isBoardComplete(@NotNull Board board) { + MinesweeperBoard minesweeperBoard = (MinesweeperBoard) board; + + for (ContradictionRule rule : contradictionRules) { + if (rule.checkContradiction(minesweeperBoard) == null) { + return false; + } + } + for (PuzzleElement data : minesweeperBoard.getPuzzleElements()) { + final MinesweeperCell cell = (MinesweeperCell) data; + if (cell.getData().equals(MinesweeperTileData.empty())) { + return false; + } + } + return true; + } + + @Override + @Contract(pure = true) + public void onBoardChange(@NotNull Board board) { + + } + + @Override + @Contract(pure = true) + public boolean isValidDimensions(int rows, int columns) { + return rows >= 1 && columns >= 1; + } + +} 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..ea6f560e1 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperBoard.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperBoard.java @@ -1,36 +1,36 @@ -package edu.rpi.legup.puzzle.minesweeper; - -import edu.rpi.legup.model.gameboard.GridBoard; - -public class MinesweeperBoard extends GridBoard { - - public MinesweeperBoard(int width, int height) { - super(width, height); - } - - public MinesweeperBoard(int size) { - super(size); - } - - @Override - public MinesweeperCell getCell(int x, int y) { - return (MinesweeperCell) super.getCell(x, y); - } - - /** - * Performs a deep copy of the Board - * - * @return a new copy of the board that is independent of this one - */ - @Override - public MinesweeperBoard copy() { - MinesweeperBoard newMinesweeperBoard = - new MinesweeperBoard(this.dimension.width, this.dimension.height); - for (int x = 0; x < this.dimension.width; x++) { - for (int y = 0; y < this.dimension.height; y++) { - newMinesweeperBoard.setCell(x, y, getCell(x, y).copy()); - } - } - return newMinesweeperBoard; - } -} +package edu.rpi.legup.puzzle.minesweeper; + +import edu.rpi.legup.model.gameboard.GridBoard; + +public class MinesweeperBoard extends GridBoard { + + public MinesweeperBoard(int width, int height) { + super(width, height); + } + + public MinesweeperBoard(int size) { + super(size); + } + + @Override + public MinesweeperCell getCell(int x, int y) { + return (MinesweeperCell) super.getCell(x, y); + } + + + /** + * Performs a deep copy of the Board + * + * @return a new copy of the board that is independent of this one + */ + @Override + public MinesweeperBoard copy() { + MinesweeperBoard newMinesweeperBoard = new MinesweeperBoard(this.dimension.width, this.dimension.height); + for (int x = 0; x < this.dimension.width; x++) { + for (int y = 0; y < this.dimension.height; y++) { + newMinesweeperBoard.setCell(x, y, getCell(x, y).copy()); + } + } + 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..6770e5263 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperCell.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperCell.java @@ -1,73 +1,76 @@ -package edu.rpi.legup.puzzle.minesweeper; - -import edu.rpi.legup.model.elements.Element; -import edu.rpi.legup.model.gameboard.GridCell; -import java.awt.*; -import java.awt.event.MouseEvent; -import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; - -public class MinesweeperCell extends GridCell { - - public MinesweeperCell(@NotNull MinesweeperTileData value, @NotNull Point location) { - super(value, location); - } - - public @NotNull MinesweeperTileType getTileType() { - return super.data.type(); - } - - public @NotNull int getTileNumber() { - return super.data.data(); - } - - @Override - @Contract(pure = false) - /** 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(); - break; - } - case MinesweeperElementIdentifiers.FLAG -> { - final int currentData = super.data.data(); - switch (event.getButton()) { - case MouseEvent.BUTTON1 -> { - if (currentData >= 8) { - this.data = MinesweeperTileData.empty(); - return; - } - this.data = MinesweeperTileData.flag(currentData + 1); - return; - } - case MouseEvent.BUTTON2, MouseEvent.BUTTON3 -> { - if (currentData <= 0) { - this.data = MinesweeperTileData.empty(); - return; - } - this.data = MinesweeperTileData.flag(currentData - 1); - return; - } - } - } - default -> { - this.data = MinesweeperTileData.empty(); - } - } - } - - public void setCellType(MinesweeperTileData type) { - this.data = type; - } - - @Override - @Contract(pure = true) - public @NotNull MinesweeperCell copy() { - MinesweeperCell copy = new MinesweeperCell(data, (Point) location.clone()); - copy.setIndex(index); - copy.setModifiable(isModifiable); - copy.setGiven(isGiven); - return copy; - } -} +package edu.rpi.legup.puzzle.minesweeper; + +import edu.rpi.legup.model.elements.Element; +import edu.rpi.legup.model.gameboard.GridCell; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; + +import java.awt.*; +import java.awt.event.MouseEvent; + +public class MinesweeperCell extends GridCell { + + public MinesweeperCell(@NotNull MinesweeperTileData value, @NotNull Point location) { + super(value, location); + } + + public @NotNull MinesweeperTileType getTileType() { + return super.data.type(); + } + + public @NotNull int getTileNumber() { + return super.data.data(); + } + + @Override + @Contract(pure = false) + /** + * 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(); + break; + } + case MinesweeperElementIdentifiers.FLAG -> { + final int currentData = super.data.data(); + switch (event.getButton()) { + case MouseEvent.BUTTON1 -> { + if (currentData >= 8) { + this.data = MinesweeperTileData.empty(); + return; + } + this.data = MinesweeperTileData.flag(currentData + 1); + return; + } + case MouseEvent.BUTTON2, MouseEvent.BUTTON3 -> { + if (currentData <= 0) { + this.data = MinesweeperTileData.empty(); + return; + } + this.data = MinesweeperTileData.flag(currentData - 1); + return; + } + } + } + default -> { + this.data = MinesweeperTileData.empty(); + } + } + } + + public void setCellType(MinesweeperTileData type){ + this.data = type; + } + + @Override + @Contract(pure = true) + public @NotNull MinesweeperCell copy() { + MinesweeperCell copy = new MinesweeperCell(data, (Point) location.clone()); + copy.setIndex(index); + copy.setModifiable(isModifiable); + copy.setGiven(isGiven); + return copy; + } +} 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..45957cb82 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperCellFactory.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperCellFactory.java @@ -1,101 +1,110 @@ -package edu.rpi.legup.puzzle.minesweeper; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.ElementFactory; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.save.InvalidFileFormatException; -import java.awt.*; -import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NamedNodeMap; -import org.w3c.dom.Node; - -public class MinesweeperCellFactory extends ElementFactory { - - /** The key of the data used in {@link NamedNodeMap} */ - private static final String DATA_ATTRIBUTE = "data"; - - /** The key of the x position used in {@link NamedNodeMap} */ - private static final String X_ATTRIBUTE = "x"; - - /** The key of the y position used in {@link NamedNodeMap} */ - private static final String Y_ATTRIBUTE = "y"; - - private MinesweeperCellFactory() {} - - public static final MinesweeperCellFactory INSTANCE = new MinesweeperCellFactory(); - - /** - * @param node node that represents the puzzleElement - * @param board Board to use to verify the newly created {@link MinesweeperCell} is valid - * @return a new {@link MinesweeperCell} - * @throws InvalidFileFormatException If the node name is not "cell" - * @throws NumberFormatException If the {@link #X_ATTRIBUTE} or {@link #Y_ATTRIBUTE} is not a - * number - * @throws NullPointerException If one of {@link #DATA_ATTRIBUTE}, {@link #X_ATTRIBUTE} or - * {@link #Y_ATTRIBUTE} does not exist. - */ - @Override - @Contract(pure = false) - public @NotNull PuzzleElement importCell( - @NotNull Node node, @NotNull Board board) throws InvalidFileFormatException { - try { - if (!node.getNodeName().equalsIgnoreCase("cell")) { - throw new InvalidFileFormatException( - "Minesweeper Factory: unknown puzzleElement puzzleElement"); - } - - MinesweeperBoard minesweeperBoard = (MinesweeperBoard) board; - final int width = minesweeperBoard.getWidth(); - final int height = minesweeperBoard.getHeight(); - - final NamedNodeMap attributeList = node.getAttributes(); - final int value = - Integer.parseInt(attributeList.getNamedItem(DATA_ATTRIBUTE).getNodeValue()); - final int x = Integer.parseInt(attributeList.getNamedItem(X_ATTRIBUTE).getNodeValue()); - final int y = Integer.parseInt(attributeList.getNamedItem(Y_ATTRIBUTE).getNodeValue()); - if (x >= width || y >= height) { - throw new InvalidFileFormatException( - "Minesweeper Factory: cell location out of bounds"); - } - if (value < -2) { - throw new InvalidFileFormatException("Minesweeper Factory: cell unknown value"); - } - final MinesweeperCell cell = - new MinesweeperCell(MinesweeperTileData.fromData(value), new Point(x, y)); - cell.setIndex(y * height + x); - return cell; - } catch (NumberFormatException e) { - throw new InvalidFileFormatException( - "Minesweeper Factory: unknown value where integer expected"); - } catch (NullPointerException e) { - throw new InvalidFileFormatException( - "Minesweeper Factory: could not find attribute(s)"); - } - } - - /** - * @param document Document used to create the element - * @param puzzleElement PuzzleElement cell - * @return a {@link Element} that contains the {@link #DATA_ATTRIBUTE}, {@link #X_ATTRIBUTE}, - * and {@link #Y_ATTRIBUTE} - */ - @Override - @Contract(pure = false) - public @NotNull Element exportCell( - @NotNull Document document, - @SuppressWarnings("rawtypes") @NotNull PuzzleElement puzzleElement) { - org.w3c.dom.Element cellElement = document.createElement("cell"); - - MinesweeperCell cell = (MinesweeperCell) puzzleElement; - Point loc = cell.getLocation(); - - cellElement.setAttribute(DATA_ATTRIBUTE, String.valueOf(cell.getData())); - cellElement.setAttribute(X_ATTRIBUTE, String.valueOf(loc.x)); - cellElement.setAttribute(Y_ATTRIBUTE, String.valueOf(loc.y)); - - return cellElement; - } -} +package edu.rpi.legup.puzzle.minesweeper; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.ElementFactory; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.save.InvalidFileFormatException; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; + +import java.awt.*; + +public class MinesweeperCellFactory extends ElementFactory { + + /** + * The key of the data used in {@link NamedNodeMap} + */ + private static final String DATA_ATTRIBUTE = "data"; + /** + * The key of the x position used in {@link NamedNodeMap} + */ + private static final String X_ATTRIBUTE = "x"; + /** + * The key of the y position used in {@link NamedNodeMap} + */ + private static final String Y_ATTRIBUTE = "y"; + + + private MinesweeperCellFactory() { + } + + public static final MinesweeperCellFactory INSTANCE = new MinesweeperCellFactory(); + + /** + * + * @param node node that represents the puzzleElement + * @param board Board to use to verify the newly created {@link MinesweeperCell} + * is valid + * @return a new {@link MinesweeperCell} + * @throws InvalidFileFormatException If the node name is not "cell" + * @throws NumberFormatException If the {@link #X_ATTRIBUTE} or {@link #Y_ATTRIBUTE} + * is not a number + * @throws NullPointerException If one of {@link #DATA_ATTRIBUTE}, {@link #X_ATTRIBUTE} or {@link #Y_ATTRIBUTE} + * does not exist. + */ + @Override + @Contract(pure = false) + public @NotNull PuzzleElement importCell( + @NotNull Node node, + @NotNull Board board + ) throws InvalidFileFormatException { + try { + if (!node.getNodeName().equalsIgnoreCase("cell")) { + throw new InvalidFileFormatException("Minesweeper Factory: unknown puzzleElement puzzleElement"); + } + + MinesweeperBoard minesweeperBoard = (MinesweeperBoard) board; + final int width = minesweeperBoard.getWidth(); + final int height = minesweeperBoard.getHeight(); + + final NamedNodeMap attributeList = node.getAttributes(); + final int value = Integer.parseInt(attributeList.getNamedItem(DATA_ATTRIBUTE).getNodeValue()); + final int x = Integer.parseInt(attributeList.getNamedItem(X_ATTRIBUTE).getNodeValue()); + final int y = Integer.parseInt(attributeList.getNamedItem(Y_ATTRIBUTE).getNodeValue()); + if (x >= width || y >= height) { + throw new InvalidFileFormatException("Minesweeper Factory: cell location out of bounds"); + } + if (value < -2) { + throw new InvalidFileFormatException("Minesweeper Factory: cell unknown value"); + } + final MinesweeperCell cell = new MinesweeperCell(MinesweeperTileData.fromData(value), new Point(x, y)); + cell.setIndex(y * height + x); + return cell; + } + catch (NumberFormatException e) { + throw new InvalidFileFormatException("Minesweeper Factory: unknown value where integer expected"); + } + catch (NullPointerException e) { + throw new InvalidFileFormatException("Minesweeper Factory: could not find attribute(s)"); + } + } + + /** + * + * @param document Document used to create the element + * @param puzzleElement PuzzleElement cell + * @return a {@link Element} that contains the {@link #DATA_ATTRIBUTE}, + * {@link #X_ATTRIBUTE}, and {@link #Y_ATTRIBUTE} + */ + @Override + @Contract(pure = false) + public @NotNull Element exportCell( + @NotNull Document document, + @SuppressWarnings("rawtypes") @NotNull PuzzleElement puzzleElement + ) { + org.w3c.dom.Element cellElement = document.createElement("cell"); + + MinesweeperCell cell = (MinesweeperCell) puzzleElement; + Point loc = cell.getLocation(); + + cellElement.setAttribute(DATA_ATTRIBUTE, String.valueOf(cell.getData())); + cellElement.setAttribute(X_ATTRIBUTE, String.valueOf(loc.x)); + cellElement.setAttribute(Y_ATTRIBUTE, String.valueOf(loc.y)); + + return cellElement; + } +} 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..7289c349c 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperController.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperController.java @@ -1,57 +1,63 @@ -package edu.rpi.legup.puzzle.minesweeper; - -import edu.rpi.legup.controller.ElementController; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import java.awt.event.MouseEvent; -import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; - -public class MinesweeperController extends ElementController { - - /** - * If the button clicked was button 1, then {@link MinesweeperTileData#fromData(int)} is called - * with a value of {@code current.data() + 1}. If the button clicked was button 2 or 3, then - * {@link MinesweeperTileData#fromData(int)} is called with a value of {@code currentData() - 1} - * Otherwise {@link MinesweeperTileData#empty()} is returned. - * - * @param event The user's click data - * @param current The current data at the cell they clicked on - * @return A different cell data depending on what the current data is - */ - @Contract(pure = true) - 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(); - }; - } - - /** - * @see #getNewCellDataOnClick(MouseEvent, MinesweeperTileData) - * @param event The user's click data - * @param data The current data at the cell they clicked on - */ - @Override - @SuppressWarnings("unchecked") - @Contract(pure = false) - public void changeCell( - @NotNull MouseEvent event, @SuppressWarnings("rawtypes") @NotNull PuzzleElement data) { - final MinesweeperCell cell = (MinesweeperCell) data; - if (event.isControlDown()) { - this.boardView - .getSelectionPopupMenu() - .show( - boardView, - this.boardView.getCanvas().getX() + event.getX(), - this.boardView.getCanvas().getY() + event.getY()); - return; - } - - final MinesweeperTileData newData = getNewCellDataOnClick(event, cell.getData()); - data.setData(newData); - } -} +package edu.rpi.legup.puzzle.minesweeper; + +import edu.rpi.legup.controller.ElementController; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; + +import java.awt.event.MouseEvent; + +public class MinesweeperController extends ElementController { + + /** + * If the button clicked was button 1, then {@link MinesweeperTileData#fromData(int)} + * is called with a value of {@code current.data() + 1}. + * If the button clicked was button 2 or 3, then {@link MinesweeperTileData#fromData(int)} + * is called with a value of {@code currentData() - 1} + * Otherwise {@link MinesweeperTileData#empty()} is returned. + * + * @param event The user's click data + * @param current The current data at the cell they clicked on + * @return A different cell data depending on what the current data is + */ + @Contract(pure = true) + 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(); + }; + } + + /** + * @see #getNewCellDataOnClick(MouseEvent, MinesweeperTileData) + * @param event The user's click data + * @param data The current data at the cell they clicked on + */ + @Override + @SuppressWarnings("unchecked") + @Contract(pure = false) + public void changeCell( + @NotNull MouseEvent event, + @SuppressWarnings("rawtypes") @NotNull PuzzleElement data + ) { + final MinesweeperCell cell = (MinesweeperCell) data; + if (event.isControlDown()) { + this.boardView.getSelectionPopupMenu().show( + boardView, + this.boardView.getCanvas().getX() + event.getX(), + this.boardView.getCanvas().getY() + event.getY() + ); + return; + } + + final MinesweeperTileData newData = getNewCellDataOnClick(event, cell.getData()); + data.setData(newData); + } +} + 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..1b626a33b 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperElementIdentifiers.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperElementIdentifiers.java @@ -1,16 +1,22 @@ -package edu.rpi.legup.puzzle.minesweeper; - -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 empty Minesweeper elements */ - public static final String EMPTY = "MINESWEEPER-EMPTY"; - - /** ID for flag Minesweeper elements */ - public static final String FLAG = "MINESWEEPER-FLAG"; -} +package edu.rpi.legup.puzzle.minesweeper; + +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 empty Minesweeper elements + */ + public static final String EMPTY = "MINESWEEPER-EMPTY"; + /** + * ID for flag Minesweeper elements + */ + public static final String FLAG = "MINESWEEPER-FLAG"; + +} 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 fd5d73928..e9658a077 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperElementView.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperElementView.java @@ -1,76 +1,77 @@ -package edu.rpi.legup.puzzle.minesweeper; - -import edu.rpi.legup.ui.boardview.GridElementView; -import java.awt.*; -import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; - -public class MinesweeperElementView extends GridElementView { - - private static final Font FONT = new Font("TimesRoman", Font.BOLD, 16); - private static final Color FONT_COLOR = Color.BLACK; - - public MinesweeperElementView(@NotNull MinesweeperCell cell) { - super(cell); - } - - @Override - public @NotNull MinesweeperCell getPuzzleElement() { - return (MinesweeperCell) super.getPuzzleElement(); - } - - @Override - @SuppressWarnings("Duplicates") - @Contract(pure = true) - public void drawElement(@NotNull Graphics2D graphics2D) { - final MinesweeperCell cell = (MinesweeperCell) puzzleElement; - final MinesweeperTileType type = cell.getTileType(); - if (type == MinesweeperTileType.FLAG) { - 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); - - 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(); - graphics2D.drawString(value, xText, yText); - return; - } - if (type == MinesweeperTileType.UNSET) { - graphics2D.setStroke(new BasicStroke(1)); - graphics2D.setColor(Color.BLACK); - graphics2D.drawRect(location.x, location.y, size.width, size.height); - graphics2D.setColor(Color.DARK_GRAY); - graphics2D.fillRect(location.x, location.y, size.width, size.height); - return; - } - if (type == MinesweeperTileType.EMPTY) { - graphics2D.setStroke(new BasicStroke(1)); - graphics2D.setColor(Color.BLACK); - graphics2D.drawRect(location.x, location.y, size.width, size.height); - graphics2D.setColor(Color.GRAY); - graphics2D.fillRect(location.x, location.y, size.width, size.height); - } - if (type == MinesweeperTileType.BOMB) { - graphics2D.setColor(Color.LIGHT_GRAY); - graphics2D.fillRect(location.x, location.y, size.width, size.height); - graphics2D.drawImage( - MinesweeperView.BOMB_IMAGE, - location.x, - location.y, - size.width, - size.height, - Color.GRAY, - null); - graphics2D.setColor(Color.BLACK); - graphics2D.drawRect(location.x, location.y, size.width, size.height); - } - } -} +package edu.rpi.legup.puzzle.minesweeper; + +import edu.rpi.legup.puzzle.lightup.LightUpView; +import edu.rpi.legup.ui.boardview.GridElementView; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; + +import java.awt.*; + +public class MinesweeperElementView extends GridElementView { + + private static final Font FONT = new Font("TimesRoman", Font.BOLD, 16); + private static final Color FONT_COLOR = Color.BLACK; + + public MinesweeperElementView(@NotNull MinesweeperCell cell) { + super(cell); + } + + @Override + public @NotNull MinesweeperCell getPuzzleElement() { + return (MinesweeperCell) super.getPuzzleElement(); + } + + @Override + @SuppressWarnings("Duplicates") + @Contract(pure = true) + public void drawElement(@NotNull Graphics2D graphics2D) { + final MinesweeperCell cell = (MinesweeperCell) puzzleElement; + final MinesweeperTileType type = cell.getTileType(); + if (type == MinesweeperTileType.FLAG) { + 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); + + 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(); + graphics2D.drawString(value, xText, yText); + return; + } + if (type == MinesweeperTileType.UNSET) { + graphics2D.setStroke(new BasicStroke(1)); + graphics2D.setColor(Color.BLACK); + graphics2D.drawRect(location.x, location.y, size.width, size.height); + graphics2D.setColor(Color.DARK_GRAY); + graphics2D.fillRect(location.x, location.y, size.width, size.height); + return; + } + if (type == MinesweeperTileType.EMPTY) { + graphics2D.setStroke(new BasicStroke(1)); + graphics2D.setColor(Color.BLACK); + graphics2D.drawRect(location.x, location.y, size.width, size.height); + graphics2D.setColor(Color.GRAY); + graphics2D.fillRect(location.x, location.y, size.width, size.height); + } + if (type == MinesweeperTileType.BOMB) { + graphics2D.setColor(Color.LIGHT_GRAY); + graphics2D.fillRect(location.x, location.y, size.width, size.height); + graphics2D.drawImage( + MinesweeperView.BOMB_IMAGE, + location.x, + location.y, + size.width, + size.height, + Color.GRAY, + null); + graphics2D.setColor(Color.BLACK); + graphics2D.drawRect(location.x, location.y, size.width, size.height); + } + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperExporter.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperExporter.java index 8ae9c5a9a..0a4f69fd6 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperExporter.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperExporter.java @@ -1,44 +1,44 @@ -package edu.rpi.legup.puzzle.minesweeper; - -import edu.rpi.legup.model.Puzzle; -import edu.rpi.legup.model.PuzzleExporter; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; -import org.w3c.dom.Document; -import org.w3c.dom.Element; - -public class MinesweeperExporter extends PuzzleExporter { - - public MinesweeperExporter(@NotNull Puzzle puzzle) { - super(puzzle); - } - - @Override - @Contract(pure = true) - protected @NotNull Element createBoardElement(@NotNull Document newDocument) { - MinesweeperBoard board; - if (puzzle.getTree() != null) { - board = (MinesweeperBoard) puzzle.getTree().getRootNode().getBoard(); - } else { - board = (MinesweeperBoard) puzzle.getBoardView().getBoard(); - } - - final org.w3c.dom.Element boardElement = newDocument.createElement("board"); - boardElement.setAttribute("width", String.valueOf(board.getWidth())); - boardElement.setAttribute("height", String.valueOf(board.getHeight())); - - final org.w3c.dom.Element cellsElement = newDocument.createElement("cells"); - for (PuzzleElement puzzleElement : board.getPuzzleElements()) { - final MinesweeperCell cell = (MinesweeperCell) puzzleElement; - if (!MinesweeperTileData.unset().equals(cell.getData())) { - final org.w3c.dom.Element cellElement = - puzzle.getFactory().exportCell(newDocument, puzzleElement); - cellsElement.appendChild(cellElement); - } - } - - boardElement.appendChild(cellsElement); - return boardElement; - } -} +package edu.rpi.legup.puzzle.minesweeper; + +import edu.rpi.legup.model.Puzzle; +import edu.rpi.legup.model.PuzzleExporter; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +public class MinesweeperExporter extends PuzzleExporter { + + public MinesweeperExporter(@NotNull Puzzle puzzle) { + super(puzzle); + } + + @Override + @Contract(pure = true) + protected @NotNull Element createBoardElement(@NotNull Document newDocument) { + MinesweeperBoard board; + if (puzzle.getTree() != null) { + board = (MinesweeperBoard) puzzle.getTree().getRootNode().getBoard(); + } + else { + board = (MinesweeperBoard) puzzle.getBoardView().getBoard(); + } + + final org.w3c.dom.Element boardElement = newDocument.createElement("board"); + boardElement.setAttribute("width", String.valueOf(board.getWidth())); + boardElement.setAttribute("height", String.valueOf(board.getHeight())); + + final org.w3c.dom.Element cellsElement = newDocument.createElement("cells"); + for (PuzzleElement puzzleElement : board.getPuzzleElements()) { + final MinesweeperCell cell = (MinesweeperCell) puzzleElement; + if (!MinesweeperTileData.unset().equals(cell.getData())) { + final org.w3c.dom.Element cellElement = puzzle.getFactory().exportCell(newDocument, puzzleElement); + cellsElement.appendChild(cellElement); + } + } + + boardElement.appendChild(cellsElement); + return boardElement; + } +} 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..8dc7037f9 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperImporter.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperImporter.java @@ -1,128 +1,119 @@ -package edu.rpi.legup.puzzle.minesweeper; - -import edu.rpi.legup.model.PuzzleImporter; -import edu.rpi.legup.save.InvalidFileFormatException; -import java.awt.*; -import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - -public class MinesweeperImporter extends PuzzleImporter { - - public MinesweeperImporter(@NotNull Minesweeper minesweeper) { - super(minesweeper); - } - - @Override - @Contract(pure = true, value = "-> true") - public boolean acceptsRowsAndColumnsInput() { - return true; - } - - @Override - @Contract(pure = true, value = "-> false") - public boolean acceptsTextInput() { - return false; - } - - @Override - @Contract(pure = false) - public void initializeBoard(int rows, int columns) { - MinesweeperBoard minesweeperBoard = new MinesweeperBoard(columns, rows); - - for (int y = 0; y < rows; y++) { - for (int x = 0; x < columns; x++) { - MinesweeperCell cell = - new MinesweeperCell(MinesweeperTileData.unset(), new Point(x, y)); - cell.setIndex(y * columns + x); - cell.setModifiable(true); - minesweeperBoard.setCell(x, y, cell); - } - } - puzzle.setCurrentBoard(minesweeperBoard); - } - - @Override - @Contract(pure = false) - public void initializeBoard(@NotNull Node node) throws InvalidFileFormatException { - try { - if (!node.getNodeName().equalsIgnoreCase("board")) { - throw new InvalidFileFormatException( - "Minesweeper Importer: cannot find board puzzleElement"); - } - final Element boardElement = (Element) node; - if (boardElement.getElementsByTagName("cells").getLength() == 0) { - throw new InvalidFileFormatException( - "Minesweeper Importer: no puzzleElement found for board"); - } - final Element dataElement = - (Element) boardElement.getElementsByTagName("cells").item(0); - final NodeList elementDataList = dataElement.getElementsByTagName("cell"); - - final MinesweeperBoard minesweeperBoard = getMinesweeperBoard(boardElement); - - final int width = minesweeperBoard.getWidth(); - final int height = minesweeperBoard.getHeight(); - - for (int i = 0; i < elementDataList.getLength(); i++) { - final MinesweeperCell cell = - (MinesweeperCell) - puzzle.getFactory() - .importCell(elementDataList.item(i), minesweeperBoard); - final Point loc = cell.getLocation(); - if (MinesweeperTileData.unset().equals(cell.getData())) { - cell.setModifiable(false); - cell.setGiven(true); - } - minesweeperBoard.setCell(loc.x, loc.y, cell); - } - - for (int y = 0; y < height; y++) { - for (int x = 0; x < width; x++) { - if (minesweeperBoard.getCell(x, y) == null) { - final MinesweeperCell cell = - new MinesweeperCell(MinesweeperTileData.unset(), new Point(x, y)); - cell.setIndex(y * height + x); - cell.setModifiable(true); - minesweeperBoard.setCell(x, y, cell); - } - } - } - puzzle.setCurrentBoard(minesweeperBoard); - } catch (NumberFormatException e) { - throw new InvalidFileFormatException( - "Minesweeper Importer: unknown value where integer expected"); - } - } - - @Contract(pure = true) - private static @NotNull MinesweeperBoard getMinesweeperBoard(@NotNull Element boardElement) - throws InvalidFileFormatException { - MinesweeperBoard minesweeperBoard = null; - if (!boardElement.getAttribute("size").isEmpty()) { - final int size = Integer.parseInt(boardElement.getAttribute("size")); - minesweeperBoard = new MinesweeperBoard(size); - } else { - if (!boardElement.getAttribute("width").isEmpty() - && !boardElement.getAttribute("height").isEmpty()) { - final int width = Integer.parseInt(boardElement.getAttribute("width")); - final int height = Integer.parseInt(boardElement.getAttribute("height")); - minesweeperBoard = new MinesweeperBoard(width, height); - } - } - - if (minesweeperBoard == null) { - throw new InvalidFileFormatException("Minesweeper Importer: invalid board dimensions"); - } - return minesweeperBoard; - } - - @Override - @Contract(value = "_ -> fail", pure = false) - public void initializeBoard(@NotNull String[] statements) - throws UnsupportedOperationException, IllegalArgumentException { - throw new UnsupportedOperationException("Minesweeper does not support text input."); - } -} +package edu.rpi.legup.puzzle.minesweeper; + +import edu.rpi.legup.model.PuzzleImporter; +import edu.rpi.legup.save.InvalidFileFormatException; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import java.awt.*; + +public class MinesweeperImporter extends PuzzleImporter { + + public MinesweeperImporter(@NotNull Minesweeper minesweeper) { + super(minesweeper); + } + + @Override + @Contract(pure = true, value = "-> true") + public boolean acceptsRowsAndColumnsInput() { + return true; + } + + @Override + @Contract(pure = true, value = "-> false") + public boolean acceptsTextInput() { + return false; + } + + @Override + @Contract(pure = false) + public void initializeBoard(int rows, int columns) { + MinesweeperBoard minesweeperBoard = new MinesweeperBoard(columns, rows); + + for (int y = 0; y < rows; y++) { + for (int x = 0; x < columns; x++) { + MinesweeperCell cell = new MinesweeperCell(MinesweeperTileData.unset(), new Point(x, y)); + cell.setIndex(y * columns + x); + cell.setModifiable(true); + minesweeperBoard.setCell(x, y, cell); + } + } + puzzle.setCurrentBoard(minesweeperBoard); + } + + @Override + @Contract(pure = false) + public void initializeBoard(@NotNull Node node) throws InvalidFileFormatException { + try { + if (!node.getNodeName().equalsIgnoreCase("board")) { + throw new InvalidFileFormatException("Minesweeper Importer: cannot find board puzzleElement"); + } + final Element boardElement = (Element) node; + if (boardElement.getElementsByTagName("cells").getLength() == 0) { + throw new InvalidFileFormatException("Minesweeper Importer: no puzzleElement found for board"); + } + final Element dataElement = (Element) boardElement.getElementsByTagName("cells").item(0); + final NodeList elementDataList = dataElement.getElementsByTagName("cell"); + + final MinesweeperBoard minesweeperBoard = getMinesweeperBoard(boardElement); + + final int width = minesweeperBoard.getWidth(); + final int height = minesweeperBoard.getHeight(); + + for (int i = 0; i < elementDataList.getLength(); i++) { + final MinesweeperCell cell = (MinesweeperCell) puzzle.getFactory().importCell(elementDataList.item(i), minesweeperBoard); + final Point loc = cell.getLocation(); + if (MinesweeperTileData.unset().equals(cell.getData())) { + cell.setModifiable(false); + cell.setGiven(true); + } + minesweeperBoard.setCell(loc.x, loc.y, cell); + } + + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + if (minesweeperBoard.getCell(x, y) == null) { + final MinesweeperCell cell = new MinesweeperCell(MinesweeperTileData.unset(), new Point(x, y)); + cell.setIndex(y * height + x); + cell.setModifiable(true); + minesweeperBoard.setCell(x, y, cell); + } + } + } + puzzle.setCurrentBoard(minesweeperBoard); + } + catch (NumberFormatException e) { + throw new InvalidFileFormatException("Minesweeper Importer: unknown value where integer expected"); + } + } + + @Contract(pure = true) + private static @NotNull MinesweeperBoard getMinesweeperBoard(@NotNull Element boardElement) throws InvalidFileFormatException { + MinesweeperBoard minesweeperBoard = null; + if (!boardElement.getAttribute("size").isEmpty()) { + final int size = Integer.parseInt(boardElement.getAttribute("size")); + minesweeperBoard = new MinesweeperBoard(size); + } + else { + if (!boardElement.getAttribute("width").isEmpty() && !boardElement.getAttribute("height").isEmpty()) { + final int width = Integer.parseInt(boardElement.getAttribute("width")); + final int height = Integer.parseInt(boardElement.getAttribute("height")); + minesweeperBoard = new MinesweeperBoard(width, height); + } + } + + if (minesweeperBoard == null) { + throw new InvalidFileFormatException("Minesweeper Importer: invalid board dimensions"); + } + return minesweeperBoard; + } + + @Override + @Contract(value = "_ -> fail", pure = false) + public void initializeBoard(@NotNull String[] statements) throws UnsupportedOperationException, IllegalArgumentException { + throw new UnsupportedOperationException("Minesweeper does not support text input."); + } +} 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..79666c243 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperTileData.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperTileData.java @@ -1,107 +1,106 @@ -package edu.rpi.legup.puzzle.minesweeper; - -import java.util.Objects; -import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -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 EMPTY_DATA = 0; - - /** - * Always has a type of {@link MinesweeperTileType#UNSET}, and a data value of {@value - * UNSET_DATA} - */ - private static final MinesweeperTileData UNSET = - new MinesweeperTileData(MinesweeperTileType.UNSET, UNSET_DATA); - - /** - * Always has a type of {@link MinesweeperTileType#BOMB}, and a data value of {@value BOMB_DATA} - */ - private static final MinesweeperTileData BOMB = - new MinesweeperTileData(MinesweeperTileType.BOMB, BOMB_DATA); - - /** - * Always has a type of {@link MinesweeperTileType#EMPTY}, and a data value of {@value - * EMPTY_DATA} - */ - private static final MinesweeperTileData EMPTY = - new MinesweeperTileData(MinesweeperTileType.EMPTY, EMPTY_DATA); - - /** - * @param count how many bombs are near the flag - * @return a new {@link MinesweeperTileData} with a {@link MinesweeperTileData#type} of {@link - * MinesweeperTileType#FLAG} and a {@link MinesweeperTileData#data} of {@code count} - */ - @Contract(pure = true) - public static @NotNull MinesweeperTileData flag(int count) { - return new MinesweeperTileData(MinesweeperTileType.FLAG, 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 - * 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. - */ - @Contract(pure = true) - public static @NotNull MinesweeperTileData fromData(int data) { - return switch (data) { - case UNSET_DATA -> unset(); - case BOMB_DATA -> bomb(); - case EMPTY_DATA -> empty(); - default -> { - if (data <= -2 || data > 8) { - yield unset(); - } - yield flag(data); - } - }; - } - - public static @NotNull MinesweeperTileData unset() { - return UNSET; - } - - public static @NotNull MinesweeperTileData bomb() { - return BOMB; - } - - public static @NotNull MinesweeperTileData empty() { - return EMPTY; - } - - public boolean isUnset() { - return this.data == UNSET_DATA; - } - - public boolean isBomb() { - return this.data == BOMB_DATA; - } - - public boolean isEmpty() { - return this.data == EMPTY_DATA; - } - - public boolean isFlag() { - return this.data > 0 && this.data <= 8; - } - - @Override - public boolean equals(@Nullable Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - MinesweeperTileData that = (MinesweeperTileData) o; - return data == that.data && type == that.type; - } - - @Override - public int hashCode() { - return Objects.hash(type, data); - } -} +package edu.rpi.legup.puzzle.minesweeper; + +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Objects; + +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 EMPTY_DATA = 0; + + /** + * Always has a type of {@link MinesweeperTileType#UNSET}, and a data value of + * {@value UNSET_DATA} + */ + private static final MinesweeperTileData UNSET = new MinesweeperTileData(MinesweeperTileType.UNSET, UNSET_DATA); + /** + * Always has a type of {@link MinesweeperTileType#BOMB}, and a data value of + * {@value BOMB_DATA} + */ + private static final MinesweeperTileData BOMB = new MinesweeperTileData(MinesweeperTileType.BOMB, BOMB_DATA); + /** + * Always has a type of {@link MinesweeperTileType#EMPTY}, and a data value of + * {@value EMPTY_DATA} + */ + private static final MinesweeperTileData EMPTY = new MinesweeperTileData(MinesweeperTileType.EMPTY, EMPTY_DATA); + + /** + * @param count how many bombs are near the flag + * @return a new {@link MinesweeperTileData} with a {@link MinesweeperTileData#type} of {@link MinesweeperTileType#FLAG} + * and a {@link MinesweeperTileData#data} of {@code count} + */ + @Contract(pure = true) + public static @NotNull MinesweeperTileData flag(int count) { + return new MinesweeperTileData(MinesweeperTileType.FLAG, 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 + * 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. + */ + @Contract(pure = true) + public static @NotNull MinesweeperTileData fromData(int data) { + return switch (data) { + case UNSET_DATA -> unset(); + case BOMB_DATA -> bomb(); + case EMPTY_DATA -> empty(); + default -> { + if (data <= -2 || data > 8) { + yield unset(); + } + yield flag(data); + } + }; + } + + public static @NotNull MinesweeperTileData unset() { + return UNSET; + } + + public static @NotNull MinesweeperTileData bomb() { + return BOMB; + } + + public static @NotNull MinesweeperTileData empty() { + return EMPTY; + } + + public boolean isUnset() { + return this.data == UNSET_DATA; + } + + public boolean isBomb() { + return this.data == BOMB_DATA; + } + + public boolean isEmpty() { + return this.data == EMPTY_DATA; + } + + public boolean isFlag() { + return this.data > 0 && this.data <= 8; + } + + @Override + public boolean equals(@Nullable Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + MinesweeperTileData that = (MinesweeperTileData) o; + return data == that.data && type == that.type; + } + + @Override + public int hashCode() { + return Objects.hash(type, data); + } +} 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..9d5dabd69 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperTileType.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperTileType.java @@ -1,14 +1,24 @@ -package edu.rpi.legup.puzzle.minesweeper; - -public enum MinesweeperTileType { - - /** A cell with nothing */ - UNSET, - - /** Represents a cell with no bombs in it */ - 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 -} +package edu.rpi.legup.puzzle.minesweeper; + +public enum MinesweeperTileType { + + + /** + * A cell with nothing + */ + UNSET, + + /** + * Represents a cell with no bombs in it + */ + 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 + +} 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 375692095..e74979e19 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperUtilities.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperUtilities.java @@ -1,18 +1,17 @@ package edu.rpi.legup.puzzle.minesweeper; import java.awt.*; -import java.util.*; import java.util.Objects; import java.util.stream.IntStream; import java.util.stream.Stream; +import java.util.*; public final class MinesweeperUtilities { private static final int SURROUNDING_CELL_MIN_INDEX = 0; private static final int SURROUNDING_CELL_MAX_INDEX = 9; - public static Stream getSurroundingCells( - MinesweeperBoard board, MinesweeperCell cell) { + public static Stream getSurroundingCells(MinesweeperBoard board, MinesweeperCell cell) { final Point loc = cell.getLocation(); final int height = board.getHeight(); final int width = board.getWidth(); @@ -26,31 +25,27 @@ public static Stream getSurroundingCells( return IntStream.range(SURROUNDING_CELL_MIN_INDEX, SURROUNDING_CELL_MAX_INDEX) // skip 0,0 element .filter(i -> i != (SURROUNDING_CELL_MAX_INDEX - SURROUNDING_CELL_MIN_INDEX) / 2) - .mapToObj( - index -> { - final int newX = index / 3 - 1 + x; - final int newY = index % 3 - 1 + y; - // only keep valid locations - if (newX < 0 || newY < 0 || newX >= width || newY >= height) { - return null; - } - return board.getCell(newX, newY); - }) + .mapToObj(index -> { + final int newX = index / 3 - 1 + x; + final int newY = index % 3 - 1 + y; + // only keep valid locations + if (newX < 0 || newY < 0 || newX >= width || newY >= height) { + return null; + } + return board.getCell(newX, newY); + }) .filter(Objects::nonNull); } - public static int countSurroundingType( - MinesweeperBoard board, MinesweeperCell cell, MinesweeperTileType type) { - final Stream stream = - getSurroundingCells(board, cell).map(MinesweeperCell::getData); - return (int) - (switch (type) { - case UNSET -> stream.filter(MinesweeperTileData::isUnset); - case BOMB -> stream.filter(MinesweeperTileData::isBomb); - case EMPTY -> stream.filter(MinesweeperTileData::isEmpty); - case FLAG -> stream.filter(MinesweeperTileData::isFlag); - }) - .count(); + public static int countSurroundingType(MinesweeperBoard board, MinesweeperCell cell, MinesweeperTileType type) { + final Stream stream = getSurroundingCells(board, cell) + .map(MinesweeperCell::getData); + return (int) (switch (type) { + case UNSET -> stream.filter(MinesweeperTileData::isUnset); + case BOMB -> stream.filter(MinesweeperTileData::isBomb); + case EMPTY -> stream.filter(MinesweeperTileData::isEmpty); + case FLAG -> stream.filter(MinesweeperTileData::isFlag); + }).count(); } public static int countSurroundingBombs(MinesweeperBoard board, MinesweeperCell cell) { @@ -70,8 +65,9 @@ public static int countSurroundingFlags(MinesweeperBoard board, MinesweeperCell } /** - * @return how many bombs are left that need to be placed around {@code cell} which must be a - * flag + * + * @return how many bombs 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()) { @@ -90,20 +86,15 @@ public static boolean hasEmptyAdjacent(MinesweeperBoard board, MinesweeperCell c return false; } - public static ArrayList getAdjacentCells( - MinesweeperBoard board, MinesweeperCell cell) { + public static ArrayList getAdjacentCells(MinesweeperBoard board, MinesweeperCell cell) { ArrayList adjCells = new ArrayList(); Point cellLoc = cell.getLocation(); - for (int i = -1; i <= 1; i++) { - for (int j = -1; j <= 1; j++) { - if (cellLoc.getX() + i < 0 - || cellLoc.y + j < 0 - || cellLoc.x + i >= board.getWidth() - || cellLoc.y + j >= board.getHeight()) { + for (int i=-1; i <= 1; i++) { + for (int j=-1; j <= 1; j++) { + if (cellLoc.getX() + i < 0 || cellLoc.y + j < 0 || cellLoc.x + i >= board.getWidth() || cellLoc.y + j >= board.getHeight()) { continue; } - MinesweeperCell adjCell = - (MinesweeperCell) board.getCell(cellLoc.x + i, cellLoc.y + j); + MinesweeperCell adjCell = (MinesweeperCell) board.getCell(cellLoc.x + i, cellLoc.y + j); if (adjCell == null) { continue; } @@ -123,13 +114,7 @@ public static ArrayList getCombinations(int chosenNumItems, int total return combinations; } - private static void recurseCombinations( - ArrayList result, - int curIndex, - int maxBlack, - int numBlack, - int len, - boolean[] workingArray) { + private static void recurseCombinations(ArrayList result, int curIndex, int maxBlack, int numBlack, int len, boolean[] workingArray) { if (curIndex == len) { // complete, but not valid solution if (numBlack != maxBlack) { @@ -146,9 +131,11 @@ private static void recurseCombinations( if (numBlack < maxBlack) { workingArray[curIndex] = true; - recurseCombinations(result, curIndex + 1, maxBlack, numBlack + 1, len, workingArray); + recurseCombinations(result, curIndex+1, maxBlack, numBlack+1, len, workingArray); } workingArray[curIndex] = false; - recurseCombinations(result, curIndex + 1, maxBlack, numBlack, len, workingArray); + recurseCombinations(result, curIndex+1, maxBlack, numBlack, len, workingArray); } + + } 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 f18fdab82..ca9214416 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperView.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperView.java @@ -1,48 +1,48 @@ -package edu.rpi.legup.puzzle.minesweeper; - -import edu.rpi.legup.controller.BoardController; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.ui.boardview.GridBoardView; -import java.awt.*; -import java.io.IOException; -import java.util.Objects; -import javax.imageio.ImageIO; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.jetbrains.annotations.NotNull; - -public class MinesweeperView extends GridBoardView { - - private static final Logger LOGGER = LogManager.getLogger(MinesweeperView.class.getName()); - public static final Image BOMB_IMAGE; - - static { - Image tempBombImage = null; - try { - tempBombImage = - ImageIO.read( - Objects.requireNonNull( - ClassLoader.getSystemClassLoader() - .getResource( - "edu/rpi/legup/images/minesweeper/tiles/Bomb.png"))); - } catch (IOException e) { - LOGGER.error("Failed to open Minesweeper images"); - } - BOMB_IMAGE = tempBombImage; - } - - public MinesweeperView(@NotNull MinesweeperBoard board) { - super(new BoardController(), new MinesweeperController(), board.getDimension()); - - for (PuzzleElement puzzleElement : board.getPuzzleElements()) { - final MinesweeperCell cell = (MinesweeperCell) puzzleElement; - final Point loc = cell.getLocation(); - final MinesweeperElementView elementView = new MinesweeperElementView(cell); - elementView.setIndex(cell.getIndex()); - elementView.setSize(elementSize); - elementView.setLocation( - new Point(loc.x * elementSize.width, loc.y * elementSize.height)); - elementViews.add(elementView); - } - } -} +package edu.rpi.legup.puzzle.minesweeper; + +import edu.rpi.legup.controller.BoardController; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.puzzle.lightup.LightUpView; +import edu.rpi.legup.ui.boardview.GridBoardView; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.NotNull; + +import javax.imageio.ImageIO; +import java.awt.*; +import java.io.IOException; +import java.util.Objects; + +public class MinesweeperView extends GridBoardView { + + private static final Logger LOGGER = LogManager.getLogger(MinesweeperView.class.getName()); + public static final Image BOMB_IMAGE; + + static { + Image tempBombImage = null; + try { + tempBombImage = + ImageIO.read( + Objects.requireNonNull(ClassLoader.getSystemClassLoader() + .getResource("edu/rpi/legup/images/minesweeper/tiles/Bomb.png"))); + } catch (IOException e) { + LOGGER.error("Failed to open Minesweeper images"); + } + BOMB_IMAGE = tempBombImage; + } + + + public MinesweeperView(@NotNull MinesweeperBoard board) { + super(new BoardController(), new MinesweeperController(), board.getDimension()); + + for (PuzzleElement puzzleElement : board.getPuzzleElements()) { + final MinesweeperCell cell = (MinesweeperCell) puzzleElement; + final Point loc = cell.getLocation(); + final MinesweeperElementView elementView = new MinesweeperElementView(cell); + elementView.setIndex(cell.getIndex()); + elementView.setSize(elementSize); + elementView.setLocation(new Point(loc.x * elementSize.width, loc.y * elementSize.height)); + elementViews.add(elementView); + } + } +} 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 index 78a5d320c..90bd8fb90 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/BombTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/BombTile.java @@ -1,13 +1,8 @@ package edu.rpi.legup.puzzle.minesweeper.elements; import edu.rpi.legup.model.elements.NonPlaceableElement; - -public class BombTile extends NonPlaceableElement { +public class BombTile extends NonPlaceableElement{ public BombTile() { - super( - "MINE-UNPL-0001", - "Bomb", - "A bomb", - "edu/rpi/legup/images/minesweeper/tiles/Bomb.png"); + 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/EmptyTile.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/EmptyTile.java index 7149bfa6a..dad1593ca 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/EmptyTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/EmptyTile.java @@ -5,10 +5,6 @@ public class EmptyTile extends PlaceableElement { public EmptyTile() { - super( - "MINE-PLAC-0002", - "Empty", - "An empty tile", - "edu/rpi/legup/images/minesweeper/tiles/Empty.png"); + super("MINE-PLAC-0002", "Empty", "An empty tile", "edu/rpi/legup/images/minesweeper/tiles/Empty.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 index 0bbca81f9..b6d44d11a 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/FlagTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/FlagTile.java @@ -1,13 +1,8 @@ package edu.rpi.legup.puzzle.minesweeper.elements; import edu.rpi.legup.model.elements.PlaceableElement; - -public class FlagTile extends PlaceableElement { +public class FlagTile extends PlaceableElement{ public FlagTile() { - super( - "MINE-PLAC-0001", - "Flag", - "The flag", - "edu/rpi/legup/images/nurikabe/tiles/BlackTile.png"); + 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/Unset.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/Unset.java index 71ce1881f..62f5b824f 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/Unset.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/Unset.java @@ -4,10 +4,6 @@ public class Unset extends NonPlaceableElement { public Unset() { - super( - "MINE-UNPL-0002", - "Unset", - "A blank tile", - "edu/rpi/legup/images/fillapix/tiles/UnknownTile.png"); + super("MINE-UNPL-0002", "Unset", "A blank tile", "edu/rpi/legup/images/fillapix/tiles/UnknownTile.png"); } -} +} \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/UnsetTile.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/UnsetTile.java index 447e2840c..1899a4fd5 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/UnsetTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/UnsetTile.java @@ -5,10 +5,7 @@ public class UnsetTile extends NonPlaceableElement { public UnsetTile() { - super( - "MINE-UNPL-0002", - "Unset", - "An unset tile", - "edu/rpi/legup/images/minesweeper/tiles/Unset.png"); + super("MINE-UNPL-0002", "Unset", "An unset tile", "edu/rpi/legup/images/minesweeper/tiles/Unset.png"); } + } diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/BombOrFilledCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/BombOrFilledCaseRule.java index a1ef97928..4bba7ff32 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/BombOrFilledCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/BombOrFilledCaseRule.java @@ -8,15 +8,15 @@ 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.MinesweeperTileType; + import java.util.ArrayList; import java.util.List; public class BombOrFilledCaseRule extends CaseRule { public BombOrFilledCaseRule() { - super( - "MINE-CASE-0001", - "Bomb Or Filled", + 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"); } @@ -68,10 +68,8 @@ public String checkRuleRaw(TreeTransition transition) { + ": This case rule must have 1 modified cell for each case."; } - MinesweeperCell mod1 = - (MinesweeperCell) case1.getBoard().getModifiedData().iterator().next(); - MinesweeperCell mod2 = - (MinesweeperCell) case2.getBoard().getModifiedData().iterator().next(); + MinesweeperCell mod1 = (MinesweeperCell) case1.getBoard().getModifiedData().iterator().next(); + MinesweeperCell mod2 = (MinesweeperCell) case2.getBoard().getModifiedData().iterator().next(); if (!mod1.getLocation().equals(mod2.getLocation())) { return super.getInvalidUseOfRuleMessage() + ": This case rule must modify the same cell for each case."; diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/LessBombsThanFlagContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/LessBombsThanFlagContradictionRule.java index 76212f6da..0cc1f6324 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/LessBombsThanFlagContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/LessBombsThanFlagContradictionRule.java @@ -3,16 +3,20 @@ 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.nurikabe.NurikabeBoard; +import edu.rpi.legup.puzzle.nurikabe.NurikabeCell; +import edu.rpi.legup.puzzle.nurikabe.NurikabeType; +import edu.rpi.legup.puzzle.nurikabe.NurikabeUtilities; +import edu.rpi.legup.utility.DisjointSets; + +import java.util.Set; public class LessBombsThanFlagContradictionRule extends ContradictionRule { - private final String NO_CONTRADICTION_MESSAGE = - "Does not contain a contradiction at this index"; + 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() { - super( - "MINE-CONT-0000", - "Less Bombs Than Flag", + 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"); } @@ -22,4 +26,7 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { return null; } + + } + diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/SatisfyFlagCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/SatisfyFlagCaseRule.java index cecd5a588..cb2250ddf 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/SatisfyFlagCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/SatisfyFlagCaseRule.java @@ -7,14 +7,14 @@ import edu.rpi.legup.model.tree.TreeNode; import edu.rpi.legup.model.tree.TreeTransition; import edu.rpi.legup.puzzle.minesweeper.*; + import java.awt.*; import java.util.*; import java.util.List; -public class SatisfyFlagCaseRule extends CaseRule { +public class SatisfyFlagCaseRule extends CaseRule{ public SatisfyFlagCaseRule() { - super( - "MINE-CASE-0002", + 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/SatisfyFlag.jpg"); @@ -27,9 +27,7 @@ public CaseBoard getCaseBoard(Board board) { minesweeperBoard.setModifiable(false); for (PuzzleElement data : minesweeperBoard.getPuzzleElements()) { MinesweeperCell cell = (MinesweeperCell) data; - if (cell.getTileNumber() >= 0 - && cell.getTileNumber() <= 8 - && MinesweeperUtilities.hasEmptyAdjacent(minesweeperBoard, cell)) { + if (cell.getTileNumber() >= 0 && cell.getTileNumber() <= 8 && MinesweeperUtilities.hasEmptyAdjacent(minesweeperBoard, cell)) { caseBoard.addPickableElement(data); } } @@ -52,8 +50,7 @@ public ArrayList getCases(Board board, PuzzleElement puzzleElement) { int cellNumBomb = 0; int cellNumUnset = 0; ArrayList unsetCells = new ArrayList(); - ArrayList adjCells = - MinesweeperUtilities.getAdjacentCells(minesweeperBoard, cell); + ArrayList adjCells = MinesweeperUtilities.getAdjacentCells(minesweeperBoard, cell); for (MinesweeperCell adjCell : adjCells) { if (adjCell.getTileType() == MinesweeperTileType.BOMB) { cellNumBomb++; @@ -70,16 +67,16 @@ public ArrayList getCases(Board board, PuzzleElement puzzleElement) { // generate all cases as boolean expressions ArrayList combinations; - combinations = - MinesweeperUtilities.getCombinations(cellMaxBlack - cellNumBomb, cellNumUnset); + combinations = MinesweeperUtilities.getCombinations(cellMaxBlack - cellNumBomb, cellNumUnset); - for (int i = 0; i < combinations.size(); i++) { + for (int i=0; i < combinations.size(); i++) { Board case_ = board.copy(); - for (int j = 0; j < combinations.get(i).length; j++) { + 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()); - } else { + } + else { cell.setCellType(MinesweeperTileData.empty()); } case_.addModifiedData(cell); @@ -108,12 +105,14 @@ public String checkRuleRaw(TreeTransition transition) { * If all the above is verified, then the transition is valid */ + /* ensure there are modified cells */ Set modCells = transition.getBoard().getModifiedData(); if (modCells.size() <= 0) { return super.getInvalidUseOfRuleMessage(); } + /* ensure modified cells occur within a 3X3 square */ int minVertLoc = Integer.MAX_VALUE, maxVertLoc = Integer.MIN_VALUE; int minHorzLoc = Integer.MAX_VALUE, maxHorzLoc = Integer.MIN_VALUE; @@ -136,13 +135,13 @@ public String checkRuleRaw(TreeTransition transition) { return super.getInvalidUseOfRuleMessage(); } + /* get the center of all possible 3X3 squares, * and collect all that have numbers */ MinesweeperBoard board = (MinesweeperBoard) transition.getParents().get(0).getBoard(); ArrayList possibleCenters = new ArrayList(); for (PuzzleElement modCell : modCells) { - ArrayList adjacentCells = - MinesweeperUtilities.getAdjacentCells(board, (MinesweeperCell) modCell); + ArrayList adjacentCells = MinesweeperUtilities.getAdjacentCells(board, (MinesweeperCell) modCell); for (MinesweeperCell cell : adjacentCells) { possibleCenters.add(cell); } @@ -154,14 +153,14 @@ public String checkRuleRaw(TreeTransition transition) { return super.getInvalidUseOfRuleMessage(); } + /* Now go through the remaining centers, and check if their combinations * match the transitions */ for (MinesweeperCell possibleCenter : possibleCenters) { int numBlack = 0; int numEmpty = 0; int maxBlack = possibleCenter.getTileNumber(); - for (MinesweeperCell adjCell : - MinesweeperUtilities.getAdjacentCells(board, possibleCenter)) { + for (MinesweeperCell adjCell : MinesweeperUtilities.getAdjacentCells(board, possibleCenter)) { if (adjCell.getTileType() == MinesweeperTileType.BOMB) { numBlack++; } @@ -174,8 +173,7 @@ public String checkRuleRaw(TreeTransition transition) { continue; } - ArrayList combinations = - MinesweeperUtilities.getCombinations(maxBlack - numBlack, numEmpty); + ArrayList combinations = MinesweeperUtilities.getCombinations(maxBlack - numBlack, numEmpty); if (combinations.size() != childTransitions.size()) { // not this center because combinations do not match transitions continue; @@ -191,10 +189,11 @@ public String checkRuleRaw(TreeTransition transition) { } boolean[] translatedModCells = new boolean[transModCells.size()]; - for (int i = 0; i < transModCells.size(); i++) { + for (int i=0; i < transModCells.size(); i++) { if (transModCells.get(i).getTileType() == MinesweeperTileType.BOMB) { translatedModCells[i] = true; - } else { + } + else { translatedModCells[i] = false; } } @@ -224,6 +223,7 @@ public String checkRuleRaw(TreeTransition transition) { return super.getInvalidUseOfRuleMessage(); } + @Override public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { return null; diff --git a/src/test/java/puzzles/minesweeper/MinesweeperUtilitiesTest.java b/src/test/java/puzzles/minesweeper/MinesweeperUtilitiesTest.java index 0e0112040..4b1b450c8 100644 --- a/src/test/java/puzzles/minesweeper/MinesweeperUtilitiesTest.java +++ b/src/test/java/puzzles/minesweeper/MinesweeperUtilitiesTest.java @@ -5,13 +5,14 @@ import edu.rpi.legup.puzzle.minesweeper.MinesweeperCell; import edu.rpi.legup.puzzle.minesweeper.MinesweeperUtilities; import edu.rpi.legup.save.InvalidFileFormatException; -import java.util.stream.Stream; import legup.MockGameBoardFacade; import legup.TestUtilities; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; +import java.util.stream.Stream; + public class MinesweeperUtilitiesTest { private static Minesweeper minesweeper; @@ -23,10 +24,11 @@ public static void setUp() { } @Test - public void getSurroundingCellsSizeThreeByThreeAtOneXOneTest() - throws InvalidFileFormatException { + public void getSurroundingCellsSizeThreeByThreeAtOneXOneTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/minesweeper/utilities/3x3test", minesweeper); + TestUtilities.importTestBoard( + "puzzles/minesweeper/utilities/3x3test", + minesweeper); final MinesweeperBoard board = (MinesweeperBoard) minesweeper.getCurrentBoard(); MinesweeperCell cell = board.getCell(1, 1); @@ -38,10 +40,11 @@ public void getSurroundingCellsSizeThreeByThreeAtOneXOneTest() } @Test - public void getSurroundingCellsSizeThreeByThreeAtZeroXZeroTest() - throws InvalidFileFormatException { + public void getSurroundingCellsSizeThreeByThreeAtZeroXZeroTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/minesweeper/utilities/3x3test", minesweeper); + TestUtilities.importTestBoard( + "puzzles/minesweeper/utilities/3x3test", + minesweeper); final MinesweeperBoard board = (MinesweeperBoard) minesweeper.getCurrentBoard(); MinesweeperCell cell = board.getCell(0, 0); @@ -53,10 +56,11 @@ public void getSurroundingCellsSizeThreeByThreeAtZeroXZeroTest() } @Test - public void getSurroundingCellsSizeThreeByThreeAtZeroXOneTest() - throws InvalidFileFormatException { + public void getSurroundingCellsSizeThreeByThreeAtZeroXOneTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/minesweeper/utilities/3x3test", minesweeper); + TestUtilities.importTestBoard( + "puzzles/minesweeper/utilities/3x3test", + minesweeper); final MinesweeperBoard board = (MinesweeperBoard) minesweeper.getCurrentBoard(); MinesweeperCell cell = board.getCell(0, 1); @@ -66,4 +70,6 @@ public void getSurroundingCellsSizeThreeByThreeAtZeroXOneTest() final long count = cells.count(); Assert.assertEquals(count, 5); } + + } From 9bffc7f63c666e23ce9693a32e325ed7bdbad8aa Mon Sep 17 00:00:00 2001 From: vockek Date: Fri, 29 Mar 2024 16:58:53 -0400 Subject: [PATCH 18/21] Added "More Bombs Than Flag" Contradiction Rule --- .../MoreBombsThanFlagContradictionRule.java | 54 ++++++++++++++++++ .../contradictions/Bomb_Surplus.jpg | Bin 0 -> 9833 bytes 2 files changed, 54 insertions(+) create mode 100644 src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/MoreBombsThanFlagContradictionRule.java create mode 100644 src/main/resources/edu/rpi/legup/images/minesweeper/contradictions/Bomb_Surplus.jpg diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/MoreBombsThanFlagContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/MoreBombsThanFlagContradictionRule.java new file mode 100644 index 000000000..aeddd103b --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/MoreBombsThanFlagContradictionRule.java @@ -0,0 +1,54 @@ +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.MinesweeperTileData; +import edu.rpi.legup.puzzle.minesweeper.MinesweeperUtilities; +import java.util.ArrayList; + +public class MoreBombsThanFlagContradictionRule extends ContradictionRule { + + public MoreBombsThanFlagContradictionRule() { + 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"); + } + + /** + * 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); + + int cellNum = cell.getTileNumber(); + if (cellNum < 0 || cellNum >= 10) { + return super.getNoContradictionMessage(); + } + int numBlack = 0; + ArrayList adjCells = MinesweeperUtilities.getAdjacentCells(minesweeperBoard, cell); + for (MinesweeperCell adjCell : adjCells) { + if (adjCell.getTileType() == MinesweeperTileType.BOMB) { + numBlack++; + } + } + if (numBlack > cellNum) { + return null; + } + + return super.getNoContradictionMessage(); + } +} diff --git a/src/main/resources/edu/rpi/legup/images/minesweeper/contradictions/Bomb_Surplus.jpg b/src/main/resources/edu/rpi/legup/images/minesweeper/contradictions/Bomb_Surplus.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5e8c36662ffe42161667275d6b4d3848dbb8ec4f GIT binary patch literal 9833 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 literal 0 HcmV?d00001 From 5a520704e23a50615c42dd9ecbb31d73af4538b6 Mon Sep 17 00:00:00 2001 From: vockek Date: Fri, 29 Mar 2024 17:16:18 -0400 Subject: [PATCH 19/21] Delete Unset (replaced by UnsetTile) --- .../edu/rpi/legup/puzzle/minesweeper/elements/Unset.java | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/Unset.java diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/Unset.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/Unset.java deleted file mode 100644 index 62f5b824f..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/Unset.java +++ /dev/null @@ -1,9 +0,0 @@ -package edu.rpi.legup.puzzle.minesweeper.elements; - -import edu.rpi.legup.model.elements.NonPlaceableElement; - -public class Unset extends NonPlaceableElement { - public Unset() { - super("MINE-UNPL-0002", "Unset", "A blank tile", "edu/rpi/legup/images/fillapix/tiles/UnknownTile.png"); - } -} \ No newline at end of file From 5e461ecfa60509d2eb1c4452c7781696998cf483 Mon Sep 17 00:00:00 2001 From: vockek Date: Fri, 29 Mar 2024 17:46:17 -0400 Subject: [PATCH 20/21] Added dot to empty tile image --- .../minesweeper/MinesweeperElementView.java | 13 ++++++++++--- .../puzzle/minesweeper/MinesweeperView.java | 15 +++++++++++++++ .../rpi/legup/images/minesweeper/tiles/Empty.png | Bin 0 -> 176 bytes 3 files changed, 25 insertions(+), 3 deletions(-) create mode 100644 src/main/resources/edu/rpi/legup/images/minesweeper/tiles/Empty.png 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 e9658a077..181b25d81 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperElementView.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperElementView.java @@ -53,11 +53,18 @@ public void drawElement(@NotNull Graphics2D graphics2D) { return; } if (type == MinesweeperTileType.EMPTY) { - graphics2D.setStroke(new BasicStroke(1)); + graphics2D.setColor(Color.LIGHT_GRAY); + graphics2D.fillRect(location.x, location.y, size.width, size.height); + graphics2D.drawImage( + MinesweeperView.EMPTY_IMAGE, + location.x, + location.y, + size.width, + size.height, + Color.GRAY, + null); graphics2D.setColor(Color.BLACK); graphics2D.drawRect(location.x, location.y, size.width, size.height); - graphics2D.setColor(Color.GRAY); - graphics2D.fillRect(location.x, location.y, size.width, size.height); } if (type == MinesweeperTileType.BOMB) { graphics2D.setColor(Color.LIGHT_GRAY); 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 ca9214416..571fd093d 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperView.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperView.java @@ -18,6 +18,8 @@ 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 EMPTY_IMAGE; + static { Image tempBombImage = null; try { @@ -31,6 +33,19 @@ public class MinesweeperView extends GridBoardView { BOMB_IMAGE = tempBombImage; } + static { + Image tempEmptyImage = null; + try { + tempEmptyImage = + ImageIO.read( + Objects.requireNonNull(ClassLoader.getSystemClassLoader() + .getResource("edu/rpi/legup/images/minesweeper/tiles/Empty.png"))); + } catch (IOException e) { + LOGGER.error("Failed to open Minesweeper images"); + } + EMPTY_IMAGE = tempEmptyImage; + } + public MinesweeperView(@NotNull MinesweeperBoard board) { super(new BoardController(), new MinesweeperController(), board.getDimension()); diff --git a/src/main/resources/edu/rpi/legup/images/minesweeper/tiles/Empty.png b/src/main/resources/edu/rpi/legup/images/minesweeper/tiles/Empty.png new file mode 100644 index 0000000000000000000000000000000000000000..c553ce15a55657d5b7af6290744e4a82c7fff30b GIT binary patch literal 176 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}Ea{HEjtmSN z`?>!lvI6;>1s;*b3=CqbAk63)r1AkM=<4a>7!u+B_Ub`S1_d6LgVw*_TXHRHQjj_H zPTh`O=}2kNhO5S6K!reHu&-^~@6y?Fp Date: Sat, 30 Mar 2024 23:27:03 -0400 Subject: [PATCH 21/21] Fixed "Satisfy Flag" Case Rule Picture --- .../minesweeper/rules/SatisfyFlagCaseRule.java | 2 +- .../images/minesweeper/cases/Satisfy_Flag.png | Bin 0 -> 3496 bytes 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 src/main/resources/edu/rpi/legup/images/minesweeper/cases/Satisfy_Flag.png diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/SatisfyFlagCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/SatisfyFlagCaseRule.java index cb2250ddf..257cfb41b 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/SatisfyFlagCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/SatisfyFlagCaseRule.java @@ -17,7 +17,7 @@ public SatisfyFlagCaseRule() { 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/SatisfyFlag.jpg"); + "edu/rpi/legup/images/minesweeper/cases/Satisfy_Flag.png"); } @Override diff --git a/src/main/resources/edu/rpi/legup/images/minesweeper/cases/Satisfy_Flag.png b/src/main/resources/edu/rpi/legup/images/minesweeper/cases/Satisfy_Flag.png new file mode 100644 index 0000000000000000000000000000000000000000..7272bbdb66d79af17513181bc3535c91745e4a92 GIT binary patch literal 3496 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 DmMtQG literal 0 HcmV?d00001