From f6f2a62a266818e879d5fc06781aab206f407c51 Mon Sep 17 00:00:00 2001 From: Fisher Date: Sat, 27 Jan 2024 21:29:15 -0500 Subject: [PATCH 01/41] Initial Minesweeper implementation work --- .../legup/puzzle/minesweeper/Minesweeper.java | 61 ++++++++++ .../puzzle/minesweeper/MinesweeperBoard.java | 14 +++ .../puzzle/minesweeper/MinesweeperCell.java | 59 ++++++++++ .../minesweeper/MinesweeperCellFactory.java | 77 ++++++++++++ .../minesweeper/MinesweeperController.java | 52 +++++++++ .../MinesweeperElementIdentifiers.java | 9 ++ .../minesweeper/MinesweeperElementView.java | 51 ++++++++ .../minesweeper/MinesweeperExporter.java | 42 +++++++ .../minesweeper/MinesweeperImporter.java | 110 ++++++++++++++++++ .../minesweeper/MinesweeperTileData.java | 64 ++++++++++ .../minesweeper/MinesweeperTileType.java | 9 ++ .../puzzle/minesweeper/MinesweeperView.java | 25 ++++ src/main/resources/edu/rpi/legup/legup/config | 4 + 13 files changed, 577 insertions(+) create mode 100644 src/main/java/edu/rpi/legup/puzzle/minesweeper/Minesweeper.java create mode 100644 src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperBoard.java create mode 100644 src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperCell.java create mode 100644 src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperCellFactory.java create mode 100644 src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperController.java create mode 100644 src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperElementIdentifiers.java create mode 100644 src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperElementView.java create mode 100644 src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperExporter.java create mode 100644 src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperImporter.java create mode 100644 src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperTileData.java create mode 100644 src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperTileType.java create mode 100644 src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperView.java diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/Minesweeper.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/Minesweeper.java new file mode 100644 index 000000000..6f00cd1ac --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/Minesweeper.java @@ -0,0 +1,61 @@ +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.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 + public void initializeView() { + this.boardView = new MinesweeperView((MinesweeperBoard) this.currentBoard); + this.boardView.setBoard(this.currentBoard); + addBoardListener(boardView); + } + + @Override + public @Nullable Board generatePuzzle(int difficulty) { + return null; + } + + @Override + 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 + public void onBoardChange(@NotNull Board board) { + + } + + @Override + 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 new file mode 100644 index 000000000..199805b6d --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperBoard.java @@ -0,0 +1,14 @@ +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); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperCell.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperCell.java new file mode 100644 index 000000000..faf787111 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperCell.java @@ -0,0 +1,59 @@ +package edu.rpi.legup.puzzle.minesweeper; + +import edu.rpi.legup.model.elements.Element; +import edu.rpi.legup.model.gameboard.GridCell; +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(); + } + + @Override + 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: + case MouseEvent.BUTTON3: + if (currentData <= 0) { + this.data = MinesweeperTileData.empty(); + return; + } + this.data = MinesweeperTileData.flag(currentData - 1); + return; + } + return; + default: + this.data = MinesweeperTileData.empty(); + } + } + + @Override + 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 new file mode 100644 index 000000000..0dab94654 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperCellFactory.java @@ -0,0 +1,77 @@ +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.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 { + + private static final String DATA_ATTRIBUTE = "x"; + private static final String X_ATTRIBUTE = "x"; + private static final String Y_ATTRIBUTE = "y"; + + + private MinesweeperCellFactory() { + } + + public static final MinesweeperCellFactory INSTANCE = new MinesweeperCellFactory(); + + @Override + 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)"); + } + } + + @Override + 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 new file mode 100644 index 000000000..5de8db2cc --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperController.java @@ -0,0 +1,52 @@ +package edu.rpi.legup.puzzle.minesweeper; + +import edu.rpi.legup.controller.ElementController; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import org.jetbrains.annotations.NotNull; + +import java.awt.event.MouseEvent; + +public class MinesweeperController extends ElementController { + + public static @NotNull MinesweeperTileData getNewCellDataOnClick( + @NotNull MouseEvent event, + @NotNull MinesweeperTileData current + ) { + final int numberData = current.data(); + switch (event.getButton()) { + case MouseEvent.BUTTON1: + if (numberData >= 8) { + return MinesweeperTileData.empty(); + } + return MinesweeperTileData.flag(numberData + 1); + case MouseEvent.BUTTON2: + case MouseEvent.BUTTON3: + if (numberData <= 0) { + return MinesweeperTileData.empty(); + } + return MinesweeperTileData.flag(numberData - 1); + } + return MinesweeperTileData.empty(); + } + + @Override + @SuppressWarnings("unchecked") + 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 new file mode 100644 index 000000000..bc59e81be --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperElementIdentifiers.java @@ -0,0 +1,9 @@ +package edu.rpi.legup.puzzle.minesweeper; + +public class MinesweeperElementIdentifiers { + + public static final String BOMB = "MINESWEEPER-BOMB"; + public static final String EMPTY = "MINESWEEPER-EMPTY"; + 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 new file mode 100644 index 000000000..51dec14b2 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperElementView.java @@ -0,0 +1,51 @@ +package edu.rpi.legup.puzzle.minesweeper; + +import edu.rpi.legup.ui.boardview.GridElementView; +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") + 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(puzzleElement.getData()); + 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(String.valueOf(puzzleElement.getData()), xText, yText); + } else { + // temp + graphics2D.setStroke(new BasicStroke(1)); + graphics2D.setColor(Color.LIGHT_GRAY); + graphics2D.fillRect(location.x, location.y, size.width, size.height); + 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 new file mode 100644 index 000000000..0c31bb1eb --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperExporter.java @@ -0,0 +1,42 @@ +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.NotNull; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +public class MinesweeperExporter extends PuzzleExporter { + + public MinesweeperExporter(@NotNull Puzzle puzzle) { + super(puzzle); + } + + @Override + 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.empty().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 new file mode 100644 index 000000000..71f9aa625 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperImporter.java @@ -0,0 +1,110 @@ +package edu.rpi.legup.puzzle.minesweeper; + +import edu.rpi.legup.model.PuzzleImporter; +import edu.rpi.legup.save.InvalidFileFormatException; +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 + public boolean acceptsRowsAndColumnsInput() { + return true; + } + + @Override + public boolean acceptsTextInput() { + return false; + } + + @Override + 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.empty(), new Point(x, y)); + cell.setIndex(y * columns + x); + cell.setModifiable(true); + minesweeperBoard.setCell(x, y, cell); + } + } + puzzle.setCurrentBoard(minesweeperBoard); + } + + @Override + 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.empty().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.empty(), 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"); + } + } + + 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 + 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 new file mode 100644 index 000000000..ac32e1dc0 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperTileData.java @@ -0,0 +1,64 @@ +package edu.rpi.legup.puzzle.minesweeper; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Objects; + +public final class MinesweeperTileData { + + public static final int BOMB_DATA = -1; + public static final int EMPTY_DATA = 0; + + private static final MinesweeperTileData BOMB = new MinesweeperTileData(MinesweeperTileType.BOMB, BOMB_DATA); + private static final MinesweeperTileData EMPTY = new MinesweeperTileData(MinesweeperTileType.EMPTY, EMPTY_DATA); + + public static @NotNull MinesweeperTileData flag(int count) { + return new MinesweeperTileData(MinesweeperTileType.FLAG, count); + } + + public static @NotNull MinesweeperTileData fromData(int data) { + switch (data) { + case BOMB_DATA: return bomb(); + case EMPTY_DATA: return empty(); + default: return flag(data); + } + } + + public static @NotNull MinesweeperTileData bomb() { + return BOMB; + } + + public static @NotNull MinesweeperTileData empty() { + return EMPTY; + } + + private final MinesweeperTileType type; + private final int data; + + private MinesweeperTileData(@NotNull MinesweeperTileType type, int data) { + this.type = type; + this.data = data; + } + + public @NotNull MinesweeperTileType type() { + return this.type; + } + + public int data() { + return this.data; + } + + @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 new file mode 100644 index 000000000..a48fef950 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperTileType.java @@ -0,0 +1,9 @@ +package edu.rpi.legup.puzzle.minesweeper; + +public enum MinesweeperTileType { + + EMPTY, + FLAG, + BOMB + +} diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperView.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperView.java new file mode 100644 index 000000000..78747a199 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperView.java @@ -0,0 +1,25 @@ +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 org.jetbrains.annotations.NotNull; + +import java.awt.*; + +public class MinesweeperView extends GridBoardView { + + 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/resources/edu/rpi/legup/legup/config b/src/main/resources/edu/rpi/legup/legup/config index 19e63a2a3..f252be8f3 100644 --- a/src/main/resources/edu/rpi/legup/legup/config +++ b/src/main/resources/edu/rpi/legup/legup/config @@ -39,5 +39,9 @@ qualifiedClassName="edu.rpi.legup.puzzle.skyscrapers.Skyscrapers" fileType=".xml" fileCreationDisabled="true"/> + From a3a2a800e6701bbd34d69b9ee0efd33d65a85334 Mon Sep 17 00:00:00 2001 From: Fisher Date: Tue, 30 Jan 2024 17:32:51 -0500 Subject: [PATCH 02/41] Add Unset tile type --- .../puzzle/minesweeper/MinesweeperController.java | 2 +- .../MinesweeperElementIdentifiers.java | 1 + .../puzzle/minesweeper/MinesweeperExporter.java | 2 +- .../puzzle/minesweeper/MinesweeperImporter.java | 6 +++--- .../puzzle/minesweeper/MinesweeperTileData.java | 4 ++++ .../puzzle/minesweeper/MinesweeperTileType.java | 15 +++++++++++++++ 6 files changed, 25 insertions(+), 5 deletions(-) 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 5de8db2cc..bcc9a0671 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperController.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperController.java @@ -21,7 +21,7 @@ public class MinesweeperController extends ElementController { return MinesweeperTileData.flag(numberData + 1); case MouseEvent.BUTTON2: case MouseEvent.BUTTON3: - if (numberData <= 0) { + if (numberData <= 1) { return MinesweeperTileData.empty(); } return MinesweeperTileData.flag(numberData - 1); 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 bc59e81be..96dd0a604 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperElementIdentifiers.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperElementIdentifiers.java @@ -2,6 +2,7 @@ public class MinesweeperElementIdentifiers { + public static final String UNSET = "MINESWEEPER-UNSET"; public static final String BOMB = "MINESWEEPER-BOMB"; public static final String EMPTY = "MINESWEEPER-EMPTY"; public static final String FLAG = "MINESWEEPER-FLAG"; 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 0c31bb1eb..20ff19410 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperExporter.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperExporter.java @@ -30,7 +30,7 @@ public MinesweeperExporter(@NotNull Puzzle puzzle) { final org.w3c.dom.Element cellsElement = newDocument.createElement("cells"); for (PuzzleElement puzzleElement : board.getPuzzleElements()) { final MinesweeperCell cell = (MinesweeperCell) puzzleElement; - if (!MinesweeperTileData.empty().equals(cell.getData())) { + if (!MinesweeperTileData.unset().equals(cell.getData())) { final org.w3c.dom.Element cellElement = puzzle.getFactory().exportCell(newDocument, puzzleElement); cellsElement.appendChild(cellElement); } 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 71f9aa625..c34a5c1a1 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperImporter.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperImporter.java @@ -31,7 +31,7 @@ public void initializeBoard(int rows, int columns) { for (int y = 0; y < rows; y++) { for (int x = 0; x < columns; x++) { - MinesweeperCell cell = new MinesweeperCell(MinesweeperTileData.empty(), new Point(x, y)); + MinesweeperCell cell = new MinesweeperCell(MinesweeperTileData.unset(), new Point(x, y)); cell.setIndex(y * columns + x); cell.setModifiable(true); minesweeperBoard.setCell(x, y, cell); @@ -61,7 +61,7 @@ public void initializeBoard(@NotNull Node node) throws InvalidFileFormatExceptio 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.empty().equals(cell.getData())) { + if (MinesweeperTileData.unset().equals(cell.getData())) { cell.setModifiable(false); cell.setGiven(true); } @@ -71,7 +71,7 @@ public void initializeBoard(@NotNull Node node) throws InvalidFileFormatExceptio 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.empty(), new Point(x, y)); + final MinesweeperCell cell = new MinesweeperCell(MinesweeperTileData.unset(), new Point(x, y)); cell.setIndex(y * height + x); cell.setModifiable(true); minesweeperBoard.setCell(x, y, cell); 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 ac32e1dc0..159cd7869 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperTileData.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperTileData.java @@ -7,9 +7,11 @@ public final class MinesweeperTileData { + public static final int UNSET_DATA = -2; public static final int BOMB_DATA = -1; public static final int EMPTY_DATA = 0; + private static final MinesweeperTileData UNSET = new MinesweeperTileData(MinesweeperTileType.UNSET, UNSET_DATA); private static final MinesweeperTileData BOMB = new MinesweeperTileData(MinesweeperTileType.BOMB, BOMB_DATA); private static final MinesweeperTileData EMPTY = new MinesweeperTileData(MinesweeperTileType.EMPTY, EMPTY_DATA); @@ -19,12 +21,14 @@ public final class MinesweeperTileData { public static @NotNull MinesweeperTileData fromData(int data) { switch (data) { + case UNSET_DATA: return unset(); case BOMB_DATA: return bomb(); case EMPTY_DATA: return empty(); default: return flag(data); } } + public static @NotNull MinesweeperTileData unset() { return UNSET; }; public static @NotNull MinesweeperTileData bomb() { return BOMB; } 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 a48fef950..ec7a10eb2 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperTileType.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperTileType.java @@ -2,8 +2,23 @@ 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 } From 303080521f68b7b90183f1d6e4a0a776daa7050d Mon Sep 17 00:00:00 2001 From: philippark Date: Fri, 9 Feb 2024 21:53:24 -0500 Subject: [PATCH 03/41] Init elements Created initial classes for bomb, flag, utilities, and contradiction rule. --- .../puzzle/minesweeper/elements/Bomb.java | 8 +++++ .../puzzle/minesweeper/elements/Flag.java | 8 +++++ .../minesweeper/minesweeperUtilities.java | 13 ++++++++ .../LessBombsThanFlagContradictionRule.java | 32 +++++++++++++++++++ 4 files changed, 61 insertions(+) create mode 100644 src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/Bomb.java create mode 100644 src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/Flag.java create mode 100644 src/main/java/edu/rpi/legup/puzzle/minesweeper/minesweeperUtilities.java create mode 100644 src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/LessBombsThanFlagContradictionRule.java diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/Bomb.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/Bomb.java new file mode 100644 index 000000000..6fe86dcee --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/Bomb.java @@ -0,0 +1,8 @@ +package edu.rpi.legup.puzzle.minesweeper.elements; + +import edu.rpi.legup.model.elements.NonPlaceableElement; +public class Bomb extends NonPlaceableElement{ + public Bomb() { + super("MINE-UNPL-0001", "Bomb", "A bomb", "edu/rpi/legup/images/nurikabe/tiles/NumberTile.png"); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/Flag.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/Flag.java new file mode 100644 index 000000000..9e9b53bae --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/Flag.java @@ -0,0 +1,8 @@ +package edu.rpi.legup.puzzle.minesweeper.elements; + +import edu.rpi.legup.model.elements.PlaceableElement; +public class Flag extends PlaceableElement{ + public Flag() { + super("NURI-PLAC-0001", "Flag", "The flag", "edu/rpi/legup/images/nurikabe/tiles/BlackTile.png"); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/minesweeperUtilities.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/minesweeperUtilities.java new file mode 100644 index 000000000..6b4e56728 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/minesweeperUtilities.java @@ -0,0 +1,13 @@ +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; + +public class minesweeperUtilities { +} 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 new file mode 100644 index 000000000..e76129d04 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/LessBombsThanFlagContradictionRule.java @@ -0,0 +1,32 @@ +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.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 INVALID_USE_MESSAGE = "Contradiction must be a region"; + + public LessBombsThanFlagContradictionRule() { + 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"); + } + + @Override + public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { + + return null; + } + + + } +} + From d592e32c7499e72f2d217c1e07bde3119ab35d5c Mon Sep 17 00:00:00 2001 From: Fisher Date: Tue, 13 Feb 2024 16:48:01 -0500 Subject: [PATCH 04/41] Make clicking tiles cycle between numbers, bomb, and empty tiles. --- .idea/codeStyles/codeStyleConfig.xml | 1 + .../minesweeper/MinesweeperController.java | 10 ++-------- .../minesweeper/MinesweeperElementView.java | 19 ++++++++++++++----- .../minesweeper/MinesweeperTileData.java | 7 ++++++- .../LessBombsThanFlagContradictionRule.java | 6 +++--- 5 files changed, 26 insertions(+), 17 deletions(-) diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml index f23d52492..38a6942c4 100644 --- a/.idea/codeStyles/codeStyleConfig.xml +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -1,5 +1,6 @@ + \ No newline at end of file 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 bcc9a0671..771cee543 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperController.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperController.java @@ -15,16 +15,10 @@ public class MinesweeperController extends ElementController { final int numberData = current.data(); switch (event.getButton()) { case MouseEvent.BUTTON1: - if (numberData >= 8) { - return MinesweeperTileData.empty(); - } - return MinesweeperTileData.flag(numberData + 1); + return MinesweeperTileData.fromData(numberData + 1); case MouseEvent.BUTTON2: case MouseEvent.BUTTON3: - if (numberData <= 1) { - return MinesweeperTileData.empty(); - } - return MinesweeperTileData.flag(numberData - 1); + return MinesweeperTileData.fromData(numberData - 1); } return MinesweeperTileData.empty(); } 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 51dec14b2..1ff6e1c72 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperElementView.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperElementView.java @@ -35,17 +35,26 @@ public void drawElement(@NotNull Graphics2D graphics2D) { graphics2D.setColor(FONT_COLOR); graphics2D.setFont(FONT); final FontMetrics metrics = graphics2D.getFontMetrics(FONT); - final String value = String.valueOf(puzzleElement.getData()); + 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(String.valueOf(puzzleElement.getData()), xText, yText); - } else { - // temp + graphics2D.drawString(value, xText, yText); + return; + } + if (type == MinesweeperTileType.UNSET) { graphics2D.setStroke(new BasicStroke(1)); - graphics2D.setColor(Color.LIGHT_GRAY); + 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); } } } 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 159cd7869..a7ba297e5 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperTileData.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperTileData.java @@ -24,7 +24,12 @@ public final class MinesweeperTileData { case UNSET_DATA: return unset(); case BOMB_DATA: return bomb(); case EMPTY_DATA: return empty(); - default: return flag(data); + default: { + if (data <= -2 || data > 8) { + return unset(); + } + return flag(data); + } } } 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..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 @@ -10,12 +10,13 @@ import edu.rpi.legup.utility.DisjointSets; import java.util.Set; -public class LessBombsThanFlagContradictionRule extends ContradictionRule{ + +public class LessBombsThanFlagContradictionRule extends ContradictionRule { private final String NO_CONTRADICTION_MESSAGE = "Does not contain a contradiction at this index"; private final String INVALID_USE_MESSAGE = "Contradiction must be a region"; public LessBombsThanFlagContradictionRule() { - 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"); } @@ -27,6 +28,5 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { } - } } From 75e2ca72d7de85b1b0f8eed19d9647f8a3195314 Mon Sep 17 00:00:00 2001 From: Fisher Date: Tue, 13 Feb 2024 16:59:55 -0500 Subject: [PATCH 05/41] Fix checkstyle errors --- .../puzzle/minesweeper/MinesweeperCellFactory.java | 6 ++++-- .../puzzle/minesweeper/MinesweeperImporter.java | 6 ++++-- .../puzzle/minesweeper/MinesweeperTileData.java | 14 ++++++++++---- 3 files changed, 18 insertions(+), 8 deletions(-) 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 0dab94654..e32e2389a 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperCellFactory.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperCellFactory.java @@ -51,9 +51,11 @@ private MinesweeperCellFactory() { final MinesweeperCell cell = new MinesweeperCell(MinesweeperTileData.fromData(value), new Point(x, y)); cell.setIndex(y * height + x); return cell; - } catch (NumberFormatException e) { + } + catch (NumberFormatException e) { throw new InvalidFileFormatException("Minesweeper Factory: unknown value where integer expected"); - } catch (NullPointerException e) { + } + catch (NullPointerException e) { throw new InvalidFileFormatException("Minesweeper Factory: could not find attribute(s)"); } } 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 c34a5c1a1..d8835b409 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperImporter.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperImporter.java @@ -79,7 +79,8 @@ public void initializeBoard(@NotNull Node node) throws InvalidFileFormatExceptio } } puzzle.setCurrentBoard(minesweeperBoard); - } catch (NumberFormatException e) { + } + catch (NumberFormatException e) { throw new InvalidFileFormatException("Minesweeper Importer: unknown value where integer expected"); } } @@ -89,7 +90,8 @@ public void initializeBoard(@NotNull Node node) throws InvalidFileFormatExceptio if (!boardElement.getAttribute("size").isEmpty()) { final int size = Integer.parseInt(boardElement.getAttribute("size")); minesweeperBoard = new MinesweeperBoard(size); - } else { + } + 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")); 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 a7ba297e5..37dc33983 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperTileData.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperTileData.java @@ -21,9 +21,12 @@ public final class MinesweeperTileData { public static @NotNull MinesweeperTileData fromData(int data) { switch (data) { - case UNSET_DATA: return unset(); - case BOMB_DATA: return bomb(); - case EMPTY_DATA: return empty(); + case UNSET_DATA: + return unset(); + case BOMB_DATA: + return bomb(); + case EMPTY_DATA: + return empty(); default: { if (data <= -2 || data > 8) { return unset(); @@ -33,7 +36,10 @@ public final class MinesweeperTileData { } } - public static @NotNull MinesweeperTileData unset() { return UNSET; }; + public static @NotNull MinesweeperTileData unset() { + return UNSET; + } + public static @NotNull MinesweeperTileData bomb() { return BOMB; } From 89fbe943a4e9ad7ae2fa7daed0b71b6f8357fe30 Mon Sep 17 00:00:00 2001 From: vockek Date: Tue, 13 Feb 2024 17:00:32 -0500 Subject: [PATCH 06/41] Added --- .../minesweeper/MinesweeperTileType.java | 6 +- .../rules/BombOrFilledCaseRule.java | 110 ++++++++++++++++++ .../LessBombsThanFlagContradictionRule.java | 2 +- src/main/resources/edu/rpi/legup/legup/config | 2 +- 4 files changed, 117 insertions(+), 3 deletions(-) create mode 100644 src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/BombOrFilledCaseRule.java 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 ec7a10eb2..a336c92a0 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperTileType.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperTileType.java @@ -19,6 +19,10 @@ public enum MinesweeperTileType { /** * A bomb tile that should be marked by nearby flags */ - BOMB + BOMB; + + public int toValue() { + return this.ordinal() - 2; + } } 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 new file mode 100644 index 000000000..e1e0d1c5c --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/BombOrFilledCaseRule.java @@ -0,0 +1,110 @@ +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.TreeTransition; +import edu.rpi.legup.puzzle.minesweeper.MinesweeperBoard; +import edu.rpi.legup.puzzle.minesweeper.MinesweeperCell; +import edu.rpi.legup.puzzle.minesweeper.MinesweeperTileType; + +import java.util.ArrayList; +import java.util.List; + +public class BombOrFilledCaseRule extends CaseRule { + + public BombOrFilledCaseRule() { + super("NURI-CASE-0001", + "Bomb or Filled", + "Each blank cell is either a bomb or empty.", + "edu/rpi/legup/images/nurikabe/cases/BlackOrWhite.png"); + } + + /** + * Checks whether the {@link TreeTransition} logically follows from the parent node using this rule. This method is + * the one that should overridden in child classes. + * + * @param transition transition to check + * @return null if the child node logically follow from the parent node, otherwise error message + */ + @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.EMPTY && mod1.getTileType() == MinesweeperTileType.BOMB))) { + return super.getInvalidUseOfRuleMessage() + ": This case rule must an empty white and black cell."; + } + + return null; + } + + @Override + public CaseBoard getCaseBoard(Board board) { + MinesweeperBoard minesweeperBoard = (MinesweeperBoard) board.copy(); + CaseBoard caseBoard = new CaseBoard(minesweeperBoard, this); + minesweeperBoard.setModifiable(false); + for (PuzzleElement element : minesweeperBoard.getPuzzleElements()) { + if (((MinesweeperCell) element).getTileType() == MinesweeperTileType.UNSET) { + caseBoard.addPickableElement(element); + } + } + return caseBoard; + } + + /** + * Gets the possible cases at a specific location based on this case rule + * + * @param board the current board state + * @param puzzleElement equivalent puzzleElement + * @return a list of elements the specified could be + */ + @Override + public ArrayList getCases(Board board, PuzzleElement puzzleElement) { + ArrayList cases = new ArrayList<>(); + Board case1 = board.copy(); + PuzzleElement data1 = case1.getPuzzleElement(puzzleElement); + data1.setData(MinesweeperTileType.EMPTY.toValue()); + case1.addModifiedData(data1); + cases.add(case1); + + Board case2 = board.copy(); + PuzzleElement data2 = case2.getPuzzleElement(puzzleElement); + data2.setData(MinesweeperTileType.BOMB.toValue()); + case2.addModifiedData(data2); + cases.add(case2); + + return cases; + } + + /** + * Checks whether the child node logically follows from the parent node + * at the specific puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified puzzleElement, + * otherwise error message + */ + @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..d2914d1e8 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 @@ -28,5 +28,5 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { } -} + diff --git a/src/main/resources/edu/rpi/legup/legup/config b/src/main/resources/edu/rpi/legup/legup/config index f252be8f3..181357a90 100644 --- a/src/main/resources/edu/rpi/legup/legup/config +++ b/src/main/resources/edu/rpi/legup/legup/config @@ -42,6 +42,6 @@ + fileCreationDisabled="false"/> From f8497f777b21dbdc341756ba427b9772590c4e17 Mon Sep 17 00:00:00 2001 From: vockek Date: Fri, 16 Feb 2024 14:28:48 -0500 Subject: [PATCH 07/41] Revert "Added" This reverts commit 89fbe943a4e9ad7ae2fa7daed0b71b6f8357fe30. --- .../minesweeper/MinesweeperTileType.java | 6 +- .../rules/BombOrFilledCaseRule.java | 110 ------------------ .../LessBombsThanFlagContradictionRule.java | 2 +- src/main/resources/edu/rpi/legup/legup/config | 2 +- 4 files changed, 3 insertions(+), 117 deletions(-) delete mode 100644 src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/BombOrFilledCaseRule.java 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 a336c92a0..ec7a10eb2 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperTileType.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperTileType.java @@ -19,10 +19,6 @@ public enum MinesweeperTileType { /** * A bomb tile that should be marked by nearby flags */ - BOMB; - - public int toValue() { - return this.ordinal() - 2; - } + BOMB } 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 deleted file mode 100644 index e1e0d1c5c..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/BombOrFilledCaseRule.java +++ /dev/null @@ -1,110 +0,0 @@ -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.TreeTransition; -import edu.rpi.legup.puzzle.minesweeper.MinesweeperBoard; -import edu.rpi.legup.puzzle.minesweeper.MinesweeperCell; -import edu.rpi.legup.puzzle.minesweeper.MinesweeperTileType; - -import java.util.ArrayList; -import java.util.List; - -public class BombOrFilledCaseRule extends CaseRule { - - public BombOrFilledCaseRule() { - super("NURI-CASE-0001", - "Bomb or Filled", - "Each blank cell is either a bomb or empty.", - "edu/rpi/legup/images/nurikabe/cases/BlackOrWhite.png"); - } - - /** - * Checks whether the {@link TreeTransition} logically follows from the parent node using this rule. This method is - * the one that should overridden in child classes. - * - * @param transition transition to check - * @return null if the child node logically follow from the parent node, otherwise error message - */ - @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.EMPTY && mod1.getTileType() == MinesweeperTileType.BOMB))) { - return super.getInvalidUseOfRuleMessage() + ": This case rule must an empty white and black cell."; - } - - return null; - } - - @Override - public CaseBoard getCaseBoard(Board board) { - MinesweeperBoard minesweeperBoard = (MinesweeperBoard) board.copy(); - CaseBoard caseBoard = new CaseBoard(minesweeperBoard, this); - minesweeperBoard.setModifiable(false); - for (PuzzleElement element : minesweeperBoard.getPuzzleElements()) { - if (((MinesweeperCell) element).getTileType() == MinesweeperTileType.UNSET) { - caseBoard.addPickableElement(element); - } - } - return caseBoard; - } - - /** - * Gets the possible cases at a specific location based on this case rule - * - * @param board the current board state - * @param puzzleElement equivalent puzzleElement - * @return a list of elements the specified could be - */ - @Override - public ArrayList getCases(Board board, PuzzleElement puzzleElement) { - ArrayList cases = new ArrayList<>(); - Board case1 = board.copy(); - PuzzleElement data1 = case1.getPuzzleElement(puzzleElement); - data1.setData(MinesweeperTileType.EMPTY.toValue()); - case1.addModifiedData(data1); - cases.add(case1); - - Board case2 = board.copy(); - PuzzleElement data2 = case2.getPuzzleElement(puzzleElement); - data2.setData(MinesweeperTileType.BOMB.toValue()); - case2.addModifiedData(data2); - cases.add(case2); - - return cases; - } - - /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule - * - * @param transition transition to check - * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message - */ - @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 d2914d1e8..e76129d04 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 @@ -28,5 +28,5 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { } - +} diff --git a/src/main/resources/edu/rpi/legup/legup/config b/src/main/resources/edu/rpi/legup/legup/config index 181357a90..f252be8f3 100644 --- a/src/main/resources/edu/rpi/legup/legup/config +++ b/src/main/resources/edu/rpi/legup/legup/config @@ -42,6 +42,6 @@ + fileCreationDisabled="true"/> From 194eb8b5f559c206f89472c645feed54d9710e91 Mon Sep 17 00:00:00 2001 From: vockek Date: Fri, 16 Feb 2024 14:45:17 -0500 Subject: [PATCH 08/41] Added --- .../legup/puzzle/minesweeper/rules/BombOrFilledCaseRule.java | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/BombOrFilledCaseRule.java 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 new file mode 100644 index 000000000..65faef5bd --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/BombOrFilledCaseRule.java @@ -0,0 +1,4 @@ +package edu.rpi.legup.puzzle.minesweeper.rules; + +public class BombOrFilledCaseRule { +} From ace712290986aead21470839844001c3eb9a582d Mon Sep 17 00:00:00 2001 From: vockek Date: Fri, 16 Feb 2024 14:53:57 -0500 Subject: [PATCH 09/41] Create 123456 --- puzzles files/minesweeper/5x5 Minesweeper Easy/123456 | 11 +++++++++++ 1 file changed, 11 insertions(+) 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 From 5f1b13ed24aa2097361b9daa04e0bf4707f9d82f Mon Sep 17 00:00:00 2001 From: vockek Date: Fri, 16 Feb 2024 16:08:59 -0500 Subject: [PATCH 10/41] 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 11/41] 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 12/41] 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 13/41] 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 14/41] 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 38a4c2413944f32217ebe571bc918a61d8561358 Mon Sep 17 00:00:00 2001 From: Fisher Date: Fri, 23 Feb 2024 10:36:16 -0500 Subject: [PATCH 15/41] Update Minesweeper classes to use newer Java features --- .../puzzle/minesweeper/MinesweeperCell.java | 17 ++++---- .../minesweeper/MinesweeperController.java | 14 +++---- .../minesweeper/MinesweeperTileData.java | 39 +++++-------------- .../minesweeper/MinesweeperUtilities.java | 4 ++ .../minesweeper/minesweeperUtilities.java | 13 ------- 5 files changed, 30 insertions(+), 57 deletions(-) create mode 100644 src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperUtilities.java delete mode 100644 src/main/java/edu/rpi/legup/puzzle/minesweeper/minesweeperUtilities.java 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..c7109caa5 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperCell.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperCell.java @@ -20,31 +20,34 @@ public MinesweeperCell(@NotNull MinesweeperTileData value, @NotNull Point locati @Override public void setType(@NotNull Element element, @NotNull MouseEvent event) { switch (element.getElementID()) { - case MinesweeperElementIdentifiers.BOMB: + case MinesweeperElementIdentifiers.BOMB -> { this.data = MinesweeperTileData.bomb(); break; - case MinesweeperElementIdentifiers.FLAG: + } + case MinesweeperElementIdentifiers.FLAG -> { final int currentData = super.data.data(); switch (event.getButton()) { - case MouseEvent.BUTTON1: + case MouseEvent.BUTTON1 -> { if (currentData >= 8) { this.data = MinesweeperTileData.empty(); return; } this.data = MinesweeperTileData.flag(currentData + 1); return; - case MouseEvent.BUTTON2: - case MouseEvent.BUTTON3: + } + case MouseEvent.BUTTON2, MouseEvent.BUTTON3 -> { if (currentData <= 0) { this.data = MinesweeperTileData.empty(); return; } this.data = MinesweeperTileData.flag(currentData - 1); return; + } } - return; - default: + } + default -> { this.data = MinesweeperTileData.empty(); + } } } 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 771cee543..fbb870390 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperController.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperController.java @@ -13,14 +13,12 @@ public class MinesweeperController extends ElementController { @NotNull MinesweeperTileData current ) { final int numberData = current.data(); - switch (event.getButton()) { - case MouseEvent.BUTTON1: - return MinesweeperTileData.fromData(numberData + 1); - case MouseEvent.BUTTON2: - case MouseEvent.BUTTON3: - return MinesweeperTileData.fromData(numberData - 1); - } - return MinesweeperTileData.empty(); + return switch (event.getButton()) { + case MouseEvent.BUTTON1 -> MinesweeperTileData.fromData(numberData + 1); + case MouseEvent.BUTTON2, + MouseEvent.BUTTON3 -> MinesweeperTileData.fromData(numberData - 1); + default -> MinesweeperTileData.empty(); + }; } @Override 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 37dc33983..1ba2501be 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperTileData.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperTileData.java @@ -5,7 +5,7 @@ import java.util.Objects; -public final class MinesweeperTileData { +public record MinesweeperTileData(MinesweeperTileType type, int data) { public static final int UNSET_DATA = -2; public static final int BOMB_DATA = -1; @@ -20,26 +20,23 @@ public final class MinesweeperTileData { } public static @NotNull MinesweeperTileData fromData(int data) { - switch (data) { - case UNSET_DATA: - return unset(); - case BOMB_DATA: - return bomb(); - case EMPTY_DATA: - return empty(); - default: { + return switch (data) { + case UNSET_DATA -> unset(); + case BOMB_DATA -> bomb(); + case EMPTY_DATA -> empty(); + default -> { if (data <= -2 || data > 8) { - return unset(); + yield unset(); } - return flag(data); + yield flag(data); } - } + }; } public static @NotNull MinesweeperTileData unset() { return UNSET; } - + public static @NotNull MinesweeperTileData bomb() { return BOMB; } @@ -48,22 +45,6 @@ public final class MinesweeperTileData { return EMPTY; } - private final MinesweeperTileType type; - private final int data; - - private MinesweeperTileData(@NotNull MinesweeperTileType type, int data) { - this.type = type; - this.data = data; - } - - public @NotNull MinesweeperTileType type() { - return this.type; - } - - public int data() { - return this.data; - } - @Override public boolean equals(@Nullable Object o) { if (this == o) return true; diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperUtilities.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperUtilities.java new file mode 100644 index 000000000..6cf9e3959 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperUtilities.java @@ -0,0 +1,4 @@ +package edu.rpi.legup.puzzle.minesweeper; + +public final class MinesweeperUtilities { +} diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/minesweeperUtilities.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/minesweeperUtilities.java deleted file mode 100644 index 6b4e56728..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/minesweeperUtilities.java +++ /dev/null @@ -1,13 +0,0 @@ -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; - -public class minesweeperUtilities { -} From fcea59a206bdf7ec42b3e298810b02e1d5bedede Mon Sep 17 00:00:00 2001 From: Fisher Date: Fri, 23 Feb 2024 16:49:23 -0500 Subject: [PATCH 16/41] Add documentation to Minesweeper classes --- .../legup/puzzle/minesweeper/Minesweeper.java | 6 ++++ .../puzzle/minesweeper/MinesweeperCell.java | 6 ++++ .../minesweeper/MinesweeperCellFactory.java | 33 ++++++++++++++++++- .../minesweeper/MinesweeperController.java | 19 +++++++++++ .../MinesweeperElementIdentifiers.java | 12 +++++++ .../minesweeper/MinesweeperElementView.java | 2 ++ .../minesweeper/MinesweeperExporter.java | 2 ++ .../minesweeper/MinesweeperImporter.java | 7 ++++ .../minesweeper/MinesweeperTileData.java | 30 +++++++++++++++++ .../minesweeper/MinesweeperTileType.java | 2 +- 10 files changed, 117 insertions(+), 2 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 6f00cd1ac..dd457f3d2 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/Minesweeper.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/Minesweeper.java @@ -4,6 +4,7 @@ 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; @@ -19,6 +20,7 @@ public Minesweeper() { } @Override + @Contract(pure = false) public void initializeView() { this.boardView = new MinesweeperView((MinesweeperBoard) this.currentBoard); this.boardView.setBoard(this.currentBoard); @@ -26,11 +28,13 @@ public void initializeView() { } @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; @@ -49,11 +53,13 @@ public boolean isBoardComplete(@NotNull Board board) { } @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/MinesweeperCell.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperCell.java index c7109caa5..50ab32393 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 org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import java.awt.*; @@ -18,6 +19,10 @@ public MinesweeperCell(@NotNull MinesweeperTileData value, @NotNull Point locati } @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 -> { @@ -52,6 +57,7 @@ public void setType(@NotNull Element element, @NotNull MouseEvent event) { } @Override + @Contract(pure = true) public @NotNull MinesweeperCell copy() { MinesweeperCell copy = new MinesweeperCell(data, (Point) location.clone()); copy.setIndex(index); 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 e32e2389a..45957cb82 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperCellFactory.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperCellFactory.java @@ -4,6 +4,7 @@ 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; @@ -14,8 +15,17 @@ public class MinesweeperCellFactory extends ElementFactory { - private static final String DATA_ATTRIBUTE = "x"; + /** + * 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"; @@ -24,7 +34,20 @@ 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 @@ -60,7 +83,15 @@ private MinesweeperCellFactory() { } } + /** + * + * @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 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 fbb870390..7289c349c 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperController.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperController.java @@ -2,12 +2,25 @@ 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 @@ -21,8 +34,14 @@ public class MinesweeperController extends ElementController { }; } + /** + * @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 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 96dd0a604..1b626a33b 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperElementIdentifiers.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperElementIdentifiers.java @@ -2,9 +2,21 @@ 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 1ff6e1c72..6384b3d99 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperElementView.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperElementView.java @@ -1,6 +1,7 @@ package edu.rpi.legup.puzzle.minesweeper; import edu.rpi.legup.ui.boardview.GridElementView; +import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import java.awt.*; @@ -21,6 +22,7 @@ public MinesweeperElementView(@NotNull MinesweeperCell cell) { @Override @SuppressWarnings("Duplicates") + @Contract(pure = true) public void drawElement(@NotNull Graphics2D graphics2D) { final MinesweeperCell cell = (MinesweeperCell) puzzleElement; final MinesweeperTileType type = cell.getTileType(); 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 20ff19410..0a4f69fd6 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperExporter.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperExporter.java @@ -3,6 +3,7 @@ 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; @@ -14,6 +15,7 @@ public MinesweeperExporter(@NotNull Puzzle puzzle) { } @Override + @Contract(pure = true) protected @NotNull Element createBoardElement(@NotNull Document newDocument) { MinesweeperBoard board; if (puzzle.getTree() != null) { 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 d8835b409..8dc7037f9 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperImporter.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperImporter.java @@ -2,6 +2,7 @@ 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; @@ -16,16 +17,19 @@ public MinesweeperImporter(@NotNull Minesweeper 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); @@ -41,6 +45,7 @@ public void initializeBoard(int rows, int columns) { } @Override + @Contract(pure = false) public void initializeBoard(@NotNull Node node) throws InvalidFileFormatException { try { if (!node.getNodeName().equalsIgnoreCase("board")) { @@ -85,6 +90,7 @@ public void initializeBoard(@NotNull Node node) throws InvalidFileFormatExceptio } } + @Contract(pure = true) private static @NotNull MinesweeperBoard getMinesweeperBoard(@NotNull Element boardElement) throws InvalidFileFormatException { MinesweeperBoard minesweeperBoard = null; if (!boardElement.getAttribute("size").isEmpty()) { @@ -106,6 +112,7 @@ public void initializeBoard(@NotNull Node node) throws InvalidFileFormatExceptio } @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 1ba2501be..0e86ff63e 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperTileData.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperTileData.java @@ -1,5 +1,6 @@ package edu.rpi.legup.puzzle.minesweeper; +import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -7,18 +8,47 @@ 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(); 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 ec7a10eb2..9d5dabd69 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperTileType.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperTileType.java @@ -9,7 +9,7 @@ public enum MinesweeperTileType { UNSET, /** - * Represents a cell with no bombs in it + * Represents a cell with no bombs in it */ EMPTY, /** From 294814f3acd1429ad18abd6033b6f750bb4631e5 Mon Sep 17 00:00:00 2001 From: vockek Date: Fri, 23 Feb 2024 17:03:57 -0500 Subject: [PATCH 17/41] 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 18/41] 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 19/41] 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 20/41] 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 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 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 21/41] 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 bca8755d747f43c9bc02372329d3eff009c7b089 Mon Sep 17 00:00:00 2001 From: Fisher Date: Tue, 27 Feb 2024 17:04:10 -0500 Subject: [PATCH 22/41] Add some methods to MinesweeperUtilities and created some tests to verify the getSurroundingCells function works as expected. --- .../puzzle/minesweeper/MinesweeperBoard.java | 5 ++ .../minesweeper/MinesweeperTileData.java | 16 ++++ .../minesweeper/MinesweeperUtilities.java | 74 ++++++++++++++++++ .../rules/BombOrFilledCaseRule.java | 36 ++++++++- src/test/java/legup/TestRunner.java | 9 ++- .../minesweeper/MinesweeperUtilitiesTest.java | 75 +++++++++++++++++++ .../puzzles/minesweeper/utilities/3x3test | 11 +++ 7 files changed, 223 insertions(+), 3 deletions(-) create mode 100644 src/test/java/puzzles/minesweeper/MinesweeperUtilitiesTest.java create mode 100644 src/test/resources/puzzles/minesweeper/utilities/3x3test 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..696d42113 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperBoard.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperBoard.java @@ -11,4 +11,9 @@ public MinesweeperBoard(int width, int height) { public MinesweeperBoard(int size) { super(size); } + + @Override + public MinesweeperCell getCell(int x, int y) { + return (MinesweeperCell) super.getCell(x, y); + } } 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 0e86ff63e..79666c243 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperTileData.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperTileData.java @@ -75,6 +75,22 @@ public record MinesweeperTileData(MinesweeperTileType type, int data) { 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; 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 6cf9e3959..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,4 +1,78 @@ package edu.rpi.legup.puzzle.minesweeper; +import java.awt.*; +import java.util.Objects; +import java.util.stream.IntStream; +import java.util.stream.Stream; + 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 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) { + return countSurroundingType(board, cell, MinesweeperTileType.BOMB); + } + + public static int countSurroundingUnset(MinesweeperBoard board, MinesweeperCell cell) { + return countSurroundingType(board, cell, MinesweeperTileType.UNSET); + } + + public static int countSurroundingEmpty(MinesweeperBoard board, MinesweeperCell cell) { + return countSurroundingType(board, cell, MinesweeperTileType.EMPTY); + } + + public static int countSurroundingFlags(MinesweeperBoard board, MinesweeperCell cell) { + return countSurroundingType(board, cell, MinesweeperTileType.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()) { + throw new IllegalArgumentException("Bombs are only needed surrounding flags"); + } + return cell.getData().data() - countSurroundingBombs(board, cell); + } + } 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..f7c42dc6f 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,38 @@ 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 java.util.List; + +public class BombOrFilledCaseRule extends CaseRule { + + public BombOrFilledCaseRule() { + super("MINE-CASE-0000", "Bomb Or Filled", + "A cell can either be a bomb or filled.\n", + ""); + } + + @Override + public CaseBoard getCaseBoard(Board board) { + return null; + } + + @Override + public List getCases(Board board, PuzzleElement puzzleElement) { + return null; + } + + @Override + public String checkRuleRaw(TreeTransition transition) { + return null; + } + + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + return null; + } } diff --git a/src/test/java/legup/TestRunner.java b/src/test/java/legup/TestRunner.java index 40cc5fa6c..95f6f4f8a 100644 --- a/src/test/java/legup/TestRunner.java +++ b/src/test/java/legup/TestRunner.java @@ -3,10 +3,11 @@ import org.junit.runner.JUnitCore; import org.junit.runner.Result; import org.junit.runner.notification.Failure; -import puzzles.battleship.rules.*; +import puzzles.battleship.rules.AdjacentShipsContradictionRuleTest; +import puzzles.battleship.rules.FinishWithShipsDirectRuleTests; import puzzles.lightup.rules.*; +import puzzles.minesweeper.MinesweeperUtilitiesTest; import puzzles.nurikabe.rules.*; -import puzzles.skyscrapers.rules.*; import puzzles.treetent.rules.*; /** This class runs all of the tests for the project without needing to run build scripts. */ @@ -91,6 +92,10 @@ public static void main(String[] args) { printTestResults(result35); Result result36 = JUnitCore.runClasses(TentOrGrassCaseRuleTest.class); printTestResults(result36); + + // Minesweeper + Result result37 = JUnitCore.runClasses(MinesweeperUtilitiesTest.class); + printTestResults(result37); } private static void printTestResults(Result result) { diff --git a/src/test/java/puzzles/minesweeper/MinesweeperUtilitiesTest.java b/src/test/java/puzzles/minesweeper/MinesweeperUtilitiesTest.java new file mode 100644 index 000000000..4b1b450c8 --- /dev/null +++ b/src/test/java/puzzles/minesweeper/MinesweeperUtilitiesTest.java @@ -0,0 +1,75 @@ +package puzzles.minesweeper; + +import edu.rpi.legup.puzzle.minesweeper.Minesweeper; +import edu.rpi.legup.puzzle.minesweeper.MinesweeperBoard; +import edu.rpi.legup.puzzle.minesweeper.MinesweeperCell; +import edu.rpi.legup.puzzle.minesweeper.MinesweeperUtilities; +import edu.rpi.legup.save.InvalidFileFormatException; +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; + + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + minesweeper = new Minesweeper(); + } + + @Test + public void getSurroundingCellsSizeThreeByThreeAtOneXOneTest() throws InvalidFileFormatException { + + TestUtilities.importTestBoard( + "puzzles/minesweeper/utilities/3x3test", + minesweeper); + + final MinesweeperBoard board = (MinesweeperBoard) minesweeper.getCurrentBoard(); + MinesweeperCell cell = board.getCell(1, 1); + + final Stream cells = MinesweeperUtilities.getSurroundingCells(board, cell); + + final long count = cells.count(); + Assert.assertEquals(count, 8); + } + + @Test + public void getSurroundingCellsSizeThreeByThreeAtZeroXZeroTest() throws InvalidFileFormatException { + + TestUtilities.importTestBoard( + "puzzles/minesweeper/utilities/3x3test", + minesweeper); + + final MinesweeperBoard board = (MinesweeperBoard) minesweeper.getCurrentBoard(); + MinesweeperCell cell = board.getCell(0, 0); + + final Stream cells = MinesweeperUtilities.getSurroundingCells(board, cell); + + final long count = cells.count(); + Assert.assertEquals(count, 3); + } + + @Test + public void getSurroundingCellsSizeThreeByThreeAtZeroXOneTest() throws InvalidFileFormatException { + + TestUtilities.importTestBoard( + "puzzles/minesweeper/utilities/3x3test", + minesweeper); + + final MinesweeperBoard board = (MinesweeperBoard) minesweeper.getCurrentBoard(); + MinesweeperCell cell = board.getCell(0, 1); + + final Stream cells = MinesweeperUtilities.getSurroundingCells(board, cell); + + final long count = cells.count(); + Assert.assertEquals(count, 5); + } + + +} diff --git a/src/test/resources/puzzles/minesweeper/utilities/3x3test b/src/test/resources/puzzles/minesweeper/utilities/3x3test new file mode 100644 index 000000000..2bf4f5c3b --- /dev/null +++ b/src/test/resources/puzzles/minesweeper/utilities/3x3test @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file From b4c8ed9b91fe5ba822df71799c68c017dd42f074 Mon Sep 17 00:00:00 2001 From: vockek Date: Tue, 12 Mar 2024 16:37:24 -0400 Subject: [PATCH 23/41] 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 7dcdfc097b031767aa3058851cdfe2b26187bc02 Mon Sep 17 00:00:00 2001 From: FisherLuba <145061313+FisherLuba@users.noreply.github.com> Date: Tue, 12 Mar 2024 16:41:12 -0400 Subject: [PATCH 24/41] Added BombOrFilledCaseRule --- .../puzzle/minesweeper/MinesweeperBoard.java | 17 ++++++ .../rules/BombOrFilledCaseRule.java | 57 ++++++++++++++++++- src/main/resources/edu/rpi/legup/legup/config | 4 ++ 3 files changed, 76 insertions(+), 2 deletions(-) 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 696d42113..ea6f560e1 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperBoard.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperBoard.java @@ -16,4 +16,21 @@ public MinesweeperBoard(int size) { 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/rules/BombOrFilledCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/BombOrFilledCaseRule.java index f7c42dc6f..bad89b4a4 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,7 +5,12 @@ 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.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 { @@ -18,16 +23,64 @@ public BombOrFilledCaseRule() { @Override public CaseBoard getCaseBoard(Board board) { - return null; + 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.getData().isUnset()) { + caseBoard.addPickableElement(data); + } + } + return caseBoard; } @Override public List getCases(Board board, PuzzleElement puzzleElement) { - return null; + ArrayList cases = new ArrayList<>(); + + Board case1 = board.copy(); + MinesweeperCell cell1 = (MinesweeperCell) case1.getPuzzleElement(puzzleElement); + cell1.setData(MinesweeperTileData.bomb()); + case1.addModifiedData(cell1); + cases.add(case1); + + Board case2 = board.copy(); + MinesweeperCell cell2 = (MinesweeperCell) case2.getPuzzleElement(puzzleElement); + cell2.setData(MinesweeperTileData.empty()); + 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.getData().isBomb() && mod2.getData().isEmpty()) + || (mod2.getData().isBomb() && mod1.getData().isEmpty()))) { + return super.getInvalidUseOfRuleMessage() + + ": This case rule must an empty cell and a bomb cell."; + } + return null; } diff --git a/src/main/resources/edu/rpi/legup/legup/config b/src/main/resources/edu/rpi/legup/legup/config index ccd4f5be3..0bfc68914 100644 --- a/src/main/resources/edu/rpi/legup/legup/config +++ b/src/main/resources/edu/rpi/legup/legup/config @@ -39,5 +39,9 @@ qualifiedClassName="edu.rpi.legup.puzzle.skyscrapers.Skyscrapers" fileType=".xml" fileCreationDisabled="false"/> + From ee4b707a3fa86fe72a38d3576b873c918cbad16a Mon Sep 17 00:00:00 2001 From: vockek Date: Tue, 12 Mar 2024 17:01:34 -0400 Subject: [PATCH 25/41] 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 26/41] 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 0e89c1126d2465c1f220854816adf14f486c2dda Mon Sep 17 00:00:00 2001 From: FisherLuba <145061313+FisherLuba@users.noreply.github.com> Date: Tue, 12 Mar 2024 17:14:42 -0400 Subject: [PATCH 27/41] Add bomb image --- .../minesweeper/MinesweeperElementView.java | 15 ++++++++++++ .../puzzle/minesweeper/MinesweeperView.java | 23 ++++++++++++++++++ .../puzzle/minesweeper/elements/Bomb.java | 2 +- .../legup/images/minesweeper/tiles/Bomb.png | Bin 0 -> 5572 bytes 4 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 src/main/resources/edu/rpi/legup/images/minesweeper/tiles/Bomb.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 6384b3d99..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,5 +1,6 @@ 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; @@ -58,5 +59,19 @@ public void drawElement(@NotNull Graphics2D graphics2D) { 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/MinesweeperView.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperView.java index 78747a199..ca9214416 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperView.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperView.java @@ -2,13 +2,36 @@ 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()); diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/Bomb.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/Bomb.java index 6fe86dcee..f5305f46a 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/Bomb.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/Bomb.java @@ -3,6 +3,6 @@ import edu.rpi.legup.model.elements.NonPlaceableElement; public class Bomb extends NonPlaceableElement{ public Bomb() { - super("MINE-UNPL-0001", "Bomb", "A bomb", "edu/rpi/legup/images/nurikabe/tiles/NumberTile.png"); + super("MINE-UNPL-0001", "Bomb", "A bomb", "edu/rpi/legup/images/minesweeper/tiles/Bomb.png"); } } diff --git a/src/main/resources/edu/rpi/legup/images/minesweeper/tiles/Bomb.png b/src/main/resources/edu/rpi/legup/images/minesweeper/tiles/Bomb.png new file mode 100644 index 0000000000000000000000000000000000000000..dd6bad509542c4ac925986d71315b4d655e952c4 GIT binary patch literal 5572 zcmeHLc~leU77v252(BO~ATgi}$;|!k{eAcT?)~mJ zlN7$Umzl{F6AT7p#+}dh1;1GBVKfSyRdI3M7>t2D&M#2yi)gS4rCcnDM6v2v1&T#u zBw`FErtw6;vhs(Hru{dZ#m4inQ!m^Px;8tf_44?eC%KL74n5InA!VLM?K|ubvHF`= zBo3VZ{d$aYLZMHSyfRpsLY}g6SwMl$;bU*|EIV0k&F$?rp?hZS3c1^+dCQV}8!ix4 zwA3sred~G5ZoaI?&d%o9>QbDqxm2?`+H1>=Rkv(gekr|JVkOJw_hmi{nac0R+@M+Hj z8Ot6m_1PH7XyQF(W%fG}UWr<^Wo_-tt;IiwPTsJ8gG`I7JvmSlzOvp$XmKlcS7T=? za|>zNp>K?K?zGq2w$^9kl=T^LGw+P|4>`T`_LC)wfK8@}2ar6;j9jE|^EE$D^_>*` zDfJd_Iav*(yo2|@eB4b*WDoZvYg3OX_mNRUG2qFo6Yi8zrHN*Q=hS_ zve*A2C zClPzfinm$QZYzGEG|x?ie!0W*a*DdK`|Z@Yr+Xi-_O;%!#+vlb$UdF&@_eIrhrGwI zbZfp#!NR==Jt&cybT+x+A$v1=a_Fe>erZ*W$5JV;CU^_|Pcv_3BX+JtQYbd8(y*LjEI~H;6 zc)j}0%*!FCTx%h< z7`I{4lcrS(_~J8_h3)yrt9z!mPlW{!4tnN?`NfaMRU2?E9S_c!Hm%6Eqw1x%9Q&9+ z7_Hy5kYp%#uuYqoNxdWeZoALPeAc772O+T&HxzK*nmf7Wit-0oeK`Z?N-x!TdA1i% z5?h3LU%|cFy|ZL{cKMU%O)t^%$yv#kOq=`q{bM_dG_M;rT}^U?J2)2)RkXQ?pA|N| z@&E1uZcK9-Ck|TiSNr2?0{3#B!JMVNwenniYyE3e1#MnLhS`~(XDT`tmfyZ*YZ1-ooJZQZ+JPJ!=8~b zV1>cxB}!N9z4Cbs|`1OfZ$ZI?!~=IyUyos&ztn- z9i}HN?JT|rBn8btiI*r*+#g+oXoAL135LQH~rxE2EB2X_k#u=57;DrcUs`- ziAyJ*tw^D*3!_OByWGoa>&n0Vm$$3r%E%PEV+Ug1)f{UnKSkz{a|>opO4;pe`AtZD zUGY3umdz5E{Fljj=bRrymzMr=sj;VpU~18wWqL!BK5g}Mho2G*Mn?JZlhcg$Go2<~ zsj%yLv9W5v{Fu4Y|5R<+swtG(19tDm{-BAlC@EU*>o}(SB>mDk`X5I}S4>IoihoMq zKM~t&8r*LC<9_4%_{^rZ@cZ_m;ntOv&%^7cDvs%IaGhN4^s8@1F@M&G&aiG?Y-sN! ztH7?fh|Y)IdbPd*7igzWPlFc~K8@P0>CyDO?%W#vqlYO^*`ntkcNl{i<1Ya_K_G7- zQz)0>5s_Sg;$x%=uv1_#t{yQ8L>Pgpu>v$qB6Gua{`wmZD-pTj0$g}7Pr*XNCG+Ey z=;AnUKVe*ikRif(xSP1fFadxRRU_CKX{1cWjB&&1aGBs*D<JC*M}YYd?q}K` zW7jDIEgp}_mJ6e_?s3^}IPLsQkz6PdF?E+@Dpf#)MJNPL42U9z1&{zmL=crECKD+n zgd#@8!=Sh_l^T%=Q7sez$4dYXg#kcZ1OkYT3ds#i$l+dTp+o?RNJCsm6jT6-86@BhN+&@A8bX2)7crQH#-Ng6k53(Oqc{NAQ(u7>B~hDaqNH7)-E5c>tNF7 zOH^R~Se-CirR$3r_#)-6)%BIGFJj<}l)qNj|BWt_Pw$GT z3_Rdzz?)#Tr#BzGMUE0I@M2@$Yri{AlxzYLW5xU+6$UeUqV~|kY|8_G3t$Y@Tpq`; zP2bdFgqgHCB@u`oaoKbH0?$6nzG$2Tn>-?|!8*(m3^&u0?Ww%MHVE3nV6|m69`Vnt zs(OUj@8$iuXD`*#-S%qK-PW4-H-&od^>@W^qOI3o1F Date: Tue, 12 Mar 2024 17:25:36 -0400 Subject: [PATCH 28/41] Added reference sheet for Minesweeper tiles for puzzle editor --- .../minesweeper/elements/{Bomb.java => BombTile.java} | 4 ++-- .../legup/puzzle/minesweeper/elements/EmptyTile.java | 10 ++++++++++ .../minesweeper/elements/{Flag.java => FlagTile.java} | 6 +++--- .../legup/puzzle/minesweeper/elements/UnsetTile.java | 11 +++++++++++ .../elements/minesweeper_elements_reference_sheet.txt | 4 ++++ 5 files changed, 30 insertions(+), 5 deletions(-) rename src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/{Bomb.java => BombTile.java} (74%) create mode 100644 src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/EmptyTile.java rename src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/{Flag.java => FlagTile.java} (53%) create mode 100644 src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/UnsetTile.java create mode 100644 src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/minesweeper_elements_reference_sheet.txt diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/Bomb.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/BombTile.java similarity index 74% rename from src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/Bomb.java rename to src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/BombTile.java index f5305f46a..90bd8fb90 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/Bomb.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/BombTile.java @@ -1,8 +1,8 @@ package edu.rpi.legup.puzzle.minesweeper.elements; import edu.rpi.legup.model.elements.NonPlaceableElement; -public class Bomb extends NonPlaceableElement{ - public Bomb() { +public class BombTile extends NonPlaceableElement{ + public BombTile() { super("MINE-UNPL-0001", "Bomb", "A bomb", "edu/rpi/legup/images/minesweeper/tiles/Bomb.png"); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/EmptyTile.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/EmptyTile.java new file mode 100644 index 000000000..dad1593ca --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/EmptyTile.java @@ -0,0 +1,10 @@ +package edu.rpi.legup.puzzle.minesweeper.elements; + +import edu.rpi.legup.model.elements.PlaceableElement; + +public class EmptyTile extends PlaceableElement { + + public EmptyTile() { + 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/Flag.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/FlagTile.java similarity index 53% rename from src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/Flag.java rename to src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/FlagTile.java index 9e9b53bae..b6d44d11a 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/Flag.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/FlagTile.java @@ -1,8 +1,8 @@ package edu.rpi.legup.puzzle.minesweeper.elements; import edu.rpi.legup.model.elements.PlaceableElement; -public class Flag extends PlaceableElement{ - public Flag() { - super("NURI-PLAC-0001", "Flag", "The flag", "edu/rpi/legup/images/nurikabe/tiles/BlackTile.png"); +public class FlagTile extends PlaceableElement{ + public FlagTile() { + super("MINE-PLAC-0001", "Flag", "The flag", "edu/rpi/legup/images/nurikabe/tiles/BlackTile.png"); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/UnsetTile.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/UnsetTile.java new file mode 100644 index 000000000..1899a4fd5 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/UnsetTile.java @@ -0,0 +1,11 @@ +package edu.rpi.legup.puzzle.minesweeper.elements; + +import edu.rpi.legup.model.elements.NonPlaceableElement; + +public class UnsetTile extends NonPlaceableElement { + + public UnsetTile() { + 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/elements/minesweeper_elements_reference_sheet.txt b/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/minesweeper_elements_reference_sheet.txt new file mode 100644 index 000000000..08ce23f59 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/minesweeper_elements_reference_sheet.txt @@ -0,0 +1,4 @@ +MINE-UNPL-0001 : BombTile +MINE-PLAC-0001 : FlagTile +MINE-PLAC-0002 : EmptyTile +MINE-UNPL-0002 : UnsetTile \ No newline at end of file From 3a1cee218e8abf06d64a0bda575415ee334b5473 Mon Sep 17 00:00:00 2001 From: vockek Date: Tue, 19 Mar 2024 17:47:35 -0400 Subject: [PATCH 29/41] 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 30/41] 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 31/41] 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 32/41] 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 33/41] 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 34/41] 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 35/41] 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 36/41] 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 From ef3685172fece2d120218ef25236223334d9ff80 Mon Sep 17 00:00:00 2001 From: vockek Date: Tue, 2 Apr 2024 16:14:21 -0400 Subject: [PATCH 37/41] Fixed "satisfy flag" bug fixed bug where "satisfy flag" allowed you to select an empty tile instead of a flag tile --- .../rpi/legup/puzzle/minesweeper/rules/SatisfyFlagCaseRule.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 257cfb41b..e3cd382ed 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 @@ -27,7 +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); } } From bbf799b99ac5fb86dce04bbb720beb859e9b9304 Mon Sep 17 00:00:00 2001 From: vockek Date: Tue, 16 Apr 2024 16:50:11 -0400 Subject: [PATCH 38/41] Added "Finish With Bombs" Direct Rule --- .../minesweeper/MinesweeperUtilities.java | 23 ++++++- .../rules/FinishWithBombsDirectRule.java | 62 ++++++++++++++++++ .../LessBombsThanFlagContradictionRule.java | 32 +++++++-- .../images/minesweeper/direct/Fill_Bombs.jpg | Bin 0 -> 22643 bytes 4 files changed, 110 insertions(+), 7 deletions(-) create mode 100644 src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/FinishWithBombsDirectRule.java create mode 100644 src/main/resources/edu/rpi/legup/images/minesweeper/direct/Fill_Bombs.jpg 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..f54a1d825 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperUtilities.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperUtilities.java @@ -1,5 +1,11 @@ package edu.rpi.legup.puzzle.minesweeper; +import edu.rpi.legup.puzzle.fillapix.FillapixBoard; +import edu.rpi.legup.puzzle.fillapix.FillapixCell; +import edu.rpi.legup.puzzle.fillapix.FillapixCellType; +import edu.rpi.legup.puzzle.fillapix.rules.TooFewBlackCellsContradictionRule; +import edu.rpi.legup.puzzle.minesweeper.rules.LessBombsThanFlagContradictionRule; + import java.awt.*; import java.util.Objects; import java.util.stream.IntStream; @@ -95,7 +101,7 @@ public static ArrayList getAdjacentCells(MinesweeperBoard board continue; } MinesweeperCell adjCell = (MinesweeperCell) board.getCell(cellLoc.x + i, cellLoc.y + j); - if (adjCell == null) { + if (adjCell == null || adjCell == cell) { continue; } adjCells.add(adjCell); @@ -137,5 +143,20 @@ private static void recurseCombinations(ArrayList result, int curInde recurseCombinations(result, curIndex+1, maxBlack, numBlack, len, workingArray); } + public static boolean isForcedBomb(MinesweeperBoard board, MinesweeperCell cell) { + + LessBombsThanFlagContradictionRule tooManyBombs = + new LessBombsThanFlagContradictionRule(); + MinesweeperBoard emptyCaseBoard = board.copy(); + MinesweeperCell emptyCell = (MinesweeperCell) emptyCaseBoard.getPuzzleElement(cell); + emptyCell.setCellType(MinesweeperTileData.empty()); + ArrayList adjCells = getAdjacentCells(emptyCaseBoard, emptyCell); + for (MinesweeperCell adjCell : adjCells) { + if (tooManyBombs.checkContradictionAt(emptyCaseBoard, adjCell) == null) { + return true; + } + } + return false; + } } diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/FinishWithBombsDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/FinishWithBombsDirectRule.java new file mode 100644 index 000000000..67bbe6a33 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/FinishWithBombsDirectRule.java @@ -0,0 +1,62 @@ +package edu.rpi.legup.puzzle.minesweeper.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.minesweeper.*; + +public class FinishWithBombsDirectRule extends DirectRule { + public FinishWithBombsDirectRule() { + super( + "Finish with Bombs", + "The remaining unknowns around a flag must be bombs to satisfy the number", + "edu/rpi/legup/images/minesweeper/direct/Fill_Bombs.jpg"); + } + + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + MinesweeperBoard board = (MinesweeperBoard) transition.getBoard(); + MinesweeperBoard parentBoard = (MinesweeperBoard) transition.getParents().get(0).getBoard(); + MinesweeperCell cell = (MinesweeperCell) board.getPuzzleElement(puzzleElement); + MinesweeperCell parentCell = (MinesweeperCell) parentBoard.getPuzzleElement(puzzleElement); + + if (!(parentCell.getTileType() == MinesweeperTileType.UNSET + && cell.getTileType() == MinesweeperTileType.BOMB)) { + return super.getInvalidUseOfRuleMessage() + + ": This cell must be black to be applicable with this rule."; + } + + if (MinesweeperUtilities.isForcedBomb(parentBoard, cell)) { + return null; + } else { + return super.getInvalidUseOfRuleMessage() + ": This cell is not forced to be black"; + } + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + MinesweeperBoard minesweeperBoard = (MinesweeperBoard) node.getBoard().copy(); + for (PuzzleElement element : minesweeperBoard.getPuzzleElements()) { + MinesweeperCell cell = (MinesweeperCell) element; + if (cell.getTileType() == MinesweeperTileType.UNSET + && MinesweeperUtilities.isForcedBomb((MinesweeperBoard) node.getBoard(), cell)) { + cell.setCellType(MinesweeperTileData.bomb()); + minesweeperBoard.addModifiedData(cell); + } + } + if (minesweeperBoard.getModifiedData().isEmpty()) { + return null; + } else { + return minesweeperBoard; + } + } +} 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..5d809d527 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,12 +3,10 @@ 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.puzzle.minesweeper.*; import edu.rpi.legup.utility.DisjointSets; +import java.util.ArrayList; import java.util.Set; public class LessBombsThanFlagContradictionRule extends ContradictionRule { @@ -23,8 +21,30 @@ public LessBombsThanFlagContradictionRule() { @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { - - return null; + MinesweeperBoard minesweeperBoard = (MinesweeperBoard) board; + MinesweeperCell cell = (MinesweeperCell) minesweeperBoard.getPuzzleElement(puzzleElement); + + int cellNum = cell.getTileNumber(); + if (cellNum <= 0 || cellNum >= 9) { + return super.getNoContradictionMessage(); + } + int numEmpty = 0; + int numAdj = 0; + ArrayList adjCells = MinesweeperUtilities.getAdjacentCells(minesweeperBoard, cell); + for (MinesweeperCell adjCell : adjCells) { + numAdj++; + if (adjCell.getTileType() == MinesweeperTileType.EMPTY && adjCell != cell) { + numEmpty++; + } + } + System.out.println(numEmpty); + System.out.println(numAdj); + System.out.println(cellNum); + if (numEmpty > (numAdj-cellNum)) { + return null; + } + + return super.getNoContradictionMessage(); } diff --git a/src/main/resources/edu/rpi/legup/images/minesweeper/direct/Fill_Bombs.jpg b/src/main/resources/edu/rpi/legup/images/minesweeper/direct/Fill_Bombs.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8214972ac8bf278e441e719ad9ef32c3feae346e GIT binary patch literal 22643 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 qKNsOIqW7=B3F9s2eTRO!tr)YnHh$2ag@yf literal 0 HcmV?d00001 From 8c653d8fb80c406d6bd9cd03f438a7e2f80f1a90 Mon Sep 17 00:00:00 2001 From: vockek Date: Tue, 16 Apr 2024 16:52:42 -0400 Subject: [PATCH 39/41] Update FinishWithBombsDirectRule.java --- .../puzzle/minesweeper/rules/FinishWithBombsDirectRule.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/FinishWithBombsDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/FinishWithBombsDirectRule.java index 67bbe6a33..9f5c4279c 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/FinishWithBombsDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/FinishWithBombsDirectRule.java @@ -10,6 +10,7 @@ public class FinishWithBombsDirectRule extends DirectRule { public FinishWithBombsDirectRule() { super( + "MINE-BASC-0001", "Finish with Bombs", "The remaining unknowns around a flag must be bombs to satisfy the number", "edu/rpi/legup/images/minesweeper/direct/Fill_Bombs.jpg"); From 30b6e5edb5cfc3d1fe9b3032813a169e97ecbf7a Mon Sep 17 00:00:00 2001 From: Bram van Heuveln Date: Tue, 16 Apr 2024 21:41:35 +0000 Subject: [PATCH 40/41] Automated Java code formatting changes --- .../rpi/legup/model/gameboard/GridRegion.java | 16 +- .../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 | 167 ++++++------ .../minesweeper/MinesweeperExporter.java | 88 +++---- .../minesweeper/MinesweeperImporter.java | 247 +++++++++--------- .../minesweeper/MinesweeperTileData.java | 213 +++++++-------- .../minesweeper/MinesweeperTileType.java | 38 +-- .../minesweeper/MinesweeperUtilities.java | 86 +++--- .../puzzle/minesweeper/MinesweeperView.java | 128 ++++----- .../puzzle/minesweeper/elements/BombTile.java | 9 +- .../minesweeper/elements/EmptyTile.java | 6 +- .../puzzle/minesweeper/elements/FlagTile.java | 9 +- .../minesweeper/elements/UnsetTile.java | 7 +- .../rules/BombOrFilledCaseRule.java | 12 +- .../rules/FinishWithBombsDirectRule.java | 3 +- .../LessBombsThanFlagContradictionRule.java | 18 +- .../MoreBombsThanFlagContradictionRule.java | 4 +- .../rules/SatisfyFlagCaseRule.java | 42 +-- .../legup/puzzle/starbattle/StarBattle.java | 4 +- .../puzzle/starbattle/StarBattleBoard.java | 20 +- .../puzzle/starbattle/StarBattleCell.java | 29 +- .../starbattle/StarBattleCellFactory.java | 26 +- .../puzzle/starbattle/StarBattleCellType.java | 10 +- .../starbattle/StarBattleController.java | 20 +- .../starbattle/StarBattleElementView.java | 11 +- .../puzzle/starbattle/StarBattleExporter.java | 6 +- .../puzzle/starbattle/StarBattleImporter.java | 31 +-- .../puzzle/starbattle/StarBattleRegion.java | 6 +- .../puzzle/starbattle/StarBattleView.java | 25 +- .../puzzle/starbattle/elements/BlackTile.java | 6 +- .../puzzle/starbattle/elements/StarTile.java | 6 +- .../starbattle/elements/UnknownTile.java | 6 +- .../puzzle/starbattle/elements/WhiteTile.java | 7 +- .../starbattle/rules/BlackoutDirectRule.java | 18 +- .../rules/ClashingOrbitContradictionRule.java | 25 +- .../rules/ColumnsWithinRegionsDirectRule.java | 39 +-- .../rules/ColumnsWithinRowsDirectRule.java | 38 +-- .../rules/FinishWithStarsDirectRule.java | 16 +- .../rules/RegionsWithinColumnsDirectRule.java | 16 +- .../rules/RegionsWithinRowsDirectRule.java | 16 +- .../rules/RowsWithinColumnsDirectRule.java | 22 +- .../rules/RowsWithinRegionsDirectRule.java | 38 +-- .../starbattle/rules/StarOrEmptyCaseRule.java | 33 +-- .../rules/SurroundStarDirectRule.java | 17 +- .../rules/TooFewStarsContradictionRule.java | 17 +- .../rules/TooManyStarsContradictionRule.java | 19 +- .../edu/rpi/legup/utility/LegupUtils.java | 3 +- .../minesweeper/MinesweeperUtilitiesTest.java | 26 +- .../rules/BlackoutDirectRuleTest.java | 26 +- 54 files changed, 1203 insertions(+), 1193 deletions(-) diff --git a/src/main/java/edu/rpi/legup/model/gameboard/GridRegion.java b/src/main/java/edu/rpi/legup/model/gameboard/GridRegion.java index 6718ab6f4..c41d5e1b2 100644 --- a/src/main/java/edu/rpi/legup/model/gameboard/GridRegion.java +++ b/src/main/java/edu/rpi/legup/model/gameboard/GridRegion.java @@ -4,18 +4,17 @@ import java.util.List; public abstract class GridRegion { - + protected List regionCells; - - /** - * Region Constructor - */ + + /** Region Constructor */ public GridRegion() { this.regionCells = new ArrayList<>(); } /** * Adds the cell to the region + * * @param cell cell to be added to the region */ public void addCell(T cell) { @@ -24,6 +23,7 @@ public void addCell(T cell) { /** * Removes the cell from the region + * * @param cell cell to be remove from the region */ public void removeCell(T cell) { @@ -32,6 +32,7 @@ public void removeCell(T cell) { /** * Returns the list of cells in the region + * * @return list of cells in region */ public List getCells() { @@ -40,14 +41,15 @@ public List getCells() { /** * Returns the number of cells in the region + * * @return number of cells in the region */ - public int getSize(){ + public int getSize() { return regionCells.size(); } /* public void colorRegion(){} */ - + } 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 181b25d81..1bfc0d698 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperElementView.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperElementView.java @@ -1,84 +1,83 @@ -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.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); - } - 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.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); + } + 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 f54a1d825..d38460ac8 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperUtilities.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperUtilities.java @@ -1,23 +1,19 @@ package edu.rpi.legup.puzzle.minesweeper; -import edu.rpi.legup.puzzle.fillapix.FillapixBoard; -import edu.rpi.legup.puzzle.fillapix.FillapixCell; -import edu.rpi.legup.puzzle.fillapix.FillapixCellType; -import edu.rpi.legup.puzzle.fillapix.rules.TooFewBlackCellsContradictionRule; import edu.rpi.legup.puzzle.minesweeper.rules.LessBombsThanFlagContradictionRule; - 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(); @@ -31,27 +27,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) { @@ -71,9 +71,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()) { @@ -92,15 +91,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 || adjCell == cell) { continue; } @@ -120,7 +124,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) { @@ -137,16 +147,15 @@ 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); } public static boolean isForcedBomb(MinesweeperBoard board, MinesweeperCell cell) { - LessBombsThanFlagContradictionRule tooManyBombs = - new LessBombsThanFlagContradictionRule(); + LessBombsThanFlagContradictionRule tooManyBombs = new LessBombsThanFlagContradictionRule(); MinesweeperBoard emptyCaseBoard = board.copy(); MinesweeperCell emptyCell = (MinesweeperCell) emptyCaseBoard.getPuzzleElement(cell); emptyCell.setCellType(MinesweeperTileData.empty()); @@ -158,5 +167,4 @@ public static boolean isForcedBomb(MinesweeperBoard board, MinesweeperCell cell) } return false; } - } diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperView.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperView.java index 571fd093d..e8ab8dfcb 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperView.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperView.java @@ -1,63 +1,65 @@ -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; - - public static final Image EMPTY_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; - } - - 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()); - - 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; + + public static final Image EMPTY_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; + } + + 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()); + + 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/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/FinishWithBombsDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/FinishWithBombsDirectRule.java index 9f5c4279c..e85008d23 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/FinishWithBombsDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/FinishWithBombsDirectRule.java @@ -49,7 +49,8 @@ public Board getDefaultBoard(TreeNode node) { for (PuzzleElement element : minesweeperBoard.getPuzzleElements()) { MinesweeperCell cell = (MinesweeperCell) element; if (cell.getTileType() == MinesweeperTileType.UNSET - && MinesweeperUtilities.isForcedBomb((MinesweeperBoard) node.getBoard(), cell)) { + && MinesweeperUtilities.isForcedBomb( + (MinesweeperBoard) node.getBoard(), cell)) { cell.setCellType(MinesweeperTileData.bomb()); minesweeperBoard.addModifiedData(cell); } 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 5d809d527..c9919343f 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 @@ -4,17 +4,17 @@ import edu.rpi.legup.model.gameboard.PuzzleElement; import edu.rpi.legup.model.rules.ContradictionRule; import edu.rpi.legup.puzzle.minesweeper.*; -import edu.rpi.legup.utility.DisjointSets; - import java.util.ArrayList; -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"); } @@ -30,7 +30,8 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { } int numEmpty = 0; int numAdj = 0; - ArrayList adjCells = MinesweeperUtilities.getAdjacentCells(minesweeperBoard, cell); + ArrayList adjCells = + MinesweeperUtilities.getAdjacentCells(minesweeperBoard, cell); for (MinesweeperCell adjCell : adjCells) { numAdj++; if (adjCell.getTileType() == MinesweeperTileType.EMPTY && adjCell != cell) { @@ -40,13 +41,10 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { System.out.println(numEmpty); System.out.println(numAdj); System.out.println(cellNum); - if (numEmpty > (numAdj-cellNum)) { + if (numEmpty > (numAdj - cellNum)) { return null; } return super.getNoContradictionMessage(); } - - } - 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 index aeddd103b..ecfdbad66 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/MoreBombsThanFlagContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/MoreBombsThanFlagContradictionRule.java @@ -6,7 +6,6 @@ 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; @@ -39,7 +38,8 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { return super.getNoContradictionMessage(); } int numBlack = 0; - ArrayList adjCells = MinesweeperUtilities.getAdjacentCells(minesweeperBoard, cell); + ArrayList adjCells = + MinesweeperUtilities.getAdjacentCells(minesweeperBoard, cell); for (MinesweeperCell adjCell : adjCells) { if (adjCell.getTileType() == MinesweeperTileType.BOMB) { numBlack++; 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 e3cd382ed..a59369b7a 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/Satisfy_Flag.png"); @@ -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/main/java/edu/rpi/legup/puzzle/starbattle/StarBattle.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattle.java index 760fa88b2..39092bbc6 100644 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattle.java +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattle.java @@ -1,4 +1,5 @@ package edu.rpi.legup.puzzle.starbattle; + import edu.rpi.legup.model.Puzzle; import edu.rpi.legup.model.gameboard.Board; @@ -30,6 +31,5 @@ public boolean isBoardComplete(Board board) { } @Override - public void onBoardChange(Board board) { - } + public void onBoardChange(Board board) {} } diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleBoard.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleBoard.java index 2c4a20ebc..5132f33e4 100644 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleBoard.java +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleBoard.java @@ -1,16 +1,16 @@ package edu.rpi.legup.puzzle.starbattle; -import java.util.*; - import edu.rpi.legup.model.gameboard.GridBoard; import edu.rpi.legup.model.gameboard.PuzzleElement; +import java.util.*; public class StarBattleBoard extends GridBoard { private int size; private int puzzleNum; protected List regions; - //private ArrayList groupSizes; + + // private ArrayList groupSizes; public StarBattleBoard(int size, int num) { super(size, size); @@ -24,10 +24,10 @@ public StarBattleBoard(int size, int num) { @Override public StarBattleCell getCell(int x, int y) { - return (StarBattleCell) super.getCell(x,y); + return (StarBattleCell) super.getCell(x, y); } - /* + /* public StarBattleCell getCell(int groupIndex, int x, int y) { return getCell(x + (groupIndex % groupSize) * groupSize, y + (groupIndex / groupSize) * groupSize); }*/ @@ -44,7 +44,9 @@ public Set getRow(int rowNum) { return row; } - public int getPuzzleNumber() { return puzzleNum; } + public int getPuzzleNumber() { + return puzzleNum; + } public Set getCol(int colNum) { Set column = new HashSet<>(); @@ -72,7 +74,7 @@ public void setRegion(int regionNum, StarBattleRegion region) { public int columnStars(int columnIndex) { int stars = 0; if (columnIndex < size) { - for (StarBattleCell c: this.getCol(columnIndex)) { + for (StarBattleCell c : this.getCol(columnIndex)) { if (c.getType() == StarBattleCellType.STAR) { ++stars; } @@ -84,7 +86,7 @@ public int columnStars(int columnIndex) { public int rowStars(int rowIndex) { int stars = 0; if (rowIndex < size) { - for (StarBattleCell c: this.getRow(rowIndex)) { + for (StarBattleCell c : this.getRow(rowIndex)) { if (c.getType() == StarBattleCellType.STAR) { ++stars; } @@ -109,5 +111,3 @@ public StarBattleBoard copy() { return copy; } } - - diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleCell.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleCell.java index a316872d9..ddae8f882 100644 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleCell.java +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleCell.java @@ -2,7 +2,6 @@ import edu.rpi.legup.model.elements.Element; import edu.rpi.legup.model.gameboard.GridCell; - import java.awt.*; import java.awt.event.MouseEvent; @@ -13,10 +12,10 @@ public class StarBattleCell extends GridCell { /** * StarBattleCell Constructor - creates a new StarBattle cell to hold the puzzleElement * - * @param value value of the star battle cell denoting its state - * @param location location of the cell on the board + * @param value value of the star battle cell denoting its state + * @param location location of the cell on the board * @param groupIndex indicates what group # the cell is in. - * @param size size of the star battle cell + * @param size size of the star battle cell */ public StarBattleCell(int value, Point location, int groupIndex, int size) { super(value, location); @@ -24,7 +23,9 @@ public StarBattleCell(int value, Point location, int groupIndex, int size) { this.max = size; } - public int getGroupIndex() { return groupIndex; } + public int getGroupIndex() { + return groupIndex; + } @Override public void setType(Element e, MouseEvent m) { @@ -38,27 +39,25 @@ public void setType(Element e, MouseEvent m) { case "STBL-PLAC-0003": this.data = -1; break; - - case "STBL-UNPL-0001"://Not sure how button events work - switch (m.getButton()){ + + case "STBL-UNPL-0001": // Not sure how button events work + switch (m.getButton()) { case MouseEvent.BUTTON1: if (this.data > 0 || this.data < -3) { this.data = -3; - } - else { + } else { this.data = this.data + 1; } break; case MouseEvent.BUTTON3: if (this.data > -4) { this.data = this.data - 1; - } - else { - this.data = -1;//Unsure + } else { + this.data = -1; // Unsure } break; } - break; + break; } } @@ -85,4 +84,4 @@ public StarBattleCell copy() { copy.setGiven(isGiven); return copy; } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleCellFactory.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleCellFactory.java index 9f7fd0fee..eb2a830f6 100644 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleCellFactory.java +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleCellFactory.java @@ -1,20 +1,21 @@ package edu.rpi.legup.puzzle.starbattle; + 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.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; -import java.awt.*; - public class StarBattleCellFactory extends ElementFactory { @Override public StarBattleCell importCell(Node node, Board board) throws InvalidFileFormatException { try { if (!node.getNodeName().equalsIgnoreCase("cell")) { - throw new InvalidFileFormatException("starbattle Factory: unknown puzzleElement puzzleElement"); + throw new InvalidFileFormatException( + "starbattle Factory: unknown puzzleElement puzzleElement"); } StarBattleBoard starbattleBoard = (StarBattleBoard) board; @@ -24,28 +25,27 @@ public StarBattleCell importCell(Node node, Board board) throws InvalidFileForma int value = Integer.valueOf(attributeList.getNamedItem("value").getNodeValue()); int x = Integer.valueOf(attributeList.getNamedItem("x").getNodeValue()); int y = Integer.valueOf(attributeList.getNamedItem("y").getNodeValue()); - int groupIndex = Integer.valueOf(attributeList.getNamedItem("groupIndex").getNodeValue()); + int groupIndex = + Integer.valueOf(attributeList.getNamedItem("groupIndex").getNodeValue()); if (x >= size || y >= size) { - throw new InvalidFileFormatException("starbattle Factory: cell location out of bounds"); + throw new InvalidFileFormatException( + "starbattle Factory: cell location out of bounds"); } if (groupIndex >= size || groupIndex < 0) { throw new InvalidFileFormatException("starbattle Factory: not in a valid region"); } - if (value != 0) { //ALL INITIAL PUZZLES ARE BLANK, SUBJECT TO CHANGE + if (value != 0) { // ALL INITIAL PUZZLES ARE BLANK, SUBJECT TO CHANGE throw new InvalidFileFormatException("starbattle Factory: cell unknown value"); } StarBattleCell cell = new StarBattleCell(value, new Point(x, y), groupIndex, size); cell.setIndex(y * size + x); return cell; - } - - catch (NumberFormatException e1) { + } catch (NumberFormatException e1) { e1.printStackTrace(); - throw new InvalidFileFormatException("starbattle Factory: unknown value where integer expected"); - } - - catch (NullPointerException e2) { + throw new InvalidFileFormatException( + "starbattle Factory: unknown value where integer expected"); + } catch (NullPointerException e2) { e2.printStackTrace(); throw new InvalidFileFormatException("starbattle Factory: could not find attribute(s)"); } diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleCellType.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleCellType.java index 565f608d7..e48e46fcb 100644 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleCellType.java +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleCellType.java @@ -1,12 +1,14 @@ -//StarBattleCellType.java +// StarBattleCellType.java package edu.rpi.legup.puzzle.starbattle; public enum StarBattleCellType { - STAR(-2), BLACK(-1), UNKNOWN(0); + STAR(-2), + BLACK(-1), + UNKNOWN(0); - public int value; + public int value; StarBattleCellType(int value) { this.value = value; } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleController.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleController.java index 4ebeb39ba..ba19361c9 100644 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleController.java +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleController.java @@ -2,7 +2,6 @@ import edu.rpi.legup.controller.ElementController; import edu.rpi.legup.model.gameboard.PuzzleElement; - import java.awt.event.MouseEvent; public class StarBattleController extends ElementController { @@ -11,23 +10,24 @@ public void changeCell(MouseEvent e, PuzzleElement data) { StarBattleCell cell = (StarBattleCell) data; if (e.getButton() == MouseEvent.BUTTON1) { if (e.isControlDown()) { - this.boardView.getSelectionPopupMenu().show(boardView, this.boardView.getCanvas().getX() + e.getX(), this.boardView.getCanvas().getY() + e.getY()); - } - else { + this.boardView + .getSelectionPopupMenu() + .show( + boardView, + this.boardView.getCanvas().getX() + e.getX(), + this.boardView.getCanvas().getY() + e.getY()); + } else { if (cell.getData() >= 0) { data.setData(-2); - } - else { + } else { data.setData(cell.getData() + 1); } } - } - else { + } else { if (e.getButton() == MouseEvent.BUTTON3) { if (cell.getData() == -2) { data.setData(0); - } - else { + } else { data.setData(cell.getData() - 1); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleElementView.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleElementView.java index ff5d54d1c..66d59d364 100644 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleElementView.java +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleElementView.java @@ -1,7 +1,6 @@ package edu.rpi.legup.puzzle.starbattle; import edu.rpi.legup.ui.boardview.GridElementView; - import java.awt.*; public class StarBattleElementView extends GridElementView { @@ -22,7 +21,14 @@ public void drawElement(Graphics2D graphics2D) { if (type == StarBattleCellType.STAR) { graphics2D.setColor(Color.LIGHT_GRAY); graphics2D.fillRect(location.x, location.y, size.width, size.height); - graphics2D.drawImage(StarBattleView.STAR, location.x, location.y, size.width, size.height, Color.WHITE, null); + graphics2D.drawImage( + StarBattleView.STAR, + location.x, + location.y, + size.width, + size.height, + Color.WHITE, + null); graphics2D.setColor(Color.BLACK); graphics2D.drawRect(location.x, location.y, size.width, size.height); } else if (type == StarBattleCellType.BLACK) { @@ -36,6 +42,5 @@ public void drawElement(Graphics2D graphics2D) { graphics2D.setColor(Color.BLACK); graphics2D.drawRect(location.x, location.y, size.width, size.height); } - } } diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleExporter.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleExporter.java index 58fb41e63..f2d2c4d80 100644 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleExporter.java +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleExporter.java @@ -1,7 +1,6 @@ package edu.rpi.legup.puzzle.starbattle; import edu.rpi.legup.model.PuzzleExporter; - import org.w3c.dom.Document; public class StarBattleExporter extends PuzzleExporter { @@ -20,14 +19,15 @@ protected org.w3c.dom.Element createBoardElement(Document newDocument) { org.w3c.dom.Element cellsElement = newDocument.createElement("cells"); for (StarBattleCell cell : sb_region.getCells()) { if (cell.getData() == 0) { - org.w3c.dom.Element cellElement = puzzle.getFactory().exportCell(newDocument, cell); + org.w3c.dom.Element cellElement = + puzzle.getFactory().exportCell(newDocument, cell); cellsElement.appendChild(cellElement); } regionsElement.appendChild(cellsElement); } boardElement.appendChild(regionsElement); } - + return boardElement; } } diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleImporter.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleImporter.java index fa0e065ee..2a608c893 100644 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleImporter.java +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleImporter.java @@ -2,37 +2,32 @@ import edu.rpi.legup.model.PuzzleImporter; import edu.rpi.legup.save.InvalidFileFormatException; +import java.awt.Point; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; -import java.awt.Point; +public class StarBattleImporter extends PuzzleImporter { -public class StarBattleImporter extends PuzzleImporter{ - - public StarBattleImporter(StarBattle starbattle) { super(starbattle); } - /** - * Puzzle setting to support row and column inputs - */ + /** Puzzle setting to support row and column inputs */ @Override public boolean acceptsRowsAndColumnsInput() { return true; } - /** - * Puzzle setting to disable support for text input - */ + /** Puzzle setting to disable support for text input */ @Override public boolean acceptsTextInput() { return false; } - /** + /** * Constructs empty StarBattle gameboard as per the provided dimensions + * * @param rows number of rows and columns for the gameboard */ @Override @@ -44,6 +39,7 @@ public void initializeBoard(int rows, int columns) { /** * Constructs StarBattle gameboard + * * @param node xml document node * @throws InvalidFileFormatException if file is invalid */ @@ -54,10 +50,13 @@ public void initializeBoard(Node node) throws InvalidFileFormatException { NodeList regionNodes = puzzleElement.getElementsByTagName("region"); int size = Integer.parseInt(puzzleElement.getAttribute("size")); if (regionNodes.getLength() != size) { - throw new InvalidFileFormatException("Not the current amount of regions in the puzzle."); + throw new InvalidFileFormatException( + "Not the current amount of regions in the puzzle."); } - StarBattleBoard StarBattleBoard = new StarBattleBoard(size, puzzle_num); // Initialize the board with width and height from XML + StarBattleBoard StarBattleBoard = + new StarBattleBoard( + size, puzzle_num); // Initialize the board with width and height from XML for (int i = 0; i < regionNodes.getLength(); i++) { Element regionElement = (Element) regionNodes.item(i); @@ -87,10 +86,9 @@ public void initializeBoard(Node node) throws InvalidFileFormatException { puzzle.setCurrentBoard(StarBattleBoard); } - - /** * Initialize board via string of statements. + * * @throws UnsupportedOperationException since StarBattle does not support text input */ @Override @@ -98,6 +96,3 @@ public void initializeBoard(String[] statements) throws UnsupportedOperationExce throw new UnsupportedOperationException("Star Battle does not accept text input"); } } - - - diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleRegion.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleRegion.java index 730f9291f..b35d80655 100644 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleRegion.java +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleRegion.java @@ -2,14 +2,14 @@ import edu.rpi.legup.model.gameboard.GridRegion; -public class StarBattleRegion extends GridRegion{ +public class StarBattleRegion extends GridRegion { public StarBattleRegion() { super(); } public StarBattleRegion copy() { StarBattleRegion copy = new StarBattleRegion(); - for (StarBattleCell c: regionCells) { + for (StarBattleCell c : regionCells) { copy.addCell(c.copy()); } return copy; @@ -17,7 +17,7 @@ public StarBattleRegion copy() { public int numStars() { int stars = 0; - for (StarBattleCell c: regionCells) { + for (StarBattleCell c : regionCells) { if (c.getType() == StarBattleCellType.STAR) { ++stars; } diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleView.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleView.java index ceb0eec19..550b5495d 100644 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleView.java +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleView.java @@ -1,26 +1,22 @@ package edu.rpi.legup.puzzle.starbattle; -import java.io.IOException; - -import javax.imageio.ImageIO; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import edu.rpi.legup.puzzle.starbattle.StarBattleView; -import edu.rpi.legup.ui.boardview.GridBoardView; - 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 javax.imageio.ImageIO; public class StarBattleView extends GridBoardView { static Image STAR; static { try { - STAR = ImageIO.read(ClassLoader.getSystemClassLoader().getResource("edu/rpi/legup/images/starbattle/star.gif")); - } - catch (IOException e) { + STAR = + ImageIO.read( + ClassLoader.getSystemClassLoader() + .getResource("edu/rpi/legup/images/starbattle/star.gif")); + } catch (IOException e) { // pass } } @@ -34,10 +30,9 @@ public StarBattleView(StarBattleBoard board) { StarBattleElementView elementView = new StarBattleElementView(cell); elementView.setIndex(cell.getIndex()); elementView.setSize(elementSize); - elementView.setLocation(new Point(loc.x * elementSize.width, loc.y * elementSize.height)); + 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/starbattle/elements/BlackTile.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/elements/BlackTile.java index 2601bd351..99f42886e 100644 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/elements/BlackTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/elements/BlackTile.java @@ -4,6 +4,10 @@ public class BlackTile extends NonPlaceableElement { public BlackTile() { - super("STBL-PLAC-0002", "Black Tile", "The black tile that shows where you cannot place a star", "edu/rpi/legup/images/lightup/black.gif"); + super( + "STBL-PLAC-0002", + "Black Tile", + "The black tile that shows where you cannot place a star", + "edu/rpi/legup/images/lightup/black.gif"); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/elements/StarTile.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/elements/StarTile.java index d42cc0010..13ada3f4d 100644 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/elements/StarTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/elements/StarTile.java @@ -4,6 +4,10 @@ public class StarTile extends NonPlaceableElement { public StarTile() { - super("STBL-PLAC-0001", "Star Tile", "The star tile, the token of the game.", "edu/rpi/legup/images/starbattle/star.gif"); + super( + "STBL-PLAC-0001", + "Star Tile", + "The star tile, the token of the game.", + "edu/rpi/legup/images/starbattle/star.gif"); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/elements/UnknownTile.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/elements/UnknownTile.java index c2459f642..425fb5d5e 100644 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/elements/UnknownTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/elements/UnknownTile.java @@ -4,6 +4,10 @@ public class UnknownTile extends NonPlaceableElement { public UnknownTile() { - super("STBL-UNPL-0001", "Unknown Tile", "An empty tile", "edu/rpi/legup/images/starbattle/star.gif"); + super( + "STBL-UNPL-0001", + "Unknown Tile", + "An empty tile", + "edu/rpi/legup/images/starbattle/star.gif"); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/elements/WhiteTile.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/elements/WhiteTile.java index a064c1fad..2227eb37a 100644 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/elements/WhiteTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/elements/WhiteTile.java @@ -4,7 +4,10 @@ public class WhiteTile extends PlaceableElement { public WhiteTile() { - super("STBL-PLAC-0001", "White Tile", "The white tile", "edu/rpi/legup/images/starbattle/white.gif"); + super( + "STBL-PLAC-0001", + "White Tile", + "The white tile", + "edu/rpi/legup/images/starbattle/white.gif"); } } - diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/BlackoutDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/BlackoutDirectRule.java index 75fbaadb6..2ab66cf93 100644 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/BlackoutDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/BlackoutDirectRule.java @@ -13,20 +13,21 @@ public class BlackoutDirectRule extends DirectRule { public BlackoutDirectRule() { - super("STBL-BASC-0001", + super( + "STBL-BASC-0001", "Blackout", "If a row, column, or region has enough stars, its unknown spaces are black.", "edu/rpi/legup/images/starbattle/rules/BlackOutDirectRule.png"); } /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule * - * @param transition transition to check + * @param transition transition to check * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message */ @Override public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { @@ -50,7 +51,8 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem } /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. * * @param node tree node used to create default transition board * @return default board or null if this rule cannot be applied to this tree node @@ -60,5 +62,3 @@ public Board getDefaultBoard(TreeNode node) { return null; } } - - diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/ClashingOrbitContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/ClashingOrbitContradictionRule.java index 0ca27ab4a..88f0072e5 100644 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/ClashingOrbitContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/ClashingOrbitContradictionRule.java @@ -3,30 +3,29 @@ 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.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; import edu.rpi.legup.puzzle.starbattle.StarBattleBoard; import edu.rpi.legup.puzzle.starbattle.StarBattleCell; import edu.rpi.legup.puzzle.starbattle.StarBattleCellType; - import java.awt.*; public class ClashingOrbitContradictionRule extends ContradictionRule { public ClashingOrbitContradictionRule() { - super("STBL-CONT-0003", + super( + "STBL-CONT-0003", "Clashing Orbit", "No two stars can be adjacent to each other.", "edu/rpi/legup/images/starbattle/contradictions/ClashingOrbitContradictionRule.png"); } /** - * Checks whether the transition has a contradiction at the specific puzzleElement index using this rule + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule * - * @param board board to check contradiction + * @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 + * otherwise error message */ @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { @@ -41,15 +40,15 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { // check neighboring cells for a star Point location = cell.getLocation(); - int rowStart = Math.max( location.x - 1, 0 ); - int rowEnd = Math.min( location.x + 1, starbattleBoard.getSize() - 1 ); - int colStart = Math.max( location.y - 1, 0 ); - int colEnd = Math.min( location.y + 1, starbattleBoard.getSize() - 1 ); + int rowStart = Math.max(location.x - 1, 0); + int rowEnd = Math.min(location.x + 1, starbattleBoard.getSize() - 1); + int colStart = Math.max(location.y - 1, 0); + int colEnd = Math.min(location.y + 1, starbattleBoard.getSize() - 1); for (int row = rowStart; row <= rowEnd; row++) { for (int col = colStart; col <= colEnd; col++) { if (starbattleBoard.getCell(row, col).getType() == StarBattleCellType.STAR - && (row != location.x || col != location.y)) { + && (row != location.x || col != location.y)) { return null; } } @@ -57,4 +56,4 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { return super.getNoContradictionMessage(); } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/ColumnsWithinRegionsDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/ColumnsWithinRegionsDirectRule.java index b42bfd1c0..433567460 100644 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/ColumnsWithinRegionsDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/ColumnsWithinRegionsDirectRule.java @@ -1,7 +1,6 @@ package edu.rpi.legup.puzzle.starbattle.rules; import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.GridRegion; import edu.rpi.legup.model.gameboard.PuzzleElement; import edu.rpi.legup.model.rules.DirectRule; import edu.rpi.legup.model.tree.TreeNode; @@ -9,41 +8,41 @@ import edu.rpi.legup.puzzle.starbattle.StarBattleBoard; import edu.rpi.legup.puzzle.starbattle.StarBattleCell; import edu.rpi.legup.puzzle.starbattle.StarBattleCellType; - import java.util.HashSet; import java.util.Set; public class ColumnsWithinRegionsDirectRule extends DirectRule { public ColumnsWithinRegionsDirectRule() { - super("STBL-BASC-0002", + super( + "STBL-BASC-0002", "Columns Within Regions", "If a number of columns is fully contained by a number of regions with an equal number of missing stars, spaces of other columns in those regions must be black.", "edu/rpi/legup/images/starbattle/rules/ColumnsWithinRegionsDirectRule.png"); } /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule * - * @param transition transition to check + * @param transition transition to check * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message */ @Override public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - //assumption: the rule has been applied to its fullest extent and the rows and regions - //are now mutually encompassing + // assumption: the rule has been applied to its fullest extent and the rows and regions + // are now mutually encompassing StarBattleBoard board = (StarBattleBoard) transition.getBoard(); StarBattleCell cell = (StarBattleCell) board.getPuzzleElement(puzzleElement); if (cell.getType() != StarBattleCellType.BLACK) { return "Only black cells are allowed for this rule!"; } - //the columns that are contained + // the columns that are contained Set columns = new HashSet(); - //the regions that contain them + // the regions that contain them Set regions = new HashSet(); - //columns and regions to process + // columns and regions to process Set columnsToCheck = new HashSet(); Set regionsToCheck = new HashSet(); int columnStars = 0; @@ -52,9 +51,9 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem regionsToCheck.add(cell.getGroupIndex()); while (!columnsToCheck.isEmpty() || !regionsToCheck.isEmpty()) { - for (int r: regionsToCheck) { + for (int r : regionsToCheck) { regionStars += board.getRegion(r).numStars(); - for (PuzzleElement c: board.getRegion(r).getCells()) { + for (PuzzleElement c : board.getRegion(r).getCells()) { int column = ((StarBattleCell) c).getLocation().x; if (columns.add(column)) { columnsToCheck.add(column); @@ -62,10 +61,10 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem } regionsToCheck.remove(r); } - for (int c: columnsToCheck) { + for (int c : columnsToCheck) { columnStars += board.columnStars(c); for (int i = 0; i < board.getSize(); ++i) { - int region = board.getCell(c,i).getGroupIndex(); + int region = board.getCell(c, i).getGroupIndex(); if (regions.add(region)) { regionsToCheck.add(region); } @@ -74,14 +73,16 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem } } // are the columns and regions missing an equal amount of stars - if (board.getPuzzleNumber() * columns.size() - columnStars != board.getPuzzleNumber() * regions.size() - regionStars) { + if (board.getPuzzleNumber() * columns.size() - columnStars + != board.getPuzzleNumber() * regions.size() - regionStars) { return "The number of missing stars in the columns and regions must be equal and every extraneous cell must be black!"; } return null; } /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. * * @param node tree node used to create default transition board * @return default board or null if this rule cannot be applied to this tree node diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/ColumnsWithinRowsDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/ColumnsWithinRowsDirectRule.java index 0a78c8868..5d108a0cd 100644 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/ColumnsWithinRowsDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/ColumnsWithinRowsDirectRule.java @@ -8,44 +8,44 @@ import edu.rpi.legup.puzzle.starbattle.StarBattleBoard; import edu.rpi.legup.puzzle.starbattle.StarBattleCell; import edu.rpi.legup.puzzle.starbattle.StarBattleCellType; - import java.util.HashSet; import java.util.Set; public class ColumnsWithinRowsDirectRule extends DirectRule { public ColumnsWithinRowsDirectRule() { - super("STBL-BASC-0003", + super( + "STBL-BASC-0003", "Columns Within Rows", "If a number of columns is fully contained by a number of rows with an equal number of missing stars, spaces of other columns in those rows must be black.", "edu/rpi/legup/images/starbattle/rules/ColumnsWithinRowsDirectRule.png"); } /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule * - * @param transition transition to check + * @param transition transition to check * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message */ @Override public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - //assumption: the rule has been applied to its fullest extent and the rows and columns - //are now mutually encompassing + // assumption: the rule has been applied to its fullest extent and the rows and columns + // are now mutually encompassing StarBattleBoard board = (StarBattleBoard) transition.getBoard(); StarBattleCell cell = (StarBattleCell) board.getPuzzleElement(puzzleElement); if (cell.getType() != StarBattleCellType.BLACK) { return "Only black cells are allowed for this rule!"; } - //the columns that are contained + // the columns that are contained Set columns = new HashSet(); - //the rows that contain them + // the rows that contain them Set rows = new HashSet(); - //columns and rows to process + // columns and rows to process Set columnsToCheck = new HashSet(); Set rowsToCheck = new HashSet(); int columnStars = 0; @@ -55,9 +55,9 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem rowsToCheck.add(firstRow); while (!columnsToCheck.isEmpty() || !rowsToCheck.isEmpty()) { - for (int r: rowsToCheck) { + for (int r : rowsToCheck) { rowStars += board.rowStars(r); - for (PuzzleElement c: board.getRow(r)) { + for (PuzzleElement c : board.getRow(r)) { int column = ((StarBattleCell) c).getLocation().x; if (columns.add(column)) { columnsToCheck.add(column); @@ -65,9 +65,9 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem } rowsToCheck.remove(r); } - for (int c: columnsToCheck) { + for (int c : columnsToCheck) { columnStars += board.columnStars(c); - for (PuzzleElement r: board.getCol(c)) { + for (PuzzleElement r : board.getCol(c)) { int row = ((StarBattleCell) r).getLocation().y; if (rows.add(row)) { rowsToCheck.add(row); @@ -77,14 +77,16 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem } } // are the columns and regions missing an equal amount of stars - if (board.getPuzzleNumber() * columns.size() - columnStars != board.getPuzzleNumber() * rows.size() - rowStars) { + if (board.getPuzzleNumber() * columns.size() - columnStars + != board.getPuzzleNumber() * rows.size() - rowStars) { return "The number of missing stars in the columns and rows must be equal and every extraneous cell must be black!"; } return null; } /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. * * @param node tree node used to create default transition board * @return default board or null if this rule cannot be applied to this tree node diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/FinishWithStarsDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/FinishWithStarsDirectRule.java index 36e691e74..80ae9a4c8 100644 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/FinishWithStarsDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/FinishWithStarsDirectRule.java @@ -13,20 +13,21 @@ public class FinishWithStarsDirectRule extends DirectRule { public FinishWithStarsDirectRule() { - super("STBL-BASC-0004", + super( + "STBL-BASC-0004", "Finish With Stars", "Unknown spaces must be stars if there are just enough in a row, column, or region to satisfy the puzzle number.", "edu/rpi/legup/images/starbattle/rules/FinishWithStarDirectRule.png"); } /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule * - * @param transition transition to check + * @param transition transition to check * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message */ @Override public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { @@ -50,7 +51,8 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem } /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. * * @param node tree node used to create default transition board * @return default board or null if this rule cannot be applied to this tree node diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/RegionsWithinColumnsDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/RegionsWithinColumnsDirectRule.java index 16951fb2a..7022a06ac 100644 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/RegionsWithinColumnsDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/RegionsWithinColumnsDirectRule.java @@ -8,20 +8,21 @@ public class RegionsWithinColumnsDirectRule extends DirectRule { public RegionsWithinColumnsDirectRule() { - super("STBL-BASC-0005", + super( + "STBL-BASC-0005", "Regions Within Columns", "If a number of regions is fully contained by a number of columns with an equal number of missing stars, spaces of other regions in those columns must be black.", "edu/rpi/legup/images/starbattle/rules/RegionsWithinColumnsDirectRule.png"); } /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule * - * @param transition transition to check + * @param transition transition to check * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message */ @Override public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { @@ -30,7 +31,8 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem } /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. * * @param node tree node used to create default transition board * @return default board or null if this rule cannot be applied to this tree node diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/RegionsWithinRowsDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/RegionsWithinRowsDirectRule.java index 27dc001a0..7ab50d42b 100644 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/RegionsWithinRowsDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/RegionsWithinRowsDirectRule.java @@ -8,20 +8,21 @@ public class RegionsWithinRowsDirectRule extends DirectRule { public RegionsWithinRowsDirectRule() { - super("STBL-BASC-0006", + super( + "STBL-BASC-0006", "Regions Within Rows", "If a number of regions is fully contained by a number of rows with an equal number of missing stars, spaces of other regions in those rows must be black.", "edu/rpi/legup/images/starbattle/rules/RegionsWithinRowsDirectRule.png"); } /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule * - * @param transition transition to check + * @param transition transition to check * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message */ @Override public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { @@ -31,7 +32,8 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem } /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. * * @param node tree node used to create default transition board * @return default board or null if this rule cannot be applied to this tree node diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/RowsWithinColumnsDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/RowsWithinColumnsDirectRule.java index 4054ec017..2df20e464 100644 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/RowsWithinColumnsDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/RowsWithinColumnsDirectRule.java @@ -5,30 +5,25 @@ import edu.rpi.legup.model.rules.DirectRule; import edu.rpi.legup.model.tree.TreeNode; import edu.rpi.legup.model.tree.TreeTransition; -import edu.rpi.legup.puzzle.starbattle.StarBattleBoard; -import edu.rpi.legup.puzzle.starbattle.StarBattleCell; -import edu.rpi.legup.puzzle.starbattle.StarBattleCellType; - -import java.util.HashSet; -import java.util.Set; public class RowsWithinColumnsDirectRule extends DirectRule { public RowsWithinColumnsDirectRule() { - super("STBL-BASC-0007", + super( + "STBL-BASC-0007", "Rows Withing Columns", "If a number of rows is fully contained by a number of columns with an equal number of missing stars, spaces of other rows in those columns must be black.", "edu/rpi/legup/images/starbattle/rules/RowsWithinColumnsDirectRule.png"); } /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule * - * @param transition transition to check + * @param transition transition to check * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message */ @Override public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { @@ -38,7 +33,8 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem } /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. * * @param node tree node used to create default transition board * @return default board or null if this rule cannot be applied to this tree node diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/RowsWithinRegionsDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/RowsWithinRegionsDirectRule.java index 7af2c79ed..78f8f00e7 100644 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/RowsWithinRegionsDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/RowsWithinRegionsDirectRule.java @@ -8,42 +8,42 @@ import edu.rpi.legup.puzzle.starbattle.StarBattleBoard; import edu.rpi.legup.puzzle.starbattle.StarBattleCell; import edu.rpi.legup.puzzle.starbattle.StarBattleCellType; - import java.util.HashSet; import java.util.Set; public class RowsWithinRegionsDirectRule extends DirectRule { public RowsWithinRegionsDirectRule() { - super("STBL-BASC-0008", + super( + "STBL-BASC-0008", "Rows Within Regions", "If a number of rows is fully contained by a number of regions with an equal number of missing stars, spaces of other rows in those regions must be black.", "edu/rpi/legup/images/starbattle/rules/RowsWithinRegionsDirectRule.png"); } /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule * - * @param transition transition to check + * @param transition transition to check * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message */ @Override public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - //assumption: the rule has been applied to its fullest extent and the rows and regions - //are now mutually encompassing + // assumption: the rule has been applied to its fullest extent and the rows and regions + // are now mutually encompassing StarBattleBoard board = (StarBattleBoard) transition.getBoard(); StarBattleCell cell = (StarBattleCell) board.getPuzzleElement(puzzleElement); if (cell.getType() != StarBattleCellType.BLACK) { return "Only black cells are allowed for this rule!"; } - //the rows that are contained + // the rows that are contained Set rows = new HashSet(); - //the regions that contain them + // the regions that contain them Set regions = new HashSet(); - //rows and regions to process + // rows and regions to process Set rowsToCheck = new HashSet(); Set regionsToCheck = new HashSet(); int rowStars = 0; @@ -52,9 +52,9 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem regionsToCheck.add(cell.getGroupIndex()); while (!rowsToCheck.isEmpty() || !regionsToCheck.isEmpty()) { - for (int r: regionsToCheck) { + for (int r : regionsToCheck) { regionStars += board.getRegion(r).numStars(); - for (PuzzleElement ro: board.getRegion(r).getCells()) { + for (PuzzleElement ro : board.getRegion(r).getCells()) { int row = ((StarBattleCell) ro).getLocation().y; if (rows.add(row)) { rowsToCheck.add(row); @@ -62,10 +62,10 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem } regionsToCheck.remove(r); } - for (int r: rowsToCheck) { + for (int r : rowsToCheck) { rowStars += board.rowStars(r); for (int i = 0; i < board.getSize(); ++i) { - int region = board.getCell(i,r).getGroupIndex(); + int region = board.getCell(i, r).getGroupIndex(); if (regions.add(region)) { regionsToCheck.add(region); } @@ -74,14 +74,16 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem } } // are the columns and regions missing an equal amount of stars - if (board.getPuzzleNumber() * rows.size() - rowStars != board.getPuzzleNumber() * regions.size() - regionStars) { + if (board.getPuzzleNumber() * rows.size() - rowStars + != board.getPuzzleNumber() * regions.size() - regionStars) { return "The number of missing stars in the rows and regions must be equal and every extraneous cell must be black!"; } return null; } /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. * * @param node tree node used to create default transition board * @return default board or null if this rule cannot be applied to this tree node diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/StarOrEmptyCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/StarOrEmptyCaseRule.java index 0aa147c6f..df900dcd5 100644 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/StarOrEmptyCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/StarOrEmptyCaseRule.java @@ -1,31 +1,29 @@ package edu.rpi.legup.puzzle.starbattle.rules; -import edu.rpi.legup.model.rules.CaseRule; 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.nurikabe.NurikabeCell; -import edu.rpi.legup.puzzle.nurikabe.NurikabeType; import edu.rpi.legup.puzzle.starbattle.StarBattleBoard; import edu.rpi.legup.puzzle.starbattle.StarBattleCell; import edu.rpi.legup.puzzle.starbattle.StarBattleCellType; - import java.util.ArrayList; import java.util.List; public class StarOrEmptyCaseRule extends CaseRule { public StarOrEmptyCaseRule() { - super("STBL-CASE-0002", + super( + "STBL-CASE-0002", "Star or Empty", "Each unknown space is either a star or empty.", "edu/rpi/legup/images/starbattle/cases/StarOrEmptyCaseRule.png"); } /** - * Checks whether the {@link TreeTransition} logically follows from the parent node using this rule. This method is - * the one that should overridden in child classes. + * Checks whether the {@link TreeTransition} logically follows from the parent node using this + * rule. This method is the one that should overridden in child classes. * * @param transition transition to check * @return null if the child node logically follow from the parent node, otherwise error message @@ -39,20 +37,25 @@ public String checkRuleRaw(TreeTransition transition) { 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."; + 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."; } StarBattleCell mod1 = (StarBattleCell) case1.getBoard().getModifiedData().iterator().next(); StarBattleCell mod2 = (StarBattleCell) 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."; + return super.getInvalidUseOfRuleMessage() + + ": This case rule must modify the same cell for each case."; } - if (!((mod1.getType() == StarBattleCellType.STAR && mod2.getType() == StarBattleCellType.BLACK) || - (mod2.getType() == StarBattleCellType.STAR && mod1.getType() == StarBattleCellType.BLACK))) { - return super.getInvalidUseOfRuleMessage() + ": This case rule must create a star cell and a black cell."; + if (!((mod1.getType() == StarBattleCellType.STAR + && mod2.getType() == StarBattleCellType.BLACK) + || (mod2.getType() == StarBattleCellType.STAR + && mod1.getType() == StarBattleCellType.BLACK))) { + return super.getInvalidUseOfRuleMessage() + + ": This case rule must create a star cell and a black cell."; } return null; @@ -74,7 +77,7 @@ public CaseBoard getCaseBoard(Board board) { /** * Gets the possible cases at a specific location based on this case rule * - * @param board the current board state + * @param board the current board state * @param puzzleElement equivalent puzzleElement * @return a list of elements the specified could be */ diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/SurroundStarDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/SurroundStarDirectRule.java index e1c6f3084..89857875d 100644 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/SurroundStarDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/SurroundStarDirectRule.java @@ -13,20 +13,21 @@ public class SurroundStarDirectRule extends DirectRule { public SurroundStarDirectRule() { - super("STBL-BASC-0009", + super( + "STBL-BASC-0009", "Surround Star", "Any space adjacent to a star must be black.", "edu/rpi/legup/images/starbattle/rules/SurroundStar.png"); } /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule * - * @param transition transition to check + * @param transition transition to check * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message */ @Override public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { @@ -49,7 +50,8 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem } /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. * * @param node tree node used to create default transition board * @return default board or null if this rule cannot be applied to this tree node @@ -60,4 +62,3 @@ public Board getDefaultBoard(TreeNode node) { return null; } } - diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/TooFewStarsContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/TooFewStarsContradictionRule.java index d1ed62107..e88b7c6b9 100644 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/TooFewStarsContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/TooFewStarsContradictionRule.java @@ -3,31 +3,30 @@ 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.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; import edu.rpi.legup.puzzle.starbattle.StarBattleBoard; import edu.rpi.legup.puzzle.starbattle.StarBattleCell; import edu.rpi.legup.puzzle.starbattle.StarBattleCellType; import edu.rpi.legup.puzzle.starbattle.StarBattleRegion; - import java.awt.*; public class TooFewStarsContradictionRule extends ContradictionRule { public TooFewStarsContradictionRule() { - super("STBL-CONT-0002", + super( + "STBL-CONT-0002", "Too Few Stars", "There are too few stars in this region/row/column and there are not enough places to put the remaining stars.", "edu/rpi/legup/images/starbattle/contradictions/TooFewStarsContradictionRule.png"); } /** - * Checks whether the transition has a contradiction at the specific puzzleElement index using this rule + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule * - * @param board board to check contradiction + * @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 + * otherwise error message */ @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { @@ -51,7 +50,7 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { } StarBattleRegion region = sbBoard.getRegion(cell); int regionCount = 0; - for (StarBattleCell c: region.getCells()) { + for (StarBattleCell c : region.getCells()) { if (c.getType() != StarBattleCellType.BLACK) { ++regionCount; } @@ -61,4 +60,4 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { } return super.getNoContradictionMessage(); } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/TooManyStarsContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/TooManyStarsContradictionRule.java index 2ae424d45..12603a6ba 100644 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/TooManyStarsContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/TooManyStarsContradictionRule.java @@ -3,34 +3,33 @@ 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.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -import edu.rpi.legup.puzzle.lightup.LightUpCell; import edu.rpi.legup.puzzle.starbattle.StarBattleBoard; import edu.rpi.legup.puzzle.starbattle.StarBattleCell; import edu.rpi.legup.puzzle.starbattle.StarBattleCellType; import edu.rpi.legup.puzzle.starbattle.StarBattleRegion; - import java.awt.*; import java.util.List; public class TooManyStarsContradictionRule extends ContradictionRule { - private final String INVALID_USE_MESSAGE = "Contradiction must be applied to a cell containing a star."; + private final String INVALID_USE_MESSAGE = + "Contradiction must be applied to a cell containing a star."; public TooManyStarsContradictionRule() { - super("STBL-CONT-0001", + super( + "STBL-CONT-0001", "Too Many Stars", "There are too many stars in this region/row/column.", "edu/rpi/legup/images/starbattle/contradictions/TooManyStarsContradictionRule.png"); } /** - * Checks whether the transition has a contradiction at the specific puzzleElement index using this rule + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule * - * @param board board to check contradiction + * @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 + * otherwise error message */ @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { @@ -111,4 +110,4 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { } return null; } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/utility/LegupUtils.java b/src/main/java/edu/rpi/legup/utility/LegupUtils.java index 770ccc6a2..ce21a8d9a 100644 --- a/src/main/java/edu/rpi/legup/utility/LegupUtils.java +++ b/src/main/java/edu/rpi/legup/utility/LegupUtils.java @@ -98,8 +98,7 @@ private static List findClassesZip(String path, String packageName) try { Class c = Class.forName(substr); classes.add(c); - } - catch (LinkageError | ClassNotFoundException e) { + } catch (LinkageError | ClassNotFoundException e) { System.out.println("Failed on " + substr); } } 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); } - - } diff --git a/src/test/java/puzzles/starbattle/rules/BlackoutDirectRuleTest.java b/src/test/java/puzzles/starbattle/rules/BlackoutDirectRuleTest.java index d42f40c87..441d5ebd4 100644 --- a/src/test/java/puzzles/starbattle/rules/BlackoutDirectRuleTest.java +++ b/src/test/java/puzzles/starbattle/rules/BlackoutDirectRuleTest.java @@ -1,25 +1,19 @@ package puzzles.starbattle.rules; -import edu.rpi.legup.puzzle.nurikabe.Nurikabe; -import edu.rpi.legup.puzzle.nurikabe.NurikabeBoard; -import edu.rpi.legup.puzzle.nurikabe.NurikabeCell; -import edu.rpi.legup.puzzle.nurikabe.NurikabeType; -import legup.MockGameBoardFacade; -import legup.TestUtilities; import edu.rpi.legup.model.tree.TreeNode; import edu.rpi.legup.model.tree.TreeTransition; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; - import edu.rpi.legup.puzzle.starbattle.StarBattle; import edu.rpi.legup.puzzle.starbattle.StarBattleBoard; import edu.rpi.legup.puzzle.starbattle.StarBattleCell; import edu.rpi.legup.puzzle.starbattle.StarBattleCellType; import edu.rpi.legup.puzzle.starbattle.rules.BlackoutDirectRule; import edu.rpi.legup.save.InvalidFileFormatException; - import java.awt.*; +import legup.MockGameBoardFacade; +import legup.TestUtilities; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; public class BlackoutDirectRuleTest { @@ -34,7 +28,8 @@ public static void setUp() { @Test public void BlackoutDirectRuleTest_ColumnBlackout() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/BlackoutDirectRule/ColumnBlackout", starbattle); + TestUtilities.importTestBoard( + "puzzles/starbattle/rules/BlackoutDirectRule/ColumnBlackout", starbattle); TreeNode rootNode = starbattle.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -57,10 +52,11 @@ public void BlackoutDirectRuleTest_ColumnBlackout() throws InvalidFileFormatExce for (int i = 0; i < board.getHeight(); i++) { for (int k = 0; k < board.getWidth(); k++) { Point point = new Point(k, i); - if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) || point.equals(cell3.getLocation())) { + if (point.equals(cell1.getLocation()) + || point.equals(cell2.getLocation()) + || point.equals(cell3.getLocation())) { Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - else { + } else { Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); } } From 9e623a005927781c8450438f5d49ef3963ec9c50 Mon Sep 17 00:00:00 2001 From: Bram van Heuveln Date: Sun, 5 May 2024 18:09:31 +0000 Subject: [PATCH 41/41] Automated Java code formatting changes --- .../edu/rpi/legup/model/PuzzleImporter.java | 27 ++-- .../legup/puzzle/treetent/TreeTentBoard.java | 2 - .../puzzle/treetent/TreeTentImporter.java | 1 - .../treetent/rules/FillinRowCaseRule.java | 37 +++-- .../edu/rpi/legup/ui/ProofEditorPanel.java | 2 +- .../rules/BlackoutDirectRuleTest.java | 49 +++--- .../rules/EmptyFieldDirectRuleTest.java | 83 +++++----- .../treetent/rules/FillinRowCaseRuleTest.java | 49 +++--- .../rules/FinishWithGrassDirectRuleTest.java | 149 ++++++++--------- .../rules/FinishWithTentsDirectRuleTest.java | 152 ++++++++---------- .../rules/LastCampingSpotDirectRuleTest.java | 80 +++++---- .../treetent/rules/LinkTentCaseRuleTest.java | 33 ++-- .../treetent/rules/LinkTreeCaseRuleTest.java | 46 +++--- .../SurroundTentWithGrassDirectRuleTest.java | 62 ++++--- .../rules/TentForTreeDirectRuleTest.java | 151 ++++++++--------- .../rules/TreeForTentDirectRuleTest.java | 63 ++++---- 16 files changed, 450 insertions(+), 536 deletions(-) diff --git a/src/main/java/edu/rpi/legup/model/PuzzleImporter.java b/src/main/java/edu/rpi/legup/model/PuzzleImporter.java index c22831c8d..0902478db 100644 --- a/src/main/java/edu/rpi/legup/model/PuzzleImporter.java +++ b/src/main/java/edu/rpi/legup/model/PuzzleImporter.java @@ -6,8 +6,6 @@ import edu.rpi.legup.model.rules.Rule; import edu.rpi.legup.model.tree.*; import edu.rpi.legup.save.InvalidFileFormatException; - -import java.lang.reflect.Array; import java.util.*; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -132,18 +130,19 @@ public void initializePuzzle(Node node) throws InvalidFileFormatException { public abstract void initializeBoard(String[] statements) throws UnsupportedOperationException, IllegalArgumentException; - /** - * Used to check that elements in the proof tree are saved properly. - *

Make sure the list elements are lowercase - * - * @return A list of elements that will change when solving the puzzle - * * e.g. {"cell"}, {"cell", "line"} - */ - public List getImporterElements() { - List elements = new ArrayList<>(); - elements.add("cell"); - return elements; - } + /** + * Used to check that elements in the proof tree are saved properly. + * + *

Make sure the list elements are lowercase + * + * @return A list of elements that will change when solving the puzzle * e.g. {"cell"}, {"cell", + * "line"} + */ + public List getImporterElements() { + List elements = new ArrayList<>(); + elements.add("cell"); + return elements; + } /** * Creates the proof for building diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentBoard.java b/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentBoard.java index 6ded23a18..c8962aa03 100644 --- a/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentBoard.java +++ b/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentBoard.java @@ -3,8 +3,6 @@ import edu.rpi.legup.model.gameboard.Board; import edu.rpi.legup.model.gameboard.GridBoard; import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.tree.Tree; - import java.awt.*; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentImporter.java b/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentImporter.java index c791617ce..56dcca59f 100644 --- a/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentImporter.java +++ b/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentImporter.java @@ -5,7 +5,6 @@ import java.awt.*; import java.util.ArrayList; import java.util.List; - import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/rules/FillinRowCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/treetent/rules/FillinRowCaseRule.java index a796c992a..aaa1a8fbc 100644 --- a/src/main/java/edu/rpi/legup/puzzle/treetent/rules/FillinRowCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/treetent/rules/FillinRowCaseRule.java @@ -1,11 +1,9 @@ package edu.rpi.legup.puzzle.treetent.rules; -import edu.rpi.legup.model.Puzzle; 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.Tree; import edu.rpi.legup.model.tree.TreeTransition; import edu.rpi.legup.puzzle.treetent.TreeTentBoard; import edu.rpi.legup.puzzle.treetent.TreeTentCell; @@ -13,9 +11,7 @@ import edu.rpi.legup.puzzle.treetent.TreeTentType; import java.awt.*; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; -import java.util.ListIterator; public class FillinRowCaseRule extends CaseRule { @@ -95,7 +91,6 @@ public ArrayList getCases(Board board, PuzzleElement puzzleElement) { } /** - * * @param iBoard the board to place tents onto * @param tiles the locations where tents can be placed * @param target the target number of tents to place @@ -111,14 +106,21 @@ private ArrayList genCombinations( boolean isRow) { ArrayList generatedBoards = new ArrayList<>(); genCombRecursive( - iBoard, tiles, target, 0, new ArrayList(), 0, index, generatedBoards, isRow); + iBoard, + tiles, + target, + 0, + new ArrayList(), + 0, + index, + generatedBoards, + isRow); return generatedBoards; } /** - * - * Recursive function to generate all ways of placing the target number of tents - * from the list of tiles to fill. + * Recursive function to generate all ways of placing the target number of tents from the list + * of tiles to fill. * * @param iBoard The board * @param tiles Unknown Tiles to fill @@ -128,10 +130,8 @@ private ArrayList genCombinations( * @param selected the cells which have tents * @param index The index of the clue * @param isRow Used for checking if the board is good - * - * The generated boards are placed into generatedBoards (passed by reference) + *

The generated boards are placed into generatedBoards (passed by reference) */ - private void genCombRecursive( TreeTentBoard iBoard, List tiles, @@ -168,14 +168,23 @@ private void genCombRecursive( // // Backtracking: // Remove the placed tent from the board and selected - for (int i = currentTile; i < tiles.size(); ++i){ + for (int i = currentTile; i < tiles.size(); ++i) { TreeTentCell tile = tiles.get(i); selected.add(tile); PuzzleElement element = iBoard.getPuzzleElement(tile); element.setData(TreeTentType.TENT); iBoard.addModifiedData(element); if (goodBoard(iBoard, index, isRow)) { - genCombRecursive(iBoard, tiles, target, current + 1, selected, i + 1, index, generatedBoards, isRow); + genCombRecursive( + iBoard, + tiles, + target, + current + 1, + selected, + i + 1, + index, + generatedBoards, + isRow); } element.setData(TreeTentType.UNKNOWN); iBoard.addModifiedData(element); diff --git a/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java b/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java index 8401e19f2..645a2c0d7 100644 --- a/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java +++ b/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java @@ -580,7 +580,7 @@ private void saveProofAs() { if (puzzle == null) { return; } - + LegupPreferences preferences = LegupPreferences.getInstance(); File preferredDirectory = new File(preferences.getUserPref(LegupPreferences.WORK_DIRECTORY)); diff --git a/src/test/java/puzzles/starbattle/rules/BlackoutDirectRuleTest.java b/src/test/java/puzzles/starbattle/rules/BlackoutDirectRuleTest.java index 7789b273b..59d5b37af 100644 --- a/src/test/java/puzzles/starbattle/rules/BlackoutDirectRuleTest.java +++ b/src/test/java/puzzles/starbattle/rules/BlackoutDirectRuleTest.java @@ -2,30 +2,30 @@ // Commenting this out for now, but once Star Battle is fully implemented this should // be uncommented and finished. -//package puzzles.starbattle.rules; +// package puzzles.starbattle.rules; // -//import edu.rpi.legup.puzzle.nurikabe.Nurikabe; -//import edu.rpi.legup.puzzle.nurikabe.NurikabeBoard; -//import edu.rpi.legup.puzzle.nurikabe.NurikabeCell; -//import edu.rpi.legup.puzzle.nurikabe.NurikabeType; -//import legup.MockGameBoardFacade; -//import legup.TestUtilities; -//import edu.rpi.legup.model.tree.TreeNode; -//import edu.rpi.legup.model.tree.TreeTransition; -//import org.junit.Assert; -//import org.junit.BeforeClass; -//import org.junit.Test; +// import edu.rpi.legup.puzzle.nurikabe.Nurikabe; +// import edu.rpi.legup.puzzle.nurikabe.NurikabeBoard; +// import edu.rpi.legup.puzzle.nurikabe.NurikabeCell; +// import edu.rpi.legup.puzzle.nurikabe.NurikabeType; +// import legup.MockGameBoardFacade; +// import legup.TestUtilities; +// import edu.rpi.legup.model.tree.TreeNode; +// import edu.rpi.legup.model.tree.TreeTransition; +// import org.junit.Assert; +// import org.junit.BeforeClass; +// import org.junit.Test; // -//import edu.rpi.legup.puzzle.starbattle.StarBattle; -//import edu.rpi.legup.puzzle.starbattle.StarBattleBoard; -//import edu.rpi.legup.puzzle.starbattle.StarBattleCell; -//import edu.rpi.legup.puzzle.starbattle.StarBattleCellType; -//import edu.rpi.legup.puzzle.starbattle.rules.BlackoutDirectRule; -//import edu.rpi.legup.save.InvalidFileFormatException; +// import edu.rpi.legup.puzzle.starbattle.StarBattle; +// import edu.rpi.legup.puzzle.starbattle.StarBattleBoard; +// import edu.rpi.legup.puzzle.starbattle.StarBattleCell; +// import edu.rpi.legup.puzzle.starbattle.StarBattleCellType; +// import edu.rpi.legup.puzzle.starbattle.rules.BlackoutDirectRule; +// import edu.rpi.legup.save.InvalidFileFormatException; // -//import java.awt.*; +// import java.awt.*; // -//public class BlackoutDirectRuleTest { +// public class BlackoutDirectRuleTest { // // private static final BlackoutDirectRule RULE = new BlackoutDirectRule(); // private static StarBattle starbattle; @@ -38,7 +38,9 @@ // // @Test // public void BlackoutDirectRuleTest_ColumnBlackout() throws InvalidFileFormatException { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/BlackoutDirectRule/ColumnBlackout", starbattle); +// +// TestUtilities.importTestBoard("puzzles/starbattle/rules/BlackoutDirectRule/ColumnBlackout", +// starbattle); // TreeNode rootNode = starbattle.getTree().getRootNode(); // TreeTransition transition = rootNode.getChildren().get(0); // transition.setRule(RULE); @@ -61,7 +63,8 @@ // for (int i = 0; i < board.getHeight(); i++) { // for (int k = 0; k < board.getWidth(); k++) { // Point point = new Point(k, i); -// if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) || point.equals(cell3.getLocation())) { +// if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) || +// point.equals(cell3.getLocation())) { // Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); // } // else { @@ -70,4 +73,4 @@ // } // } // } -//} +// } diff --git a/src/test/java/puzzles/treetent/rules/EmptyFieldDirectRuleTest.java b/src/test/java/puzzles/treetent/rules/EmptyFieldDirectRuleTest.java index 8ffb2ee4f..c704d59b7 100644 --- a/src/test/java/puzzles/treetent/rules/EmptyFieldDirectRuleTest.java +++ b/src/test/java/puzzles/treetent/rules/EmptyFieldDirectRuleTest.java @@ -26,17 +26,16 @@ public static void setUp() { treetent = new TreeTent(); } - /** - * 3x3 TreeTent puzzle Tests EmptyFieldDirectRule - *

Empty - * XXX - * XGX - * XXX - *

Makes the (1, 1) tile GRASS - * Checks if the rule correctly detects no trees around the grass tile - */ - @Test - public void EmptyFieldTest() throws InvalidFileFormatException { + /** + * 3x3 TreeTent puzzle Tests EmptyFieldDirectRule + * + *

Empty XXX XGX XXX + * + *

Makes the (1, 1) tile GRASS Checks if the rule correctly detects no trees around the grass + * tile + */ + @Test + public void EmptyFieldTest() throws InvalidFileFormatException { TestUtilities.importTestBoard( "puzzles/treetent/rules/EmptyFieldDirectRule/EmptyField", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); @@ -70,17 +69,16 @@ public void EmptyFieldTest() throws InvalidFileFormatException { } } - /** - * 3x3 TreeTent puzzle Tests EmptyFieldDirectRule - *

Trees are at (0, 0), (2, 0), (0, 2), and (2, 2) - * RXR - * XGX - * RXR - *

Makes the (1, 1) tile GRASS - * Checks if the rule correctly ignores the trees on the diagonals - */ - @Test - public void DiagonalTreeTest() throws InvalidFileFormatException { + /** + * 3x3 TreeTent puzzle Tests EmptyFieldDirectRule + * + *

Trees are at (0, 0), (2, 0), (0, 2), and (2, 2) RXR XGX RXR + * + *

Makes the (1, 1) tile GRASS Checks if the rule correctly ignores the trees on the + * diagonals + */ + @Test + public void DiagonalTreeTest() throws InvalidFileFormatException { TestUtilities.importTestBoard( "puzzles/treetent/rules/EmptyFieldDirectRule/DiagonalTree", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); @@ -114,17 +112,15 @@ public void DiagonalTreeTest() throws InvalidFileFormatException { } } - /** - * 3x3 TreeTent puzzle Tests EmptyFieldDirectRule - *

Trees are at (0, 1), (1, 0), (1, 2), and (2, 1) - * XRX - * RGR - * XRX - *

Makes the (1, 1) tile GRASS - * Checks if the rule is not valid when there are adjacent trees - */ - @Test - public void EmptyFieldTestFail() throws InvalidFileFormatException { + /** + * 3x3 TreeTent puzzle Tests EmptyFieldDirectRule + * + *

Trees are at (0, 1), (1, 0), (1, 2), and (2, 1) XRX RGR XRX + * + *

Makes the (1, 1) tile GRASS Checks if the rule is not valid when there are adjacent trees + */ + @Test + public void EmptyFieldTestFail() throws InvalidFileFormatException { TestUtilities.importTestBoard( "puzzles/treetent/rules/EmptyFieldDirectRule/EmptyFieldFail", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); @@ -153,17 +149,16 @@ public void EmptyFieldTestFail() throws InvalidFileFormatException { } } - /** - * 3x3 TreeTent puzzle Tests EmptyFieldDirectRule - *

Tree at (1, 0) - * XRX - * XGX - * XXX - *

Makes the (1, 1) tile GRASS - * Checks if the rule is not valid when there is one adjacent tree - */ - @Test - public void EmptyFieldTestFailTop() throws InvalidFileFormatException { + /** + * 3x3 TreeTent puzzle Tests EmptyFieldDirectRule + * + *

Tree at (1, 0) XRX XGX XXX + * + *

Makes the (1, 1) tile GRASS Checks if the rule is not valid when there is one adjacent + * tree + */ + @Test + public void EmptyFieldTestFailTop() throws InvalidFileFormatException { TestUtilities.importTestBoard( "puzzles/treetent/rules/EmptyFieldDirectRule/EmptyFieldFailTop", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); diff --git a/src/test/java/puzzles/treetent/rules/FillinRowCaseRuleTest.java b/src/test/java/puzzles/treetent/rules/FillinRowCaseRuleTest.java index 71b478e7a..3b8389407 100644 --- a/src/test/java/puzzles/treetent/rules/FillinRowCaseRuleTest.java +++ b/src/test/java/puzzles/treetent/rules/FillinRowCaseRuleTest.java @@ -6,17 +6,15 @@ import edu.rpi.legup.puzzle.treetent.*; import edu.rpi.legup.puzzle.treetent.rules.FillinRowCaseRule; import edu.rpi.legup.save.InvalidFileFormatException; +import java.util.ArrayList; import legup.MockGameBoardFacade; import legup.TestUtilities; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; -import java.lang.reflect.Array; -import java.util.ArrayList; - public class FillinRowCaseRuleTest { - private static final FillinRowCaseRule RULE = new FillinRowCaseRule(); + private static final FillinRowCaseRule RULE = new FillinRowCaseRule(); private static TreeTent treetent; @BeforeClass @@ -26,11 +24,11 @@ public static void setUp() { } /** - * empty 3x3 TreeTent puzzle Tests FillinRowCaseRule on row with 3 UNKNOWN tiles - * and a clue of 0 tents in the row. + * empty 3x3 TreeTent puzzle Tests FillinRowCaseRule on row with 3 UNKNOWN tiles and a clue of 0 + * tents in the row. * - *

checks that 1 case is created and that it is equivalent to FinishWithGrass rule - * May need to change checks due to issue #777 + *

checks that 1 case is created and that it is equivalent to FinishWithGrass rule May need + * to change checks due to issue #777 * * @throws InvalidFileFormatException */ @@ -98,16 +96,12 @@ public void TentOrTreeTestZeroTentClue() throws InvalidFileFormatException { } /** - * empty 3x3 TreeTent puzzle Tests FillinRowCaseRule on row with 3 UNKNOWN tiles - * and a clue of 1 tent in the row. The column rules make the board impossible, but - * they are not checked here. + * empty 3x3 TreeTent puzzle Tests FillinRowCaseRule on row with 3 UNKNOWN tiles and a clue of 1 + * tent in the row. The column rules make the board impossible, but they are not checked here. * - *

checks 3 cases are created checks; - * first case is TENT tile at x=0, - * second case is TENT tile at x=1, - * and a third case is TENT tile at x=2. - * The cases can be in any order. - * Then, it checks that other cells have not been modified + *

checks 3 cases are created checks; first case is TENT tile at x=0, second case is TENT + * tile at x=1, and a third case is TENT tile at x=2. The cases can be in any order. Then, it + * checks that other cells have not been modified * * @throws InvalidFileFormatException */ @@ -145,7 +139,7 @@ public void FillInRowEmptyOneTentClue() throws InvalidFileFormatException { for (int w = 0; w < board.getWidth(); w++) { for (int h = 0; h < board.getHeight(); h++) { if (h == 1) { - continue; + continue; } original_cell = board.getCell(w, h); @@ -155,7 +149,6 @@ public void FillInRowEmptyOneTentClue() throws InvalidFileFormatException { case_cell = testCase.getCell(w, h); Assert.assertEquals(original_cell.getType(), case_cell.getType()); - } } } @@ -199,13 +192,11 @@ public void FillInRowEmptyOneTentClue() throws InvalidFileFormatException { } /** - * empty 3x3 TreeTent puzzle Tests FillinRowCaseRule on row with 3 UNKNOWN tiles - * and a clue of 2 tent in the row. The column rules make the board impossible, but - * they are not checked here. + * empty 3x3 TreeTent puzzle Tests FillinRowCaseRule on row with 3 UNKNOWN tiles and a clue of 2 + * tent in the row. The column rules make the board impossible, but they are not checked here. * - *

checks 1 case is created. Checks that the case is when - * there are TENT tiles at x=0 and x=2. - * Then, it checks that other cells have not been modified + *

checks 1 case is created. Checks that the case is when there are TENT tiles at x=0 and + * x=2. Then, it checks that other cells have not been modified * * @throws InvalidFileFormatException */ @@ -287,8 +278,8 @@ public void FillInRowEmptyTwoTentClue() throws InvalidFileFormatException { } /** - * empty 3x3 TreeTent puzzle Tests FillinRowCaseRule on row with 3 UNKNOWN tiles - * and a clue of 3 tent in the row. + * empty 3x3 TreeTent puzzle Tests FillinRowCaseRule on row with 3 UNKNOWN tiles and a clue of 3 + * tent in the row. * *

checks that 0 cases are created * @@ -319,8 +310,8 @@ public void FillInRowEmptyThreeTentClue() throws InvalidFileFormatException { } /** - * empty 5x5 TreeTent puzzle Tests FillinRowCaseRule on row with 5 UNKNOWN tiles - * and a clue of 2 tents in the row. + * empty 5x5 TreeTent puzzle Tests FillinRowCaseRule on row with 5 UNKNOWN tiles and a clue of 2 + * tents in the row. * *

checks that 6 cases are created and each case has the right number of tents * diff --git a/src/test/java/puzzles/treetent/rules/FinishWithGrassDirectRuleTest.java b/src/test/java/puzzles/treetent/rules/FinishWithGrassDirectRuleTest.java index f37761e26..c89c96dd1 100644 --- a/src/test/java/puzzles/treetent/rules/FinishWithGrassDirectRuleTest.java +++ b/src/test/java/puzzles/treetent/rules/FinishWithGrassDirectRuleTest.java @@ -28,18 +28,16 @@ public static void setUp() { treetent = new TreeTent(); } - /** - * 3x3 TreeTent puzzle Tests FinishWithGrassDirectRule - *

Tent at (1, 1) - * XXX x - * GTG 1 - * XXX x - * xxx - *

Makes (0, 1) and (2, 1) GRASS - * Checks if the rule detects the middle row to be filled in correctly - */ - @Test - public void FinishWithGrassHorizontalTest() throws InvalidFileFormatException { + /** + * 3x3 TreeTent puzzle Tests FinishWithGrassDirectRule + * + *

Tent at (1, 1) XXX x GTG 1 XXX x xxx + * + *

Makes (0, 1) and (2, 1) GRASS Checks if the rule detects the middle row to be filled in + * correctly + */ + @Test + public void FinishWithGrassHorizontalTest() throws InvalidFileFormatException { TestUtilities.importTestBoard( "puzzles/treetent/rules/FinishWithGrassDirectRule/CornerTent", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); @@ -78,18 +76,16 @@ public void FinishWithGrassHorizontalTest() throws InvalidFileFormatException { } } - /** - * 3x3 TreeTent puzzle Tests FinishWithGrassDirectRule - *

Tent at (0, 0) - * TXX x - * GXX x - * GXX x - * 1xx - *

Makes (0, 1) and (0, 2) GRASS - * Checks if the rule detects the leftmost column to be filled in correctly - */ - @Test - public void FinishWithGrassVerticalTest() throws InvalidFileFormatException { + /** + * 3x3 TreeTent puzzle Tests FinishWithGrassDirectRule + * + *

Tent at (0, 0) TXX x GXX x GXX x 1xx + * + *

Makes (0, 1) and (0, 2) GRASS Checks if the rule detects the leftmost column to be filled + * in correctly + */ + @Test + public void FinishWithGrassVerticalTest() throws InvalidFileFormatException { TestUtilities.importTestBoard( "puzzles/treetent/rules/FinishWithGrassDirectRule/CornerTent", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); @@ -130,13 +126,11 @@ public void FinishWithGrassVerticalTest() throws InvalidFileFormatException { /** * 3x3 TreeTent puzzle Tests FinishWithGrassDirectRule - *

Tent at (0, 0) - * TGG 1 - * GXX x - * GXX x - * 1xx - *

Makes (0, 1), (0, 2), (1, 0), and (2, 0) GRASS - * Checks if the rule detects the top row and leftmost column to be filled in correctly + * + *

Tent at (0, 0) TGG 1 GXX x GXX x 1xx + * + *

Makes (0, 1), (0, 2), (1, 0), and (2, 0) GRASS Checks if the rule detects the top row and + * leftmost column to be filled in correctly */ @Test public void FinishWithGrassTest() throws InvalidFileFormatException { @@ -186,18 +180,16 @@ public void FinishWithGrassTest() throws InvalidFileFormatException { } } - /** - * 3x3 TreeTent puzzle Tests FinishWithGrassDirectRule - *

Empty - * GGG 0 - * GGG 0 - * GGG 0 - * 000 - *

Fill Board with GRASS - * Checks if the rule allows all cells to be filled when the clue for all rows and columns is zero. - */ - @Test - public void NoTentTest() throws InvalidFileFormatException { + /** + * 3x3 TreeTent puzzle Tests FinishWithGrassDirectRule + * + *

Empty GGG 0 GGG 0 GGG 0 000 + * + *

Fill Board with GRASS Checks if the rule allows all cells to be filled when the clue for + * all rows and columns is zero. + */ + @Test + public void NoTentTest() throws InvalidFileFormatException { TestUtilities.importTestBoard( "puzzles/treetent/rules/FinishWithGrassDirectRule/NoTent", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); @@ -231,18 +223,16 @@ public void NoTentTest() throws InvalidFileFormatException { } } - /** - * 3x3 TreeTent puzzle Tests FinishWithGrassDirectRule - *

Tent at (1, 1) - * XGX x - * GTG 1 - * XGX x - * x1x - *

Makes (1, 0), (0, 1), (2, 1), and (1, 2) GRASS - * Checks if the rule correctly allows the central row and column to be filled with grass. - */ - @Test - public void MiddleTentTest() throws InvalidFileFormatException { + /** + * 3x3 TreeTent puzzle Tests FinishWithGrassDirectRule + * + *

Tent at (1, 1) XGX x GTG 1 XGX x x1x + * + *

Makes (1, 0), (0, 1), (2, 1), and (1, 2) GRASS Checks if the rule correctly allows the + * central row and column to be filled with grass. + */ + @Test + public void MiddleTentTest() throws InvalidFileFormatException { TestUtilities.importTestBoard( "puzzles/treetent/rules/FinishWithGrassDirectRule/MiddleTent", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); @@ -290,18 +280,16 @@ public void MiddleTentTest() throws InvalidFileFormatException { } } - /** - * 3x3 TreeTent puzzle Tests FinishWithGrassDirectRule - *

Empty - * GGG 1 - * GGG 1 - * GGG 1 - * 111 - *

Fill Board with GRASS - * Checks if the rule is not valid when a row or column does not have the required number of tents but is filled with grass - */ - @Test - public void FailTentTest() throws InvalidFileFormatException { + /** + * 3x3 TreeTent puzzle Tests FinishWithGrassDirectRule + * + *

Empty GGG 1 GGG 1 GGG 1 111 + * + *

Fill Board with GRASS Checks if the rule is not valid when a row or column does not have + * the required number of tents but is filled with grass + */ + @Test + public void FailTentTest() throws InvalidFileFormatException { TestUtilities.importTestBoard( "puzzles/treetent/rules/FinishWithGrassDirectRule/FailTent", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); @@ -335,22 +323,17 @@ public void FailTentTest() throws InvalidFileFormatException { } } - /** - * 7x7 TreeTent puzzle Tests FinishWithGrassDirectRule - *

Tents at (1, 3), (3, 3), and (5, 3) - * XXXXXXX x - * XXXXXXX x - * XXXXXXX x - * TGTGTGT 4 - * XXXXXXX x - * XXXXXXX x - * XXXXXXX x - * xxxxxxx - *

Makes (0, 3), (2, 3), (4, 3), and (6, 3) GRASS - * Checks if applying the rule on row 3 is valid - */ - @Test - public void SpacedOutTentTest() throws InvalidFileFormatException { + /** + * 7x7 TreeTent puzzle Tests FinishWithGrassDirectRule + * + *

Tents at (1, 3), (3, 3), and (5, 3) XXXXXXX x XXXXXXX x XXXXXXX x TGTGTGT 4 XXXXXXX x + * XXXXXXX x XXXXXXX x xxxxxxx + * + *

Makes (0, 3), (2, 3), (4, 3), and (6, 3) GRASS Checks if applying the rule on row 3 is + * valid + */ + @Test + public void SpacedOutTentTest() throws InvalidFileFormatException { TestUtilities.importTestBoard( "puzzles/treetent/rules/FinishWithGrassDirectRule/SpacedOutTent", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); diff --git a/src/test/java/puzzles/treetent/rules/FinishWithTentsDirectRuleTest.java b/src/test/java/puzzles/treetent/rules/FinishWithTentsDirectRuleTest.java index d82be3f87..b72b0f556 100644 --- a/src/test/java/puzzles/treetent/rules/FinishWithTentsDirectRuleTest.java +++ b/src/test/java/puzzles/treetent/rules/FinishWithTentsDirectRuleTest.java @@ -27,18 +27,15 @@ public static void setUp() { treetent = new TreeTent(); } - /** - * 3x3 TreeTent puzzle Tests FinishWithTentsDirectRule - *

Grass at (0, 0) - * GTT 2 - * XXX x - * XXX x - * xxx - *

Makes (1, 0) and (2, 0) TENT - * Checks that the rule correctly fills in the first row - */ - @Test - public void FinishWithHorizontalTentsTest() throws InvalidFileFormatException { + /** + * 3x3 TreeTent puzzle Tests FinishWithTentsDirectRule + * + *

Grass at (0, 0) GTT 2 XXX x XXX x xxx + * + *

Makes (1, 0) and (2, 0) TENT Checks that the rule correctly fills in the first row + */ + @Test + public void FinishWithHorizontalTentsTest() throws InvalidFileFormatException { TestUtilities.importTestBoard( "puzzles/treetent/rules/FinishWithTentsDirectRule/FinishWithHorizontalTents", treetent); @@ -71,18 +68,15 @@ public void FinishWithHorizontalTentsTest() throws InvalidFileFormatException { } } - /** - * 3x3 TreeTent puzzle Tests FinishWithTentsDirectRule - *

Grass at (0, 0) - * GXX x - * TXX x - * TXX x - * 2xx - *

Makes (0, 1) and (0, 2) TENT - * Checks that the rule correctly fills in the first column - */ - @Test - public void FinishWithVerticalTentsTest() throws InvalidFileFormatException { + /** + * 3x3 TreeTent puzzle Tests FinishWithTentsDirectRule + * + *

Grass at (0, 0) GXX x TXX x TXX x 2xx + * + *

Makes (0, 1) and (0, 2) TENT Checks that the rule correctly fills in the first column + */ + @Test + public void FinishWithVerticalTentsTest() throws InvalidFileFormatException { TestUtilities.importTestBoard( "puzzles/treetent/rules/FinishWithTentsDirectRule/FinishWithVerticalTents", treetent); @@ -115,18 +109,16 @@ public void FinishWithVerticalTentsTest() throws InvalidFileFormatException { } } - /** - * 3x3 TreeTent puzzle Tests FinishWithTentsDirectRule - *

Grass at (0, 0) - * GTT 2 - * TXX x - * TXX x - * 2xx - *

Makes (1, 0), (2, 0), (0, 1) and (0, 2) TENT - * Checks that the rule correctly fills both the first row and first column - */ - @Test - public void FinishWithTentsTest() throws InvalidFileFormatException { + /** + * 3x3 TreeTent puzzle Tests FinishWithTentsDirectRule + * + *

Grass at (0, 0) GTT 2 TXX x TXX x 2xx + * + *

Makes (1, 0), (2, 0), (0, 1) and (0, 2) TENT Checks that the rule correctly fills both the + * first row and first column + */ + @Test + public void FinishWithTentsTest() throws InvalidFileFormatException { TestUtilities.importTestBoard( "puzzles/treetent/rules/FinishWithTentsDirectRule/FinishWithTents", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); @@ -167,18 +159,16 @@ public void FinishWithTentsTest() throws InvalidFileFormatException { } } - /** - * 3x3 TreeTent puzzle Tests FinishWithTentsDirectRule - *

Tent at (1, 1) - * XTX x - * TTT 3 - * XTX x - * x3x - *

Makes (1, 0), (0, 1), (2, 1), and (1, 2) TENT - * Checks that the rule correctly fills in the middle row and column when a tent starts at (1, 1) - */ - @Test - public void AdditionalTentsTest() throws InvalidFileFormatException { + /** + * 3x3 TreeTent puzzle Tests FinishWithTentsDirectRule + * + *

Tent at (1, 1) XTX x TTT 3 XTX x x3x + * + *

Makes (1, 0), (0, 1), (2, 1), and (1, 2) TENT Checks that the rule correctly fills in the + * middle row and column when a tent starts at (1, 1) + */ + @Test + public void AdditionalTentsTest() throws InvalidFileFormatException { TestUtilities.importTestBoard( "puzzles/treetent/rules/FinishWithTentsDirectRule/AdditionalTents", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); @@ -219,18 +209,16 @@ public void AdditionalTentsTest() throws InvalidFileFormatException { } } - /** - * 3x3 TreeTent puzzle Tests FinishWithTentsDirectRule - *

Empty - * TTT 0 - * TTT 0 - * TTT 0 - * 000 - *

Fills the board with tents - * Checks that the rule does not allow for more tents in any of the rows or columns - */ - @Test - public void FinishWithTentsFailTest() throws InvalidFileFormatException { + /** + * 3x3 TreeTent puzzle Tests FinishWithTentsDirectRule + * + *

Empty TTT 0 TTT 0 TTT 0 000 + * + *

Fills the board with tents Checks that the rule does not allow for more tents in any of + * the rows or columns + */ + @Test + public void FinishWithTentsFailTest() throws InvalidFileFormatException { TestUtilities.importTestBoard( "puzzles/treetent/rules/FinishWithTentsDirectRule/FinishWithTentsFail", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); @@ -259,18 +247,16 @@ public void FinishWithTentsFailTest() throws InvalidFileFormatException { } } - /** - * 3x3 TreeTent puzzle Tests FinishWithTentsDirectRule - *

Tent at (1, 1) - * XTX x - * TTT 1 - * XTX x - * x1x - *

Makes (1, 0), (0, 1), (2, 1) and (1, 2) Tent - * Checks that the rule does not allow for more tents in the central row or central column - */ - @Test - public void TooManyTentsTest() throws InvalidFileFormatException { + /** + * 3x3 TreeTent puzzle Tests FinishWithTentsDirectRule + * + *

Tent at (1, 1) XTX x TTT 1 XTX x x1x + * + *

Makes (1, 0), (0, 1), (2, 1) and (1, 2) Tent Checks that the rule does not allow for more + * tents in the central row or central column + */ + @Test + public void TooManyTentsTest() throws InvalidFileFormatException { TestUtilities.importTestBoard( "puzzles/treetent/rules/FinishWithTentsDirectRule/TooManyTents", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); @@ -302,18 +288,16 @@ public void TooManyTentsTest() throws InvalidFileFormatException { } } - /** - * 3x3 TreeTent puzzle Tests FinishWithTentsDirectRule - *

Tent at (1, 1) - * XTX x - * TTT 2 - * XTX x - * x2x - *

Makes (1, 0), (0, 1), (2, 1) and (1, 2) Tent - * Checks that the rule is not satisfied because there are multiple configurations of tents for the central row and central column - */ - @Test - public void AmbiguousTentsTest() throws InvalidFileFormatException { + /** + * 3x3 TreeTent puzzle Tests FinishWithTentsDirectRule + * + *

Tent at (1, 1) XTX x TTT 2 XTX x x2x + * + *

Makes (1, 0), (0, 1), (2, 1) and (1, 2) Tent Checks that the rule is not satisfied because + * there are multiple configurations of tents for the central row and central column + */ + @Test + public void AmbiguousTentsTest() throws InvalidFileFormatException { TestUtilities.importTestBoard( "puzzles/treetent/rules/FinishWithTentsDirectRule/AmbiguousTents", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); diff --git a/src/test/java/puzzles/treetent/rules/LastCampingSpotDirectRuleTest.java b/src/test/java/puzzles/treetent/rules/LastCampingSpotDirectRuleTest.java index ad4559922..fdd55029f 100644 --- a/src/test/java/puzzles/treetent/rules/LastCampingSpotDirectRuleTest.java +++ b/src/test/java/puzzles/treetent/rules/LastCampingSpotDirectRuleTest.java @@ -26,17 +26,15 @@ public static void setUp() { treetent = new TreeTent(); } - /** - * 3x3 TreeTent puzzle Tests LastCampingSpotDirectRule - *

TREE at (1, 1) and (0, 1); GRASS at (1, 2) and (2, 1) - * XTX - * RRG - * XGX - *

Makes (1, 0) TENT - * Checks that a tent must be placed above the central tree - */ - @Test - public void EmptyFieldTest_Up() throws InvalidFileFormatException { + /** + * 3x3 TreeTent puzzle Tests LastCampingSpotDirectRule + * + *

TREE at (1, 1) and (0, 1); GRASS at (1, 2) and (2, 1) XTX RRG XGX + * + *

Makes (1, 0) TENT Checks that a tent must be placed above the central tree + */ + @Test + public void EmptyFieldTest_Up() throws InvalidFileFormatException { TestUtilities.importTestBoard( "puzzles/treetent/rules/LastCampingSpotDirectRule/LastCampingSpotUp", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); @@ -64,17 +62,15 @@ public void EmptyFieldTest_Up() throws InvalidFileFormatException { } } - /** - * 3x3 TreeTent puzzle Tests LastCampingSpotDirectRule - *

TREE at (1, 1) and (0, 1); GRASS at (1, 0) and (1, 2) - * XGX - * RRG - * XTX - *

Makes (1, 2) TENT - * Checks that a tent must be placed below the central tree - */ - @Test - public void EmptyFieldTest_Down() throws InvalidFileFormatException { + /** + * 3x3 TreeTent puzzle Tests LastCampingSpotDirectRule + * + *

TREE at (1, 1) and (0, 1); GRASS at (1, 0) and (1, 2) XGX RRG XTX + * + *

Makes (1, 2) TENT Checks that a tent must be placed below the central tree + */ + @Test + public void EmptyFieldTest_Down() throws InvalidFileFormatException { TestUtilities.importTestBoard( "puzzles/treetent/rules/LastCampingSpotDirectRule/LastCampingSpotDown", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); @@ -102,17 +98,15 @@ public void EmptyFieldTest_Down() throws InvalidFileFormatException { } } - /** - * 3x3 TreeTent puzzle Tests LastCampingSpotDirectRule - *

TREE at (1, 1) and (2, 1); GRASS at (1, 0) and (1, 2) - * XGX - * TRR - * XGX - *

Makes (0, 1) TENT - * Checks that a tent must be placed on the left of the central tree - */ - @Test - public void EmptyFieldTest_Left() throws InvalidFileFormatException { + /** + * 3x3 TreeTent puzzle Tests LastCampingSpotDirectRule + * + *

TREE at (1, 1) and (2, 1); GRASS at (1, 0) and (1, 2) XGX TRR XGX + * + *

Makes (0, 1) TENT Checks that a tent must be placed on the left of the central tree + */ + @Test + public void EmptyFieldTest_Left() throws InvalidFileFormatException { TestUtilities.importTestBoard( "puzzles/treetent/rules/LastCampingSpotDirectRule/LastCampingSpotLeft", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); @@ -140,17 +134,15 @@ public void EmptyFieldTest_Left() throws InvalidFileFormatException { } } - /** - * 3x3 TreeTent puzzle Tests LastCampingSpotDirectRule - *

TREE at (1, 1) and (1, 2); GRASS at (0, 1) and (1, 0) - * XGX - * GRT - * XRX - *

Makes (2, 1) TENT - * Checks that a tent must be placed to the right of the central tree - */ - @Test - public void EmptyFieldTest_Right() throws InvalidFileFormatException { + /** + * 3x3 TreeTent puzzle Tests LastCampingSpotDirectRule + * + *

TREE at (1, 1) and (1, 2); GRASS at (0, 1) and (1, 0) XGX GRT XRX + * + *

Makes (2, 1) TENT Checks that a tent must be placed to the right of the central tree + */ + @Test + public void EmptyFieldTest_Right() throws InvalidFileFormatException { TestUtilities.importTestBoard( "puzzles/treetent/rules/LastCampingSpotDirectRule/LastCampingSpotRight", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); diff --git a/src/test/java/puzzles/treetent/rules/LinkTentCaseRuleTest.java b/src/test/java/puzzles/treetent/rules/LinkTentCaseRuleTest.java index 3ed1fd79e..ed482eba0 100644 --- a/src/test/java/puzzles/treetent/rules/LinkTentCaseRuleTest.java +++ b/src/test/java/puzzles/treetent/rules/LinkTentCaseRuleTest.java @@ -1,22 +1,18 @@ package puzzles.treetent.rules; import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.tree.Tree; import edu.rpi.legup.model.tree.TreeNode; import edu.rpi.legup.model.tree.TreeTransition; import edu.rpi.legup.puzzle.treetent.*; import edu.rpi.legup.puzzle.treetent.rules.LinkTentCaseRule; import edu.rpi.legup.save.InvalidFileFormatException; +import java.util.ArrayList; import legup.MockGameBoardFacade; import legup.TestUtilities; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; -import java.lang.reflect.Array; -import java.util.ArrayList; -import java.util.LinkedList; - public class LinkTentCaseRuleTest { private static final LinkTentCaseRule RULE = new LinkTentCaseRule(); private static TreeTent treetent; @@ -28,8 +24,8 @@ public static void setUp() { } /** - * empty 3x3 TreeTent puzzle Tests LinkTentCaseRule on a central tent - * with one tree surrounding it. + * empty 3x3 TreeTent puzzle Tests LinkTentCaseRule on a central tent with one tree surrounding + * it. * *

checks that 1 cases is with the line connecting the central tent and the tree * @@ -76,11 +72,11 @@ public void LinkTentOneTreeTest() throws InvalidFileFormatException { } /** - * empty 3x3 TreeTent puzzle Tests LinkTentCaseRule on a central tent - * with four trees surrounding it. + * empty 3x3 TreeTent puzzle Tests LinkTentCaseRule on a central tent with four trees + * surrounding it. * - *

checks that 4 cases are created, each of which create a line - * connecting the tent to one of the four trees without repeat. + *

checks that 4 cases are created, each of which create a line connecting the tent to one of + * the four trees without repeat. * * @throws InvalidFileFormatException */ @@ -106,7 +102,7 @@ public void LinkTentFourTreesTest() throws InvalidFileFormatException { expectedLines.addFirst(new TreeTentLine(board.getCell(1, 1), board.getCell(1, 2))); for (Board testCaseBoard : cases) { - TreeTentBoard testCase = (TreeTentBoard) testCaseBoard ; + TreeTentBoard testCase = (TreeTentBoard) testCaseBoard; ArrayList lines = testCase.getLines(); // Each case should connect one line from the tent to @@ -142,17 +138,15 @@ public void LinkTentFourTreesTest() throws InvalidFileFormatException { } /** - * empty 3x3 TreeTent puzzle Tests LinkTentCaseRule on a central tent - * with zero trees around it. + * empty 3x3 TreeTent puzzle Tests LinkTentCaseRule on a central tent with zero trees around it. * - *

Ensures no cases are created + *

Ensures no cases are created * * @throws InvalidFileFormatException */ @Test public void LinkTentNoTreesTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard( - "puzzles/treetent/rules/LinkTentCaseRule/NoTrees", treetent); + TestUtilities.importTestBoard("puzzles/treetent/rules/LinkTentCaseRule/NoTrees", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -166,10 +160,9 @@ public void LinkTentNoTreesTest() throws InvalidFileFormatException { } /** - * empty 3x3 TreeTent puzzle Tests LinkTentCaseRule on a central tent - * with trees on a diagonal. + * empty 3x3 TreeTent puzzle Tests LinkTentCaseRule on a central tent with trees on a diagonal. * - *

Ensures no cases are created + *

Ensures no cases are created * * @throws InvalidFileFormatException */ diff --git a/src/test/java/puzzles/treetent/rules/LinkTreeCaseRuleTest.java b/src/test/java/puzzles/treetent/rules/LinkTreeCaseRuleTest.java index fffde14b1..be237e8d4 100644 --- a/src/test/java/puzzles/treetent/rules/LinkTreeCaseRuleTest.java +++ b/src/test/java/puzzles/treetent/rules/LinkTreeCaseRuleTest.java @@ -1,6 +1,5 @@ package puzzles.treetent.rules; -import com.sun.source.doctree.LinkTree; import edu.rpi.legup.model.gameboard.Board; import edu.rpi.legup.model.tree.TreeNode; import edu.rpi.legup.model.tree.TreeTransition; @@ -10,16 +9,15 @@ import edu.rpi.legup.puzzle.treetent.TreeTentLine; import edu.rpi.legup.puzzle.treetent.rules.LinkTreeCaseRule; import edu.rpi.legup.save.InvalidFileFormatException; +import java.util.ArrayList; import legup.MockGameBoardFacade; import legup.TestUtilities; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; -import java.util.ArrayList; - public class LinkTreeCaseRuleTest { - private static final LinkTreeCaseRule RULE = new LinkTreeCaseRule(); + private static final LinkTreeCaseRule RULE = new LinkTreeCaseRule(); private static TreeTent treetent; @BeforeClass @@ -29,17 +27,15 @@ public static void setUp() { } /** - * empty 3x3 TreeTent puzzle Tests LinkTentCaseRule on a central tree - * with one tent above + * empty 3x3 TreeTent puzzle Tests LinkTentCaseRule on a central tree with one tent above * - *

Ensures one case is created that connects the tree to the tent. + *

Ensures one case is created that connects the tree to the tent. * * @throws InvalidFileFormatException */ @Test public void LinkTentOneTentTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard( - "puzzles/treetent/rules/LinkTreeCaseRule/OneTent", treetent); + TestUtilities.importTestBoard("puzzles/treetent/rules/LinkTreeCaseRule/OneTent", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -77,20 +73,18 @@ public void LinkTentOneTentTest() throws InvalidFileFormatException { } /** - * empty 3x3 TreeTent puzzle Tests LinkTentCaseRule on a central tree - * with two tents, one on the left and one on the right. + * empty 3x3 TreeTent puzzle Tests LinkTentCaseRule on a central tree with two tents, one on the + * left and one on the right. * - *

Ensures two cases are created, one connecting the tree and the - * left tent, and one connecting the tree and the right tent. - * Because tents must be surrounded by grass, there can be at most - * two tents around a given tree. + *

Ensures two cases are created, one connecting the tree and the left tent, and one + * connecting the tree and the right tent. Because tents must be surrounded by grass, there can + * be at most two tents around a given tree. * * @throws InvalidFileFormatException */ @Test public void LinkTentTwoTentsTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard( - "puzzles/treetent/rules/LinkTreeCaseRule/TwoTents", treetent); + TestUtilities.importTestBoard("puzzles/treetent/rules/LinkTreeCaseRule/TwoTents", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -107,7 +101,7 @@ public void LinkTentTwoTentsTest() throws InvalidFileFormatException { expectedLines.addFirst(new TreeTentLine(board.getCell(1, 1), board.getCell(2, 1))); for (Board testCaseBoard : cases) { - TreeTentBoard testCase = (TreeTentBoard) testCaseBoard ; + TreeTentBoard testCase = (TreeTentBoard) testCaseBoard; ArrayList lines = testCase.getLines(); // Each case should connect one line from the tent to @@ -143,17 +137,15 @@ public void LinkTentTwoTentsTest() throws InvalidFileFormatException { } /** - * empty 3x3 TreeTent puzzle Tests LinkTentCaseRule on a central tree - * with zero tents around it. + * empty 3x3 TreeTent puzzle Tests LinkTentCaseRule on a central tree with zero tents around it. * - *

Ensures no cases are created + *

Ensures no cases are created * * @throws InvalidFileFormatException */ @Test public void LinkTentNoTreesTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard( - "puzzles/treetent/rules/LinkTreeCaseRule/NoTents", treetent); + TestUtilities.importTestBoard("puzzles/treetent/rules/LinkTreeCaseRule/NoTents", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -167,17 +159,15 @@ public void LinkTentNoTreesTest() throws InvalidFileFormatException { } /** - * empty 3x3 TreeTent puzzle Tests LinkTentCaseRule on a central tree - * with tents on a diagonal. + * empty 3x3 TreeTent puzzle Tests LinkTentCaseRule on a central tree with tents on a diagonal. * - *

Ensures no cases are created + *

Ensures no cases are created * * @throws InvalidFileFormatException */ @Test public void LinkTentDiagTentsTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard( - "puzzles/treetent/rules/LinkTreeCaseRule/NoTents", treetent); + TestUtilities.importTestBoard("puzzles/treetent/rules/LinkTreeCaseRule/NoTents", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); diff --git a/src/test/java/puzzles/treetent/rules/SurroundTentWithGrassDirectRuleTest.java b/src/test/java/puzzles/treetent/rules/SurroundTentWithGrassDirectRuleTest.java index 6177bb64c..dc61cb863 100644 --- a/src/test/java/puzzles/treetent/rules/SurroundTentWithGrassDirectRuleTest.java +++ b/src/test/java/puzzles/treetent/rules/SurroundTentWithGrassDirectRuleTest.java @@ -27,17 +27,16 @@ public static void setUp() { treetent = new TreeTent(); } - /** - * 3x3 TreeTent puzzle Tests SurroundTentWithGrassDirectRule - *

TREE at (0, 0), (2, 0), (0, 1), (2, 1), (1, 2), and (2, 2); TENT at (1, 1) - * RGR - * RTR - * GRR - *

Makes (1, 0) and (0, 2) GRASS - * Checks that the rule detects unknown adjacent and diagonal tiles correctly - */ - @Test - public void SurroundTentWithGrassBasicRuleTest() throws InvalidFileFormatException { + /** + * 3x3 TreeTent puzzle Tests SurroundTentWithGrassDirectRule + * + *

TREE at (0, 0), (2, 0), (0, 1), (2, 1), (1, 2), and (2, 2); TENT at (1, 1) RGR RTR GRR + * + *

Makes (1, 0) and (0, 2) GRASS Checks that the rule detects unknown adjacent and diagonal + * tiles correctly + */ + @Test + public void SurroundTentWithGrassBasicRuleTest() throws InvalidFileFormatException { TestUtilities.importTestBoard( "puzzles/treetent/rules/SurroundTentWithGrassDirectRule/SurroundTentWithGrass", treetent); @@ -69,17 +68,16 @@ public void SurroundTentWithGrassBasicRuleTest() throws InvalidFileFormatExcepti } } - /** - * 3x3 TreeTent puzzle Tests SurroundTentWithGrassDirectRule - *

TENT at (1, 1) - * GGG - * GTG - * GGG - *

Makes all cells adjacent and diagonal to the tent GRASS - * Checks that the rule detects all adjacent and diagonal tiles correctly - */ - @Test - public void SurroundTentWithGrassBasicRuleTest_BadBoard() throws InvalidFileFormatException { + /** + * 3x3 TreeTent puzzle Tests SurroundTentWithGrassDirectRule + * + *

TENT at (1, 1) GGG GTG GGG + * + *

Makes all cells adjacent and diagonal to the tent GRASS Checks that the rule detects all + * adjacent and diagonal tiles correctly + */ + @Test + public void SurroundTentWithGrassBasicRuleTest_BadBoard() throws InvalidFileFormatException { TestUtilities.importTestBoard( "puzzles/treetent/rules/SurroundTentWithGrassDirectRule/SurroundTentWithGrassBad", treetent); @@ -137,17 +135,15 @@ public void SurroundTentWithGrassBasicRuleTest_BadBoard() throws InvalidFileForm } } - /** - * 3x3 TreeTent puzzle Tests SurroundTentWithGrassDirectRule - *

TENT at (1, 1); TREE on all adjacent and diagonal tiles - * RRR - * RTR - * RRR - *

Null - * Checks that the rule correctly detects no missing tiles - */ - @Test - public void SurroundTentWithGrassBasicRuleTest_FullBoard() throws InvalidFileFormatException { + /** + * 3x3 TreeTent puzzle Tests SurroundTentWithGrassDirectRule + * + *

TENT at (1, 1); TREE on all adjacent and diagonal tiles RRR RTR RRR + * + *

Null Checks that the rule correctly detects no missing tiles + */ + @Test + public void SurroundTentWithGrassBasicRuleTest_FullBoard() throws InvalidFileFormatException { TestUtilities.importTestBoard( "puzzles/treetent/rules/SurroundTentWithGrassDirectRule/SurroundTentWithGrassTrees", treetent); diff --git a/src/test/java/puzzles/treetent/rules/TentForTreeDirectRuleTest.java b/src/test/java/puzzles/treetent/rules/TentForTreeDirectRuleTest.java index e55704ec2..6bd2db071 100644 --- a/src/test/java/puzzles/treetent/rules/TentForTreeDirectRuleTest.java +++ b/src/test/java/puzzles/treetent/rules/TentForTreeDirectRuleTest.java @@ -5,14 +5,13 @@ import edu.rpi.legup.puzzle.treetent.*; import edu.rpi.legup.puzzle.treetent.rules.TentForTreeDirectRule; import edu.rpi.legup.save.InvalidFileFormatException; +import java.util.ArrayList; import legup.MockGameBoardFacade; import legup.TestUtilities; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; -import java.util.ArrayList; - public class TentForTreeDirectRuleTest { private static final TentForTreeDirectRule RULE = new TentForTreeDirectRule(); @@ -24,62 +23,58 @@ public static void setUp() { treetent = new TreeTent(); } - /** - * 3x3 TreeTent puzzle Tests TentForTreeDirectRule - *

TREE at (1, 0); TENT at (1, 1) - * XRX - * XTX - * XXX - *

Makes a line between (1, 0) and (1, 1) - * Checks that the rule correctly detects the central tent as the only possible connection - */ - @Test - public void TentForTreeTestOneTreeOneTentTest() throws InvalidFileFormatException { - - TestUtilities.importTestBoard( - "puzzles/treetent/rules/TentForTreeDirectRule/OneTreeOneTent", - treetent); - - TreeNode rootNode = treetent.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - TreeTentBoard board = (TreeTentBoard) transition.getBoard(); - - TreeTentCell cell1 = board.getCell(1, 0); - TreeTentCell cell2 = board.getCell(1, 1); - TreeTentLine line = new TreeTentLine(cell1, cell2); - - board.addModifiedData(line); - board.getLines().add(line); - - Assert.assertNull(RULE.checkRule(transition)); - - ArrayList lines = board.getLines(); - for (TreeTentLine l : lines) { - if (l.compare((line))) { - Assert.assertNull(RULE.checkRuleAt(transition, l)); - } else { - Assert.assertNotNull(RULE.checkRuleAt(transition, l)); + /** + * 3x3 TreeTent puzzle Tests TentForTreeDirectRule + * + *

TREE at (1, 0); TENT at (1, 1) XRX XTX XXX + * + *

Makes a line between (1, 0) and (1, 1) Checks that the rule correctly detects the central + * tent as the only possible connection + */ + @Test + public void TentForTreeTestOneTreeOneTentTest() throws InvalidFileFormatException { + + TestUtilities.importTestBoard( + "puzzles/treetent/rules/TentForTreeDirectRule/OneTreeOneTent", treetent); + + TreeNode rootNode = treetent.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + TreeTentBoard board = (TreeTentBoard) transition.getBoard(); + + TreeTentCell cell1 = board.getCell(1, 0); + TreeTentCell cell2 = board.getCell(1, 1); + TreeTentLine line = new TreeTentLine(cell1, cell2); + + board.addModifiedData(line); + board.getLines().add(line); + + Assert.assertNull(RULE.checkRule(transition)); + + ArrayList lines = board.getLines(); + for (TreeTentLine l : lines) { + if (l.compare((line))) { + Assert.assertNull(RULE.checkRuleAt(transition, l)); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, l)); + } } } - } - - /** - * 3x3 TreeTent puzzle Tests TentForTreeDirectRule - *

TREE at (1, 0) and (1, 2); TENT at (1, 1) - * XRX - * XTX - * XRX - *

Makes a line between (1, 0) and (1, 1) - * Checks that the rule works when connecting a line between the tree at (1, 0) and tent at (1, 1) - */ - @Test - public void TentForTreeArbitraryTreeTest() throws InvalidFileFormatException { + + /** + * 3x3 TreeTent puzzle Tests TentForTreeDirectRule + * + *

TREE at (1, 0) and (1, 2); TENT at (1, 1) XRX XTX XRX + * + *

Makes a line between (1, 0) and (1, 1) Checks that the rule works when connecting a line + * between the tree at (1, 0) and tent at (1, 1) + */ + @Test + public void TentForTreeArbitraryTreeTest() throws InvalidFileFormatException { TestUtilities.importTestBoard( - "puzzles/treetent/rules/TentForTreeDirectRule/ArbitraryTree", - treetent); + "puzzles/treetent/rules/TentForTreeDirectRule/ArbitraryTree", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); @@ -97,21 +92,19 @@ public void TentForTreeArbitraryTreeTest() throws InvalidFileFormatException { Assert.assertNull(RULE.checkRule(transition)); } - /** - * 3x3 TreeTent puzzle Tests TentForTreeDirectRule - *

TREE at (1, 0) and (1, 2); TENT at (1, 1); LINE between (1, 0) and (1, 1) - * XRX - * XTX - * XRX - *

Makes a line between (1, 1) and (1, 2) - * Checks that the rule fails for the tree at (1, 2) because there are no valid tents to connect to - */ - @Test - public void TentForTreeConnectedTent() throws InvalidFileFormatException { + /** + * 3x3 TreeTent puzzle Tests TentForTreeDirectRule + * + *

TREE at (1, 0) and (1, 2); TENT at (1, 1); LINE between (1, 0) and (1, 1) XRX XTX XRX + * + *

Makes a line between (1, 1) and (1, 2) Checks that the rule fails for the tree at (1, 2) + * because there are no valid tents to connect to + */ + @Test + public void TentForTreeConnectedTent() throws InvalidFileFormatException { TestUtilities.importTestBoard( - "puzzles/treetent/rules/TentForTreeDirectRule/ArbitraryTree", - treetent); + "puzzles/treetent/rules/TentForTreeDirectRule/ArbitraryTree", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); @@ -134,20 +127,18 @@ public void TentForTreeConnectedTent() throws InvalidFileFormatException { } } - /** - * 3x3 TreeTent puzzle Tests TentForTreeDirectRule - *

TREE at (1, 1); TENT at (1, 0) and (1, 2) - * XTX - * XRX - * XTX - *

Makes a line between (1, 1) and (1, 2) - * Checks that the rule fails for the tree at (1, 1) because there are two valid tents to connect to - */ - @Test - public void TentForTreeOneTreeTwoAdjacentTent() throws InvalidFileFormatException { + /** + * 3x3 TreeTent puzzle Tests TentForTreeDirectRule + * + *

TREE at (1, 1); TENT at (1, 0) and (1, 2) XTX XRX XTX + * + *

Makes a line between (1, 1) and (1, 2) Checks that the rule fails for the tree at (1, 1) + * because there are two valid tents to connect to + */ + @Test + public void TentForTreeOneTreeTwoAdjacentTent() throws InvalidFileFormatException { TestUtilities.importTestBoard( - "puzzles/treetent/rules/TentForTreeDirectRule/OneTreeTwoAdjacentTent", - treetent); + "puzzles/treetent/rules/TentForTreeDirectRule/OneTreeTwoAdjacentTent", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); diff --git a/src/test/java/puzzles/treetent/rules/TreeForTentDirectRuleTest.java b/src/test/java/puzzles/treetent/rules/TreeForTentDirectRuleTest.java index ba1b49b8c..3cccdc417 100644 --- a/src/test/java/puzzles/treetent/rules/TreeForTentDirectRuleTest.java +++ b/src/test/java/puzzles/treetent/rules/TreeForTentDirectRuleTest.java @@ -8,14 +8,13 @@ import edu.rpi.legup.puzzle.treetent.TreeTentLine; import edu.rpi.legup.puzzle.treetent.rules.TreeForTentDirectRule; import edu.rpi.legup.save.InvalidFileFormatException; +import java.util.ArrayList; import legup.MockGameBoardFacade; import legup.TestUtilities; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; -import java.util.ArrayList; - public class TreeForTentDirectRuleTest { private static final TreeForTentDirectRule RULE = new TreeForTentDirectRule(); @@ -29,19 +28,17 @@ public static void setUp() { /** * 3x3 TreeTent puzzle Tests TreeForTentDirectRule - *

TENT at (1, 0); TREE at (1, 1) - * XTX - * XRX - * XXX - *

Makes a line between (1, 0) and (1, 1) - * Checks that the rule correctly detects the central tree as the only possible connection + * + *

TENT at (1, 0); TREE at (1, 1) XTX XRX XXX + * + *

Makes a line between (1, 0) and (1, 1) Checks that the rule correctly detects the central + * tree as the only possible connection */ - @Test - public void TreeForTentTestOneTreeOneTentTest() throws InvalidFileFormatException { + @Test + public void TreeForTentTestOneTreeOneTentTest() throws InvalidFileFormatException { TestUtilities.importTestBoard( - "puzzles/treetent/rules/TreeForTentDirectRule/OneTentOneTree", - treetent); + "puzzles/treetent/rules/TreeForTentDirectRule/OneTentOneTree", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); @@ -61,19 +58,17 @@ public void TreeForTentTestOneTreeOneTentTest() throws InvalidFileFormatExceptio /** * 3x3 TreeTent puzzle Tests TreeForTentDirectRule - *

TENT at (1, 0) and (1, 2); TREE at (1, 1) - * XTX - * XRX - * XTX - *

Makes a line between (1, 0) and (1, 1) - * Checks that the rule works when connecting a line between the tent at (1, 0) and the tree at (1, 1) + * + *

TENT at (1, 0) and (1, 2); TREE at (1, 1) XTX XRX XTX + * + *

Makes a line between (1, 0) and (1, 1) Checks that the rule works when connecting a line + * between the tent at (1, 0) and the tree at (1, 1) */ @Test public void TentForTreeWithArbitraryTreeTest() throws InvalidFileFormatException { TestUtilities.importTestBoard( - "puzzles/treetent/rules/TreeForTentDirectRule/ArbitraryTent", - treetent); + "puzzles/treetent/rules/TreeForTentDirectRule/ArbitraryTent", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); @@ -93,19 +88,17 @@ public void TentForTreeWithArbitraryTreeTest() throws InvalidFileFormatException /** * 3x3 TreeTent puzzle Tests TreeForTentDirectRule - *

TENT at (1, 0) and (1, 2); TREE at (1, 1); LINE between (1, 0) and (1, 1) - * XTX - * XRX - * XTX - *

Makes a line between (1, 1) and (1, 2) - * Checks that the rule fails for the tent at (1, 2) because there are no valid trees to connect to + * + *

TENT at (1, 0) and (1, 2); TREE at (1, 1); LINE between (1, 0) and (1, 1) XTX XRX XTX + * + *

Makes a line between (1, 1) and (1, 2) Checks that the rule fails for the tent at (1, 2) + * because there are no valid trees to connect to */ @Test public void TentForTreeConnectedTent() throws InvalidFileFormatException { TestUtilities.importTestBoard( - "puzzles/treetent/rules/TreeForTentDirectRule/ConnectedTree", - treetent); + "puzzles/treetent/rules/TreeForTentDirectRule/ConnectedTree", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); @@ -130,18 +123,16 @@ public void TentForTreeConnectedTent() throws InvalidFileFormatException { /** * 3x3 TreeTent puzzle Tests TreeForTentDirectRule - *

TENT at (1, 1); TREE at (1, 0) and (1, 2) - * XRX - * XTX - * XRX - *

Makes a line between (1, 1) and (1, 2) - * Checks that the rule fails for the tree at (1, 1) because there are two valid trees to connect to + * + *

TENT at (1, 1); TREE at (1, 0) and (1, 2) XRX XTX XRX + * + *

Makes a line between (1, 1) and (1, 2) Checks that the rule fails for the tree at (1, 1) + * because there are two valid trees to connect to */ @Test public void TentForTreeOneTreeTwoAdjacentTent() throws InvalidFileFormatException { TestUtilities.importTestBoard( - "puzzles/treetent/rules/TreeForTentDirectRule/OneTentTwoAdjacentTrees", - treetent); + "puzzles/treetent/rules/TreeForTentDirectRule/OneTentTwoAdjacentTrees", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0);