From 1328083eedf257c0972fc3d35ced9f5cc802a4e7 Mon Sep 17 00:00:00 2001 From: zachbonagura Date: Tue, 30 Jan 2024 16:27:15 -0500 Subject: [PATCH 001/258] Test commit --- src/main/java/edu/rpi/legup/puzzle/binary/test.java | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/main/java/edu/rpi/legup/puzzle/binary/test.java diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/test.java b/src/main/java/edu/rpi/legup/puzzle/binary/test.java new file mode 100644 index 000000000..e69de29bb From 3a5ce8ece1bff3d06ae8646cb8f58c1c8f25be25 Mon Sep 17 00:00:00 2001 From: zachbonagura Date: Tue, 30 Jan 2024 16:30:07 -0500 Subject: [PATCH 002/258] Test commit again --- src/main/java/edu/rpi/legup/puzzle/binary/test.java | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 src/main/java/edu/rpi/legup/puzzle/binary/test.java diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/test.java b/src/main/java/edu/rpi/legup/puzzle/binary/test.java deleted file mode 100644 index e69de29bb..000000000 From 4a85b7f90e450491aa8a22cbdf9a9ff78ad3b867 Mon Sep 17 00:00:00 2001 From: zachbonagura Date: Tue, 30 Jan 2024 17:05:29 -0500 Subject: [PATCH 003/258] Implementing the constructor and some abstract methods --- .../edu/rpi/legup/puzzle/binary/Binary.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 src/main/java/edu/rpi/legup/puzzle/binary/Binary.java diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/Binary.java b/src/main/java/edu/rpi/legup/puzzle/binary/Binary.java new file mode 100644 index 000000000..c49d90af6 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/Binary.java @@ -0,0 +1,28 @@ +package edu.rpi.legup.puzzle.binary; + +import edu.rpi.legup.model.Puzzle; +import edu.rpi.legup.model.gameboard.Board; + +public class Binary extends Puzzle { + public Binary() { + super(); + } + + @Override + public void initializeView() { + } + + @Override + public Board generatePuzzle(int difficulty) { + return null; + } + + @Override + public boolean isBoardComplete(Board board) { + return true; + } + + @Override + public void onBoardChange(Board board) { + } +} \ No newline at end of file From f24c41fd60ddd8bf3aa1d5b0cac6cb37fcb74b52 Mon Sep 17 00:00:00 2001 From: zachbonagura Date: Thu, 1 Feb 2024 18:52:12 -0500 Subject: [PATCH 004/258] Implementing the BinaryType file for the grid cell possibilities --- .../java/edu/rpi/legup/puzzle/binary/BinaryType.java | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 src/main/java/edu/rpi/legup/puzzle/binary/BinaryType.java diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryType.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryType.java new file mode 100644 index 000000000..7fa857b30 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryType.java @@ -0,0 +1,9 @@ +package edu.rpi.legup.puzzle.binary; + +public enum BinaryType { + UNKNOWN, ZERO, ONE, NUMBER; + + public int toValue() { + return this.ordinal() - 2; + } +} From 9d33a1c98b2f9fbf8bf80003c9692eec27da96bc Mon Sep 17 00:00:00 2001 From: Brandon McCusker Date: Fri, 2 Feb 2024 17:16:00 -0500 Subject: [PATCH 005/258] initialized puzzle files, began writing the puzzle importer and finished most of binary.java functionality --- .../edu/rpi/legup/puzzle/binary/Binary.java | 33 +++++ .../rpi/legup/puzzle/binary/BinaryBoard.java | 19 +++ .../rpi/legup/puzzle/binary/BinaryCell.java | 36 ++++++ .../legup/puzzle/binary/BinaryExporter.java | 1 + .../legup/puzzle/binary/BinaryImporter.java | 113 ++++++++++++++++++ .../puzzle/binary/elements/BlankTile.java | 1 + .../puzzle/binary/elements/NumberTile.java | 1 + 7 files changed, 204 insertions(+) create mode 100644 src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java create mode 100644 src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java create mode 100644 src/main/java/edu/rpi/legup/puzzle/binary/BinaryExporter.java create mode 100644 src/main/java/edu/rpi/legup/puzzle/binary/BinaryImporter.java create mode 100644 src/main/java/edu/rpi/legup/puzzle/binary/elements/BlankTile.java create mode 100644 src/main/java/edu/rpi/legup/puzzle/binary/elements/NumberTile.java diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/Binary.java b/src/main/java/edu/rpi/legup/puzzle/binary/Binary.java index c49d90af6..a7d14c375 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/Binary.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/Binary.java @@ -6,10 +6,19 @@ public class Binary extends Puzzle { public Binary() { super(); + + this.name = "Binary"; + this.importer = new BinaryImporter(this); + this.exporter = new BinaryExporter(this); + + this.factory = new BinaryCellFactory(this); } @Override public void initializeView() { + boardView = new BinaryView((BinaryBoard) currentBoard); + boardView.setBoard(currentBoard); + addBoardListner(boardView); } @Override @@ -25,4 +34,28 @@ public boolean isBoardComplete(Board board) { @Override public void onBoardChange(Board board) { } + + + @Overrride + public boolean isValidDimensions(int rows, int columns){ + return rows >= 2 && rows % 2 == 0 && columns >= 2 && columns % 2 == 0; + } + + Override + public boolean isBoardComplete(Board board) { + BinaryBoard binaryBoard = (BinaryBoard) board; + + for (ContradictionRule rule : contradictionRules) { + if (rule.checkContradiction(binaryBoard) == null) { + return false; + } + } + for (PuzzleElement data : binaryBoard.getPuzzleElements()) { + BinaryCell cell = (BinaryCell) data; + if (cell.getType() == BinaryType.UNKNOWN) { + return false; + } + } + return true; + } } \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java new file mode 100644 index 000000000..7707aa068 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java @@ -0,0 +1,19 @@ +package edu.rpi.legup.puzzle.binary; + +import edu.rpi.legup.model.gameboard.GridBoard; +import edu.rpi.legup.model.gameboard.PuzzleElement; + +public class BinaryBoard extends GridBoard { + public BinaryBoard(int width, int height) { + super(width, height); + } + + public BinaryBoard(int size) { + super(size, size); + } + + @Override + public BinaryCell getCell(int x, int y) { + return (BinaryCell) super.getCell(x, y); + } +} \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java new file mode 100644 index 000000000..65464b372 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java @@ -0,0 +1,36 @@ +package edu.rpi.legup.puzzle.binary; + +import edu.rpi.legup.model.gameboard.GridCell; + +import java.awt.Point; + +public class BinaryCell extends GridCell { + public BinaryCell(int valueInt, Point location) { + super(valueInt, location); + } + + public BinaryType getType() { + switch (data) { + case -2: + return BinaryType.UNKNOWN; + case -1: + return BinaryType.ONE; + case 0: + return BinaryType.ZERO; + default: + if (data > 0) { + return BinaryType.NUMBER; + } + } + return null; + } + + @Override + public BinaryCell copy() { + BinaryCell copy = new BinaryCell(data, (Point) location.clone()); + copy.setIndex(index); + copy.setModifiable(isModifiable); + copy.setGiven(isGiven); + return copy; + } +} \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryExporter.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryExporter.java new file mode 100644 index 000000000..250267cc6 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryExporter.java @@ -0,0 +1 @@ +BinaryExporter.java \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryImporter.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryImporter.java new file mode 100644 index 000000000..85e957d43 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryImporter.java @@ -0,0 +1,113 @@ +package edu.rpi.legup.puzzle.binary; + +import edu.rpi.legup.model.PuzzleImporter; +import edu.rpi.legup.save.InvalidFileFormatException; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import java.awt.*; + +public class BinaryImporter extends PuzzleImporter { + public BinaryImporter(Binary binary) { + super(Binary); + } + + @Override + public boolean acceptsRowsAndColumnsInput() { + return true; + } + + @Override + public boolean acceptsTextInput() { + return false; + } + + @Override + public void initializeBoard(int rows, int columns) { + BinaryBoard binaryBoard = new BinaryBoard(columns, rows); + + for (int y = 0; y < rows; y++) { + for (int x = 0; x < columns; x++) { + BinaryCell cell = new BinaryCell(BinaryType.UNKNOWN.toValue(), new Point(x, y)); + cell.setIndex(y * columns + x); + cell.setModifiable(true); + binaryBoard.setCell(x, y, cell); + } + } + puzzle.setCurrentBoard(binaryBoard); + } + + /** + * Creates the board for building + * + * @param node xml document node + * @throws InvalidFileFormatException if file is invalid + */ + @Override + public void initializeBoard(Node node) throws InvalidFileFormatException { + try { + if (!node.getNodeName().equalsIgnoreCase("board")) { + throw new InvalidFileFormatException("binary Importer: cannot find board puzzleElement"); + } + Element boardElement = (Element) node; + if (boardElement.getElementsByTagName("cells").getLength() == 0) { + throw new InvalidFileFormatException("binary Importer: no puzzleElement found for board"); + } + + Element dataElement = (Element) boardElement.getElementsByTagName("cells").item(0); + NodeList elementDataList = dataElement.getElementsByTagName("cell"); + + BinaryBoard binaryBoard = null; + if (!boardElement.getAttribute("size").isEmpty()) { + int size = Integer.valueOf(boardElement.getAttribute("size")); + binaryBoard = new BinaryBoard(size); + } + else { + if (!boardElement.getAttribute("width").isEmpty() && !boardElement.getAttribute("height").isEmpty()) { + int width = Integer.valueOf(boardElement.getAttribute("width")); + int height = Integer.valueOf(boardElement.getAttribute("height")); + binaryBoard = new BinaryBoard(width, height); + } + } + + int width = nurikabeBoard.getWidth(); + int height = nurikabeBoard.getHeight(); + + if (binaryBoard == null || width % 2 != 0 || height % 2 != 0) { + throw new InvalidFileFormatException("binary Importer: invalid board dimensions"); + } + + + for (int i = 0; i < elementDataList.getLength(); i++) { + BinaryCell cell = (BinaryCell) puzzle.getFactory().importCell(elementDataList.item(i), binaryBoard); + Point loc = cell.getLocation(); + if (cell.getData() != BinaryType.UNKNOWN.toValue()) { + cell.setModifiable(false); + cell.setGiven(true); + } + binaryBoard.setCell(loc.x, loc.y, cell); + } + + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + if (binaryBoard.getCell(x, y) == null) { + BinaryCell cell = new BinaryCell(BinaryType.UNKNOWN.toValue(), new Point(x, y)); + cell.setIndex(y * height + x); + cell.setModifiable(true); + binaryBoard.setCell(x, y, cell); + } + } + } + puzzle.setCurrentBoard(binaryBoard); + } + catch (NumberFormatException e) { + throw new InvalidFileFormatException("binary Importer: unknown value where integer expected"); + } + } + + @Override + public void initializeBoard(String[] statements) throws UnsupportedOperationException { + throw new UnsupportedOperationException("Binary cannot accept text input"); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/elements/BlankTile.java b/src/main/java/edu/rpi/legup/puzzle/binary/elements/BlankTile.java new file mode 100644 index 000000000..ab1895ce5 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/elements/BlankTile.java @@ -0,0 +1 @@ +BlankTile.java diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/elements/NumberTile.java b/src/main/java/edu/rpi/legup/puzzle/binary/elements/NumberTile.java new file mode 100644 index 000000000..38bc619d6 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/elements/NumberTile.java @@ -0,0 +1 @@ +NumberTile.java \ No newline at end of file From ae2d93ca6911cd7088535f622c2d346937611b83 Mon Sep 17 00:00:00 2001 From: zachbonagura Date: Thu, 1 Feb 2024 23:13:38 -0500 Subject: [PATCH 006/258] Implemented the BinaryCell class with the constructor, and worked on BinaryType getType() function and BinaryCell copy() function --- .../rpi/legup/puzzle/binary/BinaryCell.java | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java new file mode 100644 index 000000000..56b37c03e --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java @@ -0,0 +1,36 @@ +package edu.rpi.legup.puzzle.binary; + +import edu.rpi.legup.model.gameboard.GridCell; + +import java.awt.Point; + +public class BinaryCell extends GridCell { + public BinaryCell(int valueInt, Point location) { + super(valueInt, location); + } + + public BinaryType getType() { + switch (data) { + case -2: + return BinaryType.UNKNOWN; + case -1: + return BinaryType.ZERO; + case 0: + return BinaryType.ONE; + default: + if (data > 0) { + return BinaryType.NUMBER; + } + } + return null; + } + + @Override + public BinaryCell copy() { + BinaryCell copy = new BinaryCell(data, (Point) location.clone()); + copy.setIndex(index); + copy.setModifiable(isModifiable); + copy.setGiven(isGiven); + return copy; + } +} \ No newline at end of file From 923b93a33e7f7aaa34d292f0a773f90b058a7059 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Tue, 6 Feb 2024 16:52:53 -0500 Subject: [PATCH 007/258] Finished setting up BinaryImporter completely with all helper files (BinaryView, BinaryCellFactory, BinaryController, BinaryElementView). These files create the grid view of the puzzle and are responsible for the GUI of the puzzle. --- .../edu/rpi/legup/puzzle/binary/Binary.java | 2 +- .../puzzle/binary/BinaryCellFactory.java | 58 +++++++++++++++ .../legup/puzzle/binary/BinaryController.java | 47 ++++++++++++ .../puzzle/binary/BinaryElementView.java | 72 +++++++++++++++++++ .../legup/puzzle/binary/BinaryExporter.java | 1 - .../legup/puzzle/binary/BinaryImporter.java | 6 +- .../rpi/legup/puzzle/binary/BinaryView.java | 24 +++++++ .../ThreeAdjacentZerosContradictionRule.java | 20 ++++++ 8 files changed, 225 insertions(+), 5 deletions(-) create mode 100644 src/main/java/edu/rpi/legup/puzzle/binary/BinaryCellFactory.java create mode 100644 src/main/java/edu/rpi/legup/puzzle/binary/BinaryController.java create mode 100644 src/main/java/edu/rpi/legup/puzzle/binary/BinaryElementView.java delete mode 100644 src/main/java/edu/rpi/legup/puzzle/binary/BinaryExporter.java create mode 100644 src/main/java/edu/rpi/legup/puzzle/binary/BinaryView.java create mode 100644 src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentZerosContradictionRule.java diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/Binary.java b/src/main/java/edu/rpi/legup/puzzle/binary/Binary.java index a7d14c375..06428ea18 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/Binary.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/Binary.java @@ -41,7 +41,7 @@ public boolean isValidDimensions(int rows, int columns){ return rows >= 2 && rows % 2 == 0 && columns >= 2 && columns % 2 == 0; } - Override + @Override public boolean isBoardComplete(Board board) { BinaryBoard binaryBoard = (BinaryBoard) board; diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCellFactory.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCellFactory.java new file mode 100644 index 000000000..729cae171 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCellFactory.java @@ -0,0 +1,58 @@ +package edu.rpi.legup.puzzle.binary; + +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.w3c.dom.Document; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; + +import java.awt.*; + +public class BinaryCellFactory extends ElementFactory { + public BinaryCell importCell(Node node, Board board) throws InvalidFileFormatException { + try { + if (!node.getNodeName().equalsIgnoreCase("cell")) { + throw new InvalidFileFormatException("nurikabe Factory: unknown puzzleElement puzzleElement"); + } + + BinaryBoard binaryBoard = (BinaryBoard) board; + int width = binaryBoard.getWidth(); + int height = binaryBoard.getHeight(); + + NamedNodeMap attributeList = node.getAttributes(); + int value = Integer.valueOf(attributeList.getNamedItem("value").getNodeValue()); + int x = Integer.valueOf(attributeList.getNamedItem("x").getNodeValue()); + int y = Integer.valueOf(attributeList.getNamedItem("y").getNodeValue()); + + if (x >= width || y >= height) { + throw new InvalidFileFormatException("binary Factory: cell location out of bounds"); + } + if (value < -2) { + throw new InvalidFileFormatException("binary Factory: cell unknown value"); + } + + BinaryCell cell = new BinaryCell(value, new Point(x, y)); + cell.setIndex(y * height + x); + return cell; + } catch (NumberFormatException e) { + throw new InvalidFileFormatException("binary Factory: unknown value where integer expected"); + } catch (NullPointerException e) { + throw new InvalidFileFormatException("binary Factory: could not find attribute(s)"); + } + } + + public org.w3c.dom.Element exportCell(Document document, PuzzleElement puzzleElement) { + org.w3c.dom.Element cellElement = document.createElement("cell"); + + BinaryCell cell = (BinaryCell) puzzleElement; + Point loc = cell.getLocation(); + + cellElement.setAttribute("value", String.valueOf(cell.getData())); + cellElement.setAttribute("x", String.valueOf(loc.x)); + cellElement.setAttribute("y", String.valueOf(loc.y)); + + return cellElement; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryController.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryController.java new file mode 100644 index 000000000..9189f7ebe --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryController.java @@ -0,0 +1,47 @@ +package edu.rpi.legup.puzzle.binary; + +import edu.rpi.legup.controller.ElementController; +import edu.rpi.legup.model.gameboard.PuzzleElement; + +import java.awt.event.MouseEvent; + +public class BinaryController extends ElementController { + + @Override + public void changeCell(MouseEvent e, PuzzleElement data) { + BinaryCell cell = (BinaryCell) 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 { + if (cell.getData() == -2) { + data.setData(0); + } + else { + if (cell.getData() == 0) { + data.setData(-1); + } + else { + data.setData(-2); + } + } + } + } + else { + if (e.getButton() == MouseEvent.BUTTON3) { + if (cell.getData() == -2) { + data.setData(-1); + } + else { + if (cell.getData() == 0) { + data.setData(-2); + } + else { + data.setData(0); + } + } + } + } + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryElementView.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryElementView.java new file mode 100644 index 000000000..ca37de73f --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryElementView.java @@ -0,0 +1,72 @@ +package edu.rpi.legup.puzzle.binary; + +import edu.rpi.legup.ui.boardview.GridElementView; + +import java.awt.*; + +public class BinaryElementView extends GridElementView { + + private static final Font FONT = new Font("TimesRoman", Font.BOLD, 16); + private static final Color FONT_COLOR = Color.BLACK; + + public BinaryElementView(BinaryCell cell) { + super(cell); + } + + /** + * Gets the PuzzleElement associated with this view + * + * @return PuzzleElement associated with this view + */ + @Override + public BinaryCell getPuzzleElement() { + return (BinaryCell) super.getPuzzleElement(); + } + + @Override + public void drawElement(Graphics2D graphics2D) { + BinaryCell cell = (BinaryCell) puzzleElement; + BinaryType type = cell.getType(); + if (type == BinaryType.NUMBER) { + graphics2D.setStroke(new BasicStroke(1)); + graphics2D.setColor(Color.WHITE); + graphics2D.fillRect(location.x, location.y, size.width, size.height); + + graphics2D.setColor(Color.BLACK); + graphics2D.drawRect(location.x, location.y, size.width, size.height); + + graphics2D.setColor(FONT_COLOR); + graphics2D.setFont(FONT); + FontMetrics metrics = graphics2D.getFontMetrics(FONT); + String value = String.valueOf(puzzleElement.getData()); + int xText = location.x + (size.width - metrics.stringWidth(value)) / 2; + int yText = location.y + ((size.height - metrics.getHeight()) / 2) + metrics.getAscent(); + graphics2D.drawString(String.valueOf(puzzleElement.getData()), xText, yText); + } + else { + if (type == BinaryType.ZERO) { + graphics2D.setStroke(new BasicStroke(1)); + graphics2D.setColor(Color.BLACK); + graphics2D.fillRect(location.x, location.y, size.width, size.height); + } + else { + if (type == BinaryType.ONE) { + 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); + } + else { + if (type == BinaryType.UNKNOWN) { + 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/binary/BinaryExporter.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryExporter.java deleted file mode 100644 index 250267cc6..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryExporter.java +++ /dev/null @@ -1 +0,0 @@ -BinaryExporter.java \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryImporter.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryImporter.java index 85e957d43..c6839e36c 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryImporter.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryImporter.java @@ -10,7 +10,7 @@ public class BinaryImporter extends PuzzleImporter { public BinaryImporter(Binary binary) { - super(Binary); + super(binary); } @Override @@ -71,8 +71,8 @@ public void initializeBoard(Node node) throws InvalidFileFormatException { } } - int width = nurikabeBoard.getWidth(); - int height = nurikabeBoard.getHeight(); + int width = binaryBoard.getWidth(); + int height = binaryBoard.getHeight(); if (binaryBoard == null || width % 2 != 0 || height % 2 != 0) { throw new InvalidFileFormatException("binary Importer: invalid board dimensions"); diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryView.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryView.java new file mode 100644 index 000000000..9e678b003 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryView.java @@ -0,0 +1,24 @@ +package edu.rpi.legup.puzzle.binary; + +import edu.rpi.legup.controller.BoardController; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.ui.boardview.GridBoardView; + +import java.awt.*; + +public class BinaryView extends GridBoardView { + + public BinaryView(BinaryBoard board) { + super(new BoardController(), new BinaryController(), board.getDimension()); + + for (PuzzleElement puzzleElement : board.getPuzzleElements()) { + BinaryCell cell = (BinaryCell) puzzleElement; + Point loc = cell.getLocation(); + BinaryElementView elementView = new BinaryElementView(cell); + elementView.setIndex(cell.getIndex()); + elementView.setSize(elementSize); + elementView.setLocation(new Point(loc.x * elementSize.width, loc.y * elementSize.height)); + elementViews.add(elementView); + } + } +} \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentZerosContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentZerosContradictionRule.java new file mode 100644 index 000000000..cf1b6c2b9 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentZerosContradictionRule.java @@ -0,0 +1,20 @@ +package edu.rpi.legup.puzzle.binary.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.binary.BinaryBoard; +import edu.rpi.legup.puzzle.binary.BinaryCell; +import edu.rpi.legup.puzzle.binary.BinaryType; + +import java.util.Set; +public class ThreeAdjacentZerosContradictionRule extends ContradictionRule { + private final String NO_CONTRADICTION_MESSAGE = "Does not contain a contradiction at this index"; + + public ThreeAdjacentZerosContradictionRule() { + super("","Three Adjacent Zeros", "There cannot be three adjacent zeros in a row or column", ""); + } + public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { + return null; + } +} From 5c301f77610c4d6176546d4446eeaf9f27410570 Mon Sep 17 00:00:00 2001 From: Brandon McCusker Date: Tue, 6 Feb 2024 17:03:48 -0500 Subject: [PATCH 008/258] Fixed bugs in binary files, wrote binary exporter --- gradlew | 0 puzzles files/binary/6x6 easy/123456789.xml | 24 +++++++++++ .../edu/rpi/legup/puzzle/binary/Binary.java | 2 +- .../legup/puzzle/binary/BinaryExporter.java | 40 ++++++++++++++++++- .../legup/puzzle/binary/BinaryImporter.java | 6 +-- .../puzzle/binary/elements/BlankTile.java | 2 +- .../puzzle/binary/elements/NumberTile.java | 1 - 7 files changed, 68 insertions(+), 7 deletions(-) mode change 100644 => 100755 gradlew create mode 100644 puzzles files/binary/6x6 easy/123456789.xml diff --git a/gradlew b/gradlew old mode 100644 new mode 100755 diff --git a/puzzles files/binary/6x6 easy/123456789.xml b/puzzles files/binary/6x6 easy/123456789.xml new file mode 100644 index 000000000..18a8cbab3 --- /dev/null +++ b/puzzles files/binary/6x6 easy/123456789.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/Binary.java b/src/main/java/edu/rpi/legup/puzzle/binary/Binary.java index a7d14c375..06428ea18 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/Binary.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/Binary.java @@ -41,7 +41,7 @@ public boolean isValidDimensions(int rows, int columns){ return rows >= 2 && rows % 2 == 0 && columns >= 2 && columns % 2 == 0; } - Override + @Override public boolean isBoardComplete(Board board) { BinaryBoard binaryBoard = (BinaryBoard) board; diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryExporter.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryExporter.java index 250267cc6..46df98a47 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryExporter.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryExporter.java @@ -1 +1,39 @@ -BinaryExporter.java \ No newline at end of file +package edu.rpi.legup.puzzle.nurikabe; + +import edu.rpi.legup.model.PuzzleExporter; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import org.w3c.dom.Document; + +public class BinaryExporter extends PuzzleExporter { + + public BinaryExporter(Binary binary) { + super(binary); + } + + @Override + protected org.w3c.dom.Element createBoardElement(Document newDocument) { + BinaryBoard board; + if (puzzle.getTree() != null) { + board = (BinaryBoard) puzzle.getTree().getRootNode().getBoard(); + } + else { + board = (BinaryBoard) puzzle.getBoardView().getBoard(); + } + + org.w3c.dom.Element boardElement = newDocument.createElement("board"); + boardElement.setAttribute("width", String.valueOf(board.getWidth())); + boardElement.setAttribute("height", String.valueOf(board.getHeight())); + + org.w3c.dom.Element cellsElement = newDocument.createElement("cells"); + for (PuzzleElement puzzleElement : board.getPuzzleElements()) { + BinaryCell cell = (BinaryCell) puzzleElement; + if (cell.getData() != -2) { + 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/binary/BinaryImporter.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryImporter.java index 85e957d43..c6839e36c 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryImporter.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryImporter.java @@ -10,7 +10,7 @@ public class BinaryImporter extends PuzzleImporter { public BinaryImporter(Binary binary) { - super(Binary); + super(binary); } @Override @@ -71,8 +71,8 @@ public void initializeBoard(Node node) throws InvalidFileFormatException { } } - int width = nurikabeBoard.getWidth(); - int height = nurikabeBoard.getHeight(); + int width = binaryBoard.getWidth(); + int height = binaryBoard.getHeight(); if (binaryBoard == null || width % 2 != 0 || height % 2 != 0) { throw new InvalidFileFormatException("binary Importer: invalid board dimensions"); diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/elements/BlankTile.java b/src/main/java/edu/rpi/legup/puzzle/binary/elements/BlankTile.java index ab1895ce5..8b1378917 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/elements/BlankTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/elements/BlankTile.java @@ -1 +1 @@ -BlankTile.java + diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/elements/NumberTile.java b/src/main/java/edu/rpi/legup/puzzle/binary/elements/NumberTile.java index 38bc619d6..e69de29bb 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/elements/NumberTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/elements/NumberTile.java @@ -1 +0,0 @@ -NumberTile.java \ No newline at end of file From a62c000f9d98ef23cb12d83c0e5fe0468180a5dd Mon Sep 17 00:00:00 2001 From: Brandon McCusker Date: Fri, 9 Feb 2024 16:23:55 -0500 Subject: [PATCH 009/258] Fixed compile errors --- puzzles files/binary/6x6 easy/123456789.xml | 24 ------------- puzzles files/binary/6x6 easy/876868768.xml | 24 +++++++++++++ .../edu/rpi/legup/puzzle/binary/Binary.java | 35 +++++++++---------- .../legup/puzzle/binary/BinaryExporter.java | 2 +- 4 files changed, 42 insertions(+), 43 deletions(-) create mode 100644 puzzles files/binary/6x6 easy/876868768.xml diff --git a/puzzles files/binary/6x6 easy/123456789.xml b/puzzles files/binary/6x6 easy/123456789.xml index 18a8cbab3..e69de29bb 100644 --- a/puzzles files/binary/6x6 easy/123456789.xml +++ b/puzzles files/binary/6x6 easy/123456789.xml @@ -1,24 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/puzzles files/binary/6x6 easy/876868768.xml b/puzzles files/binary/6x6 easy/876868768.xml new file mode 100644 index 000000000..18a8cbab3 --- /dev/null +++ b/puzzles files/binary/6x6 easy/876868768.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/Binary.java b/src/main/java/edu/rpi/legup/puzzle/binary/Binary.java index 06428ea18..7a48ee190 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/Binary.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/Binary.java @@ -2,6 +2,8 @@ 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; public class Binary extends Puzzle { public Binary() { @@ -11,14 +13,14 @@ public Binary() { this.importer = new BinaryImporter(this); this.exporter = new BinaryExporter(this); - this.factory = new BinaryCellFactory(this); + this.factory = new BinaryCellFactory(); } @Override public void initializeView() { boardView = new BinaryView((BinaryBoard) currentBoard); boardView.setBoard(currentBoard); - addBoardListner(boardView); + addBoardListener(boardView); } @Override @@ -26,22 +28,7 @@ public Board generatePuzzle(int difficulty) { return null; } - @Override - public boolean isBoardComplete(Board board) { - return true; - } - - @Override - public void onBoardChange(Board board) { - } - - - @Overrride - public boolean isValidDimensions(int rows, int columns){ - return rows >= 2 && rows % 2 == 0 && columns >= 2 && columns % 2 == 0; - } - - @Override + @Override public boolean isBoardComplete(Board board) { BinaryBoard binaryBoard = (BinaryBoard) board; @@ -58,4 +45,16 @@ public boolean isBoardComplete(Board board) { } return true; } + + @Override + public void onBoardChange(Board board) { + } + + + @Override + public boolean isValidDimensions(int rows, int columns){ + return rows >= 2 && rows % 2 == 0 && columns >= 2 && columns % 2 == 0; + } + + } \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryExporter.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryExporter.java index 46df98a47..2f79d61b2 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryExporter.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryExporter.java @@ -1,4 +1,4 @@ -package edu.rpi.legup.puzzle.nurikabe; +package edu.rpi.legup.puzzle.binary; import edu.rpi.legup.model.PuzzleExporter; import edu.rpi.legup.model.gameboard.PuzzleElement; From 49b00580400cb36f24768706c482a1b8b253ab90 Mon Sep 17 00:00:00 2001 From: Brandon McCusker Date: Fri, 9 Feb 2024 18:22:49 -0500 Subject: [PATCH 010/258] Added binary puzzle to config, began writing rules --- bin/main/edu/rpi/legup/legup/config | 4 ++++ puzzles files/binary/6x6 easy/123456789.xml | 0 puzzles files/binary/6x6 easy/876868768.xml | 2 +- .../puzzle/binary/BinaryCellFactory.java | 1 + .../rules/CompleteRowColumnDirectRule.java | 21 +++++++++++++++++++ .../binary/rules/OneTileGapDirectRule.java | 21 +++++++++++++++++++ .../binary/rules/OneorZeroCaseRule.java | 20 ++++++++++++++++++ .../binary/rules/SurroundPairDirectRule.java | 21 +++++++++++++++++++ .../ThreeAdjacentZerosContradictionRule.java | 20 ------------------ .../rules/ThreeInARowContradictionRule.java | 20 ++++++++++++++++++ .../UnbalancedRowColumnContractionRule.java | 20 ++++++++++++++++++ .../binary/rules/binary_reference_sheet.txt | 8 +++++++ 12 files changed, 137 insertions(+), 21 deletions(-) delete mode 100644 puzzles files/binary/6x6 easy/123456789.xml create mode 100644 src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java create mode 100644 src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java create mode 100644 src/main/java/edu/rpi/legup/puzzle/binary/rules/OneorZeroCaseRule.java create mode 100644 src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java delete mode 100644 src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentZerosContradictionRule.java create mode 100644 src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeInARowContradictionRule.java create mode 100644 src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowColumnContractionRule.java create mode 100644 src/main/java/edu/rpi/legup/puzzle/binary/rules/binary_reference_sheet.txt diff --git a/bin/main/edu/rpi/legup/legup/config b/bin/main/edu/rpi/legup/legup/config index 19e63a2a3..b30cb8525 100644 --- a/bin/main/edu/rpi/legup/legup/config +++ b/bin/main/edu/rpi/legup/legup/config @@ -39,5 +39,9 @@ qualifiedClassName="edu.rpi.legup.puzzle.skyscrapers.Skyscrapers" fileType=".xml" fileCreationDisabled="true"/> + diff --git a/puzzles files/binary/6x6 easy/123456789.xml b/puzzles files/binary/6x6 easy/123456789.xml deleted file mode 100644 index e69de29bb..000000000 diff --git a/puzzles files/binary/6x6 easy/876868768.xml b/puzzles files/binary/6x6 easy/876868768.xml index 18a8cbab3..ceefaefff 100644 --- a/puzzles files/binary/6x6 easy/876868768.xml +++ b/puzzles files/binary/6x6 easy/876868768.xml @@ -1,7 +1,7 @@ - + diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCellFactory.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCellFactory.java index 729cae171..d56e26e7c 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCellFactory.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCellFactory.java @@ -11,6 +11,7 @@ import java.awt.*; public class BinaryCellFactory extends ElementFactory { + public BinaryCell importCell(Node node, Board board) throws InvalidFileFormatException { try { if (!node.getNodeName().equalsIgnoreCase("cell")) { diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java new file mode 100644 index 000000000..bab6e7223 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java @@ -0,0 +1,21 @@ +package edu.rpi.legup.puzzle.binary.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.DirectRule; +import edu.rpi.legup.model.ContradictionRule; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.binary.BinaryBoard; +import edu.rpi.legup.puzzle.binary.BinaryCell; +import edu.rpi.legup.puzzle.binary.BinaryType; + +public class CompleteRowColumnDirectRule extends DirectRule { + + public CompleteRowColumnDirectRule() { + super("BINA-BASC-0003", + "Complete Row Column" + "If a row/column of length n contains n/2 of a single value, the remaining cells must contain the other value", + "FILL IN WITH IMAGE"); + } +} \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java new file mode 100644 index 000000000..8a8a1f53e --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java @@ -0,0 +1,21 @@ +package edu.rpi.legup.puzzle.binary.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.DirectRule; +import edu.rpi.legup.model.ContradictionRule; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.binary.BinaryBoard; +import edu.rpi.legup.puzzle.binary.BinaryCell; +import edu.rpi.legup.puzzle.binary.BinaryType; + +public class OneTileGapDirectRule extends DirectRule { + + public OneTileGapDirectRule() { + super("BINA-BASC-0002", + "One Tile Gap", + "If an empty tile is surrounded by the same value, fill the gap with the other value.", + "FILL IN WITH IMAGE"); + } +} \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneorZeroCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneorZeroCaseRule.java new file mode 100644 index 000000000..63f882f83 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneorZeroCaseRule.java @@ -0,0 +1,20 @@ +package edu.rpi.legup.puzzle.binary.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.binary.BinaryBoard; +import edu.rpi.legup.puzzle.binary.BinaryCell; +import edu.rpi.legup.puzzle.binary.BinaryType; + +public class OneOrZeroCaseRule extends CaseRule { + + public OneOrZeroCaseRule() { + super("BINA-CASE-0001", + "One or Zero", + "Each blank cell is either a one or a zero.", + "FILL IN WITH IMAGE"); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java new file mode 100644 index 000000000..44bd5beee --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java @@ -0,0 +1,21 @@ +package edu.rpi.legup.puzzle.binary.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.DirectRule; +import edu.rpi.legup.model.ContradictionRule; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.binary.BinaryBoard; +import edu.rpi.legup.puzzle.binary.BinaryCell; +import edu.rpi.legup.puzzle.binary.BinaryType; + +public class SurroundPairDirectRule extends DirectRule { + + public SurroundPairDirectRule() { + super("BINA-BASC-0001", + "Surround Pair", + "If two adjacent tiles have the same value, surround the tiles with the other value.", + "FILL IN WITH IMAGE"); + } +} \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentZerosContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentZerosContradictionRule.java deleted file mode 100644 index cf1b6c2b9..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentZerosContradictionRule.java +++ /dev/null @@ -1,20 +0,0 @@ -package edu.rpi.legup.puzzle.binary.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.binary.BinaryBoard; -import edu.rpi.legup.puzzle.binary.BinaryCell; -import edu.rpi.legup.puzzle.binary.BinaryType; - -import java.util.Set; -public class ThreeAdjacentZerosContradictionRule extends ContradictionRule { - private final String NO_CONTRADICTION_MESSAGE = "Does not contain a contradiction at this index"; - - public ThreeAdjacentZerosContradictionRule() { - super("","Three Adjacent Zeros", "There cannot be three adjacent zeros in a row or column", ""); - } - public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { - return null; - } -} diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeInARowContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeInARowContradictionRule.java new file mode 100644 index 000000000..4965ce24a --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeInARowContradictionRule.java @@ -0,0 +1,20 @@ +package edu.rpi.legup.puzzle.binary.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.BinaryBoard; +import edu.rpi.legup.puzzle.nurikabe.BinaryCell; +import edu.rpi.legup.puzzle.nurikabe.BinaryType; + +public class ThreeInARowContradictionRule extends ContradictionRule { + + private final String NO_CONTRADICTION_MESSAGE = ""; + private final String INVALID_USE_MESSAGE = "Does not contain a contradiction at this index"; + + public ThreeInARowContradictionRule() { + super("BINA-CONT-0001", + "Three In A Row", + "Three of the same value cannot exist in a row", + "FILL IN WITH IMAGE"); + } \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowColumnContractionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowColumnContractionRule.java new file mode 100644 index 000000000..f86377004 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowColumnContractionRule.java @@ -0,0 +1,20 @@ +package edu.rpi.legup.puzzle.binary.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.BinaryBoard; +import edu.rpi.legup.puzzle.nurikabe.BinaryCell; +import edu.rpi.legup.puzzle.nurikabe.BinaryType; + +public class UnbalancedRowColumnContradictionRule extends ContradictionRule { + + private final String NO_CONTRADICTION_MESSAGE = ""; + private final String INVALID_USE_MESSAGE = "Does not contain a contradiction at this index"; + + public UnbalancedRowColumnContradictionRule() { + super("BINA-CONT-0002", + "Unbalanced Row Column", + "A row or column cannot contain more of more value than the other", + "FILL IN WITH IMAGE"); + } \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/binary_reference_sheet.txt b/src/main/java/edu/rpi/legup/puzzle/binary/rules/binary_reference_sheet.txt new file mode 100644 index 000000000..bab194b2f --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/binary_reference_sheet.txt @@ -0,0 +1,8 @@ +BINA-BASC-0001 : SurroundPairDirectRule +BINA-BASC-0002 : OneTileGapDirectRule +BINA-BASC-0003 : CompleteRowCloumnDirectRule + +BINA-CONT-0001 : ThreeInARowContradictionRule +BINA-CONT-0002 : UnbalancedRowColumnContradictionRule + +BINA-CASE-0001 : OneOrZeroCaseRule \ No newline at end of file From 3432007d189a58ea1431a4f6a2eb7414e319fa94 Mon Sep 17 00:00:00 2001 From: Brandon McCusker Date: Fri, 9 Feb 2024 18:51:26 -0500 Subject: [PATCH 011/258] Fixed minor syntax and import error --- .../rules/CompleteRowColumnDirectRule.java | 18 +++++++++++---- ...roCaseRule.java => OneOrZeroCaseRule.java} | 23 +++++++++++++++++++ .../binary/rules/OneTileGapDirectRule.java | 16 ++++++++++--- .../binary/rules/SurroundPairDirectRule.java | 17 +++++++++++--- .../rules/ThreeInARowContradictionRule.java | 14 +++++++---- ...UnbalancedRowColumnContradictionRule.java} | 14 +++++++---- 6 files changed, 84 insertions(+), 18 deletions(-) rename src/main/java/edu/rpi/legup/puzzle/binary/rules/{OneorZeroCaseRule.java => OneOrZeroCaseRule.java} (57%) rename src/main/java/edu/rpi/legup/puzzle/binary/rules/{UnbalancedRowColumnContractionRule.java => UnbalancedRowColumnContradictionRule.java} (71%) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java index bab6e7223..1a35902f3 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java @@ -1,10 +1,10 @@ package edu.rpi.legup.puzzle.binary.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.DirectRule; -import edu.rpi.legup.model.ContradictionRule; +import edu.rpi.legup.model.rules.DirectRule; +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.binary.BinaryBoard; import edu.rpi.legup.puzzle.binary.BinaryCell; @@ -14,8 +14,18 @@ public class CompleteRowColumnDirectRule extends DirectRule { public CompleteRowColumnDirectRule() { super("BINA-BASC-0003", - "Complete Row Column" + "Complete Row Column", "If a row/column of length n contains n/2 of a single value, the remaining cells must contain the other value", "FILL IN WITH IMAGE"); } + + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + return null; + } + + @Override + public Board getDefaultBoard(TreeNode node) { + return null; + } } \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneorZeroCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneOrZeroCaseRule.java similarity index 57% rename from src/main/java/edu/rpi/legup/puzzle/binary/rules/OneorZeroCaseRule.java rename to src/main/java/edu/rpi/legup/puzzle/binary/rules/OneOrZeroCaseRule.java index 63f882f83..0e3337d2f 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneorZeroCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneOrZeroCaseRule.java @@ -9,6 +9,9 @@ import edu.rpi.legup.puzzle.binary.BinaryCell; import edu.rpi.legup.puzzle.binary.BinaryType; +import java.util.ArrayList; +import java.util.List; + public class OneOrZeroCaseRule extends CaseRule { public OneOrZeroCaseRule() { @@ -17,4 +20,24 @@ public OneOrZeroCaseRule() { "Each blank cell is either a one or a zero.", "FILL IN WITH IMAGE"); } + + @Override + public String checkRuleRaw(TreeTransition transition) { + return null; + } + + @Override + public CaseBoard getCaseBoard(Board board) { + return null; + } + + @Override + public ArrayList getCases(Board board, PuzzleElement puzzleElement) { + return null; + } + + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + return null; + } } diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java index 8a8a1f53e..704098e56 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java @@ -1,10 +1,10 @@ package edu.rpi.legup.puzzle.binary.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.DirectRule; -import edu.rpi.legup.model.ContradictionRule; +import edu.rpi.legup.model.rules.DirectRule; +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.binary.BinaryBoard; import edu.rpi.legup.puzzle.binary.BinaryCell; @@ -18,4 +18,14 @@ public OneTileGapDirectRule() { "If an empty tile is surrounded by the same value, fill the gap with the other value.", "FILL IN WITH IMAGE"); } + + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + return null; + } + + @Override + public Board getDefaultBoard(TreeNode node) { + return null; + } } \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java index 44bd5beee..acc774f26 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java @@ -1,10 +1,10 @@ package edu.rpi.legup.puzzle.binary.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.DirectRule; -import edu.rpi.legup.model.ContradictionRule; +import edu.rpi.legup.model.rules.DirectRule; +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.binary.BinaryBoard; import edu.rpi.legup.puzzle.binary.BinaryCell; @@ -18,4 +18,15 @@ public SurroundPairDirectRule() { "If two adjacent tiles have the same value, surround the tiles with the other value.", "FILL IN WITH IMAGE"); } + + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + return null; + } + + @Override + public Board getDefaultBoard(TreeNode node) { + return null; + } + } \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeInARowContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeInARowContradictionRule.java index 4965ce24a..201ba00f5 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeInARowContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeInARowContradictionRule.java @@ -3,9 +3,9 @@ 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.BinaryBoard; -import edu.rpi.legup.puzzle.nurikabe.BinaryCell; -import edu.rpi.legup.puzzle.nurikabe.BinaryType; +import edu.rpi.legup.puzzle.binary.BinaryBoard; +import edu.rpi.legup.puzzle.binary.BinaryCell; +import edu.rpi.legup.puzzle.binary.BinaryType; public class ThreeInARowContradictionRule extends ContradictionRule { @@ -17,4 +17,10 @@ public ThreeInARowContradictionRule() { "Three In A Row", "Three of the same value cannot exist in a row", "FILL IN WITH IMAGE"); - } \ No newline at end of file + } + + @Override + public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { + return null; + } +} \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowColumnContractionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowColumnContradictionRule.java similarity index 71% rename from src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowColumnContractionRule.java rename to src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowColumnContradictionRule.java index f86377004..1bfe72ecb 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowColumnContractionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowColumnContradictionRule.java @@ -3,9 +3,9 @@ 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.BinaryBoard; -import edu.rpi.legup.puzzle.nurikabe.BinaryCell; -import edu.rpi.legup.puzzle.nurikabe.BinaryType; +import edu.rpi.legup.puzzle.binary.BinaryBoard; +import edu.rpi.legup.puzzle.binary.BinaryCell; +import edu.rpi.legup.puzzle.binary.BinaryType; public class UnbalancedRowColumnContradictionRule extends ContradictionRule { @@ -17,4 +17,10 @@ public UnbalancedRowColumnContradictionRule() { "Unbalanced Row Column", "A row or column cannot contain more of more value than the other", "FILL IN WITH IMAGE"); - } \ No newline at end of file + } + + @Override + public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { + return null; + } +} \ No newline at end of file From b718f16d48dffdb17420f289228f3e96fec722e8 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Tue, 13 Feb 2024 16:28:35 -0500 Subject: [PATCH 012/258] Fixed checkstyle error message in BinaryCellFactory --- .../java/edu/rpi/legup/puzzle/binary/BinaryCellFactory.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCellFactory.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCellFactory.java index d56e26e7c..a2211f35c 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCellFactory.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCellFactory.java @@ -37,9 +37,11 @@ public BinaryCell importCell(Node node, Board board) throws InvalidFileFormatExc BinaryCell cell = new BinaryCell(value, new Point(x, y)); cell.setIndex(y * height + x); return cell; - } catch (NumberFormatException e) { + } + catch (NumberFormatException e) { throw new InvalidFileFormatException("binary Factory: unknown value where integer expected"); - } catch (NullPointerException e) { + } + catch (NullPointerException e) { throw new InvalidFileFormatException("binary Factory: could not find attribute(s)"); } } From 76660a3528d8ec5dd7072dd0816f28e01c07d021 Mon Sep 17 00:00:00 2001 From: EggyMath <55564321+EggyMath@users.noreply.github.com> Date: Tue, 13 Feb 2024 17:24:26 -0500 Subject: [PATCH 013/258] Refactoring and bug fixes Refactored Case Rules to match wiki description and fixed bug that only checked regions and not all group types. --- .../legup/puzzle/sudoku/PossibleNumberCaseBoard.java | 4 ++-- ...le.java => NoCellForNumberContradictionRule.java} | 6 +++--- ...Rule.java => PossibleCellsForNumberCaseRule.java} | 8 ++++---- ...Rule.java => PossibleNumbersForCellCaseRule.java} | 12 ++++++------ 4 files changed, 15 insertions(+), 15 deletions(-) rename src/main/java/edu/rpi/legup/puzzle/sudoku/rules/{NoSolutionContradictionRule.java => NoCellForNumberContradictionRule.java} (91%) rename src/main/java/edu/rpi/legup/puzzle/sudoku/rules/{PossibleNumberCaseRule.java => PossibleCellsForNumberCaseRule.java} (94%) rename src/main/java/edu/rpi/legup/puzzle/sudoku/rules/{PossibleCellCaseRule.java => PossibleNumbersForCellCaseRule.java} (90%) diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/PossibleNumberCaseBoard.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/PossibleNumberCaseBoard.java index 8af2aca2e..871b5392b 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/PossibleNumberCaseBoard.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/PossibleNumberCaseBoard.java @@ -2,7 +2,7 @@ import edu.rpi.legup.model.gameboard.CaseBoard; import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.puzzle.sudoku.rules.PossibleNumberCaseRule; +import edu.rpi.legup.puzzle.sudoku.rules.PossibleCellsForNumberCaseRule; import java.awt.event.MouseEvent; import java.util.HashSet; @@ -16,7 +16,7 @@ public class PossibleNumberCaseBoard extends CaseBoard { private Set pickableCols; - public PossibleNumberCaseBoard(SudokuBoard baseBoard, PossibleNumberCaseRule caseRule, SudokuCell cell) { + public PossibleNumberCaseBoard(SudokuBoard baseBoard, PossibleCellsForNumberCaseRule caseRule, SudokuCell cell) { super(baseBoard, caseRule); this.cell = cell; this.pickableRegions = new HashSet<>(); diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoSolutionContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberContradictionRule.java similarity index 91% rename from src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoSolutionContradictionRule.java rename to src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberContradictionRule.java index fb87764fe..a308e1dfc 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoSolutionContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberContradictionRule.java @@ -9,10 +9,10 @@ import java.util.HashSet; import java.util.Set; -public class NoSolutionContradictionRule extends ContradictionRule { +public class NoCellForNumberContradictionRule extends ContradictionRule { - public NoSolutionContradictionRule() { - super("SUDO-CONT-0001", "No Solution for Cell", + public NoCellForNumberContradictionRule() { + super("SUDO-CONT-0001", "No Cell for Number", "Process of elimination yields no valid numbers for an empty cell.", "edu/rpi/legup/images/sudoku/NoSolution.png"); } diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleNumberCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberCaseRule.java similarity index 94% rename from src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleNumberCaseRule.java rename to src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberCaseRule.java index 27d6b58b7..9fc047ff4 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleNumberCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberCaseRule.java @@ -14,12 +14,12 @@ import java.util.List; import java.util.Set; -public class PossibleNumberCaseRule extends CaseRule { +public class PossibleCellsForNumberCaseRule extends CaseRule { - public PossibleNumberCaseRule() { - super("SUDO-CASE-0002", "Possible Numbers for Cell", + public PossibleCellsForNumberCaseRule() { + super("SUDO-CASE-0002", "Possible Cells for Number", "An empty cell has a limited set of possible numbers that can fill it.", - "edu/rpi/legup/images/sudoku/PossibleValues.png"); + "edu/rpi/legup/images/sudoku/possible_cells_number.png"); } /** diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleNumbersForCellCaseRule.java similarity index 90% rename from src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellCaseRule.java rename to src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleNumbersForCellCaseRule.java index 373b60457..7f00eff55 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleNumbersForCellCaseRule.java @@ -12,11 +12,11 @@ import java.util.HashSet; import java.util.Set; -public class PossibleCellCaseRule extends CaseRule { - public PossibleCellCaseRule() { - super("SUDO-CASE-0001", "Possible Cells for Number", +public class PossibleNumbersForCellCaseRule extends CaseRule { + public PossibleNumbersForCellCaseRule() { + super("SUDO-CASE-0001", "Possible Numbers for Cell", "A number has a limited set of cells in which it can be placed.", - "edu/rpi/legup/images/sudoku/possible_cells_number.png"); + "edu/rpi/legup/images/sudoku/PossibleValues.png"); } /** @@ -82,14 +82,14 @@ public ArrayList getCases(Board board, PuzzleElement puzzleElement) { } int rowNum = cell.getLocation().y; - for (SudokuCell c : sudokuBoard.getRegion(rowNum)) { + for (SudokuCell c : sudokuBoard.getRow(rowNum)) { if (c.getData().equals(c.getData())) { possibleValue.remove(c.getData()); } } int colNum = cell.getLocation().x; - for (SudokuCell c : sudokuBoard.getRegion(colNum)) { + for (SudokuCell c : sudokuBoard.getCol(colNum)) { if (c.getData().equals(c.getData())) { possibleValue.remove(c.getData()); } From 9d026f4379d6b776bd1a8e26d27602bcfb8e5344 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Sat, 17 Feb 2024 14:20:14 -0500 Subject: [PATCH 014/258] Made slight progress when trying to output puzzle, first edition of Three Adjacent Ones and Zeros Contradiction rules --- bin/main/edu/rpi/legup/legup/config | 8 +-- .../6x6 easy/{876868768.xml => 876868768} | 0 .../edu/rpi/legup/puzzle/binary/Binary.java | 32 ++++++++---- .../ThreeAdjacentOnesContradictionRule.java | 50 +++++++++++++++++++ .../ThreeAdjacentZerosContradictionRule.java | 50 +++++++++++++++++++ .../rules/ThreeInARowContradictionRule.java | 26 ---------- 6 files changed, 127 insertions(+), 39 deletions(-) rename puzzles files/binary/6x6 easy/{876868768.xml => 876868768} (100%) create mode 100644 src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentOnesContradictionRule.java create mode 100644 src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentZerosContradictionRule.java delete mode 100644 src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeInARowContradictionRule.java diff --git a/bin/main/edu/rpi/legup/legup/config b/bin/main/edu/rpi/legup/legup/config index b30cb8525..7dc58cdda 100644 --- a/bin/main/edu/rpi/legup/legup/config +++ b/bin/main/edu/rpi/legup/legup/config @@ -4,6 +4,10 @@ qualifiedClassName="edu.rpi.legup.puzzle.battleship.Battleship" fileType=".xml" fileCreationDisabled="true"/> + - diff --git a/puzzles files/binary/6x6 easy/876868768.xml b/puzzles files/binary/6x6 easy/876868768 similarity index 100% rename from puzzles files/binary/6x6 easy/876868768.xml rename to puzzles files/binary/6x6 easy/876868768 diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/Binary.java b/src/main/java/edu/rpi/legup/puzzle/binary/Binary.java index 7a48ee190..6730b2806 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/Binary.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/Binary.java @@ -10,12 +10,16 @@ public Binary() { super(); this.name = "Binary"; + this.importer = new BinaryImporter(this); this.exporter = new BinaryExporter(this); this.factory = new BinaryCellFactory(); } + /** + * Initializes the game board. Called by the invoker of the class + */ @Override public void initializeView() { boardView = new BinaryView((BinaryBoard) currentBoard); @@ -23,12 +27,30 @@ public void initializeView() { addBoardListener(boardView); } + /** + * Generates a random edu.rpi.legup.puzzle based on the difficulty + * + * @param difficulty level of difficulty (1-10) + * @return board of the random edu.rpi.legup.puzzle + */ @Override public Board generatePuzzle(int difficulty) { return null; } - @Override +// /** +// * Determines if the given dimensions are valid for Binary +// * +// * @param rows the number of rows +// * @param columns the number of columns +// * @return true if the given dimensions are valid for Binary, false otherwise +// */ +// @Override +// public boolean isValidDimensions(int rows, int columns){ +// return rows >= 2 && rows % 2 == 0 && columns >= 2 && columns % 2 == 0; +// } + + @Override public boolean isBoardComplete(Board board) { BinaryBoard binaryBoard = (BinaryBoard) board; @@ -49,12 +71,4 @@ public boolean isBoardComplete(Board board) { @Override public void onBoardChange(Board board) { } - - - @Override - public boolean isValidDimensions(int rows, int columns){ - return rows >= 2 && rows % 2 == 0 && columns >= 2 && columns % 2 == 0; - } - - } \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentOnesContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentOnesContradictionRule.java new file mode 100644 index 000000000..bc2d83ccd --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentOnesContradictionRule.java @@ -0,0 +1,50 @@ +package edu.rpi.legup.puzzle.binary.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.binary.BinaryBoard; +import edu.rpi.legup.puzzle.binary.BinaryCell; +import edu.rpi.legup.puzzle.binary.BinaryType; +import java.util.Set; +public class ThreeAdjacentOnesContradictionRule 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 one"; + + public ThreeAdjacentOnesContradictionRule() { + super("BINA-CONT-0002", + "Three Adjacent Ones", + "There must not be three adjacent ones in a row or column", + "currentlynoimage.png"); + } + + @Override + public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { + BinaryBoard binaryBoard = (BinaryBoard) board; + + BinaryCell cell = (BinaryCell) binaryBoard.getPuzzleElement(puzzleElement); + if (cell.getType() != BinaryType.ONE) + { + return super.getInvalidUseOfRuleMessage() + ": " + this.INVALID_USE_MESSAGE; + } + + BinaryCell upTwo = binaryBoard.getCell(cell.getLocation().x, cell.getLocation().y+2); + BinaryCell upOne = binaryBoard.getCell(cell.getLocation().x, cell.getLocation().y+1); + BinaryCell leftTwo = binaryBoard.getCell(cell.getLocation().x-2, cell.getLocation().y); + BinaryCell leftOne = binaryBoard.getCell(cell.getLocation().x-1, cell.getLocation().y); + BinaryCell rightTwo = binaryBoard.getCell(cell.getLocation().x+2, cell.getLocation().y); + BinaryCell rightOne = binaryBoard.getCell(cell.getLocation().x+1, cell.getLocation().y); + BinaryCell downTwo = binaryBoard.getCell(cell.getLocation().x, cell.getLocation().y-2); + BinaryCell downOne = binaryBoard.getCell(cell.getLocation().x, cell.getLocation().y-1); + + if ((upTwo.getType() == BinaryType.ONE && upOne.getType() == BinaryType.ONE) || + (leftTwo.getType() == BinaryType.ONE && leftOne.getType() == BinaryType.ONE) || + (rightTwo.getType() == BinaryType.ONE && rightOne.getType() == BinaryType.ONE) || + (downTwo.getType() == BinaryType.ONE && downOne.getType() == BinaryType.ONE) || + (leftOne.getType() == BinaryType.ONE && rightOne.getType() == BinaryType.ONE) || + (upOne.getType() == BinaryType.ONE && downOne.getType() == BinaryType.ONE)) + { + return null; + } + return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentZerosContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentZerosContradictionRule.java new file mode 100644 index 000000000..6357fcd62 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentZerosContradictionRule.java @@ -0,0 +1,50 @@ +package edu.rpi.legup.puzzle.binary.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.binary.BinaryBoard; +import edu.rpi.legup.puzzle.binary.BinaryCell; +import edu.rpi.legup.puzzle.binary.BinaryType; +import java.util.Set; +public class ThreeAdjacentZerosContradictionRule 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 zero"; + + public ThreeAdjacentZerosContradictionRule() { + super("BINA-CONT-0001", + "Three Adjacent Zeros", + "There must not be three adjacent zeros in a row or column", + "currentlynoimage.png"); + } + + @Override + public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { + BinaryBoard binaryBoard = (BinaryBoard) board; + + BinaryCell cell = (BinaryCell) binaryBoard.getPuzzleElement(puzzleElement); + if (cell.getType() != BinaryType.ZERO) + { + return super.getInvalidUseOfRuleMessage() + ": " + this.INVALID_USE_MESSAGE; + } + + BinaryCell upTwo = binaryBoard.getCell(cell.getLocation().x, cell.getLocation().y+2); + BinaryCell upOne = binaryBoard.getCell(cell.getLocation().x, cell.getLocation().y+1); + BinaryCell leftTwo = binaryBoard.getCell(cell.getLocation().x-2, cell.getLocation().y); + BinaryCell leftOne = binaryBoard.getCell(cell.getLocation().x-1, cell.getLocation().y); + BinaryCell rightTwo = binaryBoard.getCell(cell.getLocation().x+2, cell.getLocation().y); + BinaryCell rightOne = binaryBoard.getCell(cell.getLocation().x+1, cell.getLocation().y); + BinaryCell downTwo = binaryBoard.getCell(cell.getLocation().x, cell.getLocation().y-2); + BinaryCell downOne = binaryBoard.getCell(cell.getLocation().x, cell.getLocation().y-1); + + if ((upTwo.getType() == BinaryType.ZERO && upOne.getType() == BinaryType.ZERO) || + (leftTwo.getType() == BinaryType.ZERO && leftOne.getType() == BinaryType.ZERO) || + (rightTwo.getType() == BinaryType.ZERO && rightOne.getType() == BinaryType.ZERO) || + (downTwo.getType() == BinaryType.ZERO && downOne.getType() == BinaryType.ZERO) || + (leftOne.getType() == BinaryType.ZERO && rightOne.getType() == BinaryType.ZERO) || + (upOne.getType() == BinaryType.ZERO && downOne.getType() == BinaryType.ZERO)) + { + return null; + } + return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeInARowContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeInARowContradictionRule.java deleted file mode 100644 index 201ba00f5..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeInARowContradictionRule.java +++ /dev/null @@ -1,26 +0,0 @@ -package edu.rpi.legup.puzzle.binary.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.binary.BinaryBoard; -import edu.rpi.legup.puzzle.binary.BinaryCell; -import edu.rpi.legup.puzzle.binary.BinaryType; - -public class ThreeInARowContradictionRule extends ContradictionRule { - - private final String NO_CONTRADICTION_MESSAGE = ""; - private final String INVALID_USE_MESSAGE = "Does not contain a contradiction at this index"; - - public ThreeInARowContradictionRule() { - super("BINA-CONT-0001", - "Three In A Row", - "Three of the same value cannot exist in a row", - "FILL IN WITH IMAGE"); - } - - @Override - public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { - return null; - } -} \ No newline at end of file From 6515bc3f410fcbcaaceaa76f2ca722ef2bb98d59 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Sat, 17 Feb 2024 14:26:54 -0500 Subject: [PATCH 015/258] Fixed checkstyle error for if statements --- .../binary/rules/ThreeAdjacentOnesContradictionRule.java | 6 ++---- .../binary/rules/ThreeAdjacentZerosContradictionRule.java | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentOnesContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentOnesContradictionRule.java index bc2d83ccd..3b24e1ac0 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentOnesContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentOnesContradictionRule.java @@ -22,8 +22,7 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { BinaryBoard binaryBoard = (BinaryBoard) board; BinaryCell cell = (BinaryCell) binaryBoard.getPuzzleElement(puzzleElement); - if (cell.getType() != BinaryType.ONE) - { + if (cell.getType() != BinaryType.ONE) { return super.getInvalidUseOfRuleMessage() + ": " + this.INVALID_USE_MESSAGE; } @@ -41,8 +40,7 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { (rightTwo.getType() == BinaryType.ONE && rightOne.getType() == BinaryType.ONE) || (downTwo.getType() == BinaryType.ONE && downOne.getType() == BinaryType.ONE) || (leftOne.getType() == BinaryType.ONE && rightOne.getType() == BinaryType.ONE) || - (upOne.getType() == BinaryType.ONE && downOne.getType() == BinaryType.ONE)) - { + (upOne.getType() == BinaryType.ONE && downOne.getType() == BinaryType.ONE)) { return null; } return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE; diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentZerosContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentZerosContradictionRule.java index 6357fcd62..285c9dae6 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentZerosContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentZerosContradictionRule.java @@ -22,8 +22,7 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { BinaryBoard binaryBoard = (BinaryBoard) board; BinaryCell cell = (BinaryCell) binaryBoard.getPuzzleElement(puzzleElement); - if (cell.getType() != BinaryType.ZERO) - { + if (cell.getType() != BinaryType.ZERO) { return super.getInvalidUseOfRuleMessage() + ": " + this.INVALID_USE_MESSAGE; } @@ -41,8 +40,7 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { (rightTwo.getType() == BinaryType.ZERO && rightOne.getType() == BinaryType.ZERO) || (downTwo.getType() == BinaryType.ZERO && downOne.getType() == BinaryType.ZERO) || (leftOne.getType() == BinaryType.ZERO && rightOne.getType() == BinaryType.ZERO) || - (upOne.getType() == BinaryType.ZERO && downOne.getType() == BinaryType.ZERO)) - { + (upOne.getType() == BinaryType.ZERO && downOne.getType() == BinaryType.ZERO)) { return null; } return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE; From 0346d374423d04cb3979192a9baf24758e7708b5 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Sun, 18 Feb 2024 13:38:26 -0500 Subject: [PATCH 016/258] Added functions to BinaryBoard that returns the rows and columns of a specified index. --- .../rpi/legup/puzzle/binary/BinaryBoard.java | 24 ++++++++++++++++--- .../ThreeAdjacentOnesContradictionRule.java | 1 - .../ThreeAdjacentZerosContradictionRule.java | 1 - 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java index 7707aa068..59a588e29 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java @@ -3,17 +3,35 @@ import edu.rpi.legup.model.gameboard.GridBoard; import edu.rpi.legup.model.gameboard.PuzzleElement; +import java.awt.*; +import java.util.HashSet; +import java.util.Set; public class BinaryBoard extends GridBoard { - public BinaryBoard(int width, int height) { - super(width, height); - } + private int size; public BinaryBoard(int size) { super(size, size); + this.size = size; } @Override public BinaryCell getCell(int x, int y) { return (BinaryCell) super.getCell(x, y); } + + public Set getRow(int rowNum) { + Set row = new HashSet<>(); + for (int i = 0; i < size; i++) { + row.add(getCell(i, rowNum)); + } + return row; + } + + public Set getCol(int colNum) { + Set col = new HashSet<>(); + for (int i = 0; i < size; i ++) { + col.add(getCell(colNum, i)); + } + return col; + } } \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentOnesContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentOnesContradictionRule.java index 3b24e1ac0..318495472 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentOnesContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentOnesContradictionRule.java @@ -5,7 +5,6 @@ import edu.rpi.legup.puzzle.binary.BinaryBoard; import edu.rpi.legup.puzzle.binary.BinaryCell; import edu.rpi.legup.puzzle.binary.BinaryType; -import java.util.Set; public class ThreeAdjacentOnesContradictionRule 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 one"; diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentZerosContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentZerosContradictionRule.java index 285c9dae6..04d8181de 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentZerosContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentZerosContradictionRule.java @@ -5,7 +5,6 @@ import edu.rpi.legup.puzzle.binary.BinaryBoard; import edu.rpi.legup.puzzle.binary.BinaryCell; import edu.rpi.legup.puzzle.binary.BinaryType; -import java.util.Set; public class ThreeAdjacentZerosContradictionRule 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 zero"; From aaa23c01de99dbb6161aa47ddd82b35668349660 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Sun, 18 Feb 2024 13:45:53 -0500 Subject: [PATCH 017/258] Fixed error that causes BinaryImporter to fail to initialize board --- src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java index 59a588e29..f24667d37 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java @@ -8,6 +8,10 @@ import java.util.Set; public class BinaryBoard extends GridBoard { private int size; + public BinaryBoard(int width, int height) { + super(width, height); + this.size = width; + } public BinaryBoard(int size) { super(size, size); @@ -34,4 +38,4 @@ public Set getCol(int colNum) { } return col; } -} \ No newline at end of file +} From a532c1ce5703c1788d0bfbc932b049977aeebcd9 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Sun, 18 Feb 2024 14:00:34 -0500 Subject: [PATCH 018/258] First edition of Unbalanced Row and Unbalanced Column Contradiction rules --- .../UnbalancedColumnContradictionRule.java | 50 +++++++++++++++++++ .../UnbalancedRowColumnContradictionRule.java | 26 ---------- .../rules/UnbalancedRowContradictionRule.java | 50 +++++++++++++++++++ 3 files changed, 100 insertions(+), 26 deletions(-) create mode 100644 src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedColumnContradictionRule.java delete mode 100644 src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowColumnContradictionRule.java create mode 100644 src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowContradictionRule.java diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedColumnContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedColumnContradictionRule.java new file mode 100644 index 000000000..96a56c4cc --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedColumnContradictionRule.java @@ -0,0 +1,50 @@ +package edu.rpi.legup.puzzle.binary.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.binary.BinaryBoard; +import edu.rpi.legup.puzzle.binary.BinaryCell; +import edu.rpi.legup.puzzle.binary.BinaryType; + +import java.util.Set; +public class UnbalancedColumnContradictionRule extends ContradictionRule { + + private final String NO_CONTRADICTION_MESSAGE = "Does not contain a contradiction at this index"; + private final String INVALID_USE_MESSAGE = "Column must have a value in each cell"; + + public UnbalancedColumnContradictionRule() { + super("BINA-CONT-0004", + "Unbalanced Column", + "Each column must contain an equal number of zeros and ones ", + "currentlynoimage.png"); + } + + @Override + public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { + BinaryBoard binaryBoard = (BinaryBoard) board; + + BinaryCell cell = (BinaryCell) binaryBoard.getPuzzleElement(puzzleElement); + Set col = binaryBoard.getCol(cell.getLocation().x); + + int size = col.size(); + int numZeros = 0; + int numOnes = 0; + + for (BinaryCell item : col) { + if (item.getType() == BinaryType.ZERO) { + numZeros++; + } + else if(item.getType() == BinaryType.ONE) { + numOnes++; + } + } + if (numZeros + numOnes != size) { + return super.getInvalidUseOfRuleMessage() + ": " + this.INVALID_USE_MESSAGE; + } + if (numZeros != numOnes) { + return null; + } + return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE; + } +} \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowColumnContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowColumnContradictionRule.java deleted file mode 100644 index 1bfe72ecb..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowColumnContradictionRule.java +++ /dev/null @@ -1,26 +0,0 @@ -package edu.rpi.legup.puzzle.binary.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.binary.BinaryBoard; -import edu.rpi.legup.puzzle.binary.BinaryCell; -import edu.rpi.legup.puzzle.binary.BinaryType; - -public class UnbalancedRowColumnContradictionRule extends ContradictionRule { - - private final String NO_CONTRADICTION_MESSAGE = ""; - private final String INVALID_USE_MESSAGE = "Does not contain a contradiction at this index"; - - public UnbalancedRowColumnContradictionRule() { - super("BINA-CONT-0002", - "Unbalanced Row Column", - "A row or column cannot contain more of more value than the other", - "FILL IN WITH IMAGE"); - } - - @Override - public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { - return null; - } -} \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowContradictionRule.java new file mode 100644 index 000000000..a9c3346b0 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowContradictionRule.java @@ -0,0 +1,50 @@ +package edu.rpi.legup.puzzle.binary.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.binary.BinaryBoard; +import edu.rpi.legup.puzzle.binary.BinaryCell; +import edu.rpi.legup.puzzle.binary.BinaryType; + +import java.util.Set; +public class UnbalancedRowContradictionRule extends ContradictionRule { + + private final String NO_CONTRADICTION_MESSAGE = "Does not contain a contradiction at this index"; + private final String INVALID_USE_MESSAGE = "Row must have a value in each cell"; + + public UnbalancedRowContradictionRule() { + super("BINA-CONT-0003", + "Unbalanced Row", + "Each row must contain an equal number of zeros and ones ", + "currentlynoimage.png"); + } + + @Override + public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { + BinaryBoard binaryBoard = (BinaryBoard) board; + + BinaryCell cell = (BinaryCell) binaryBoard.getPuzzleElement(puzzleElement); + Set row = binaryBoard.getRow(cell.getLocation().y); + + int size = row.size(); + int numZeros = 0; + int numOnes = 0; + + for (BinaryCell item : row) { + if (item.getType() == BinaryType.ZERO) { + numZeros++; + } + else if(item.getType() == BinaryType.ONE) { + numOnes++; + } + } + if (numZeros + numOnes != size) { + return super.getInvalidUseOfRuleMessage() + ": " + this.INVALID_USE_MESSAGE; + } + if (numZeros != numOnes) { + return null; + } + return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE; + } +} \ No newline at end of file From 6a3cc9c752567aa54f35f93772cb0f985caa36f9 Mon Sep 17 00:00:00 2001 From: charlestian23 Date: Fri, 23 Feb 2024 16:47:32 -0500 Subject: [PATCH 019/258] Update config --- src/main/resources/edu/rpi/legup/legup/config | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/resources/edu/rpi/legup/legup/config b/src/main/resources/edu/rpi/legup/legup/config index 19e63a2a3..7dc58cdda 100644 --- a/src/main/resources/edu/rpi/legup/legup/config +++ b/src/main/resources/edu/rpi/legup/legup/config @@ -4,6 +4,10 @@ qualifiedClassName="edu.rpi.legup.puzzle.battleship.Battleship" fileType=".xml" fileCreationDisabled="true"/> + Date: Fri, 23 Feb 2024 17:16:20 -0500 Subject: [PATCH 020/258] Deleted false config file, began rule implementation, began fixing puzzle board visual --- bin/main/edu/rpi/legup/legup/config | 47 ------------------ .../puzzle/binary/BinaryElementView.java | 10 ++-- .../rules/CompleteRowColumnDirectRule.java | 49 ++++++++++++++++++- 3 files changed, 53 insertions(+), 53 deletions(-) delete mode 100644 bin/main/edu/rpi/legup/legup/config diff --git a/bin/main/edu/rpi/legup/legup/config b/bin/main/edu/rpi/legup/legup/config deleted file mode 100644 index 7dc58cdda..000000000 --- a/bin/main/edu/rpi/legup/legup/config +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryElementView.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryElementView.java index ca37de73f..0ce5f3f58 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryElementView.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryElementView.java @@ -45,8 +45,8 @@ public void drawElement(Graphics2D graphics2D) { } else { if (type == BinaryType.ZERO) { - graphics2D.setStroke(new BasicStroke(1)); - graphics2D.setColor(Color.BLACK); + graphics2D.setStroke(new BasicStroke(0)); + graphics2D.setColor(Color.white); graphics2D.fillRect(location.x, location.y, size.width, size.height); } else { @@ -54,15 +54,15 @@ public void drawElement(Graphics2D graphics2D) { graphics2D.setStroke(new BasicStroke(1)); graphics2D.setColor(Color.WHITE); graphics2D.fillRect(location.x, location.y, size.width, size.height); - graphics2D.setColor(Color.BLACK); + graphics2D.setColor(Color.LIGHT_GRAY); graphics2D.drawRect(location.x, location.y, size.width, size.height); } else { if (type == BinaryType.UNKNOWN) { - graphics2D.setStroke(new BasicStroke(1)); + graphics2D.setStroke(new BasicStroke(0)); graphics2D.setColor(Color.LIGHT_GRAY); graphics2D.fillRect(location.x, location.y, size.width, size.height); - graphics2D.setColor(Color.BLACK); + graphics2D.setColor(Color.WHITE); graphics2D.drawRect(location.x, location.y, size.width, size.height); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java index 1a35902f3..7641e08cf 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java @@ -10,6 +10,10 @@ import edu.rpi.legup.puzzle.binary.BinaryCell; import edu.rpi.legup.puzzle.binary.BinaryType; +import java.util.Set; +import java.util.HashSet; + + public class CompleteRowColumnDirectRule extends DirectRule { public CompleteRowColumnDirectRule() { @@ -18,9 +22,52 @@ public CompleteRowColumnDirectRule() { "If a row/column of length n contains n/2 of a single value, the remaining cells must contain the other value", "FILL IN WITH IMAGE"); } - + /** + * 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) { + BinaryBoard initialBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); + BinaryBoard finalBoard = (BinaryBoard) transition.getBoard(); + int elementIndex = puzzleElement.getIndex(); + int boardDim = initialBoard.getWidth(); + int elementRow = elementIndex / boardDim; + int elementCol = elementIndex % boardDim; + Set curRow = initialBoard.getRow(elementRow); + Set curCol = initialBoard.getCol(elementCol); + + int numColZeros = 0; + int numColOnes = 0; + + for (int i = 0; i < boardDim; i++) { + BinaryCell cell = initialBoard.getCell(i, elementCol); + if(cell.getData() == 1) + numColOnes ++; + else if(cell.getData() == 0) + numColZeros ++; + } + int numRowZeros = 0; + int numRowOnes = 0; + + for (int i = 0; i < boardDim; i++) { + BinaryCell cell = initialBoard.getCell(elementRow, i); + if(cell.getData() == 1) + numRowOnes ++; + else if(cell.getData() == 0) + numRowZeros ++; + } + if (numColOnes + numColZeros != boardDim) { + return super.getInvalidUseOfRuleMessage() + ": The column for the specificed element is not complete"; + } + if (numRowOnes + numRowZeros != boardDim) { + return super.getInvalidUseOfRuleMessage() + ": The row for the specified element is not complete"; + } return null; } From 9ec7cd17281fd342ccbfaedc632fb5c1be4cee75 Mon Sep 17 00:00:00 2001 From: Brandon McCusker Date: Fri, 23 Feb 2024 17:22:01 -0500 Subject: [PATCH 021/258] Fixed stylecheck errors --- .../binary/rules/CompleteRowColumnDirectRule.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java index 7641e08cf..33a7dcb58 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java @@ -47,20 +47,24 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem for (int i = 0; i < boardDim; i++) { BinaryCell cell = initialBoard.getCell(i, elementCol); - if(cell.getData() == 1) + if(cell.getData() == 1){ numColOnes ++; - else if(cell.getData() == 0) + } + else if(cell.getData() == 0){ numColZeros ++; + } } int numRowZeros = 0; int numRowOnes = 0; for (int i = 0; i < boardDim; i++) { BinaryCell cell = initialBoard.getCell(elementRow, i); - if(cell.getData() == 1) + if(cell.getData() == 1){ numRowOnes ++; - else if(cell.getData() == 0) + } + else if(cell.getData() == 0){ numRowZeros ++; + } } if (numColOnes + numColZeros != boardDim) { return super.getInvalidUseOfRuleMessage() + ": The column for the specificed element is not complete"; From 473d2eb24b21402a21411270208e37524c3710d8 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Sun, 25 Feb 2024 16:31:27 -0500 Subject: [PATCH 022/258] First edition of Duplicate Rows and Duplicate Columns Contradiction rules --- .../DuplicateColumnsContradictionRule.java | 49 +++++++++++++++++++ .../rules/DuplicateRowsContradictionRule.java | 49 +++++++++++++++++++ .../UnbalancedColumnContradictionRule.java | 2 +- .../rules/UnbalancedRowContradictionRule.java | 2 +- 4 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateColumnsContradictionRule.java create mode 100644 src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsContradictionRule.java diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateColumnsContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateColumnsContradictionRule.java new file mode 100644 index 000000000..bc38352d0 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateColumnsContradictionRule.java @@ -0,0 +1,49 @@ +package edu.rpi.legup.puzzle.binary.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.binary.BinaryBoard; +import edu.rpi.legup.puzzle.binary.BinaryCell; +import edu.rpi.legup.puzzle.binary.BinaryType; + +import java.util.Set; +public class DuplicateColumnsContradictionRule extends ContradictionRule { + private final String NO_CONTRADICTION_MESSAGE = "Does not contain a contradiction at this index"; + private final String INVALID_USE_MESSAGE = "Column must have a value in each cell"; + + public DuplicateColumnsContradictionRule() { + super("BINA-CONT-0006", + "Duplicate Columns", + "There must not be two columns that are duplicates", + "currentlynoimage.png"); + } + + @Override + public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { + BinaryBoard binaryBoard = (BinaryBoard) board; + + BinaryCell cell = (BinaryCell) binaryBoard.getPuzzleElement(puzzleElement); + Set col = binaryBoard.getCol(cell.getLocation().x); + BinaryCell[] colArray = col.toArray(new BinaryCell[0]); + int size = col.size(); + int x = cell.getLocation().x; + for (int i = 0; i < size; i++) { + if (i != x) { + Set currCol = binaryBoard.getCol(i); + BinaryCell[] currColArray = currCol.toArray(new BinaryCell[0]); + for (int j = 0; j < size; j++) { + BinaryCell colElement = colArray[j]; + BinaryCell currColElement = currColArray[j]; + if (colElement.getType() == BinaryType.UNKNOWN || currColElement.getType() == BinaryType.UNKNOWN) { + return super.getInvalidUseOfRuleMessage() + ": " + this.INVALID_USE_MESSAGE; + } + if (colElement.getType() != currColElement.getType()) { + return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE; + } + } + } + } + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsContradictionRule.java new file mode 100644 index 000000000..5a2d09177 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsContradictionRule.java @@ -0,0 +1,49 @@ +package edu.rpi.legup.puzzle.binary.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.binary.BinaryBoard; +import edu.rpi.legup.puzzle.binary.BinaryCell; +import edu.rpi.legup.puzzle.binary.BinaryType; + +import java.util.Set; +public class DuplicateRowsContradictionRule extends ContradictionRule { + private final String NO_CONTRADICTION_MESSAGE = "Does not contain a contradiction at this index"; + private final String INVALID_USE_MESSAGE = "Row must have a value in each cell"; + + public DuplicateRowsContradictionRule() { + super("BINA-CONT-0005", + "Duplicate Rows", + "There must not be two rows that are duplicates", + "currentlynoimage.png"); + } + + @Override + public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { + BinaryBoard binaryBoard = (BinaryBoard) board; + + BinaryCell cell = (BinaryCell) binaryBoard.getPuzzleElement(puzzleElement); + Set row = binaryBoard.getRow(cell.getLocation().y); + BinaryCell[] rowArray = row.toArray(new BinaryCell[0]); + int size = row.size(); + int y = cell.getLocation().y; + for (int i = 0; i < size; i++) { + if (i != y) { + Set currRow = binaryBoard.getRow(i); + BinaryCell[] currRowArray = currRow.toArray(new BinaryCell[0]); + for (int j = 0; j < size; j++) { + BinaryCell rowElement = rowArray[j]; + BinaryCell currRowElement = currRowArray[j]; + if (rowElement.getType() == BinaryType.UNKNOWN || currRowElement.getType() == BinaryType.UNKNOWN) { + return super.getInvalidUseOfRuleMessage() + ": " + this.INVALID_USE_MESSAGE; + } + if (rowElement.getType() != currRowElement.getType()) { + return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE; + } + } + } + } + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedColumnContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedColumnContradictionRule.java index 96a56c4cc..1867a895c 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedColumnContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedColumnContradictionRule.java @@ -16,7 +16,7 @@ public class UnbalancedColumnContradictionRule extends ContradictionRule { public UnbalancedColumnContradictionRule() { super("BINA-CONT-0004", "Unbalanced Column", - "Each column must contain an equal number of zeros and ones ", + "Each column must contain an equal number of zeros and ones", "currentlynoimage.png"); } diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowContradictionRule.java index a9c3346b0..40dd439d7 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowContradictionRule.java @@ -16,7 +16,7 @@ public class UnbalancedRowContradictionRule extends ContradictionRule { public UnbalancedRowContradictionRule() { super("BINA-CONT-0003", "Unbalanced Row", - "Each row must contain an equal number of zeros and ones ", + "Each row must contain an equal number of zeros and ones", "currentlynoimage.png"); } From c53b197faa696801dc1217629128503fa02ea39a Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Sun, 25 Feb 2024 17:13:45 -0500 Subject: [PATCH 023/258] First edition of One Tile Gap Direct rule --- .../binary/rules/OneTileGapDirectRule.java | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java index 704098e56..cda84b0ad 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java @@ -11,17 +11,33 @@ import edu.rpi.legup.puzzle.binary.BinaryType; public class OneTileGapDirectRule extends DirectRule { - + private final String INVALID_USE_MESSAGE = "Number at cell is incorrect"; public OneTileGapDirectRule() { super("BINA-BASC-0002", "One Tile Gap", - "If an empty tile is surrounded by the same value, fill the gap with the other value.", + "If an empty tile is in between the same value, fill the gap with the other value.", "FILL IN WITH IMAGE"); } @Override public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - return null; + BinaryBoard iniitalBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); + BinaryBoard finalBoard = (BinaryBoard) transition.getBoard(); + int boardDim = iniitalBoard.getWidth(); + BinaryCell cell = (BinaryCell) finalBoard.getPuzzleElement(puzzleElement); + + BinaryCell upOne = finalBoard.getCell(cell.getLocation().x, cell.getLocation().y+1); + BinaryCell downOne = finalBoard.getCell(cell.getLocation().x, cell.getLocation().y-1); + BinaryCell leftOne = finalBoard.getCell(cell.getLocation().x-1, cell.getLocation().y); + BinaryCell rightOne = finalBoard.getCell(cell.getLocation().x+1, cell.getLocation().y); + + if ((upOne.getType() == BinaryType.ONE && downOne.getType() == BinaryType.ONE && cell.getType() == BinaryType.ONE) || + (upOne.getType() == BinaryType.ZERO && downOne.getType() == BinaryType.ZERO && cell.getType() == BinaryType.ZERO) || + (leftOne.getType() == BinaryType.ONE && rightOne.getType() == BinaryType.ONE && cell.getType() == BinaryType.ONE) || + (leftOne.getType() == BinaryType.ZERO && downOne.getType() == BinaryType.ZERO && cell.getType() == BinaryType.ZERO)) { + return null; + } + return super.getInvalidUseOfRuleMessage() + ": " + this.INVALID_USE_MESSAGE; } @Override From 63e858c714de6d55242b1aff82c40aa52b014112 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Sun, 25 Feb 2024 17:21:33 -0500 Subject: [PATCH 024/258] Second edition of One Tile Gap Direct rule, typo in if statement --- .../legup/puzzle/binary/rules/OneTileGapDirectRule.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java index cda84b0ad..5f4e6d95d 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java @@ -31,10 +31,10 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem BinaryCell leftOne = finalBoard.getCell(cell.getLocation().x-1, cell.getLocation().y); BinaryCell rightOne = finalBoard.getCell(cell.getLocation().x+1, cell.getLocation().y); - if ((upOne.getType() == BinaryType.ONE && downOne.getType() == BinaryType.ONE && cell.getType() == BinaryType.ONE) || - (upOne.getType() == BinaryType.ZERO && downOne.getType() == BinaryType.ZERO && cell.getType() == BinaryType.ZERO) || - (leftOne.getType() == BinaryType.ONE && rightOne.getType() == BinaryType.ONE && cell.getType() == BinaryType.ONE) || - (leftOne.getType() == BinaryType.ZERO && downOne.getType() == BinaryType.ZERO && cell.getType() == BinaryType.ZERO)) { + if ((upOne.getType() == BinaryType.ONE && downOne.getType() == BinaryType.ONE && cell.getType() != BinaryType.ONE) || + (upOne.getType() == BinaryType.ZERO && downOne.getType() == BinaryType.ZERO && cell.getType() != BinaryType.ZERO) || + (leftOne.getType() == BinaryType.ONE && rightOne.getType() == BinaryType.ONE && cell.getType() != BinaryType.ONE) || + (leftOne.getType() == BinaryType.ZERO && downOne.getType() == BinaryType.ZERO && cell.getType() != BinaryType.ZERO)) { return null; } return super.getInvalidUseOfRuleMessage() + ": " + this.INVALID_USE_MESSAGE; From 104f4464bdca0616d0b829966deea48705f20163 Mon Sep 17 00:00:00 2001 From: kchiu1 <152306707+kchiu1@users.noreply.github.com> Date: Tue, 27 Feb 2024 16:16:42 -0500 Subject: [PATCH 025/258] Refactoring Possible Numbers for Cell Trying again since there was a merge issue last time. --- .../rules/PossibleNumbersForCellCaseRule.java | 59 ++++++++----------- 1 file changed, 24 insertions(+), 35 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleNumbersForCellCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleNumbersForCellCaseRule.java index 7f00eff55..72a5f5bfe 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleNumbersForCellCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleNumbersForCellCaseRule.java @@ -5,17 +5,20 @@ 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.sudoku.GroupType; +import edu.rpi.legup.puzzle.sudoku.PossibleNumberCaseBoard; import edu.rpi.legup.puzzle.sudoku.SudokuBoard; import edu.rpi.legup.puzzle.sudoku.SudokuCell; import java.util.ArrayList; -import java.util.HashSet; +import java.util.List; import java.util.Set; public class PossibleNumbersForCellCaseRule extends CaseRule { + public PossibleNumbersForCellCaseRule() { super("SUDO-CASE-0001", "Possible Numbers for Cell", - "A number has a limited set of cells in which it can be placed.", + "An empty cell has a limited set of possible numbers that can fill it.", "edu/rpi/legup/images/sudoku/PossibleValues.png"); } @@ -55,7 +58,6 @@ public CaseBoard getCaseBoard(Board board) { } return caseBoard; } - /** * Gets the possible cases at a specific location based on this case rule * @@ -65,42 +67,29 @@ public CaseBoard getCaseBoard(Board board) { */ @Override public ArrayList getCases(Board board, PuzzleElement puzzleElement) { + return getCases(board, puzzleElement, 1, GroupType.REGION); + } + + /** + * Gets the possible cases at a specific location based on this case rule + * + * @param board the current board state + * @param puzzleElement equivalent puzzleElement + * @param value value that the rule will be applied from + * @param groupType group type + * @return a list of elements the specified could be + */ + public ArrayList getCases(Board board, PuzzleElement puzzleElement, int value, GroupType groupType) { ArrayList cases = new ArrayList<>(); SudokuBoard sudokuBoard = (SudokuBoard) board; + List caseCells = new ArrayList<>(); SudokuCell cell = (SudokuCell) puzzleElement; - Set possibleValue = new HashSet<>(); - for (int i = 1; i <= sudokuBoard.getSize(); i++) { - possibleValue.add(i); - } - - int groupNum = cell.getGroupIndex(); - for (SudokuCell c : sudokuBoard.getRegion(groupNum)) { - if (c.getData().equals(c.getData())) { - possibleValue.remove(c.getData()); - } - } - - int rowNum = cell.getLocation().y; - for (SudokuCell c : sudokuBoard.getRow(rowNum)) { - if (c.getData().equals(c.getData())) { - possibleValue.remove(c.getData()); - } - } - - int colNum = cell.getLocation().x; - for (SudokuCell c : sudokuBoard.getCol(colNum)) { - if (c.getData().equals(c.getData())) { - possibleValue.remove(c.getData()); - } - } - - for (Integer i : possibleValue) { - SudokuBoard newCase = sudokuBoard.copy(); - - PuzzleElement newCasePuzzleElement = newCase.getPuzzleElement(puzzleElement); - newCasePuzzleElement.setData(i); - newCase.addModifiedData(newCasePuzzleElement); + for (int i = 0; i < 9; i++) { + Board newCase = sudokuBoard.copy(); + PuzzleElement element = newCase.getPuzzleElement(puzzleElement); + element.setData(value); + newCase.addModifiedData(element); cases.add(newCase); } From 0ad68f6fa46976ef5719c0ca8bf9913b8818b1bb Mon Sep 17 00:00:00 2001 From: Brandon McCusker Date: Tue, 27 Feb 2024 17:33:40 -0500 Subject: [PATCH 026/258] Initial Board Rendering correct --- puzzles files/binary/6x6 easy/876868768 | 22 ++++----- .../rpi/legup/puzzle/binary/BinaryCell.java | 13 ++--- .../puzzle/binary/BinaryCellFactory.java | 3 +- .../puzzle/binary/BinaryElementView.java | 47 +++++++++---------- .../rpi/legup/puzzle/binary/BinaryType.java | 4 +- 5 files changed, 44 insertions(+), 45 deletions(-) diff --git a/puzzles files/binary/6x6 easy/876868768 b/puzzles files/binary/6x6 easy/876868768 index ceefaefff..a7ac3d25f 100644 --- a/puzzles files/binary/6x6 easy/876868768 +++ b/puzzles files/binary/6x6 easy/876868768 @@ -3,20 +3,18 @@ - - - - - - - - + + + + + + - - - - + + + + diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java index 65464b372..ebc5a8ab3 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java @@ -10,16 +10,17 @@ public BinaryCell(int valueInt, Point location) { } public BinaryType getType() { + System.out.println(data); switch (data) { - case -2: - return BinaryType.UNKNOWN; - case -1: - return BinaryType.ONE; case 0: return BinaryType.ZERO; + case 1: + return BinaryType.ONE; + case 2: + return BinaryType.UNKNOWN; default: - if (data > 0) { - return BinaryType.NUMBER; + if (data > 1) { + return BinaryType.UNKNOWN; } } return null; diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCellFactory.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCellFactory.java index a2211f35c..37685f9a9 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCellFactory.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCellFactory.java @@ -15,7 +15,7 @@ public class BinaryCellFactory extends ElementFactory { public BinaryCell importCell(Node node, Board board) throws InvalidFileFormatException { try { if (!node.getNodeName().equalsIgnoreCase("cell")) { - throw new InvalidFileFormatException("nurikabe Factory: unknown puzzleElement puzzleElement"); + throw new InvalidFileFormatException("binary Factory: unknown puzzleElement puzzleElement"); } BinaryBoard binaryBoard = (BinaryBoard) board; @@ -53,6 +53,7 @@ public org.w3c.dom.Element exportCell(Document document, PuzzleElement puzzleEle Point loc = cell.getLocation(); cellElement.setAttribute("value", String.valueOf(cell.getData())); + System.out.println(cell.getData()); cellElement.setAttribute("x", String.valueOf(loc.x)); cellElement.setAttribute("y", String.valueOf(loc.y)); diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryElementView.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryElementView.java index 0ce5f3f58..910fc6e8e 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryElementView.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryElementView.java @@ -27,45 +27,44 @@ public BinaryCell getPuzzleElement() { public void drawElement(Graphics2D graphics2D) { BinaryCell cell = (BinaryCell) puzzleElement; BinaryType type = cell.getType(); - if (type == BinaryType.NUMBER) { + if (type == BinaryType.ZERO) { 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); - FontMetrics metrics = graphics2D.getFontMetrics(FONT); - String value = String.valueOf(puzzleElement.getData()); - int xText = location.x + (size.width - metrics.stringWidth(value)) / 2; + graphics2D.setColor(FONT_COLOR); + graphics2D.setFont(FONT); + FontMetrics metrics = graphics2D.getFontMetrics(FONT); + String value = String.valueOf(puzzleElement.getData()); + int xText = location.x + (size.width - metrics.stringWidth(value)) / 2; int yText = location.y + ((size.height - metrics.getHeight()) / 2) + metrics.getAscent(); graphics2D.drawString(String.valueOf(puzzleElement.getData()), xText, yText); } else { - if (type == BinaryType.ZERO) { - graphics2D.setStroke(new BasicStroke(0)); - graphics2D.setColor(Color.white); + if (type == BinaryType.ONE) { + 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); + FontMetrics metrics = graphics2D.getFontMetrics(FONT); + String value = String.valueOf(puzzleElement.getData()); + int xText = location.x + (size.width - metrics.stringWidth(value)) / 2; + int yText = location.y + ((size.height - metrics.getHeight()) / 2) + metrics.getAscent(); + graphics2D.drawString(String.valueOf(puzzleElement.getData()), xText, yText); + } else { - if (type == BinaryType.ONE) { - graphics2D.setStroke(new BasicStroke(1)); - graphics2D.setColor(Color.WHITE); - graphics2D.fillRect(location.x, location.y, size.width, size.height); + if (type == BinaryType.UNKNOWN) { + graphics2D.setStroke(new BasicStroke(0)); 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); } - else { - if (type == BinaryType.UNKNOWN) { - graphics2D.setStroke(new BasicStroke(0)); - graphics2D.setColor(Color.LIGHT_GRAY); - graphics2D.fillRect(location.x, location.y, size.width, size.height); - graphics2D.setColor(Color.WHITE); - graphics2D.drawRect(location.x, location.y, size.width, size.height); - } - } } } } diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryType.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryType.java index 7fa857b30..32792cf1e 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryType.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryType.java @@ -1,9 +1,9 @@ package edu.rpi.legup.puzzle.binary; public enum BinaryType { - UNKNOWN, ZERO, ONE, NUMBER; + ZERO, ONE, UNKNOWN; public int toValue() { - return this.ordinal() - 2; + return this.ordinal(); } } From d5280c438d33228fda65ec928f9f64037d17e587 Mon Sep 17 00:00:00 2001 From: EggyMath <55564321+EggyMath@users.noreply.github.com> Date: Tue, 27 Feb 2024 20:57:16 -0500 Subject: [PATCH 027/258] PossibleCellsForNumber Region Based Implementation Updated PossibleCellsForNumber to display number values when case board is clicked and generate proper case boards based off number chosen and local region. --- .../legup/puzzle/sudoku/ModelSudokuBoard.java | 17 ++++ .../sudoku/PossibleNumberCaseBoard.java | 4 +- ...PossibleCellsForNumberRegionCaseRule.java} | 78 ++++++------------- .../rules/PossibleNumbersForCellCaseRule.java | 5 +- 4 files changed, 44 insertions(+), 60 deletions(-) create mode 100644 src/main/java/edu/rpi/legup/puzzle/sudoku/ModelSudokuBoard.java rename src/main/java/edu/rpi/legup/puzzle/sudoku/rules/{PossibleCellsForNumberCaseRule.java => PossibleCellsForNumberRegionCaseRule.java} (54%) diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/ModelSudokuBoard.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/ModelSudokuBoard.java new file mode 100644 index 000000000..f7893ca32 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/ModelSudokuBoard.java @@ -0,0 +1,17 @@ +package edu.rpi.legup.puzzle.sudoku; + +public class ModelSudokuBoard { + public int getModelRegionNumbers(int index) { + int columnMod = index % 3 + 1; + int rowMod = ((index / 9) % 3) * 3; + return columnMod + rowMod; + } + + public int getModelRowNumbers(int index) { + return index % 9 + 1; + } + + public int getModelColumnNumbers(int index) { + return index / 9 + 1; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/PossibleNumberCaseBoard.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/PossibleNumberCaseBoard.java index 871b5392b..8bf3e26bf 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/PossibleNumberCaseBoard.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/PossibleNumberCaseBoard.java @@ -2,7 +2,7 @@ import edu.rpi.legup.model.gameboard.CaseBoard; import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.puzzle.sudoku.rules.PossibleCellsForNumberCaseRule; +import edu.rpi.legup.puzzle.sudoku.rules.PossibleCellsForNumberRegionCaseRule; import java.awt.event.MouseEvent; import java.util.HashSet; @@ -16,7 +16,7 @@ public class PossibleNumberCaseBoard extends CaseBoard { private Set pickableCols; - public PossibleNumberCaseBoard(SudokuBoard baseBoard, PossibleCellsForNumberCaseRule caseRule, SudokuCell cell) { + public PossibleNumberCaseBoard(SudokuBoard baseBoard, PossibleCellsForNumberRegionCaseRule caseRule, SudokuCell cell) { super(baseBoard, caseRule); this.cell = cell; this.pickableRegions = new HashSet<>(); diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberRegionCaseRule.java similarity index 54% rename from src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberCaseRule.java rename to src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberRegionCaseRule.java index 9fc047ff4..3cdb954b7 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberRegionCaseRule.java @@ -5,18 +5,19 @@ 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.sudoku.GroupType; -import edu.rpi.legup.puzzle.sudoku.PossibleNumberCaseBoard; -import edu.rpi.legup.puzzle.sudoku.SudokuBoard; -import edu.rpi.legup.puzzle.sudoku.SudokuCell; +import edu.rpi.legup.puzzle.sudoku.*; import java.util.ArrayList; -import java.util.List; import java.util.Set; -public class PossibleCellsForNumberCaseRule extends CaseRule { +public class PossibleCellsForNumberRegionCaseRule extends CaseRule { - public PossibleCellsForNumberCaseRule() { + //Board math for translating indexes to numbers + private ModelSudokuBoard model = new ModelSudokuBoard(); + + //Old board for caseBoard reference + private SudokuBoard lagBoard; + public PossibleCellsForNumberRegionCaseRule() { super("SUDO-CASE-0002", "Possible Cells for Number", "An empty cell has a limited set of possible numbers that can fill it.", "edu/rpi/legup/images/sudoku/possible_cells_number.png"); @@ -49,12 +50,12 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem @Override public CaseBoard getCaseBoard(Board board) { - SudokuBoard sudokuBoard = (SudokuBoard) board; - PossibleNumberCaseBoard caseBoard = new PossibleNumberCaseBoard(sudokuBoard, this, null); - for (int i = 0; i < sudokuBoard.getSize(); i++) { - caseBoard.addPickableRegion(i); - caseBoard.addPickableRow(i); - caseBoard.addPickableCol(i); + SudokuBoard sudokuBoard = (SudokuBoard) board.copy(); + lagBoard = (SudokuBoard) sudokuBoard.copy(); + CaseBoard caseBoard = new CaseBoard(sudokuBoard, this); + for (PuzzleElement puzzleElement : sudokuBoard.getPuzzleElements()) { + puzzleElement.setData(model.getModelRegionNumbers(puzzleElement.getIndex())); + caseBoard.addPickableElement(puzzleElement); } return caseBoard; } @@ -82,50 +83,19 @@ public ArrayList getCases(Board board, PuzzleElement puzzleElement) { */ public ArrayList getCases(Board board, PuzzleElement puzzleElement, int value, GroupType groupType) { ArrayList cases = new ArrayList<>(); - SudokuBoard sudokuBoard = (SudokuBoard) board; - List caseCells = new ArrayList<>(); - SudokuCell cell = (SudokuCell) puzzleElement; - - Set group; - if (groupType == GroupType.REGION) { - group = sudokuBoard.getRegion(cell.getGroupIndex()); - } - else { - if (groupType == GroupType.ROW) { - group = sudokuBoard.getRow(cell.getLocation().y); - } - else { - group = sudokuBoard.getCol(cell.getLocation().x); - } - } - - for (SudokuCell c : group) { - if (c.getData() == 0) { - Set blockableCells = sudokuBoard.getRegion(c.getGroupIndex()); - blockableCells.addAll(sudokuBoard.getRow(c.getLocation().y)); - blockableCells.addAll(sudokuBoard.getCol(c.getLocation().x)); + SudokuBoard sudokuBoard = lagBoard; + SudokuCell sourceCell = (SudokuCell) puzzleElement; - boolean repeat = false; - for (SudokuCell bc : blockableCells) { - if (bc.getData() == value) { - repeat = true; - break; - } - } - if (!repeat) { - caseCells.add(c); - } + Set group = sudokuBoard.getRegion(sourceCell.getGroupIndex()); + for (SudokuCell cell : group){ + if(cell.getData() == 0){ + Board newCase = sudokuBoard.copy(); + PuzzleElement element = newCase.getPuzzleElement(cell); + element.setData(model.getModelRegionNumbers(sourceCell.getIndex())); + newCase.addModifiedData(element); + cases.add(newCase); } } - - for (SudokuCell c : caseCells) { - Board newCase = sudokuBoard.copy(); - PuzzleElement element = newCase.getPuzzleElement(c); - element.setData(value); - newCase.addModifiedData(element); - cases.add(newCase); - } - return cases; } } diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleNumbersForCellCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleNumbersForCellCaseRule.java index 72a5f5bfe..f355695ac 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleNumbersForCellCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleNumbersForCellCaseRule.java @@ -5,10 +5,7 @@ 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.sudoku.GroupType; -import edu.rpi.legup.puzzle.sudoku.PossibleNumberCaseBoard; -import edu.rpi.legup.puzzle.sudoku.SudokuBoard; -import edu.rpi.legup.puzzle.sudoku.SudokuCell; +import edu.rpi.legup.puzzle.sudoku.*; import java.util.ArrayList; import java.util.List; From 1f5fd80bd6baea989c944e5475d1f3746a5a39f9 Mon Sep 17 00:00:00 2001 From: Brandon McCusker Date: Tue, 12 Mar 2024 16:32:34 -0400 Subject: [PATCH 028/258] All user board interactions fiex to be correct --- puzzles files/binary/6x6 easy/876868768 | 22 ++++++++++--------- .../legup/puzzle/binary/BinaryController.java | 18 +++++++-------- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/puzzles files/binary/6x6 easy/876868768 b/puzzles files/binary/6x6 easy/876868768 index a7ac3d25f..ceefaefff 100644 --- a/puzzles files/binary/6x6 easy/876868768 +++ b/puzzles files/binary/6x6 easy/876868768 @@ -3,18 +3,20 @@ - - - - - - + + + + + + + + - - - - + + + + diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryController.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryController.java index 9189f7ebe..ef519dd16 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryController.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryController.java @@ -15,27 +15,27 @@ public void changeCell(MouseEvent e, PuzzleElement data) { this.boardView.getSelectionPopupMenu().show(boardView, this.boardView.getCanvas().getX() + e.getX(), this.boardView.getCanvas().getY() + e.getY()); } else { - if (cell.getData() == -2) { - data.setData(0); + if (cell.getData() == 0) { + data.setData(1); } else { - if (cell.getData() == 0) { - data.setData(-1); + if (cell.getData() == 1) { + data.setData(2); } else { - data.setData(-2); + data.setData(0); } } } } else { if (e.getButton() == MouseEvent.BUTTON3) { - if (cell.getData() == -2) { - data.setData(-1); + if (cell.getData() == 0) { + data.setData(1); } else { - if (cell.getData() == 0) { - data.setData(-2); + if (cell.getData() == 1) { + data.setData(2); } else { data.setData(0); From f33342931c085630a466bc1f7d487680e463755a Mon Sep 17 00:00:00 2001 From: Brandon McCusker Date: Tue, 12 Mar 2024 17:04:48 -0400 Subject: [PATCH 029/258] Altered given cells color and fixed rules ref --- .../puzzle/binary/BinaryElementView.java | 49 ++++++++++++++++++- .../rules/CompleteRowColumnDirectRule.java | 2 +- .../binary/rules/binary_reference_sheet.txt | 10 ++-- 3 files changed, 55 insertions(+), 6 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryElementView.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryElementView.java index 910fc6e8e..012ca2261 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryElementView.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryElementView.java @@ -6,7 +6,7 @@ public class BinaryElementView extends GridElementView { - private static final Font FONT = new Font("TimesRoman", Font.BOLD, 16); + private static final Font FONT = new Font("TimesRoman", Font.BOLD, 17); private static final Color FONT_COLOR = Color.BLACK; public BinaryElementView(BinaryCell cell) { @@ -21,6 +21,51 @@ public BinaryElementView(BinaryCell cell) { @Override public BinaryCell getPuzzleElement() { return (BinaryCell) super.getPuzzleElement(); + + }@Override + public void drawGiven(Graphics2D graphics2D) { + BinaryCell cell = (BinaryCell) puzzleElement; + BinaryType type = cell.getType(); + if (type == BinaryType.ZERO) { + 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); + graphics2D.setColor(FONT_COLOR); + graphics2D.setFont(FONT); + FontMetrics metrics = graphics2D.getFontMetrics(FONT); + String value = String.valueOf(puzzleElement.getData()); + int xText = location.x + (size.width - metrics.stringWidth(value)) / 2; + int yText = location.y + ((size.height - metrics.getHeight()) / 2) + metrics.getAscent(); + graphics2D.drawString(String.valueOf(puzzleElement.getData()), xText, yText); + } + else { + if (type == BinaryType.ONE) { + 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); + graphics2D.setColor(FONT_COLOR); + graphics2D.setFont(FONT); + FontMetrics metrics = graphics2D.getFontMetrics(FONT); + String value = String.valueOf(puzzleElement.getData()); + int xText = location.x + (size.width - metrics.stringWidth(value)) / 2; + int yText = location.y + ((size.height - metrics.getHeight()) / 2) + metrics.getAscent(); + graphics2D.drawString(String.valueOf(puzzleElement.getData()), xText, yText); + + } + else { + if (type == BinaryType.UNKNOWN) { + graphics2D.setStroke(new BasicStroke(0)); + 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); + } + } + } } @Override @@ -60,7 +105,7 @@ public void drawElement(Graphics2D graphics2D) { else { if (type == BinaryType.UNKNOWN) { graphics2D.setStroke(new BasicStroke(0)); - graphics2D.setColor(Color.LIGHT_GRAY); + 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); diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java index 33a7dcb58..3454ac88f 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java @@ -20,7 +20,7 @@ public CompleteRowColumnDirectRule() { super("BINA-BASC-0003", "Complete Row Column", "If a row/column of length n contains n/2 of a single value, the remaining cells must contain the other value", - "FILL IN WITH IMAGE"); + "edu/rpi/legup/images/nurikabe/rules/CornerBlack.png"); } /** * Checks whether the child node logically follows from the parent node diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/binary_reference_sheet.txt b/src/main/java/edu/rpi/legup/puzzle/binary/rules/binary_reference_sheet.txt index bab194b2f..b0fcae407 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/binary_reference_sheet.txt +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/binary_reference_sheet.txt @@ -1,8 +1,12 @@ BINA-BASC-0001 : SurroundPairDirectRule BINA-BASC-0002 : OneTileGapDirectRule -BINA-BASC-0003 : CompleteRowCloumnDirectRule +BINA-BASC-0003 : CompleteRowColumnDirectRule -BINA-CONT-0001 : ThreeInARowContradictionRule -BINA-CONT-0002 : UnbalancedRowColumnContradictionRule +BINA-CONT-0001 : ThreeAdjacentZerosContradictionRule +BINA-CONT-0002 : ThreeAdjacentOnesContradictionRule +BINA-CONT-0003 : UnbalancedRowContradictionRule +BINA-CONT-0004 : UnbalancedColumnContradictionRule +BINA-CONT-0005 : DuplicateRowsContradictionRule +BINA-CONT-0006 : DuplicateColumnsContradictionRule BINA-CASE-0001 : OneOrZeroCaseRule \ No newline at end of file From cb667f893d64c4883e107ef8c659eadb3d3a0c9b Mon Sep 17 00:00:00 2001 From: EggyMath <55564321+EggyMath@users.noreply.github.com> Date: Tue, 12 Mar 2024 17:22:13 -0400 Subject: [PATCH 030/258] Added two new versions of the Possible Cell For Number case rule Added and bug tested two alternate versions of the region based Possible Cells For Number case rule. --- .../PossibleCellsForNumberColumnCaseRule.java | 104 ++++++++++++++++++ .../PossibleCellsForNumberRegionCaseRule.java | 2 +- .../PossibleCellsForNumberRowCaseRule.java | 104 ++++++++++++++++++ 3 files changed, 209 insertions(+), 1 deletion(-) create mode 100644 src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberColumnCaseRule.java create mode 100644 src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberRowCaseRule.java diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberColumnCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberColumnCaseRule.java new file mode 100644 index 000000000..22f768313 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberColumnCaseRule.java @@ -0,0 +1,104 @@ +package edu.rpi.legup.puzzle.sudoku.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.sudoku.GroupType; +import edu.rpi.legup.puzzle.sudoku.ModelSudokuBoard; +import edu.rpi.legup.puzzle.sudoku.SudokuBoard; +import edu.rpi.legup.puzzle.sudoku.SudokuCell; + +import java.util.ArrayList; +import java.util.Set; + +public class PossibleCellsForNumberColumnCaseRule extends CaseRule { + + //Board math for translating indexes to numbers + private ModelSudokuBoard model = new ModelSudokuBoard(); + + //Old board for caseBoard reference + private SudokuBoard lagBoard; + public PossibleCellsForNumberColumnCaseRule() { + super("SUDO-CASE-0004", "Possible Cells for Number - Column", + "An empty cell has a limited set of possible numbers that can fill it.", + "edu/rpi/legup/images/sudoku/possible_cells_number.png"); + } + + /** + * Checks whether the transition logically follows from the parent node using this rule + * + * @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) { + return null; + } + + /** + * 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; + } + + @Override + public CaseBoard getCaseBoard(Board board) { + SudokuBoard sudokuBoard = (SudokuBoard) board.copy(); + lagBoard = (SudokuBoard) sudokuBoard.copy(); + CaseBoard caseBoard = new CaseBoard(sudokuBoard, this); + for (PuzzleElement puzzleElement : sudokuBoard.getPuzzleElements()) { + puzzleElement.setData(model.getModelColumnNumbers(puzzleElement.getIndex())); + caseBoard.addPickableElement(puzzleElement); + } + 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) { + return getCases(board, puzzleElement, 1, GroupType.COLUMN); + } + + /** + * Gets the possible cases at a specific location based on this case rule + * + * @param board the current board state + * @param puzzleElement equivalent puzzleElement + * @param value value that the rule will be applied from + * @param groupType group type + * @return a list of elements the specified could be + */ + public ArrayList getCases(Board board, PuzzleElement puzzleElement, int value, GroupType groupType) { + ArrayList cases = new ArrayList<>(); + SudokuBoard sudokuBoard = lagBoard; + SudokuCell sourceCell = (SudokuCell) puzzleElement; + + Set group = sudokuBoard.getCol(sourceCell.getLocation().x); + for (SudokuCell cell : group){ + if(cell.getData() == 0){ + Board newCase = sudokuBoard.copy(); + PuzzleElement element = newCase.getPuzzleElement(cell); + element.setData(model.getModelColumnNumbers(sourceCell.getIndex())); + newCase.addModifiedData(element); + cases.add(newCase); + } + } + return cases; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberRegionCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberRegionCaseRule.java index 3cdb954b7..62bc9a74d 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberRegionCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberRegionCaseRule.java @@ -18,7 +18,7 @@ public class PossibleCellsForNumberRegionCaseRule extends CaseRule { //Old board for caseBoard reference private SudokuBoard lagBoard; public PossibleCellsForNumberRegionCaseRule() { - super("SUDO-CASE-0002", "Possible Cells for Number", + super("SUDO-CASE-0002", "Possible Cells for Number - Region", "An empty cell has a limited set of possible numbers that can fill it.", "edu/rpi/legup/images/sudoku/possible_cells_number.png"); } diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberRowCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberRowCaseRule.java new file mode 100644 index 000000000..5da0158a6 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberRowCaseRule.java @@ -0,0 +1,104 @@ +package edu.rpi.legup.puzzle.sudoku.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.sudoku.GroupType; +import edu.rpi.legup.puzzle.sudoku.ModelSudokuBoard; +import edu.rpi.legup.puzzle.sudoku.SudokuBoard; +import edu.rpi.legup.puzzle.sudoku.SudokuCell; + +import java.util.ArrayList; +import java.util.Set; + +public class PossibleCellsForNumberRowCaseRule extends CaseRule { + + //Board math for translating indexes to numbers + private ModelSudokuBoard model = new ModelSudokuBoard(); + + //Old board for caseBoard reference + private SudokuBoard lagBoard; + public PossibleCellsForNumberRowCaseRule() { + super("SUDO-CASE-0003", "Possible Cells for Number - Row", + "An empty cell has a limited set of possible numbers that can fill it.", + "edu/rpi/legup/images/sudoku/possible_cells_number.png"); + } + + /** + * Checks whether the transition logically follows from the parent node using this rule + * + * @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) { + return null; + } + + /** + * 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; + } + + @Override + public CaseBoard getCaseBoard(Board board) { + SudokuBoard sudokuBoard = (SudokuBoard) board.copy(); + lagBoard = (SudokuBoard) sudokuBoard.copy(); + CaseBoard caseBoard = new CaseBoard(sudokuBoard, this); + for (PuzzleElement puzzleElement : sudokuBoard.getPuzzleElements()) { + puzzleElement.setData(model.getModelRowNumbers(puzzleElement.getIndex())); + caseBoard.addPickableElement(puzzleElement); + } + 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) { + return getCases(board, puzzleElement, 1, GroupType.ROW); + } + + /** + * Gets the possible cases at a specific location based on this case rule + * + * @param board the current board state + * @param puzzleElement equivalent puzzleElement + * @param value value that the rule will be applied from + * @param groupType group type + * @return a list of elements the specified could be + */ + public ArrayList getCases(Board board, PuzzleElement puzzleElement, int value, GroupType groupType) { + ArrayList cases = new ArrayList<>(); + SudokuBoard sudokuBoard = lagBoard; + SudokuCell sourceCell = (SudokuCell) puzzleElement; + + Set group = sudokuBoard.getRow(sourceCell.getLocation().y); + for (SudokuCell cell : group){ + if(cell.getData() == 0){ + Board newCase = sudokuBoard.copy(); + PuzzleElement element = newCase.getPuzzleElement(cell); + element.setData(model.getModelRowNumbers(sourceCell.getIndex())); + newCase.addModifiedData(element); + cases.add(newCase); + } + } + return cases; + } +} From c3894d504f3fbc55168f584a23ffe4b6501bd24c Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Tue, 12 Mar 2024 17:29:22 -0400 Subject: [PATCH 031/258] Added temporary images to rules --- .../rules/CompleteRowColumnDirectRule.java | 2 +- .../DuplicateColumnsContradictionRule.java | 2 +- .../rules/DuplicateRowsContradictionRule.java | 2 +- .../puzzle/binary/rules/OneOrZeroCaseRule.java | 2 +- .../binary/rules/OneTileGapDirectRule.java | 2 +- .../binary/rules/SurroundPairDirectRule.java | 2 +- .../ThreeAdjacentOnesContradictionRule.java | 2 +- .../ThreeAdjacentZerosContradictionRule.java | 2 +- .../UnbalancedColumnContradictionRule.java | 2 +- .../rules/UnbalancedRowContradictionRule.java | 2 +- .../rules/CompleteRowColumnDirectRule.png | Bin 0 -> 35435 bytes .../rules/DuplicateColumnsContradictionRule.png | Bin 0 -> 38259 bytes .../rules/DuplicateRowsContradictionRule.png | Bin 0 -> 37440 bytes .../images/binary/rules/OneOrZeroCaseRule.png | Bin 0 -> 36679 bytes .../binary/rules/OneTileGapDirectRule.png | Bin 0 -> 16465 bytes .../binary/rules/SurroundPairDirectRule.png | Bin 0 -> 37015 bytes .../ThreeAdjacentOnesContradictionRule.png | Bin 0 -> 52347 bytes .../ThreeAdjacentZerosContradictionRule.png | Bin 0 -> 52375 bytes .../rules/UnbalancedColumnContradictionRule.png | Bin 0 -> 50546 bytes .../rules/UnbalancedRowContradictionRule.png | Bin 0 -> 48068 bytes 20 files changed, 10 insertions(+), 10 deletions(-) create mode 100644 src/main/resources/edu/rpi/legup/images/binary/rules/CompleteRowColumnDirectRule.png create mode 100644 src/main/resources/edu/rpi/legup/images/binary/rules/DuplicateColumnsContradictionRule.png create mode 100644 src/main/resources/edu/rpi/legup/images/binary/rules/DuplicateRowsContradictionRule.png create mode 100644 src/main/resources/edu/rpi/legup/images/binary/rules/OneOrZeroCaseRule.png create mode 100644 src/main/resources/edu/rpi/legup/images/binary/rules/OneTileGapDirectRule.png create mode 100644 src/main/resources/edu/rpi/legup/images/binary/rules/SurroundPairDirectRule.png create mode 100644 src/main/resources/edu/rpi/legup/images/binary/rules/ThreeAdjacentOnesContradictionRule.png create mode 100644 src/main/resources/edu/rpi/legup/images/binary/rules/ThreeAdjacentZerosContradictionRule.png create mode 100644 src/main/resources/edu/rpi/legup/images/binary/rules/UnbalancedColumnContradictionRule.png create mode 100644 src/main/resources/edu/rpi/legup/images/binary/rules/UnbalancedRowContradictionRule.png diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java index 3454ac88f..6f9b386af 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java @@ -20,7 +20,7 @@ public CompleteRowColumnDirectRule() { super("BINA-BASC-0003", "Complete Row Column", "If a row/column of length n contains n/2 of a single value, the remaining cells must contain the other value", - "edu/rpi/legup/images/nurikabe/rules/CornerBlack.png"); + "edu/rpi/legup/images/binary/rules/CompleteRowColumnDirectRule.png"); } /** * Checks whether the child node logically follows from the parent node diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateColumnsContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateColumnsContradictionRule.java index bc38352d0..fb69040aa 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateColumnsContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateColumnsContradictionRule.java @@ -16,7 +16,7 @@ public DuplicateColumnsContradictionRule() { super("BINA-CONT-0006", "Duplicate Columns", "There must not be two columns that are duplicates", - "currentlynoimage.png"); + "edu/rpi/legup/images/binary/rules/DuplicateColumnsContradictionRule.png"); } @Override diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsContradictionRule.java index 5a2d09177..1b83c9690 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsContradictionRule.java @@ -16,7 +16,7 @@ public DuplicateRowsContradictionRule() { super("BINA-CONT-0005", "Duplicate Rows", "There must not be two rows that are duplicates", - "currentlynoimage.png"); + "edu/rpi/legup/images/binary/rules/DuplicateRowsContradictionRule.png"); } @Override diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneOrZeroCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneOrZeroCaseRule.java index 0e3337d2f..63af9d3e6 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneOrZeroCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneOrZeroCaseRule.java @@ -18,7 +18,7 @@ public OneOrZeroCaseRule() { super("BINA-CASE-0001", "One or Zero", "Each blank cell is either a one or a zero.", - "FILL IN WITH IMAGE"); + "edu/rpi/legup/images/binary/rules/OneOrZeroCaseRule.png"); } @Override diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java index 5f4e6d95d..bb5cf6cc2 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java @@ -16,7 +16,7 @@ public OneTileGapDirectRule() { super("BINA-BASC-0002", "One Tile Gap", "If an empty tile is in between the same value, fill the gap with the other value.", - "FILL IN WITH IMAGE"); + "edu/rpi/legup/images/binary/rules/OneTileGapDirectRule.png"); } @Override diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java index acc774f26..232870977 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java @@ -16,7 +16,7 @@ public SurroundPairDirectRule() { super("BINA-BASC-0001", "Surround Pair", "If two adjacent tiles have the same value, surround the tiles with the other value.", - "FILL IN WITH IMAGE"); + "edu/rpi/legup/images/binary/rules/SurroundPairDirectRule.png"); } @Override diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentOnesContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentOnesContradictionRule.java index 318495472..164f50c4e 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentOnesContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentOnesContradictionRule.java @@ -13,7 +13,7 @@ public ThreeAdjacentOnesContradictionRule() { super("BINA-CONT-0002", "Three Adjacent Ones", "There must not be three adjacent ones in a row or column", - "currentlynoimage.png"); + "edu/rpi/legup/images/binary/rules/ThreeAdjacentOnesContradictionRule.png"); } @Override diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentZerosContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentZerosContradictionRule.java index 04d8181de..503bc7752 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentZerosContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentZerosContradictionRule.java @@ -13,7 +13,7 @@ public ThreeAdjacentZerosContradictionRule() { super("BINA-CONT-0001", "Three Adjacent Zeros", "There must not be three adjacent zeros in a row or column", - "currentlynoimage.png"); + "edu/rpi/legup/images/binary/rules/ThreeAdjacentZerosContradictionRule.png"); } @Override diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedColumnContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedColumnContradictionRule.java index 1867a895c..5f747e275 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedColumnContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedColumnContradictionRule.java @@ -17,7 +17,7 @@ public UnbalancedColumnContradictionRule() { super("BINA-CONT-0004", "Unbalanced Column", "Each column must contain an equal number of zeros and ones", - "currentlynoimage.png"); + "edu/rpi/legup/images/binary/rules/UnbalancedColumnContradictionRule.png"); } @Override diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowContradictionRule.java index 40dd439d7..c1fc3f286 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowContradictionRule.java @@ -17,7 +17,7 @@ public UnbalancedRowContradictionRule() { super("BINA-CONT-0003", "Unbalanced Row", "Each row must contain an equal number of zeros and ones", - "currentlynoimage.png"); + "edu/rpi/legup/images/binary/rules/UnbalancedRowContradictionRule.png"); } @Override diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/CompleteRowColumnDirectRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/CompleteRowColumnDirectRule.png new file mode 100644 index 0000000000000000000000000000000000000000..ed738b444046be7708c0de59044f96575f6fdf01 GIT binary patch literal 35435 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/DuplicateColumnsContradictionRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/DuplicateColumnsContradictionRule.png new file mode 100644 index 0000000000000000000000000000000000000000..57b75b579684d58d4085bf5bcf2a15eb84979503 GIT binary patch literal 38259 zcmeFZcTm&m+cz4^u5qndq==#`t|%ZP3Wz~Kk$?&T6+)ydsF)xi5~?(nRS8WO1?jyd zKtu^hw-B(=2`C6Cy$DF}@LqSocg{0&X3os{>zsLaXMT_Fvl{aK-uHc7pLX3oXSFpp z{2}}Y27}pf`jpyv3}!9-_O}@9@9@jIHn$e|Wrh8D4OL7=#r9tKm(`Xhh$k?Z%)oVX zmwtnPUwh+}fjtHzav%L~MPTRf6%6JH_O#jwJ!jJ&&1;`Vwoj}4+?$QvwbpzCE`PIP zCX2m=O{Oy%D?mwHoSk%oWfxL_wTj-`#pLW zXa0K+OMBzL_we6)_-_yVw+H^)1OM%T|MtLtd*J_%dms(4Z-*R41+&w0&MvQy!K}$2 zDhkh|_5RxxVP7G8ttzIDNoKjN_M-cPg%tac$P$|-_{^<`8FAIwY)aEWR1_>sHX>Be!DaF>2PI-)$(6>YD~kd zY^-yiYz~QX8+kuAkki@~*=IghN2?{0jp5hpFUo^w#(H(&RG5dJ=azqKOUa@{ob}39gmS9 zW45-pSFn*yZkvK#Z*#s=(Y@@NMoiUK%ZPJdGh#Q$fBvi4ZL~ah<=xr;ShW`?Zugf;+hJ@p@^!)8YLu}28 zzhcVW7N)yhxbkhzdn0bB8s2#QTP;pw`=g?TnSQqoK_@GtltvlK7EOKmlP$Mu{}D8O z3Ljn|`bplrhbDrF?sJo6=Ji>vBIJYpg~yIe#!uasWP$5=4|gt@z{F zN&M)i!?hl>10lArpUPN_FxqN$RLYm1-fLnPW_1=*JUQY}`N6mANzyMq9n$P;V3}3R zTnSW~I7K#fxgxCW=8PZ6s;xPW@?d7FS=?b+xP^u~7`1z7ca?!4n_Y&d*@Dk*zqgc#}r9T&R z7qhu46}|M{BgNCij6TKh-h4G0JKY~kKAkI??h60)1$q?F7jWu$q>+>uY$!qIkM@|M zphvqoKF=3vVd_54rA;&}2Ee0H2hJyY{v>vVl?1q~4 zhd(`ZVl+9my4RXGH9tY8HqUV&Ou&Rz-InP%)S}cH=eTC4+l`q@&xIgmSdg|0>khoU znD_0@I(p`n^69Dez*_mH>$=BU4#JZp!&%%nKG2ktQnn3GyO#I!&AQq>A;#zB-pRDO zjV8kWIWX|DJs{Pr*uy2q@$Q;U+LqDojv1w2>?@V5{?HY%|0L5p)6de`=`nR_xKZl) zJ5f&N)i6qun{RL~IwDWVrlB^)^AlqqBv~EJbV^dFSo+I0I;Gj6frvJKn0>|3Q8~8H ztIG78maxHs(F)P+eBI}CyP`c8vOY*K6U^rO$Y^J~-&*Y1 zcsYnjx3}@x6Z|fJ>FvLod<5I(YU5$d7LU31oykyb_K^8;_dY{qu_u|lts*=Kz_0p! z{X5b?66}+)>F#J)9&D)E!}z0{l*Y~)QWBrsl&c_-O`dqn)J6;R_Y96UwJyjS_0%Gup!Rd|;{1^4#lxvr!>zMXIWv}% z#-A8?QK{Su|HZZ?wLBw#FwA3dw)M!Y+tQPIjT~CJexHA{Q>zlI&$r^h6*=WoV?FVK z0+&(^->Q7~l`c9}yfDu4y`d3m>@nR*AV&v#d#ciGXFi%O{EMov`mThvgzf~aft2Z%Z zWaH9z`ROi-S^c=QbepZQLmk=gQQs-+FA7qs$7If1!7kUfEtL%nKW6S`@OI-Fso_2*OJH|1!$-!dx;!QKhPK~#`lBl{$~KLZ#;|#v@v(p;ye!Ak91fTcGdlq6Sw;UsohJSw^m z)u!etm61yKI(bq@WuAt5RmO)sdEc++^(GPCS*S{~3U1spGnzOnnN0e ziZ16WwR`gmuD(&CWX8)l>?Zfo@*{+^`|?&1Hj7t8uiB^(L%ktZ+F;_+`6QPiUFyxj zW;<)QOEWX_s72Z4^#+zw0cHa?QFl9BdF*iO^Srkk75C5gn=O7IaZva0E^BisImLEf z1l%wzsyFf3B9Q-f?!7j4GwdCD!_tCarWSh6Hw35e_u83dwlEUX+vY1>!Bvo{mr&he zy+@VL6F$(Mgu8wJN{ER(*`L(^?9W~Q3h{H#Lp?LWJ%3t-4sbn`BxBNK)yYky4KK7( zbfT3xFOyK49;y?(6bRk+ShMHiyi2ku{#D(dD}|v)pq61Tr%fxTFy4OhZX1@{UhL57 zKAA|;H`qhwy3Y>e5H9XfJ-&f}69Ja!(Fz641G$%7`%;r{atka1j*5wROnuK4-dpieLB*(j zqRE!!YB~T_hx76!mLt~<#gQePM?Xg$&RezgT3R>ZF)I?Ee>V5+B)RWa_j|`2p%1E8 zzfMg3snY|91a?ID`Nf6#QEkq{T_U5&6S zRgVlV^^GA~Zi&1mYxexMok$64_XnuFzzx7Q5t;#twr5M?P2Bo3(Jf{#^zRF+bq6oDYS< zKEfypSdU>lbU((vQ4@;4bSnPnN2wfRL)f+UBs(bhouqEu_t5)0Jrv0N8X^vQM3d{n zhF0n98Yr|O%xwPdhAEsmpDQ%pQHBdQZ$3*Nqi6lM5lz0YI$k4#$`_j(y)c%X%K&)A zdv>p(O@P?+P*DabH(IGu$-EhQ^MiOT?6a?zpQRo}z|xeoew+OMLO>t6ecK0%7Z(Z` zJuQW|8lBty?YX&Q{SDGA3H5;Oq2zKaChj8Y(@tOQG%_R*5G$aD3dPn}#Rn>fk(b`~ z@h|9Yk9@I=hTTB??JhpQ$E&u{MxMzkay8{bKdpp^yaD^SlSEj39^Zef9@TNi6xxam z7i+ndKLA!=qh)9$r+m2@E=87l!P{6IIJZIn^GCej8{I*2zp?>Cq_0@@dqRdueitL| z#cy5=|3$-_@Ar%{Mk&OysNqJ&sw&ubBaArP)*=_~O)g%`f9qi}05IfVsQ3d=oqbP| zRvt$X!gT)GC$!q6;n!<+c96P%LXn2=iZ(E#o$#|WH91N`J*XK_V(-0eHm4d)Z&~w* zMrVjw6oN%=AA_x!8;{F;NRM?kR#}{`G;;U?CwlZ;-!>&zn&~nSyCMd){lm}iZ$}wL z^#STse}w76<`_ythGirNZ|rqc;c^*0TqfC+U3{d)c{jjw7YfwmGq8-FVVCZ0t*OzJ zj?_1C;ARcx^(RHob?l}1N@btA`}>A7P1ZRk+(AV)m5HfJITsH=mfc{g8DipSz&x-x zRi-j>u5Whaqx2{;H{hRrhtV$C;nMM_fWbmIX8dhU;jKy72U;s)9_`lXBDssmJRg9C zIR(st5(eL-7PZcdqM1HXwc4l^8TH=oj8p*(brbxxieLNw6WaGKP}!H>Jwm4y+)bJd z878BQIHMdJ7rALUe)TXYJ);cwIXLL2J|4)wo(Du?RJ-gN6LVIB)`d`%BKOxqWkq2& zpB3i8#QE_Cds61tn;$#5n{?P-#K0X&Bh(RQee6CzSY1|Q%k4Ego^AwCZ_GW?Osh?V zdZ;o0yr9>qc-ExwW2j|RsP@s$$60eDAG?imjE!L56y67%V1V;tj*mc<6Eu0qBXD)P zI*G~A9(aUudtqA>Z41Zs5fUDGw6vC9&-pMb&$Odvz?_k9ycQ3Kf`{lo^uxLMz@$eh z-Rk0YH0TNS026XBQwpHK<}}<9icmfVu1Q*Y7x{Fi<$z zLW%uH;KL*}S3K!jxC)bNnuC=lkmC)dKkk2_W$4PfKi&G%U)e`+S6bHEWa zJ2u{1yLTu5(&A1jLp3h@QVnx#nqlc1r_v7j*lC-2&O2mC#5HMJ;$Aa<6S(jfng8Vd zjqp17c0~)Cxyg|ELrh&MVU|%YH@QWP5|}L}uENy7hV{!&;lZPf2onNp^~hzgQs?iP zyPZGDT}j{@MI@WsAsC+~jCPYQoK<`7(f!49BQ7L6D3;x%CYO=-dq)}Oj|c*%CDXIc zXEd6zF=wqRLT|5H(?ue zDvphQstL?kUg}0TfmPygpokRM#l(~M*1uOAM_5-I>XliBScais7*wlxtX^Fkfbi2A z+wIgc8cn?~A(-9GaM`U9pmpm8U;E46Kygi+LVfbmD`iTgLIUS z!g07s>5g=&P~=B7g-HiQD2fUWm33J7-9qkwKsV+n^ZD84m-4);aF|Wh|Otn zl@x($_N#0NX<)EDvZesoK~WIozZB^&-hn>xe+4v-uXXW;wvHUJaF* za~Trqfjc7gjqNyN_f_V0ZP=-NY$(b6Qw?fosIJi9k-MAiT*rDIk*$ZIeM^--A#9e| z(c~Pj?k_R%`^N1T_3#rVKKMBr^+>IKrs3y1> zpGx9ty6E5h@uS*6rGLqO-)3VpP1t5?D-6Gf6wh7Bn`-m5=Vl{;P;~nXpkrN;!M+<$ z0-rsFYE}zn|H|#P+KSc)cKQBPJ6U~OY~}F{Wex;|#Kx!0wMt`ECxPGU1CucKmC|Rg zJLhfO=HfZs8PfZ9lgg)ju8H&ae>nYSzOV1DInsBEZ&$dX>Mr-0G4Z@ktsZzIn#{E4 zXEMSBCVgYdy-zTyqMx>ShQ&3V(-oZ?0Z`P<5Pc(6{XHq{H$mfr>A78DNNC_#%>cnm z0stoE{`2*kX@Pb%!9;8Zai4k?!8u(3ch-t({1qCPiFdQ|!c_ZW|5zOyBGDW5kBjFA zY$-q)DoGY5`HoU=lwOp}8{q_m6&}zz&m5ls0A`9|rMfw({%2)}Y=g0VB2=X0DO-Ed?X|{JmiM+^y>>I9ek$WUS4~Jv^>Xoaxh*~8 zI07s2KXv?mB0*O6gY1Pm1FN!FYxH z8E`ykuYVIv(3CEeHSwGu??rI((1k4`nM;ji2@;pf^1EL1@2MLtQ(2JNuuVP$(d+vw;kkGBZa+Q&q^dX;5@I;u<3a(yR zc*Q=|3o`YR_~9(|uhQxcoX^=wYDW@G9KY-#vwdtdk(qdU0*e*8I!Zk0u`N^nN{dUk zROwN~w|h~UYavo@|0eK`X&1Mu{`Q-vhJ~%4zZU~V zYn^n#4O7y7AdoKH0%xMwmfgv&lY^1W#*%)g1{0@5tBl+v?3nE24)3WWzi$xMTYa(3 zL*`KW(P}vf{QOrSE)>voKjd>cN2h9|7qWVS?LiXZZ-1%keN(LNr;Co3+eY&aqwV>* zH*~yTwzZ}cjtyaT2(X=3bNbKwVxMf-u5fUEBBxj?svFv;zFXI?bqqYUQBjbg z_5l}>EcNi;$>wi=Bw%p)Q5L)s!PgN~b6Oo>J|pjN(fx;%6>1`|-f3AiXL1=S6LNE~ z0!g6F$|1>tQkQZL;ZtpB=eKYzsg8cZ^!ANAl?$9b?7kXUM#`BTwyS<3uC7UVAbCdy zPEL74miDn?Y<9`DG}tpN1xIgs9G_0XreQaunysm^&QkGKXZwaGetO*yu> z&5Vf_4)!Hzp@l+~{JSCz^QZOrDu;k!OYhK_o3*Pb88x~ZdZp$M$+U;I+?&HfyQ}z4 zJOlVG5F%YP6^H$u1B6U0svY!-N6`QB+@zP@#J5>U^~BuG`Wv%)>HmRYgNU{K+y7Vb zmWzkNK-(EvW(OEUXrC7k{khC3F&EDR!_!jN)%tEFw7eFl+e0k9HXeel*-heT9WH;o z%+xSd_$A%;nq{TRqMIwoO0}r7UIpb3A@5}1ncY^)lqjZiwb!q29aG|mSw0CEuRj4_ zFaL-CGk)KHep1C{!|`oAmkA2l6U+ck;S-HMvGtV0UYVZ3Iw7#cKdu;%l>h!aU zJsN@d)=Dtb{&i9;hQ4yh8oEucaI)v(LT_$&)W>Cpg2~z-;^pP&1V1<#bvcn6uU1I? zvFI%n?f}kE0?5Yf9syZePt`B~2(uZAqvI$D00}4V{+@_REjq+5IpaH^0LtF@_KF7V zzI$2!!5qh6uL1o_> zLlt0vXnk-_Xm8f;-IAjO(xfi(*x2oAH-2ULfEqP^hV_d=z~7kb1RXOOz3y@_H(V^+ zMAy^a?Yh6^b{tXu%ilvub@@(1zib|_o$|=i^AnbnKqf{mV<;s);LMusH;!i*+GON* zoq-B(lK12JN4f<U4QxgUhmJhn<}{pUjX(s{kX9F zCx5zEB@TLy2*+>%>*UKq4@$oD_FiYC9V%gCfF~2-eIFUp@)%}MF3b)k2P)5`yhIcp zy)({*OoXi+`s<}ypO2f@eF0l0h-o)7Ib>EK(5k`nj0%R;U17Cr5vN6UrEOYUj;l8< zzy?G-S%Yxo7*OIZWxY^`hZkrGn^fiw0!XmpOyjx<#xvvnAuMYn5D^WA-82HW8yxE% z?!I))cIn%D8TNqZ=Oa|fJvhgQL}6{*f{)jS4M)B{bcCiVYK#j(lp8!tN$Y~)QVNHk zynm$@Xr4N&)@;;5>x$6JXrW^LaM{ji28LAgK9x7GFfe252bZW58TnP(=N%yb-#rcPL9}VXSyD!L2LZDGE{jQu<2wtNOI+}wOX7} z<68slTJ>$#kM%EH`p3M)-=o)<^c-9Z9%Frfd(vh5kpn7iDF&lVo zS#WlfL(Dvm4%OL!g0)X|*E*@JvtZ98&@gnbGX*w$c^&_1)i)t{ zoWcZ7#5k{apPeXIWQPKc^v%#|PtPnB?ggjgKs~TEYdly;HBj!zv~QtLv5H8BK9xU^ zZPY>ug&L=TN>p!qph|@zpWt@}coL#g`9GfjqGU0uYyP_UFX37nZ0Jf72R8CygSRR& zjs3|g^OR~rqTKiB8&KJ{+>Stx;L?3xQuV}l@Bzi~E4ji8YpZ?s;eR9UYl%iC1BF#M z!2khVH0wnLzJE)zs~88ii0Rzq-A&5-R0-gjTqb^x-fZz2@z^ooGkb>W4yfu5M;QIN zuy!~sNB+h#DsWqbwjJ~XMCw%GsLwavZa{M8E74LDHsQwJsHT_`cWV&!bnpt?hHJApyuw$j(><35TRJ7a3>FP^+-fWl2mV6_$0m2nd6nI=><*`w%mg(<44g1tB zi3(>VuLIZUwe_4eLUsnK%tn4%;mAK_kMlflct9f5Y)4llN)9SWraecz(XKSmTU3z=IwaDF`YllR@G2s1pGCw*8)pl2*tb9`BqN0VUoAe!_4ai0&9KQl@ z>7ybSxn6{)*Hq_cCv~9X7z3Hy^%$KoaytzBD0q;; z2nWBX2IQ)9-gkuQ5368B$+{P*bn&E9W!vqw@W5+gk;2QKnkiPIe>U$ic%Z)auukAczYlX!HMBp zp@NG*B@36aj3Ta`LdS))jVKG+msar4N|42Czu(^pl>%$@6+VG)!=m>~>(!bdHavBb zFm)T|j0Jkm?Ix=jL?kk-4eJZy8~yZaROEus0FgItC)_ zklqm#A%J9$IN6_|u0JE~ImsmOV~l3-|;dn572_e!ccKv(YM#4^XEdUKA3_=A>f}X!7yL?by9GKw6%Diki+l)Tj7x%A_`vOy%(dM?DN ztLng}>8l% z>o`Op(Ss!s3}Cc?T1YK(MuKzS{Y1If8Bip|Sz<&srV1)|6j>zs*5n}AOMpt?L1g{_ zdBG-^q43RXRSgo)fPjY~ zSs4Y(Q7;let!7&_z&8Rl$CL!oq+%L0#7;&LEX4t-+>U>F22oD4qfyIpV@`?0Y(Ds& z;o!U#LT&I6JhO+u&XAEJ4G4k2_d(Lo;-=pND@k3g>O7T5q|MZTl=hfeiiDOd=mGqf zVv%X=4m#;Cbm-NEI!&74niv_2(gfsPkq3sFY>SDgjAuwNl(K^v@+0EvI__ZN~fB$0H{Aibi zUkNs-QC%nX7*0HwqJa>r9_8nC5oO-+SCMgq)_+(@mG6oPv27P>YtYOV>J<*GEmWWT=6AXwzaNzwT zr|5tDXak_^wa}r0m@{!f6$sHGgIW7y$$SV>^1uHhC@>DPqrse$DlYglYR#l!K-D=4 z>-pM~5QrIreb60A2l4@1{{mPL;B$d~CW)V^Ya8-hyoGx?v&;We-w$M^6fl~BC7)xD z>arhhTYB3+--4^1m5S;Cyk<9GlVMgFrvcJmz+K)7RkFpp5l~U^0;qZXucJ|N4j|gC z=`g$R52)r}FR)AtZ<6dlg%c2=D+6|iR_J^kEE0QM0%hMyZNS~m8I5I7|0AGIW*d_t zpndd$YX6>OftxxC^{}=Qk|SYJ-5qs_njr-<3;AFt)xKFL9RWGn=!Dpl_q&>XW#_ecej?b^wbyw0$LZ>bn$$#m^3p1Pt=@1j-#c4r? zv5{D*f)k}bQ-l3Mw=?4A#mLJ2P65WX{|+B_Zk**wL+HelB334!PlYKYPI{3 z&Tgn}Q3D30GSa-0Qe)wgs8*znwEu?09&x1`hob=8U%TbVt@ZQQrjE z%>p8qL_1y}6BPmcR`Up<_l_WFbkN`LQLiQTz)93b_yhN^uf2y`iX{FB;(5sYJ_A;k zO_2j<<+}Z6zb<>CF}pytFi|_zji5$eO;#d2%q|q0qAUYqgnD0QB>9Ob%A;IMFECn7 zNE=^9`CO=^N9o{N>7(*i(hWrP~Nk8L`$m&DlK+Sy;ag5wQ^L zQxaeEv$%c|ErEWP>=$thQe+Ir-@_1XY;pu;;#Y~+15`F}723D>8@$Y)*TIDNl%GBt zzjHnX`<)kMM)`+)Vt-AdCXNAp<1l?tIb8-Abi%4l#||pN{v}{j;=xy>!mq*Iil(%E z^b8f`gM>jae6R51xOt93e$RfcA&<8}PZyg${EOUqLMa`v0eMXm39U1*cMQ@1jF!3) zYt63%zDs``fbUCbD?-iR5CRCJY<3gK>5zCT+i~l9P~-(+6lI=4h8iSyb9qD(k^AYe zM$S|Q%GOXL>S>!%HnavbawD2Ds<$oH`&CtWfyf5x;{0S~eyWf?Q0w8Or{?swX`)ua z0`6PbSwEuHX(391kgj|zR-d2|4$^u_d-Peqj|{@wvd!HW{T!_Pg*bAt(4m!i$pOY7 zh&iXF3x29LLciFi6ijV%QSTYx5j(&czK@pW84R(Pr<7LhLfL7g5F+Jm44^_H%9f*u z4`DJ4+oYCak;xH|?8_F2FB*iBgUVbo1YY?=u=OP=Y49L|i-Stv zTXqN#j9?j+lAQR`bM>t@w>dCv>Gpf>sM%FWgFTD{rZn+=%g!&Tpi3tmgZV#OFaQ67 zKd_|PW3=v|^j;x^#3?^MXQqNLO@Upg1KN#Mk-)yYD8$eVG`knn5hB<~ye5H?cBAa2 zrHl-MNPpICuKr2J+&f^;BDT@`z>7VPHb%!*e<8TKIN+A3b6 zhr|m&i4B6>cpBiCD+-0s2Y0J%K}rhQ*p4uRLIo92CT@$1<%3Qq0mQ<+XsHw8`9O-_ zI0;f`A~cOH7Wxabt&3F3Hm^{MN=leiyqM>tr7Qj#h{$96kxPvce=+7`rO80s2)im&F8!< z06*WwsSSl5vjEg3g8*NQU3J2e3u7?=X2QDwlt4=}(a3Y?4`vQU12mIDQ7ZtL2tT2b z0m;TD6h=VGp)va_iaynw-WuR#J)YcEDv6sRaf^~F>s)CMlIw4N+Ae4$kbcGAPWUr!RevmMGpu>peBlpQDlF++&3(F$_61gVd}QB`k6v_=4oO4 zU7^If$0$JwsUK`7&j|;pbQ*~=xE<4g`bODOwRQHuY`%=r12#t{HGTjNW4QWu05HpC z{&`#jISU+svS;V8ZjkrsjOpkfFFztQj;-+&D+i!yLVHKO2E|NE$#v`W37QyRGvbjlw$|zvP{IPn!dvIWtaCeqDFBqTi)WjM@YcypYPU9RmgllfA3m&fpb4JP?UgEUAh!s?P-egI&csmSyX`!ku478^xd%Vp()ELlk&=?AqvWAeh z45#WLixP??5_olcngLCtK=HnXS#bOW%WQ4!luKOfU}q+yxXcAlXd}~&GkB{tF~h7@ z5dWV7{KyysKB`?~MNZPzzLz;po(49mYn8aIJ zRgg-2KjNdvC4faAnKL{ssSS3cCUDW4!;uOLwv_;Pl)qGH@Ve5s*?7&!MM;&a-+8JJ zBvv{gisd1KLTq7fq8C9{o=bL)7>@5p+6ODu7AeTQWILQ$-q0SB#oUM=c}xYw7{Wz# zj47}blK8)oYyyM;y9eBmX^!&?ELH0oL~PC=KEN|$bv$Qk3z`a47KQ^kGP|cXpYX?S z)9WwFgc-~v)O=8kjAI{F1;GQoWA#{D5{z7xB_LA<<@HcHNDEmvjd0RO*{Rr>66-dh z4bi#53IQ^F+A0%tR z9x(Ct7rvL$<^a8oSaTr%$N2)4c3wOiDpxsIVSZ*@vf{Rn&*Tq4Z`vRyYM(26knb$L z2C{N>Qv78;Wqh}vV} zL>VqOUpw9iD^e$i-cM;pkooHELZ1#t7dsE8^LHD2TeZE|aXT6bcvgML-S(|KQSkfl zG`%5SPSh_O1)G{H+eUeO3}vIne|$OIYHr+faEGRwSlev!r3d?!eUWExw{RVDMJ_q* zX>js5me#63@f>CV1w=6$Ik~(vJT(HvkHF{Ag$yH1nm#%J&mju~o^5Qup^rh@c<~KF z2mgX8yWv7tV8mO>=%W%l8lcEMM6+mazDbYqv|rBDMY+h}I6&#N!6O-)w|?F6ls zVUmRkcRg4xZ9~@zCQyrLSVBj2`&J&u1offZ;#}O99$r4qNJ|+B|IHwM>5UH)e>{in zSyu?mfBFw!NLe z4JtLP(_mO&+(r?i1a3r=X3*WvBRSQz;Yh*uo9}i_*N<~@pF^pthrn!M-@KS3iuU%Q zNyET;JS2SFo1xhnj8Ab70FtwA1{ub8HVUTQ{4)X@;soG8TgK1spjDliZfryWJ_qEu zn?PJzScH}P5xkA|JS6z;Ol-?3p10;Uq`x62jca%G~_<|@|L>hlv%`y;D;V*j(YlJ}$ zBtqUIu?9^>6x6y_6ZVv3#s!str9iG@KiDW!Eh36PExV`Xep0C}TTipp!Qaz#SQxp< z9EI>MH&Bcr(+xXEp!*{T;TQbgQT(Cgz390-3IGt2n@0g!`Bo^)9AfBKb1gtj(FQ8m zae1ddf8@QkX^oJe;DG180h+_d;`q4UVSQ1xEphAgG}RiC6eiI?%NUI7b~ZN>LXvxg z_#&wc_Yij7RHa%(5K3thn{7*dD+tIz3^MtEf6J#F5C%_rgP87~vqH0>ENTKzu-p5_J1|b_$hXSEc8@>EnnU%2uxMJ_u0J~=Q;`-XMC3)osWoE*O-EQ_2ckfWpr13|ps`pddgp90 zj5>zT$KFED1`6+>uAOOf#?OMDX)iSnN_47_QN8eRgvH}J^hXP7heh4^zegvPCUQkp z|G+5-?KE8r4d9lkgQ?vh(jX}B9`15U9v6M}97KM(KUCRz1;KX8oNIZ(_f+1XOcMMV zrtuRE?-1dDPwQ}|bGv+AH87YNjh8RlBMn3~2Dj1ZdM1Z%N8_sfH6mC%MOco#gf;AG z#B|CXXGXyIFM?i`B*L6f0btcmh6PHvqS@j1BzH7wGTiP;I~EE;eXX7@kwj~H5U>Gx zNN7gHcksjphk-^mR*_r7?EzI#3p96PMyb!kcc70yX4;{t|7`H`vtXYm!$9el@4hHp z5ec8hDJGSJxgUaTYoG$Rlh+Ojo`{DTVw_eFGDiEtA=OyJf`L9`IeDnKNjwunyc{+> z#~mf6fU|&JZMgcd=*v-P!2*>^Z#Ltyr#%;k7CVg+X@j}lNr2;|$nBp%L!p4xBwY~= zxG;O_NU85eRgkou@i37~Z^#XMsf_=F+XkaX``;YqmK5g$Xh;AbJVSxpR`8%3$La;9 zH<}(+57j5`aAnC4pj8Bg>#A!+XlG}j??y0_2o1?d!sZzv$)cuZJ#@ZqH`=98RyS8S|~|H?=uLf@ea>dwJ_YxN}XzuX>Lq3rdiWR zW4_z_*dM%eknPRKR0^1i0N@V1tQloX5TpS--qgB~ofOjwr>iL?+|Z4se$CQ6?v^2K zAywd>U*+_-*LN3(M&(d`|GamF$7pzK0*s3&4(TJ@%yD0Wn_>Jb{_;AFgm#UG&#JF{ zes*bEK%~EfPbY208ReSuka*w9pdez_3_HtsT*!C-^Ha?zJtr0J2)sqFaM2q@f9e1_ z+fVQC7lEcg8ft(PnVYYV?_^A)43dgq#M{@?^Nj@&>hyTu%k5B?{Y{gB#5W+`=J59Z zrb@+j#QPSVih*htIxixO=w>|%O*6uEad7G*l3(3?yO81P0EdpowSYm6ltDPDA9Jq% z04X3N9JE1Zi_=^paPH~)@+JT|+nOh1?r!|hAU}kmN(X?qELT4?Z`#UmA-cC} zIU9h4*l!B4BDcU9l)cFV%Ya<~U=Gub!CxSVvQ0#?BE*meXSv#aCyZ^tS7>vva&9#(bmaopcApj?&H|F^L*PMu zatPjEGve{KO9s{1NZiF&f8T;P1fEfzQr2ZZJtLpN9U#LvXGoxwH4RW1w=VH-n{CaC zO9_IwpmGEzjoGGthV%n}LvEr{(O(3PHA!(FVKTC3`yuhT(X&Prg^_M=KJ8O*#9G(h49yM>1gq)cq_cY9{| zq95IB%WVZF>7SRTcNnq(ZA!*4O8|4UAZbL~0D4AGkl;I-nc5(S_vQ5O+#N4W&p1qU zSkt#27~gJR?K9QZk`+1kc!L~}0qp3T9RhBnO*U~LWt4`R)5YnP7yM?!o(kDH174S% z3GmalL00T?spc8227YU)`_y~1HllkCWDG4;agILcG-TeS>dUMYQ-40z#|2{#q~@(4 zWylOlczm*^u5R!)|4Noa(?QI7%12C@E#XkfJ^-Nf5Vm|msE z#vR)L^wRSq%<-;gFMQsy`!;;bBG=s?@aH3jQ1CKC0-18=W9QS&|2FnppxYPK|KxTE zM8CcF{RLKra4mUHrIK>HU9`~F`YJTqM^5Ma9wIc%zw2RF$vF3o)~-9Jg5CnUHH|PE zHh2jFk#FS(sK@#RVrXniMs)wm%Q6gBt%sI4$=-q8Eg{^kDjd_0|4Ku{|G#QR;$mB`#ivUH19$KLUm+ z*ihLqG|~Z6z9L!ykZd$|h;VjCii$BwuU|_p76yy-1`PjPfx4h1nePagV1i|#+q>tW z9t4s3k?F&%nCv-=T!nq)NF%pyV<2@9II>X$8(b%Yia=_cyKN6-QPYHPq;a5ERbNg? z4x5_OyY(Ze|HT5FBZ1aP0FjzAFi2xSYn*}EEmLn!fI{1YxLfrACWCBETA_G9MKY8u zaImh(q2j5cT zLM!UevNy`G>E}$iSxJ%_w7gu9MvcC@CpY#yMYNZNzuzOQn;x#M@xX@2%~K?;OCs*8 z2tleOnV(qLU2XtrAKz+A5pjH0iNec!kd`v*;7*eLPBZGKQw$#@>*H=x_TkqrIm9M@ zTNHZ}f^L%XsgdS9ld^BFEnlMaq6r9y))Pl!3iF<@+1M2x(2-%pU42{W1y(S9qpOU5 zdMx(JQgc`e0c`LbTOZV}(L{}nKzU0kAQYfQpld0h>US{OV(;&O=|9f3ka|CL-y5e- zT9o>|XIAV|_XI)g2w8+>I2lP@@o23Q)N^ofhbGZjJ2RN_{&Q;fW)Xd1`awN|yeTa@ z)>dwd2+go2H#HW)18P}V&lLAO?vzz|50e@_4qnbN7Cr}}7EEU|R8qykTWq%4wyRUc^>i*?4PG@`3&MWIAouF#mh|u zX;`hamvX8q~Qpp(Fe@lOcV zB!m03AEFEiLTr10_Q?Rd#OCLRJar%r>N4}~?xqnbE5Y4a!ic4tI(TqPn~8&e>1((E zuZL+)bVUiXe$;>^Bzx^FgUOsN{s_%Jyak-VF_0wo^3+5$t&@}X5`>%@0i)}WP`84& zCYuQjO0>YE@j%02!oO zQ$2OHhTqOIc0h6)4+Omy(Khq6+Wjv+ou_phK!dM^U`Vt)%u4ctjnVTzEGeKvXac4& zEwUVdapRyvs*HHjte?Y}(DV1`a*-6_gD8$V${2U6mlSrCp_d8lu0a!9&Nfl~m zZq^(a|2yZmI^wHnR^2&te+?u4pe=kdN-wheMo`&_*PGjXm&7B@#|J=Lg8y6Nq2VO%YeoK7AP8g8FLS#C)&5-s~drYhn; zC?hv&GfU49+2C-w;o)hL)X#c>?pqq+7pf9sv4Z-wrqSbviju5jgD3ak#W>iad!i3> zVFtUaZ&o_*JUeHHl4}BR-=oWc8Gn>d+KK!Lw%>jb&>XokbbX(;Y+?Eter zl#zNv%c$?c=*!%{^mR?b8rxo&4hUIS8>IMAMKrR(k4*$b1OZP#H%=&?2Dd5+cy40k zLK?dUO*xJ3S-7eU!B~zn8*Vp}P=d@g;o$`EeoZv|F0&HHTiO_LbkvN%zlK``fLHEf zHJZ&`Fd5MJ42`4%PVly&8eXL6D_(*oE529(;onds8yb`LXH}{8f;3J95UK;X#RMfh z=}p?sNXV#xO{Kf~m2lXFBheu5$Uxc*Hh4kb93%4X6}Z4+%$evufu6}a&Co!(Kd2U} zAw;ndf`apb+x+84*dLg2xHtlZqUFpGZsXmzg$x5;3=IzMzS3P2L#@TsZ<~0Ja#8hH zhKc@6{bY4{%BFoirL$wR1GaYyc3%c%<|e6HAXb+5UA+u>xg|7j!<<3)_CPH_ zAs4tv19WpHuR``SNJc;%_iGgQ zrN-t{FR`=bb5|XYZL}|WDrfmA7vzw0nJf0z;Z*b)ayuYwNMBN~1 z;v(ll2uZoeyU+YXk2A+PJLH#lHNKDJK=7Xw^-+`VmU@+ z5Sr&*t^!#q5aJ+yf?7d|_m_w1Sx5{8p{O6sT6O{}{lJ`I%wuLzUIj_HWGN>YsXgNQ zqdGJR@{mcTmQW}y;UNmar-2--l-fa=^tBi?HVzH9yB-9mr_9DeIKRCpo=hsc0GTB? zCZPXGuo^Y|6d~|gkz7yvXuvx@qNP&A5B9|{=`zAF2l}Oj7*NL3r%-Cq_6IUYL-(^V zTwrn+uA8Y}-6%?fc=RTaEcE*SaDw+KSh;iQQ0|5th;>pbMvZm?EKL!yqpP>5Bn$#! zrNHG&#K2=Cr&`i4pi5o0+kbk*q$4IG=M?kwENyZ6?aqaVOgfsxLh>vCJP3`$cc#7$ zf4^&`;RZIXqY|0{m$CCpyIUv}EeOwoy4^vtM)$MGf4+Ek42-?*$N+Rw(2472v_b5C zKYj&UkEWF>aEFr8c$9zWgcVy1GZqv*mmtL7P=%tcWGTMDMI`-^2;PFpF#KmMBZI>* zG<2Bpq^6>5O(ce5&>h}(c!oX;|*HS znRH;LNgI!@B;k==DZa@-?d`B-E}bK+&K?58n&aqlXTzyK8H`9fL5i-%&{#h6@)mUMZ2yGxgkm%@RrGvD$ zMw|Qr2+YT32}v(WfV>;}2N)RTic$@F7p(z_9C-70Il7{y1~QkmARj++ z!kc7^u<4euCk1wxWBMDB}>1VL*tCaGC6 zfFLW8xrC~#peSYZ+G^hN8S=j;5-;kPRVr+iMg7~rO#=nv(DgTA*A6aq3^diJTW#G1 zO)R}}&)_J7WEHwAt&XP*NVjk3QSjktFy!COB!SzAbkoTX^V-D z*!Jcv%>kl9S?|Td6JT;}-%vIS+1PM*9Ht&h(Z9?Yb3HB^Bl5N_y{~U5iN~Y^myFA4&vi;ef##lnhOiPq{0uS)fp|A$WuRziBmofPkhk%_J0oN^J|=cKXi6 z@IP1F>lwtU=xI#t%3CLQBx?U10s#A4ID85R#-t2ZUl*$@_FN1r{U*CbWlnzm2Q{J8 z`k$JsQ{sHj>x%k~gJ{HEH~$rkbj~#<66NJ;Fa5qU+eMz1e=iLiz1wkk_cTfRNo@Xs`5Se{(wI6t0X{L?+ z;4eMzl+rba+KlP;jIgQgM}DaDe`jH_+FB7g!%Fs$(&&mTHGfQYt7!kT`GWcNChyxR z_u}pvxYf58G6^(U-?Q!Bq89|puBCz$m|y+iwZh^~013wIz@7wti#)L{?cd^NwXD>f z`(XLX;ifIg@IR*f1iMwe4~F;u;P19`6Khw@Z+ywZ-r&vFm)<7so1m_>L)T>Z2h2i7 zS#RKiJ~1L6bUUjIVKgU1?-r_z1-3vqC{ff3H=F3Ynd!~Cm0AhkHdsPMNoZEm7u%~g z8Hm;AWin%h8sLV9y=pl=Nu`SaVC~c6-q1C!-0>E=Y6t6v?A&DkYUG zaWAdTMCjmD(*zd2fRqY1RfshETd7vR-kbMSZqLf(;YeJoB1+i|w@%skR$M2#EAQ@D z8r-Sc4v43@WK%G%-sjOpbmeG^b!5+9f2w>cd%!UC`0Ssl3dH)RjO)HUsVsHc#-osW zuSKC8Z!fWs>}z!sFx{7kUCCtxZ$4$@a{!2vliydW4;EYUl!+}?6ZAigGr1hM>J04& z)knx_3|(9WwZ1TAuYi`7banII($#=0Jj#C$4f`{iJ9VA3%}kF-`(N!{YfMvT7zWaf zW{B7emmt_ulEPqMt0`+h0TFZrLBo(cOki0DMWG90P(eBeTRCkC1Y`=1`(U655*Y(J z+{&fXOrS<^PGs660fr13<6wZY_k%3>XFr#i>^nbB`{SgSFW-6I_kG^yeNGusBJE81 zBPV5^+HT9R z#1vgsu|!T>zis>#ZcqO}t|PkxCB0&C7q9|M$ErlTU}ZsbK*qY96`K?rK@o9kZigD` z)A~>G&|n-`S0U}SOq;**=X@okuM!c&%rsBE+_56p8x)u`&E4(C`t!Ur3^dAqCECf) z8r55#@byl%VMMVOa)zo6U(rQ6$C>vi+p;ZJX)Z3D3AcPuqZd>}K6EwV={iXed$%l2 zSOfQ~wrv{Mj`G-yuTDnWYKUpOPru2E1JjE;six<4BrS3pBv1icCta`W4G;4Fq7@Cx zwYF>C$ZqPHX@{jx^Au5>Lj<^N1;20s18sa8k zz+8Pl(hhn6OK-gh8IZRb^ts8)U5(=-VU+V+W?WzNQ~NH65LWd+hX^0#UxW6z$34NN z+GUmM`Z?>^^aE1Zxr9Mhx_5L_SX_4S%bssPbTb|`;p^Xr^dT8~C4^@9wEWf*dvKM$_YoA4JQt}+D={?{A_57ik zMre{+0}{LVw6c{x=xqj3xTu+amGU_6c-9DbHrhCni@1n5~`qEuenBZO#BVf zfXIZ$Ka~uMTr^h5pN`gX;e1v#nS;E&bOp@`=?wz?Q~HQc{N1c0hW(5YAMZIy6eKG# z_BX}OD*Nfci>D<|0%tkQ>KnpvbsjBK9Bk7f&m$~mQ)tPzUSMo3IVmdaAulBUUCgltKMva7UU(1ud>eTI?jdu1zY zj6t%TD2z3`tk3%%`d;7X-{-lm-#@?axvp~^=NvJg`*Yv#_iKCKe&@B-+5YDJ8-u~H zojs#+0fYGqzT6nix(WWVrN^TS{;|&Kg8C^8wSG4P{)NTrq}E9cCL?&u;?<4t?|l@IOL-uM7S;Zh^r(rJq$fdGU_PaOcJs{6Bvy{gS!!_R5FTti1O&-A+2=cs)ir zMwa7Hg%^kQq4NhHEXU+=95V4QlxGS1cl59DD}U|$w7j6%HD!6*O6IoA>wTvcqnt)R zFVuF(yN`9edf+tU9+{+3=DiPoIrFdRXZt^`tpD?Goc~~0{`2+z|9y?tg7bgtz}yo5 zTZh$?@xOKW-#Ywn5BzTr{QuemEeYRCCwP4v+mfQZ!o^D$C#0{u_i0Yh2$LR4%}f-_ zX%o_tAIbW?Yjv41q+k{wjELD-@vQcND34oIHQ8V9H_$Sw1YV1-eMhCbn$Nn6<+r;% z!w9(354V1%w6O6?A2fDjBrts0wa@fNy5AV=F7@u(u=)p-=?n}DhrpeG?@l%A=_Ckx z&FytK#2uHkKgwgG2OF1U8E%~@y)c}~y>irLB~8n5;xKA{UwBq;kbL6t{x?!1r7O#fxM0O<_urD)&7Xfp-0u1; znw&pg$u~(JdAMEBgt$|FejtwKFpv z8uOMY@Ln7b_SWq7oHgz$3%&{~_?c2kvbP;BSs2ymkGO3z-><2o*)R?rfaF9%y;QI54cVO06hD(&p3GuuBcxp|@6SOvL-d1bKu%o2q7?|L4S`2J| za`s1gdl^`S;G4F|4?l6~a_!Ihy#IB4T5gxzSVD@palsGzfaf%wU_DtUqeC!qRP9>B zctq)Sd!n0#0uEnbxl=75=)LIZ)*C3(q%hm@94&KJ1(#v`jn0Cfgk!Dgrlnc6M{D9? z>xetVNKKD?lj-!F?X(Uvb~(#;BkyYajlz*8Mp9Jd%vYeTk_;5wRthsfz+uL+e@v-i$+>TosjUyDRhRENXffcqc-|S_2->*INVJv3-IW5`m zzSiWFL=n&0BV}7t2!Hj>CLTk;f|HNCb7Kkvz@nT4PG;u zQ_Blu{bIz#fse$#S5}F(>BTt%F6>uHRO7Sy^f&f?>UQ^zEa?03EEeJ6=p7*tXut6{HhpM9@}k7i@&nk%mRLr`)VXgHPKp8 zz1(7*YKPKGBS-W5BZ;sXl9rbil1|>=^s`t=LC|wb*KPTCKdpGS>-GHfP*|7O!pIaX z_|Ibg-fs@2S`Nk2mmC-2UB}4g>L~ucCV7b}OmxYOx?1)yVYbU%LSej|osszZhKQmL zsbS&J#@=c<%!8mgQrV;JI)Wa*PP)O)pux|JxKT7-IW-U$oG8=nA?3L=-TGUf#8K+q zV^9c3(SK+pB`H#5)Nu7-yyOa`7YQaCdQ-X=`(zlVEAs@Z+Q7G52kcuOJsqVbqGM{J z<;$xNrz-gz;!_gCMH~*z7IrUD=QgZ7*?YPv{<(HI*X1jBdy2J>|9tU#*R(t;m2fZ& zNPGRw>*U9Z7#&UxVwIuUeKZ{Tra1x1lr|oc}1d>A{fP7701>8`r*9`Mg)*MI?)A!bVb07@`)6doGSwRpbwK z7T$JDg|!h^inAXr94jGywFu+9dyio1iE~JUjdQl?U5)r_ILc{RW!vQA^{pasV<|c; zUT~&zh^@xAIlsTm3oIa5eB4ub@GpzkH&A$apqO+7UJ4vtipO`ap$M0aTZ!>{b&)qeoGmGx}Y$%TbD+ zO%M5QTsCqFIQ;HRSG#M0%Sd?1@4nYYfji6>prX7rqW42VKdh*sS2+AmBXcNEz;U^! z$QVkBDr;)O9$gQDhFJE+@g=)=pZ6z}dK>KQ{4AdT<5^Gp<0raCx!%8POq)a~sn4Qx zqvrTC;T?0WOSsdmrzxpw;69Q~bFAVIi_$GcCvXIongLrx?4C1CQ%bAdxz#vevMro- zu3WY7hPzI)d?J=U!>X8-#0fvBRd8E9>baxIqTr)_5n;E0?Uv%fw!MbqJfQj}}i zV9jXEwrzdLt}VN_w7?6xiEXC&2=rK2hatEZiuAqulnT*nPIiJa9CllGj#xE6eoVZGq- z6R$!86H(|I5HP%vZ&8L$c5rh+;Ia1PuR{bw`|P4zFDTFYnZ4z`zx$&a8j?*rdbNTx z>6Z+D7XJ)7-uJSn#CE=*MW9A3*Qm1}sTCNEk7F?Q%KOXQog&pLR$*jbIpX#4G4o)B zOGKXIy(B6B0s+a`f!Wd(&vy8blc6?`>kl^44-~x3QYAY0*B{Uj&%frjvNSu{(iiL0 z^l^*Cn`PLnoDu%*z4h{Ani>+t#LOFtaW*NF+J>r+LROY(_6pBdE=iNIFQ>Qvsmyp` z3=7E_*3OHOoX#Umf2GFVay@``y!=cW^kaqM$$EKL+i#1LQ7f9>i@kzQxEu1*&3Xaj z7Q**+MzD9E@GvgzuS~6w&20I2T(bR;T4=>w9(3Qs4))@euBxm;Y7!x@tP@{N*wmJ@ z<|UecP~$X@?(xi$jujjAd%$IIFfFU;Tt#w5s3Og0-3I?F=jf-DSAI8m!^aLGm>f?x z;9f_84V+E=w|=1fHn#V@8PU{M$gcS!$**u}=9?2fipQ9cn6@rD%)~84T9&I+ucrKE z8IKgfaxf)HTU@MRs4snN|$Ct+3HXH{_$M3KkTS&YKEE|Ag+K0>4}UUf6=~T zoK(H6x#QxyD(Lc2+Dc1Pi?z2JwSI=%Qa|JC5RCDy>Tx;&d#7S{rJP-dBj#O|pm&jU z2eyBPP&$uy+(zE>@f^3wovTzEp+%|wH%@(I3v5fk!Vt8aYC{_#BInh}yv@= z5dU`j8A9-X`$YmOm^6H*eyi5<{D3F=9bsZ{P+k4cU(#ze_4YIg?4qQXw3}@v5A2`% z8D`pNGj#)=x`^zzU;`(*9{HTZqO_3HU*GtY=mcFw9p|l3L6Yhc0wu6 z=&SAg>{!%nj#ewx_%;6!fb$x6!xlhmmg%wWgEpK!-sZis#8ou{L^3r#+A&c zf=*0)vP?HM^V>Jkm4i0!Ykmm<`O!S{vbR^uCNd3NIvlG)N)&T~?VoEM)6a}@2hjMV zIBphd0!>WyhoFamPz-s9v_0WSK5F?FiVa-zumJ0Y%GnrM{Qu6J3?nURBh0)gn;W zdzQaJ!R6If{QaW{>9J4@$&Kq+2ROEf=Up+u9lQP|x`<32xWU11gj!2cLO!q(?g$xJ zsOP!O9k5P}F88rIdfv}LO1iil2FJ;NGYFpXlDgxAft*R`ElI#B@{?;6y$1jhwBM=` z3&36lY;QJSW4e5S_-{(p1r4!~)sCz3C>lW4KZG<;cZ%)B2m=6wkC%=`%<2OmRZD59_9bT(~F)_`h>nTUsPBZoo5vu`3P8? zLb}@HZR(8?HbkMK=8GDg-lu$n)uy4s9ow>F^~rzH_F-6v{sWb|mIGg6T=8N6m#$*n zt{-Y^4o}Nz7fH7mlytO24e}A==THc+A>C<~6eg^ST2qnzZQv>ahI>UW?^IC4J0}$>+ld z?p+8D;$6qJ_i19Q8_^&B-SIVNY}p4hC_N> z)%th7Kd8F?f(|>_*kiMn!s4$oSGp0ABErXitYB0_YlAW>((QM81D)_rG%cB*_^;jdEZ?bOt=X2h9tyS-jh9CcV8$M!Y~F8_K2 zr_*9x^uEx`Lh0=e0Kpn4;YpEhBI)5n?b)^lz=oXg>~UWJ^w%QRNWu2-NEW18?+}S3 z96M?s|8Cn!CBQR=YzY--auRzKR9mA5PI1Ilt+u#1#!fgosv7H}cUivNn_elAS$E9P zgzhobsP2lp!6SR~iV2-`_CTm4=Z7#5#|n6~xFRmy$ou|~2(OAe!V=MpsrjMweybc~ zb!Uvf?hUPqg?2az?bB^g|0Z>L7ZxWQCdp2_;moPNwffNuh(=?qXi|H=!F%~RLY#}K zmCN(3rHS{q$sHt2`_;>6iM{(I!)O>!qiA(*x8h4mrd zqdC$F+yFux2OHzm$2&Vgc+iUftisWvi(JqAF@~?^6uuA_O^D|Ld>RJc-0AVN ze!zL@6W+WLH~7Y>{%nnSpAyG>V9#%o^aX}==i zdYc4$Ywq#HNU7y00OYD@i)Bi4P!?44{y8OWF7=)s`Bvvu*`OlbXC{e>x~~5j-E1CQJ!cy&Z9s-?0t}rLK6XMiutJ z87F(#@~(KjW06Bp{j_xyrY};}E(7nJv?(tx21eg!m2hU5M_2vJI*tblHkz~iDfrm`2E$s z745*Wn;;~LufI912!PfvcFP5pbCF*2j49w69Q=lnfJ>)92uXx?uum|5vf15h20nyz z!->fs*&pY z-xGm1$HSq@7`SnC&>XY}4R|AjZ~&nbly+*i_#t~;moA|qj;ka$!2pSpJB?2*GAg(< z0>lfh8(e#;%4Ek#^h3&ef1C@|twD!K|LRb>bPLb^JxZ$KgcML?(M$SPaRV2m606mo z(49(=WM%zfBX=!cizcoBzthkpa7ViJym4SV_IiBcx@cBc#8^>}coKLvDT`;4lmBH; z9uoWwuH4-?5n1U4TLP&}9DAkK_JBIt1NCsufU-m@0{|HCYHa=zb9$0&&&$g@F<6DO zYkNBdn6{6+|D$*>wEGKO^GGV0B%7-qh)V2>bRTU7#$omYuhDr`uDWd)Bb`&PZ)H>S z`zum~HKpoaP{LVndBP6L7a_ES^g~#*2^u}GoQf0$CxRLM}psOw{p_AqBkh+&-s=wevm7XJ=&{xS%r@Jy`xg5)MBhcQ`=YJ5NORiGqmH31FK zC(7Ck0&)F)mZ-nl6?nSQhSXa8;0?muXW04n4kDEYaCokRyb(MOQq;$~m$bA_jF+eA zL@DO;${dE%=8AWMNBDuSas{$KK~B6q*2N^;^fm(5P3s0+CMfoRSUNUqZ4koKT6~&; zj$Cdp9?GI=*HCU*^pC+A)Hd~;##7tHE2~tKA`(MEvM;jfL~^7hfEADcjf-voEjR1T zT4?y^x#lxeG>vdMqXk2K_&PS3j`NEPfGm>$p1r*s%n{dJeeVwcUbQ~sn;$l!N~Gdg zzq-qk!P>c!ItNw8UsoA94P6%iZ4YJ5ZJtO(dMg2k)Lav~1K3*PBLy@Qc+vLrP-DU< zIr;E*Cdrn7J#b9SIGXI9p+_ibWUc-7T)pnt&0`bVF^&9>-Lr!?EIeiF2go1Xx~~-=Y^KGZ5G;0 zV${;GRfS;IYkwuLD7V3seBR=BPtRGH-!gCl+#i%PdB*(>ur_8<+H9nlvE3kbfsxPh4oOS zD9#zGFTssy?5-9+0$tLT-Ui4$f>2j6kcvDravu;U2dW&rriYc;aq7{g-=7df!n+(tcMdEk6x4y7k#i`l6o2-C(dckFxDL3M@F_ zR|6 zUD~cbGNOa=z{fyJINq~lWqCo!_hL&OB2aad`Bbng>(-xc>^yw$0aF-1dWzFVF+)!6 zr%F=TQPeYEuly?cu!#@gp7>5m5)X$sm{e1uE;A%6I1t~G7!AA-QxO5njaKO30H z0GQAHJs~lc@AKiz+GiBU8l;aB0#)DkfIeD>uR)(E3z}gPtVa^-)Qblkp$0Z7uq6Eg zU_0j9d{94@HL!jp`@K^VZ5oPwh?*Jkv^OVZSIhIy5lt2ZT2n}c5i8@j~ zxdFPS3GcAqs978`bQ#kp$a#X{{^u_m)qvQ$f$%C%+|15o(aRH#_e2ZqlfG;a!#Sc> zafpu%a{SnK%f4mJAmjfJgB;$ zpOBIxxUW}^fl6h-_gSWDw^P;~9hEQp>eX2+!(F=mYP3Fd@04SZM8QC8QTG0OO5=s8 z3e}Z9sxPfCHXb^7Pbck_bBjK$CqN>Sg59*0=LrF4p_IN)qIB_=W8EA0Uln7$1JYcr zIvQrCzBpiwJw*wLX?wNS_A{F?Z}sxKzexnI$=BWS-XQCMLNQ)7%34(}8$IK{?KF7q zH|L>+Ooa9cy~p<6@7c~6fAlLcc7qm+Pk7Lf|IKq>Us7}tw`F!EeBHe*;+NYW96TjH zo^M{OOY>3ILq@pc@=ykpW!%si_Pwv&PVLQXP;}4SCcOQ`FJ*(P4>)hp-`z20u~%a= z2=P0jw|HP*L3-9d_jUnR)Pyq9v6KHswaRsKaK^>t-jp8?%uof&Cg*7OW+b>Ot}aQPTg{ zW#Ua&U#~1vm(HmcfJ%Lf z-tlSdpL$c$g8$euQx1I{aOA3y4EBk2@Z6}?8^_9~ZV6%4w<&hDrh1L94u3Qjdj(x0 zU`U?&)J z((x4;WLsH$DWq}}jwIJg&i?f~(;j%6rRr%2XREn{h_GLM$@-Mvks~cJ@1_oPbq(xAr>cDmFw3!1nz3(j2A_~it_I@P9ZKHVZ#+KUg=BcTmDN+{_jAJ@5SJH?T-M@UsaYtrciCh75$u?01p57FJr@Ct3sAK zaqu`2!GPc6eO+Rubky5Gee>^SlB${kRrQyw7fHkOG_d%3x`TFp2m%(JGH_I?AVVq6 ze~%W)$HqZDMDVolTeDOGvBx_2jxlM_Kf_+k@5UL(Md(on**inGo%r=$2-?@|OOGl< zGO%ra-b0eDMou9?(tLCq%xb^B^uKXZ(je957-&yTPHtsvGC%P7c}YT9JI&i- zYjoUIc8o{g-zHMYJ_9O@gMBGrsw3&)uc2%OEW`^q3TC-PWLqo}9zVf0tj2ebaGDOte*dPk!wx7hN{-4R}9zHQ)| zJw;vtNIFWS5T$>r8vL{cB@_2|*=qD`AD66WAUlW8?(NAgx!5hAl4FJIUY0aKc!WbZ zQRvE!F$&J9R#F|S_SmV};7Rm8i%tz>tQXlBzj>}(@hOD~HWVF~&0gpcv3|-rw%sQm zM*-b2|Hg_(Ng^St7Wh#Zte#yQC6g>(EjYbC4V;f(Je+a=XVPhpHb z-BG&PYh|Ik-)5@k_7Dg;ro6jJ3rIj{zYgct|YoG2O4G&c<^jdTxV;^rX2pTnK?_(s^n%RAUK5ew9TRO~R&sntuuA6@YcNN<4laY-9R82_( zk@fsol6B4Fn4{yrh1zzSzudHK_vPL4r&JsL4wO8aE3#*hnlHYo8Q|p*e&5qJ{>lo_ zOzd+F7T@ZULe>{WfGjHRP+6s$zttsadXxYljJqQ^KG_@Y*TCHy8fxOkSWL|cnB}<} z$$F1X;6&aXv=pjG4t6;hNsaH~2A73tg%O;obBette$n_hldJ)xlsui@yuCquv!)ue z*0w#%fk8Us%RL>QAe>fY@95TIVec)PX3!2OxexQWYL)ZkvdUJ>(j&)gK0VpX0Od@) zWQDcad8j3g_3xbiBI#);f}AlKvSX4$Z8HD;8n*fHyQ0&`e= zR(lmDI&;@Ll(T34_5US|_hlQqmbC7l49)vs4Ge2EKa0=m55({gfSYBNv9QlguiE68 z_jw;o->y?L_dk^Qi4u;o9qDV|`)?I}HP6Qd^=}I!AsN z)pw8K$^8qn?uZF;5t*4UqrkUcPHjnmjed-C2ifNZ2=TtGZKSu3RjLW2%H`sDp4qy)lgdRgE+#5@UE@c#ZJ{FJRgsUDn}>kUo< zY^{XENe0AdG*E169uQU&BF9kl3#0+1aYX0|VKP4cEgFxK0Hr%Cjm>vr+9B6SgWnrP z!R7#dhu{MD&%q>Sk_{y%=Z7;JCPJ|&ca+uX@@>tTzziG)p^;Joc03XCQ{2H|^B;2H zFFus`QYa1NFl)#cihWc*LbY+gTz~Jg&KgKc4c;7*XIjREE_HOBhC@kjo&i%xH=?IP z_J;v*t^QB6Odm~qNJFRTkB2fO1Lx4o{_hpvy{8`{c|`O{;rBjj$komQ7dQzbkctk6WFUieUFWFlt$az6x& zG*O-*;Cs~B0};~9pc4v$0%X&2gO3_8s)$rwpmn+aH>*(uZw7Ku(q&tveh}y$P(};d znytZO3;d|`9X^9-LEe`P$fQOR?AiC`0V0q>NX;7D6OGcvpAs}!F~xe90+B+O*lz^) z!$^Jxo9G;TqZ4x*f=~DwCE}(aD<`hBs$gISGyzhsuzMFNG2)+t&p~35hvgg+7-zqF zA3)r3e(2PyGOwS;I(rN0oM@m(pDtEBauMYjK-;I69^RGyI`&z9Rh~f)|j9fnH#zn+pywvL8IEOJMkH8&c zk|i`j+NVkG)_FKgdPcp-a6 z|C^BKtAQs#Qrx)v1YozrUS36EdDP08?5(ToG`$0JZ@dG7QV}Q;4fLWd9UKZpf>I=F zTL!vj!*(5}D%)_<{y9@g-j+6jtm5O*Hm& z6BNV9D9Mjtu!SIH+N?;Q1*gV&G8)%%S$HI`H;94gR#$rgEL?%CC5xchKX_j@@KiF2 zaxEcTDfV$QvZBXdspH^dagO0W8d?O&4JHd=juHpH2xYy6BOQ+dy<_}XasU2u$#Abk z*(ekx7^EfXbTt`~o)rR8qJggXY7|Z*GnS?hSmA1XJ?4S`*kEqyl08;=h!x9`Km4wy z3H0n&P*_WZI*yTLC75w&urWwoXH+Boq z?4iLN|K9S2e2Dopf!=*VF47J}gEJ`Ih!P^q>_G0Z88~r?;J)R~QG3JvSDH(qDKdaO z)ivw67<;hb~AS%=`$P?z5)n?lu62WHz)`>^_JeobI z3vvdU{}IQ)}+@IH2FYxMQu5 z!c}W92IM~x`S2lRX0u~p>j%!rc7zLiPEg8In}}^&F*oRb-e2Tc#`g>$3r}oRD2pXM@sWdYT!g zO3$tW&+gkVSo*%W=H1}_B{T?r3x@dHKc)9`^5Lwaq_D1AZHoYew@#LUy4v;&wn3jT zeGDAa>n=qg{T+l@DL7yUc##Z;Vx<`X38ahQ(EX;buH=_|-rQhJrKse71~|gC_&QWv zQJl%hxnzK4XM{qFsrOQ>?OAstSUqdxATeF6Ca*@-edQTQ_nQJCkHc9Z_H?ZcC9TD- zygj+c{d&88d~s}mPO+L7RkjM+?=8vpWE`4CFrn{;u3Ry_(>x2bZ%R?NJxbEWKCc79 z^eQ*2?&>4{OT-yJNB!x7AI~%{beDM2Ak&U-w@8vwO^TUY^ai#RU>hSA+k3$yXg~!= z4lU>>**9(^i^baN8M#B9basPRFxfJ%8kRIrjv@!4%i^|_r?Vpf*bIHp#KgITN0%ecQ%)$4J<1+s}pcP{w<3l znCF|I=||?ajKL{A3%Md~$@)}H63U{b+`?J9%?!UH#BoQ7s%cjoq~6`Ixi4)xU{5nL z2rq4rey(}+>|j^1dpMYq0nQp`yY)yBwiILrRGP!fphheQYrLHdT>bSI!Bd_$i2T%Pk$qNS6?{a+*M50yWm!T=Gyz0B z`4O;@KsN_pMFSOl$0YinGuM((J<7hI-w840)S_u3BSd@(L&@NzL6n9rNR1@R8Un>!x>*#74$H2 zpql!O)6zj`WyKtGF9IX+_pXQ`s3ZqHm0(!I^mM7$5=13upySINh7^246^ap-L1t${ z%FqRfW@w35a}}7Q9ls#-(oc}S{pIB5kP<4IvDp>J-F@<_q#|JUMN&>cl+s|v{+Czo zsX3oO*vzt@0Z-|W2Tg^KDWO~VLW3OkPJazykbto=*#MvtpX5^hnVHI<3FBQ zrUzE-)Hp2J?*0o7uk{?n6uSnTA!^a!UQ^+^Yx?(i@@#RawOi^P1R~%M8O#qO-@FWb zim)j9ySY>}I>wN^bouIo#nhJUsRhgCD%4MYp%?=}dIqqH^e~{@gmgpL8Izf-r8e4$ zXWgdWjCC6}fh$UiwW;Ar3EJ7Iu!`bqA%chK5tX8G_JmBqZE#+WqCm+z_;Ab5DKi1O z8jTO)!F+YqZ~~5}X}vjNpoBf*bfpSWVDKO_Jb+zZo-IXSipq2L7->V5+GZwOJx}xS9VUkkn(PzCdx9 zjSKqhuY0@kuauNLYOG$vz~~2nxAABUXF!o73RjZpR?tP-5<8^RA*@wlRSHul%dHj3 zIHb*w^CLFts!@lscPIvIlx<3i4;acwnBIvi(=AF9e^3vOegt_i)|{qb0m z01ETE!DIz*;K3nH$71i_Kf}P6hd$&#ZaVG%^rqyzDD}5n89^y0Z~N!sG%4?2=nva@$@10p|w)!kSS5BZAwV!w`_j|j| zZQ9;mWdI!bgs%e-8p>r%Y&4=v$kA0~!V_aftDua%1}ip5(PAuPA3B8Cqt=74DxWEi z>ck_*2b1G&(Or8MHNlt9Cm$Np#F1f~iqrU3xW7+}U1nVXYdgFtjPKu^+=)vNv3Q71x7E~A|FZDO@td9$dRbBMJLA!vZ;1RE?nf1&OdD@!J=AhM54diR~pAs_sd%i*FlHd6Jrf#x&R1Imr`k_t!4%)|2EuD1i->dcBqu z;pJqd#OfejE`eQ!iEnOI7m;_ho?3@Q8j~g2c6M2J05A~yvg>HiBZD;;VTC59C{fgR z4JEKs`|t~5K;&HUNKfd)FSYaekhBf7K(k`LxG%5JdpkyD@iBoZts>Yok+e%#^7TQW zke?|T>8Z~@p-8;V;xCjXK>3DFlq`o@rU6d1F>`*abY*Fb>2L-s&L33D^pZS9Nm2Bi z|3S}7x9jK(<}V*SEK&69lnMRtYLszwZO>HRMvp7X=P3xHo=T ze{(bvoKVh@VBQTWwkL=M8_{1B=jPa0v$UciW>L9nq|KplN~{xY-R9j-(1Zn=k}k?M z57{VRt#%}kQoY^*meAE?iI~mtiSgLIcz9u~7PD5@7TcJorSSF`guT31mR)f(s(X@R zV)hbnC>CjwZTeLb(a-&0nHfnY#>UlvUJ{NhGn8y9avlbxoDK<_VP0NB$i^FVZy4=Y-yz`oH-DKQ|l)frW;;9@U#DM;w`8Mc8GyrDC zEbqg4jb)-x%s<@*P0AMW&W0G@$8W`CPu~&ibmwr$l!M0o% zk;6Fm@w|Pf&5tlK%wQudO28?&&(u;J4Xrl%w2PkNgWRkU)duQK{uFSt1mwvxT|3*F z_Q~Tl)G(+f5UcjI`0xTz#`MZaL3xZc2v(sk4rpFyg1iJCMnVxe<^TN|oIt43H^I3; z&FQDN<-#Z@W%xtWOzvfvQZO1IZQ1)5oc2#?f)gc%=hGseMHbhv< zgnj~|2(GwM(Jh@J59o63!H|%#m~~V4WvdBdjws=mDyJ9Lp4|Xu!h7>ks$(j+3yfbi zGy&^`a}h(p0`CN*AuQ+@nLzS&8;E%XvJ~jWaDvkk_IyOAfS^Pj*hy~&2D+NWq90Iu zpN-dl{7=C)Hhwv2n01F#UeVz0)hHB7Oq(xxi54cxEx3s+48wSJ4Ugw$G+bg`^>#pQ zjeGQNS+|F$0clqZcu-fW4T`~J0cPM@ad`nE)vvAV1 zrkukhCyeVOkY}=#hsH1 z11vjMI4_*{`A~{N=dDm!7w966x6CKLGLr{nW>z6KKsNL6aR@0d7-`*Yf2)09l%~c;b5< zFl(P&GIpkCL9nZzoG}oei6-ok*ymvV`i>{DM;4;#{so8M@AOVa&LAY~KaiLVaoYO& z^)m=Y&jYgqk^>Hb7@PuNYGQ2XPC)7fvbu=RLMZM^stLB^@g5!b^%B@+ee*yZtPCjl z&7EiW%dMn>UK4SwkD7v_N6w;l14NK2 zVUqGvKG_vI9}NwlQs&D)<(e)H66)?*H7ba%S6)5tM-(B*^S3&`^F^RW`M2n8X!e%N z=;j9^NFa$Yt9-)2UZ2DXd6fYFe;XivAA$Uq+4w2&MIh`uzIg$~-hmHu?vvxF5L{3{ z(De;um6yxFL;J;W*qacSeQ*oU24cWv6Z#t%)Dw#=tG{@xau7-IXc~`dFat9coH3cG zIyhJthOW0osa))SYbI$0UG~)!>dRsg5~q%!xoDw>KP5C>$h0~J& z#4fJwSb?^hMXMh1q)4IZU}NMqU z?7Fsrd6d93d@yj#31p5im%skHzlrS}>fAJdn=e}+(bW??jWTKlNNEI>?jnnqkP3&e zmnHOJvyMyp>d)R$k6lINA7yWx=xvbMT9H85f{~h8FS34%RxzAj25juJP)L8R$gu^I zktpm=2}e`n={6=%%43Hfs4BqCsRBJkr;cFiyI-c7wlI!uV{=QM#781I<4xmjp+2T!@C z1>$YNyF!{LbH0{-*)I6)Rgal>Pj5MPmS2Cb%BBAgvyItmEk?@1PXD8$^ahKwNlI+q z;|{fj2Khz$!7EL=eK5QkJ5XIHdZb%MYCJh(J;G&+q?uX8NJ2kTR$73xl0kQ@@uzlKFe718zj9xK23= zj+qrQZJcnYimF)cv(;JDwLxisSS-Llu9L5UpmD^d^|%K+>S>+kN3n^_jGK*)HZa=w z8DG<5fJT7=ZW?GHyHLoEz12yd5HX;_-u*iYI=|Z8Y`4;+cTPLZi_qxwPqH(%o!7WE zp2wBzLq6+<>=yohZ-my9MpIT z32m9!`;JRWQ(sQ!uK|k;jm>+apRzJkW`kKT5#vFyrt-AX4CWxj9UodL|A5s|Wj2(j z7hNHf&AaTU{2t=crnl#;jM$B}g?7-NvD!$F%;~k@EbNZ=JQnu9dGXbpSM2FJ*anx0 zOMW}f(q?lY7r}KkYR2Cd_fZ}xUZBML-WU3$$F=N-HA2xl43C(q(Lg$kPSm>57 z!rfcaBj+Ht$i6PI@qza#;%GPopWwiJdQ$i4mky619AHuZZHkgYZ}%Yu6uS+nj5N@{ zX*P2QsAYMrLu@On1?;^}AaXK^7JhHFNi46?XM??$uW#48oG*ZHPA@|(>#@Yb!krME%4LBln zO<>xLSiwo)K!eV5W7hh0%QUH?oUe#7!^eF zT7aW5_KlyD%kIYqk7J6+)KBxqjNE>wV5 zl}VOWkK5v*irHVV3C&0cDlUL!{E{HtydV(1=~`^2mf`8kk8w?j0T9yqGL+KvMSKQw#InFHyXw2kSi*EU67h zQo?H#U5*f?U}^TF2@-t9q(J}kr-}O3>A+68s{9?*u*27FG1o6TlDwAYIeVX&N$VAr zvNn`k1@F*Q=vOEyL>GSyJmVNkh?DPT>aXskMlA%-us8goRf*3)mktSk@Xx6?V?0A# ztppZ_%Bgu*0Gj^FpTVgzBn2WR2D=sPg9L+OwI1GpArU!R)=zhTNju3PF_l(wo@J$q zM|$JkA#k@2b?JFLoQo7b%sD11CthJS$co+LKRFFTPZHc5z&(4Btb}kaik)nDn8(R$8*Qj zxn-f@mdGP(JSr>f4|Bs{F22NGSzUV!=KR(5%K!WN|MWT-^Dc{~ubWE;N+@OwaLO7+ z$*cjh|7)yi9jU=;3uX*u4j*sANY9WdN({0y2 zJ^2$M@o@~;rmXxOy1^NggkXj~LPNEVd|+0RteyUG~7K8}UjZPFv?g%F|IhqB_kpRe`KW*)Mn74p6 zr)h+VyW-r?)OI^e^!|t(CVmc1>o)o6PWM@;IKUb#UtO=Yi`@gJ|{}1dw}> z&724-l_FdXgf7(?ph`_#hHHT|kS^Wz?RW{8%Tr+Zi=hDH2-Hqylm=2AHST;15VY}s zt9QZy!B?bQjJvJ%JtWaAi$3=QP@iaJm;$sBn7IM$;>5h=3100BF6i&g z5M?e($^b@w0Oi7*gU_#}daf+OHNM2hDCmR+So6uR02|RDgBwDLDq$V6gUQl_h$kqK z#=MgYB>6(-SatAZwZfbGm8`6!Y*$ z5iNTdE=o}k7RaAxEYPBsUm%gwDDVi%WucP=^15op<+q9GWn{rbOgtJTw+E2mYFh`l zD;cg$NMn4CqG6hR5Q}L@$*PCo7i?WXCuf*kXqq+)uY5JOf&)IGG&Fcm8b<3lPsYIP zjgrHz7?Ac50a?SY7@tbmdCpo7G5_U!DjnWg4Z{V3KH{=!F}M zeNR&0mKa2x<3Wj4bok8(n4~v@9v+qh?As`?3tcX@Dt#Nlu0;-7!8 z3t&|eSX}u$y_|QW;6e9~fTF{Ivmv(rBvRzPT+D6LvM(Xrb^$Vq6QNNha9R@K*Mcp) zS>O%~z&ng&w`wDijLr%Is0A~LwzkWn)iA6BN05eIfc7*xF-(=!dGQyhBZ=s0Hyd9- zG$+vB1!titLBjwPT+kI_MAm-9^>gqecECY(M8qGZ!zM$=Yd~~>t0O@q@i56Y_Du=* zpZrtdk&w;bgPcz!?eM}y6J01S(6CUL3rNAWV@+`WK1wK6_kyUn3DX-G*8;QJn?%(PRxd!pL8LT(bx0X8$QjIAh)(iG}xf zM$qk!2=am9&BPvGXwLwyC-E$xGVoIj$7i3V+lWn0tL{?w4Ge;`q7i)z<#yzNxjNxK zBJn{Sgb1VTRLE*G;93jF=s-(xov)DadP?box~AB2UkAW_L`OeU zZXssZ$aejyD%WR28{~=sT$TB0v-o9Kr>oGlKX+%N1xrxl#{8|Pg~KD?zKO|Bn-@oK zmx@+C4BU=_u1JS73gkzZ-?T#j<3HyMhkAw^i~s@9wgxo{ZoYs)hETLbMoU>}95i8X zGIAAp;x3K#A`xWuYQ7QJvf5}w2EA0~&3g!gqK)fuZSBn@qnRu4$d*b4V11*SFc6L3 z{T$@b5b;y!_BFV+1u&~M$U?~r89)h=Q0oG{>aZBBTE(4gNDIj#I~=v=diAw}uzJp> zT`+&6KqtBs5{8*0?9dG=aAMFs0&5qNIzj{JoLDto*7On#k2^Y~_J3g>46MJ{#~f0H zNiiYjrAi=-BI^}qND9|J{}nsvZRfIa7-`UJ6F_Lf5pd9v?I95we2ZT24)X=5$}56B z?dyjai!kG3={5pz3B;f7<&y!)>x1+b%=tF>pYTDTuxmgM)TSD=#;FGvkzGL!pn(%} z3m*k%SYm0Rdj;|t2Vn>urMf{zsr_@jKqn2 zc(+bCH>Aa)9rA5AFRvaJ6Ar}ylsQ0Af6OS%>JRe6G6!m?HfE$&Fjt;YLeY&6=vC*F zfA448?OhU7= zSwPVff#C`}{P!E*mJL@;CP36(j(|gf2owNvqQ8UL#=Ysh^5Bv-0hWqnuKzxCy=+Xf z`HxmqN|D!7bO5DF_NB||fd8kV?uF#-C8)@nC`jjqm^zHcO-A;idkAg-+sbNCT!@cU zaOa8|>4ppB3Lt?uu{O(&iIzld7bOIl=mNb7f*881GX$|~Bb*CZ1c_)jXo22q4behP zbSib#!`|rDLFg3x`Ww~we&l*;sNa2nPytfwtsm~PJcG*gfAY=fa@#C8%ZXsSG1~+4 zK3e3~@WQ1fUKZz&hwx{bK-nCst*y*m02jafKkZyiNK|1I zeGJm5p=d}`A|ZjgvEU7_DQ)2(Iv}NjD1>CAGcx|YAVC)sBH_V+aq z2%&-t$%P`$2trUQIHVLfi_{jOo%@*Cv~D+N^LX%PGxxjq+l2O5&0c-1+ds+O4QOv zEpUkGV9K_> zfj07ds7dG)ZdHTIcz^MDaIOJf>VCS{Zwum@^|iR7hIs&+cS*=u4dg?($#J>pw&jjV z8chyNxMxMQ4jomKbU!x>)5o4`ZH8Q5B2#Az5wJ4n&3N!9dH58Px{&SM6)_dOqDAeF z!9@USB3zGUrWTNTCm zLW%XAN`ocMG&&xANzT}7T5eQ`#vj8Zv<7`cVWbc@2n9?Nk|LQjSwgTXV8uu%fCUHz zgaSeVp@2{T3lItj1%v`Z0ii%FK-!R80UHFw0dEip1%v`Z0il3Zfmnby2&4^J6(A0% lIUy7f3J3*+f`6)l#>dvX7nXx5Roj>3OIc|}$xLy5&tDlA{1E^E literal 0 HcmV?d00001 diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/OneOrZeroCaseRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/OneOrZeroCaseRule.png new file mode 100644 index 0000000000000000000000000000000000000000..2aa2c91f5e09ffdef37afa1e0f9c2f27e01d0ae8 GIT binary patch literal 36679 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 JO_h?f>t7AgHs=5U literal 0 HcmV?d00001 diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/SurroundPairDirectRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/SurroundPairDirectRule.png new file mode 100644 index 0000000000000000000000000000000000000000..0d4aa11db818fdee5e10559f8f13e7fadfefcea5 GIT binary patch literal 37015 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/ThreeAdjacentOnesContradictionRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/ThreeAdjacentOnesContradictionRule.png new file mode 100644 index 0000000000000000000000000000000000000000..aefacb6ae82ccbab764b867781f22b6bd781fbf3 GIT binary patch literal 52347 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 bR*aM05}2c!Ju;H2XWmt+4A-X)Jh literal 0 HcmV?d00001 diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/ThreeAdjacentZerosContradictionRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/ThreeAdjacentZerosContradictionRule.png new file mode 100644 index 0000000000000000000000000000000000000000..4199e7f176fc32903ca84b92d015d8877a20744c GIT binary patch literal 52375 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

<7q||v7G5P(!KZzu<6r*cZ}SV6)%O;bEqCws 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/UnbalancedColumnContradictionRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/UnbalancedColumnContradictionRule.png new file mode 100644 index 0000000000000000000000000000000000000000..17a658e427c7ef23f941f0185f764a75b9c7f58d GIT binary patch literal 50546 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 literal 0 HcmV?d00001 From 84bb1a2054963837834ff4ec920e875f8c1bef80 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Tue, 12 Mar 2024 17:38:08 -0400 Subject: [PATCH 032/258] Fixed checkStyle error --- .../java/edu/rpi/legup/puzzle/binary/BinaryElementView.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryElementView.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryElementView.java index 012ca2261..5086b2453 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryElementView.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryElementView.java @@ -22,7 +22,8 @@ public BinaryElementView(BinaryCell cell) { public BinaryCell getPuzzleElement() { return (BinaryCell) super.getPuzzleElement(); - }@Override + } + @Override public void drawGiven(Graphics2D graphics2D) { BinaryCell cell = (BinaryCell) puzzleElement; BinaryType type = cell.getType(); From 35ef7599f0b677cf6b9a739e223c890cda590193 Mon Sep 17 00:00:00 2001 From: Brandon McCusker Date: Fri, 15 Mar 2024 16:12:13 -0400 Subject: [PATCH 033/258] Changed Direct Rule --- .../legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java index 3454ac88f..33a7dcb58 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java @@ -20,7 +20,7 @@ public CompleteRowColumnDirectRule() { super("BINA-BASC-0003", "Complete Row Column", "If a row/column of length n contains n/2 of a single value, the remaining cells must contain the other value", - "edu/rpi/legup/images/nurikabe/rules/CornerBlack.png"); + "FILL IN WITH IMAGE"); } /** * Checks whether the child node logically follows from the parent node From c4c8a506c8a5dc4c34c0d3744532cfab4e38fc19 Mon Sep 17 00:00:00 2001 From: EggyMath <55564321+EggyMath@users.noreply.github.com> Date: Fri, 15 Mar 2024 16:26:30 -0400 Subject: [PATCH 034/258] Added new images to represent case rules Created and applied formatted images to case rules to help better show how case rule functions. --- .../PossibleCellsForNumberColumnCaseRule.java | 2 +- .../PossibleCellsForNumberRegionCaseRule.java | 2 +- .../rules/PossibleCellsForNumberRowCaseRule.java | 2 +- .../sudoku/possible_cells_number_column.png | Bin 0 -> 3336 bytes .../sudoku/possible_cells_number_region.png | Bin 0 -> 3623 bytes .../images/sudoku/possible_cells_number_row.png | Bin 0 -> 803 bytes 6 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 src/main/resources/edu/rpi/legup/images/sudoku/possible_cells_number_column.png create mode 100644 src/main/resources/edu/rpi/legup/images/sudoku/possible_cells_number_region.png create mode 100644 src/main/resources/edu/rpi/legup/images/sudoku/possible_cells_number_row.png diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberColumnCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberColumnCaseRule.java index 22f768313..b6ea1be21 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberColumnCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberColumnCaseRule.java @@ -23,7 +23,7 @@ public class PossibleCellsForNumberColumnCaseRule extends CaseRule { public PossibleCellsForNumberColumnCaseRule() { super("SUDO-CASE-0004", "Possible Cells for Number - Column", "An empty cell has a limited set of possible numbers that can fill it.", - "edu/rpi/legup/images/sudoku/possible_cells_number.png"); + "edu/rpi/legup/images/sudoku/possible_cells_number_column.png"); } /** diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberRegionCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberRegionCaseRule.java index 62bc9a74d..f12a9fb0b 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberRegionCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberRegionCaseRule.java @@ -20,7 +20,7 @@ public class PossibleCellsForNumberRegionCaseRule extends CaseRule { public PossibleCellsForNumberRegionCaseRule() { super("SUDO-CASE-0002", "Possible Cells for Number - Region", "An empty cell has a limited set of possible numbers that can fill it.", - "edu/rpi/legup/images/sudoku/possible_cells_number.png"); + "edu/rpi/legup/images/sudoku/possible_cells_number_region.png"); } /** diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberRowCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberRowCaseRule.java index 5da0158a6..6d434ed5a 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberRowCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberRowCaseRule.java @@ -23,7 +23,7 @@ public class PossibleCellsForNumberRowCaseRule extends CaseRule { public PossibleCellsForNumberRowCaseRule() { super("SUDO-CASE-0003", "Possible Cells for Number - Row", "An empty cell has a limited set of possible numbers that can fill it.", - "edu/rpi/legup/images/sudoku/possible_cells_number.png"); + "edu/rpi/legup/images/sudoku/possible_cells_number_row.png"); } /** diff --git a/src/main/resources/edu/rpi/legup/images/sudoku/possible_cells_number_column.png b/src/main/resources/edu/rpi/legup/images/sudoku/possible_cells_number_column.png new file mode 100644 index 0000000000000000000000000000000000000000..2ebdc582364e4afc93c26d2e41548abf30456ed8 GIT binary patch literal 3336 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 SmU`#_0000uJ@VVD_U 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/edu/rpi/legup/images/sudoku/possible_cells_number_row.png b/src/main/resources/edu/rpi/legup/images/sudoku/possible_cells_number_row.png new file mode 100644 index 0000000000000000000000000000000000000000..80476a42820b213907af74ce76c96424a103b862 GIT binary patch literal 803 zcmeAS@N?(olHy`uVBq!ia0vp^DImV7lw+;uumf z=j~kEJgGntH+%OuhDZmoi4$WaPKH{U2a1`9YM){XaxLQWP7#cBh~o10Yjx^4&V1(k zgF7F~r6xG|Pp|$`SMmATxvRel|E_6xcy}o?$A2M310@!>mIECE5`s+1P6;j?JsgdN zw%=OcEwgr)$?y95xaz~^K*eOs8M+I!;Hlq$@iDW2kKmOj`3V_dO{b+#AWK6n|M}E5P11zN!Ub1 zQDG(7`FFgGmNYpnIXpSWw=E>3!(`r@E~6!foR&OX5l0AR_{`y}D+-{TV;{Rs_-QDFn=lPnv+ACit z!nbeZxLN<9^S7hMx>wh9 zAAtmTB6ZEb%@OrHzlqUu({e(~Cm3Z<`mh=YLWD)Q!J) z)xH;a(o@{Mde_#{sZak*T)QfI`wPiQ>+9C1p2+&De0NLN<;c6cPW~6@toGdMI_KQ0 zYhsGeJ@zH<$P!J@+JAlqIK=yAIqMa&z7<(@>qN^^MF)8F(Ut f1vEJ2J?7VB=2_pOylEaV)iZdy`njxgN@xNAzyM-G literal 0 HcmV?d00001 From 7c51f189d4a463d625edab7d139e9e9120ccadca Mon Sep 17 00:00:00 2001 From: Brandon McCusker Date: Fri, 15 Mar 2024 16:49:45 -0400 Subject: [PATCH 035/258] Create MyWikiContributions --- MyWikiContributions | 54 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 MyWikiContributions diff --git a/MyWikiContributions b/MyWikiContributions new file mode 100644 index 000000000..80f3bf914 --- /dev/null +++ b/MyWikiContributions @@ -0,0 +1,54 @@ +# Binary +Binary is a grid based puzzle game akin to Sudoku. You are given a grid of empty squares and squares filled with 1 or 0. Your task is to fill the board with 1s and 0s while adhering to the rules of the game. + +Each binary puzzle has a unique solution. It is always possible to make a next step by reasoning. In other words, the solution can always be found without guessing. + +### Interacting with the Binary Board +Clicking on a white square fills it with a 0 + +Clicking on a square with a 0 fills it with a 1 + +Clicking on a square with a 1 returns it white + +# Rules +### Here are the direct rules of the puzzle +1) Each square should contain either a zero or a one. +2) Three orthogonally adjacent zeros or ones is not allowed. +3) Each row and each column should contain an equal number of zeros and ones. +4) Each row is unique and each column is unique. Thus, any row cannot be exactly equal to another row, and any column cannot be exactly equal to another column. + +# LEGUP Proof Rules + +## Case Rules + +### One or Zero + +This rule is a direct consequence of rule #1. If a tile can be filled with a 0 or a 1 based on the current state of the board, create a split in the tree where the tile is a 0 in one path and 1 in the other to show two possible cases. + +## Contradiction Rules + +### Three in a Row + +This rule is a direct consequence of Rule #2. If a sequence of three of the same digit exists on the board, then the board is in a state of contradiction. + +### Unbalanced Row/Column Rule + +This rule is a direct consequence of Rule #3. If a row or column contains more of one digit than the other, then the board is in a state of contradiction. + +### Identical Row/Column Rule + +This rule is a direct consequence of Rule #4. If a row is identical to another row or a column is identical to another column, then the board is in a state of contradiction. + +## Direct Rules + +### Surround Pair + +This rule is a direct consequence of Rule #2. If two of the same digit exist adjacent to each other in any given row or column, then in order to avoid violating Rule #2, the pair must be surrounded with other digit on both sides. + +### One Tile Gap + +This rule is a direct consequence of Rule #2. If two of the same digit exist with a one tile gap between them, then in order to avoid violating Rule #2, the pair must be separated by placing the other digit between them. + +### Complete Row/Column + +This rule is a direct consequence of Rules #2 and #3. If a row or column is completely filled with 1s and 0s, there does not exist a grouping of three 1s or 0s anywhere in the row, and From 197f078d05b32fcb716b8959ca71a578f4e1815c Mon Sep 17 00:00:00 2001 From: Brandon McCusker Date: Fri, 15 Mar 2024 16:50:37 -0400 Subject: [PATCH 036/258] Rename MyWikiContributions to MyWikiContributions.md --- MyWikiContributions => MyWikiContributions.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename MyWikiContributions => MyWikiContributions.md (100%) diff --git a/MyWikiContributions b/MyWikiContributions.md similarity index 100% rename from MyWikiContributions rename to MyWikiContributions.md From 8eaff04b7fef7d9bee480e1e88cd07d2e0dd7579 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Fri, 15 Mar 2024 17:00:59 -0400 Subject: [PATCH 037/258] Combined each of the contradiction rules into one file rather than two separate files --- .../DuplicateColumnsContradictionRule.java | 49 ------------ .../rules/DuplicateRowsContradictionRule.java | 49 ------------ ...plicateRowsOrColumnsContradictionRule.java | 78 +++++++++++++++++++ ...va => ThreeAdjacentContradictionRule.java} | 42 ++++++---- .../ThreeAdjacentOnesContradictionRule.java | 47 ----------- .../UnbalancedColumnContradictionRule.java | 50 ------------ ...balancedRowOrColumnContradictionRule.java} | 46 ++++++++--- .../binary/rules/binary_reference_sheet.txt | 9 +-- 8 files changed, 143 insertions(+), 227 deletions(-) delete mode 100644 src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateColumnsContradictionRule.java delete mode 100644 src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsContradictionRule.java create mode 100644 src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsOrColumnsContradictionRule.java rename src/main/java/edu/rpi/legup/puzzle/binary/rules/{ThreeAdjacentZerosContradictionRule.java => ThreeAdjacentContradictionRule.java} (50%) delete mode 100644 src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentOnesContradictionRule.java delete mode 100644 src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedColumnContradictionRule.java rename src/main/java/edu/rpi/legup/puzzle/binary/rules/{UnbalancedRowContradictionRule.java => UnbalancedRowOrColumnContradictionRule.java} (51%) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateColumnsContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateColumnsContradictionRule.java deleted file mode 100644 index fb69040aa..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateColumnsContradictionRule.java +++ /dev/null @@ -1,49 +0,0 @@ -package edu.rpi.legup.puzzle.binary.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.binary.BinaryBoard; -import edu.rpi.legup.puzzle.binary.BinaryCell; -import edu.rpi.legup.puzzle.binary.BinaryType; - -import java.util.Set; -public class DuplicateColumnsContradictionRule extends ContradictionRule { - private final String NO_CONTRADICTION_MESSAGE = "Does not contain a contradiction at this index"; - private final String INVALID_USE_MESSAGE = "Column must have a value in each cell"; - - public DuplicateColumnsContradictionRule() { - super("BINA-CONT-0006", - "Duplicate Columns", - "There must not be two columns that are duplicates", - "edu/rpi/legup/images/binary/rules/DuplicateColumnsContradictionRule.png"); - } - - @Override - public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { - BinaryBoard binaryBoard = (BinaryBoard) board; - - BinaryCell cell = (BinaryCell) binaryBoard.getPuzzleElement(puzzleElement); - Set col = binaryBoard.getCol(cell.getLocation().x); - BinaryCell[] colArray = col.toArray(new BinaryCell[0]); - int size = col.size(); - int x = cell.getLocation().x; - for (int i = 0; i < size; i++) { - if (i != x) { - Set currCol = binaryBoard.getCol(i); - BinaryCell[] currColArray = currCol.toArray(new BinaryCell[0]); - for (int j = 0; j < size; j++) { - BinaryCell colElement = colArray[j]; - BinaryCell currColElement = currColArray[j]; - if (colElement.getType() == BinaryType.UNKNOWN || currColElement.getType() == BinaryType.UNKNOWN) { - return super.getInvalidUseOfRuleMessage() + ": " + this.INVALID_USE_MESSAGE; - } - if (colElement.getType() != currColElement.getType()) { - return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE; - } - } - } - } - return null; - } -} diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsContradictionRule.java deleted file mode 100644 index 1b83c9690..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsContradictionRule.java +++ /dev/null @@ -1,49 +0,0 @@ -package edu.rpi.legup.puzzle.binary.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.binary.BinaryBoard; -import edu.rpi.legup.puzzle.binary.BinaryCell; -import edu.rpi.legup.puzzle.binary.BinaryType; - -import java.util.Set; -public class DuplicateRowsContradictionRule extends ContradictionRule { - private final String NO_CONTRADICTION_MESSAGE = "Does not contain a contradiction at this index"; - private final String INVALID_USE_MESSAGE = "Row must have a value in each cell"; - - public DuplicateRowsContradictionRule() { - super("BINA-CONT-0005", - "Duplicate Rows", - "There must not be two rows that are duplicates", - "edu/rpi/legup/images/binary/rules/DuplicateRowsContradictionRule.png"); - } - - @Override - public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { - BinaryBoard binaryBoard = (BinaryBoard) board; - - BinaryCell cell = (BinaryCell) binaryBoard.getPuzzleElement(puzzleElement); - Set row = binaryBoard.getRow(cell.getLocation().y); - BinaryCell[] rowArray = row.toArray(new BinaryCell[0]); - int size = row.size(); - int y = cell.getLocation().y; - for (int i = 0; i < size; i++) { - if (i != y) { - Set currRow = binaryBoard.getRow(i); - BinaryCell[] currRowArray = currRow.toArray(new BinaryCell[0]); - for (int j = 0; j < size; j++) { - BinaryCell rowElement = rowArray[j]; - BinaryCell currRowElement = currRowArray[j]; - if (rowElement.getType() == BinaryType.UNKNOWN || currRowElement.getType() == BinaryType.UNKNOWN) { - return super.getInvalidUseOfRuleMessage() + ": " + this.INVALID_USE_MESSAGE; - } - if (rowElement.getType() != currRowElement.getType()) { - return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE; - } - } - } - } - return null; - } -} diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsOrColumnsContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsOrColumnsContradictionRule.java new file mode 100644 index 000000000..17dd4b631 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsOrColumnsContradictionRule.java @@ -0,0 +1,78 @@ +package edu.rpi.legup.puzzle.binary.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.binary.BinaryBoard; +import edu.rpi.legup.puzzle.binary.BinaryCell; +import edu.rpi.legup.puzzle.binary.BinaryType; + +import java.util.Set; +public class DuplicateRowsOrColumnsContradictionRule extends ContradictionRule { + private final String NO_CONTRADICTION_MESSAGE = "Does not contain a contradiction at this index"; + private final String INVALID_USE_MESSAGE = "Row or column must have a value in each cell"; + + public DuplicateRowsOrColumnsContradictionRule() { + super("BINA-CONT-0003", + "Duplicate Rows Or Columns", + "There must not be two rows or two columns that are duplicates", + "edu/rpi/legup/images/binary/rules/DuplicateRowsContradictionRule.png"); + } + + @Override + public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { + BinaryBoard binaryBoard = (BinaryBoard) board; + boolean rowValid = false; + boolean colValid = false; + BinaryCell cell = (BinaryCell) binaryBoard.getPuzzleElement(puzzleElement); + Set row = binaryBoard.getRow(cell.getLocation().y); + BinaryCell[] rowArray = row.toArray(new BinaryCell[0]); + int size = row.size(); + int y = cell.getLocation().y; + for (int i = 0; i < size; i++) { + if (rowValid) { + break; + } + if (i != y) { + Set currRow = binaryBoard.getRow(i); + BinaryCell[] currRowArray = currRow.toArray(new BinaryCell[0]); + for (int j = 0; j < size; j++) { + BinaryCell rowElement = rowArray[j]; + BinaryCell currRowElement = currRowArray[j]; + if (rowElement.getType() != currRowElement.getType()) { + rowValid = true; + } + } + } + } + if (!rowValid) { + return null; + } + Set col = binaryBoard.getCol(cell.getLocation().x); + BinaryCell[] colArray = col.toArray(new BinaryCell[0]); + size = col.size(); + int x = cell.getLocation().x; + for (int i = 0; i < size; i++) { + if (colValid) { + break; + } + if (i != x) { + Set currCol = binaryBoard.getCol(i); + BinaryCell[] currColArray = currCol.toArray(new BinaryCell[0]); + for (int j = 0; j < size; j++) { + BinaryCell colElement = colArray[j]; + BinaryCell currColElement = currColArray[j]; + if (colElement.getType() != currColElement.getType()) { + colValid = true; + } + } + } + } + if (!colValid) { + return null; + } + + return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE; + + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentZerosContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java similarity index 50% rename from src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentZerosContradictionRule.java rename to src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java index 503bc7752..7b5a079c1 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentZerosContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java @@ -5,14 +5,14 @@ import edu.rpi.legup.puzzle.binary.BinaryBoard; import edu.rpi.legup.puzzle.binary.BinaryCell; import edu.rpi.legup.puzzle.binary.BinaryType; -public class ThreeAdjacentZerosContradictionRule extends ContradictionRule { +public class ThreeAdjacentContradictionRule 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 zero"; + private final String INVALID_USE_MESSAGE = "Contradiction must be a zero or one"; - public ThreeAdjacentZerosContradictionRule() { + public ThreeAdjacentContradictionRule() { super("BINA-CONT-0001", - "Three Adjacent Zeros", - "There must not be three adjacent zeros in a row or column", + "Three Adjacent", + "There must not be three adjacent zeros or three adjacent ones in a row or column", "edu/rpi/legup/images/binary/rules/ThreeAdjacentZerosContradictionRule.png"); } @@ -21,7 +21,7 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { BinaryBoard binaryBoard = (BinaryBoard) board; BinaryCell cell = (BinaryCell) binaryBoard.getPuzzleElement(puzzleElement); - if (cell.getType() != BinaryType.ZERO) { + if (cell.getType() != BinaryType.ZERO && cell.getType() != BinaryType.ONE) { return super.getInvalidUseOfRuleMessage() + ": " + this.INVALID_USE_MESSAGE; } @@ -34,14 +34,28 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { BinaryCell downTwo = binaryBoard.getCell(cell.getLocation().x, cell.getLocation().y-2); BinaryCell downOne = binaryBoard.getCell(cell.getLocation().x, cell.getLocation().y-1); - if ((upTwo.getType() == BinaryType.ZERO && upOne.getType() == BinaryType.ZERO) || - (leftTwo.getType() == BinaryType.ZERO && leftOne.getType() == BinaryType.ZERO) || - (rightTwo.getType() == BinaryType.ZERO && rightOne.getType() == BinaryType.ZERO) || - (downTwo.getType() == BinaryType.ZERO && downOne.getType() == BinaryType.ZERO) || - (leftOne.getType() == BinaryType.ZERO && rightOne.getType() == BinaryType.ZERO) || - (upOne.getType() == BinaryType.ZERO && downOne.getType() == BinaryType.ZERO)) { - return null; + if (cell.getType() == BinaryType.ZERO) + { + if ((upTwo.getType() == BinaryType.ZERO && upOne.getType() == BinaryType.ZERO) || + (leftTwo.getType() == BinaryType.ZERO && leftOne.getType() == BinaryType.ZERO) || + (rightTwo.getType() == BinaryType.ZERO && rightOne.getType() == BinaryType.ZERO) || + (downTwo.getType() == BinaryType.ZERO && downOne.getType() == BinaryType.ZERO) || + (leftOne.getType() == BinaryType.ZERO && rightOne.getType() == BinaryType.ZERO) || + (upOne.getType() == BinaryType.ZERO && downOne.getType() == BinaryType.ZERO)) { + return null; + } + } + else if (cell.getType() == BinaryType.ONE) + { + if ((upTwo.getType() == BinaryType.ONE && upOne.getType() == BinaryType.ONE) || + (leftTwo.getType() == BinaryType.ONE && leftOne.getType() == BinaryType.ONE) || + (rightTwo.getType() == BinaryType.ONE && rightOne.getType() == BinaryType.ONE) || + (downTwo.getType() == BinaryType.ONE && downOne.getType() == BinaryType.ONE) || + (leftOne.getType() == BinaryType.ONE && rightOne.getType() == BinaryType.ONE) || + (upOne.getType() == BinaryType.ONE && downOne.getType() == BinaryType.ONE)) { + return null; + } } return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE; } -} +} \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentOnesContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentOnesContradictionRule.java deleted file mode 100644 index 164f50c4e..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentOnesContradictionRule.java +++ /dev/null @@ -1,47 +0,0 @@ -package edu.rpi.legup.puzzle.binary.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.binary.BinaryBoard; -import edu.rpi.legup.puzzle.binary.BinaryCell; -import edu.rpi.legup.puzzle.binary.BinaryType; -public class ThreeAdjacentOnesContradictionRule 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 one"; - - public ThreeAdjacentOnesContradictionRule() { - super("BINA-CONT-0002", - "Three Adjacent Ones", - "There must not be three adjacent ones in a row or column", - "edu/rpi/legup/images/binary/rules/ThreeAdjacentOnesContradictionRule.png"); - } - - @Override - public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { - BinaryBoard binaryBoard = (BinaryBoard) board; - - BinaryCell cell = (BinaryCell) binaryBoard.getPuzzleElement(puzzleElement); - if (cell.getType() != BinaryType.ONE) { - return super.getInvalidUseOfRuleMessage() + ": " + this.INVALID_USE_MESSAGE; - } - - BinaryCell upTwo = binaryBoard.getCell(cell.getLocation().x, cell.getLocation().y+2); - BinaryCell upOne = binaryBoard.getCell(cell.getLocation().x, cell.getLocation().y+1); - BinaryCell leftTwo = binaryBoard.getCell(cell.getLocation().x-2, cell.getLocation().y); - BinaryCell leftOne = binaryBoard.getCell(cell.getLocation().x-1, cell.getLocation().y); - BinaryCell rightTwo = binaryBoard.getCell(cell.getLocation().x+2, cell.getLocation().y); - BinaryCell rightOne = binaryBoard.getCell(cell.getLocation().x+1, cell.getLocation().y); - BinaryCell downTwo = binaryBoard.getCell(cell.getLocation().x, cell.getLocation().y-2); - BinaryCell downOne = binaryBoard.getCell(cell.getLocation().x, cell.getLocation().y-1); - - if ((upTwo.getType() == BinaryType.ONE && upOne.getType() == BinaryType.ONE) || - (leftTwo.getType() == BinaryType.ONE && leftOne.getType() == BinaryType.ONE) || - (rightTwo.getType() == BinaryType.ONE && rightOne.getType() == BinaryType.ONE) || - (downTwo.getType() == BinaryType.ONE && downOne.getType() == BinaryType.ONE) || - (leftOne.getType() == BinaryType.ONE && rightOne.getType() == BinaryType.ONE) || - (upOne.getType() == BinaryType.ONE && downOne.getType() == BinaryType.ONE)) { - return null; - } - return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE; - } -} diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedColumnContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedColumnContradictionRule.java deleted file mode 100644 index 5f747e275..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedColumnContradictionRule.java +++ /dev/null @@ -1,50 +0,0 @@ -package edu.rpi.legup.puzzle.binary.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.binary.BinaryBoard; -import edu.rpi.legup.puzzle.binary.BinaryCell; -import edu.rpi.legup.puzzle.binary.BinaryType; - -import java.util.Set; -public class UnbalancedColumnContradictionRule extends ContradictionRule { - - private final String NO_CONTRADICTION_MESSAGE = "Does not contain a contradiction at this index"; - private final String INVALID_USE_MESSAGE = "Column must have a value in each cell"; - - public UnbalancedColumnContradictionRule() { - super("BINA-CONT-0004", - "Unbalanced Column", - "Each column must contain an equal number of zeros and ones", - "edu/rpi/legup/images/binary/rules/UnbalancedColumnContradictionRule.png"); - } - - @Override - public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { - BinaryBoard binaryBoard = (BinaryBoard) board; - - BinaryCell cell = (BinaryCell) binaryBoard.getPuzzleElement(puzzleElement); - Set col = binaryBoard.getCol(cell.getLocation().x); - - int size = col.size(); - int numZeros = 0; - int numOnes = 0; - - for (BinaryCell item : col) { - if (item.getType() == BinaryType.ZERO) { - numZeros++; - } - else if(item.getType() == BinaryType.ONE) { - numOnes++; - } - } - if (numZeros + numOnes != size) { - return super.getInvalidUseOfRuleMessage() + ": " + this.INVALID_USE_MESSAGE; - } - if (numZeros != numOnes) { - return null; - } - return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE; - } -} \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowOrColumnContradictionRule.java similarity index 51% rename from src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowContradictionRule.java rename to src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowOrColumnContradictionRule.java index c1fc3f286..7c8074eba 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowOrColumnContradictionRule.java @@ -8,15 +8,15 @@ import edu.rpi.legup.puzzle.binary.BinaryType; import java.util.Set; -public class UnbalancedRowContradictionRule extends ContradictionRule { +public class UnbalancedRowOrColumnContradictionRule extends ContradictionRule { private final String NO_CONTRADICTION_MESSAGE = "Does not contain a contradiction at this index"; - private final String INVALID_USE_MESSAGE = "Row must have a value in each cell"; + private final String INVALID_USE_MESSAGE = "Row or column must have a value in each cell"; - public UnbalancedRowContradictionRule() { - super("BINA-CONT-0003", - "Unbalanced Row", - "Each row must contain an equal number of zeros and ones", + public UnbalancedRowOrColumnContradictionRule() { + super("BINA-CONT-0002", + "Unbalanced Row Or Column", + "Each row or column must contain an equal number of zeros and ones", "edu/rpi/legup/images/binary/rules/UnbalancedRowContradictionRule.png"); } @@ -28,23 +28,45 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { Set row = binaryBoard.getRow(cell.getLocation().y); int size = row.size(); - int numZeros = 0; - int numOnes = 0; + int rowNumZeros = 0; + int rowNumOnes = 0; for (BinaryCell item : row) { if (item.getType() == BinaryType.ZERO) { - numZeros++; + rowNumZeros++; } else if(item.getType() == BinaryType.ONE) { - numOnes++; + rowNumOnes++; } } - if (numZeros + numOnes != size) { + if (rowNumZeros + rowNumOnes != size) { return super.getInvalidUseOfRuleMessage() + ": " + this.INVALID_USE_MESSAGE; } - if (numZeros != numOnes) { + if (rowNumZeros != rowNumOnes) { return null; } + + Set col = binaryBoard.getCol(cell.getLocation().x); + + size = col.size(); + int colNumZeros = 0; + int colNumOnes = 0; + + for (BinaryCell item : col) { + if (item.getType() == BinaryType.ZERO) { + colNumZeros++; + } + else if(item.getType() == BinaryType.ONE) { + colNumOnes++; + } + } + if (colNumZeros + colNumOnes != size) { + return super.getInvalidUseOfRuleMessage() + ": " + this.INVALID_USE_MESSAGE; + } + if (colNumZeros != colNumOnes) { + return null; + } + return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE; } } \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/binary_reference_sheet.txt b/src/main/java/edu/rpi/legup/puzzle/binary/rules/binary_reference_sheet.txt index b0fcae407..c8cb0d1b9 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/binary_reference_sheet.txt +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/binary_reference_sheet.txt @@ -2,11 +2,8 @@ BINA-BASC-0001 : SurroundPairDirectRule BINA-BASC-0002 : OneTileGapDirectRule BINA-BASC-0003 : CompleteRowColumnDirectRule -BINA-CONT-0001 : ThreeAdjacentZerosContradictionRule -BINA-CONT-0002 : ThreeAdjacentOnesContradictionRule -BINA-CONT-0003 : UnbalancedRowContradictionRule -BINA-CONT-0004 : UnbalancedColumnContradictionRule -BINA-CONT-0005 : DuplicateRowsContradictionRule -BINA-CONT-0006 : DuplicateColumnsContradictionRule +BINA-CONT-0001 : ThreeAdjacentContradictionRule +BINA-CONT-0002 : UnbalancedRowOrColumnContradictionRule +BINA-CONT-0003 : DuplicateRowsOrColumnsContradictionRule BINA-CASE-0001 : OneOrZeroCaseRule \ No newline at end of file From e2b4a9696e80c5cbd1e6d8c9d3469039924ef0d8 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Fri, 15 Mar 2024 17:04:17 -0400 Subject: [PATCH 038/258] Fixed checkStyle error in ThreeAdjacentContradictionRule --- .../puzzle/binary/rules/ThreeAdjacentContradictionRule.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java index 7b5a079c1..c048c2871 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java @@ -34,8 +34,7 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { BinaryCell downTwo = binaryBoard.getCell(cell.getLocation().x, cell.getLocation().y-2); BinaryCell downOne = binaryBoard.getCell(cell.getLocation().x, cell.getLocation().y-1); - if (cell.getType() == BinaryType.ZERO) - { + if (cell.getType() == BinaryType.ZERO) { if ((upTwo.getType() == BinaryType.ZERO && upOne.getType() == BinaryType.ZERO) || (leftTwo.getType() == BinaryType.ZERO && leftOne.getType() == BinaryType.ZERO) || (rightTwo.getType() == BinaryType.ZERO && rightOne.getType() == BinaryType.ZERO) || @@ -45,8 +44,7 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { return null; } } - else if (cell.getType() == BinaryType.ONE) - { + else if (cell.getType() == BinaryType.ONE) { if ((upTwo.getType() == BinaryType.ONE && upOne.getType() == BinaryType.ONE) || (leftTwo.getType() == BinaryType.ONE && leftOne.getType() == BinaryType.ONE) || (rightTwo.getType() == BinaryType.ONE && rightOne.getType() == BinaryType.ONE) || From 2bf9bfb60a199cf7eeb7e541e5a85a49be6c8bbe Mon Sep 17 00:00:00 2001 From: Brandon McCusker Date: Fri, 15 Mar 2024 17:22:24 -0400 Subject: [PATCH 039/258] Wrote prelim OneZeroCaseRule --- .../binary/rules/OneOrZeroCaseRule.java | 49 ++++++++++++++++++- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneOrZeroCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneOrZeroCaseRule.java index 63af9d3e6..21f0b3cbb 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneOrZeroCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneOrZeroCaseRule.java @@ -23,17 +23,62 @@ public OneOrZeroCaseRule() { @Override public String checkRuleRaw(TreeTransition transition) { + List childTransitions = transition.getParents().get(3).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."; + } + + BinaryCell mod1 = (BinaryCell) case1.getBoard().getModifiedData().iterator().next(); + BinaryCell mod2 = (BinaryCell) 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.getType() == BinaryType.ZERO && mod2.getType() == BinaryType.ONE) || + (mod2.getType() == BinaryType.ZERO && mod1.getType() == BinaryType.ONE))) { + return super.getInvalidUseOfRuleMessage() + ": This case rule must an empty white and black cell."; + } + return null; } @Override public CaseBoard getCaseBoard(Board board) { - return null; + BinaryBoard binaryBoard = (BinaryBoard) board.copy(); + CaseBoard caseBoard = new CaseBoard(binaryBoard, this); + binaryBoard.setModifiable(false); + for (PuzzleElement element : binaryBoard.getPuzzleElements()) { + if (((BinaryCell) element).getType() == BinaryType.UNKNOWN) { + caseBoard.addPickableElement(element); + } + } + return caseBoard; } + @Override public ArrayList getCases(Board board, PuzzleElement puzzleElement) { - return null; + ArrayList cases = new ArrayList<>(); + Board case1 = board.copy(); + PuzzleElement data1 = case1.getPuzzleElement(puzzleElement); + data1.setData(BinaryType.ZERO.toValue()); + case1.addModifiedData(data1); + cases.add(case1); + + Board case2 = board.copy(); + PuzzleElement data2 = case2.getPuzzleElement(puzzleElement); + data2.setData(BinaryType.ONE.toValue()); + case2.addModifiedData(data2); + cases.add(case2); + + return cases; } @Override From 439f7a547bdcab35f386f2a9539ed2bab5c19088 Mon Sep 17 00:00:00 2001 From: EggyMath <55564321+EggyMath@users.noreply.github.com> Date: Fri, 15 Mar 2024 17:27:14 -0400 Subject: [PATCH 040/258] Fixed Last Cell for Number Direct Rule Last Cell for Number Direct Rule was almost completely re-written to improve functionality and minimize playing errors. --- .../rules/LastCellForNumberDirectRule.java | 125 ++++++++++++++---- 1 file changed, 102 insertions(+), 23 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/LastCellForNumberDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/LastCellForNumberDirectRule.java index 51d963247..ad393ee42 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/LastCellForNumberDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/LastCellForNumberDirectRule.java @@ -31,52 +31,131 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem SudokuBoard finalBoard = (SudokuBoard) transition.getBoard(); SudokuCell cell = (SudokuCell) finalBoard.getPuzzleElement(puzzleElement); + + //Check if empty cell placed if (cell.getData() == 0) { return super.getInvalidUseOfRuleMessage() + ": Cell is not forced at this index"; } - int size = initialBoard.getSize(); - + //Get defaults Set region = initialBoard.getRegion(cell.getGroupIndex()); Set row = initialBoard.getRow(cell.getLocation().y); Set col = initialBoard.getCol(cell.getLocation().x); - boolean contains = false; - if (region.size() == size - 1) { - for (SudokuCell c : region) { - if (cell.getData() == c.getData()) { + //Check if new cell conflicts group + for(SudokuCell c : region){ + if(c.getData() == cell.getData()) + return super.getInvalidUseOfRuleMessage() + ": Cell is not forced at this index"; + } + for(SudokuCell c : row){ + if(c.getData() == cell.getData()) + return super.getInvalidUseOfRuleMessage() + ": Cell is not forced at this index"; + } + for(SudokuCell c : col){ + if(c.getData() == cell.getData()) + return super.getInvalidUseOfRuleMessage() + ": Cell is not forced at this index"; + } + + //// + //Loop to see if the number is constrained to the cell + boolean restrained = true; + for(SudokuCell c : region){ + //Test if its not a valid testing cell + if(c.getData() != 0) + continue; + if(c.getLocation().y == cell.getLocation().y && c.getLocation().x == cell.getLocation().x) + continue; + //Check if cell is eligible to hold number + Set crow = initialBoard.getRow(c.getLocation().y); + Set ccol = initialBoard.getCol(c.getLocation().x); + boolean contains = false; + for(SudokuCell rc : crow){ + if(rc.getData() == cell.getData()) { + contains = true; + } + } + for(SudokuCell cc : ccol){ + if(cc.getData() == cell.getData()) { contains = true; - break; } } - if (!contains) { - return null; + //Stop if another cell can hold number + if(!contains) { + restrained = false; + break; } } - if (row.size() == size - 1) { - contains = false; - for (SudokuCell c : row) { - if (cell.getData() == c.getData()) { + //Output if success + if(restrained) + return null; + + //// + //Loop to see if the number is constrained to the cell + restrained = true; + for(SudokuCell c : row){ + //Test if its not a valid testing cell + if(c.getData() != 0) + continue; + if(c.getLocation().y == cell.getLocation().y && c.getLocation().x == cell.getLocation().x) + continue; + //Check if cell is eligible to hold number + Set cregion = initialBoard.getRegion(c.getGroupIndex()); + Set ccol = initialBoard.getCol(c.getLocation().x); + boolean contains = false; + for(SudokuCell rc : cregion){ + if(rc.getData() == cell.getData()) { contains = true; - break; } } - if (!contains) { - return null; + for(SudokuCell cc : ccol){ + if(cc.getData() == cell.getData()) { + contains = true; + } + } + //Stop if another cell can hold number + if(!contains) { + restrained = false; + break; } } - if (col.size() == size - 1) { - contains = false; - for (SudokuCell c : col) { - if (cell.getData() == c.getData()) { + //Output if success + if(restrained) + return null; + + //// + //Loop to see if the number is constrained to the cell + restrained = true; + for(SudokuCell c : col){ + //Test if its not a valid testing cell + if(c.getData() != 0) + continue; + if(c.getLocation().y == cell.getLocation().y && c.getLocation().x == cell.getLocation().x) + continue; + //Check if cell is eligible to hold number + Set cregion = initialBoard.getRegion(c.getGroupIndex()); + Set crow = initialBoard.getRow(c.getLocation().y); + boolean contains = false; + for(SudokuCell rc : cregion){ + if(rc.getData() == cell.getData()) { contains = true; - break; } } - if (!contains) { - return null; + for(SudokuCell cc : crow){ + if(cc.getData() == cell.getData()) { + contains = true; + } + } + //Stop if another cell can hold number + if(!contains) { + restrained = false; + break; } } + //Output if success + if(restrained) + return null; + + //Output fail return super.getInvalidUseOfRuleMessage() + ": Cell is not forced at this index"; } From 24bae33a4ae94282cc530350391478a23089fa98 Mon Sep 17 00:00:00 2001 From: EggyMath <55564321+EggyMath@users.noreply.github.com> Date: Tue, 19 Mar 2024 17:35:25 -0400 Subject: [PATCH 041/258] Fixed LastNumberForCell Direct Rule LastNumberForCell allowed any number to go into a cell if the cell only had one option for number. I.e if the last option was 9 you could put any number 1-9 in cell, this patch fixed that error --- .../rules/LastNumberForCellDirectRule.java | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/LastNumberForCellDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/LastNumberForCellDirectRule.java index 28e64ce7b..f38543cc9 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/LastNumberForCellDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/LastNumberForCellDirectRule.java @@ -31,28 +31,37 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem SudokuBoard initialBoard = (SudokuBoard) transition.getParents().get(0).getBoard(); SudokuBoard finalBoard = (SudokuBoard) transition.getBoard(); - int index = puzzleElement.getIndex(); + //Assign basics int groupSize = initialBoard.getWidth(); int groupDim = (int) Math.sqrt(groupSize); + + //Get position info + int index = puzzleElement.getIndex(); int rowIndex = index / groupSize; int colIndex = index % groupSize; - int groupNum = rowIndex / groupDim * groupDim + colIndex % groupDim; + int groupNum = (rowIndex / groupDim) * groupDim + (colIndex / groupDim); + + //Create hashset of all numbers HashSet numbers = new HashSet<>(); for (int i = 1; i <= groupSize; i++) { numbers.add(i); } + + //Run through region, row, col to see contradicitng numbers for (int i = 0; i < groupSize; i++) { SudokuCell cell = initialBoard.getCell(groupNum, i % groupDim, i / groupDim); numbers.remove(cell.getData()); } for (int i = 0; i < groupSize; i++) { - SudokuCell cell = initialBoard.getCell(i, colIndex); + SudokuCell cell = initialBoard.getCell(i, rowIndex); numbers.remove(cell.getData()); } for (int i = 0; i < groupSize; i++) { - SudokuCell cell = initialBoard.getCell(rowIndex, i); + SudokuCell cell = initialBoard.getCell(colIndex, i); numbers.remove(cell.getData()); } + + //Check if plausible if (numbers.size() > 1) { return super.getInvalidUseOfRuleMessage() + ": The number at the index is not forced"; } @@ -61,7 +70,9 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem return super.getInvalidUseOfRuleMessage() + ": The number at the index is forced but not correct"; } } - return null; + if(numbers.toArray(new Integer[1])[0] == puzzleElement.getData()) + return null; + return super.getInvalidUseOfRuleMessage() + ": The number at the index is forced but not correct"; } /** From d888a773e56c5309d779f8a3c44c6b3bd93638b2 Mon Sep 17 00:00:00 2001 From: EggyMath <55564321+EggyMath@users.noreply.github.com> Date: Fri, 22 Mar 2024 16:41:37 -0400 Subject: [PATCH 042/258] Fixed Case & Contradiction Rule PossibleCellForNumber Case rule was only generating branches for and as the value 1 and no other values. Repeated Numbers Case rule was always triggering contradiction since it was taking the empty tile value of 0 in to account with other numbers. --- .../rules/PossibleNumbersForCellCaseRule.java | 4 +- .../RepeatedNumberContradictionRule.java | 54 ++++++++++--------- 2 files changed, 32 insertions(+), 26 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleNumbersForCellCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleNumbersForCellCaseRule.java index f355695ac..e577a4c3b 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleNumbersForCellCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleNumbersForCellCaseRule.java @@ -82,10 +82,10 @@ public ArrayList getCases(Board board, PuzzleElement puzzleElement, int v List caseCells = new ArrayList<>(); SudokuCell cell = (SudokuCell) puzzleElement; - for (int i = 0; i < 9; i++) { + for (int i = 1; i <= 9; i++) { Board newCase = sudokuBoard.copy(); PuzzleElement element = newCase.getPuzzleElement(puzzleElement); - element.setData(value); + element.setData(i); newCase.addModifiedData(element); cases.add(newCase); } diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/RepeatedNumberContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/RepeatedNumberContradictionRule.java index 4a5cc2074..a0801d5f3 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/RepeatedNumberContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/RepeatedNumberContradictionRule.java @@ -27,39 +27,45 @@ public RepeatedNumberContradictionRule() { */ @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { + //Get board to check SudokuBoard sudokuBoard = (SudokuBoard) board; - SudokuCell cell = (SudokuCell) sudokuBoard.getPuzzleElement(puzzleElement); - if (cell.getData() == 0) { - return super.getNoContradictionMessage(); - } - Set region = sudokuBoard.getRegion(cell.getGroupIndex()); - Set row = sudokuBoard.getRow(cell.getLocation().y); - Set col = sudokuBoard.getCol(cell.getLocation().x); + //Loop all group indexes + for(int i = 0; i < 9; i++) { + //Get regions and sets to check duplicates + Set region = sudokuBoard.getRegion(i); + Set regionDup = new HashSet<>(); + + Set row = sudokuBoard.getRow(i); + Set rowDup = new HashSet<>(); - Set regionDup = new HashSet<>(); - Set rowDup = new HashSet<>(); - Set colDup = new HashSet<>(); + Set col = sudokuBoard.getCol(i); + Set colDup = new HashSet<>(); - for (SudokuCell c : region) { - if (regionDup.contains(c.getData())) { - return null; + //Check for non zero duplicates to trigger contradiction + for (SudokuCell c : region) { + if (c.getData() == 0) + continue; + if (regionDup.contains(c.getData())) + return null; + regionDup.add(c.getData()); } - regionDup.add(c.getData()); - } - for (SudokuCell c : row) { - if (rowDup.contains(c.getData())) { - return null; + for (SudokuCell c : row) { + if (c.getData() == 0) + continue; + if (rowDup.contains(c.getData())) + return null; + rowDup.add(c.getData()); } - rowDup.add(c.getData()); - } - for (SudokuCell c : col) { - if (colDup.contains(c.getData())) { - return null; + for (SudokuCell c : col) { + if (c.getData() == 0) + continue; + if (colDup.contains(c.getData())) + return null; + colDup.add(c.getData()); } - colDup.add(c.getData()); } return super.getNoContradictionMessage(); From 46857372dafe0401d2c66797b05f65f2e520ec68 Mon Sep 17 00:00:00 2001 From: kchiu1 <152306707+kchiu1@users.noreply.github.com> Date: Fri, 22 Mar 2024 16:46:37 -0400 Subject: [PATCH 043/258] No cell for number no number for cell Unfinished but pushing --- .../NoCellForNumberContradictionRule.java | 41 ++++++++------ .../NoNumberForCellContradictionRule.java | 56 +++++++++++++++++++ 2 files changed, 81 insertions(+), 16 deletions(-) create mode 100644 src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoNumberForCellContradictionRule.java diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberContradictionRule.java index a308e1dfc..11376d1a2 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberContradictionRule.java @@ -3,6 +3,7 @@ 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.sudoku.Sudoku; import edu.rpi.legup.puzzle.sudoku.SudokuBoard; import edu.rpi.legup.puzzle.sudoku.SudokuCell; @@ -12,8 +13,8 @@ public class NoCellForNumberContradictionRule extends ContradictionRule { public NoCellForNumberContradictionRule() { - super("SUDO-CONT-0001", "No Cell for Number", - "Process of elimination yields no valid numbers for an empty cell.", + super("SUDO-CONT-0001", "No Cell for Number (Region)", + "Process of elimination yields no valid numbers for an empty cell in a region.", "edu/rpi/legup/images/sudoku/NoSolution.png"); } @@ -36,27 +37,35 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { int groupSize = sudokuBoard.getSize(); Set region = sudokuBoard.getRegion(cell.getGroupIndex()); - Set row = sudokuBoard.getRow(cell.getLocation().y); - Set col = sudokuBoard.getCol(cell.getLocation().x); - Set solution = new HashSet<>(); + Set numbersNotInRegion = new HashSet<>(); + Set numberNotFit = new HashSet<>(); + Set numberCanFit = new HashSet<>(); + for (int i = 1; i <= groupSize; i++) { - solution.add(i); + numbersNotInRegion.add(i); } - for (SudokuCell c : region) { - solution.remove(c.getData()); - } - for (SudokuCell c : row) { - solution.remove(c.getData()); - } - for (SudokuCell c : col) { - solution.remove(c.getData()); + if(c.getData() != 0) { + numbersNotInRegion.remove(c.getData()); + } } + for (SudokuCell c : region) { + + Set row = sudokuBoard.getRow(c.getLocation().y); + Set col = sudokuBoard.getCol(c.getLocation().x); + for(SudokuCell c1 : row) { + numberNotFit.add(c1.getData()); + } + for(SudokuCell c2 : col) { + numberNotFit.add(c2.getData()); + } - if (solution.isEmpty()) { - return null; + for(int i : numbersNotInRegion) { + numbersNotInRegion.remove(numberNotFit); + } } + return super.getNoContradictionMessage(); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoNumberForCellContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoNumberForCellContradictionRule.java new file mode 100644 index 000000000..158b535d4 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoNumberForCellContradictionRule.java @@ -0,0 +1,56 @@ +package edu.rpi.legup.puzzle.sudoku.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.sudoku.SudokuBoard; +import edu.rpi.legup.puzzle.sudoku.SudokuCell; + +import java.util.HashSet; +import java.util.Set; + +public class NoNumberForCellContradictionRule extends ContradictionRule { + + public NoNumberForCellContradictionRule() { + super("SUDO-CONT-0003", "No Number for Cell", + "Process of elimination yields no valid numbers for an empty cell.", + "edu/rpi/legup/images/sudoku/NoSolution.png"); + } + + /** + * Checks whether the transition has a contradiction at the specific puzzleElement index using this rule + * + * @param board board to check contradiction + * @param puzzleElement equivalent puzzleElement + * @return null if the transition contains a contradiction at the specified puzzleElement, + * otherwise error message + */ + @Override + public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { + SudokuBoard sudokuBoard = (SudokuBoard) board; + SudokuCell cell = (SudokuCell) sudokuBoard.getPuzzleElement(puzzleElement); + if (cell.getData() != 0) { + return super.getNoContradictionMessage(); + } + + int groupSize = sudokuBoard.getSize(); + + Set region = sudokuBoard.getRegion(cell.getGroupIndex()); + Set row = sudokuBoard.getRow(cell.getLocation().y); + Set col = sudokuBoard.getCol(cell.getLocation().x); + Set solution = new HashSet<>(); + for (int i = 1; i <= groupSize; i++) { + solution.add(i); + } + + for (SudokuCell c : region) { + solution.remove(c.getData()); + } + + if (solution.isEmpty()) { + return null; + } + + return super.getNoContradictionMessage(); + } +} From 8d765adc5e52af924824479b12bbb0ee47e89ba0 Mon Sep 17 00:00:00 2001 From: kchiu1 <152306707+kchiu1@users.noreply.github.com> Date: Fri, 22 Mar 2024 17:14:29 -0400 Subject: [PATCH 044/258] Update NoNumberForCellContradictionRule.java added code that might work --- .../rules/NoNumberForCellContradictionRule.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoNumberForCellContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoNumberForCellContradictionRule.java index 158b535d4..fb325ef88 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoNumberForCellContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoNumberForCellContradictionRule.java @@ -39,15 +39,19 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { Set row = sudokuBoard.getRow(cell.getLocation().y); Set col = sudokuBoard.getCol(cell.getLocation().x); Set solution = new HashSet<>(); - for (int i = 1; i <= groupSize; i++) { - solution.add(i); + for(SudokuCell s : region) { + solution.add(s.getData()); + } + for(SudokuCell s : row) { + solution.add(s.getData()); } - for (SudokuCell c : region) { - solution.remove(c.getData()); + for(SudokuCell s : col) { + solution.add(s.getData()); } + solution.remove(0); - if (solution.isEmpty()) { + if(solution.size() == 9) { return null; } From e2ee69c4dc9cd9258a54f3132756a9ffea5fc97c Mon Sep 17 00:00:00 2001 From: Brandon McCusker Date: Fri, 22 Mar 2024 17:22:57 -0400 Subject: [PATCH 045/258] Fixed bugs and continued Contradiciton rule work --- .../rpi/legup/puzzle/binary/BinaryBoard.java | 20 +++++++++++++ .../rpi/legup/puzzle/binary/BinaryCell.java | 1 - .../puzzle/binary/BinaryCellFactory.java | 2 -- .../binary/rules/OneTileGapDirectRule.java | 19 ++++++++++++ .../rules/ThreeAdjacentContradictionRule.java | 29 ++++++++++++++++++- 5 files changed, 67 insertions(+), 4 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java index f24667d37..332355808 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java @@ -20,6 +20,10 @@ public BinaryBoard(int size) { @Override public BinaryCell getCell(int x, int y) { + if (y * dimension.width + x >= puzzleElements.size() || x >= dimension.width || + y >= dimension.height || x < 0 || y < 0) { + return null; + } return (BinaryCell) super.getCell(x, y); } @@ -38,4 +42,20 @@ public Set getCol(int colNum) { } return col; } + + + @Override + public BinaryBoard copy() { + System.out.println("BinaryBoard copy()"); + BinaryBoard copy = new BinaryBoard(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/binary/BinaryCell.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java index ebc5a8ab3..fc68116dc 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java @@ -10,7 +10,6 @@ public BinaryCell(int valueInt, Point location) { } public BinaryType getType() { - System.out.println(data); switch (data) { case 0: return BinaryType.ZERO; diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCellFactory.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCellFactory.java index 37685f9a9..dd25dff10 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCellFactory.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCellFactory.java @@ -51,9 +51,7 @@ public org.w3c.dom.Element exportCell(Document document, PuzzleElement puzzleEle BinaryCell cell = (BinaryCell) puzzleElement; Point loc = cell.getLocation(); - cellElement.setAttribute("value", String.valueOf(cell.getData())); - System.out.println(cell.getData()); cellElement.setAttribute("x", String.valueOf(loc.x)); cellElement.setAttribute("y", String.valueOf(loc.y)); diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java index bb5cf6cc2..d037c3891 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java @@ -30,7 +30,25 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem BinaryCell downOne = finalBoard.getCell(cell.getLocation().x, cell.getLocation().y-1); BinaryCell leftOne = finalBoard.getCell(cell.getLocation().x-1, cell.getLocation().y); BinaryCell rightOne = finalBoard.getCell(cell.getLocation().x+1, cell.getLocation().y); + BinaryType cellType = cell.getType(); + if(downOne.getType() == upOne.getType()) + { + if(downOne.getType() == cellType) + { + return "Filled cell matches vertical outer cells"; + } + } + if(rightOne.getType() == leftOne.getType()) + { + if(rightOne.getType() == cellType) + { + return "Filled cell matches hroizontal outer cells"; + } + } + return null; + } +/* if ((upOne.getType() == BinaryType.ONE && downOne.getType() == BinaryType.ONE && cell.getType() != BinaryType.ONE) || (upOne.getType() == BinaryType.ZERO && downOne.getType() == BinaryType.ZERO && cell.getType() != BinaryType.ZERO) || (leftOne.getType() == BinaryType.ONE && rightOne.getType() == BinaryType.ONE && cell.getType() != BinaryType.ONE) || @@ -39,6 +57,7 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem } return super.getInvalidUseOfRuleMessage() + ": " + this.INVALID_USE_MESSAGE; } +*/ @Override public Board getDefaultBoard(TreeNode node) { diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java index c048c2871..f2e406318 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java @@ -5,6 +5,7 @@ import edu.rpi.legup.puzzle.binary.BinaryBoard; import edu.rpi.legup.puzzle.binary.BinaryCell; import edu.rpi.legup.puzzle.binary.BinaryType; + public class ThreeAdjacentContradictionRule 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 zero or one"; @@ -19,12 +20,21 @@ public ThreeAdjacentContradictionRule() { @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { BinaryBoard binaryBoard = (BinaryBoard) board; + int height = binaryBoard.getHeight(); + int width = binaryBoard.getWidth(); + BinaryCell cell = (BinaryCell) binaryBoard.getPuzzleElement(puzzleElement); + + + int cellX = cell.getLocation().x; + int cellY = cell.getLocation().y; + System.out.println("X = " + cellX + ", Y = " + cellY); +/* if (cell.getType() != BinaryType.ZERO && cell.getType() != BinaryType.ONE) { return super.getInvalidUseOfRuleMessage() + ": " + this.INVALID_USE_MESSAGE; } - + BinaryCell upTwo = binaryBoard.getCell(cell.getLocation().x, cell.getLocation().y+2); BinaryCell upOne = binaryBoard.getCell(cell.getLocation().x, cell.getLocation().y+1); BinaryCell leftTwo = binaryBoard.getCell(cell.getLocation().x-2, cell.getLocation().y); @@ -33,6 +43,8 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { BinaryCell rightOne = binaryBoard.getCell(cell.getLocation().x+1, cell.getLocation().y); BinaryCell downTwo = binaryBoard.getCell(cell.getLocation().x, cell.getLocation().y-2); BinaryCell downOne = binaryBoard.getCell(cell.getLocation().x, cell.getLocation().y-1); + if(upTwo.getType() == null) + upTwo.getType() = UNKNOWN; if (cell.getType() == BinaryType.ZERO) { if ((upTwo.getType() == BinaryType.ZERO && upOne.getType() == BinaryType.ZERO) || @@ -53,7 +65,22 @@ else if (cell.getType() == BinaryType.ONE) { (upOne.getType() == BinaryType.ONE && downOne.getType() == BinaryType.ONE)) { return null; } + }*/ + + for (int x = cell.getLocation().x - 2; x >= 0 && x < cell.getLocation().x && x < width - 1; x++) { + if(binaryBoard.getCell(x, cellY).getType() == binaryBoard.getCell(x + 1, cellY).getType() && + binaryBoard.getCell(x + 1, cellY).getType() == binaryBoard.getCell(x + 2, cellY).getType()) { + return null; + } + } + + for (int y = cell.getLocation().y - 2; y >= 0 && y < cell.getLocation().y && y < height - 1; y++) { + if(binaryBoard.getCell(cellX, y).getType() == binaryBoard.getCell(cellX, y + 1).getType() && + binaryBoard.getCell(cellX, y + 1).getType() == binaryBoard.getCell(cellX, y + 2).getType()) { + return null; + } } + return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE; } } \ No newline at end of file From 86d985350b6be2278ed9acc7951ab1ad4b2aa0bd Mon Sep 17 00:00:00 2001 From: EggyMath <55564321+EggyMath@users.noreply.github.com> Date: Fri, 22 Mar 2024 17:23:30 -0400 Subject: [PATCH 046/258] Update NoCellForNumberContradictionRule.java Reformatted NoCellForNumber to function completely in all tested cases. --- .../NoCellForNumberContradictionRule.java | 50 +++++++++++++------ 1 file changed, 35 insertions(+), 15 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberContradictionRule.java index 11376d1a2..81fbe6821 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberContradictionRule.java @@ -29,6 +29,12 @@ public NoCellForNumberContradictionRule() { @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { SudokuBoard sudokuBoard = (SudokuBoard) board; + + //Loop through every individual region + //Check if there is a number that cannot exist in region with current board + + + SudokuCell cell = (SudokuCell) sudokuBoard.getPuzzleElement(puzzleElement); if (cell.getData() != 0) { return super.getNoContradictionMessage(); @@ -38,8 +44,6 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { Set region = sudokuBoard.getRegion(cell.getGroupIndex()); Set numbersNotInRegion = new HashSet<>(); - Set numberNotFit = new HashSet<>(); - Set numberCanFit = new HashSet<>(); for (int i = 1; i <= groupSize; i++) { numbersNotInRegion.add(i); @@ -49,23 +53,39 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { numbersNotInRegion.remove(c.getData()); } } - for (SudokuCell c : region) { - Set row = sudokuBoard.getRow(c.getLocation().y); - Set col = sudokuBoard.getCol(c.getLocation().x); - for(SudokuCell c1 : row) { - numberNotFit.add(c1.getData()); - } - for(SudokuCell c2 : col) { - numberNotFit.add(c2.getData()); - } + for (Integer i : numbersNotInRegion) { + //Check if number can be in cell + boolean canFit = false; + for(SudokuCell c : region){ + if(c.getData() != 0) + continue; - for(int i : numbersNotInRegion) { - numbersNotInRegion.remove(numberNotFit); - } - } + //Get row and col groups + Set row = sudokuBoard.getRow(c.getLocation().y); + Set col = sudokuBoard.getCol(c.getLocation().x); + //Check if it alr exists in row or col + boolean duplicate = false; + for(SudokuCell rc : row) { + if(rc.getData() == i) + duplicate = true; + } + for(SudokuCell cc : col) { + if(cc.getData() == i) + duplicate = true; + } + //If there is no duplicate it can exist in the region + if(!duplicate) { + canFit = true; + break; + } + } + //If the number can't fit anywhere in region then contradiction + if(!canFit) + return null; + } return super.getNoContradictionMessage(); } } From b6c29ad738905abcd39d4cc967c763630d663902 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Fri, 22 Mar 2024 17:32:00 -0400 Subject: [PATCH 047/258] Added copy in BinaryBoard, fixed getCell with checking out of bounds --- puzzles files/binary/6x6 easy/876868768 | 1 + .../rpi/legup/puzzle/binary/BinaryBoard.java | 42 ++++++++--- .../rpi/legup/puzzle/binary/BinaryCell.java | 1 - .../puzzle/binary/BinaryCellFactory.java | 1 - .../rules/ThreeAdjacentContradictionRule.java | 73 ++++++++++--------- 5 files changed, 70 insertions(+), 48 deletions(-) diff --git a/puzzles files/binary/6x6 easy/876868768 b/puzzles files/binary/6x6 easy/876868768 index ceefaefff..6b080c918 100644 --- a/puzzles files/binary/6x6 easy/876868768 +++ b/puzzles files/binary/6x6 easy/876868768 @@ -17,6 +17,7 @@ + diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java index f24667d37..848afc910 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java @@ -20,22 +20,40 @@ public BinaryBoard(int size) { @Override public BinaryCell getCell(int x, int y) { + if (y * dimension.width + x >= puzzleElements.size() || x >= dimension.width || + y >= dimension.height || x < 0 || y < 0) { + return null; + } return (BinaryCell) super.getCell(x, y); } - public Set getRow(int rowNum) { - Set row = new HashSet<>(); - for (int i = 0; i < size; i++) { - row.add(getCell(i, rowNum)); + @Override + public BinaryBoard copy() { + System.out.println("BinaryBoard copy()"); + BinaryBoard copy = new BinaryBoard(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()); + } } - return row; - } - - public Set getCol(int colNum) { - Set col = new HashSet<>(); - for (int i = 0; i < size; i ++) { - col.add(getCell(colNum, i)); + for (PuzzleElement e : modifiedData) { + copy.getPuzzleElement(e).setModifiable(false); } - return col; + return copy; } +// public Set getRow(int rowNum) { +// Set row = new HashSet<>(); +// for (int i = 0; i < size; i++) { +// row.add(getCell(i, rowNum)); +// } +// return row; +// } +// +// public Set getCol(int colNum) { +// Set col = new HashSet<>(); +// for (int i = 0; i < size; i ++) { +// col.add(getCell(colNum, i)); +// } +// return col; +// } } diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java index ebc5a8ab3..fc68116dc 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java @@ -10,7 +10,6 @@ public BinaryCell(int valueInt, Point location) { } public BinaryType getType() { - System.out.println(data); switch (data) { case 0: return BinaryType.ZERO; diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCellFactory.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCellFactory.java index 37685f9a9..913b54c14 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCellFactory.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCellFactory.java @@ -53,7 +53,6 @@ public org.w3c.dom.Element exportCell(Document document, PuzzleElement puzzleEle Point loc = cell.getLocation(); cellElement.setAttribute("value", String.valueOf(cell.getData())); - System.out.println(cell.getData()); cellElement.setAttribute("x", String.valueOf(loc.x)); cellElement.setAttribute("y", String.valueOf(loc.y)); diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java index c048c2871..27d08bce8 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java @@ -19,41 +19,46 @@ public ThreeAdjacentContradictionRule() { @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { BinaryBoard binaryBoard = (BinaryBoard) board; - BinaryCell cell = (BinaryCell) binaryBoard.getPuzzleElement(puzzleElement); - if (cell.getType() != BinaryType.ZERO && cell.getType() != BinaryType.ONE) { - return super.getInvalidUseOfRuleMessage() + ": " + this.INVALID_USE_MESSAGE; - } - - BinaryCell upTwo = binaryBoard.getCell(cell.getLocation().x, cell.getLocation().y+2); - BinaryCell upOne = binaryBoard.getCell(cell.getLocation().x, cell.getLocation().y+1); - BinaryCell leftTwo = binaryBoard.getCell(cell.getLocation().x-2, cell.getLocation().y); - BinaryCell leftOne = binaryBoard.getCell(cell.getLocation().x-1, cell.getLocation().y); - BinaryCell rightTwo = binaryBoard.getCell(cell.getLocation().x+2, cell.getLocation().y); - BinaryCell rightOne = binaryBoard.getCell(cell.getLocation().x+1, cell.getLocation().y); - BinaryCell downTwo = binaryBoard.getCell(cell.getLocation().x, cell.getLocation().y-2); - BinaryCell downOne = binaryBoard.getCell(cell.getLocation().x, cell.getLocation().y-1); +// + System.out.println("X = " + cell.getLocation().x + ", Y = " + cell.getLocation().y); - if (cell.getType() == BinaryType.ZERO) { - if ((upTwo.getType() == BinaryType.ZERO && upOne.getType() == BinaryType.ZERO) || - (leftTwo.getType() == BinaryType.ZERO && leftOne.getType() == BinaryType.ZERO) || - (rightTwo.getType() == BinaryType.ZERO && rightOne.getType() == BinaryType.ZERO) || - (downTwo.getType() == BinaryType.ZERO && downOne.getType() == BinaryType.ZERO) || - (leftOne.getType() == BinaryType.ZERO && rightOne.getType() == BinaryType.ZERO) || - (upOne.getType() == BinaryType.ZERO && downOne.getType() == BinaryType.ZERO)) { - return null; - } - } - else if (cell.getType() == BinaryType.ONE) { - if ((upTwo.getType() == BinaryType.ONE && upOne.getType() == BinaryType.ONE) || - (leftTwo.getType() == BinaryType.ONE && leftOne.getType() == BinaryType.ONE) || - (rightTwo.getType() == BinaryType.ONE && rightOne.getType() == BinaryType.ONE) || - (downTwo.getType() == BinaryType.ONE && downOne.getType() == BinaryType.ONE) || - (leftOne.getType() == BinaryType.ONE && rightOne.getType() == BinaryType.ONE) || - (upOne.getType() == BinaryType.ONE && downOne.getType() == BinaryType.ONE)) { - return null; - } - } - return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE; +// BinaryCell cell = (BinaryCell) binaryBoard.getPuzzleElement(puzzleElement); +// if (cell.getType() != BinaryType.ZERO && cell.getType() != BinaryType.ONE) { +// return super.getInvalidUseOfRuleMessage() + ": " + this.INVALID_USE_MESSAGE; +// } +// +// BinaryCell upTwo = binaryBoard.getCell(cell.getLocation().x, cell.getLocation().y+2); +// +// BinaryCell upOne = binaryBoard.getCell(cell.getLocation().x, cell.getLocation().y+1); +// BinaryCell leftTwo = binaryBoard.getCell(cell.getLocation().x-2, cell.getLocation().y); +// BinaryCell leftOne = binaryBoard.getCell(cell.getLocation().x-1, cell.getLocation().y); +// BinaryCell rightTwo = binaryBoard.getCell(cell.getLocation().x+2, cell.getLocation().y); +// BinaryCell rightOne = binaryBoard.getCell(cell.getLocation().x+1, cell.getLocation().y); +// BinaryCell downTwo = binaryBoard.getCell(cell.getLocation().x, cell.getLocation().y-2); +// BinaryCell downOne = binaryBoard.getCell(cell.getLocation().x, cell.getLocation().y-1); +// +// if (cell.getType() == BinaryType.ZERO) { +// if ((upTwo.getType() == BinaryType.ZERO && upOne.getType() == BinaryType.ZERO) || +// (leftTwo.getType() == BinaryType.ZERO && leftOne.getType() == BinaryType.ZERO) || +// (rightTwo.getType() == BinaryType.ZERO && rightOne.getType() == BinaryType.ZERO) || +// (downTwo.getType() == BinaryType.ZERO && downOne.getType() == BinaryType.ZERO) || +// (leftOne.getType() == BinaryType.ZERO && rightOne.getType() == BinaryType.ZERO) || +// (upOne.getType() == BinaryType.ZERO && downOne.getType() == BinaryType.ZERO)) { +// return null; +// } +// } +// else if (cell.getType() == BinaryType.ONE) { +// if ((upTwo.getType() == BinaryType.ONE && upOne.getType() == BinaryType.ONE) || +// (leftTwo.getType() == BinaryType.ONE && leftOne.getType() == BinaryType.ONE) || +// (rightTwo.getType() == BinaryType.ONE && rightOne.getType() == BinaryType.ONE) || +// (downTwo.getType() == BinaryType.ONE && downOne.getType() == BinaryType.ONE) || +// (leftOne.getType() == BinaryType.ONE && rightOne.getType() == BinaryType.ONE) || +// (upOne.getType() == BinaryType.ONE && downOne.getType() == BinaryType.ONE)) { +// return null; +// } +// } +// return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE; + return null; } } \ No newline at end of file From 7bc87396916780fb7605bae8a7d4949c9518cbda Mon Sep 17 00:00:00 2001 From: Brandon McCusker Date: Fri, 22 Mar 2024 17:57:52 -0400 Subject: [PATCH 048/258] Three adjacent CR complete and prelim testing done --- .../rules/ThreeAdjacentContradictionRule.java | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java index f2e406318..cd2fe848e 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java @@ -66,21 +66,26 @@ else if (cell.getType() == BinaryType.ONE) { return null; } }*/ + if(cell.getType() == BinaryType.ONE || cell.getType() == BinaryType.ZERO) + { + for (int x = cell.getLocation().x - 2; x >= 0 && x < cell.getLocation().x && x < width - 2; x++) { - for (int x = cell.getLocation().x - 2; x >= 0 && x < cell.getLocation().x && x < width - 1; x++) { - if(binaryBoard.getCell(x, cellY).getType() == binaryBoard.getCell(x + 1, cellY).getType() && - binaryBoard.getCell(x + 1, cellY).getType() == binaryBoard.getCell(x + 2, cellY).getType()) { - return null; + if(binaryBoard.getCell(x, cellY).getType() == binaryBoard.getCell(x + 1, cellY).getType() && + binaryBoard.getCell(x + 1, cellY).getType() == binaryBoard.getCell(x + 2, cellY).getType()) { + System.out.println("CUR XY fail X= " + cellX + " , " + cellY); + return null; + } } - } - for (int y = cell.getLocation().y - 2; y >= 0 && y < cell.getLocation().y && y < height - 1; y++) { - if(binaryBoard.getCell(cellX, y).getType() == binaryBoard.getCell(cellX, y + 1).getType() && - binaryBoard.getCell(cellX, y + 1).getType() == binaryBoard.getCell(cellX, y + 2).getType()) { - return null; + for (int y = cell.getLocation().y - 2; y >= 0 && y < cell.getLocation().y && y < height - 2; y++) { + + if(binaryBoard.getCell(cellX, y).getType() == binaryBoard.getCell(cellX, y + 1).getType() && + binaryBoard.getCell(cellX, y + 1).getType() == binaryBoard.getCell(cellX, y + 2).getType()) { + System.out.println("CUR XY fail Y= " + cellX + " , " + cellY); + return null; + } } } - return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE; } } \ No newline at end of file From 97a50dd0df9055704fcce221b623c31966bd7a1c Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Fri, 22 Mar 2024 22:50:02 -0400 Subject: [PATCH 049/258] Tested UnbalancedRowOrColumnContradictionRule to verify correction Fixed checkStyle errors --- MyWikiContributions.md | 54 +++++++++++++++++++ puzzles files/binary/6x6 easy/876868768 | 2 + .../binary/rules/OneTileGapDirectRule.java | 12 ++--- .../rules/ThreeAdjacentContradictionRule.java | 35 ------------ ...nbalancedRowOrColumnContradictionRule.java | 16 +++--- 5 files changed, 68 insertions(+), 51 deletions(-) create mode 100644 MyWikiContributions.md diff --git a/MyWikiContributions.md b/MyWikiContributions.md new file mode 100644 index 000000000..80f3bf914 --- /dev/null +++ b/MyWikiContributions.md @@ -0,0 +1,54 @@ +# Binary +Binary is a grid based puzzle game akin to Sudoku. You are given a grid of empty squares and squares filled with 1 or 0. Your task is to fill the board with 1s and 0s while adhering to the rules of the game. + +Each binary puzzle has a unique solution. It is always possible to make a next step by reasoning. In other words, the solution can always be found without guessing. + +### Interacting with the Binary Board +Clicking on a white square fills it with a 0 + +Clicking on a square with a 0 fills it with a 1 + +Clicking on a square with a 1 returns it white + +# Rules +### Here are the direct rules of the puzzle +1) Each square should contain either a zero or a one. +2) Three orthogonally adjacent zeros or ones is not allowed. +3) Each row and each column should contain an equal number of zeros and ones. +4) Each row is unique and each column is unique. Thus, any row cannot be exactly equal to another row, and any column cannot be exactly equal to another column. + +# LEGUP Proof Rules + +## Case Rules + +### One or Zero + +This rule is a direct consequence of rule #1. If a tile can be filled with a 0 or a 1 based on the current state of the board, create a split in the tree where the tile is a 0 in one path and 1 in the other to show two possible cases. + +## Contradiction Rules + +### Three in a Row + +This rule is a direct consequence of Rule #2. If a sequence of three of the same digit exists on the board, then the board is in a state of contradiction. + +### Unbalanced Row/Column Rule + +This rule is a direct consequence of Rule #3. If a row or column contains more of one digit than the other, then the board is in a state of contradiction. + +### Identical Row/Column Rule + +This rule is a direct consequence of Rule #4. If a row is identical to another row or a column is identical to another column, then the board is in a state of contradiction. + +## Direct Rules + +### Surround Pair + +This rule is a direct consequence of Rule #2. If two of the same digit exist adjacent to each other in any given row or column, then in order to avoid violating Rule #2, the pair must be surrounded with other digit on both sides. + +### One Tile Gap + +This rule is a direct consequence of Rule #2. If two of the same digit exist with a one tile gap between them, then in order to avoid violating Rule #2, the pair must be separated by placing the other digit between them. + +### Complete Row/Column + +This rule is a direct consequence of Rules #2 and #3. If a row or column is completely filled with 1s and 0s, there does not exist a grouping of three 1s or 0s anywhere in the row, and diff --git a/puzzles files/binary/6x6 easy/876868768 b/puzzles files/binary/6x6 easy/876868768 index 6b080c918..f6282d4c7 100644 --- a/puzzles files/binary/6x6 easy/876868768 +++ b/puzzles files/binary/6x6 easy/876868768 @@ -18,6 +18,8 @@ + + diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java index d037c3891..62977a507 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java @@ -32,17 +32,13 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem BinaryCell rightOne = finalBoard.getCell(cell.getLocation().x+1, cell.getLocation().y); BinaryType cellType = cell.getType(); - if(downOne.getType() == upOne.getType()) - { - if(downOne.getType() == cellType) - { + if(downOne.getType() == upOne.getType()) { + if(downOne.getType() == cellType) { return "Filled cell matches vertical outer cells"; } } - if(rightOne.getType() == leftOne.getType()) - { - if(rightOne.getType() == cellType) - { + if(rightOne.getType() == leftOne.getType()) { + if(rightOne.getType() == cellType) { return "Filled cell matches hroizontal outer cells"; } } diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java index cd2fe848e..f041ecfa8 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java @@ -30,42 +30,7 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { int cellX = cell.getLocation().x; int cellY = cell.getLocation().y; System.out.println("X = " + cellX + ", Y = " + cellY); -/* - if (cell.getType() != BinaryType.ZERO && cell.getType() != BinaryType.ONE) { - return super.getInvalidUseOfRuleMessage() + ": " + this.INVALID_USE_MESSAGE; - } - - BinaryCell upTwo = binaryBoard.getCell(cell.getLocation().x, cell.getLocation().y+2); - BinaryCell upOne = binaryBoard.getCell(cell.getLocation().x, cell.getLocation().y+1); - BinaryCell leftTwo = binaryBoard.getCell(cell.getLocation().x-2, cell.getLocation().y); - BinaryCell leftOne = binaryBoard.getCell(cell.getLocation().x-1, cell.getLocation().y); - BinaryCell rightTwo = binaryBoard.getCell(cell.getLocation().x+2, cell.getLocation().y); - BinaryCell rightOne = binaryBoard.getCell(cell.getLocation().x+1, cell.getLocation().y); - BinaryCell downTwo = binaryBoard.getCell(cell.getLocation().x, cell.getLocation().y-2); - BinaryCell downOne = binaryBoard.getCell(cell.getLocation().x, cell.getLocation().y-1); - if(upTwo.getType() == null) - upTwo.getType() = UNKNOWN; - if (cell.getType() == BinaryType.ZERO) { - if ((upTwo.getType() == BinaryType.ZERO && upOne.getType() == BinaryType.ZERO) || - (leftTwo.getType() == BinaryType.ZERO && leftOne.getType() == BinaryType.ZERO) || - (rightTwo.getType() == BinaryType.ZERO && rightOne.getType() == BinaryType.ZERO) || - (downTwo.getType() == BinaryType.ZERO && downOne.getType() == BinaryType.ZERO) || - (leftOne.getType() == BinaryType.ZERO && rightOne.getType() == BinaryType.ZERO) || - (upOne.getType() == BinaryType.ZERO && downOne.getType() == BinaryType.ZERO)) { - return null; - } - } - else if (cell.getType() == BinaryType.ONE) { - if ((upTwo.getType() == BinaryType.ONE && upOne.getType() == BinaryType.ONE) || - (leftTwo.getType() == BinaryType.ONE && leftOne.getType() == BinaryType.ONE) || - (rightTwo.getType() == BinaryType.ONE && rightOne.getType() == BinaryType.ONE) || - (downTwo.getType() == BinaryType.ONE && downOne.getType() == BinaryType.ONE) || - (leftOne.getType() == BinaryType.ONE && rightOne.getType() == BinaryType.ONE) || - (upOne.getType() == BinaryType.ONE && downOne.getType() == BinaryType.ONE)) { - return null; - } - }*/ if(cell.getType() == BinaryType.ONE || cell.getType() == BinaryType.ZERO) { for (int x = cell.getLocation().x - 2; x >= 0 && x < cell.getLocation().x && x < width - 2; x++) { diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowOrColumnContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowOrColumnContradictionRule.java index 7c8074eba..d74fe3264 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowOrColumnContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowOrColumnContradictionRule.java @@ -39,10 +39,10 @@ else if(item.getType() == BinaryType.ONE) { rowNumOnes++; } } - if (rowNumZeros + rowNumOnes != size) { - return super.getInvalidUseOfRuleMessage() + ": " + this.INVALID_USE_MESSAGE; - } - if (rowNumZeros != rowNumOnes) { +// if (rowNumZeros + rowNumOnes != size) { +// return super.getInvalidUseOfRuleMessage() + ": " + this.INVALID_USE_MESSAGE; +// } + if (rowNumZeros > size/2 || rowNumOnes > size/2) { return null; } @@ -60,10 +60,10 @@ else if(item.getType() == BinaryType.ONE) { colNumOnes++; } } - if (colNumZeros + colNumOnes != size) { - return super.getInvalidUseOfRuleMessage() + ": " + this.INVALID_USE_MESSAGE; - } - if (colNumZeros != colNumOnes) { +// if (colNumZeros + colNumOnes != size) { +// return super.getInvalidUseOfRuleMessage() + ": " + this.INVALID_USE_MESSAGE; +// } + if (colNumZeros > size/2 || rowNumOnes > size/2) { return null; } From 418f3b66e2854495eef35920db7a2ab47ff94ce7 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Fri, 22 Mar 2024 22:50:50 -0400 Subject: [PATCH 050/258] Tested UnbalancedRowOrColumnContradictionRule to verify correction Fixed checkStyle errors --- .../binary/rules/UnbalancedRowOrColumnContradictionRule.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowOrColumnContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowOrColumnContradictionRule.java index d74fe3264..09692c394 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowOrColumnContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowOrColumnContradictionRule.java @@ -63,7 +63,7 @@ else if(item.getType() == BinaryType.ONE) { // if (colNumZeros + colNumOnes != size) { // return super.getInvalidUseOfRuleMessage() + ": " + this.INVALID_USE_MESSAGE; // } - if (colNumZeros > size/2 || rowNumOnes > size/2) { + if (colNumZeros > size/2 || colNumOnes > size/2) { return null; } From 974c7a485bf9ba9646422484fe1c095f4c817e81 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Fri, 22 Mar 2024 22:53:52 -0400 Subject: [PATCH 051/258] Fixed checkStyle error in ThreeAdjacentContradictionRule --- .../puzzle/binary/rules/ThreeAdjacentContradictionRule.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java index f041ecfa8..8e1fffaa9 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java @@ -31,8 +31,7 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { int cellY = cell.getLocation().y; System.out.println("X = " + cellX + ", Y = " + cellY); - if(cell.getType() == BinaryType.ONE || cell.getType() == BinaryType.ZERO) - { + if(cell.getType() == BinaryType.ONE || cell.getType() == BinaryType.ZERO) { for (int x = cell.getLocation().x - 2; x >= 0 && x < cell.getLocation().x && x < width - 2; x++) { if(binaryBoard.getCell(x, cellY).getType() == binaryBoard.getCell(x + 1, cellY).getType() && From bafc113fb660b1628e351815eeb0f9eb50016e37 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Fri, 22 Mar 2024 23:11:40 -0400 Subject: [PATCH 052/258] Deleted unnecessary file that was auto created --- MyWikiContributions.md | 54 ------------------------------------------ 1 file changed, 54 deletions(-) delete mode 100644 MyWikiContributions.md diff --git a/MyWikiContributions.md b/MyWikiContributions.md deleted file mode 100644 index 80f3bf914..000000000 --- a/MyWikiContributions.md +++ /dev/null @@ -1,54 +0,0 @@ -# Binary -Binary is a grid based puzzle game akin to Sudoku. You are given a grid of empty squares and squares filled with 1 or 0. Your task is to fill the board with 1s and 0s while adhering to the rules of the game. - -Each binary puzzle has a unique solution. It is always possible to make a next step by reasoning. In other words, the solution can always be found without guessing. - -### Interacting with the Binary Board -Clicking on a white square fills it with a 0 - -Clicking on a square with a 0 fills it with a 1 - -Clicking on a square with a 1 returns it white - -# Rules -### Here are the direct rules of the puzzle -1) Each square should contain either a zero or a one. -2) Three orthogonally adjacent zeros or ones is not allowed. -3) Each row and each column should contain an equal number of zeros and ones. -4) Each row is unique and each column is unique. Thus, any row cannot be exactly equal to another row, and any column cannot be exactly equal to another column. - -# LEGUP Proof Rules - -## Case Rules - -### One or Zero - -This rule is a direct consequence of rule #1. If a tile can be filled with a 0 or a 1 based on the current state of the board, create a split in the tree where the tile is a 0 in one path and 1 in the other to show two possible cases. - -## Contradiction Rules - -### Three in a Row - -This rule is a direct consequence of Rule #2. If a sequence of three of the same digit exists on the board, then the board is in a state of contradiction. - -### Unbalanced Row/Column Rule - -This rule is a direct consequence of Rule #3. If a row or column contains more of one digit than the other, then the board is in a state of contradiction. - -### Identical Row/Column Rule - -This rule is a direct consequence of Rule #4. If a row is identical to another row or a column is identical to another column, then the board is in a state of contradiction. - -## Direct Rules - -### Surround Pair - -This rule is a direct consequence of Rule #2. If two of the same digit exist adjacent to each other in any given row or column, then in order to avoid violating Rule #2, the pair must be surrounded with other digit on both sides. - -### One Tile Gap - -This rule is a direct consequence of Rule #2. If two of the same digit exist with a one tile gap between them, then in order to avoid violating Rule #2, the pair must be separated by placing the other digit between them. - -### Complete Row/Column - -This rule is a direct consequence of Rules #2 and #3. If a row or column is completely filled with 1s and 0s, there does not exist a grouping of three 1s or 0s anywhere in the row, and From fef7499cdbe10e81a803d7681460f2fa16ffeec6 Mon Sep 17 00:00:00 2001 From: EggyMath <55564321+EggyMath@users.noreply.github.com> Date: Tue, 26 Mar 2024 16:18:24 -0400 Subject: [PATCH 053/258] Fix Build Failure Test If statements missing brackets were causing build errors, this should fix that. --- .../rules/LastCellForNumberDirectRule.java | 36 ++++++++++++------- .../rules/LastNumberForCellDirectRule.java | 3 +- .../NoCellForNumberContradictionRule.java | 18 +++++----- .../RepeatedNumberContradictionRule.java | 18 ++++++---- 4 files changed, 46 insertions(+), 29 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/LastCellForNumberDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/LastCellForNumberDirectRule.java index ad393ee42..af10fdc79 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/LastCellForNumberDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/LastCellForNumberDirectRule.java @@ -44,16 +44,19 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem //Check if new cell conflicts group for(SudokuCell c : region){ - if(c.getData() == cell.getData()) + if(c.getData() == cell.getData()) { return super.getInvalidUseOfRuleMessage() + ": Cell is not forced at this index"; + } } for(SudokuCell c : row){ - if(c.getData() == cell.getData()) + if(c.getData() == cell.getData()) { return super.getInvalidUseOfRuleMessage() + ": Cell is not forced at this index"; + } } for(SudokuCell c : col){ - if(c.getData() == cell.getData()) + if(c.getData() == cell.getData()) { return super.getInvalidUseOfRuleMessage() + ": Cell is not forced at this index"; + } } //// @@ -61,10 +64,12 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem boolean restrained = true; for(SudokuCell c : region){ //Test if its not a valid testing cell - if(c.getData() != 0) + if(c.getData() != 0) { continue; - if(c.getLocation().y == cell.getLocation().y && c.getLocation().x == cell.getLocation().x) + } + if(c.getLocation().y == cell.getLocation().y && c.getLocation().x == cell.getLocation().x) { continue; + } //Check if cell is eligible to hold number Set crow = initialBoard.getRow(c.getLocation().y); Set ccol = initialBoard.getCol(c.getLocation().x); @@ -86,18 +91,21 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem } } //Output if success - if(restrained) + if(restrained) { return null; + } //// //Loop to see if the number is constrained to the cell restrained = true; for(SudokuCell c : row){ //Test if its not a valid testing cell - if(c.getData() != 0) + if(c.getData() != 0) { continue; - if(c.getLocation().y == cell.getLocation().y && c.getLocation().x == cell.getLocation().x) + } + if(c.getLocation().y == cell.getLocation().y && c.getLocation().x == cell.getLocation().x) { continue; + } //Check if cell is eligible to hold number Set cregion = initialBoard.getRegion(c.getGroupIndex()); Set ccol = initialBoard.getCol(c.getLocation().x); @@ -119,18 +127,21 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem } } //Output if success - if(restrained) + if(restrained) { return null; + } //// //Loop to see if the number is constrained to the cell restrained = true; for(SudokuCell c : col){ //Test if its not a valid testing cell - if(c.getData() != 0) + if(c.getData() != 0) { continue; - if(c.getLocation().y == cell.getLocation().y && c.getLocation().x == cell.getLocation().x) + } + if(c.getLocation().y == cell.getLocation().y && c.getLocation().x == cell.getLocation().x) { continue; + } //Check if cell is eligible to hold number Set cregion = initialBoard.getRegion(c.getGroupIndex()); Set crow = initialBoard.getRow(c.getLocation().y); @@ -152,8 +163,9 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem } } //Output if success - if(restrained) + if(restrained) { return null; + } //Output fail return super.getInvalidUseOfRuleMessage() + ": Cell is not forced at this index"; diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/LastNumberForCellDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/LastNumberForCellDirectRule.java index f38543cc9..888f000ff 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/LastNumberForCellDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/LastNumberForCellDirectRule.java @@ -70,8 +70,9 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem return super.getInvalidUseOfRuleMessage() + ": The number at the index is forced but not correct"; } } - if(numbers.toArray(new Integer[1])[0] == puzzleElement.getData()) + if(numbers.toArray(new Integer[1])[0] == puzzleElement.getData()) { return null; + } return super.getInvalidUseOfRuleMessage() + ": The number at the index is forced but not correct"; } diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberContradictionRule.java index 81fbe6821..9c53df794 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberContradictionRule.java @@ -29,12 +29,6 @@ public NoCellForNumberContradictionRule() { @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { SudokuBoard sudokuBoard = (SudokuBoard) board; - - //Loop through every individual region - //Check if there is a number that cannot exist in region with current board - - - SudokuCell cell = (SudokuCell) sudokuBoard.getPuzzleElement(puzzleElement); if (cell.getData() != 0) { return super.getNoContradictionMessage(); @@ -58,8 +52,9 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { //Check if number can be in cell boolean canFit = false; for(SudokuCell c : region){ - if(c.getData() != 0) + if(c.getData() != 0) { continue; + } //Get row and col groups Set row = sudokuBoard.getRow(c.getLocation().y); @@ -68,12 +63,14 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { //Check if it alr exists in row or col boolean duplicate = false; for(SudokuCell rc : row) { - if(rc.getData() == i) + if(rc.getData() == i) { duplicate = true; + } } for(SudokuCell cc : col) { - if(cc.getData() == i) + if(cc.getData() == i) { duplicate = true; + } } //If there is no duplicate it can exist in the region @@ -83,8 +80,9 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { } } //If the number can't fit anywhere in region then contradiction - if(!canFit) + if(!canFit) { return null; + } } return super.getNoContradictionMessage(); } diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/RepeatedNumberContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/RepeatedNumberContradictionRule.java index a0801d5f3..51a8bf40b 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/RepeatedNumberContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/RepeatedNumberContradictionRule.java @@ -44,26 +44,32 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { //Check for non zero duplicates to trigger contradiction for (SudokuCell c : region) { - if (c.getData() == 0) + if (c.getData() == 0) { continue; - if (regionDup.contains(c.getData())) + } + if (regionDup.contains(c.getData())) { return null; + } regionDup.add(c.getData()); } for (SudokuCell c : row) { - if (c.getData() == 0) + if (c.getData() == 0) { continue; - if (rowDup.contains(c.getData())) + } + if (rowDup.contains(c.getData())) { return null; + } rowDup.add(c.getData()); } for (SudokuCell c : col) { - if (c.getData() == 0) + if (c.getData() == 0) { continue; - if (colDup.contains(c.getData())) + } + if (colDup.contains(c.getData())) { return null; + } colDup.add(c.getData()); } } From 86e413a754e55369dc866212c64a9910386e68ff Mon Sep 17 00:00:00 2001 From: kchiu1 <152306707+kchiu1@users.noreply.github.com> Date: Tue, 26 Mar 2024 16:37:01 -0400 Subject: [PATCH 054/258] Refactored contradiction rules +2 new contradiction rule Change old contradiction rule numbering to reflect as such --- ...oCellForNumberColumnContradictionRule.java | 88 +++++++++++++++++++ .../NoCellForNumberRowContradictionRule.java | 88 +++++++++++++++++++ .../NoNumberForCellContradictionRule.java | 2 +- 3 files changed, 177 insertions(+), 1 deletion(-) create mode 100644 src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberColumnContradictionRule.java create mode 100644 src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberRowContradictionRule.java diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberColumnContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberColumnContradictionRule.java new file mode 100644 index 000000000..64db5ff37 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberColumnContradictionRule.java @@ -0,0 +1,88 @@ +package edu.rpi.legup.puzzle.sudoku.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.sudoku.SudokuBoard; +import edu.rpi.legup.puzzle.sudoku.SudokuCell; + +import java.util.HashSet; +import java.util.Set; + +public class NoCellForNumberColumnContradictionRule extends ContradictionRule { + + public NoCellForNumberColumnContradictionRule() { + super("SUDO-CONT-0003", "No Cell for Number (Column)", + "Process of elimination yields no valid numbers for an empty cell in a column.", + "edu/rpi/legup/images/sudoku/NoSolution.png"); + } + + /** + * Checks whether the transition has a contradiction at the specific puzzleElement index using this rule + * + * @param board board to check contradiction + * @param puzzleElement equivalent puzzleElement + * @return null if the transition contains a contradiction at the specified puzzleElement, + * otherwise error message + */ + @Override + public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { + SudokuBoard sudokuBoard = (SudokuBoard) board; + SudokuCell cell = (SudokuCell) sudokuBoard.getPuzzleElement(puzzleElement); + if (cell.getData() != 0) { + return super.getNoContradictionMessage(); + } + + int groupSize = sudokuBoard.getSize(); + + Set col = sudokuBoard.getCol(cell.getGroupIndex()); + Set numbersNotInColumn = new HashSet<>(); + + for (int i = 1; i <= groupSize; i++) { + numbersNotInColumn.add(i); + } + for (SudokuCell c : col) { + if(c.getData() != 0) { + numbersNotInColumn.remove(c.getData()); + } + } + + for (Integer i : numbersNotInColumn) { + //Check if number can be in cell + boolean canFit = false; + for(SudokuCell c : col){ + if(c.getData() != 0) { + continue; + } + + //Get row and col groups + Set region = sudokuBoard.getRow(c.getLocation().y); + Set row = sudokuBoard.getCol(c.getLocation().x); + + //Check if it alr exists in row or col + boolean duplicate = false; + for(SudokuCell rc : region) { + if(rc.getData() == i) { + duplicate = true; + } + } + for(SudokuCell cc : row) { + if(cc.getData() == i) { + duplicate = true; + } + } + + //If there is no duplicate it can exist in the region + if(!duplicate) { + canFit = true; + break; + } + } + //If the number can't fit anywhere in region then contradiction + if(!canFit) { + return null; + } + } + return super.getNoContradictionMessage(); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberRowContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberRowContradictionRule.java new file mode 100644 index 000000000..28fc9a49b --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberRowContradictionRule.java @@ -0,0 +1,88 @@ +package edu.rpi.legup.puzzle.sudoku.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.sudoku.SudokuBoard; +import edu.rpi.legup.puzzle.sudoku.SudokuCell; + +import java.util.HashSet; +import java.util.Set; + +public class NoCellForNumberRowContradictionRule extends ContradictionRule { + + public NoCellForNumberRowContradictionRule() { + super("SUDO-CONT-0002", "No Cell for Number (Row)", + "Process of elimination yields no valid numbers for an empty cell in a row.", + "edu/rpi/legup/images/sudoku/NoSolution.png"); + } + + /** + * Checks whether the transition has a contradiction at the specific puzzleElement index using this rule + * + * @param board board to check contradiction + * @param puzzleElement equivalent puzzleElement + * @return null if the transition contains a contradiction at the specified puzzleElement, + * otherwise error message + */ + @Override + public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { + SudokuBoard sudokuBoard = (SudokuBoard) board; + SudokuCell cell = (SudokuCell) sudokuBoard.getPuzzleElement(puzzleElement); + if (cell.getData() != 0) { + return super.getNoContradictionMessage(); + } + + int groupSize = sudokuBoard.getSize(); + + Set row = sudokuBoard.getRow(cell.getGroupIndex()); + Set numbersNotInRow = new HashSet<>(); + + for (int i = 1; i <= groupSize; i++) { + numbersNotInRow.add(i); + } + for (SudokuCell c : row) { + if(c.getData() != 0) { + numbersNotInRow.remove(c.getData()); + } + } + + for (Integer i : numbersNotInRow) { + //Check if number can be in cell + boolean canFit = false; + for(SudokuCell c : row){ + if(c.getData() != 0) { + continue; + } + + //Get row and col groups + Set region = sudokuBoard.getRow(c.getLocation().y); + Set col = sudokuBoard.getCol(c.getLocation().x); + + //Check if it alr exists in row or col + boolean duplicate = false; + for(SudokuCell rc : region) { + if(rc.getData() == i) { + duplicate = true; + } + } + for(SudokuCell cc : col) { + if(cc.getData() == i) { + duplicate = true; + } + } + + //If there is no duplicate it can exist in the region + if(!duplicate) { + canFit = true; + break; + } + } + //If the number can't fit anywhere in region then contradiction + if(!canFit) { + return null; + } + } + return super.getNoContradictionMessage(); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoNumberForCellContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoNumberForCellContradictionRule.java index fb325ef88..7b2736aba 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoNumberForCellContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoNumberForCellContradictionRule.java @@ -12,7 +12,7 @@ public class NoNumberForCellContradictionRule extends ContradictionRule { public NoNumberForCellContradictionRule() { - super("SUDO-CONT-0003", "No Number for Cell", + super("SUDO-CONT-0005", "No Number for Cell", "Process of elimination yields no valid numbers for an empty cell.", "edu/rpi/legup/images/sudoku/NoSolution.png"); } From 196ce8f161f40e14081dbfde13fb4c5eba9a0600 Mon Sep 17 00:00:00 2001 From: kchiu1 <152306707+kchiu1@users.noreply.github.com> Date: Tue, 26 Mar 2024 17:32:49 -0400 Subject: [PATCH 055/258] number changes for contradictionrules changed the order and reference sheet to reflect that --- .../sudoku/rules/NoNumberForCellContradictionRule.java | 2 +- .../puzzle/sudoku/rules/RepeatedNumberContradictionRule.java | 2 +- .../rpi/legup/puzzle/sudoku/rules/sudoku_reference_sheet.txt | 5 ++++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoNumberForCellContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoNumberForCellContradictionRule.java index 7b2736aba..41650d3ba 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoNumberForCellContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoNumberForCellContradictionRule.java @@ -12,7 +12,7 @@ public class NoNumberForCellContradictionRule extends ContradictionRule { public NoNumberForCellContradictionRule() { - super("SUDO-CONT-0005", "No Number for Cell", + super("SUDO-CONT-0004", "No Number for Cell", "Process of elimination yields no valid numbers for an empty cell.", "edu/rpi/legup/images/sudoku/NoSolution.png"); } diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/RepeatedNumberContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/RepeatedNumberContradictionRule.java index 51a8bf40b..2f131f44d 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/RepeatedNumberContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/RepeatedNumberContradictionRule.java @@ -12,7 +12,7 @@ public class RepeatedNumberContradictionRule extends ContradictionRule { public RepeatedNumberContradictionRule() { - super("SUDO-CONT-0002", "Repeated Numbers", + super("SUDO-CONT-0005", "Repeated Numbers", "Two identical numbers are placed in the same group.", "edu/rpi/legup/images/sudoku/RepeatedNumber.png"); } diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/sudoku_reference_sheet.txt b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/sudoku_reference_sheet.txt index a8635330d..b36fc5e02 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/sudoku_reference_sheet.txt +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/sudoku_reference_sheet.txt @@ -2,7 +2,10 @@ SUDO-BASC-0001 : AdvancedDeductionDirectRule SUDO-BASC-0002 : LastCellForNumberDirectRule SUDO-BASC-0003 : LastNumberForCellDirectRule -SUDO-CONT-0001 : NoSolutionContradictionRule +SUDO-CONT-0001 : NoCellForNumberContradictionRule +SUDO-CONT-0002 : NoCellForNumberRowContradictionRule +SUDO-CONT-0003 : NoCellForNumberColumnContradictionRule +SUDO-CONT-0004 : NoNumberForCellContradictionRule SUDO-CONT-0002 : RepeatedNumberContradictionRule SUDO-CASE-0001 : PossibleCellCaseRule From ce20def95341856f9914e8c96aca77b280908abe Mon Sep 17 00:00:00 2001 From: Brandon McCusker Date: Tue, 26 Mar 2024 17:44:28 -0400 Subject: [PATCH 056/258] OneZeroCaseRule working version complete, began writing SurroundPairDIrectRule fixed minor bugs --- .../binary/rules/OneOrZeroCaseRule.java | 2 +- .../binary/rules/SurroundPairDirectRule.java | 21 ++++++++++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneOrZeroCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneOrZeroCaseRule.java index 21f0b3cbb..192317e9f 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneOrZeroCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneOrZeroCaseRule.java @@ -23,7 +23,7 @@ public OneOrZeroCaseRule() { @Override public String checkRuleRaw(TreeTransition transition) { - List childTransitions = transition.getParents().get(3).getChildren(); + List childTransitions = transition.getParents().get(0).getChildren(); if (childTransitions.size() != 2) { return super.getInvalidUseOfRuleMessage() + ": This case rule must have 2 children."; } diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java index 232870977..7e0caff73 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java @@ -21,7 +21,26 @@ public SurroundPairDirectRule() { @Override public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - return null; + BinaryBoard board = (BinaryBoard) transition.getBoard(); + BinaryBoard origBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); + ContradictionRule contraRule = new ThreeAdjacentContradictionRule(); + + + BinaryCell cell = (BinaryCell) board.getPuzzleElement(puzzleElement); + + if (cell.getType() == BinaryType.UNKNOWN) { + return "Only ONE or ZERO cells are allowed for this rule!"; + } + + BinaryBoard modified = origBoard.copy(); + modified.getPuzzleElement(puzzleElement).setData(BinaryType.WHITE.toValue()); + if (contraRule.checkContradictionAt(modified, puzzleElement) != null) { + return "Black cells must be placed in a region of black cells!"; + } + return null; + + return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE; + } @Override From 5972432d0cffed8765a80774409db9fcc51eec38 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Tue, 26 Mar 2024 17:47:41 -0400 Subject: [PATCH 057/258] Finished DuplicateRowsOrColumnsContradictionRule for rows but not columns, added method to get all types of cells in row. --- puzzles files/binary/6x6 easy/876868768 | 11 +- puzzles files/binary/6x6 easy/blank | 11 ++ .../rpi/legup/puzzle/binary/BinaryBoard.java | 16 ++- .../rules/CompleteRowColumnDirectRule.java | 8 +- ...plicateRowsOrColumnsContradictionRule.java | 104 ++++++++++-------- ...nbalancedRowOrColumnContradictionRule.java | 2 +- 6 files changed, 95 insertions(+), 57 deletions(-) create mode 100644 puzzles files/binary/6x6 easy/blank diff --git a/puzzles files/binary/6x6 easy/876868768 b/puzzles files/binary/6x6 easy/876868768 index f6282d4c7..d4a8f71d4 100644 --- a/puzzles files/binary/6x6 easy/876868768 +++ b/puzzles files/binary/6x6 easy/876868768 @@ -11,15 +11,20 @@ - - - + + + + + + + + diff --git a/puzzles files/binary/6x6 easy/blank b/puzzles files/binary/6x6 easy/blank new file mode 100644 index 000000000..006528e16 --- /dev/null +++ b/puzzles files/binary/6x6 easy/blank @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java index 332355808..8471028ef 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java @@ -4,6 +4,7 @@ import edu.rpi.legup.model.gameboard.PuzzleElement; import java.awt.*; +import java.util.ArrayList; import java.util.HashSet; import java.util.Set; public class BinaryBoard extends GridBoard { @@ -26,11 +27,20 @@ public BinaryCell getCell(int x, int y) { } return (BinaryCell) super.getCell(x, y); } - - public Set getRow(int rowNum) { + public Set getRowCells(int rowNum) { Set row = new HashSet<>(); for (int i = 0; i < size; i++) { - row.add(getCell(i, rowNum)); + BinaryCell cell = getCell(i, rowNum); + row.add(cell); + } + return row; + } + + public ArrayList getRowTypes(int rowNum) { + ArrayList row = new ArrayList(); + for (int i = 0; i < size; i++) { + BinaryCell cell = getCell(i, rowNum); + row.add(cell.getType()); } return row; } diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java index fbb64a13c..147d1c2a1 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java @@ -40,8 +40,6 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem int boardDim = initialBoard.getWidth(); int elementRow = elementIndex / boardDim; int elementCol = elementIndex % boardDim; - Set curRow = initialBoard.getRow(elementRow); - Set curCol = initialBoard.getCol(elementCol); int numColZeros = 0; int numColOnes = 0; @@ -51,7 +49,7 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem if(cell.getData() == 1){ numColOnes ++; } - else if(cell.getData() == 0){ + else if(cell.getData() == 0) { numColZeros ++; } } @@ -60,10 +58,10 @@ else if(cell.getData() == 0){ for (int i = 0; i < boardDim; i++) { BinaryCell cell = initialBoard.getCell(elementRow, i); - if(cell.getData() == 1){ + if(cell.getData() == 1) { numRowOnes ++; } - else if(cell.getData() == 0){ + else if(cell.getData() == 0) { numRowZeros ++; } } diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsOrColumnsContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsOrColumnsContradictionRule.java index 17dd4b631..295f48598 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsOrColumnsContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsOrColumnsContradictionRule.java @@ -7,6 +7,8 @@ import edu.rpi.legup.puzzle.binary.BinaryCell; import edu.rpi.legup.puzzle.binary.BinaryType; +import java.util.ArrayList; +import java.util.Iterator; import java.util.Set; public class DuplicateRowsOrColumnsContradictionRule extends ContradictionRule { private final String NO_CONTRADICTION_MESSAGE = "Does not contain a contradiction at this index"; @@ -22,57 +24,69 @@ public DuplicateRowsOrColumnsContradictionRule() { @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { BinaryBoard binaryBoard = (BinaryBoard) board; - boolean rowValid = false; - boolean colValid = false; BinaryCell cell = (BinaryCell) binaryBoard.getPuzzleElement(puzzleElement); - Set row = binaryBoard.getRow(cell.getLocation().y); - BinaryCell[] rowArray = row.toArray(new BinaryCell[0]); + + ArrayList row = binaryBoard.getRowTypes(cell.getLocation().y); + + System.out.println(row); int size = row.size(); - int y = cell.getLocation().y; - for (int i = 0; i < size; i++) { - if (rowValid) { - break; - } - if (i != y) { - Set currRow = binaryBoard.getRow(i); - BinaryCell[] currRowArray = currRow.toArray(new BinaryCell[0]); - for (int j = 0; j < size; j++) { - BinaryCell rowElement = rowArray[j]; - BinaryCell currRowElement = currRowArray[j]; - if (rowElement.getType() != currRowElement.getType()) { - rowValid = true; - } - } - } - } - if (!rowValid) { - return null; - } - Set col = binaryBoard.getCol(cell.getLocation().x); - BinaryCell[] colArray = col.toArray(new BinaryCell[0]); - size = col.size(); - int x = cell.getLocation().x; + + for (int i = 0; i < size; i++) { - if (colValid) { - break; + if (i > cell.getLocation().y) { + ArrayList currRow = binaryBoard.getRowTypes(i); + if (currRow.equals(row)) + return null; } - if (i != x) { - Set currCol = binaryBoard.getCol(i); - BinaryCell[] currColArray = currCol.toArray(new BinaryCell[0]); - for (int j = 0; j < size; j++) { - BinaryCell colElement = colArray[j]; - BinaryCell currColElement = currColArray[j]; - if (colElement.getType() != currColElement.getType()) { - colValid = true; - } - } - } - } - if (!colValid) { - return null; } +// BinaryCell[] rowArray = row.toArray(new BinaryCell[0]); +// +// boolean rowValid = false; +// int size = row.size(); +// int y = cell.getLocation().y; +// for (int i = 0; i < size; i++) { +// if (i != y) { +// Set currRow = binaryBoard.getRow(i); +// BinaryCell[] currRowArray = currRow.toArray(new BinaryCell[0]); +// for (int j = 0; j < size; j++) { +// BinaryCell rowElement = rowArray[j]; +// BinaryCell currRowElement = currRowArray[j]; +// System.out.println("Row: " + i + " Org x: " + rowElement.getLocation().x + " Curr x: " + currRowElement.getLocation().x); +//// if (rowElement.getType() != currRowElement.getType()) { +//// rowValid = true; +//// break; +//// } +// } +//// if (!rowValid) +//// return null; +// } +// } +// return null; +// Set col = binaryBoard.getCol(cell.getLocation().x); +// BinaryCell[] colArray = col.toArray(new BinaryCell[0]); +// size = col.size(); +// int x = cell.getLocation().x; +// for (int i = 0; i < size; i++) { +// if (colValid) { +// break; +// } +// if (i != x) { +// Set currCol = binaryBoard.getCol(i); +// BinaryCell[] currColArray = currCol.toArray(new BinaryCell[0]); +// for (int j = 0; j < size; j++) { +// BinaryCell colElement = colArray[j]; +// BinaryCell currColElement = currColArray[j]; +// if (colElement.getType() != currColElement.getType()) { +// colValid = true; +// } +// } +// } +// } +// if (!colValid) { +// return null; +// } + //System.out.println(cell.getLocation().x + " " + cell.getLocation().y); return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE; - } } diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowOrColumnContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowOrColumnContradictionRule.java index 09692c394..b58f9f02e 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowOrColumnContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowOrColumnContradictionRule.java @@ -25,7 +25,7 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { BinaryBoard binaryBoard = (BinaryBoard) board; BinaryCell cell = (BinaryCell) binaryBoard.getPuzzleElement(puzzleElement); - Set row = binaryBoard.getRow(cell.getLocation().y); + Set row = binaryBoard.getRowCells(cell.getLocation().y); int size = row.size(); int rowNumZeros = 0; From 012fe90ce2df8ced1125e36c18102b6ac9168740 Mon Sep 17 00:00:00 2001 From: Brandon McCusker Date: Tue, 26 Mar 2024 17:50:24 -0400 Subject: [PATCH 058/258] fixed stylecheck errors --- .../puzzle/binary/rules/SurroundPairDirectRule.java | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java index 7e0caff73..c97c1f139 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java @@ -33,14 +33,13 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem } BinaryBoard modified = origBoard.copy(); - modified.getPuzzleElement(puzzleElement).setData(BinaryType.WHITE.toValue()); - if (contraRule.checkContradictionAt(modified, puzzleElement) != null) { - return "Black cells must be placed in a region of black cells!"; - } + // modified.getPuzzleElement(puzzleElement).setData(BinaryType.WHITE.toValue()); + // if (contraRule.checkContradictionAt(modified, puzzleElement) != null) { + // return "Black cells must be placed in a region of black cells!"; + // } return null; - return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE; - + } @Override From c54515483bed156263dbb03b4bf09486a64760f3 Mon Sep 17 00:00:00 2001 From: Brandon McCusker Date: Tue, 26 Mar 2024 17:52:25 -0400 Subject: [PATCH 059/258] fixed stylecheck errors --- .../binary/rules/DuplicateRowsOrColumnsContradictionRule.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsOrColumnsContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsOrColumnsContradictionRule.java index 295f48598..f08c023ee 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsOrColumnsContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsOrColumnsContradictionRule.java @@ -35,8 +35,9 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { for (int i = 0; i < size; i++) { if (i > cell.getLocation().y) { ArrayList currRow = binaryBoard.getRowTypes(i); - if (currRow.equals(row)) + if (currRow.equals(row)){ return null; + } } } // BinaryCell[] rowArray = row.toArray(new BinaryCell[0]); From 5f6f092750fa6fba1b470defcfcbf1394719f357 Mon Sep 17 00:00:00 2001 From: Brandon McCusker Date: Thu, 28 Mar 2024 02:26:01 -0400 Subject: [PATCH 060/258] All rules complete and ready for test suite, constructed additional test puzzles --- puzzles files/binary/6x6 easy/089764562 | 22 ++++++++++++++ puzzles files/binary/6x6 easy/128903434 | 21 ++++++++++++++ puzzles files/binary/6x6 easy/876868768 | 29 +++++++------------ puzzles files/binary/6x6 easy/927364891 | 28 ++++++++++++++++++ .../rpi/legup/puzzle/binary/BinaryBoard.java | 9 ++++++ ...plicateRowsOrColumnsContradictionRule.java | 22 ++++++++++---- .../binary/rules/OneTileGapDirectRule.java | 27 +++++++---------- .../binary/rules/SurroundPairDirectRule.java | 22 +++++++------- 8 files changed, 129 insertions(+), 51 deletions(-) create mode 100644 puzzles files/binary/6x6 easy/089764562 create mode 100644 puzzles files/binary/6x6 easy/128903434 create mode 100644 puzzles files/binary/6x6 easy/927364891 diff --git a/puzzles files/binary/6x6 easy/089764562 b/puzzles files/binary/6x6 easy/089764562 new file mode 100644 index 000000000..7b22ffc10 --- /dev/null +++ b/puzzles files/binary/6x6 easy/089764562 @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/puzzles files/binary/6x6 easy/128903434 b/puzzles files/binary/6x6 easy/128903434 new file mode 100644 index 000000000..ea8ef93b0 --- /dev/null +++ b/puzzles files/binary/6x6 easy/128903434 @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/puzzles files/binary/6x6 easy/876868768 b/puzzles files/binary/6x6 easy/876868768 index d4a8f71d4..0f0ff745e 100644 --- a/puzzles files/binary/6x6 easy/876868768 +++ b/puzzles files/binary/6x6 easy/876868768 @@ -3,28 +3,21 @@ - - - - - - - - - - - - - - + + - + - - - + + + + + + + + diff --git a/puzzles files/binary/6x6 easy/927364891 b/puzzles files/binary/6x6 easy/927364891 new file mode 100644 index 000000000..da76d067b --- /dev/null +++ b/puzzles files/binary/6x6 easy/927364891 @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java index 8471028ef..b5faa1fef 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java @@ -45,6 +45,15 @@ public ArrayList getRowTypes(int rowNum) { return row; } + public ArrayList getColTypes(int colNum) { + ArrayList col = new ArrayList(); + for (int i = 0; i < size; i++) { + BinaryCell cell = getCell(colNum, i); + col.add(cell.getType()); + } + return col; + } + public Set getCol(int colNum) { Set col = new HashSet<>(); for (int i = 0; i < size; i ++) { diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsOrColumnsContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsOrColumnsContradictionRule.java index f08c023ee..14960fd5a 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsOrColumnsContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsOrColumnsContradictionRule.java @@ -25,13 +25,11 @@ public DuplicateRowsOrColumnsContradictionRule() { public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { BinaryBoard binaryBoard = (BinaryBoard) board; BinaryCell cell = (BinaryCell) binaryBoard.getPuzzleElement(puzzleElement); - + ArrayList row = binaryBoard.getRowTypes(cell.getLocation().y); - - System.out.println(row); + int size = row.size(); - - + System.out.println("Row: " + row); for (int i = 0; i < size; i++) { if (i > cell.getLocation().y) { ArrayList currRow = binaryBoard.getRowTypes(i); @@ -40,6 +38,20 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { } } } + + ArrayList col = binaryBoard.getColTypes(cell.getLocation().x); + + System.out.println("column: " + col); + for (int i = 0; i < size; i++) { + if (i > cell.getLocation().x) { + ArrayList currCol = binaryBoard.getColTypes(i); + if (currCol.equals(col)){ + return null; + } + } + } + + // BinaryCell[] rowArray = row.toArray(new BinaryCell[0]); // // boolean rowValid = false; diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java index 62977a507..daa49c46e 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java @@ -21,26 +21,21 @@ public OneTileGapDirectRule() { @Override public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - BinaryBoard iniitalBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); - BinaryBoard finalBoard = (BinaryBoard) transition.getBoard(); - int boardDim = iniitalBoard.getWidth(); - BinaryCell cell = (BinaryCell) finalBoard.getPuzzleElement(puzzleElement); + BinaryBoard board = (BinaryBoard) transition.getBoard(); + BinaryBoard origBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); + ContradictionRule contraRule = new ThreeAdjacentContradictionRule(); - BinaryCell upOne = finalBoard.getCell(cell.getLocation().x, cell.getLocation().y+1); - BinaryCell downOne = finalBoard.getCell(cell.getLocation().x, cell.getLocation().y-1); - BinaryCell leftOne = finalBoard.getCell(cell.getLocation().x-1, cell.getLocation().y); - BinaryCell rightOne = finalBoard.getCell(cell.getLocation().x+1, cell.getLocation().y); - BinaryType cellType = cell.getType(); - if(downOne.getType() == upOne.getType()) { - if(downOne.getType() == cellType) { - return "Filled cell matches vertical outer cells"; + BinaryCell cell = (BinaryCell) board.getPuzzleElement(puzzleElement); + if(cell.getType() != BinaryType.UNKNOWN){ + if (cell.getType() == BinaryType.UNKNOWN) { + return "Only ONE or ZERO cells are allowed for this rule!"; } - } - if(rightOne.getType() == leftOne.getType()) { - if(rightOne.getType() == cellType) { - return "Filled cell matches hroizontal outer cells"; + + if (contraRule.checkContradictionAt(origBoard, puzzleElement) == null) { + return "Grouping of Three Ones or Zeros found"; } + } return null; } diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java index c97c1f139..5ef0566d7 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java @@ -27,19 +27,17 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem BinaryCell cell = (BinaryCell) board.getPuzzleElement(puzzleElement); - - if (cell.getType() == BinaryType.UNKNOWN) { - return "Only ONE or ZERO cells are allowed for this rule!"; + if(cell.getType() != BinaryType.UNKNOWN){ + if (cell.getType() == BinaryType.UNKNOWN) { + return "Only ONE or ZERO cells are allowed for this rule!"; + } + + if (contraRule.checkContradictionAt(origBoard, puzzleElement) == null) { + return "Grouping of Three Ones or Zeros found"; + } + } - - BinaryBoard modified = origBoard.copy(); - // modified.getPuzzleElement(puzzleElement).setData(BinaryType.WHITE.toValue()); - // if (contraRule.checkContradictionAt(modified, puzzleElement) != null) { - // return "Black cells must be placed in a region of black cells!"; - // } - return null; - - + return null; } @Override From c55b5d27b14f23555fd7c013263ebabbb9b89858 Mon Sep 17 00:00:00 2001 From: Brandon McCusker Date: Thu, 28 Mar 2024 02:40:12 -0400 Subject: [PATCH 061/258] Cleaned rule files, unified formatting, removed print statements from testing --- ...plicateRowsOrColumnsContradictionRule.java | 52 +------------------ .../binary/rules/OneTileGapDirectRule.java | 19 ++----- .../binary/rules/SurroundPairDirectRule.java | 10 ++-- .../rules/ThreeAdjacentContradictionRule.java | 11 +--- ...nbalancedRowOrColumnContradictionRule.java | 8 +-- 5 files changed, 14 insertions(+), 86 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsOrColumnsContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsOrColumnsContradictionRule.java index 14960fd5a..f65ccc58c 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsOrColumnsContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsOrColumnsContradictionRule.java @@ -29,7 +29,7 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { ArrayList row = binaryBoard.getRowTypes(cell.getLocation().y); int size = row.size(); - System.out.println("Row: " + row); + for (int i = 0; i < size; i++) { if (i > cell.getLocation().y) { ArrayList currRow = binaryBoard.getRowTypes(i); @@ -41,7 +41,6 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { ArrayList col = binaryBoard.getColTypes(cell.getLocation().x); - System.out.println("column: " + col); for (int i = 0; i < size; i++) { if (i > cell.getLocation().x) { ArrayList currCol = binaryBoard.getColTypes(i); @@ -51,55 +50,6 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { } } - -// BinaryCell[] rowArray = row.toArray(new BinaryCell[0]); -// -// boolean rowValid = false; -// int size = row.size(); -// int y = cell.getLocation().y; -// for (int i = 0; i < size; i++) { -// if (i != y) { -// Set currRow = binaryBoard.getRow(i); -// BinaryCell[] currRowArray = currRow.toArray(new BinaryCell[0]); -// for (int j = 0; j < size; j++) { -// BinaryCell rowElement = rowArray[j]; -// BinaryCell currRowElement = currRowArray[j]; -// System.out.println("Row: " + i + " Org x: " + rowElement.getLocation().x + " Curr x: " + currRowElement.getLocation().x); -//// if (rowElement.getType() != currRowElement.getType()) { -//// rowValid = true; -//// break; -//// } -// } -//// if (!rowValid) -//// return null; -// } -// } -// return null; -// Set col = binaryBoard.getCol(cell.getLocation().x); -// BinaryCell[] colArray = col.toArray(new BinaryCell[0]); -// size = col.size(); -// int x = cell.getLocation().x; -// for (int i = 0; i < size; i++) { -// if (colValid) { -// break; -// } -// if (i != x) { -// Set currCol = binaryBoard.getCol(i); -// BinaryCell[] currColArray = currCol.toArray(new BinaryCell[0]); -// for (int j = 0; j < size; j++) { -// BinaryCell colElement = colArray[j]; -// BinaryCell currColElement = currColArray[j]; -// if (colElement.getType() != currColElement.getType()) { -// colValid = true; -// } -// } -// } -// } -// if (!colValid) { -// return null; -// } - - //System.out.println(cell.getLocation().x + " " + cell.getLocation().y); return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE; } } diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java index daa49c46e..e091b8557 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java @@ -27,28 +27,17 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem BinaryCell cell = (BinaryCell) board.getPuzzleElement(puzzleElement); - if(cell.getType() != BinaryType.UNKNOWN){ - if (cell.getType() == BinaryType.UNKNOWN) { - return "Only ONE or ZERO cells are allowed for this rule!"; - } + if (cell.getType() == BinaryType.UNKNOWN) { + return "Only ONE or ZERO cells are allowed for this rule!"; + } + if(cell.getType() != BinaryType.UNKNOWN){ if (contraRule.checkContradictionAt(origBoard, puzzleElement) == null) { return "Grouping of Three Ones or Zeros found"; } } return null; - } -/* - if ((upOne.getType() == BinaryType.ONE && downOne.getType() == BinaryType.ONE && cell.getType() != BinaryType.ONE) || - (upOne.getType() == BinaryType.ZERO && downOne.getType() == BinaryType.ZERO && cell.getType() != BinaryType.ZERO) || - (leftOne.getType() == BinaryType.ONE && rightOne.getType() == BinaryType.ONE && cell.getType() != BinaryType.ONE) || - (leftOne.getType() == BinaryType.ZERO && downOne.getType() == BinaryType.ZERO && cell.getType() != BinaryType.ZERO)) { - return null; - } - return super.getInvalidUseOfRuleMessage() + ": " + this.INVALID_USE_MESSAGE; - } -*/ @Override public Board getDefaultBoard(TreeNode node) { diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java index 5ef0566d7..732885a2a 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java @@ -26,12 +26,12 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem ContradictionRule contraRule = new ThreeAdjacentContradictionRule(); - BinaryCell cell = (BinaryCell) board.getPuzzleElement(puzzleElement); + BinaryCell cell = (BinaryCell) board.getPuzzleElement(puzzleElement); + if (cell.getType() == BinaryType.UNKNOWN) { + return "Only ONE or ZERO cells are allowed for this rule!"; + } + if(cell.getType() != BinaryType.UNKNOWN){ - if (cell.getType() == BinaryType.UNKNOWN) { - return "Only ONE or ZERO cells are allowed for this rule!"; - } - if (contraRule.checkContradictionAt(origBoard, puzzleElement) == null) { return "Grouping of Three Ones or Zeros found"; } diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java index 8e1fffaa9..69be423d4 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java @@ -23,29 +23,22 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { int height = binaryBoard.getHeight(); int width = binaryBoard.getWidth(); - BinaryCell cell = (BinaryCell) binaryBoard.getPuzzleElement(puzzleElement); - int cellX = cell.getLocation().x; int cellY = cell.getLocation().y; - System.out.println("X = " + cellX + ", Y = " + cellY); if(cell.getType() == BinaryType.ONE || cell.getType() == BinaryType.ZERO) { - for (int x = cell.getLocation().x - 2; x >= 0 && x < cell.getLocation().x && x < width - 2; x++) { - + for (int x = cell.getLocation().x - 2; x >= 0 && x < cell.getLocation().x && x < width - 2; x++){ if(binaryBoard.getCell(x, cellY).getType() == binaryBoard.getCell(x + 1, cellY).getType() && binaryBoard.getCell(x + 1, cellY).getType() == binaryBoard.getCell(x + 2, cellY).getType()) { - System.out.println("CUR XY fail X= " + cellX + " , " + cellY); return null; } } - for (int y = cell.getLocation().y - 2; y >= 0 && y < cell.getLocation().y && y < height - 2; y++) { - + for (int y = cell.getLocation().y - 2; y >= 0 && y < cell.getLocation().y && y < height - 2; y++){ if(binaryBoard.getCell(cellX, y).getType() == binaryBoard.getCell(cellX, y + 1).getType() && binaryBoard.getCell(cellX, y + 1).getType() == binaryBoard.getCell(cellX, y + 2).getType()) { - System.out.println("CUR XY fail Y= " + cellX + " , " + cellY); return null; } } diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowOrColumnContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowOrColumnContradictionRule.java index b58f9f02e..de18e3b5c 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowOrColumnContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowOrColumnContradictionRule.java @@ -39,9 +39,7 @@ else if(item.getType() == BinaryType.ONE) { rowNumOnes++; } } -// if (rowNumZeros + rowNumOnes != size) { -// return super.getInvalidUseOfRuleMessage() + ": " + this.INVALID_USE_MESSAGE; -// } + if (rowNumZeros > size/2 || rowNumOnes > size/2) { return null; } @@ -60,9 +58,7 @@ else if(item.getType() == BinaryType.ONE) { colNumOnes++; } } -// if (colNumZeros + colNumOnes != size) { -// return super.getInvalidUseOfRuleMessage() + ": " + this.INVALID_USE_MESSAGE; -// } + if (colNumZeros > size/2 || colNumOnes > size/2) { return null; } From 2fbc3f035603388e4e406237703b32bce433dc2a Mon Sep 17 00:00:00 2001 From: Brandon McCusker Date: Thu, 28 Mar 2024 02:49:00 -0400 Subject: [PATCH 062/258] Cleaned rule files, unified formatting, removed print statements from testing, fixed minor bug --- .../edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java index e091b8557..469d898ab 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java @@ -38,6 +38,7 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem } return null; + } @Override public Board getDefaultBoard(TreeNode node) { From bc7d4a53814716631b5567c892d3054702cfed23 Mon Sep 17 00:00:00 2001 From: EggyMath <55564321+EggyMath@users.noreply.github.com> Date: Fri, 29 Mar 2024 16:45:20 -0400 Subject: [PATCH 063/258] Refactor and Image addtions Made and added images for new contradiciton rules. Also refactored NoCellForNumber rule to NoCellForNumberRegion. --- .../NoCellForNumberColumnContradictionRule.java | 2 +- ... NoCellForNumberRegionContradictionRule.java} | 7 +++---- .../NoCellForNumberRowContradictionRule.java | 2 +- .../images/sudoku/NoCellForNumberColumn.png | Bin 0 -> 958 bytes .../images/sudoku/NoCellForNumberRegion.png | Bin 0 -> 1077 bytes .../legup/images/sudoku/NoCellForNumberRow.png | Bin 0 -> 916 bytes 6 files changed, 5 insertions(+), 6 deletions(-) rename src/main/java/edu/rpi/legup/puzzle/sudoku/rules/{NoCellForNumberContradictionRule.java => NoCellForNumberRegionContradictionRule.java} (92%) create mode 100644 src/main/resources/edu/rpi/legup/images/sudoku/NoCellForNumberColumn.png create mode 100644 src/main/resources/edu/rpi/legup/images/sudoku/NoCellForNumberRegion.png create mode 100644 src/main/resources/edu/rpi/legup/images/sudoku/NoCellForNumberRow.png diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberColumnContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberColumnContradictionRule.java index 64db5ff37..4cf076892 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberColumnContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberColumnContradictionRule.java @@ -14,7 +14,7 @@ public class NoCellForNumberColumnContradictionRule extends ContradictionRule { public NoCellForNumberColumnContradictionRule() { super("SUDO-CONT-0003", "No Cell for Number (Column)", "Process of elimination yields no valid numbers for an empty cell in a column.", - "edu/rpi/legup/images/sudoku/NoSolution.png"); + "edu/rpi/legup/images/sudoku/NoCellForNumberColumn.png"); } /** diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberRegionContradictionRule.java similarity index 92% rename from src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberContradictionRule.java rename to src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberRegionContradictionRule.java index 9c53df794..9923bd207 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberRegionContradictionRule.java @@ -3,19 +3,18 @@ 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.sudoku.Sudoku; import edu.rpi.legup.puzzle.sudoku.SudokuBoard; import edu.rpi.legup.puzzle.sudoku.SudokuCell; import java.util.HashSet; import java.util.Set; -public class NoCellForNumberContradictionRule extends ContradictionRule { +public class NoCellForNumberRegionContradictionRule extends ContradictionRule { - public NoCellForNumberContradictionRule() { + public NoCellForNumberRegionContradictionRule() { super("SUDO-CONT-0001", "No Cell for Number (Region)", "Process of elimination yields no valid numbers for an empty cell in a region.", - "edu/rpi/legup/images/sudoku/NoSolution.png"); + "edu/rpi/legup/images/sudoku/NoCellForNumberRegion.png"); } /** diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberRowContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberRowContradictionRule.java index 28fc9a49b..6e8616a9f 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberRowContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberRowContradictionRule.java @@ -14,7 +14,7 @@ public class NoCellForNumberRowContradictionRule extends ContradictionRule { public NoCellForNumberRowContradictionRule() { super("SUDO-CONT-0002", "No Cell for Number (Row)", "Process of elimination yields no valid numbers for an empty cell in a row.", - "edu/rpi/legup/images/sudoku/NoSolution.png"); + "edu/rpi/legup/images/sudoku/NoCellForNumberRow.png"); } /** diff --git a/src/main/resources/edu/rpi/legup/images/sudoku/NoCellForNumberColumn.png b/src/main/resources/edu/rpi/legup/images/sudoku/NoCellForNumberColumn.png new file mode 100644 index 0000000000000000000000000000000000000000..9dcade64b2fb79be751848670324692e7b464cce GIT binary patch literal 958 zcmV;v13~Px&cu7P-RCt{2oWE|{Fc62&MF))<`XUzK#XyG|=+Ni!%*l^cAWMOGFu=S>2M--I z6iA0!jigW#?|2fg((eO;1djX%`g}a{MBUEc{42Gn4i)*Er!iuVNjZMYeBeF-CwE>x zat^KzRp)mbNYa5N1Sfrd*h3bW7YH#1gcu{3LqbU#EJIMpD-pdYCGh>BqMgbsZG+&D z^>XvHSBR4Rp;8mO6$W!isuakOF`Cq+QXoUlkuw@xU5kk1@ z42hKf|F_I&QkO3JF#D1-C?vHUGA3o~Q7}eOh*oV1k-{gKLv}<&GoQ$*T(VVyLN1q! z>YF&{R9~;p{~$JYn9jN{3%TSyqH3>IEDGjEFLo{(144`eA;w4&GWYChi-?6l#yp6G zIOnJ=OYP4BC?P`5=d#AJ5s|J6k6Q zYtdl^baHsmEvKFI&$WY26S?GP}eopb)EZTEZ@n&YIIm((M}FAci_e_$FP!n zsA@nh%NU{vX%ADJAuHxC+^w^CCkF@^hb3gHlLJU6T1adshZqng!$b+;c5(o6CWS~l zIZS~l34=}!#u%LTYISlLdkyUxu5a?nJ-WHSNreC_+x(PW1HsiTu@5Q52ZgD#8|W{BrE3 z3A2IHi7_C=7!YC%2r))5sbeae4{UNU28JwSK!`CQ#264_3yOtH2F`>4l2P;C_ gZBv_{_TwO(KSVOPa4)&_O8@`>07*qoM6N<$g6E{9PXGV_ literal 0 HcmV?d00001 diff --git a/src/main/resources/edu/rpi/legup/images/sudoku/NoCellForNumberRegion.png b/src/main/resources/edu/rpi/legup/images/sudoku/NoCellForNumberRegion.png new file mode 100644 index 0000000000000000000000000000000000000000..000dc8b68935563c869c695b114190eac7499805 GIT binary patch literal 1077 zcmeAS@N?(olHy`uVBq!ia0vp^DImV1DoE;uumf z=k1)me$tKt$N&2Y6uk`p=oNk>s4K#2;`4rb9xS z7iK=SsK4{>OjTNb-K1^@iM$_o@6}b*3zKK1sW$F0Z5C)l(Hs9l}f z^X*5i;>;_WlV*kS)yv6u_uOaS6dL9gwERxwt;h4ZUT!j1TWNPPqraZ($?pkvo<~&{ z+x|10G;Qzij7e2dzxV#0Iz@H)w;$~Zf=qi&Qf>9PFDPYX7BX0`12JonP$_7uTOJjLr~g}(jhe518xwdlFc%4K$?H*eL33p@`}XsTDGHtIQ#o$WvU9?^ly7T&Zh6Mm?bEUQXXw%DVPic> zk~d;l5Z>R?_#QR`O`wi_4*YwV@p4f8L}zC^ID7 zQOWF=cb+uiXp&>8to(}Cv%V^v5AFN=D|tguP~r>$6trO~V`<=Z)1N_`SLbyV?YtAW zuSjodqmNV4^(V(O_7}SNUgteh7~HzSe$%U6$5MDJ6&= zvfa~o{rI%slb+jXx!XmmmuAiSc{nuBd}p!vrozK&OJ<(9Eo^l>_L`Wp?$dAIbsKDo zf&O3D{ao(TzXQkFlTLn|!KIm%ydsuuK@A^g;nc$wHpgDoxk_!%=0B>bxmsXa>@U`a zx3BlFOr4V~zo@DuBR;S+@QO?jlbVYJ1bMa=9ZT$bJ$>okciL?CiRK zjpD*(@z(+ZuIguVtav>=)Jp4j>Q>JF6PD9XeSTleaNyZ}wi}=1vNpZFa=0$|t$2Hn z8%rtgjX%d_PVZKoR_^_Sz5ipynO&M;clBRCd&YKPcF)`?@g_lO_tS3txx44L)Yodg z+>r05tM1vA*C%_6{IB${aRc&q{j21Cklf0B)#j1>pZ3UUzj@Yo)I~Dv?I~WkD?Uu4 zF+1oxzue~ao9}v;y6=?vyX=tQK~t-+@2l^2OK<(V=^X2KnM0cl-(1euD&>?B+gw<~ zrz&DF)8~eK?r|b literal 0 HcmV?d00001 diff --git a/src/main/resources/edu/rpi/legup/images/sudoku/NoCellForNumberRow.png b/src/main/resources/edu/rpi/legup/images/sudoku/NoCellForNumberRow.png new file mode 100644 index 0000000000000000000000000000000000000000..f984f836508fbc3d6f0dce4d9b749f5e53de8d87 GIT binary patch literal 916 zcmeAS@N?(olHy`uVBq!ia0vp^DImVD|HLaSW-L z^LFmWyxRsMuJgNjq)flK`#3oBl&omv`zv>T)}Kh$O)MSk%xC&bPOQ+K8F8a2*YnBZ zd#csv=l!sgw+mV%lJ@xgzhDlY`)imdWNWbSa4|MJ9atb>fW(}qV|S(W+@oaihv)A- zDZZ(gFr&odK$eKzpL-(rTv}e zMq{QoAme+oS|aR^Us%MYINiuA&fY~!P)H-T&BN8{*88=kETUcFn|^N;7M$3>U;db9 ziAGe%>p47!6?`v;7{+#r=&5}8_A5=+u~)0*ipxf)L$?B@k8%l4Ty?F_p>TG0W1_?w z<&=dl_*PC#vR<-nrPcvHOiuy*cUk&yRGiO+7Fnh?&-N?3-Y#Uc2Kirkwt(J^!j!iH zCYtMt3uYcGIK_k!B%3%K_g`~Y%Wf|aF0`Dp2^3(9=C>EjJ#kp=Ykk1cu9I8$E#VV+ zU8*1Hk?>A@W7t9OqY>R4D>ymt{8n1SHBYEnNoj$e3(Mz}){PQVVv;w-q_!qa?Amvx zX-c-wG(N?TIW8?u4HdJj7QPL3xi>Yc=CZW(p zor_s6c+mFH+uw12{p{HPJy}0*d)8XTll7O%EFT5A$48j!UFX+zoMp-U@5%qUInU3> zxq3~SP?(q))uCJV=jihZij(Gj7JAEUv3U8KYSzrRnwcBJ{4Q%|XO(339S|vc&Lebd zTj*`cIGvO{Mya5nWvfk#o>hF>k#QQ2@#E!F3`Y22N%uG!+zUgxUM2u-s3x+XM7 z(^B40(kq%sZU$yE22WQ%mvv4F FO#n+HlXCz7 literal 0 HcmV?d00001 From 27f0d919a5d36b35424037f0070c8620fb9f2361 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Fri, 29 Mar 2024 18:24:51 -0400 Subject: [PATCH 064/258] Found error in ThreeAdjacentContradictionRule, missing valid contradictions in OneTileGap and SurroundPair Direct Rules --- .../rules/CompleteRowColumnDirectRule.java | 43 +++++-------------- .../binary/rules/OneTileGapDirectRule.java | 39 +++++++++++------ .../binary/rules/SurroundPairDirectRule.java | 29 +++++++------ .../rules/ThreeAdjacentContradictionRule.java | 10 ++++- 4 files changed, 63 insertions(+), 58 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java index 147d1c2a1..6b4399903 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java @@ -34,42 +34,21 @@ public CompleteRowColumnDirectRule() { */ @Override public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - BinaryBoard initialBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); - BinaryBoard finalBoard = (BinaryBoard) transition.getBoard(); - int elementIndex = puzzleElement.getIndex(); - int boardDim = initialBoard.getWidth(); - int elementRow = elementIndex / boardDim; - int elementCol = elementIndex % boardDim; - - int numColZeros = 0; - int numColOnes = 0; - for (int i = 0; i < boardDim; i++) { - BinaryCell cell = initialBoard.getCell(i, elementCol); - if(cell.getData() == 1){ - numColOnes ++; - } - else if(cell.getData() == 0) { - numColZeros ++; - } + BinaryBoard board = (BinaryBoard) transition.getBoard(); + BinaryBoard origBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); + ContradictionRule contraRule = new UnbalancedRowOrColumnContradictionRule(); + + BinaryCell cell = (BinaryCell) board.getPuzzleElement(puzzleElement); + if (cell.getType() == BinaryType.UNKNOWN) { + return "Only ONE or ZERO cells are allowed for this rule!"; } - int numRowZeros = 0; - int numRowOnes = 0; - for (int i = 0; i < boardDim; i++) { - BinaryCell cell = initialBoard.getCell(elementRow, i); - if(cell.getData() == 1) { - numRowOnes ++; - } - else if(cell.getData() == 0) { - numRowZeros ++; + if(cell.getType() != BinaryType.UNKNOWN){ + if (contraRule.checkContradictionAt(origBoard, puzzleElement) != null) { + return "Balanced row or column found"; } - } - if (numColOnes + numColZeros != boardDim) { - return super.getInvalidUseOfRuleMessage() + ": The column for the specificed element is not complete"; - } - if (numRowOnes + numRowZeros != boardDim) { - return super.getInvalidUseOfRuleMessage() + ": The row for the specified element is not complete"; + } return null; } diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java index 469d898ab..26f1f1be0 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java @@ -10,6 +10,8 @@ import edu.rpi.legup.puzzle.binary.BinaryCell; import edu.rpi.legup.puzzle.binary.BinaryType; +import java.util.Set; + public class OneTileGapDirectRule extends DirectRule { private final String INVALID_USE_MESSAGE = "Number at cell is incorrect"; public OneTileGapDirectRule() { @@ -21,22 +23,35 @@ public OneTileGapDirectRule() { @Override public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - BinaryBoard board = (BinaryBoard) transition.getBoard(); + BinaryBoard destBoard = (BinaryBoard) transition.getBoard(); BinaryBoard origBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); ContradictionRule contraRule = new ThreeAdjacentContradictionRule(); + Set changedCells = destBoard.getModifiedData(); +// for (PuzzleElement p : changedCells) { +// BinaryCell c = (BinaryCell) destBoard.getPuzzleElement(p); +// if (c.getData() == 0) { +// c.setData(1); +// int cX = c.getLocation().x; +// int cY = c.getLocation().y; +// if ((destBoard.getCell(cX-1, cY).getType() == BinaryType.ONE && destBoard.getCell(cX+1, cY).getType() == BinaryType.ONE) || +// (destBoard.getCell(cX, cY-1).getType() == BinaryType.ONE && destBoard.getCell(cX, cY+1).getType() == BinaryType.ONE)) { +// return "" +// } +// +// } +// else if (c.getData() == 1) +// c.setData(0); +// else if (c.getData() == 2) +// return "Only ONE or ZERO cells are allowed for this rule!"; +// if (c.getLocation().x-1) +// } +// +// if (c.getType() ) +// if (contraRule.checkContradictionAt(destBoard, puzzleElement) != null) { +// return "Grouping of Three Ones or Zeros found"; +// } - BinaryCell cell = (BinaryCell) board.getPuzzleElement(puzzleElement); - if (cell.getType() == BinaryType.UNKNOWN) { - return "Only ONE or ZERO cells are allowed for this rule!"; - } - - if(cell.getType() != BinaryType.UNKNOWN){ - if (contraRule.checkContradictionAt(origBoard, puzzleElement) == null) { - return "Grouping of Three Ones or Zeros found"; - } - - } return null; } diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java index 732885a2a..d6747b9fa 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java @@ -10,6 +10,9 @@ import edu.rpi.legup.puzzle.binary.BinaryCell; import edu.rpi.legup.puzzle.binary.BinaryType; +import java.util.ArrayList; +import java.util.Set; + public class SurroundPairDirectRule extends DirectRule { public SurroundPairDirectRule() { @@ -21,22 +24,24 @@ public SurroundPairDirectRule() { @Override public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - BinaryBoard board = (BinaryBoard) transition.getBoard(); + BinaryBoard destBoard = (BinaryBoard) transition.getBoard(); BinaryBoard origBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); ContradictionRule contraRule = new ThreeAdjacentContradictionRule(); - - BinaryCell cell = (BinaryCell) board.getPuzzleElement(puzzleElement); - if (cell.getType() == BinaryType.UNKNOWN) { - return "Only ONE or ZERO cells are allowed for this rule!"; - } - - if(cell.getType() != BinaryType.UNKNOWN){ - if (contraRule.checkContradictionAt(origBoard, puzzleElement) == null) { - return "Grouping of Three Ones or Zeros found"; - } - + Set changedCells = destBoard.getModifiedData(); +// for (PuzzleElement p : changedCells) { +// BinaryCell c = (BinaryCell) destBoard.getPuzzleElement(p); +// if (c.getData() == 0) +// c.setData(1); +// else if (c.getData() == 1) +// c.setData(0); +// else if (c.getData() == 2) +// return "Only ONE or ZERO cells are allowed for this rule!"; +// } + if (contraRule.checkContradictionAt(destBoard, puzzleElement) == null) { + return "Grouping of Three Ones or Zeros found"; } + return null; } diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java index 69be423d4..8c39900e1 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java @@ -29,16 +29,22 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { int cellY = cell.getLocation().y; if(cell.getType() == BinaryType.ONE || cell.getType() == BinaryType.ZERO) { - for (int x = cell.getLocation().x - 2; x >= 0 && x < cell.getLocation().x && x < width - 2; x++){ + for (int x = cell.getLocation().x - 2; x < cell.getLocation().x && x < width - 2; x++){ + if (x < 0) + continue; if(binaryBoard.getCell(x, cellY).getType() == binaryBoard.getCell(x + 1, cellY).getType() && binaryBoard.getCell(x + 1, cellY).getType() == binaryBoard.getCell(x + 2, cellY).getType()) { + System.out.println("Contradiction Found because of " + binaryBoard.getCell(x, cellY).getLocation().x + " " + binaryBoard.getCell(x, cellY).getLocation().y + " " + + binaryBoard.getCell(x+1, cellY).getLocation().x + " " + binaryBoard.getCell(x+1, cellY).getLocation().y + " " + + binaryBoard.getCell(x+2, cellY).getLocation().x + " " + binaryBoard.getCell(x+2, cellY).getLocation().y); return null; } } - for (int y = cell.getLocation().y - 2; y >= 0 && y < cell.getLocation().y && y < height - 2; y++){ + for (int y = cell.getLocation().y - 2; y < cell.getLocation().y && y < height - 2; y++){ + if (y < 0) + continue; if(binaryBoard.getCell(cellX, y).getType() == binaryBoard.getCell(cellX, y + 1).getType() && binaryBoard.getCell(cellX, y + 1).getType() == binaryBoard.getCell(cellX, y + 2).getType()) { + System.out.println("Contradiction Found because of " + binaryBoard.getCell(cellX, y+2).getLocation().x + " " + binaryBoard.getCell(cellX, y).getLocation().y + " " + + binaryBoard.getCell(cellX, y+1).getLocation().x + " " + binaryBoard.getCell(cellX, y+1).getLocation().y + " " + + binaryBoard.getCell(cellX, y+2).getLocation().x + " " + binaryBoard.getCell(cellX, y+2).getLocation().y); return null; } } From 6d43ce06996e1f2bf64dfe6bdba3247c349b7e72 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Sat, 30 Mar 2024 01:26:42 -0400 Subject: [PATCH 065/258] Fixed checkStyle error "if construct must use {}'s" --- .../puzzle/binary/rules/ThreeAdjacentContradictionRule.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java index 8c39900e1..2f36a220f 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java @@ -30,8 +30,9 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { if(cell.getType() == BinaryType.ONE || cell.getType() == BinaryType.ZERO) { for (int x = cell.getLocation().x - 2; x < cell.getLocation().x && x < width - 2; x++){ - if (x < 0) + if (x < 0) { continue; + } if(binaryBoard.getCell(x, cellY).getType() == binaryBoard.getCell(x + 1, cellY).getType() && binaryBoard.getCell(x + 1, cellY).getType() == binaryBoard.getCell(x + 2, cellY).getType()) { System.out.println("Contradiction Found because of " + binaryBoard.getCell(x, cellY).getLocation().x + " " + binaryBoard.getCell(x, cellY).getLocation().y + " " + + binaryBoard.getCell(x+1, cellY).getLocation().x + " " + binaryBoard.getCell(x+1, cellY).getLocation().y + " " + + binaryBoard.getCell(x+2, cellY).getLocation().x + " " + binaryBoard.getCell(x+2, cellY).getLocation().y); @@ -40,8 +41,9 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { } for (int y = cell.getLocation().y - 2; y < cell.getLocation().y && y < height - 2; y++){ - if (y < 0) + if (y < 0) { continue; + } if(binaryBoard.getCell(cellX, y).getType() == binaryBoard.getCell(cellX, y + 1).getType() && binaryBoard.getCell(cellX, y + 1).getType() == binaryBoard.getCell(cellX, y + 2).getType()) { System.out.println("Contradiction Found because of " + binaryBoard.getCell(cellX, y+2).getLocation().x + " " + binaryBoard.getCell(cellX, y).getLocation().y + " " + + binaryBoard.getCell(cellX, y+1).getLocation().x + " " + binaryBoard.getCell(cellX, y+1).getLocation().y + " " + + binaryBoard.getCell(cellX, y+2).getLocation().x + " " + binaryBoard.getCell(cellX, y+2).getLocation().y); From 1174d5148c0c9674300941983917d09624200b26 Mon Sep 17 00:00:00 2001 From: kchiu1 <152306707+kchiu1@users.noreply.github.com> Date: Tue, 2 Apr 2024 16:26:55 -0400 Subject: [PATCH 066/258] No more advanced deduction It wasn't doing anything and was always returning true. --- .../rules/AdvancedDeductionDirectRule.java | 96 ------------------ .../legup/images/sudoku/AdvancedDeduction.png | Bin 3351 -> 0 bytes 2 files changed, 96 deletions(-) delete mode 100644 src/main/java/edu/rpi/legup/puzzle/sudoku/rules/AdvancedDeductionDirectRule.java delete mode 100644 src/main/resources/edu/rpi/legup/images/sudoku/AdvancedDeduction.png diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/AdvancedDeductionDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/AdvancedDeductionDirectRule.java deleted file mode 100644 index 0be30fa36..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/AdvancedDeductionDirectRule.java +++ /dev/null @@ -1,96 +0,0 @@ -package edu.rpi.legup.puzzle.sudoku.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.sudoku.SudokuBoard; -import edu.rpi.legup.puzzle.sudoku.SudokuCell; - -public class AdvancedDeductionDirectRule extends DirectRule { - - public AdvancedDeductionDirectRule() { - super("SUDO-BASC-0001", "Advanced Deduction", - "Use of group logic deduces more answers by means of forced by Location and forced by Deduction", - "edu/rpi/legup/images/sudoku/AdvancedDeduction.png"); - } - - /** - * 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 - */ - public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - SudokuBoard initialBoard = (SudokuBoard) transition.getParents().get(0).getBoard(); - SudokuBoard finalBoard = (SudokuBoard) transition.getBoard(); - - SudokuCell cell = (SudokuCell) finalBoard.getPuzzleElement(puzzleElement); - int index = cell.getIndex(); - int groupSize = initialBoard.getWidth(); - int groupDim = (int) Math.sqrt(groupSize); - int rowIndex = index / groupSize; - int colIndex = index % groupSize; - int relX = rowIndex / groupDim; - int relY = colIndex % groupDim; - int groupNum = rowIndex / groupDim * groupDim + colIndex / groupDim; - boolean[][] possible = new boolean[groupDim][groupDim]; - for (int y = 0; y < groupDim; y++) { - for (int x = 0; x < groupDim; x++) { - SudokuCell c = initialBoard.getCell(groupNum, x, y); - if (c.getData() == cell.getData() && x != relX && y != relY) { - return super.getRuleName() + ": Duplicate value in sub-region"; - } - possible[y][x] = c.getData() == 0; - } - } - for (int y = 0; y < groupDim; y++) { - for (int x = 0; x < groupSize; x++) { - SudokuCell r = initialBoard.getCell(x, (groupNum / groupDim) * groupDim + y); - SudokuCell c = initialBoard.getCell((groupNum % groupDim) * groupDim + y, x); - if (r.getData() == cell.getData()) { - for (int i = 0; i < groupDim; i++) { - possible[y][i] = false; - } - } - if (c.getData() == cell.getData()) { - for (int i = 0; i < groupDim; i++) { - possible[i][y] = false; - } - } - } - } - boolean isForced = false; - for (int y = 0; y < groupDim; y++) { - for (int x = 0; x < groupDim; x++) { - if (possible[y][x] && !isForced) { - isForced = true; - } - else { - if (possible[y][x]) { - return super.getInvalidUseOfRuleMessage() + ": Not forced"; - } - } - } - } - if (!isForced) { - return super.getInvalidUseOfRuleMessage() + ": Not forced"; - } - return null; - } - - /** - * 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) { - return null; - } -} diff --git a/src/main/resources/edu/rpi/legup/images/sudoku/AdvancedDeduction.png b/src/main/resources/edu/rpi/legup/images/sudoku/AdvancedDeduction.png deleted file mode 100644 index d51538baf164400e6c4cca37fa44f738b2d3c6c1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3351 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 From 7294dac452c73656737ade178bba5e7185bb5394 Mon Sep 17 00:00:00 2001 From: kchiu1 <152306707+kchiu1@users.noreply.github.com> Date: Tue, 2 Apr 2024 16:44:44 -0400 Subject: [PATCH 067/258] Updated reference sheet --- .../legup/puzzle/sudoku/rules/sudoku_reference_sheet.txt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/sudoku_reference_sheet.txt b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/sudoku_reference_sheet.txt index b36fc5e02..daf2c5047 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/sudoku_reference_sheet.txt +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/sudoku_reference_sheet.txt @@ -2,11 +2,13 @@ SUDO-BASC-0001 : AdvancedDeductionDirectRule SUDO-BASC-0002 : LastCellForNumberDirectRule SUDO-BASC-0003 : LastNumberForCellDirectRule -SUDO-CONT-0001 : NoCellForNumberContradictionRule +SUDO-CONT-0001 : NoCellForNumberRegionContradictionRule SUDO-CONT-0002 : NoCellForNumberRowContradictionRule SUDO-CONT-0003 : NoCellForNumberColumnContradictionRule SUDO-CONT-0004 : NoNumberForCellContradictionRule SUDO-CONT-0002 : RepeatedNumberContradictionRule -SUDO-CASE-0001 : PossibleCellCaseRule -SUDO-CASE-0002 : PossibleNumberCaseRule \ No newline at end of file +SUDO-CASE-0001 : PossibleNumbersForCellCaseRule +SUDO-CASE-0002 : PossibleCellsForNumberRegionCaseRule +SUDO-CASE-0003 : PossibleCellsForNumberRowCaseRule +SUDO-CASE-0004 : PossibleCellsForNumberColumnCaseRule \ No newline at end of file From a87fc7d1ab970200bf0c039f9c200a95f3147ae3 Mon Sep 17 00:00:00 2001 From: kchiu1 <152306707+kchiu1@users.noreply.github.com> Date: Tue, 2 Apr 2024 16:50:15 -0400 Subject: [PATCH 068/258] No advanced deduction in list --- .../edu/rpi/legup/puzzle/sudoku/rules/sudoku_reference_sheet.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/sudoku_reference_sheet.txt b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/sudoku_reference_sheet.txt index daf2c5047..3f9e62cc8 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/sudoku_reference_sheet.txt +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/sudoku_reference_sheet.txt @@ -1,4 +1,3 @@ -SUDO-BASC-0001 : AdvancedDeductionDirectRule SUDO-BASC-0002 : LastCellForNumberDirectRule SUDO-BASC-0003 : LastNumberForCellDirectRule From 82536afff133be7fc0b1b8b5689e96ecdc4d3bcc Mon Sep 17 00:00:00 2001 From: Brandon McCusker Date: Fri, 5 Apr 2024 15:52:24 -0400 Subject: [PATCH 069/258] Fixed buggy three adjacent contradiction rule --- .../binary/rules/SurroundPairDirectRule.java | 40 ++++++++++++------ .../rules/ThreeAdjacentContradictionRule.java | 42 +++++++++++-------- 2 files changed, 51 insertions(+), 31 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java index d6747b9fa..f8e801090 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java @@ -24,24 +24,38 @@ public SurroundPairDirectRule() { @Override public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - BinaryBoard destBoard = (BinaryBoard) transition.getBoard(); + BinaryBoard board = (BinaryBoard) transition.getBoard(); BinaryBoard origBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); ContradictionRule contraRule = new ThreeAdjacentContradictionRule(); - Set changedCells = destBoard.getModifiedData(); -// for (PuzzleElement p : changedCells) { -// BinaryCell c = (BinaryCell) destBoard.getPuzzleElement(p); -// if (c.getData() == 0) -// c.setData(1); -// else if (c.getData() == 1) -// c.setData(0); -// else if (c.getData() == 2) -// return "Only ONE or ZERO cells are allowed for this rule!"; -// } - if (contraRule.checkContradictionAt(destBoard, puzzleElement) == null) { - return "Grouping of Three Ones or Zeros found"; + BinaryCell cell = (BinaryCell) board.getPuzzleElement(puzzleElement); + if(cell.getType() == BinaryType.UNKNOWN){ + return "Only ONE and ZERO allowed for this rule!"; } + BinaryBoard modified = origBoard.copy(); + BinaryCell c = (BinaryCell) modified.getPuzzleElement(puzzleElement); + if (c.getData() == 0) + modified.getPuzzleElement(puzzleElement).setData(1); + else if (c.getData() == 1) + modified.getPuzzleElement(puzzleElement).setData(0); + if(contraRule.checkContradictionAt(modified, puzzleElement) != null){ + return "Grouping of three ONEs or ZEROs found"; + } + + + // Set changedCells = destBoard.getModifiedData(); + // for (PuzzleElement p : changedCells) { + // BinaryCell c = (BinaryCell) destBoard.getPuzzleElement(p); + // System.out.println(c.getLocation()); + // // if (c.getData() == 0) + // // c.setData(1); + // // else if (c.getData() == 1) + // // c.setData(0); + // if (contraRule.checkContradictionAt(destBoard, puzzleElement) == null) { + // return "Grouping of Three Ones or Zeros found"; + // } + // } return null; } diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java index 2f36a220f..1ca2bda1b 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java @@ -24,31 +24,37 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { int width = binaryBoard.getWidth(); BinaryCell cell = (BinaryCell) binaryBoard.getPuzzleElement(puzzleElement); - + int cellX = cell.getLocation().x; int cellY = cell.getLocation().y; + BinaryCell oneUp = null; + BinaryCell oneDown = null; + BinaryCell oneForward = null; + BinaryCell oneBackward = null; + if(binaryBoard.getCell(cellX, cellY + 1) != null){ + oneUp = binaryBoard.getCell(cellX, cellY + 1); + } + if(binaryBoard.getCell(cellX, cellY - 1) != null){ + oneDown = binaryBoard.getCell(cellX, cellY - 1); + } + if(binaryBoard.getCell(cellX + 1, cellY) != null){ + oneForward = binaryBoard.getCell(cellX + 1, cellY); + } + if(binaryBoard.getCell(cellX - 1, cellY) != null){ + oneBackward = binaryBoard.getCell(cellX - 1, cellY); + } + //System.out.println("UP: " + oneUp.getLocation() + " " + "DOWN: " + oneDown.getLocation() + + // " " + "BACKWARD: " + oneBackward.getLocation() + " " + "FORWARD: " + oneForward.getLocation() + " " + "CELL: " + cell.getLocation()); + if(cell.getType() == BinaryType.ONE || cell.getType() == BinaryType.ZERO) { - for (int x = cell.getLocation().x - 2; x < cell.getLocation().x && x < width - 2; x++){ - if (x < 0) { - continue; - } - if(binaryBoard.getCell(x, cellY).getType() == binaryBoard.getCell(x + 1, cellY).getType() && - binaryBoard.getCell(x + 1, cellY).getType() == binaryBoard.getCell(x + 2, cellY).getType()) { - System.out.println("Contradiction Found because of " + binaryBoard.getCell(x, cellY).getLocation().x + " " + binaryBoard.getCell(x, cellY).getLocation().y + " " + + binaryBoard.getCell(x+1, cellY).getLocation().x + " " + binaryBoard.getCell(x+1, cellY).getLocation().y + " " + + binaryBoard.getCell(x+2, cellY).getLocation().x + " " + binaryBoard.getCell(x+2, cellY).getLocation().y); + if(oneBackward != null && oneForward != null){ + if(oneBackward.getType() == cell.getType() && oneForward.getType() == cell.getType()) return null; - } } - - for (int y = cell.getLocation().y - 2; y < cell.getLocation().y && y < height - 2; y++){ - if (y < 0) { - continue; - } - if(binaryBoard.getCell(cellX, y).getType() == binaryBoard.getCell(cellX, y + 1).getType() && - binaryBoard.getCell(cellX, y + 1).getType() == binaryBoard.getCell(cellX, y + 2).getType()) { - System.out.println("Contradiction Found because of " + binaryBoard.getCell(cellX, y+2).getLocation().x + " " + binaryBoard.getCell(cellX, y).getLocation().y + " " + + binaryBoard.getCell(cellX, y+1).getLocation().x + " " + binaryBoard.getCell(cellX, y+1).getLocation().y + " " + + binaryBoard.getCell(cellX, y+2).getLocation().x + " " + binaryBoard.getCell(cellX, y+2).getLocation().y); + if(oneUp != null && oneDown != null){ + if(oneUp.getType() == cell.getType() && oneDown.getType() == cell.getType()) return null; - } } } return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE; From 534e5561a06cad6bdc88816d3f2e6f3de74d215f Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Fri, 5 Apr 2024 15:59:50 -0400 Subject: [PATCH 070/258] Made slight progress in onetilegap direct rule --- .../binary/rules/OneTileGapDirectRule.java | 64 ++++++++++++------- .../binary/rules/SurroundPairDirectRule.java | 18 +++--- .../rules/ThreeAdjacentContradictionRule.java | 10 +-- 3 files changed, 52 insertions(+), 40 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java index 26f1f1be0..d89fab61b 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java @@ -21,6 +21,16 @@ public OneTileGapDirectRule() { "edu/rpi/legup/images/binary/rules/OneTileGapDirectRule.png"); } + boolean checkLeftRight(BinaryCell c, BinaryBoard board) { + int x = c.getLocation().x; + int y = c.getLocation().y; + return board.getCell(x - 1, y).getType() != c.getType() || board.getCell(x + 1, y).getType() != c.getType(); + } + boolean checkUpDown(BinaryCell c, BinaryBoard board) { + int x = c.getLocation().x; + int y = c.getLocation().y; + return board.getCell(x, y - 1).getType() != c.getType() || board.getCell(x, y + 1).getType() != c.getType(); + } @Override public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { BinaryBoard destBoard = (BinaryBoard) transition.getBoard(); @@ -28,30 +38,38 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem ContradictionRule contraRule = new ThreeAdjacentContradictionRule(); Set changedCells = destBoard.getModifiedData(); -// for (PuzzleElement p : changedCells) { -// BinaryCell c = (BinaryCell) destBoard.getPuzzleElement(p); -// if (c.getData() == 0) { -// c.setData(1); -// int cX = c.getLocation().x; -// int cY = c.getLocation().y; -// if ((destBoard.getCell(cX-1, cY).getType() == BinaryType.ONE && destBoard.getCell(cX+1, cY).getType() == BinaryType.ONE) || -// (destBoard.getCell(cX, cY-1).getType() == BinaryType.ONE && destBoard.getCell(cX, cY+1).getType() == BinaryType.ONE)) { -// return "" -// } -// -// } -// else if (c.getData() == 1) -// c.setData(0); -// else if (c.getData() == 2) -// return "Only ONE or ZERO cells are allowed for this rule!"; -// if (c.getLocation().x-1) -// } -// -// if (c.getType() ) -// if (contraRule.checkContradictionAt(destBoard, puzzleElement) != null) { -// return "Grouping of Three Ones or Zeros found"; -// } + for (PuzzleElement p : changedCells) { + BinaryCell c = (BinaryCell) destBoard.getPuzzleElement(p); + int x = c.getLocation().x; + int y = c.getLocation().y; + boolean xOutOfBounds = false; + boolean yOutOfBounds = false; + if ((x - 1 < 0 || x + 1 >= destBoard.getWidth())) { + xOutOfBounds = true; + } + if ((y - 1 < 0 || y + 1 >= destBoard.getHeight())) { + yOutOfBounds = true; + } + if (xOutOfBounds && yOutOfBounds) { + return "Corner of cell cannot have a one tile gap solution"; + } + if (xOutOfBounds && !yOutOfBounds) { + if (!checkUpDown(c, destBoard)) { + return "Not a valid one tile gap"; + } + } + System.out.println(x + " " + y); + System.out.println(c.getType()); + if (c.getType() != BinaryType.UNKNOWN) { + if (destBoard.getCell(x-1, y).getType() == c.getType() && + destBoard.getCell(x+1, y).getType() == c.getType() || + (destBoard.getCell(x, y-1).getType() == c.getType() && + destBoard.getCell(x, y+1).getType() == c.getType())) { + return "Grouping of Three Ones or Zeros found"; + } + } + } return null; } diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java index d6747b9fa..1c54eacb3 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java @@ -29,15 +29,15 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem ContradictionRule contraRule = new ThreeAdjacentContradictionRule(); Set changedCells = destBoard.getModifiedData(); -// for (PuzzleElement p : changedCells) { -// BinaryCell c = (BinaryCell) destBoard.getPuzzleElement(p); -// if (c.getData() == 0) -// c.setData(1); -// else if (c.getData() == 1) -// c.setData(0); -// else if (c.getData() == 2) -// return "Only ONE or ZERO cells are allowed for this rule!"; -// } + for (PuzzleElement p : changedCells) { + BinaryCell c = (BinaryCell) destBoard.getPuzzleElement(p); + if (c.getData() == 0) + c.setData(1); + else if (c.getData() == 1) + c.setData(0); + else if (c.getData() == 2) + return "Only ONE or ZERO cells are allowed for this rule!"; + } if (contraRule.checkContradictionAt(destBoard, puzzleElement) == null) { return "Grouping of Three Ones or Zeros found"; } diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java index 2f36a220f..e4e1b3ba2 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java @@ -29,10 +29,7 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { int cellY = cell.getLocation().y; if(cell.getType() == BinaryType.ONE || cell.getType() == BinaryType.ZERO) { - for (int x = cell.getLocation().x - 2; x < cell.getLocation().x && x < width - 2; x++){ - if (x < 0) { - continue; - } + for (int x = cell.getLocation().x - 2; x < 0 && x < cell.getLocation().x && x < width - 2; x++) { if(binaryBoard.getCell(x, cellY).getType() == binaryBoard.getCell(x + 1, cellY).getType() && binaryBoard.getCell(x + 1, cellY).getType() == binaryBoard.getCell(x + 2, cellY).getType()) { System.out.println("Contradiction Found because of " + binaryBoard.getCell(x, cellY).getLocation().x + " " + binaryBoard.getCell(x, cellY).getLocation().y + " " + + binaryBoard.getCell(x+1, cellY).getLocation().x + " " + binaryBoard.getCell(x+1, cellY).getLocation().y + " " + + binaryBoard.getCell(x+2, cellY).getLocation().x + " " + binaryBoard.getCell(x+2, cellY).getLocation().y); @@ -40,10 +37,7 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { } } - for (int y = cell.getLocation().y - 2; y < cell.getLocation().y && y < height - 2; y++){ - if (y < 0) { - continue; - } + for (int y = cell.getLocation().y - 2; y < 0 && y < cell.getLocation().y && y < height - 2; y++){ if(binaryBoard.getCell(cellX, y).getType() == binaryBoard.getCell(cellX, y + 1).getType() && binaryBoard.getCell(cellX, y + 1).getType() == binaryBoard.getCell(cellX, y + 2).getType()) { System.out.println("Contradiction Found because of " + binaryBoard.getCell(cellX, y+2).getLocation().x + " " + binaryBoard.getCell(cellX, y).getLocation().y + " " + + binaryBoard.getCell(cellX, y+1).getLocation().x + " " + binaryBoard.getCell(cellX, y+1).getLocation().y + " " + + binaryBoard.getCell(cellX, y+2).getLocation().x + " " + binaryBoard.getCell(cellX, y+2).getLocation().y); From 019649c01b702fb7db78a16baac5b4f6ccc76b95 Mon Sep 17 00:00:00 2001 From: kchiu1 <152306707+kchiu1@users.noreply.github.com> Date: Fri, 5 Apr 2024 16:13:31 -0400 Subject: [PATCH 071/258] Added Fake Tests Fake tests added --- .../BottomLeftWhiteBlackSquare | 11 +++++++++++ .../BottomRightWhiteBlackSquare | 11 +++++++++++ .../TopLeftWhiteBlackSquare | 11 +++++++++++ .../TopRightWhiteBlackSquare | 11 +++++++++++ .../sudoku/rules/RepeatedNumberContradictionRule/a | 0 5 files changed, 44 insertions(+) create mode 100644 output_path/test/src/resources/puzzles/sudoku/rules/PreventBlackSquareBasicRule/BottomLeftWhiteBlackSquare create mode 100644 output_path/test/src/resources/puzzles/sudoku/rules/PreventBlackSquareBasicRule/BottomRightWhiteBlackSquare create mode 100644 output_path/test/src/resources/puzzles/sudoku/rules/PreventBlackSquareBasicRule/TopLeftWhiteBlackSquare create mode 100644 output_path/test/src/resources/puzzles/sudoku/rules/PreventBlackSquareBasicRule/TopRightWhiteBlackSquare create mode 100644 output_path/test/src/resources/puzzles/sudoku/rules/RepeatedNumberContradictionRule/a diff --git a/output_path/test/src/resources/puzzles/sudoku/rules/PreventBlackSquareBasicRule/BottomLeftWhiteBlackSquare b/output_path/test/src/resources/puzzles/sudoku/rules/PreventBlackSquareBasicRule/BottomLeftWhiteBlackSquare new file mode 100644 index 000000000..1c789c55c --- /dev/null +++ b/output_path/test/src/resources/puzzles/sudoku/rules/PreventBlackSquareBasicRule/BottomLeftWhiteBlackSquare @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/output_path/test/src/resources/puzzles/sudoku/rules/PreventBlackSquareBasicRule/BottomRightWhiteBlackSquare b/output_path/test/src/resources/puzzles/sudoku/rules/PreventBlackSquareBasicRule/BottomRightWhiteBlackSquare new file mode 100644 index 000000000..1cf3694d4 --- /dev/null +++ b/output_path/test/src/resources/puzzles/sudoku/rules/PreventBlackSquareBasicRule/BottomRightWhiteBlackSquare @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/output_path/test/src/resources/puzzles/sudoku/rules/PreventBlackSquareBasicRule/TopLeftWhiteBlackSquare b/output_path/test/src/resources/puzzles/sudoku/rules/PreventBlackSquareBasicRule/TopLeftWhiteBlackSquare new file mode 100644 index 000000000..e4de84894 --- /dev/null +++ b/output_path/test/src/resources/puzzles/sudoku/rules/PreventBlackSquareBasicRule/TopLeftWhiteBlackSquare @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/output_path/test/src/resources/puzzles/sudoku/rules/PreventBlackSquareBasicRule/TopRightWhiteBlackSquare b/output_path/test/src/resources/puzzles/sudoku/rules/PreventBlackSquareBasicRule/TopRightWhiteBlackSquare new file mode 100644 index 000000000..52c0ca68f --- /dev/null +++ b/output_path/test/src/resources/puzzles/sudoku/rules/PreventBlackSquareBasicRule/TopRightWhiteBlackSquare @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/output_path/test/src/resources/puzzles/sudoku/rules/RepeatedNumberContradictionRule/a b/output_path/test/src/resources/puzzles/sudoku/rules/RepeatedNumberContradictionRule/a new file mode 100644 index 000000000..e69de29bb From fd90f2da2db741561ae2c3e2ca835d2733af1e0e Mon Sep 17 00:00:00 2001 From: kchiu1 <152306707+kchiu1@users.noreply.github.com> Date: Fri, 5 Apr 2024 16:34:45 -0400 Subject: [PATCH 072/258] Deleted fake tests and added a real test Fake tests was bad --- .../BottomLeftWhiteBlackSquare | 11 ----------- .../BottomRightWhiteBlackSquare | 11 ----------- .../TopLeftWhiteBlackSquare | 11 ----------- .../TopRightWhiteBlackSquare | 11 ----------- .../sudoku/rules/LastCellForNumberDirectRuleTest.java | 10 ++++++++++ 5 files changed, 10 insertions(+), 44 deletions(-) delete mode 100644 output_path/test/src/resources/puzzles/sudoku/rules/PreventBlackSquareBasicRule/BottomLeftWhiteBlackSquare delete mode 100644 output_path/test/src/resources/puzzles/sudoku/rules/PreventBlackSquareBasicRule/BottomRightWhiteBlackSquare delete mode 100644 output_path/test/src/resources/puzzles/sudoku/rules/PreventBlackSquareBasicRule/TopLeftWhiteBlackSquare delete mode 100644 output_path/test/src/resources/puzzles/sudoku/rules/PreventBlackSquareBasicRule/TopRightWhiteBlackSquare create mode 100644 src/test/java/puzzles/sudoku/rules/LastCellForNumberDirectRuleTest.java diff --git a/output_path/test/src/resources/puzzles/sudoku/rules/PreventBlackSquareBasicRule/BottomLeftWhiteBlackSquare b/output_path/test/src/resources/puzzles/sudoku/rules/PreventBlackSquareBasicRule/BottomLeftWhiteBlackSquare deleted file mode 100644 index 1c789c55c..000000000 --- a/output_path/test/src/resources/puzzles/sudoku/rules/PreventBlackSquareBasicRule/BottomLeftWhiteBlackSquare +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/output_path/test/src/resources/puzzles/sudoku/rules/PreventBlackSquareBasicRule/BottomRightWhiteBlackSquare b/output_path/test/src/resources/puzzles/sudoku/rules/PreventBlackSquareBasicRule/BottomRightWhiteBlackSquare deleted file mode 100644 index 1cf3694d4..000000000 --- a/output_path/test/src/resources/puzzles/sudoku/rules/PreventBlackSquareBasicRule/BottomRightWhiteBlackSquare +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/output_path/test/src/resources/puzzles/sudoku/rules/PreventBlackSquareBasicRule/TopLeftWhiteBlackSquare b/output_path/test/src/resources/puzzles/sudoku/rules/PreventBlackSquareBasicRule/TopLeftWhiteBlackSquare deleted file mode 100644 index e4de84894..000000000 --- a/output_path/test/src/resources/puzzles/sudoku/rules/PreventBlackSquareBasicRule/TopLeftWhiteBlackSquare +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/output_path/test/src/resources/puzzles/sudoku/rules/PreventBlackSquareBasicRule/TopRightWhiteBlackSquare b/output_path/test/src/resources/puzzles/sudoku/rules/PreventBlackSquareBasicRule/TopRightWhiteBlackSquare deleted file mode 100644 index 52c0ca68f..000000000 --- a/output_path/test/src/resources/puzzles/sudoku/rules/PreventBlackSquareBasicRule/TopRightWhiteBlackSquare +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/src/test/java/puzzles/sudoku/rules/LastCellForNumberDirectRuleTest.java b/src/test/java/puzzles/sudoku/rules/LastCellForNumberDirectRuleTest.java new file mode 100644 index 000000000..7b98ce488 --- /dev/null +++ b/src/test/java/puzzles/sudoku/rules/LastCellForNumberDirectRuleTest.java @@ -0,0 +1,10 @@ +package puzzles.sudoku.rules; + +import static org.junit.Assert.*; + +public class LastCellForNumberDirectRuleTest { + @test + public LastCellForNumberDirectRuleTest() { + assertTrue(true); + } +} From 6ec594c0eb0f6d412ff3cf3a496aa761a1438d14 Mon Sep 17 00:00:00 2001 From: kchiu1 <152306707+kchiu1@users.noreply.github.com> Date: Fri, 5 Apr 2024 16:35:48 -0400 Subject: [PATCH 073/258] fixed empty test file --- .../sudoku/rules/LastCellForNumberDirectRuleTest.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/test/java/puzzles/sudoku/rules/LastCellForNumberDirectRuleTest.java b/src/test/java/puzzles/sudoku/rules/LastCellForNumberDirectRuleTest.java index 7b98ce488..35d39401d 100644 --- a/src/test/java/puzzles/sudoku/rules/LastCellForNumberDirectRuleTest.java +++ b/src/test/java/puzzles/sudoku/rules/LastCellForNumberDirectRuleTest.java @@ -1,10 +1,12 @@ package puzzles.sudoku.rules; +import org.junit.Test; + import static org.junit.Assert.*; public class LastCellForNumberDirectRuleTest { - @test - public LastCellForNumberDirectRuleTest() { + @Test + public void LastCellForNumberDirectRuleTest() { assertTrue(true); } } From c5653ca5c6a61f88c5b39e5b8c4b01bbdae4293c Mon Sep 17 00:00:00 2001 From: kchiu1 <152306707+kchiu1@users.noreply.github.com> Date: Fri, 5 Apr 2024 16:47:31 -0400 Subject: [PATCH 074/258] Update LastCellForNumberDirectRuleTest.java --- .../sudoku/rules/LastCellForNumberDirectRuleTest.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/test/java/puzzles/sudoku/rules/LastCellForNumberDirectRuleTest.java b/src/test/java/puzzles/sudoku/rules/LastCellForNumberDirectRuleTest.java index 35d39401d..e3ef0183c 100644 --- a/src/test/java/puzzles/sudoku/rules/LastCellForNumberDirectRuleTest.java +++ b/src/test/java/puzzles/sudoku/rules/LastCellForNumberDirectRuleTest.java @@ -1,10 +1,18 @@ package puzzles.sudoku.rules; +import edu.rpi.legup.puzzle.nurikabe.Nurikabe; +import legup.MockGameBoardFacade; import org.junit.Test; +import edu.rpi.legup.puzzle.sudoku.Sudoku; import static org.junit.Assert.*; public class LastCellForNumberDirectRuleTest { + private Sudoku sudoku; + public static void setUp() { + MockGameBoardFacade.getInstance(); + sudoku = new Sudoku(); + } @Test public void LastCellForNumberDirectRuleTest() { assertTrue(true); From 0e29a1579e5e891498e6e8f72222e205eefac414 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Fri, 5 Apr 2024 17:37:17 -0400 Subject: [PATCH 075/258] Slight progress with SurroundPairDirectRule --- .../binary/rules/SurroundPairDirectRule.java | 90 +++++++++++++------ 1 file changed, 63 insertions(+), 27 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java index f8e801090..fd4264a16 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java @@ -25,38 +25,74 @@ public SurroundPairDirectRule() { @Override public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { BinaryBoard board = (BinaryBoard) transition.getBoard(); - BinaryBoard origBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); + BinaryBoard originalBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); ContradictionRule contraRule = new ThreeAdjacentContradictionRule(); +// BinaryCell c = (BinaryCell) modified.getPuzzleElement(puzzleElement); +// System.out.println(c.getLocation()); +// +// System.out.println("BEFORE: " + c.getType()); +// if (c.getData() == 0) +// c.setData(1); +// else if (c.getData() == 1) +// c.setData(0); +// +// System.out.println("AFTER: " + c.getType()); +// modified.setCell(c.getLocation().x, c.getLocation().y, c); +// + BinaryBoard modified = originalBoard.copy(); + BinaryCell binaryCell = (BinaryCell) puzzleElement; - BinaryCell cell = (BinaryCell) board.getPuzzleElement(puzzleElement); - if(cell.getType() == BinaryType.UNKNOWN){ - return "Only ONE and ZERO allowed for this rule!"; - } - BinaryBoard modified = origBoard.copy(); - BinaryCell c = (BinaryCell) modified.getPuzzleElement(puzzleElement); - if (c.getData() == 0) - modified.getPuzzleElement(puzzleElement).setData(1); - else if (c.getData() == 1) - modified.getPuzzleElement(puzzleElement).setData(0); - if(contraRule.checkContradictionAt(modified, puzzleElement) != null){ - return "Grouping of three ONEs or ZEROs found"; + System.out.println("ORIG" + binaryCell.getData()); + System.out.println("AFTER" + Math.abs(binaryCell.getData() - 1)); + modified.getPuzzleElement(puzzleElement).setData(Math.abs(binaryCell.getData() - 1)); + +// + System.out.println(contraRule.checkContradictionAt(modified, puzzleElement)); +// + if (contraRule.checkContradictionAt(modified, puzzleElement) == null) { + return null; } - + return "Grouping of Three Ones or Zeros found"; +// BinaryCell cell = (BinaryCell) board.getPuzzleElement(puzzleElement); +// if(cell.getType() == BinaryType.UNKNOWN){ +// return "Only ONE and ZERO allowed for this rule!"; +// } +// BinaryBoard modified = board.copy(); +// Set changedCells = board.getModifiedData(); +// for (PuzzleElement p : changedCells) { +// BinaryCell c = (BinaryCell) board.getPuzzleElement(p); +// } +// +// if (c.getData() == 0) +// modified.getPuzzleElement(puzzleElement).setData(1); +// else if (c.getData() == 1) +// modified.getPuzzleElement(puzzleElement).setData(0); +// if(contraRule.checkContradictionAt(modified, puzzleElement) != null){ +// return "Grouping of three ONEs or ZEROs found"; +// } +// +// +// Set changedCells = board.getModifiedData(); +// System.out.println("SIZE" + changedCells.size()); +// for (PuzzleElement p : changedCells) { +// BinaryCell c = (BinaryCell) board.getPuzzleElement(p); +// System.out.println(c.getLocation()); +// if (c.getData() == 0) +// c.setData(1); +// else if (c.getData() == 1) +// c.setData(0); +// System.out.println("HI"); +// } - // Set changedCells = destBoard.getModifiedData(); - // for (PuzzleElement p : changedCells) { - // BinaryCell c = (BinaryCell) destBoard.getPuzzleElement(p); - // System.out.println(c.getLocation()); - // // if (c.getData() == 0) - // // c.setData(1); - // // else if (c.getData() == 1) - // // c.setData(0); - // if (contraRule.checkContradictionAt(destBoard, puzzleElement) == null) { - // return "Grouping of Three Ones or Zeros found"; - // } - // } - return null; +// for (PuzzleElement p : changedCells) { +// BinaryCell c = (BinaryCell) board.getPuzzleElement(p); +// //System.out.println(c.getLocation()); +// if (c.getData() == 0) +// c.setData(1); +// else if (c.getData() == 1) +// c.setData(0); +// } } @Override From ceab9056aed9a4f49794fd2aad09bb559f3f9b76 Mon Sep 17 00:00:00 2001 From: kchiu1 <152306707+kchiu1@users.noreply.github.com> Date: Fri, 5 Apr 2024 17:42:07 -0400 Subject: [PATCH 076/258] Modified tests, made sample test --- .../rules/LastCellForNumberDirectRule/TestBoard | 16 ++++++++++++++++ .../rules/LastCellForNumberDirectRuleTest.java | 11 +++++++++-- 2 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 output_path/test/src/resources/puzzles/sudoku/rules/LastCellForNumberDirectRule/TestBoard diff --git a/output_path/test/src/resources/puzzles/sudoku/rules/LastCellForNumberDirectRule/TestBoard b/output_path/test/src/resources/puzzles/sudoku/rules/LastCellForNumberDirectRule/TestBoard new file mode 100644 index 000000000..4a66f38fc --- /dev/null +++ b/output_path/test/src/resources/puzzles/sudoku/rules/LastCellForNumberDirectRule/TestBoard @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/java/puzzles/sudoku/rules/LastCellForNumberDirectRuleTest.java b/src/test/java/puzzles/sudoku/rules/LastCellForNumberDirectRuleTest.java index e3ef0183c..eff4feb93 100644 --- a/src/test/java/puzzles/sudoku/rules/LastCellForNumberDirectRuleTest.java +++ b/src/test/java/puzzles/sudoku/rules/LastCellForNumberDirectRuleTest.java @@ -1,20 +1,27 @@ package puzzles.sudoku.rules; import edu.rpi.legup.puzzle.nurikabe.Nurikabe; +import edu.rpi.legup.save.InvalidFileFormatException; import legup.MockGameBoardFacade; +import legup.TestUtilities; +import org.junit.BeforeClass; import org.junit.Test; import edu.rpi.legup.puzzle.sudoku.Sudoku; +import edu.rpi.legup.puzzle.sudoku.rules.LastCellForNumberDirectRule; import static org.junit.Assert.*; public class LastCellForNumberDirectRuleTest { - private Sudoku sudoku; + private static Sudoku sudoku; + @BeforeClass public static void setUp() { MockGameBoardFacade.getInstance(); sudoku = new Sudoku(); } @Test - public void LastCellForNumberDirectRuleTest() { + public void LastCellForNumberDirectRuleTest() throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/sudoku/rules/LastCellForNumberRule/TestBoard", sudoku); assertTrue(true); + } } From f764c376b7e2f5cae867bd5c72382dc0cea77957 Mon Sep 17 00:00:00 2001 From: EggyMath <55564321+EggyMath@users.noreply.github.com> Date: Tue, 9 Apr 2024 16:26:27 -0400 Subject: [PATCH 077/258] First Sudoku Test Case Basic Last Number for Cell test case. --- .gitignore | 3 +- .../LastNumberForCellDirectRule/FullRegion | 19 +++++++ src/test/java/legup/TestRunner.java | 5 ++ .../LastCellForNumberDirectRuleTest.java | 20 -------- ...LastNumberForCellDirectRuleRegionTest.java | 49 +++++++++++++++++++ .../LastNumberForCellDirectRule/FullRegion | 18 +++++++ 6 files changed, 93 insertions(+), 21 deletions(-) create mode 100644 output_path/test/src/resources/puzzles/sudoku/rules/LastNumberForCellDirectRule/FullRegion delete mode 100644 src/test/java/puzzles/sudoku/rules/LastCellForNumberDirectRuleTest.java create mode 100644 src/test/java/puzzles/sudoku/rules/LastNumberForCellDirectRuleRegionTest.java create mode 100644 src/test/resources/puzzles/sudoku/rules/LastNumberForCellDirectRule/FullRegion diff --git a/.gitignore b/.gitignore index baee37e51..bafea84a3 100644 --- a/.gitignore +++ b/.gitignore @@ -92,4 +92,5 @@ gradle-app.setting gradle/wrapper/gradle-wrapper.properties # Visual Studio Code configs -.vscode/* \ No newline at end of file +.vscode/* +src/test/java/legup/TestRunner.java diff --git a/output_path/test/src/resources/puzzles/sudoku/rules/LastNumberForCellDirectRule/FullRegion b/output_path/test/src/resources/puzzles/sudoku/rules/LastNumberForCellDirectRule/FullRegion new file mode 100644 index 000000000..49dae4aa6 --- /dev/null +++ b/output_path/test/src/resources/puzzles/sudoku/rules/LastNumberForCellDirectRule/FullRegion @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/src/test/java/legup/TestRunner.java b/src/test/java/legup/TestRunner.java index 3a74c4c61..4e516b55f 100644 --- a/src/test/java/legup/TestRunner.java +++ b/src/test/java/legup/TestRunner.java @@ -7,6 +7,7 @@ import puzzles.battleship.rules.*; import puzzles.lightup.rules.*; import puzzles.nurikabe.rules.*; +import puzzles.sudoku.rules.LastNumberForCellDirectRuleRegionTest; import puzzles.treetent.rules.*; /** @@ -93,6 +94,10 @@ public static void main(String[] args) { printTestResults(result35); Result result36 = JUnitCore.runClasses(TentOrGrassCaseRuleTest.class); printTestResults(result36); + + //Sudoku Tests + Result result37 = JUnitCore.runClasses(LastNumberForCellDirectRuleRegionTest.class); + printTestResults(result37); } private static void printTestResults(Result result) { diff --git a/src/test/java/puzzles/sudoku/rules/LastCellForNumberDirectRuleTest.java b/src/test/java/puzzles/sudoku/rules/LastCellForNumberDirectRuleTest.java deleted file mode 100644 index e3ef0183c..000000000 --- a/src/test/java/puzzles/sudoku/rules/LastCellForNumberDirectRuleTest.java +++ /dev/null @@ -1,20 +0,0 @@ -package puzzles.sudoku.rules; - -import edu.rpi.legup.puzzle.nurikabe.Nurikabe; -import legup.MockGameBoardFacade; -import org.junit.Test; -import edu.rpi.legup.puzzle.sudoku.Sudoku; - -import static org.junit.Assert.*; - -public class LastCellForNumberDirectRuleTest { - private Sudoku sudoku; - public static void setUp() { - MockGameBoardFacade.getInstance(); - sudoku = new Sudoku(); - } - @Test - public void LastCellForNumberDirectRuleTest() { - assertTrue(true); - } -} diff --git a/src/test/java/puzzles/sudoku/rules/LastNumberForCellDirectRuleRegionTest.java b/src/test/java/puzzles/sudoku/rules/LastNumberForCellDirectRuleRegionTest.java new file mode 100644 index 000000000..d47ee9a19 --- /dev/null +++ b/src/test/java/puzzles/sudoku/rules/LastNumberForCellDirectRuleRegionTest.java @@ -0,0 +1,49 @@ +package puzzles.sudoku.rules; + +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.sudoku.Sudoku; +import edu.rpi.legup.puzzle.sudoku.SudokuBoard; +import edu.rpi.legup.puzzle.sudoku.SudokuCell; +import edu.rpi.legup.puzzle.sudoku.rules.LastNumberForCellDirectRule; +import edu.rpi.legup.save.InvalidFileFormatException; +import legup.MockGameBoardFacade; +import legup.TestUtilities; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class LastNumberForCellDirectRuleRegionTest { + private static final LastNumberForCellDirectRule RULE = new LastNumberForCellDirectRule(); + private static Sudoku sudoku; + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + sudoku = new Sudoku(); + } + @Test + public void LastNumberForCellDirectRule_FullRegionTest() throws InvalidFileFormatException { + //Import board and create transition + TestUtilities.importTestBoard("puzzles/sudoku/rules/LastNumberForCellDirectRule/FullRegion", sudoku); + TreeNode rootNode = sudoku.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + for(int i = 1; i < 10; i++){ + //Reset board + SudokuBoard board = (SudokuBoard) transition.getBoard(); + //Set cell + SudokuCell cell1 = board.getCell(2, 5); + cell1.setData(i); + board.addModifiedData(cell1); + + //Test the case + if(i == 9) { + Assert.assertNull(RULE.checkRuleAt(transition, cell1)); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, cell1)); + } + } + + } +} diff --git a/src/test/resources/puzzles/sudoku/rules/LastNumberForCellDirectRule/FullRegion b/src/test/resources/puzzles/sudoku/rules/LastNumberForCellDirectRule/FullRegion new file mode 100644 index 000000000..58fd02162 --- /dev/null +++ b/src/test/resources/puzzles/sudoku/rules/LastNumberForCellDirectRule/FullRegion @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + From 7e673c228cb1495a8635d8b3b249377e8f66734b Mon Sep 17 00:00:00 2001 From: EggyMath <55564321+EggyMath@users.noreply.github.com> Date: Tue, 9 Apr 2024 16:34:01 -0400 Subject: [PATCH 078/258] Create CorneredRegion --- .../LastCellForNumberDirectRule/CorneredRegion | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 src/test/resources/puzzles/sudoku/rules/LastCellForNumberDirectRule/CorneredRegion diff --git a/src/test/resources/puzzles/sudoku/rules/LastCellForNumberDirectRule/CorneredRegion b/src/test/resources/puzzles/sudoku/rules/LastCellForNumberDirectRule/CorneredRegion new file mode 100644 index 000000000..4d3c57225 --- /dev/null +++ b/src/test/resources/puzzles/sudoku/rules/LastCellForNumberDirectRule/CorneredRegion @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + From 3ea0ab323d611c2c01f6651470bdfa8a75bdd45c Mon Sep 17 00:00:00 2001 From: EggyMath <55564321+EggyMath@users.noreply.github.com> Date: Tue, 9 Apr 2024 17:00:53 -0400 Subject: [PATCH 079/258] More Test Cases and Test Classes Implemented 2 new test cases for LastNumberForCell and made Class and Test Case for RepeatedNumber contradiction rule --- ...LastNumberForCellDirectRuleRegionTest.java | 46 ++++++++++++++++ .../RepeatedNumberContradictionRuleTest.java | 55 +++++++++++++++++++ .../LastNumberForCellDirectRule/FullMixed | 18 ++++++ .../rules/LastNumberForCellDirectRule/FullRow | 18 ++++++ .../BlankBoard | 11 ++++ 5 files changed, 148 insertions(+) create mode 100644 src/test/java/puzzles/sudoku/rules/RepeatedNumberContradictionRuleTest.java create mode 100644 src/test/resources/puzzles/sudoku/rules/LastNumberForCellDirectRule/FullMixed create mode 100644 src/test/resources/puzzles/sudoku/rules/LastNumberForCellDirectRule/FullRow create mode 100644 src/test/resources/puzzles/sudoku/rules/RepeatedNumberContradictionRule/BlankBoard diff --git a/src/test/java/puzzles/sudoku/rules/LastNumberForCellDirectRuleRegionTest.java b/src/test/java/puzzles/sudoku/rules/LastNumberForCellDirectRuleRegionTest.java index d47ee9a19..28406c1ab 100644 --- a/src/test/java/puzzles/sudoku/rules/LastNumberForCellDirectRuleRegionTest.java +++ b/src/test/java/puzzles/sudoku/rules/LastNumberForCellDirectRuleRegionTest.java @@ -29,6 +29,7 @@ public void LastNumberForCellDirectRule_FullRegionTest() throws InvalidFileForma TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); + //Loop all numbers at point for(int i = 1; i < 10; i++){ //Reset board SudokuBoard board = (SudokuBoard) transition.getBoard(); @@ -45,5 +46,50 @@ public void LastNumberForCellDirectRule_FullRegionTest() throws InvalidFileForma } } + //Import Board and create transition + TestUtilities.importTestBoard("puzzles/sudoku/rules/LastNumberForCellDirectRule/FullRow", sudoku); + rootNode = sudoku.getTree().getRootNode(); + transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + //Loop all numbers at point + for(int i = 1; i < 10; i++){ + //Reset board + SudokuBoard board = (SudokuBoard) transition.getBoard(); + //Set cell + SudokuCell cell = board.getCell(4, 4); + cell.setData(i); + board.addModifiedData(cell); + + //Test the case + if(i == 5) { + Assert.assertNull(RULE.checkRuleAt(transition, cell)); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, cell)); + } + } + + //Import Board and create transition + TestUtilities.importTestBoard("puzzles/sudoku/rules/LastNumberForCellDirectRule/FullMixed", sudoku); + rootNode = sudoku.getTree().getRootNode(); + transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + //Loop all numbers at point + for(int i = 1; i < 10; i++){ + //Reset board + SudokuBoard board = (SudokuBoard) transition.getBoard(); + //Set cell + SudokuCell cell = board.getCell(5, 3); + cell.setData(i); + board.addModifiedData(cell); + + //Test the case + if(i == 2) { + Assert.assertNull(RULE.checkRuleAt(transition, cell)); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, cell)); + } + } } } diff --git a/src/test/java/puzzles/sudoku/rules/RepeatedNumberContradictionRuleTest.java b/src/test/java/puzzles/sudoku/rules/RepeatedNumberContradictionRuleTest.java new file mode 100644 index 000000000..524509b26 --- /dev/null +++ b/src/test/java/puzzles/sudoku/rules/RepeatedNumberContradictionRuleTest.java @@ -0,0 +1,55 @@ +package puzzles.sudoku.rules; + +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.sudoku.Sudoku; +import edu.rpi.legup.puzzle.sudoku.SudokuBoard; +import edu.rpi.legup.puzzle.sudoku.SudokuCell; +import edu.rpi.legup.puzzle.sudoku.rules.LastNumberForCellDirectRule; +import edu.rpi.legup.puzzle.sudoku.rules.RepeatedNumberContradictionRule; +import edu.rpi.legup.save.InvalidFileFormatException; +import legup.MockGameBoardFacade; +import legup.TestUtilities; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class RepeatedNumberContradictionRuleTest { + private static final RepeatedNumberContradictionRule RULE = new RepeatedNumberContradictionRule(); + private static Sudoku sudoku; + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + sudoku = new Sudoku(); + } + @Test + public void RepeatedNumberContradictionRule_GlobalTest() throws InvalidFileFormatException { + //Import board and create transition + TestUtilities.importTestBoard("puzzles/sudoku/rules/RepeatedNumberContradictionRule/BlankBoard", sudoku); + TreeNode rootNode = sudoku.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + //Loop through every cell + for(int i = 0; i < 81; i++){ + //Reset board + SudokuBoard board = (SudokuBoard) transition.getBoard(); + //Set cell + int x = i / 9; + int y = i % 9; + if(x == 0 && y == 0) + continue; + SudokuCell cell = board.getCell(x, y); + cell.setData(7); + + //Test the case + if(x == 0 || y == 0 || (x < 3 && y < 3)){ + Assert.assertNull(RULE.checkRuleAt(transition, cell)); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, cell)); + } + cell.setData(0); + } + + } +} diff --git a/src/test/resources/puzzles/sudoku/rules/LastNumberForCellDirectRule/FullMixed b/src/test/resources/puzzles/sudoku/rules/LastNumberForCellDirectRule/FullMixed new file mode 100644 index 000000000..55b501fec --- /dev/null +++ b/src/test/resources/puzzles/sudoku/rules/LastNumberForCellDirectRule/FullMixed @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/puzzles/sudoku/rules/LastNumberForCellDirectRule/FullRow b/src/test/resources/puzzles/sudoku/rules/LastNumberForCellDirectRule/FullRow new file mode 100644 index 000000000..07e502ed9 --- /dev/null +++ b/src/test/resources/puzzles/sudoku/rules/LastNumberForCellDirectRule/FullRow @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/sudoku/rules/RepeatedNumberContradictionRule/BlankBoard b/src/test/resources/puzzles/sudoku/rules/RepeatedNumberContradictionRule/BlankBoard new file mode 100644 index 000000000..5692dea64 --- /dev/null +++ b/src/test/resources/puzzles/sudoku/rules/RepeatedNumberContradictionRule/BlankBoard @@ -0,0 +1,11 @@ + + + + + + + + + + + From 077505de2660fc532e451452cb54c44b65863493 Mon Sep 17 00:00:00 2001 From: kchiu1 <152306707+kchiu1@users.noreply.github.com> Date: Tue, 9 Apr 2024 17:09:17 -0400 Subject: [PATCH 080/258] Added lastcellfornumber test --- .../LastCellForNumberDirectRule/TestBoard | 29 +++++++------- .../LastCellForNumberDirectRuleTest.java | 39 +++++++++++++++---- 2 files changed, 47 insertions(+), 21 deletions(-) diff --git a/output_path/test/src/resources/puzzles/sudoku/rules/LastCellForNumberDirectRule/TestBoard b/output_path/test/src/resources/puzzles/sudoku/rules/LastCellForNumberDirectRule/TestBoard index 4a66f38fc..81a88d8f6 100644 --- a/output_path/test/src/resources/puzzles/sudoku/rules/LastCellForNumberDirectRule/TestBoard +++ b/output_path/test/src/resources/puzzles/sudoku/rules/LastCellForNumberDirectRule/TestBoard @@ -1,16 +1,19 @@ - - - + + + + - - - - - - - - + + + + + + + + + - - \ No newline at end of file + + + diff --git a/src/test/java/puzzles/sudoku/rules/LastCellForNumberDirectRuleTest.java b/src/test/java/puzzles/sudoku/rules/LastCellForNumberDirectRuleTest.java index eff4feb93..f4531a893 100644 --- a/src/test/java/puzzles/sudoku/rules/LastCellForNumberDirectRuleTest.java +++ b/src/test/java/puzzles/sudoku/rules/LastCellForNumberDirectRuleTest.java @@ -1,17 +1,20 @@ package puzzles.sudoku.rules; -import edu.rpi.legup.puzzle.nurikabe.Nurikabe; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.sudoku.Sudoku; +import edu.rpi.legup.puzzle.sudoku.SudokuBoard; +import edu.rpi.legup.puzzle.sudoku.SudokuCell; +import edu.rpi.legup.puzzle.sudoku.rules.LastNumberForCellDirectRule; 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 edu.rpi.legup.puzzle.sudoku.Sudoku; -import edu.rpi.legup.puzzle.sudoku.rules.LastCellForNumberDirectRule; - -import static org.junit.Assert.*; public class LastCellForNumberDirectRuleTest { + private static final LastNumberForCellDirectRule RULE = new LastNumberForCellDirectRule(); private static Sudoku sudoku; @BeforeClass public static void setUp() { @@ -19,9 +22,29 @@ public static void setUp() { sudoku = new Sudoku(); } @Test - public void LastCellForNumberDirectRuleTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/sudoku/rules/LastCellForNumberRule/TestBoard", sudoku); - assertTrue(true); + public void LastNumberForCellDirectRuleTest() throws InvalidFileFormatException { + //Import board and create transition + + TestUtilities.importTestBoard("puzzles/sudoku/rules/LasCellForNumberDirectRule/TestBoard", sudoku); + TreeNode rootNode = sudoku.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + for(int i = 1; i < 10; i++){ + //Reset board + SudokuBoard board = (SudokuBoard) transition.getBoard(); + //Set cell + SudokuCell cell1 = board.getCell(2, 2); + cell1.setData(i); + board.addModifiedData(cell1); + + //Test the case + if(i == 9) { + Assert.assertNotNull(RULE.checkRuleAt(transition, cell1)); + } else { + Assert.assertNull(RULE.checkRuleAt(transition, cell1)); + } + } } } From 70de0d76fb8867c41655a537622e155bb74cb2a1 Mon Sep 17 00:00:00 2001 From: EggyMath <55564321+EggyMath@users.noreply.github.com> Date: Tue, 9 Apr 2024 17:15:23 -0400 Subject: [PATCH 081/258] More Tests for RepeatedNumbers Added another test for RepeatedNumbers contradiction rule and fixed previous error. --- .../RepeatedNumberContradictionRuleTest.java | 33 +++++++++++++++++-- .../BlankBoard4 | 12 +++++++ .../{BlankBoard => BlankBoard7} | 0 3 files changed, 42 insertions(+), 3 deletions(-) create mode 100644 src/test/resources/puzzles/sudoku/rules/RepeatedNumberContradictionRule/BlankBoard4 rename src/test/resources/puzzles/sudoku/rules/RepeatedNumberContradictionRule/{BlankBoard => BlankBoard7} (100%) diff --git a/src/test/java/puzzles/sudoku/rules/RepeatedNumberContradictionRuleTest.java b/src/test/java/puzzles/sudoku/rules/RepeatedNumberContradictionRuleTest.java index 524509b26..3a65fbd47 100644 --- a/src/test/java/puzzles/sudoku/rules/RepeatedNumberContradictionRuleTest.java +++ b/src/test/java/puzzles/sudoku/rules/RepeatedNumberContradictionRuleTest.java @@ -5,7 +5,6 @@ import edu.rpi.legup.puzzle.sudoku.Sudoku; import edu.rpi.legup.puzzle.sudoku.SudokuBoard; import edu.rpi.legup.puzzle.sudoku.SudokuCell; -import edu.rpi.legup.puzzle.sudoku.rules.LastNumberForCellDirectRule; import edu.rpi.legup.puzzle.sudoku.rules.RepeatedNumberContradictionRule; import edu.rpi.legup.save.InvalidFileFormatException; import legup.MockGameBoardFacade; @@ -25,7 +24,7 @@ public static void setUp() { @Test public void RepeatedNumberContradictionRule_GlobalTest() throws InvalidFileFormatException { //Import board and create transition - TestUtilities.importTestBoard("puzzles/sudoku/rules/RepeatedNumberContradictionRule/BlankBoard", sudoku); + TestUtilities.importTestBoard("puzzles/sudoku/rules/RepeatedNumberContradictionRule/BlankBoard7", sudoku); TreeNode rootNode = sudoku.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -37,8 +36,9 @@ public void RepeatedNumberContradictionRule_GlobalTest() throws InvalidFileForma //Set cell int x = i / 9; int y = i % 9; - if(x == 0 && y == 0) + if(x == 0 && y == 0) { continue; + } SudokuCell cell = board.getCell(x, y); cell.setData(7); @@ -50,6 +50,33 @@ public void RepeatedNumberContradictionRule_GlobalTest() throws InvalidFileForma } cell.setData(0); } + //Import board and create transition + TestUtilities.importTestBoard("puzzles/sudoku/rules/RepeatedNumberContradictionRule/BlankBoard4", sudoku); + rootNode = sudoku.getTree().getRootNode(); + transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + //Loop through every cell + for(int i = 0; i < 81; i++){ + //Reset board + SudokuBoard board = (SudokuBoard) transition.getBoard(); + //Set cell + int x = i / 9; + int y = i % 9; + if((x == 3 && y == 0) || (x == 6 && y == 8)) { + continue; + } + SudokuCell cell = board.getCell(x, y); + cell.setData(4); + + //Test the case + if((x == 3 || y == 0 || x == 6 || y == 8) || (x > 2 && x < 6 && y < 3) || (x > 5 && y > 5)){ + Assert.assertNull(RULE.checkRuleAt(transition, cell)); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, cell)); + } + cell.setData(0); + } } } diff --git a/src/test/resources/puzzles/sudoku/rules/RepeatedNumberContradictionRule/BlankBoard4 b/src/test/resources/puzzles/sudoku/rules/RepeatedNumberContradictionRule/BlankBoard4 new file mode 100644 index 000000000..abaa0ba6b --- /dev/null +++ b/src/test/resources/puzzles/sudoku/rules/RepeatedNumberContradictionRule/BlankBoard4 @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/sudoku/rules/RepeatedNumberContradictionRule/BlankBoard b/src/test/resources/puzzles/sudoku/rules/RepeatedNumberContradictionRule/BlankBoard7 similarity index 100% rename from src/test/resources/puzzles/sudoku/rules/RepeatedNumberContradictionRule/BlankBoard rename to src/test/resources/puzzles/sudoku/rules/RepeatedNumberContradictionRule/BlankBoard7 From 90e273accda5124d7b6f644ddef7aa0296e56805 Mon Sep 17 00:00:00 2001 From: kchiu1 <152306707+kchiu1@users.noreply.github.com> Date: Tue, 9 Apr 2024 17:21:34 -0400 Subject: [PATCH 082/258] fixed test file, LastCellForNumberDirectRuleTest --- .../rules/LastCellForNumberDirectRule/TestBoard | 16 ++++++++-------- .../rules/LastCellForNumberDirectRuleTest.java | 10 +++++----- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/output_path/test/src/resources/puzzles/sudoku/rules/LastCellForNumberDirectRule/TestBoard b/output_path/test/src/resources/puzzles/sudoku/rules/LastCellForNumberDirectRule/TestBoard index 81a88d8f6..a41ad749c 100644 --- a/output_path/test/src/resources/puzzles/sudoku/rules/LastCellForNumberDirectRule/TestBoard +++ b/output_path/test/src/resources/puzzles/sudoku/rules/LastCellForNumberDirectRule/TestBoard @@ -3,14 +3,14 @@ - - - - - - - - + + + + + + + + diff --git a/src/test/java/puzzles/sudoku/rules/LastCellForNumberDirectRuleTest.java b/src/test/java/puzzles/sudoku/rules/LastCellForNumberDirectRuleTest.java index f4531a893..8b3e96a79 100644 --- a/src/test/java/puzzles/sudoku/rules/LastCellForNumberDirectRuleTest.java +++ b/src/test/java/puzzles/sudoku/rules/LastCellForNumberDirectRuleTest.java @@ -5,7 +5,7 @@ import edu.rpi.legup.puzzle.sudoku.Sudoku; import edu.rpi.legup.puzzle.sudoku.SudokuBoard; import edu.rpi.legup.puzzle.sudoku.SudokuCell; -import edu.rpi.legup.puzzle.sudoku.rules.LastNumberForCellDirectRule; +import edu.rpi.legup.puzzle.sudoku.rules.LastCellForNumberDirectRule; import edu.rpi.legup.save.InvalidFileFormatException; import legup.MockGameBoardFacade; import legup.TestUtilities; @@ -14,7 +14,7 @@ import org.junit.Test; public class LastCellForNumberDirectRuleTest { - private static final LastNumberForCellDirectRule RULE = new LastNumberForCellDirectRule(); + private static final LastCellForNumberDirectRule RULE = new LastCellForNumberDirectRule(); private static Sudoku sudoku; @BeforeClass public static void setUp() { @@ -22,10 +22,10 @@ public static void setUp() { sudoku = new Sudoku(); } @Test - public void LastNumberForCellDirectRuleTest() throws InvalidFileFormatException { + public void LastCellForNumberDirectRuleTest() throws InvalidFileFormatException { //Import board and create transition - - TestUtilities.importTestBoard("puzzles/sudoku/rules/LasCellForNumberDirectRule/TestBoard", sudoku); + //puzzles\sudoku\rules\LastCellForNumberDirectRule\TestBoard + TestUtilities.importTestBoard("puzzles/sudoku/rules/LastCellForNumberDirectRule/TestBoard", sudoku); TreeNode rootNode = sudoku.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); From 10efd8b0056cdbf7f65a854e4d1e52d0849fbba6 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Tue, 9 Apr 2024 17:46:30 -0400 Subject: [PATCH 083/258] Completed and tested all rules to verify correctness. --- .../rules/CompleteRowColumnDirectRule.java | 23 +++--- .../binary/rules/OneTileGapDirectRule.java | 47 ++++------- .../binary/rules/SurroundPairDirectRule.java | 78 ++++--------------- .../rules/ThreeAdjacentContradictionRule.java | 59 +++++++++++--- ...nbalancedRowOrColumnContradictionRule.java | 10 +-- 5 files changed, 93 insertions(+), 124 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java index 6b4399903..50a5eb534 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java @@ -34,23 +34,22 @@ public CompleteRowColumnDirectRule() { */ @Override public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - - BinaryBoard board = (BinaryBoard) transition.getBoard(); BinaryBoard origBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); ContradictionRule contraRule = new UnbalancedRowOrColumnContradictionRule(); + BinaryCell binaryCell = (BinaryCell) puzzleElement; + BinaryBoard modified = origBoard.copy(); + BinaryCell c = (BinaryCell) modified.getPuzzleElement(puzzleElement); - BinaryCell cell = (BinaryCell) board.getPuzzleElement(puzzleElement); - if (cell.getType() == BinaryType.UNKNOWN) { - return "Only ONE or ZERO cells are allowed for this rule!"; - } - - if(cell.getType() != BinaryType.UNKNOWN){ - if (contraRule.checkContradictionAt(origBoard, puzzleElement) != null) { - return "Balanced row or column found"; - } + //System.out.println("ORIG" + binaryCell.getData()); + //System.out.println("AFTER" + Math.abs(binaryCell.getData() - 1)); + modified.getPuzzleElement(puzzleElement).setData(binaryCell.getData()); + System.out.println(contraRule.checkContradictionAt(modified, puzzleElement)); + if (contraRule.checkContradictionAt(modified, puzzleElement) != null) { + return null; } - return null; + + return "Grouping of Three Ones or Zeros not found"; } @Override diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java index d89fab61b..221fcad3d 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java @@ -33,44 +33,25 @@ boolean checkUpDown(BinaryCell c, BinaryBoard board) { } @Override public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - BinaryBoard destBoard = (BinaryBoard) transition.getBoard(); BinaryBoard origBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); ContradictionRule contraRule = new ThreeAdjacentContradictionRule(); + BinaryCell binaryCell = (BinaryCell) puzzleElement; + BinaryBoard modified = origBoard.copy(); - Set changedCells = destBoard.getModifiedData(); - for (PuzzleElement p : changedCells) { - BinaryCell c = (BinaryCell) destBoard.getPuzzleElement(p); + //System.out.println("ORIG" + binaryCell.getData()); + //System.out.println("AFTER" + Math.abs(binaryCell.getData() - 1)); + modified.getPuzzleElement(puzzleElement).setData(Math.abs(binaryCell.getData() - 1)); - int x = c.getLocation().x; - int y = c.getLocation().y; - boolean xOutOfBounds = false; - boolean yOutOfBounds = false; - if ((x - 1 < 0 || x + 1 >= destBoard.getWidth())) { - xOutOfBounds = true; - } - if ((y - 1 < 0 || y + 1 >= destBoard.getHeight())) { - yOutOfBounds = true; - } - if (xOutOfBounds && yOutOfBounds) { - return "Corner of cell cannot have a one tile gap solution"; - } - if (xOutOfBounds && !yOutOfBounds) { - if (!checkUpDown(c, destBoard)) { - return "Not a valid one tile gap"; - } - } - System.out.println(x + " " + y); - System.out.println(c.getType()); - if (c.getType() != BinaryType.UNKNOWN) { - if (destBoard.getCell(x-1, y).getType() == c.getType() && - destBoard.getCell(x+1, y).getType() == c.getType() || - (destBoard.getCell(x, y-1).getType() == c.getType() && - destBoard.getCell(x, y+1).getType() == c.getType())) { - return "Grouping of Three Ones or Zeros found"; - } - } + PuzzleElement newP = binaryCell; + + System.out.println(contraRule.checkContradictionAt(modified, newP)); + + if (contraRule.checkContradictionAt(modified, newP) == null) { + return null; } - return null; + modified.getPuzzleElement(puzzleElement).setData(Math.abs(binaryCell.getData() - 1)); + + return "Grouping of Three Ones or Zeros not found"; } @Override diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java index fd4264a16..b3fc73b00 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java @@ -21,83 +21,31 @@ public SurroundPairDirectRule() { "If two adjacent tiles have the same value, surround the tiles with the other value.", "edu/rpi/legup/images/binary/rules/SurroundPairDirectRule.png"); } - - @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - BinaryBoard board = (BinaryBoard) transition.getBoard(); - BinaryBoard originalBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); + BinaryBoard origBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); ContradictionRule contraRule = new ThreeAdjacentContradictionRule(); -// BinaryCell c = (BinaryCell) modified.getPuzzleElement(puzzleElement); -// System.out.println(c.getLocation()); -// -// System.out.println("BEFORE: " + c.getType()); -// if (c.getData() == 0) -// c.setData(1); -// else if (c.getData() == 1) -// c.setData(0); -// -// System.out.println("AFTER: " + c.getType()); -// modified.setCell(c.getLocation().x, c.getLocation().y, c); -// - BinaryBoard modified = originalBoard.copy(); BinaryCell binaryCell = (BinaryCell) puzzleElement; + BinaryBoard modified = origBoard.copy(); - System.out.println("ORIG" + binaryCell.getData()); - System.out.println("AFTER" + Math.abs(binaryCell.getData() - 1)); + //System.out.println("ORIG" + binaryCell.getData()); + //System.out.println("AFTER" + Math.abs(binaryCell.getData() - 1)); modified.getPuzzleElement(puzzleElement).setData(Math.abs(binaryCell.getData() - 1)); -// - System.out.println(contraRule.checkContradictionAt(modified, puzzleElement)); -// - if (contraRule.checkContradictionAt(modified, puzzleElement) == null) { + PuzzleElement newP = binaryCell; + + System.out.println(contraRule.checkContradictionAt(modified, newP)); + + if (contraRule.checkContradictionAt(modified, newP) == null) { return null; } - return "Grouping of Three Ones or Zeros found"; -// BinaryCell cell = (BinaryCell) board.getPuzzleElement(puzzleElement); -// if(cell.getType() == BinaryType.UNKNOWN){ -// return "Only ONE and ZERO allowed for this rule!"; -// } -// BinaryBoard modified = board.copy(); -// Set changedCells = board.getModifiedData(); -// for (PuzzleElement p : changedCells) { -// BinaryCell c = (BinaryCell) board.getPuzzleElement(p); -// } -// -// if (c.getData() == 0) -// modified.getPuzzleElement(puzzleElement).setData(1); -// else if (c.getData() == 1) -// modified.getPuzzleElement(puzzleElement).setData(0); -// if(contraRule.checkContradictionAt(modified, puzzleElement) != null){ -// return "Grouping of three ONEs or ZEROs found"; -// } - -// -// -// Set changedCells = board.getModifiedData(); -// System.out.println("SIZE" + changedCells.size()); -// for (PuzzleElement p : changedCells) { -// BinaryCell c = (BinaryCell) board.getPuzzleElement(p); -// System.out.println(c.getLocation()); -// if (c.getData() == 0) -// c.setData(1); -// else if (c.getData() == 1) -// c.setData(0); -// System.out.println("HI"); -// } + modified.getPuzzleElement(puzzleElement).setData(Math.abs(binaryCell.getData() - 1)); -// for (PuzzleElement p : changedCells) { -// BinaryCell c = (BinaryCell) board.getPuzzleElement(p); -// //System.out.println(c.getLocation()); -// if (c.getData() == 0) -// c.setData(1); -// else if (c.getData() == 1) -// c.setData(0); -// } + return "Grouping of Three Ones or Zeros not found"; } @Override public Board getDefaultBoard(TreeNode node) { return null; } - -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java index 1ca2bda1b..ad14883f9 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java @@ -24,13 +24,17 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { int width = binaryBoard.getWidth(); BinaryCell cell = (BinaryCell) binaryBoard.getPuzzleElement(puzzleElement); - + System.out.println("THE CELL IS : " + cell.getType()); int cellX = cell.getLocation().x; int cellY = cell.getLocation().y; BinaryCell oneUp = null; BinaryCell oneDown = null; BinaryCell oneForward = null; BinaryCell oneBackward = null; + BinaryCell twoUp = null; + BinaryCell twoDown = null; + BinaryCell twoForward = null; + BinaryCell twoBackward = null; if(binaryBoard.getCell(cellX, cellY + 1) != null){ oneUp = binaryBoard.getCell(cellX, cellY + 1); } @@ -42,19 +46,56 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { } if(binaryBoard.getCell(cellX - 1, cellY) != null){ oneBackward = binaryBoard.getCell(cellX - 1, cellY); - } - //System.out.println("UP: " + oneUp.getLocation() + " " + "DOWN: " + oneDown.getLocation() + - // " " + "BACKWARD: " + oneBackward.getLocation() + " " + "FORWARD: " + oneForward.getLocation() + " " + "CELL: " + cell.getLocation()); - + } + if(binaryBoard.getCell(cellX, cellY + 2) != null){ + twoUp = binaryBoard.getCell(cellX, cellY + 2); + } + if(binaryBoard.getCell(cellX, cellY - 2) != null){ + twoDown = binaryBoard.getCell(cellX, cellY - 2); + } + if(binaryBoard.getCell(cellX + 2, cellY) != null){ + twoForward = binaryBoard.getCell(cellX + 2, cellY); + } + if(binaryBoard.getCell(cellX - 2, cellY) != null){ + twoBackward = binaryBoard.getCell(cellX - 2, cellY); + } if(cell.getType() == BinaryType.ONE || cell.getType() == BinaryType.ZERO) { - if(oneBackward != null && oneForward != null){ - if(oneBackward.getType() == cell.getType() && oneForward.getType() == cell.getType()) + if(twoBackward != null && oneBackward != null && twoBackward.getType() != BinaryType.UNKNOWN && oneBackward.getType() != BinaryType.UNKNOWN) { + if(twoBackward.getType() == cell.getType() && oneBackward.getType() == cell.getType()) { + System.out.println("1"); + return null; + } + } + if(twoForward != null && oneForward != null && twoForward.getType() != BinaryType.UNKNOWN && oneForward.getType() != BinaryType.UNKNOWN){ + if(twoForward.getType() == cell.getType() && oneForward.getType() == cell.getType()) { + System.out.println("2"); + return null; + } + } + if(twoDown != null && oneDown != null && twoDown.getType() != BinaryType.UNKNOWN && oneDown.getType() != BinaryType.UNKNOWN) { + if(twoDown.getType() == cell.getType() && oneDown.getType() == cell.getType()){ + System.out.println("3"); + return null; + } + } + if(twoUp != null && oneUp != null && twoUp.getType() != BinaryType.UNKNOWN && oneUp.getType() != BinaryType.UNKNOWN) { + if (twoUp.getType() == cell.getType() && oneUp.getType() == cell.getType()){ + System.out.println("4"); + return null; + } + } + if(oneBackward != null && oneForward != null && oneBackward.getType() != BinaryType.UNKNOWN && oneForward.getType() != BinaryType.UNKNOWN) { + if(oneBackward.getType() == cell.getType() && oneForward.getType() == cell.getType()){ + System.out.println("5"); return null; + } } - if(oneUp != null && oneDown != null){ - if(oneUp.getType() == cell.getType() && oneDown.getType() == cell.getType()) + if(oneUp != null && oneDown != null && oneUp.getType() != BinaryType.UNKNOWN && oneDown.getType() != BinaryType.UNKNOWN) { + if(oneUp.getType() == cell.getType() && oneDown.getType() == cell.getType()){ + System.out.println("6"); return null; + } } } return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE; diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowOrColumnContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowOrColumnContradictionRule.java index de18e3b5c..c7c429c9f 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowOrColumnContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowOrColumnContradictionRule.java @@ -40,8 +40,8 @@ else if(item.getType() == BinaryType.ONE) { } } - if (rowNumZeros > size/2 || rowNumOnes > size/2) { - return null; + if (rowNumZeros == size/2 && rowNumOnes == size/2) { + return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE; } Set col = binaryBoard.getCol(cell.getLocation().x); @@ -59,10 +59,10 @@ else if(item.getType() == BinaryType.ONE) { } } - if (colNumZeros > size/2 || colNumOnes > size/2) { - return null; + if (colNumZeros == size/2 && colNumOnes == size/2) { + return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE; } - return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE; + return null; } } \ No newline at end of file From 51b5646380754a4347dd657e563d1a7e5c745ac2 Mon Sep 17 00:00:00 2001 From: Brandon McCusker Date: Thu, 11 Apr 2024 22:59:21 -0400 Subject: [PATCH 084/258] Added final rule images, adjusted nming converntions for rule images, updated wiki with new rule images --- ...plicateRowsOrColumnsContradictionRule.java | 2 +- .../rules/ThreeAdjacentContradictionRule.java | 2 +- ...nbalancedRowOrColumnContradictionRule.java | 2 +- .../rules/CompleteRowColumnDirectRule.png | Bin 35435 -> 2941 bytes .../DuplicateColumnsContradictionRule.png | Bin 38259 -> 0 bytes .../DuplicateRowOrColumnContradictionRule.png | Bin 0 -> 3455 bytes .../rules/DuplicateRowsContradictionRule.png | Bin 37440 -> 0 bytes .../images/binary/rules/OneOrZeroCaseRule.png | Bin 36679 -> 5578 bytes .../binary/rules/OneTileGapDirectRule.png | Bin 16465 -> 3101 bytes .../binary/rules/SurroundPairDirectRule.png | Bin 37015 -> 3341 bytes .../rules/ThreeAdjacentContradictionRule.png | Bin 0 -> 2335 bytes .../ThreeAdjacentOnesContradictionRule.png | Bin 52347 -> 0 bytes .../ThreeAdjacentZerosContradictionRule.png | Bin 52375 -> 0 bytes .../UnbalancedColumnContradictionRule.png | Bin 50546 -> 0 bytes .../UnbalancedRowColumnContradictionRule.png | Bin 0 -> 3742 bytes .../rules/UnbalancedRowContradictionRule.png | Bin 48068 -> 0 bytes 16 files changed, 3 insertions(+), 3 deletions(-) delete mode 100644 src/main/resources/edu/rpi/legup/images/binary/rules/DuplicateColumnsContradictionRule.png create mode 100644 src/main/resources/edu/rpi/legup/images/binary/rules/DuplicateRowOrColumnContradictionRule.png delete mode 100644 src/main/resources/edu/rpi/legup/images/binary/rules/DuplicateRowsContradictionRule.png create mode 100644 src/main/resources/edu/rpi/legup/images/binary/rules/ThreeAdjacentContradictionRule.png delete mode 100644 src/main/resources/edu/rpi/legup/images/binary/rules/ThreeAdjacentOnesContradictionRule.png delete mode 100644 src/main/resources/edu/rpi/legup/images/binary/rules/ThreeAdjacentZerosContradictionRule.png delete mode 100644 src/main/resources/edu/rpi/legup/images/binary/rules/UnbalancedColumnContradictionRule.png create mode 100644 src/main/resources/edu/rpi/legup/images/binary/rules/UnbalancedRowColumnContradictionRule.png delete mode 100644 src/main/resources/edu/rpi/legup/images/binary/rules/UnbalancedRowContradictionRule.png diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsOrColumnsContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsOrColumnsContradictionRule.java index f65ccc58c..45b7f808a 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsOrColumnsContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsOrColumnsContradictionRule.java @@ -18,7 +18,7 @@ public DuplicateRowsOrColumnsContradictionRule() { super("BINA-CONT-0003", "Duplicate Rows Or Columns", "There must not be two rows or two columns that are duplicates", - "edu/rpi/legup/images/binary/rules/DuplicateRowsContradictionRule.png"); + "edu/rpi/legup/images/binary/rules/DuplicateRowOrColumnContradictionRule.png"); } @Override diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java index ad14883f9..a6f89cf11 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java @@ -14,7 +14,7 @@ public ThreeAdjacentContradictionRule() { super("BINA-CONT-0001", "Three Adjacent", "There must not be three adjacent zeros or three adjacent ones in a row or column", - "edu/rpi/legup/images/binary/rules/ThreeAdjacentZerosContradictionRule.png"); + "edu/rpi/legup/images/binary/rules/ThreeAdjacentContradictionRule.png"); } @Override diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowOrColumnContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowOrColumnContradictionRule.java index c7c429c9f..8c9c5a161 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowOrColumnContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowOrColumnContradictionRule.java @@ -17,7 +17,7 @@ public UnbalancedRowOrColumnContradictionRule() { super("BINA-CONT-0002", "Unbalanced Row Or Column", "Each row or column must contain an equal number of zeros and ones", - "edu/rpi/legup/images/binary/rules/UnbalancedRowContradictionRule.png"); + "edu/rpi/legup/images/binary/rules/UnbalancedRowColumnContradictionRule.png"); } @Override diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/CompleteRowColumnDirectRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/CompleteRowColumnDirectRule.png index ed738b444046be7708c0de59044f96575f6fdf01..5906402e2be9f4759e7e7a5a022d59bf9f45957c 100644 GIT binary patch literal 2941 zcmZvec{CLI7r-g9Jv)(o_aaL@4Ml_@JB?wiBfA(+*2bPJ%@|}F*_R@Fwq$8yh#3?@ zwqc&ZkSY6+HPvr=@4Rz<@ArOxe82bJbHC@FbIluVU^I2#dHl2Eq!BiTW!=M$yt8_I~s0tY^ zb&=O4!OBAYQ3s@}m3!*-mt@=@^_#YHKitX<=Xd0{?i|lkr}`Hsdb$z}5WgH%9-jwB zm~_ZEzvmP^d-iON_Qf-2g@jP!AE$VqRxdolm7VPU=NspE;s+lUO7gre1FHT#ZX{PM0O&jrS zIf6+XD)`JDob|q;GY98-!T!R+laqCHXJ;n}gBfw=Z{?cd+-Rrv4K6J*`=3U(dG^3c zwN|TngC8W}m0uW91ZQMusW3F$sP$)_a!|AiU&Fvzq$cI?upPUbepmag;isOyG1S2Z zsg01x!kxOYvC&)tCAhcNH#9)5;ktEUp4!v(Svav4c(AI6d~K>26KGR6?!CsW}+K6jPWwmMRoXamlrCT%IR)Mnhs(xz`sKrnIwUE559(6l?%ka%;U;(`o7VRz+az3Jg|1oCgr*tI08@py zy2txkMF1}mfu06My^&JIH3J$&lLz`mCEL|UldX#+p9%DI;qN`&Gp)aymS*@?7`5w4 z@i=_B{DZJhNGP>5R)#kE1G2vX?FH-{2U2$~Im!mz3%C^JcqxsASJov4kjHiV8?BN4 zPz8Fu+kO?ns_*nnXz^6*9d}3!`g!87AU03?#-+9C2H$xH*Tax66lSqBVMGrUe=GNT zr7IZ`nteerEvW={$is^je+( zP){ak9+vF09HWpd6C@KRViP?i5DBrje>bQMbY+!MjgMNUj+79#=DSek<>i#wmH@j3 zz3uV?>Tq7P3qPn%4>%evQR|%$+4>ucsI;P+RVt)61?Wc{mH3TQR9Gya2Ot^F4{%mk z6SX8p0nNR4TM|cqfq|DdGF@c14E)4o+WDO%d5+o)m(=x9xYQ1DOz83)dz~7hov5B= z$sWj!`gghhm2Wve4K$M+iaox-SfULcep<>Mw@kKuRf#iEf)=JV%l~oIc>1`?pf^KY z+bYXmPfgSdSD1V|{9HRE(hO=`0O~6VsLG#DQ5y#%(2X6T1T? ze256)S2d)BTZ})>Z>s-fLiaf7U_ZxeYREzRH3Ypo(f|rSHQp_UGF7^FhDfa11d8)D zcoNUF4u~}9;18|u9^LVaxv64cO_b228)xK{2Fpduxv9Fj?_3h0__P8>X zjW>xgX!puZkNkQKN$Ldwyq_r27-nj zTAlWPc)LKL#TWEPXLMV81r03ai{rcHBx8W#HM)WG%#7lF}q!i-U{ibMdaDT^?}0qjrjj01$7a{~r$_ zUgnAv?>Eq7bc z^%U6!%^-4?^RP?I3L|1=!5r^T+Lv&PizdS^V$cId+4;) zSs_5K4sKP4*Ii%sn;^9XK{~%To>ISZ7-CREz40dOb`L<0PP~V=WLePBKC?-d=HAFE zXC)Fx`o|jF4BK#Dm(G?HnL=L|KKefNtA6eo;-oZqdB?xysi)SrOHl0U3-LdDFXQO7 z-(;+)$e#oH@9zA^{61&Dd0vn&DA_K`-F#Y>*v}Xnfsi6CK`%PnlC+{|`DLB#_dgkZ zXWXY%UbWXn3aNy96$pm#4CS~I0Zud-aG|*5Jt{AZ=>xcKCvy^O)NLA&aG6Q8Df#+n zx!Mh7=+5J}g|hjPDmRjOc$g+WLUy;Rt#S&PcV!9tSfD4g--6%gE;-}dPf}cQ=4#{>ma%N5gE$p6 zwdwt6Y<70G|JU&0xTk}r?~S0+A^NqP|FyJ1yv%N%u-N{7^E1Bz7o5H_Gng7#0qYHJ G-Tx2u0kbOr literal 35435 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 diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/DuplicateColumnsContradictionRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/DuplicateColumnsContradictionRule.png deleted file mode 100644 index 57b75b579684d58d4085bf5bcf2a15eb84979503..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 38259 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/DuplicateRowsContradictionRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/DuplicateRowsContradictionRule.png deleted file mode 100644 index 69c64a2bfa5205a7e46a58ab35e38026b26a1bec..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 37440 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 diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/OneOrZeroCaseRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/OneOrZeroCaseRule.png index 2aa2c91f5e09ffdef37afa1e0f9c2f27e01d0ae8..73072f2ce5ea9d189fe55058aa6a4fa09ecc3979 100644 GIT binary patch literal 5578 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 literal 36679 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 KT9l(aDgOl%`m4_X literal 16465 zcmeI2Pbh<79LIlS<~5d;gFjL4$$4=SWm}W2SXvG!qOhBki-W^L$!WQW3(8e1r5wpw zP7ZQ#P_`5YHwVS)ul)@QZ7&-?CA?bG-9zMtpq-5$#hN5UOp5s75dshmiI4(pD* zkZu|u*B*2eSji11rF7HztUJMcVl*LgT5SB7tJD34<@Dr=NY|D<1I4Ge1(CsWCY2ap zoq4%WM8uC?#x5@^8};40XNUWD2l;@0tNO@PTHVm=5qCJg7x3KStERXcMi-^#dt8Xs zM&04f_JSMw*AjH&xsdOMUN1i_0uapu39(7Rlu-zDh(&=?H42<%6auGRivqG>6p#gl zfGk)PkOhT+ELaqf1*3p0CQQ3dn*{Ko%4NvS3j_78C-qU{OF8i~_Qt5dJ0$ z=hOX1dUIjCZT|DN{2uBveD?514 JO_h?f>t7AgHs=5U diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/SurroundPairDirectRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/SurroundPairDirectRule.png index 0d4aa11db818fdee5e10559f8f13e7fadfefcea5..265a5f77a54038bb5a6bfdfa86a6cd910e8cc367 100644 GIT binary patch literal 3341 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 diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/ThreeAdjacentContradictionRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/ThreeAdjacentContradictionRule.png new file mode 100644 index 0000000000000000000000000000000000000000..7b08696dbc074e460bb7664721d0be79d3a4f21f GIT binary patch literal 2335 zcma)8cU03^7LElep@=ZJL3s6zPme z00{$`Unmh9hY}G`l7J)zP@74v-{8Pamyd~-t)cp&Uxp)`+fJm1SG;jP6i?a z0)gZ#;bwN?2#Ad=wMXoOVKximup`XQ0tO;?t4)c)ZXXj{6A-926)bd@5M$|JxMLUy zB;WGQcC-hPJV79-KP}Bnu131>xo;30E9JHjh6J&)vu>Io_e*k5$GitN11k|JhJ=j*T|m*VwAQ!Zv$#Zm4_+ z93*j++1b&eS6JFhr%MC6#%l7`tV>0Z@l0OK+U4~#G$DR^Io-9tKQL9E=Atpvm3Nvx z-Cx7NVv;zsEaL9t+$?gtNEFlLyqCi($s(*r;bvlbJ$!z)q2AC48@OLiU7L~JL(c*W z*rv^AXuJ4Jn}ILzJp3#9cuzsSL(C%fNn-jfrzozhR}`ebKAWkdaD>-p?g- zlounrh#+)w2@P;VjB^$d#nU z#jyHo^1w+0IB86uT#E4^m|^j_wfQ$#plTV}f2Wa13y@P`jla?|fML6m4l}DD7R)oM zZ2Q&QPpRG&4R-z}*bv|I%+se&2UbDklC7}YGAMM~0duzkCxviPb61@)?vp04rDuk% ze%SQh*4?E5ue1}`f?mb`1gn++S~cOMMY%tD-msQVN-_0Se5Gw`^39jWp|v;A+?X{} z328vq;rZ9$;n&#KRJKU!nmD)4H1lm4B3^-scg)B(v~@Uvq3y4ux^Wfo`hhQl##3k0 z-%PNPoM^1kqE4J!Nmh1U05e+_M~8H1?9Q-N>Lsw>_NgpgLP6l&zIQ6pb$>NVw)VD% zyV^jsncOg?ES9#zSq!?SxJ1R#v_oHd{aDyg-5y2?`>m8Zrl>7@q>fa59u*Jq-T9rO zGhNyov*h~zU@o+ZV#dl+y855FsZQL%V#&7T zGslMLqR}p6dO%vXgzeK1TqoK40sHH3HPti3zbNUlpiD#{5G31@FTvLLj`3+>+m-CP_-qA!eyH5TyhI*J7TMMp57SWYr4aw@Nj z#)wL#!lX{V*JK(#M7F5GCzf%H3z$wR==lqP@#8XNQBe`CI&@U)!;j-5 zDlD3YiYM47>)Nu`YfM~|NmA3kDzdlzAU{F6BoN6J)jo>>_K4TxPRNV>Ke&t_c>ksC z1DW{CP5Mb1qkr2cK3lMgg*IDgfMMK2J0X%{FCBj2Q&r&3sVL)Aq+}bb`A%GuyM={C zU{!u>?5_IwXM1@BI`YakFAqP*o=buE$LfVImP&=c9IDt#RgC##5m@_OupyI`cx>Nv z2w0sbTpO{e=?_D1!1rtAsSWp7E=d~rX;`Q)hExGx`KFd0o)lC20}-)o<= zEgx+;9u_#iJ+?I&-aK8~&8}3hXD}F-vZ0wu2|om7OVvJLogF`N>@Dxc^KKR-P>S=P z+tt79T)|9M0Q8dYlWafc&?yCZ065{|$*3gRWQR`(g{e7!HI+zxPTu z#V!n}%BDjddc^&DU`p$tL=ie9Ix_v7 z^J$Y2+`@)v-mTuD)%M`Y75yTj&=*6ah20%FS%WnUzMEs4V)6LDF+QIJD~Pt+T3MlT zJR|`?N6hVA*Pfz;;VAuL>WYLMU>s+hh_l?~2*ZBaEiFd*T+!i+_DFQ32@I+PYaa<| znt6hAbW(_CzXcDLXAx?fIuw9-#n$A*AGH1tor&d`|0AqGBhTMY%?JPtB1vAu>!odz z%Ta;W1{m-WIH~M--PEr}?k5i9P2=gAnz>$@ss1o59+RgMZMboki?><6`Rze)lTqi^ zJ}kF3pyIwamBeL6@V)ZA2HfPV54z6GIk@mX;jl7UA%*>Y|C3Z(*k}Qa99003!9%%dch;2pKxbE)y z{E=))re^vB_R_rn-C)xFPfYn`PJK|u+|VmpQNX%j%(||zG4~u^^qF5fvN+L0r}*^r wnrx~xhb=^@I8F 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 bR*aM05}2c!Ju;H2XWmt+4A-X)Jh diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/ThreeAdjacentZerosContradictionRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/ThreeAdjacentZerosContradictionRule.png deleted file mode 100644 index 4199e7f176fc32903ca84b92d015d8877a20744c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 52375 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

    i|C9#y#k97|Nzij8?|e-?S8~uQR#q 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 IE(gf}0f7YAKL7v# literal 0 HcmV?d00001 From 714daee5ec4d4c344f78fccffd479bde1aac0bae Mon Sep 17 00:00:00 2001 From: Brandon McCusker Date: Fri, 12 Apr 2024 20:39:48 -0400 Subject: [PATCH 087/258] Added Wiki Contributions --- WikiContributions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WikiContributions.md b/WikiContributions.md index f0ba97334..243dfa834 100644 --- a/WikiContributions.md +++ b/WikiContributions.md @@ -65,4 +65,4 @@ This rule is a direct consequence of Rule #2. If two of the same digit exist wit [![JvztVKN.th.png](https://iili.io/JvztVKN.th.png)](https://freeimage.host/i/JvztVKN) -This rule is a direct consequence of Rules #2 and #3. If a row or column is completely filled with 1s and 0s, there does not exist a grouping of three 1s or 0s anywhere in the row or column, and the row or column is unique then the row contains no contradictions. \ No newline at end of file +This rule is a direct consequence of Rules #2 and #3. If a row or column is completely filled with 1s and 0s, there does not exist a grouping of three 1s or 0s anywhere in the row or column, and the row or column is unique then the row contains no contradictions. From 44d0de5b5e506c58ce0dd6b3316a7115eb2919c2 Mon Sep 17 00:00:00 2001 From: zachbonagura <157537291+zachbonagura@users.noreply.github.com> Date: Fri, 12 Apr 2024 21:27:15 -0400 Subject: [PATCH 088/258] Add files via upload --- LEGUPBinaryPuzzleProgress.pptx | Bin 0 -> 317474 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 LEGUPBinaryPuzzleProgress.pptx diff --git a/LEGUPBinaryPuzzleProgress.pptx b/LEGUPBinaryPuzzleProgress.pptx new file mode 100644 index 0000000000000000000000000000000000000000..06e0f6895888da7a9d31c62b982b8f3c2928618e GIT binary patch literal 317474 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

    -udG5<-o!N9 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£(ne6!_f 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 Date: Tue, 16 Apr 2024 16:27:07 -0400 Subject: [PATCH 089/258] this does nothing its forcing me to do this --- .../puzzles/sudoku/rules/LastCellForNumberDirectRuleTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/java/puzzles/sudoku/rules/LastCellForNumberDirectRuleTest.java b/src/test/java/puzzles/sudoku/rules/LastCellForNumberDirectRuleTest.java index 8b3e96a79..a2c3ba63f 100644 --- a/src/test/java/puzzles/sudoku/rules/LastCellForNumberDirectRuleTest.java +++ b/src/test/java/puzzles/sudoku/rules/LastCellForNumberDirectRuleTest.java @@ -24,7 +24,6 @@ public static void setUp() { @Test public void LastCellForNumberDirectRuleTest() throws InvalidFileFormatException { //Import board and create transition - //puzzles\sudoku\rules\LastCellForNumberDirectRule\TestBoard TestUtilities.importTestBoard("puzzles/sudoku/rules/LastCellForNumberDirectRule/TestBoard", sudoku); TreeNode rootNode = sudoku.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); From d0ae7e54ca09f6d507b0fbab9aa3a22bfa5fb45f Mon Sep 17 00:00:00 2001 From: kchiu1 <152306707+kchiu1@users.noreply.github.com> Date: Tue, 16 Apr 2024 16:40:23 -0400 Subject: [PATCH 090/258] Delete LastCellForNumberDirectRuleTest.java --- .../LastCellForNumberDirectRuleTest.java | 49 ------------------- 1 file changed, 49 deletions(-) delete mode 100644 src/test/java/puzzles/sudoku/rules/LastCellForNumberDirectRuleTest.java diff --git a/src/test/java/puzzles/sudoku/rules/LastCellForNumberDirectRuleTest.java b/src/test/java/puzzles/sudoku/rules/LastCellForNumberDirectRuleTest.java deleted file mode 100644 index a2c3ba63f..000000000 --- a/src/test/java/puzzles/sudoku/rules/LastCellForNumberDirectRuleTest.java +++ /dev/null @@ -1,49 +0,0 @@ -package puzzles.sudoku.rules; - -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -import edu.rpi.legup.puzzle.sudoku.Sudoku; -import edu.rpi.legup.puzzle.sudoku.SudokuBoard; -import edu.rpi.legup.puzzle.sudoku.SudokuCell; -import edu.rpi.legup.puzzle.sudoku.rules.LastCellForNumberDirectRule; -import edu.rpi.legup.save.InvalidFileFormatException; -import legup.MockGameBoardFacade; -import legup.TestUtilities; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; - -public class LastCellForNumberDirectRuleTest { - private static final LastCellForNumberDirectRule RULE = new LastCellForNumberDirectRule(); - private static Sudoku sudoku; - @BeforeClass - public static void setUp() { - MockGameBoardFacade.getInstance(); - sudoku = new Sudoku(); - } - @Test - public void LastCellForNumberDirectRuleTest() throws InvalidFileFormatException { - //Import board and create transition - TestUtilities.importTestBoard("puzzles/sudoku/rules/LastCellForNumberDirectRule/TestBoard", sudoku); - TreeNode rootNode = sudoku.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - for(int i = 1; i < 10; i++){ - //Reset board - SudokuBoard board = (SudokuBoard) transition.getBoard(); - //Set cell - SudokuCell cell1 = board.getCell(2, 2); - cell1.setData(i); - board.addModifiedData(cell1); - - //Test the case - if(i == 9) { - Assert.assertNotNull(RULE.checkRuleAt(transition, cell1)); - } else { - Assert.assertNull(RULE.checkRuleAt(transition, cell1)); - } - } - - } -} From 19fbed62a599fa211d52cd023f5b69b9bcb14d1b Mon Sep 17 00:00:00 2001 From: Brandon McCusker Date: Tue, 16 Apr 2024 16:44:18 -0400 Subject: [PATCH 091/258] Made improvement to rule images --- .../rules/CompleteRowColumnDirectRule.png | Bin 2941 -> 2835 bytes .../binary/rules/OneTileGapDirectRule.png | Bin 3101 -> 2751 bytes .../binary/rules/SurroundPairDirectRule.png | Bin 3341 -> 2982 bytes .../rules/ThreeAdjacentContradictionRule.png | Bin 2335 -> 2508 bytes .../UnbalancedRowColumnContradictionRule.png | Bin 3742 -> 2793 bytes 5 files changed, 0 insertions(+), 0 deletions(-) diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/CompleteRowColumnDirectRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/CompleteRowColumnDirectRule.png index 5906402e2be9f4759e7e7a5a022d59bf9f45957c..a74654d4301f75defc639727604f3d59f05612a3 100644 GIT binary patch literal 2835 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 W-$D%jr3*N)f}HK$?8r8Oq<;bxYC}%| literal 2941 zcmZvec{CLI7r-g9Jv)(o_aaL@4Ml_@JB?wiBfA(+*2bPJ%@|}F*_R@Fwq$8yh#3?@ zwqc&ZkSY6+HPvr=@4Rz<@ArOxe82bJbHC@FbIluVU^I2#dHl2Eq!BiTW!=M$yt8_I~s0tY^ zb&=O4!OBAYQ3s@}m3!*-mt@=@^_#YHKitX<=Xd0{?i|lkr}`Hsdb$z}5WgH%9-jwB zm~_ZEzvmP^d-iON_Qf-2g@jP!AE$VqRxdolm7VPU=NspE;s+lUO7gre1FHT#ZX{PM0O&jrS zIf6+XD)`JDob|q;GY98-!T!R+laqCHXJ;n}gBfw=Z{?cd+-Rrv4K6J*`=3U(dG^3c zwN|TngC8W}m0uW91ZQMusW3F$sP$)_a!|AiU&Fvzq$cI?upPUbepmag;isOyG1S2Z zsg01x!kxOYvC&)tCAhcNH#9)5;ktEUp4!v(Svav4c(AI6d~K>26KGR6?!CsW}+K6jPWwmMRoXamlrCT%IR)Mnhs(xz`sKrnIwUE559(6l?%ka%;U;(`o7VRz+az3Jg|1oCgr*tI08@py zy2txkMF1}mfu06My^&JIH3J$&lLz`mCEL|UldX#+p9%DI;qN`&Gp)aymS*@?7`5w4 z@i=_B{DZJhNGP>5R)#kE1G2vX?FH-{2U2$~Im!mz3%C^JcqxsASJov4kjHiV8?BN4 zPz8Fu+kO?ns_*nnXz^6*9d}3!`g!87AU03?#-+9C2H$xH*Tax66lSqBVMGrUe=GNT zr7IZ`nteerEvW={$is^je+( zP){ak9+vF09HWpd6C@KRViP?i5DBrje>bQMbY+!MjgMNUj+79#=DSek<>i#wmH@j3 zz3uV?>Tq7P3qPn%4>%evQR|%$+4>ucsI;P+RVt)61?Wc{mH3TQR9Gya2Ot^F4{%mk z6SX8p0nNR4TM|cqfq|DdGF@c14E)4o+WDO%d5+o)m(=x9xYQ1DOz83)dz~7hov5B= z$sWj!`gghhm2Wve4K$M+iaox-SfULcep<>Mw@kKuRf#iEf)=JV%l~oIc>1`?pf^KY z+bYXmPfgSdSD1V|{9HRE(hO=`0O~6VsLG#DQ5y#%(2X6T1T? ze256)S2d)BTZ})>Z>s-fLiaf7U_ZxeYREzRH3Ypo(f|rSHQp_UGF7^FhDfa11d8)D zcoNUF4u~}9;18|u9^LVaxv64cO_b228)xK{2Fpduxv9Fj?_3h0__P8>X zjW>xgX!puZkNkQKN$Ldwyq_r27-nj zTAlWPc)LKL#TWEPXLMV81r03ai{rcHBx8W#HM)WG%#7lF}q!i-U{ibMdaDT^?}0qjrjj01$7a{~r$_ zUgnAv?>Eq7bc z^%U6!%^-4?^RP?I3L|1=!5r^T+Lv&PizdS^V$cId+4;) zSs_5K4sKP4*Ii%sn;^9XK{~%To>ISZ7-CREz40dOb`L<0PP~V=WLePBKC?-d=HAFE zXC)Fx`o|jF4BK#Dm(G?HnL=L|KKefNtA6eo;-oZqdB?xysi)SrOHl0U3-LdDFXQO7 z-(;+)$e#oH@9zA^{61&Dd0vn&DA_K`-F#Y>*v}Xnfsi6CK`%PnlC+{|`DLB#_dgkZ zXWXY%UbWXn3aNy96$pm#4CS~I0Zud-aG|*5Jt{AZ=>xcKCvy^O)NLA&aG6Q8Df#+n zx!Mh7=+5J}g|hjPDmRjOc$g+WLUy;Rt#S&PcV!9tSfD4g--6%gE;-}dPf}cQ=4#{>ma%N5gE$p6 zwdwt6Y<70G|JU&0xTk}r?~S0+A^NqP|FyJ1yv%N%u-N{7^E1Bz7o5H_Gng7#0qYHJ G-Tx2u0kbOr diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/OneTileGapDirectRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/OneTileGapDirectRule.png index 157e3d6b2af2c654ca3300d7108ca6cbf3ae198f..b68f67e441d3519f17daffd48da37f35e9b3bcfb 100644 GIT binary patch literal 2751 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 literal 3101 zcmZ{mc{CJiAIAq1(@=wkiMf~vS?5x=k{Be-G_s8~W8Z1UI@E~CXfl>osxh*pM3%9R zYmmtn*;-zEH6)QNQI^O%oqOJM?tAXNfBc@``98}z&vSm?=kq*Q&tk3ifMvk|0AP>x zDGNJ(F6T!DNSNRHo}EVXlR%`M6$((^_uDLA00Ydatn&O=b1YRnD zg+a}<#Igokp5oy9UhP)I>8I+@oC6OOs5x*JjTv!%3+#go-gYQa*?pI zvJ$@YbDOX5%@>LImW1dZ-@k}z#T!L_OdG2WabkZpWpkfhfgJG0;i9ER(`Ju4E`169 zJkc0SH_>PGmfsI~OeT}d2Lq$FF=)Bpe$x!ym>;SB)jbi&P&bZW?b-u@AUCh*5f+Z%%La}OoJh7liVjNDx9WO`&-=x}9gT;}JL zloS+Qge&D+k|(oBq?^R^Qly!r%(1WX2JW@4H=EZLnnuyjV67L%xmh0Ud`s0&J~IwU z@&*!2`PlJn|3ll&uUnPyChNMNMe{np9Kan9e+46PT<~+=1KHmui5v3ScapivD*1$~ z)`#4^CBc7{5RdSl9+E|LkTBWu4QM|0>xbtBlg7#}qA=l(k{2s8{d7k|cZir+F|=Y; zsW4c??R zbF(T79cm7wA$E;`VXVE(r%Ql>Gk#0ADU6`tV0HIdp}HFk^$cahi|YhpGSeOduY!ip zpRs(xe2`msTfhU&8TQ_O!q7D!fmN>+5n%iLH23b|o9_xxmW4|zm+I?LK8E9Pp>G@MUNxdf@l2~(BdNir@N2|JlIRGg`C`rsg9y$C6X^A8jk(#Dn!XH!bGkX=0f*hgOu> znXCNmUH zEM&+XlXm?^To^a1C;y0voqbs}Pyk6=<6C)rV`XN7Ka46hshknXsvi@)58e+#?hhJMq@D!)Ox{UXya3U1UwIC6h zFuU^?1E>eNR9inEqX*LmN<|bceW8kM@t_oNKckVP0n<*?d@E&C)HRnR=a;JNb)`~G z-Gbr0^Sg$F_W1DOv+NKdRwv59ZE`3yCPv?V+Ol81udCZ-K1pAiSPp4|mfNj=_Y6AZ zUUW-p;l&G#VUH--NsZ{bQ`Gh5us!?q?BXKQLseUZipJc~bZmR^Z?PmLC?O7kr8!ZuJ}i%o zcmQ7^P?)|*<`_6*{kC`^@)%H8~pp?H!v&$8PN{#{y+nFQ2_Pef!R@iBbj@qsyf z3?qov4;yv(O^=cw*ju;t?Q`}Ro9N?Z)!TZsa=M)kn@EQnpwKX$2b*BFebg{wcj#DM zubd$PQS-_Ct6X5+bg5It_}bz-x}R?^`g!GaFT;Rd=C&ii0}lhs3a#br?d>fUnh+>D zR#;d#^~~lGAviZ{JTLQ_yxG6*^RK6{rqbs%hMo70I1$Q?E~l^R4V?=u0q9!@7v`qL z(p(NL?Kmr&=}UrM1s-v|wDU78P6s+uY={?i6d5_f=qcQSw7wgLpR)>Yl*mlF-n3l^l zl@`1}26D{(9ak~zNupUQvdVQb;rea+4%?!2YMDFRj}w%NM9t-wu+h;OZw>Kwh9%v{!|!5opKELH{UbXo_QN08`x+P33*YC73MUexS}yJE z)%y8xr6^ps8ASU)AuNtJOm%d0@L?*>8d7sN$@xYL!VBNJ^$l=5T=D4f1vc^wK85^P zblmuNqdw9DU|e5*CU&&Jm(xLEB*_xUC>^Lfhsl!6!2yHRwQuOw}`vZ$`9&7zH`&- z7l8M01@F%sz#@8DUY@`x9SMs8iMvVMwBzu9Da!>kf0XY&3xpIL9GuFb7)nS;TX`PP zH$`K0hpj`euJy6B28G>J1fEL)&*vy^Q2ZmXpviXGKAgxt$~D(Sn3Cu}@D($k14_Tj zRM@0AY+~l!g>dhtu$z=Mc67EE9@yNe+#_fMpM6xPJKGbV_u0X0McV3)x~I$_H^%mk zI*0s2zvh$BRQh8|`SW{Gt^tRHUj@k53shx KT9l(aDgOl%`m4_X diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/SurroundPairDirectRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/SurroundPairDirectRule.png index 265a5f77a54038bb5a6bfdfa86a6cd910e8cc367..67a4e47f363222af68afe45acacd0783f0f35319 100644 GIT binary patch literal 2982 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 literal 3341 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 HUy1z(|GtR) literal 2335 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 literal 3742 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 f-;tzWdHxaMFi Date: Tue, 16 Apr 2024 16:48:18 -0400 Subject: [PATCH 092/258] Delete LEGUP Binary Puzzle Progress.pptx --- LEGUP Binary Puzzle Progress.pptx | Bin 317431 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 LEGUP Binary Puzzle Progress.pptx diff --git a/LEGUP Binary Puzzle Progress.pptx b/LEGUP Binary Puzzle Progress.pptx deleted file mode 100644 index b1d96fa1323b0ae39677a4b95b75f6d6ad556657..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 317431 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

    i|C9#y#k97|Nzij8?|e-?S8~uQR#q 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 IE(gf}0f7YAKL7v# From 04f572867eee7f0edc5fb75e96ebf2d8c4411050 Mon Sep 17 00:00:00 2001 From: Charles Tian <46334090+charlestian23@users.noreply.github.com> Date: Tue, 16 Apr 2024 16:48:40 -0400 Subject: [PATCH 093/258] Delete LEGUPBinaryPuzzleProgress.pptx --- LEGUPBinaryPuzzleProgress.pptx | Bin 317474 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 LEGUPBinaryPuzzleProgress.pptx diff --git a/LEGUPBinaryPuzzleProgress.pptx b/LEGUPBinaryPuzzleProgress.pptx deleted file mode 100644 index 06e0f6895888da7a9d31c62b982b8f3c2928618e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 317474 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

    -udG5<-o!N9 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£(ne6!_f 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 Date: Tue, 16 Apr 2024 16:49:00 -0400 Subject: [PATCH 094/258] Delete WikiContributions.md --- WikiContributions.md | 68 -------------------------------------------- 1 file changed, 68 deletions(-) delete mode 100644 WikiContributions.md diff --git a/WikiContributions.md b/WikiContributions.md deleted file mode 100644 index 243dfa834..000000000 --- a/WikiContributions.md +++ /dev/null @@ -1,68 +0,0 @@ -# Binary -Binary is a grid based puzzle game akin to Sudoku. You are given a grid of empty squares and squares filled with 1 or 0. Your task is to fill the board with 1s and 0s while adhering to the rules of the game. - -Each binary puzzle has a unique solution. It is always possible to make a next step by reasoning. In other words, the solution can always be found without guessing. - -### Interacting with the Binary Board -Clicking on a white square fills it with a 0 - -Clicking on a square with a 0 fills it with a 1 - -Clicking on a square with a 1 returns it white - -# Rules -### Here are the direct rules of the puzzle -1) Each square should contain either a zero or a one. -2) Three orthogonally adjacent zeros or ones is not allowed. -3) Each row and each column should contain an equal number of zeros and ones. -4) Each row is unique and each column is unique. Thus, any row cannot be exactly equal to another row, and any column cannot be exactly equal to another column. - -# LEGUP Proof Rules - -## Case Rules - -### One or Zero - -[![JvzOzNe.th.png](https://iili.io/JvzOzNe.th.png)](https://freeimage.host/i/JvzOzNe) - -This rule is a direct consequence of rule #1. If a tile can be filled with a 0 or a 1 based on the current state of the board, create a split in the tree where the tile is a 0 in one path and 1 in the other to show two possible cases. - -## Contradiction Rules - -### Three in a Row - -[![Jvz8tYQ.th.png](https://iili.io/Jvz8tYQ.th.png)](https://freeimage.host/i/Jvz8tYQ) - -This rule is a direct consequence of Rule #2. If a sequence of three of the same digit exists on the board, then the board is in a state of contradiction. - -### Unbalanced Row/Column Rule - -[![Jvzr9Z7.th.png](https://iili.io/Jvzr9Z7.th.png)](https://freeimage.host/i/Jvzr9Z7) - -This rule is a direct consequence of Rule #3. If a row or column contains more of one digit than the other, then the board is in a state of contradiction. - -### Identical Row/Column Rule - -[![JvzrpUJ.th.png](https://iili.io/JvzrpUJ.th.png)](https://freeimage.host/i/JvzrpUJ) - -This rule is a direct consequence of Rule #4. If a row is identical to another row or a column is identical to another column, then the board is in a state of contradiction. - -## Direct Rules - -### Surround Pair - -[![Jvzs8an.th.png](https://iili.io/Jvzs8an.th.png)](https://freeimage.host/i/Jvzs8an) - -This rule is a direct consequence of Rule #2. If two of the same digit exist adjacent to each other in any given row or column, then in order to avoid violating Rule #2, the pair must be surrounded with other digit on both sides. - -### One Tile Gap - -[![JvzLAFt.th.png](https://iili.io/JvzLAFt.th.png)](https://freeimage.host/i/JvzLAFt) - -This rule is a direct consequence of Rule #2. If two of the same digit exist with a one tile gap between them, then in order to avoid violating Rule #2, the pair must be separated by placing the other digit between them. - -### Complete Row/Column - -[![JvztVKN.th.png](https://iili.io/JvztVKN.th.png)](https://freeimage.host/i/JvztVKN) - -This rule is a direct consequence of Rules #2 and #3. If a row or column is completely filled with 1s and 0s, there does not exist a grouping of three 1s or 0s anywhere in the row or column, and the row or column is unique then the row contains no contradictions. From 9c80334ac5243e6e12d4cf8299de764b1fb8e625 Mon Sep 17 00:00:00 2001 From: kchiu1 <152306707+kchiu1@users.noreply.github.com> Date: Tue, 16 Apr 2024 16:53:50 -0400 Subject: [PATCH 095/258] funny number change --- .../rpi/legup/puzzle/sudoku/rules/sudoku_reference_sheet.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/sudoku_reference_sheet.txt b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/sudoku_reference_sheet.txt index 3f9e62cc8..ceffa168c 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/sudoku_reference_sheet.txt +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/sudoku_reference_sheet.txt @@ -5,7 +5,7 @@ SUDO-CONT-0001 : NoCellForNumberRegionContradictionRule SUDO-CONT-0002 : NoCellForNumberRowContradictionRule SUDO-CONT-0003 : NoCellForNumberColumnContradictionRule SUDO-CONT-0004 : NoNumberForCellContradictionRule -SUDO-CONT-0002 : RepeatedNumberContradictionRule +SUDO-CONT-0005 : RepeatedNumberContradictionRule SUDO-CASE-0001 : PossibleNumbersForCellCaseRule SUDO-CASE-0002 : PossibleCellsForNumberRegionCaseRule From 31c3ead782ad72634e4dca03724aa46e5e51262c Mon Sep 17 00:00:00 2001 From: Bram van Heuveln Date: Tue, 16 Apr 2024 20:55:38 +0000 Subject: [PATCH 096/258] Automated Java code formatting changes --- .../sudoku/PossibleNumberCaseBoard.java | 4 +- .../rules/LastCellForNumberDirectRule.java | 374 +++++++++--------- .../rules/LastNumberForCellDirectRule.java | 183 ++++----- ...oCellForNumberColumnContradictionRule.java | 40 +- ...oCellForNumberRegionContradictionRule.java | 40 +- .../NoCellForNumberRowContradictionRule.java | 40 +- .../NoNumberForCellContradictionRule.java | 14 +- .../PossibleCellsForNumberColumnCaseRule.java | 35 +- .../PossibleCellsForNumberRegionCaseRule.java | 35 +- .../PossibleCellsForNumberRowCaseRule.java | 22 +- .../rules/PossibleNumbersForCellCaseRule.java | 6 +- .../RepeatedNumberContradictionRule.java | 14 +- src/test/java/legup/TestRunner.java | 1 - ...LastNumberForCellDirectRuleRegionTest.java | 53 +-- .../RepeatedNumberContradictionRuleTest.java | 46 ++- 15 files changed, 474 insertions(+), 433 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/PossibleNumberCaseBoard.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/PossibleNumberCaseBoard.java index 5c94e3e0b..c5f9eec2a 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/PossibleNumberCaseBoard.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/PossibleNumberCaseBoard.java @@ -3,7 +3,6 @@ import edu.rpi.legup.model.gameboard.CaseBoard; import edu.rpi.legup.model.gameboard.PuzzleElement; import edu.rpi.legup.puzzle.sudoku.rules.PossibleCellsForNumberRegionCaseRule; - import java.awt.event.MouseEvent; import java.util.HashSet; import java.util.Set; @@ -15,7 +14,8 @@ public class PossibleNumberCaseBoard extends CaseBoard { private Set pickableRows; private Set pickableCols; - public PossibleNumberCaseBoard(SudokuBoard baseBoard, PossibleCellsForNumberRegionCaseRule caseRule, SudokuCell cell) { + public PossibleNumberCaseBoard( + SudokuBoard baseBoard, PossibleCellsForNumberRegionCaseRule caseRule, SudokuCell cell) { super(baseBoard, caseRule); this.cell = cell; this.pickableRegions = new HashSet<>(); diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/LastCellForNumberDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/LastCellForNumberDirectRule.java index f9b1e2e28..f5646a3c0 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/LastCellForNumberDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/LastCellForNumberDirectRule.java @@ -1,185 +1,189 @@ - -package edu.rpi.legup.puzzle.sudoku.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.sudoku.SudokuBoard; -import edu.rpi.legup.puzzle.sudoku.SudokuCell; - -import java.util.Set; - -public class LastCellForNumberDirectRule extends DirectRule { - public LastCellForNumberDirectRule() { - super("SUDO-BASC-0002", "Last Cell for Number", - "This is the only cell open in its group for some number.", - "edu/rpi/legup/images/sudoku/forcedByElimination.png"); - } - - /** - * 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 - */ - public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - SudokuBoard initialBoard = (SudokuBoard) transition.getParents().get(0).getBoard(); - SudokuBoard finalBoard = (SudokuBoard) transition.getBoard(); - - SudokuCell cell = (SudokuCell) finalBoard.getPuzzleElement(puzzleElement); - - //Check if empty cell placed - if (cell.getData() == 0) { - return super.getInvalidUseOfRuleMessage() + ": Cell is not forced at this index"; - } - - //Get defaults - Set region = initialBoard.getRegion(cell.getGroupIndex()); - Set row = initialBoard.getRow(cell.getLocation().y); - Set col = initialBoard.getCol(cell.getLocation().x); - - //Check if new cell conflicts group - for(SudokuCell c : region){ - if(c.getData() == cell.getData()) { - return super.getInvalidUseOfRuleMessage() + ": Cell is not forced at this index"; - } - } - for(SudokuCell c : row){ - if(c.getData() == cell.getData()) { - return super.getInvalidUseOfRuleMessage() + ": Cell is not forced at this index"; - } - } - for(SudokuCell c : col){ - if(c.getData() == cell.getData()) { - return super.getInvalidUseOfRuleMessage() + ": Cell is not forced at this index"; - } - } - - //// - //Loop to see if the number is constrained to the cell - boolean restrained = true; - for(SudokuCell c : region){ - //Test if its not a valid testing cell - if(c.getData() != 0) { - continue; - } - if(c.getLocation().y == cell.getLocation().y && c.getLocation().x == cell.getLocation().x) { - continue; - } - //Check if cell is eligible to hold number - Set crow = initialBoard.getRow(c.getLocation().y); - Set ccol = initialBoard.getCol(c.getLocation().x); - boolean contains = false; - for(SudokuCell rc : crow){ - if(rc.getData() == cell.getData()) { - contains = true; - } - } - for(SudokuCell cc : ccol){ - if(cc.getData() == cell.getData()) { - contains = true; - } - } - //Stop if another cell can hold number - if(!contains) { - restrained = false; - break; - } - } - //Output if success - if(restrained) { - return null; - } - - //// - //Loop to see if the number is constrained to the cell - restrained = true; - for(SudokuCell c : row){ - //Test if its not a valid testing cell - if(c.getData() != 0) { - continue; - } - if(c.getLocation().y == cell.getLocation().y && c.getLocation().x == cell.getLocation().x) { - continue; - } - //Check if cell is eligible to hold number - Set cregion = initialBoard.getRegion(c.getGroupIndex()); - Set ccol = initialBoard.getCol(c.getLocation().x); - boolean contains = false; - for(SudokuCell rc : cregion){ - if(rc.getData() == cell.getData()) { - contains = true; - } - } - for(SudokuCell cc : ccol){ - if(cc.getData() == cell.getData()) { - contains = true; - } - } - //Stop if another cell can hold number - if(!contains) { - restrained = false; - break; - } - } - //Output if success - if(restrained) { - return null; - } - - //// - //Loop to see if the number is constrained to the cell - restrained = true; - for(SudokuCell c : col){ - //Test if its not a valid testing cell - if(c.getData() != 0) { - continue; - } - if(c.getLocation().y == cell.getLocation().y && c.getLocation().x == cell.getLocation().x) { - continue; - } - //Check if cell is eligible to hold number - Set cregion = initialBoard.getRegion(c.getGroupIndex()); - Set crow = initialBoard.getRow(c.getLocation().y); - boolean contains = false; - for(SudokuCell rc : cregion){ - if(rc.getData() == cell.getData()) { - contains = true; - } - } - for(SudokuCell cc : crow){ - if(cc.getData() == cell.getData()) { - contains = true; - } - } - //Stop if another cell can hold number - if(!contains) { - restrained = false; - break; - } - } - //Output if success - if(restrained) { - return null; - } - - //Output fail - return super.getInvalidUseOfRuleMessage() + ": Cell is not forced at this index"; - } - - /** - * 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) { - return null; - } -} \ No newline at end of file +package edu.rpi.legup.puzzle.sudoku.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.sudoku.SudokuBoard; +import edu.rpi.legup.puzzle.sudoku.SudokuCell; +import java.util.Set; + +public class LastCellForNumberDirectRule extends DirectRule { + public LastCellForNumberDirectRule() { + super( + "SUDO-BASC-0002", + "Last Cell for Number", + "This is the only cell open in its group for some number.", + "edu/rpi/legup/images/sudoku/forcedByElimination.png"); + } + + /** + * 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 + */ + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + SudokuBoard initialBoard = (SudokuBoard) transition.getParents().get(0).getBoard(); + SudokuBoard finalBoard = (SudokuBoard) transition.getBoard(); + + SudokuCell cell = (SudokuCell) finalBoard.getPuzzleElement(puzzleElement); + + // Check if empty cell placed + if (cell.getData() == 0) { + return super.getInvalidUseOfRuleMessage() + ": Cell is not forced at this index"; + } + + // Get defaults + Set region = initialBoard.getRegion(cell.getGroupIndex()); + Set row = initialBoard.getRow(cell.getLocation().y); + Set col = initialBoard.getCol(cell.getLocation().x); + + // Check if new cell conflicts group + for (SudokuCell c : region) { + if (c.getData() == cell.getData()) { + return super.getInvalidUseOfRuleMessage() + ": Cell is not forced at this index"; + } + } + for (SudokuCell c : row) { + if (c.getData() == cell.getData()) { + return super.getInvalidUseOfRuleMessage() + ": Cell is not forced at this index"; + } + } + for (SudokuCell c : col) { + if (c.getData() == cell.getData()) { + return super.getInvalidUseOfRuleMessage() + ": Cell is not forced at this index"; + } + } + + // // + // Loop to see if the number is constrained to the cell + boolean restrained = true; + for (SudokuCell c : region) { + // Test if its not a valid testing cell + if (c.getData() != 0) { + continue; + } + if (c.getLocation().y == cell.getLocation().y + && c.getLocation().x == cell.getLocation().x) { + continue; + } + // Check if cell is eligible to hold number + Set crow = initialBoard.getRow(c.getLocation().y); + Set ccol = initialBoard.getCol(c.getLocation().x); + boolean contains = false; + for (SudokuCell rc : crow) { + if (rc.getData() == cell.getData()) { + contains = true; + } + } + for (SudokuCell cc : ccol) { + if (cc.getData() == cell.getData()) { + contains = true; + } + } + // Stop if another cell can hold number + if (!contains) { + restrained = false; + break; + } + } + // Output if success + if (restrained) { + return null; + } + + // // + // Loop to see if the number is constrained to the cell + restrained = true; + for (SudokuCell c : row) { + // Test if its not a valid testing cell + if (c.getData() != 0) { + continue; + } + if (c.getLocation().y == cell.getLocation().y + && c.getLocation().x == cell.getLocation().x) { + continue; + } + // Check if cell is eligible to hold number + Set cregion = initialBoard.getRegion(c.getGroupIndex()); + Set ccol = initialBoard.getCol(c.getLocation().x); + boolean contains = false; + for (SudokuCell rc : cregion) { + if (rc.getData() == cell.getData()) { + contains = true; + } + } + for (SudokuCell cc : ccol) { + if (cc.getData() == cell.getData()) { + contains = true; + } + } + // Stop if another cell can hold number + if (!contains) { + restrained = false; + break; + } + } + // Output if success + if (restrained) { + return null; + } + + // // + // Loop to see if the number is constrained to the cell + restrained = true; + for (SudokuCell c : col) { + // Test if its not a valid testing cell + if (c.getData() != 0) { + continue; + } + if (c.getLocation().y == cell.getLocation().y + && c.getLocation().x == cell.getLocation().x) { + continue; + } + // Check if cell is eligible to hold number + Set cregion = initialBoard.getRegion(c.getGroupIndex()); + Set crow = initialBoard.getRow(c.getLocation().y); + boolean contains = false; + for (SudokuCell rc : cregion) { + if (rc.getData() == cell.getData()) { + contains = true; + } + } + for (SudokuCell cc : crow) { + if (cc.getData() == cell.getData()) { + contains = true; + } + } + // Stop if another cell can hold number + if (!contains) { + restrained = false; + break; + } + } + // Output if success + if (restrained) { + return null; + } + + // Output fail + return super.getInvalidUseOfRuleMessage() + ": Cell is not forced at this index"; + } + + /** + * 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) { + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/LastNumberForCellDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/LastNumberForCellDirectRule.java index 888f000ff..9f6f465dd 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/LastNumberForCellDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/LastNumberForCellDirectRule.java @@ -1,89 +1,94 @@ -package edu.rpi.legup.puzzle.sudoku.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.sudoku.SudokuBoard; -import edu.rpi.legup.puzzle.sudoku.SudokuCell; - -import java.util.HashSet; - -public class LastNumberForCellDirectRule extends DirectRule { - - public LastNumberForCellDirectRule() { - super("SUDO-BASC-0003", "Last Number for Cell", - "This is the only number left that can fit in the cell of a group.", - "edu/rpi/legup/images/sudoku/forcedByDeduction.png"); - } - - /** - * 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 - */ - public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - SudokuBoard initialBoard = (SudokuBoard) transition.getParents().get(0).getBoard(); - SudokuBoard finalBoard = (SudokuBoard) transition.getBoard(); - - //Assign basics - int groupSize = initialBoard.getWidth(); - int groupDim = (int) Math.sqrt(groupSize); - - //Get position info - int index = puzzleElement.getIndex(); - int rowIndex = index / groupSize; - int colIndex = index % groupSize; - int groupNum = (rowIndex / groupDim) * groupDim + (colIndex / groupDim); - - //Create hashset of all numbers - HashSet numbers = new HashSet<>(); - for (int i = 1; i <= groupSize; i++) { - numbers.add(i); - } - - //Run through region, row, col to see contradicitng numbers - for (int i = 0; i < groupSize; i++) { - SudokuCell cell = initialBoard.getCell(groupNum, i % groupDim, i / groupDim); - numbers.remove(cell.getData()); - } - for (int i = 0; i < groupSize; i++) { - SudokuCell cell = initialBoard.getCell(i, rowIndex); - numbers.remove(cell.getData()); - } - for (int i = 0; i < groupSize; i++) { - SudokuCell cell = initialBoard.getCell(colIndex, i); - numbers.remove(cell.getData()); - } - - //Check if plausible - if (numbers.size() > 1) { - return super.getInvalidUseOfRuleMessage() + ": The number at the index is not forced"; - } - else { - if (numbers.size() == 1 && numbers.iterator().next() != finalBoard.getPuzzleElement(puzzleElement).getData()) { - return super.getInvalidUseOfRuleMessage() + ": The number at the index is forced but not correct"; - } - } - if(numbers.toArray(new Integer[1])[0] == puzzleElement.getData()) { - return null; - } - return super.getInvalidUseOfRuleMessage() + ": The number at the index is forced but not correct"; - } - - /** - * 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) { - return null; - } -} +package edu.rpi.legup.puzzle.sudoku.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.sudoku.SudokuBoard; +import edu.rpi.legup.puzzle.sudoku.SudokuCell; +import java.util.HashSet; + +public class LastNumberForCellDirectRule extends DirectRule { + + public LastNumberForCellDirectRule() { + super( + "SUDO-BASC-0003", + "Last Number for Cell", + "This is the only number left that can fit in the cell of a group.", + "edu/rpi/legup/images/sudoku/forcedByDeduction.png"); + } + + /** + * 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 + */ + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + SudokuBoard initialBoard = (SudokuBoard) transition.getParents().get(0).getBoard(); + SudokuBoard finalBoard = (SudokuBoard) transition.getBoard(); + + // Assign basics + int groupSize = initialBoard.getWidth(); + int groupDim = (int) Math.sqrt(groupSize); + + // Get position info + int index = puzzleElement.getIndex(); + int rowIndex = index / groupSize; + int colIndex = index % groupSize; + int groupNum = (rowIndex / groupDim) * groupDim + (colIndex / groupDim); + + // Create hashset of all numbers + HashSet numbers = new HashSet<>(); + for (int i = 1; i <= groupSize; i++) { + numbers.add(i); + } + + // Run through region, row, col to see contradicitng numbers + for (int i = 0; i < groupSize; i++) { + SudokuCell cell = initialBoard.getCell(groupNum, i % groupDim, i / groupDim); + numbers.remove(cell.getData()); + } + for (int i = 0; i < groupSize; i++) { + SudokuCell cell = initialBoard.getCell(i, rowIndex); + numbers.remove(cell.getData()); + } + for (int i = 0; i < groupSize; i++) { + SudokuCell cell = initialBoard.getCell(colIndex, i); + numbers.remove(cell.getData()); + } + + // Check if plausible + if (numbers.size() > 1) { + return super.getInvalidUseOfRuleMessage() + ": The number at the index is not forced"; + } else { + if (numbers.size() == 1 + && numbers.iterator().next() + != finalBoard.getPuzzleElement(puzzleElement).getData()) { + return super.getInvalidUseOfRuleMessage() + + ": The number at the index is forced but not correct"; + } + } + if (numbers.toArray(new Integer[1])[0] == puzzleElement.getData()) { + return null; + } + return super.getInvalidUseOfRuleMessage() + + ": The number at the index is forced but not correct"; + } + + /** + * 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) { + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberColumnContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberColumnContradictionRule.java index 4cf076892..86d2c8dac 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberColumnContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberColumnContradictionRule.java @@ -5,25 +5,27 @@ import edu.rpi.legup.model.rules.ContradictionRule; import edu.rpi.legup.puzzle.sudoku.SudokuBoard; import edu.rpi.legup.puzzle.sudoku.SudokuCell; - import java.util.HashSet; import java.util.Set; public class NoCellForNumberColumnContradictionRule extends ContradictionRule { public NoCellForNumberColumnContradictionRule() { - super("SUDO-CONT-0003", "No Cell for Number (Column)", + super( + "SUDO-CONT-0003", + "No Cell for Number (Column)", "Process of elimination yields no valid numbers for an empty cell in a column.", "edu/rpi/legup/images/sudoku/NoCellForNumberColumn.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) { @@ -42,44 +44,44 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { numbersNotInColumn.add(i); } for (SudokuCell c : col) { - if(c.getData() != 0) { + if (c.getData() != 0) { numbersNotInColumn.remove(c.getData()); } } for (Integer i : numbersNotInColumn) { - //Check if number can be in cell + // Check if number can be in cell boolean canFit = false; - for(SudokuCell c : col){ - if(c.getData() != 0) { + for (SudokuCell c : col) { + if (c.getData() != 0) { continue; } - //Get row and col groups + // Get row and col groups Set region = sudokuBoard.getRow(c.getLocation().y); Set row = sudokuBoard.getCol(c.getLocation().x); - //Check if it alr exists in row or col + // Check if it alr exists in row or col boolean duplicate = false; - for(SudokuCell rc : region) { - if(rc.getData() == i) { + for (SudokuCell rc : region) { + if (rc.getData() == i) { duplicate = true; } } - for(SudokuCell cc : row) { - if(cc.getData() == i) { + for (SudokuCell cc : row) { + if (cc.getData() == i) { duplicate = true; } } - //If there is no duplicate it can exist in the region - if(!duplicate) { + // If there is no duplicate it can exist in the region + if (!duplicate) { canFit = true; break; } } - //If the number can't fit anywhere in region then contradiction - if(!canFit) { + // If the number can't fit anywhere in region then contradiction + if (!canFit) { return null; } } diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberRegionContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberRegionContradictionRule.java index 9923bd207..714395cab 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberRegionContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberRegionContradictionRule.java @@ -5,25 +5,27 @@ import edu.rpi.legup.model.rules.ContradictionRule; import edu.rpi.legup.puzzle.sudoku.SudokuBoard; import edu.rpi.legup.puzzle.sudoku.SudokuCell; - import java.util.HashSet; import java.util.Set; public class NoCellForNumberRegionContradictionRule extends ContradictionRule { public NoCellForNumberRegionContradictionRule() { - super("SUDO-CONT-0001", "No Cell for Number (Region)", + super( + "SUDO-CONT-0001", + "No Cell for Number (Region)", "Process of elimination yields no valid numbers for an empty cell in a region.", "edu/rpi/legup/images/sudoku/NoCellForNumberRegion.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) { @@ -42,44 +44,44 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { numbersNotInRegion.add(i); } for (SudokuCell c : region) { - if(c.getData() != 0) { + if (c.getData() != 0) { numbersNotInRegion.remove(c.getData()); } } for (Integer i : numbersNotInRegion) { - //Check if number can be in cell + // Check if number can be in cell boolean canFit = false; - for(SudokuCell c : region){ - if(c.getData() != 0) { + for (SudokuCell c : region) { + if (c.getData() != 0) { continue; } - //Get row and col groups + // Get row and col groups Set row = sudokuBoard.getRow(c.getLocation().y); Set col = sudokuBoard.getCol(c.getLocation().x); - //Check if it alr exists in row or col + // Check if it alr exists in row or col boolean duplicate = false; - for(SudokuCell rc : row) { - if(rc.getData() == i) { + for (SudokuCell rc : row) { + if (rc.getData() == i) { duplicate = true; } } - for(SudokuCell cc : col) { - if(cc.getData() == i) { + for (SudokuCell cc : col) { + if (cc.getData() == i) { duplicate = true; } } - //If there is no duplicate it can exist in the region - if(!duplicate) { + // If there is no duplicate it can exist in the region + if (!duplicate) { canFit = true; break; } } - //If the number can't fit anywhere in region then contradiction - if(!canFit) { + // If the number can't fit anywhere in region then contradiction + if (!canFit) { return null; } } diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberRowContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberRowContradictionRule.java index 6e8616a9f..e768405fd 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberRowContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberRowContradictionRule.java @@ -5,25 +5,27 @@ import edu.rpi.legup.model.rules.ContradictionRule; import edu.rpi.legup.puzzle.sudoku.SudokuBoard; import edu.rpi.legup.puzzle.sudoku.SudokuCell; - import java.util.HashSet; import java.util.Set; public class NoCellForNumberRowContradictionRule extends ContradictionRule { public NoCellForNumberRowContradictionRule() { - super("SUDO-CONT-0002", "No Cell for Number (Row)", + super( + "SUDO-CONT-0002", + "No Cell for Number (Row)", "Process of elimination yields no valid numbers for an empty cell in a row.", "edu/rpi/legup/images/sudoku/NoCellForNumberRow.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) { @@ -42,44 +44,44 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { numbersNotInRow.add(i); } for (SudokuCell c : row) { - if(c.getData() != 0) { + if (c.getData() != 0) { numbersNotInRow.remove(c.getData()); } } for (Integer i : numbersNotInRow) { - //Check if number can be in cell + // Check if number can be in cell boolean canFit = false; - for(SudokuCell c : row){ - if(c.getData() != 0) { + for (SudokuCell c : row) { + if (c.getData() != 0) { continue; } - //Get row and col groups + // Get row and col groups Set region = sudokuBoard.getRow(c.getLocation().y); Set col = sudokuBoard.getCol(c.getLocation().x); - //Check if it alr exists in row or col + // Check if it alr exists in row or col boolean duplicate = false; - for(SudokuCell rc : region) { - if(rc.getData() == i) { + for (SudokuCell rc : region) { + if (rc.getData() == i) { duplicate = true; } } - for(SudokuCell cc : col) { - if(cc.getData() == i) { + for (SudokuCell cc : col) { + if (cc.getData() == i) { duplicate = true; } } - //If there is no duplicate it can exist in the region - if(!duplicate) { + // If there is no duplicate it can exist in the region + if (!duplicate) { canFit = true; break; } } - //If the number can't fit anywhere in region then contradiction - if(!canFit) { + // If the number can't fit anywhere in region then contradiction + if (!canFit) { return null; } } diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoNumberForCellContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoNumberForCellContradictionRule.java index b4e4e7a5f..a4646c45e 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoNumberForCellContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoNumberForCellContradictionRule.java @@ -11,8 +11,10 @@ public class NoNumberForCellContradictionRule extends ContradictionRule { public NoNumberForCellContradictionRule() { - super("SUDO-CONT-0004", "No Number for Cell", - "Process of elimination yields no valid numbers for an empty cell.", + super( + "SUDO-CONT-0004", + "No Number for Cell", + "Process of elimination yields no valid numbers for an empty cell.", "edu/rpi/legup/images/sudoku/NoSolution.png"); } @@ -39,19 +41,19 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { Set row = sudokuBoard.getRow(cell.getLocation().y); Set col = sudokuBoard.getCol(cell.getLocation().x); Set solution = new HashSet<>(); - for(SudokuCell s : region) { + for (SudokuCell s : region) { solution.add(s.getData()); } - for(SudokuCell s : row) { + for (SudokuCell s : row) { solution.add(s.getData()); } - for(SudokuCell s : col) { + for (SudokuCell s : col) { solution.add(s.getData()); } solution.remove(0); - if(solution.size() == 9) { + if (solution.size() == 9) { return null; } diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberColumnCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberColumnCaseRule.java index b6ea1be21..9c4045fbb 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberColumnCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberColumnCaseRule.java @@ -9,19 +9,21 @@ import edu.rpi.legup.puzzle.sudoku.ModelSudokuBoard; import edu.rpi.legup.puzzle.sudoku.SudokuBoard; import edu.rpi.legup.puzzle.sudoku.SudokuCell; - import java.util.ArrayList; import java.util.Set; public class PossibleCellsForNumberColumnCaseRule extends CaseRule { - //Board math for translating indexes to numbers + // Board math for translating indexes to numbers private ModelSudokuBoard model = new ModelSudokuBoard(); - //Old board for caseBoard reference + // Old board for caseBoard reference private SudokuBoard lagBoard; + public PossibleCellsForNumberColumnCaseRule() { - super("SUDO-CASE-0004", "Possible Cells for Number - Column", + super( + "SUDO-CASE-0004", + "Possible Cells for Number - Column", "An empty cell has a limited set of possible numbers that can fill it.", "edu/rpi/legup/images/sudoku/possible_cells_number_column.png"); } @@ -38,13 +40,13 @@ public String checkRuleRaw(TreeTransition transition) { } /** - * 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) { @@ -66,7 +68,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 */ @@ -78,20 +80,21 @@ public ArrayList getCases(Board board, PuzzleElement puzzleElement) { /** * 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 - * @param value value that the rule will be applied from - * @param groupType group type + * @param value value that the rule will be applied from + * @param groupType group type * @return a list of elements the specified could be */ - public ArrayList getCases(Board board, PuzzleElement puzzleElement, int value, GroupType groupType) { + public ArrayList getCases( + Board board, PuzzleElement puzzleElement, int value, GroupType groupType) { ArrayList cases = new ArrayList<>(); SudokuBoard sudokuBoard = lagBoard; SudokuCell sourceCell = (SudokuCell) puzzleElement; Set group = sudokuBoard.getCol(sourceCell.getLocation().x); - for (SudokuCell cell : group){ - if(cell.getData() == 0){ + for (SudokuCell cell : group) { + if (cell.getData() == 0) { Board newCase = sudokuBoard.copy(); PuzzleElement element = newCase.getPuzzleElement(cell); element.setData(model.getModelColumnNumbers(sourceCell.getIndex())); diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberRegionCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberRegionCaseRule.java index f12a9fb0b..43f27e888 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberRegionCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberRegionCaseRule.java @@ -6,19 +6,21 @@ import edu.rpi.legup.model.rules.CaseRule; import edu.rpi.legup.model.tree.TreeTransition; import edu.rpi.legup.puzzle.sudoku.*; - import java.util.ArrayList; import java.util.Set; public class PossibleCellsForNumberRegionCaseRule extends CaseRule { - //Board math for translating indexes to numbers + // Board math for translating indexes to numbers private ModelSudokuBoard model = new ModelSudokuBoard(); - //Old board for caseBoard reference + // Old board for caseBoard reference private SudokuBoard lagBoard; + public PossibleCellsForNumberRegionCaseRule() { - super("SUDO-CASE-0002", "Possible Cells for Number - Region", + super( + "SUDO-CASE-0002", + "Possible Cells for Number - Region", "An empty cell has a limited set of possible numbers that can fill it.", "edu/rpi/legup/images/sudoku/possible_cells_number_region.png"); } @@ -35,13 +37,13 @@ public String checkRuleRaw(TreeTransition transition) { } /** - * 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) { @@ -63,7 +65,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 */ @@ -75,20 +77,21 @@ public ArrayList getCases(Board board, PuzzleElement puzzleElement) { /** * 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 - * @param value value that the rule will be applied from - * @param groupType group type + * @param value value that the rule will be applied from + * @param groupType group type * @return a list of elements the specified could be */ - public ArrayList getCases(Board board, PuzzleElement puzzleElement, int value, GroupType groupType) { + public ArrayList getCases( + Board board, PuzzleElement puzzleElement, int value, GroupType groupType) { ArrayList cases = new ArrayList<>(); SudokuBoard sudokuBoard = lagBoard; SudokuCell sourceCell = (SudokuCell) puzzleElement; Set group = sudokuBoard.getRegion(sourceCell.getGroupIndex()); - for (SudokuCell cell : group){ - if(cell.getData() == 0){ + for (SudokuCell cell : group) { + if (cell.getData() == 0) { Board newCase = sudokuBoard.copy(); PuzzleElement element = newCase.getPuzzleElement(cell); element.setData(model.getModelRegionNumbers(sourceCell.getIndex())); diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberRowCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberRowCaseRule.java index 60e866523..5308b84fa 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberRowCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberRowCaseRule.java @@ -14,13 +14,16 @@ public class PossibleCellsForNumberRowCaseRule extends CaseRule { - //Board math for translating indexes to numbers + // Board math for translating indexes to numbers private ModelSudokuBoard model = new ModelSudokuBoard(); - //Old board for caseBoard reference + // Old board for caseBoard reference private SudokuBoard lagBoard; + public PossibleCellsForNumberRowCaseRule() { - super("SUDO-CASE-0003", "Possible Cells for Number - Row", + super( + "SUDO-CASE-0003", + "Possible Cells for Number - Row", "An empty cell has a limited set of possible numbers that can fill it.", "edu/rpi/legup/images/sudoku/possible_cells_number_row.png"); } @@ -77,20 +80,21 @@ public ArrayList getCases(Board board, PuzzleElement puzzleElement) { /** * 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 - * @param value value that the rule will be applied from - * @param groupType group type + * @param value value that the rule will be applied from + * @param groupType group type * @return a list of elements the specified could be */ - public ArrayList getCases(Board board, PuzzleElement puzzleElement, int value, GroupType groupType) { + public ArrayList getCases( + Board board, PuzzleElement puzzleElement, int value, GroupType groupType) { ArrayList cases = new ArrayList<>(); SudokuBoard sudokuBoard = lagBoard; SudokuCell sourceCell = (SudokuCell) puzzleElement; Set group = sudokuBoard.getRow(sourceCell.getLocation().y); - for (SudokuCell cell : group){ - if(cell.getData() == 0){ + for (SudokuCell cell : group) { + if (cell.getData() == 0) { Board newCase = sudokuBoard.copy(); PuzzleElement element = newCase.getPuzzleElement(cell); element.setData(model.getModelRowNumbers(sourceCell.getIndex())); diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleNumbersForCellCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleNumbersForCellCaseRule.java index e5d22f9a6..fbdc23b65 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleNumbersForCellCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleNumbersForCellCaseRule.java @@ -8,12 +8,13 @@ import edu.rpi.legup.puzzle.sudoku.*; import java.util.ArrayList; import java.util.List; -import java.util.Set; public class PossibleNumbersForCellCaseRule extends CaseRule { public PossibleNumbersForCellCaseRule() { - super("SUDO-CASE-0001", "Possible Numbers for Cell", + super( + "SUDO-CASE-0001", + "Possible Numbers for Cell", "An empty cell has a limited set of possible numbers that can fill it.", "edu/rpi/legup/images/sudoku/PossibleValues.png"); } @@ -54,6 +55,7 @@ public CaseBoard getCaseBoard(Board board) { } return caseBoard; } + /** * Gets the possible cases at a specific location based on this case rule * diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/RepeatedNumberContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/RepeatedNumberContradictionRule.java index d613edf59..4dcf95d63 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/RepeatedNumberContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/RepeatedNumberContradictionRule.java @@ -11,7 +11,9 @@ public class RepeatedNumberContradictionRule extends ContradictionRule { public RepeatedNumberContradictionRule() { - super("SUDO-CONT-0005", "Repeated Numbers", + super( + "SUDO-CONT-0005", + "Repeated Numbers", "Two identical numbers are placed in the same group.", "edu/rpi/legup/images/sudoku/RepeatedNumber.png"); } @@ -27,12 +29,12 @@ public RepeatedNumberContradictionRule() { */ @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { - //Get board to check + // Get board to check SudokuBoard sudokuBoard = (SudokuBoard) board; - //Loop all group indexes - for(int i = 0; i < 9; i++) { - //Get regions and sets to check duplicates + // Loop all group indexes + for (int i = 0; i < 9; i++) { + // Get regions and sets to check duplicates Set region = sudokuBoard.getRegion(i); Set regionDup = new HashSet<>(); @@ -42,7 +44,7 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { Set col = sudokuBoard.getCol(i); Set colDup = new HashSet<>(); - //Check for non zero duplicates to trigger contradiction + // Check for non zero duplicates to trigger contradiction for (SudokuCell c : region) { if (c.getData() == 0) { continue; diff --git a/src/test/java/legup/TestRunner.java b/src/test/java/legup/TestRunner.java index c8725b48d..de674c348 100644 --- a/src/test/java/legup/TestRunner.java +++ b/src/test/java/legup/TestRunner.java @@ -6,7 +6,6 @@ import puzzles.battleship.rules.*; import puzzles.lightup.rules.*; import puzzles.nurikabe.rules.*; -import puzzles.sudoku.rules.LastNumberForCellDirectRuleRegionTest; import puzzles.treetent.rules.*; /** This class runs all of the tests for the project without needing to run build scripts. */ diff --git a/src/test/java/puzzles/sudoku/rules/LastNumberForCellDirectRuleRegionTest.java b/src/test/java/puzzles/sudoku/rules/LastNumberForCellDirectRuleRegionTest.java index 28406c1ab..f27f38d8a 100644 --- a/src/test/java/puzzles/sudoku/rules/LastNumberForCellDirectRuleRegionTest.java +++ b/src/test/java/puzzles/sudoku/rules/LastNumberForCellDirectRuleRegionTest.java @@ -16,76 +16,81 @@ public class LastNumberForCellDirectRuleRegionTest { private static final LastNumberForCellDirectRule RULE = new LastNumberForCellDirectRule(); private static Sudoku sudoku; + @BeforeClass public static void setUp() { MockGameBoardFacade.getInstance(); sudoku = new Sudoku(); } + @Test public void LastNumberForCellDirectRule_FullRegionTest() throws InvalidFileFormatException { - //Import board and create transition - TestUtilities.importTestBoard("puzzles/sudoku/rules/LastNumberForCellDirectRule/FullRegion", sudoku); + // Import board and create transition + TestUtilities.importTestBoard( + "puzzles/sudoku/rules/LastNumberForCellDirectRule/FullRegion", sudoku); TreeNode rootNode = sudoku.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); - //Loop all numbers at point - for(int i = 1; i < 10; i++){ - //Reset board + // Loop all numbers at point + for (int i = 1; i < 10; i++) { + // Reset board SudokuBoard board = (SudokuBoard) transition.getBoard(); - //Set cell + // Set cell SudokuCell cell1 = board.getCell(2, 5); cell1.setData(i); board.addModifiedData(cell1); - //Test the case - if(i == 9) { + // Test the case + if (i == 9) { Assert.assertNull(RULE.checkRuleAt(transition, cell1)); } else { Assert.assertNotNull(RULE.checkRuleAt(transition, cell1)); } } - //Import Board and create transition - TestUtilities.importTestBoard("puzzles/sudoku/rules/LastNumberForCellDirectRule/FullRow", sudoku); + // Import Board and create transition + TestUtilities.importTestBoard( + "puzzles/sudoku/rules/LastNumberForCellDirectRule/FullRow", sudoku); rootNode = sudoku.getTree().getRootNode(); transition = rootNode.getChildren().get(0); transition.setRule(RULE); - //Loop all numbers at point - for(int i = 1; i < 10; i++){ - //Reset board + // Loop all numbers at point + for (int i = 1; i < 10; i++) { + // Reset board SudokuBoard board = (SudokuBoard) transition.getBoard(); - //Set cell + // Set cell SudokuCell cell = board.getCell(4, 4); cell.setData(i); board.addModifiedData(cell); - //Test the case - if(i == 5) { + // Test the case + if (i == 5) { Assert.assertNull(RULE.checkRuleAt(transition, cell)); } else { Assert.assertNotNull(RULE.checkRuleAt(transition, cell)); } } - //Import Board and create transition - TestUtilities.importTestBoard("puzzles/sudoku/rules/LastNumberForCellDirectRule/FullMixed", sudoku); + // Import Board and create transition + TestUtilities.importTestBoard( + "puzzles/sudoku/rules/LastNumberForCellDirectRule/FullMixed", sudoku); rootNode = sudoku.getTree().getRootNode(); transition = rootNode.getChildren().get(0); transition.setRule(RULE); - //Loop all numbers at point - for(int i = 1; i < 10; i++){ - //Reset board + // Loop all numbers at point + for (int i = 1; i < 10; i++) { + // Reset board SudokuBoard board = (SudokuBoard) transition.getBoard(); - //Set cell + // Set cell SudokuCell cell = board.getCell(5, 3); cell.setData(i); board.addModifiedData(cell); - //Test the case - if(i == 2) { + // Test the case + if (i == 2) { Assert.assertNull(RULE.checkRuleAt(transition, cell)); } else { Assert.assertNotNull(RULE.checkRuleAt(transition, cell)); diff --git a/src/test/java/puzzles/sudoku/rules/RepeatedNumberContradictionRuleTest.java b/src/test/java/puzzles/sudoku/rules/RepeatedNumberContradictionRuleTest.java index 3a65fbd47..704167a29 100644 --- a/src/test/java/puzzles/sudoku/rules/RepeatedNumberContradictionRuleTest.java +++ b/src/test/java/puzzles/sudoku/rules/RepeatedNumberContradictionRuleTest.java @@ -14,69 +14,75 @@ import org.junit.Test; public class RepeatedNumberContradictionRuleTest { - private static final RepeatedNumberContradictionRule RULE = new RepeatedNumberContradictionRule(); + private static final RepeatedNumberContradictionRule RULE = + new RepeatedNumberContradictionRule(); private static Sudoku sudoku; + @BeforeClass public static void setUp() { MockGameBoardFacade.getInstance(); sudoku = new Sudoku(); } + @Test public void RepeatedNumberContradictionRule_GlobalTest() throws InvalidFileFormatException { - //Import board and create transition - TestUtilities.importTestBoard("puzzles/sudoku/rules/RepeatedNumberContradictionRule/BlankBoard7", sudoku); + // Import board and create transition + TestUtilities.importTestBoard( + "puzzles/sudoku/rules/RepeatedNumberContradictionRule/BlankBoard7", sudoku); TreeNode rootNode = sudoku.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); - //Loop through every cell - for(int i = 0; i < 81; i++){ - //Reset board + // Loop through every cell + for (int i = 0; i < 81; i++) { + // Reset board SudokuBoard board = (SudokuBoard) transition.getBoard(); - //Set cell + // Set cell int x = i / 9; int y = i % 9; - if(x == 0 && y == 0) { + if (x == 0 && y == 0) { continue; } SudokuCell cell = board.getCell(x, y); cell.setData(7); - //Test the case - if(x == 0 || y == 0 || (x < 3 && y < 3)){ + // Test the case + if (x == 0 || y == 0 || (x < 3 && y < 3)) { Assert.assertNull(RULE.checkRuleAt(transition, cell)); } else { Assert.assertNotNull(RULE.checkRuleAt(transition, cell)); } cell.setData(0); } - //Import board and create transition - TestUtilities.importTestBoard("puzzles/sudoku/rules/RepeatedNumberContradictionRule/BlankBoard4", sudoku); + // Import board and create transition + TestUtilities.importTestBoard( + "puzzles/sudoku/rules/RepeatedNumberContradictionRule/BlankBoard4", sudoku); rootNode = sudoku.getTree().getRootNode(); transition = rootNode.getChildren().get(0); transition.setRule(RULE); - //Loop through every cell - for(int i = 0; i < 81; i++){ - //Reset board + // Loop through every cell + for (int i = 0; i < 81; i++) { + // Reset board SudokuBoard board = (SudokuBoard) transition.getBoard(); - //Set cell + // Set cell int x = i / 9; int y = i % 9; - if((x == 3 && y == 0) || (x == 6 && y == 8)) { + if ((x == 3 && y == 0) || (x == 6 && y == 8)) { continue; } SudokuCell cell = board.getCell(x, y); cell.setData(4); - //Test the case - if((x == 3 || y == 0 || x == 6 || y == 8) || (x > 2 && x < 6 && y < 3) || (x > 5 && y > 5)){ + // Test the case + if ((x == 3 || y == 0 || x == 6 || y == 8) + || (x > 2 && x < 6 && y < 3) + || (x > 5 && y > 5)) { Assert.assertNull(RULE.checkRuleAt(transition, cell)); } else { Assert.assertNotNull(RULE.checkRuleAt(transition, cell)); } cell.setData(0); } - } } From 6fe87682bc5d4c15e7aa666837ab9a8378f68407 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Tue, 16 Apr 2024 17:11:41 -0400 Subject: [PATCH 097/258] deleted blank file --- puzzles files/binary/6x6 easy/blank | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 puzzles files/binary/6x6 easy/blank diff --git a/puzzles files/binary/6x6 easy/blank b/puzzles files/binary/6x6 easy/blank deleted file mode 100644 index 006528e16..000000000 --- a/puzzles files/binary/6x6 easy/blank +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file From 7c95d5f7c1a3ee4780be9286f9c7868a27a70ab2 Mon Sep 17 00:00:00 2001 From: kchiu1 <152306707+kchiu1@users.noreply.github.com> Date: Tue, 16 Apr 2024 17:15:29 -0400 Subject: [PATCH 098/258] Revert "Merge branch 'dev' into sudoku" This reverts commit 63de212ff60000632191e1641679a81fedec9c81, reversing changes made to 31c3ead782ad72634e4dca03724aa46e5e51262c. --- bin/main/edu/rpi/legup/legup/config | 6 +- .../5x5 Star Battle 1 star Normal 1.xml | 53 ---- .../6x6 Star Battle 1star Normal1.xml | 68 ----- .../6x6 Star Battle 1star Normal2.xml | 68 ----- .../6x6 StarBattle 1star Normal3.xml | 68 ----- .../7x7 Star Battle 1star Hard1.xml | 85 ------- .../7x7 Star Battle 1star Normal.xml | 85 ------- .../7x7 Star Battle 1star Normal1.xml | 85 ------- .../7x7 Star Battle 1star Normal2.xml | 85 ------- .../8x8 Star Battle 1star Normal1.xml | 105 -------- .../8x8 Star Battle 1star Normal2.xml | 104 -------- .../8x8 Star Battle 1star Normal3.xml | 104 -------- .../rpi/legup/model/gameboard/GridRegion.java | 16 +- .../legup/puzzle/starbattle/StarBattle.java | 35 --- .../puzzle/starbattle/StarBattleBoard.java | 110 -------- .../puzzle/starbattle/StarBattleCell.java | 88 ------- .../starbattle/StarBattleCellFactory.java | 66 ----- .../puzzle/starbattle/StarBattleCellType.java | 12 - .../starbattle/StarBattleController.java | 36 --- .../starbattle/StarBattleElementView.java | 41 --- .../puzzle/starbattle/StarBattleExporter.java | 33 --- .../puzzle/starbattle/StarBattleImporter.java | 103 -------- .../puzzle/starbattle/StarBattleRegion.java | 26 -- .../puzzle/starbattle/StarBattleView.java | 43 ---- .../rpi/legup/puzzle/starbattle/allfiles.txt | 235 ------------------ .../puzzle/starbattle/elements/BlackTile.java | 9 - .../puzzle/starbattle/elements/StarTile.java | 9 - .../starbattle/elements/UnknownTile.java | 9 - .../puzzle/starbattle/elements/WhiteTile.java | 10 - .../starbattle/rules/BlackoutDirectRule.java | 64 ----- .../rules/ClashingOrbitContradictionRule.java | 60 ----- .../rules/ColumnsWithinRegionsDirectRule.java | 94 ------- .../rules/ColumnsWithinRowsDirectRule.java | 97 -------- .../rules/FinishWithStarsDirectRule.java | 63 ----- .../rules/RegionsWithinColumnsDirectRule.java | 43 ---- .../rules/RegionsWithinRowsDirectRule.java | 44 ---- .../rules/RowsWithinColumnsDirectRule.java | 51 ---- .../rules/RowsWithinRegionsDirectRule.java | 94 ------- .../starbattle/rules/StarOrEmptyCaseRule.java | 103 -------- .../rules/SurroundStarDirectRule.java | 63 ----- .../rules/TooFewStarsContradictionRule.java | 64 ----- .../rules/TooManyStarsContradictionRule.java | 114 --------- .../rules/starbattle_reference_sheet.txt | 19 -- .../edu/rpi/legup/utility/LegupUtils.java | 11 +- .../legup/images/starbattle/UnknownTile.png | Bin 9733 -> 0 bytes .../edu/rpi/legup/images/starbattle/black.gif | Bin 856 -> 0 bytes .../starbattle/cases/StarOrEmptyCaseRule.png | Bin 4437 -> 0 bytes .../ClashingOrbitContradictionRule.png | Bin 5135 -> 0 bytes .../TooFewStarsContradictionRule.png | Bin 3218 -> 0 bytes .../TooManyStarsContradictionRule.png | Bin 6199 -> 0 bytes .../edu/rpi/legup/images/starbattle/empty.gif | Bin 857 -> 0 bytes .../starbattle/rules/BlackOutDirectRule.png | Bin 4717 -> 0 bytes .../rules/ColumnsWithinRegionsDirectRule.png | Bin 6456 -> 0 bytes .../rules/ColumnsWithinRowsDirectRule.png | Bin 5331 -> 0 bytes .../rules/FinishWithStarDirectRule.png | Bin 4326 -> 0 bytes .../rules/RegionsWithinColumnsDirectRule.png | Bin 6402 -> 0 bytes .../rules/RegionsWithinRowsDirectRule.png | Bin 6269 -> 0 bytes .../rules/RowsWithinColumnsDirectRule.png | Bin 5117 -> 0 bytes .../rules/RowsWithinRegionsDirectRule.png | Bin 6477 -> 0 bytes .../images/starbattle/rules/SurroundStar.png | Bin 5102 -> 0 bytes .../edu/rpi/legup/images/starbattle/star.gif | Bin 545 -> 0 bytes .../edu/rpi/legup/images/starbattle/white.gif | Bin 9700 -> 0 bytes src/main/resources/edu/rpi/legup/legup/config | 6 +- .../rules/BlackoutDirectRuleTest.java | 69 ----- .../BlackoutDirectRule/ColumnBlackout | 40 --- .../BlackoutDirectRule/RegionBlackout | 36 --- .../BlackoutDirectRule/RowBlackout | 36 --- 67 files changed, 14 insertions(+), 2954 deletions(-) delete mode 100644 puzzles files/starbattle/5x5 Star Battle 1 star Normal/5x5 Star Battle 1 star Normal 1.xml delete mode 100644 puzzles files/starbattle/6x6 Star Battle 1 star Normal/6x6 Star Battle 1star Normal1.xml delete mode 100644 puzzles files/starbattle/6x6 Star Battle 1 star Normal/6x6 Star Battle 1star Normal2.xml delete mode 100644 puzzles files/starbattle/6x6 Star Battle 1 star Normal/6x6 StarBattle 1star Normal3.xml delete mode 100644 puzzles files/starbattle/7x7 Star Battle 1 star Hard/7x7 Star Battle 1star Hard1.xml delete mode 100644 puzzles files/starbattle/7x7 Star Battle 1 star Normal/7x7 Star Battle 1star Normal.xml delete mode 100644 puzzles files/starbattle/7x7 Star Battle 1 star Normal/7x7 Star Battle 1star Normal1.xml delete mode 100644 puzzles files/starbattle/7x7 Star Battle 1 star Normal/7x7 Star Battle 1star Normal2.xml delete mode 100644 puzzles files/starbattle/8x8 Star Battle 1 star Normal/8x8 Star Battle 1star Normal1.xml delete mode 100644 puzzles files/starbattle/8x8 Star Battle 1 star Normal/8x8 Star Battle 1star Normal2.xml delete mode 100644 puzzles files/starbattle/8x8 Star Battle 1 star Normal/8x8 Star Battle 1star Normal3.xml delete mode 100644 src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattle.java delete mode 100644 src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleBoard.java delete mode 100644 src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleCell.java delete mode 100644 src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleCellFactory.java delete mode 100644 src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleCellType.java delete mode 100644 src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleController.java delete mode 100644 src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleElementView.java delete mode 100644 src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleExporter.java delete mode 100644 src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleImporter.java delete mode 100644 src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleRegion.java delete mode 100644 src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleView.java delete mode 100644 src/main/java/edu/rpi/legup/puzzle/starbattle/allfiles.txt delete mode 100644 src/main/java/edu/rpi/legup/puzzle/starbattle/elements/BlackTile.java delete mode 100644 src/main/java/edu/rpi/legup/puzzle/starbattle/elements/StarTile.java delete mode 100644 src/main/java/edu/rpi/legup/puzzle/starbattle/elements/UnknownTile.java delete mode 100644 src/main/java/edu/rpi/legup/puzzle/starbattle/elements/WhiteTile.java delete mode 100644 src/main/java/edu/rpi/legup/puzzle/starbattle/rules/BlackoutDirectRule.java delete mode 100644 src/main/java/edu/rpi/legup/puzzle/starbattle/rules/ClashingOrbitContradictionRule.java delete mode 100644 src/main/java/edu/rpi/legup/puzzle/starbattle/rules/ColumnsWithinRegionsDirectRule.java delete mode 100644 src/main/java/edu/rpi/legup/puzzle/starbattle/rules/ColumnsWithinRowsDirectRule.java delete mode 100644 src/main/java/edu/rpi/legup/puzzle/starbattle/rules/FinishWithStarsDirectRule.java delete mode 100644 src/main/java/edu/rpi/legup/puzzle/starbattle/rules/RegionsWithinColumnsDirectRule.java delete mode 100644 src/main/java/edu/rpi/legup/puzzle/starbattle/rules/RegionsWithinRowsDirectRule.java delete mode 100644 src/main/java/edu/rpi/legup/puzzle/starbattle/rules/RowsWithinColumnsDirectRule.java delete mode 100644 src/main/java/edu/rpi/legup/puzzle/starbattle/rules/RowsWithinRegionsDirectRule.java delete mode 100644 src/main/java/edu/rpi/legup/puzzle/starbattle/rules/StarOrEmptyCaseRule.java delete mode 100644 src/main/java/edu/rpi/legup/puzzle/starbattle/rules/SurroundStarDirectRule.java delete mode 100644 src/main/java/edu/rpi/legup/puzzle/starbattle/rules/TooFewStarsContradictionRule.java delete mode 100644 src/main/java/edu/rpi/legup/puzzle/starbattle/rules/TooManyStarsContradictionRule.java delete mode 100644 src/main/java/edu/rpi/legup/puzzle/starbattle/rules/starbattle_reference_sheet.txt delete mode 100644 src/main/resources/edu/rpi/legup/images/starbattle/UnknownTile.png delete mode 100644 src/main/resources/edu/rpi/legup/images/starbattle/black.gif delete mode 100644 src/main/resources/edu/rpi/legup/images/starbattle/cases/StarOrEmptyCaseRule.png delete mode 100644 src/main/resources/edu/rpi/legup/images/starbattle/contradictions/ClashingOrbitContradictionRule.png delete mode 100644 src/main/resources/edu/rpi/legup/images/starbattle/contradictions/TooFewStarsContradictionRule.png delete mode 100644 src/main/resources/edu/rpi/legup/images/starbattle/contradictions/TooManyStarsContradictionRule.png delete mode 100644 src/main/resources/edu/rpi/legup/images/starbattle/empty.gif delete mode 100644 src/main/resources/edu/rpi/legup/images/starbattle/rules/BlackOutDirectRule.png delete mode 100644 src/main/resources/edu/rpi/legup/images/starbattle/rules/ColumnsWithinRegionsDirectRule.png delete mode 100644 src/main/resources/edu/rpi/legup/images/starbattle/rules/ColumnsWithinRowsDirectRule.png delete mode 100644 src/main/resources/edu/rpi/legup/images/starbattle/rules/FinishWithStarDirectRule.png delete mode 100644 src/main/resources/edu/rpi/legup/images/starbattle/rules/RegionsWithinColumnsDirectRule.png delete mode 100644 src/main/resources/edu/rpi/legup/images/starbattle/rules/RegionsWithinRowsDirectRule.png delete mode 100644 src/main/resources/edu/rpi/legup/images/starbattle/rules/RowsWithinColumnsDirectRule.png delete mode 100644 src/main/resources/edu/rpi/legup/images/starbattle/rules/RowsWithinRegionsDirectRule.png delete mode 100644 src/main/resources/edu/rpi/legup/images/starbattle/rules/SurroundStar.png delete mode 100644 src/main/resources/edu/rpi/legup/images/starbattle/star.gif delete mode 100644 src/main/resources/edu/rpi/legup/images/starbattle/white.gif delete mode 100644 src/test/java/puzzles/starbattle/rules/BlackoutDirectRuleTest.java delete mode 100644 src/test/resources/puzzles/starbattle.rules/BlackoutDirectRule/ColumnBlackout delete mode 100644 src/test/resources/puzzles/starbattle.rules/BlackoutDirectRule/RegionBlackout delete mode 100644 src/test/resources/puzzles/starbattle.rules/BlackoutDirectRule/RowBlackout diff --git a/bin/main/edu/rpi/legup/legup/config b/bin/main/edu/rpi/legup/legup/config index 4aef6de60..ccd4f5be3 100644 --- a/bin/main/edu/rpi/legup/legup/config +++ b/bin/main/edu/rpi/legup/legup/config @@ -31,10 +31,6 @@ - + fileCreationDisabled="false"/> diff --git a/puzzles files/starbattle/5x5 Star Battle 1 star Normal/5x5 Star Battle 1 star Normal 1.xml b/puzzles files/starbattle/5x5 Star Battle 1 star Normal/5x5 Star Battle 1 star Normal 1.xml deleted file mode 100644 index b86e16ff2..000000000 --- a/puzzles files/starbattle/5x5 Star Battle 1 star Normal/5x5 Star Battle 1 star Normal 1.xml +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/puzzles files/starbattle/6x6 Star Battle 1 star Normal/6x6 Star Battle 1star Normal1.xml b/puzzles files/starbattle/6x6 Star Battle 1 star Normal/6x6 Star Battle 1star Normal1.xml deleted file mode 100644 index 110dd9abe..000000000 --- a/puzzles files/starbattle/6x6 Star Battle 1 star Normal/6x6 Star Battle 1star Normal1.xml +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/puzzles files/starbattle/6x6 Star Battle 1 star Normal/6x6 Star Battle 1star Normal2.xml b/puzzles files/starbattle/6x6 Star Battle 1 star Normal/6x6 Star Battle 1star Normal2.xml deleted file mode 100644 index 49efeba59..000000000 --- a/puzzles files/starbattle/6x6 Star Battle 1 star Normal/6x6 Star Battle 1star Normal2.xml +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/puzzles files/starbattle/6x6 Star Battle 1 star Normal/6x6 StarBattle 1star Normal3.xml b/puzzles files/starbattle/6x6 Star Battle 1 star Normal/6x6 StarBattle 1star Normal3.xml deleted file mode 100644 index 855943612..000000000 --- a/puzzles files/starbattle/6x6 Star Battle 1 star Normal/6x6 StarBattle 1star Normal3.xml +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/puzzles files/starbattle/7x7 Star Battle 1 star Hard/7x7 Star Battle 1star Hard1.xml b/puzzles files/starbattle/7x7 Star Battle 1 star Hard/7x7 Star Battle 1star Hard1.xml deleted file mode 100644 index c1d7770f6..000000000 --- a/puzzles files/starbattle/7x7 Star Battle 1 star Hard/7x7 Star Battle 1star Hard1.xml +++ /dev/null @@ -1,85 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/puzzles files/starbattle/7x7 Star Battle 1 star Normal/7x7 Star Battle 1star Normal.xml b/puzzles files/starbattle/7x7 Star Battle 1 star Normal/7x7 Star Battle 1star Normal.xml deleted file mode 100644 index cab0a0a5e..000000000 --- a/puzzles files/starbattle/7x7 Star Battle 1 star Normal/7x7 Star Battle 1star Normal.xml +++ /dev/null @@ -1,85 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/puzzles files/starbattle/7x7 Star Battle 1 star Normal/7x7 Star Battle 1star Normal1.xml b/puzzles files/starbattle/7x7 Star Battle 1 star Normal/7x7 Star Battle 1star Normal1.xml deleted file mode 100644 index 70b81e376..000000000 --- a/puzzles files/starbattle/7x7 Star Battle 1 star Normal/7x7 Star Battle 1star Normal1.xml +++ /dev/null @@ -1,85 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/puzzles files/starbattle/7x7 Star Battle 1 star Normal/7x7 Star Battle 1star Normal2.xml b/puzzles files/starbattle/7x7 Star Battle 1 star Normal/7x7 Star Battle 1star Normal2.xml deleted file mode 100644 index c541ece06..000000000 --- a/puzzles files/starbattle/7x7 Star Battle 1 star Normal/7x7 Star Battle 1star Normal2.xml +++ /dev/null @@ -1,85 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/puzzles files/starbattle/8x8 Star Battle 1 star Normal/8x8 Star Battle 1star Normal1.xml b/puzzles files/starbattle/8x8 Star Battle 1 star Normal/8x8 Star Battle 1star Normal1.xml deleted file mode 100644 index 02dd5d6c0..000000000 --- a/puzzles files/starbattle/8x8 Star Battle 1 star Normal/8x8 Star Battle 1star Normal1.xml +++ /dev/null @@ -1,105 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/puzzles files/starbattle/8x8 Star Battle 1 star Normal/8x8 Star Battle 1star Normal2.xml b/puzzles files/starbattle/8x8 Star Battle 1 star Normal/8x8 Star Battle 1star Normal2.xml deleted file mode 100644 index 0df84ef62..000000000 --- a/puzzles files/starbattle/8x8 Star Battle 1 star Normal/8x8 Star Battle 1star Normal2.xml +++ /dev/null @@ -1,104 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/puzzles files/starbattle/8x8 Star Battle 1 star Normal/8x8 Star Battle 1star Normal3.xml b/puzzles files/starbattle/8x8 Star Battle 1 star Normal/8x8 Star Battle 1star Normal3.xml deleted file mode 100644 index 725c91d7f..000000000 --- a/puzzles files/starbattle/8x8 Star Battle 1 star Normal/8x8 Star Battle 1star Normal3.xml +++ /dev/null @@ -1,104 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file 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/starbattle/StarBattle.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattle.java deleted file mode 100644 index 760fa88b2..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattle.java +++ /dev/null @@ -1,35 +0,0 @@ -package edu.rpi.legup.puzzle.starbattle; -import edu.rpi.legup.model.Puzzle; -import edu.rpi.legup.model.gameboard.Board; - -public class StarBattle extends Puzzle { - public StarBattle() { - super(); - this.name = "StarBattle"; - - this.importer = new StarBattleImporter(this); - this.exporter = new StarBattleExporter(this); - - this.factory = new StarBattleCellFactory(); - } - - @Override - public void initializeView() { - boardView = new StarBattleView((StarBattleBoard) currentBoard); - addBoardListener(boardView); - } - - @Override - public Board generatePuzzle(int difficulty) { - return null; - } - - @Override - public boolean isBoardComplete(Board board) { - return true; - } - - @Override - 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 deleted file mode 100644 index ce04f31a6..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleBoard.java +++ /dev/null @@ -1,110 +0,0 @@ -package edu.rpi.legup.puzzle.starbattle; - -import java.util.*; - -import edu.rpi.legup.model.gameboard.GridBoard; -import edu.rpi.legup.model.gameboard.PuzzleElement; - -public class StarBattleBoard extends GridBoard { - - private int size; - private int puzzleNum; - protected List regions; - //private ArrayList groupSizes; - - public StarBattleBoard(int size, int num) { - super(size, size); - this.size = size; - this.puzzleNum = num; - this.regions = new ArrayList<>(); - for (int i = 0; i < size; i++) { - regions.add(new StarBattleRegion()); - } - } - - @Override - public StarBattleCell getCell(int x, int 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); - }*/ - - public int getSize() { - return size; - } - - public Set getRow(int rowNum) { - Set row = new HashSet<>(); - for (int i = 0; i < size; i++) { - row.add(getCell(i, rowNum)); - } - return row; - } - - public int getPuzzleNumber() { return puzzleNum; } - - public Set getCol(int colNum) { - Set column = new HashSet<>(); - for (int i = 0; i < size; i++) { - column.add(getCell(colNum, i)); - } - return column; - } - - public StarBattleRegion getRegion(int index) { - if (index >= size) { - return null; - } - return regions.get(index); - } - - public StarBattleRegion getRegion(StarBattleCell cell) { - return getRegion(cell.getGroupIndex()); - } - - public void setRegion(int regionNum, StarBattleRegion region) { - regions.set(regionNum, region); - } - - public int columnStars(int columnIndex) { - int stars = 0; - if (columnIndex < size) { - for (StarBattleCell c: this.getCol(columnIndex)) { - if (c.getType() == StarBattleCellType.STAR) - ++stars; - } - } - return stars; - } - - public int rowStars(int rowIndex) { - int stars = 0; - if (rowIndex < size) { - for (StarBattleCell c: this.getRow(rowIndex)) { - if (c.getType() == StarBattleCellType.STAR) - ++stars; - } - } - return stars; - } - - public StarBattleBoard copy() { - StarBattleBoard copy = new StarBattleBoard(size, puzzleNum); - 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()); - } - if (x < this.regions.size()) - copy.regions.add(this.getRegion(x).copy()); - } - for (PuzzleElement e : modifiedData) { - copy.getPuzzleElement(e).setModifiable(false); - } - 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 deleted file mode 100644 index a316872d9..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleCell.java +++ /dev/null @@ -1,88 +0,0 @@ -package edu.rpi.legup.puzzle.starbattle; - -import edu.rpi.legup.model.elements.Element; -import edu.rpi.legup.model.gameboard.GridCell; - -import java.awt.*; -import java.awt.event.MouseEvent; - -public class StarBattleCell extends GridCell { - private int groupIndex; - private int max; - - /** - * 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 groupIndex indicates what group # the cell is in. - * @param size size of the star battle cell - */ - public StarBattleCell(int value, Point location, int groupIndex, int size) { - super(value, location); - this.groupIndex = groupIndex; - this.max = size; - } - - public int getGroupIndex() { return groupIndex; } - - @Override - public void setType(Element e, MouseEvent m) { - switch (e.getElementID()) { - case "STBL-PLAC-0001": - this.data = -3; - break; - case "STBL-PLAC-0002": - this.data = -2; - break; - case "STBL-PLAC-0003": - this.data = -1; - break; - - 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 { - this.data = this.data + 1; - } - break; - case MouseEvent.BUTTON3: - if (this.data > -4) { - this.data = this.data - 1; - } - else { - this.data = -1;//Unsure - } - break; - } - break; - } - } - - public StarBattleCellType getType() { - switch (data) { - case -3: - return StarBattleCellType.UNKNOWN; - case -2: - return StarBattleCellType.STAR; - case -1: - return StarBattleCellType.BLACK; - default: - if (data >= 0) { - return StarBattleCellType.UNKNOWN; - } - } - return null; - } - - public StarBattleCell copy() { - StarBattleCell copy = new StarBattleCell(data, (Point) location.clone(), groupIndex, max); - copy.setIndex(index); - copy.setModifiable(isModifiable); - 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 deleted file mode 100644 index 9f7fd0fee..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleCellFactory.java +++ /dev/null @@ -1,66 +0,0 @@ -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 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"); - } - - StarBattleBoard starbattleBoard = (StarBattleBoard) board; - int size = starbattleBoard.getSize(); - - NamedNodeMap attributeList = node.getAttributes(); - 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()); - if (x >= size || y >= size) { - 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 - 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) { - e1.printStackTrace(); - 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)"); - } - } - - public org.w3c.dom.Element exportCell(Document document, PuzzleElement puzzleElement) { - org.w3c.dom.Element cellElement = document.createElement("cell"); - - StarBattleCell cell = (StarBattleCell) puzzleElement; - Point loc = cell.getLocation(); - - cellElement.setAttribute("value", String.valueOf(cell.getData())); - cellElement.setAttribute("x", String.valueOf(loc.x)); - cellElement.setAttribute("y", String.valueOf(loc.y)); - - return cellElement; - } -} diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleCellType.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleCellType.java deleted file mode 100644 index 565f608d7..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleCellType.java +++ /dev/null @@ -1,12 +0,0 @@ -//StarBattleCellType.java -package edu.rpi.legup.puzzle.starbattle; - -public enum StarBattleCellType { - STAR(-2), BLACK(-1), UNKNOWN(0); - - 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 deleted file mode 100644 index 4ebeb39ba..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleController.java +++ /dev/null @@ -1,36 +0,0 @@ -package edu.rpi.legup.puzzle.starbattle; - -import edu.rpi.legup.controller.ElementController; -import edu.rpi.legup.model.gameboard.PuzzleElement; - -import java.awt.event.MouseEvent; - -public class StarBattleController extends ElementController { - @Override - 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 { - if (cell.getData() >= 0) { - data.setData(-2); - } - else { - data.setData(cell.getData() + 1); - } - } - } - else { - if (e.getButton() == MouseEvent.BUTTON3) { - if (cell.getData() == -2) { - data.setData(0); - } - 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 deleted file mode 100644 index ff5d54d1c..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleElementView.java +++ /dev/null @@ -1,41 +0,0 @@ -package edu.rpi.legup.puzzle.starbattle; - -import edu.rpi.legup.ui.boardview.GridElementView; - -import java.awt.*; - -public class StarBattleElementView extends GridElementView { - - public StarBattleElementView(StarBattleCell cell) { - super(cell); - } - - @Override - public StarBattleCell getPuzzleElement() { - return (StarBattleCell) super.getPuzzleElement(); - } - - @Override - public void drawElement(Graphics2D graphics2D) { - StarBattleCell cell = (StarBattleCell) puzzleElement; - StarBattleCellType type = cell.getType(); - 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.setColor(Color.BLACK); - graphics2D.drawRect(location.x, location.y, size.width, size.height); - } else if (type == StarBattleCellType.BLACK) { - graphics2D.setStroke(new BasicStroke(1)); - graphics2D.setColor(Color.BLACK); - graphics2D.fillRect(location.x, location.y, size.width, size.height); - } else if (type == StarBattleCellType.UNKNOWN) { - 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/starbattle/StarBattleExporter.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleExporter.java deleted file mode 100644 index 58fb41e63..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleExporter.java +++ /dev/null @@ -1,33 +0,0 @@ -package edu.rpi.legup.puzzle.starbattle; - -import edu.rpi.legup.model.PuzzleExporter; - -import org.w3c.dom.Document; - -public class StarBattleExporter extends PuzzleExporter { - public StarBattleExporter(StarBattle starbattle) { - super(starbattle); - } - - @Override - protected org.w3c.dom.Element createBoardElement(Document newDocument) { - StarBattleBoard board = (StarBattleBoard) puzzle.getTree().getRootNode().getBoard(); - org.w3c.dom.Element boardElement = newDocument.createElement("board"); - boardElement.setAttribute("size", String.valueOf(board.getSize())); - boardElement.setAttribute("puzzle_num", String.valueOf(board.getPuzzleNumber())); - for (StarBattleRegion sb_region : board.regions) { - org.w3c.dom.Element regionsElement = newDocument.createElement("region"); - 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); - 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 deleted file mode 100644 index fa0e065ee..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleImporter.java +++ /dev/null @@ -1,103 +0,0 @@ -package edu.rpi.legup.puzzle.starbattle; - -import edu.rpi.legup.model.PuzzleImporter; -import edu.rpi.legup.save.InvalidFileFormatException; -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 StarBattleImporter(StarBattle starbattle) { - super(starbattle); - } - - /** - * Puzzle setting to support row and column inputs - */ - @Override - public boolean acceptsRowsAndColumnsInput() { - return true; - } - - /** - * 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 - public void initializeBoard(int rows, int columns) { - int puzzle_num = 1; - StarBattleBoard StarBattleBoard = new StarBattleBoard(rows, puzzle_num); - puzzle.setCurrentBoard(StarBattleBoard); - } - - /** - * Constructs StarBattle gameboard - * @param node xml document node - * @throws InvalidFileFormatException if file is invalid - */ - @Override - public void initializeBoard(Node node) throws InvalidFileFormatException { - Element puzzleElement = (Element) node; - int puzzle_num = Integer.parseInt(puzzleElement.getAttribute("puzzle_num")); - 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."); - } - - 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); - NodeList cellNodes = regionElement.getElementsByTagName("cell"); - StarBattleRegion region_i = new StarBattleRegion(); - - for (int j = 0; j < cellNodes.getLength(); j++) { - Element cellElement = (Element) cellNodes.item(j); - int x = Integer.parseInt(cellElement.getAttribute("x")); - int y = Integer.parseInt(cellElement.getAttribute("y")); - int value = Integer.parseInt(cellElement.getAttribute("value")); - - Point cellPoint = new Point(x, y); - - // Create the StarBattleCell with the cell type and value - StarBattleCell cell = new StarBattleCell(value, cellPoint, i, size); - cell.setIndex(y * size + x); // Calculate the index based on size - cell.setModifiable(true); - - // Add the cell to the board - StarBattleBoard.setCell(x, y, cell); - region_i.addCell(cell); - } - StarBattleBoard.setRegion(i, region_i); - } - - puzzle.setCurrentBoard(StarBattleBoard); - } - - - - /** - * Initialize board via string of statements. - * @throws UnsupportedOperationException since StarBattle does not support text input - */ - @Override - public void initializeBoard(String[] statements) throws UnsupportedOperationException { - 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 deleted file mode 100644 index 099cabfcd..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleRegion.java +++ /dev/null @@ -1,26 +0,0 @@ -package edu.rpi.legup.puzzle.starbattle; - -import edu.rpi.legup.model.gameboard.GridRegion; - -public class StarBattleRegion extends GridRegion{ - public StarBattleRegion() { - super(); - } - - public StarBattleRegion copy() { - StarBattleRegion copy = new StarBattleRegion(); - for (StarBattleCell c: regionCells) { - copy.addCell(c.copy()); - } - return copy; - } - - public int numStars() { - int stars = 0; - for (StarBattleCell c: regionCells) { - if (c.getType() == StarBattleCellType.STAR) - ++stars; - } - return 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 deleted file mode 100644 index ceb0eec19..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleView.java +++ /dev/null @@ -1,43 +0,0 @@ -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 java.awt.*; - -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) { - // pass - } - } - - public StarBattleView(StarBattleBoard board) { - super(new BoardController(), new StarBattleController(), board.getDimension()); - - for (PuzzleElement puzzleElement : board.getPuzzleElements()) { - StarBattleCell cell = (StarBattleCell) puzzleElement; - Point loc = cell.getLocation(); - StarBattleElementView elementView = new StarBattleElementView(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/starbattle/allfiles.txt b/src/main/java/edu/rpi/legup/puzzle/starbattle/allfiles.txt deleted file mode 100644 index 5a9ec0f0a..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/allfiles.txt +++ /dev/null @@ -1,235 +0,0 @@ -//StarBattle.java - -package edu.rpi.legup.puzzle.starbattle; - -import edu.rpi.legup.model.Puzzle; -import edu.rpi.legup.model.gameboard.Board; - -public class StarBattle extends Puzzle { - public StarBattle() { - super(); - this.name = "StarBattle"; - - this.importer = new StarBattleImporter(this); - this.exporter = new StarBattleExporter(this); - - this.factory = new StarBattleCellFactory(); - } - - @Override - public void initializeView() { - } - - @Override - public Board generatePuzzle(int difficulty) { - return null; - } - - @Override - public boolean isBoardComplete(Board board) { - return true; - } - - @Override - public void onBoardChange(Board board) { - } -} - -//StarBattleBoard.java - -package edu.rpi.legup.puzzle.lightup; - -import edu.rpi.legup.model.gameboard.GridBoard; -import edu.rpi.legup.model.gameboard.PuzzleElement; - -import java.awt.*; -import java.util.HashSet; -import java.util.Set; - -public class StarBattleBoard extends GridBoard { - - private int size; - private vector group_sizes; - - /** - * StarBattleBoard Constructor - create a new Star Battle board - * - * @param size size of one side of the star battle board - */ - - public StarBattleBoard(int size) { - super(size, size); - group_sizes = vector(size); - } - - @Override - public StarBattleCell getCell(int x, int y) { - return (StarBattleCell) super.getCell(x, y); - } - - -} - -//StarBattleCell.java - -package edu.rpi.legup.puzzle.starbattle; - -import edu.rpi.legup.model.gameboard.GridCell; - -import java.awt.*; -import java.util.HashSet; -import java.util.Set; - -public class StarBattleCell extends GridCell { - private int groupIndex; - private int max; - - /** - * StarBattleCell Constructor - creates a new StarBattle cell to hold the puzzleElement - * - * @param valueInt value of the star battle cell denoting its state - * @param location location of the cell on the board - * @param size size of the star battle cell - */ - public StarBattleCell(int value, Point location, int groupIndex, int size) { - super(value, location); - this.groupIndex = groupIndex; - this.max = size; - } - - @Override - public void setType(Element e, MouseEvent m) { - switch (e.getElementID()) { - case "SBUP-PLAC-0001": - this.data = -3; - break; - case "SBUP-PLAC-0002": - this.data = -2; - break; - case "SBUP-PLAC-0003": - this.data = -1; - break; - case "SBUP-UNPL-0001"://Not sure how button events work - switch (m.getButton()){ - case MouseEvent.BUTTON1: - if (this.data < 0 || this.data > 3) { - this.data = 0; - } - else { - this.data = this.data + 1; - } - break; - case MouseEvent.BUTTON3: - if (this.data > 0) { - this.data = this.data - 1; - } - else { - this.data = 3;//Unsure - } - break; - } - break; - } - } - - public LightUpCellType getType() { - switch (data) { - case -3: - return LightUpCellType.UNKNOWN; - case -2: - return LightUpCellType.STAR; - case -1: - return LightUpCellType.BLACK; - default: - if (data >= 0) { - return StarBattleCellType.WHITE; - } - } - return null; - } - - /** - * Gets the region index of the cell - * - * @return group index of the cell - */ - public int getGroupIndex() { - return groupIndex; - } - - /** - * Gets the size of the cell - * - * @return size of the cell - */ - - public int getMax() { - return max; - } - -} - -//StarBattleCellController.java - -package edu.rpi.legup.puzzle.starbattle; - -import edu.rpi.legup.controller.ElementController; -import edu.rpi.legup.model.gameboard.PuzzleElement; - -import java.awt.event.MouseEvent; - -public class StarBattleCellController extends ElementController { - @Override - 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 { - if (cell.getData() == 0) { - data.setData(-3); - } - else { - data.setData(cell.getData() + 1); - } - } - } - else { - if (e.getButton() == MouseEvent.BUTTON3) { - if (cell.getData() == -3) { - data.setData(0); - } - else { - data.setData(cell.getData() - 1); - } - } - } - } -} - -//StarBattleCellFactory.java - - - -//StarBattleCellType.java -package edu.rpi.legup.puzzle.starbattle; - -public enum StarBattleType { - UNKNOWN(-3), STAR(-2), BLACK(-1), WHITE(0); - - public int value; - - StarBattleCell(int value) { - this.value = value; - } -} - -//StarBattleExporter.java -//StarBattleImporter.java -//StarBattleView.java - -How to run Legup: - -./gradlew build -Java -jar build/libs/Legup.jar \ No newline at end of file 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 deleted file mode 100644 index 2601bd351..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/elements/BlackTile.java +++ /dev/null @@ -1,9 +0,0 @@ -package edu.rpi.legup.puzzle.starbattle.elements; - -import edu.rpi.legup.model.elements.NonPlaceableElement; - -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"); - } -} 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 deleted file mode 100644 index d42cc0010..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/elements/StarTile.java +++ /dev/null @@ -1,9 +0,0 @@ -package edu.rpi.legup.puzzle.starbattle.elements; - -import edu.rpi.legup.model.elements.NonPlaceableElement; - -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"); - } -} 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 deleted file mode 100644 index c2459f642..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/elements/UnknownTile.java +++ /dev/null @@ -1,9 +0,0 @@ -package edu.rpi.legup.puzzle.starbattle.elements; - -import edu.rpi.legup.model.elements.NonPlaceableElement; - -public class UnknownTile extends NonPlaceableElement { - public UnknownTile() { - 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 deleted file mode 100644 index a064c1fad..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/elements/WhiteTile.java +++ /dev/null @@ -1,10 +0,0 @@ -package edu.rpi.legup.puzzle.starbattle.elements; - -import edu.rpi.legup.model.elements.PlaceableElement; - -public class WhiteTile extends PlaceableElement { - public WhiteTile() { - 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 deleted file mode 100644 index 75fbaadb6..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/BlackoutDirectRule.java +++ /dev/null @@ -1,64 +0,0 @@ -package edu.rpi.legup.puzzle.starbattle.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.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; - -public class BlackoutDirectRule extends DirectRule { - - public BlackoutDirectRule() { - 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 - * - * @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) { - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleBoard origBoard = (StarBattleBoard) transition.getParents().get(0).getBoard(); - ContradictionRule contraRule = new TooManyStarsContradictionRule(); - - StarBattleCell cell = (StarBattleCell) board.getPuzzleElement(puzzleElement); - - if (cell.getType() != StarBattleCellType.BLACK) { - return "Only black cells are allowed for this rule!"; - } - - StarBattleBoard modified = (StarBattleBoard) origBoard.copy(); - modified.getPuzzleElement(puzzleElement).setData(StarBattleCellType.STAR.value); - if (contraRule.checkContradictionAt(modified, puzzleElement) != null) { - return "Black cells must be placed in a row, region, or column with enough stars!"; - } - return null; - } - - /** - * 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) { - 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 deleted file mode 100644 index 0ca27ab4a..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/ClashingOrbitContradictionRule.java +++ /dev/null @@ -1,60 +0,0 @@ -package edu.rpi.legup.puzzle.starbattle.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.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", - "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 - * - * @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) { - StarBattleBoard starbattleBoard = (StarBattleBoard) board; - StarBattleCell cell = (StarBattleCell) starbattleBoard.getPuzzleElement(puzzleElement); - - // Contradiction rule can only be applied to cells with a star in it - if (cell.getType() != StarBattleCellType.STAR) { - return super.getNoContradictionMessage(); - } - - // 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 ); - - 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)) { - return null; - } - } - } - - 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 deleted file mode 100644 index b42bfd1c0..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/ColumnsWithinRegionsDirectRule.java +++ /dev/null @@ -1,94 +0,0 @@ -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; -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 ColumnsWithinRegionsDirectRule extends DirectRule { - public ColumnsWithinRegionsDirectRule() { - 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 - * - * @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) { - //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 - Set columns = new HashSet(); - //the regions that contain them - Set regions = new HashSet(); - //columns and regions to process - Set columnsToCheck = new HashSet(); - Set regionsToCheck = new HashSet(); - int columnStars = 0; - int regionStars = 0; - regions.add(cell.getGroupIndex()); - regionsToCheck.add(cell.getGroupIndex()); - - while (!columnsToCheck.isEmpty() || !regionsToCheck.isEmpty()) { - for (int r: regionsToCheck) { - regionStars += board.getRegion(r).numStars(); - for (PuzzleElement c: board.getRegion(r).getCells()) { - int column = ((StarBattleCell) c).getLocation().x; - if (columns.add(column)) { - columnsToCheck.add(column); - } - } - regionsToCheck.remove(r); - } - for (int c: columnsToCheck) { - columnStars += board.columnStars(c); - for (int i = 0; i < board.getSize(); ++i) { - int region = board.getCell(c,i).getGroupIndex(); - if (regions.add(region)) { - regionsToCheck.add(region); - } - } - columnsToCheck.remove(c); - } - } - // are the columns and regions missing an equal amount of stars - 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}. - * - * @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) { - - return null; - } -} 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 deleted file mode 100644 index 0a78c8868..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/ColumnsWithinRowsDirectRule.java +++ /dev/null @@ -1,97 +0,0 @@ -package edu.rpi.legup.puzzle.starbattle.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.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", - "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 - * - * @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) { - - //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 - Set columns = new HashSet(); - //the rows that contain them - Set rows = new HashSet(); - //columns and rows to process - Set columnsToCheck = new HashSet(); - Set rowsToCheck = new HashSet(); - int columnStars = 0; - int rowStars = 0; - int firstRow = cell.getLocation().y; - rows.add(firstRow); - rowsToCheck.add(firstRow); - - while (!columnsToCheck.isEmpty() || !rowsToCheck.isEmpty()) { - for (int r: rowsToCheck) { - rowStars += board.rowStars(r); - for (PuzzleElement c: board.getRow(r)) { - int column = ((StarBattleCell) c).getLocation().x; - if (columns.add(column)) { - columnsToCheck.add(column); - } - } - rowsToCheck.remove(r); - } - for (int c: columnsToCheck) { - columnStars += board.columnStars(c); - for (PuzzleElement r: board.getCol(c)) { - int row = ((StarBattleCell) r).getLocation().y; - if (rows.add(row)) { - rowsToCheck.add(row); - } - } - columnsToCheck.remove(c); - } - } - // are the columns and regions missing an equal amount of stars - 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}. - * - * @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) { - - return null; - } -} 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 deleted file mode 100644 index 36e691e74..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/FinishWithStarsDirectRule.java +++ /dev/null @@ -1,63 +0,0 @@ -package edu.rpi.legup.puzzle.starbattle.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.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; - -public class FinishWithStarsDirectRule extends DirectRule { - - public FinishWithStarsDirectRule() { - 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 - * - * @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) { - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleBoard origBoard = (StarBattleBoard) transition.getParents().get(0).getBoard(); - ContradictionRule contraRule = new TooFewStarsContradictionRule(); - - StarBattleCell cell = (StarBattleCell) board.getPuzzleElement(puzzleElement); - - if (cell.getType() != StarBattleCellType.STAR) { - return "Only star cells are allowed for this rule!"; - } - - StarBattleBoard modified = (StarBattleBoard) origBoard.copy(); - modified.getPuzzleElement(puzzleElement).setData(StarBattleCellType.BLACK.value); - if (contraRule.checkContradictionAt(modified, puzzleElement) != null) { - return "Star cells must be placed in a row, region, or column without extra spaces!"; - } - return null; - } - - /** - * 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) { - - return null; - } -} 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 deleted file mode 100644 index 16951fb2a..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/RegionsWithinColumnsDirectRule.java +++ /dev/null @@ -1,43 +0,0 @@ -package edu.rpi.legup.puzzle.starbattle.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; - -public class RegionsWithinColumnsDirectRule extends DirectRule { - public RegionsWithinColumnsDirectRule() { - 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 - * - * @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) { - ColumnsWithinRegionsDirectRule correspondingRule = new ColumnsWithinRegionsDirectRule(); - return correspondingRule.checkRuleRawAt(transition, puzzleElement); - } - - /** - * 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) { - - return null; - } -} 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 deleted file mode 100644 index 27dc001a0..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/RegionsWithinRowsDirectRule.java +++ /dev/null @@ -1,44 +0,0 @@ -package edu.rpi.legup.puzzle.starbattle.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; - -public class RegionsWithinRowsDirectRule extends DirectRule { - public RegionsWithinRowsDirectRule() { - 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 - * - * @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) { - - RowsWithinRegionsDirectRule correspondingRule = new RowsWithinRegionsDirectRule(); - return correspondingRule.checkRuleRawAt(transition, puzzleElement); - } - - /** - * 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) { - - return null; - } -} 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 deleted file mode 100644 index 4054ec017..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/RowsWithinColumnsDirectRule.java +++ /dev/null @@ -1,51 +0,0 @@ -package edu.rpi.legup.puzzle.starbattle.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.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", - "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 - * - * @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) { - - ColumnsWithinRowsDirectRule correspondingRule = new ColumnsWithinRowsDirectRule(); - return correspondingRule.checkRuleRawAt(transition, puzzleElement); - } - - /** - * 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) { - - return null; - } -} 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 deleted file mode 100644 index 7af2c79ed..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/RowsWithinRegionsDirectRule.java +++ /dev/null @@ -1,94 +0,0 @@ -package edu.rpi.legup.puzzle.starbattle.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.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", - "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 - * - * @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) { - - //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 - Set rows = new HashSet(); - //the regions that contain them - Set regions = new HashSet(); - //rows and regions to process - Set rowsToCheck = new HashSet(); - Set regionsToCheck = new HashSet(); - int rowStars = 0; - int regionStars = 0; - regions.add(cell.getGroupIndex()); - regionsToCheck.add(cell.getGroupIndex()); - - while (!rowsToCheck.isEmpty() || !regionsToCheck.isEmpty()) { - for (int r: regionsToCheck) { - regionStars += board.getRegion(r).numStars(); - for (PuzzleElement ro: board.getRegion(r).getCells()) { - int row = ((StarBattleCell) ro).getLocation().y; - if (rows.add(row)) { - rowsToCheck.add(row); - } - } - regionsToCheck.remove(r); - } - for (int r: rowsToCheck) { - rowStars += board.rowStars(r); - for (int i = 0; i < board.getSize(); ++i) { - int region = board.getCell(i,r).getGroupIndex(); - if (regions.add(region)) { - regionsToCheck.add(region); - } - } - rowsToCheck.remove(r); - } - } - // are the columns and regions missing an equal amount of stars - 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}. - * - * @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) { - - return null; - } -} 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 deleted file mode 100644 index 0aa147c6f..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/StarOrEmptyCaseRule.java +++ /dev/null @@ -1,103 +0,0 @@ -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.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", - "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. - * - * @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."; - } - - 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."; - } - - 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; - } - - @Override - public CaseBoard getCaseBoard(Board board) { - StarBattleBoard starBattleBoard = (StarBattleBoard) board.copy(); - CaseBoard caseBoard = new CaseBoard(starBattleBoard, this); - starBattleBoard.setModifiable(false); - for (PuzzleElement element : starBattleBoard.getPuzzleElements()) { - if (((StarBattleCell) element).getType() == StarBattleCellType.UNKNOWN) { - 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(StarBattleCellType.STAR.value); - case1.addModifiedData(data1); - cases.add(case1); - - Board case2 = board.copy(); - PuzzleElement data2 = case2.getPuzzleElement(puzzleElement); - data2.setData(StarBattleCellType.BLACK.value); - case2.addModifiedData(data2); - cases.add(case2); - - return cases; - } - - @Override - public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - return checkRuleRaw(transition); - } -} 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 deleted file mode 100644 index e1c6f3084..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/SurroundStarDirectRule.java +++ /dev/null @@ -1,63 +0,0 @@ -package edu.rpi.legup.puzzle.starbattle.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.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; - -public class SurroundStarDirectRule extends DirectRule { - - public SurroundStarDirectRule() { - 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 - * - * @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) { - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleBoard origBoard = (StarBattleBoard) transition.getParents().get(0).getBoard(); - ContradictionRule contraRule = new ClashingOrbitContradictionRule(); - - StarBattleCell cell = (StarBattleCell) board.getPuzzleElement(puzzleElement); - - if (cell.getType() != StarBattleCellType.BLACK) { - return "Only black cells are allowed for this rule!"; - } - - StarBattleBoard modified = (StarBattleBoard) origBoard.copy(); - modified.getPuzzleElement(puzzleElement).setData(StarBattleCellType.STAR.value); - if (contraRule.checkContradictionAt(modified, puzzleElement) != null) { - return "Black cells must be placed adjacent to a star!"; - } - return null; - } - - /** - * 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) { - - 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 deleted file mode 100644 index d1ed62107..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/TooFewStarsContradictionRule.java +++ /dev/null @@ -1,64 +0,0 @@ -package edu.rpi.legup.puzzle.starbattle.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.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", - "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 - * - * @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) { - StarBattleBoard sbBoard = (StarBattleBoard) board; - StarBattleCell cell = (StarBattleCell) puzzleElement; - Point location = cell.getLocation(); - int column = location.x; - int row = location.y; - int rowCount = 0; - int columnCount = 0; - for (int i = 0; i < sbBoard.getSize(); ++i) { - if (sbBoard.getCell(row, i).getType() != StarBattleCellType.BLACK) { - ++rowCount; - } - if (sbBoard.getCell(i, column).getType() != StarBattleCellType.BLACK) { - ++columnCount; - } - } - if (rowCount < sbBoard.getPuzzleNumber() || columnCount < sbBoard.getPuzzleNumber()) { - return null; - } - StarBattleRegion region = sbBoard.getRegion(cell); - int regionCount = 0; - for (StarBattleCell c: region.getCells()) { - if (c.getType() != StarBattleCellType.BLACK) { - ++regionCount; - } - } - if (regionCount < sbBoard.getPuzzleNumber()) { - return null; - } - 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 deleted file mode 100644 index 2ae424d45..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/TooManyStarsContradictionRule.java +++ /dev/null @@ -1,114 +0,0 @@ -package edu.rpi.legup.puzzle.starbattle.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.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."; - - public TooManyStarsContradictionRule() { - 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 - * - * @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) { - StarBattleBoard starbattleBoard = (StarBattleBoard) board; - StarBattleCell cell = (StarBattleCell) starbattleBoard.getPuzzleElement(puzzleElement); - Point location = cell.getLocation(); - int starCount = 0; - int puzzleNum = starbattleBoard.getPuzzleNumber(); - boolean valid = true; - - if (cell.getType() != StarBattleCellType.STAR) { - return this.INVALID_USE_MESSAGE; - } - - // check row - for (int i = location.x - 1; i >= 0; i--) { - StarBattleCell check = starbattleBoard.getCell(i, location.y); - if (check.getType() == StarBattleCellType.STAR) { - starCount++; - if (starCount >= puzzleNum) { - valid = false; - break; - } - } - } - - for (int i = location.x + 1; i < starbattleBoard.getWidth(); i++) { - StarBattleCell check = starbattleBoard.getCell(i, location.y); - if (check.getType() == StarBattleCellType.STAR) { - starCount++; - if (starCount >= puzzleNum) { - valid = false; - break; - } - } - } - - // check column - starCount = 0; - for (int j = location.y - 1; j >= 0; j--) { - StarBattleCell check = starbattleBoard.getCell(location.x, j); - if (check.getType() == StarBattleCellType.STAR) { - starCount++; - if (starCount >= puzzleNum) { - valid = false; - break; - } - } - } - - for (int j = location.y + 1; j < starbattleBoard.getWidth(); j++) { - StarBattleCell check = starbattleBoard.getCell(location.x, j); - if (check.getType() == StarBattleCellType.STAR) { - starCount++; - if (starCount >= puzzleNum) { - valid = false; - break; - } - } - } - - // check region - starCount = 0; - StarBattleRegion reg = starbattleBoard.getRegion(cell); - List cellList = reg.getCells(); // list of cells - for (int k = 0; k < cellList.size(); k++) { - if (cellList.get(k).getType() == StarBattleCellType.STAR) { - starCount++; - if (starCount > puzzleNum) { - valid = false; - break; - } - } - } - - if (valid) { - return super.getNoContradictionMessage(); - } - return null; - } -} \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/starbattle_reference_sheet.txt b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/starbattle_reference_sheet.txt deleted file mode 100644 index f18965fd6..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/starbattle_reference_sheet.txt +++ /dev/null @@ -1,19 +0,0 @@ -Case Rules: -Add Star: STBL-CASE-0001 -Star or Empty: STBL-CASE-0002 - -Basic Rules: -Blackout: STBL-BASC-0001 -Columns Within Regions: STBL-BASC-0002 -Columns Within Rows: STBL-BASC-0003 -Finish With Stars: STBL-BASC-0004 -Regions Within Columns: STBL-BASC-0005 -Regions Within Rows: STBL-BASC-0006 -Rows Within Columns: STBL-BASC-0007 -Rows Within Regions: STBL-BASC-0008 -Surround Star: STBL-BASC-0009 - -Contradiction Rules: -Too Many Stars: STBL-CONT-0001 -Too Few Stars: STBL-CONT-0002 -Clashing Orbit: STBL-CONT-0003 \ 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..94f119a5e 100644 --- a/src/main/java/edu/rpi/legup/utility/LegupUtils.java +++ b/src/main/java/edu/rpi/legup/utility/LegupUtils.java @@ -94,14 +94,9 @@ private static List findClassesZip(String path, String packageName) && entry.getName().endsWith(".class") && entry.getName().startsWith(packageName)) { String className = entry.getName().replace('/', '.'); - String substr = className.substring(0, className.length() - ".class".length()); - try { - Class c = Class.forName(substr); - classes.add(c); - } - catch (LinkageError | ClassNotFoundException e) { - System.out.println("Failed on " + substr); - } + classes.add( + Class.forName( + className.substring(0, className.length() - ".class".length()))); } } return classes; diff --git a/src/main/resources/edu/rpi/legup/images/starbattle/UnknownTile.png b/src/main/resources/edu/rpi/legup/images/starbattle/UnknownTile.png deleted file mode 100644 index 850fbf127f04020fe83c6a4f6db75078967916ea..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9733 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 QTOg2`(SBUvUiYy70dQO53jhEB diff --git a/src/main/resources/edu/rpi/legup/images/starbattle/black.gif b/src/main/resources/edu/rpi/legup/images/starbattle/black.gif deleted file mode 100644 index 13381a7179c2af7ad23ef064b743d3e479b56070..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 856 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 diff --git a/src/main/resources/edu/rpi/legup/images/starbattle/contradictions/ClashingOrbitContradictionRule.png b/src/main/resources/edu/rpi/legup/images/starbattle/contradictions/ClashingOrbitContradictionRule.png deleted file mode 100644 index d25340b407edf02eebfdbc35764b0527ecea59b7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5135 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 D%D^dv diff --git a/src/main/resources/edu/rpi/legup/images/starbattle/contradictions/TooManyStarsContradictionRule.png b/src/main/resources/edu/rpi/legup/images/starbattle/contradictions/TooManyStarsContradictionRule.png deleted file mode 100644 index b468ae6f6fb70271fd594e8cb6b5148dbd9153c5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6199 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 YEnSqZ8g?u{`D@=m$5i{drepa30M6m=2LJ#7 diff --git a/src/main/resources/edu/rpi/legup/images/starbattle/empty.gif b/src/main/resources/edu/rpi/legup/images/starbattle/empty.gif deleted file mode 100644 index 38b91d0a2b9c6599eb19d14466db047a86d2ea97..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 857 zcmZ?wbhEHbRA5kG_|Cxa|Nno6Q7{?;BQ*qcKpqF>1qKc~21X7Uj|~eBHggDT#hlo% z@Nm0;vez7sjf;+UOBiR}IkEBaF$M+Z0v^pz$tNbN+pdZ^xoPR?=?2NC=6GICbzrat E0QgHHq5uE@ diff --git a/src/main/resources/edu/rpi/legup/images/starbattle/rules/BlackOutDirectRule.png b/src/main/resources/edu/rpi/legup/images/starbattle/rules/BlackOutDirectRule.png deleted file mode 100644 index f72fd7d7f82687cfae12872a76855ab94d80fdcb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4717 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 G67esNMHw6b diff --git a/src/main/resources/edu/rpi/legup/images/starbattle/rules/ColumnsWithinRegionsDirectRule.png b/src/main/resources/edu/rpi/legup/images/starbattle/rules/ColumnsWithinRegionsDirectRule.png deleted file mode 100644 index 1a88e9d07c6a0e4a1425d9725be9d1fc130058ee..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6456 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 A-2eap diff --git a/src/main/resources/edu/rpi/legup/images/starbattle/rules/ColumnsWithinRowsDirectRule.png b/src/main/resources/edu/rpi/legup/images/starbattle/rules/ColumnsWithinRowsDirectRule.png deleted file mode 100644 index 24fb0d48a84c46608fc3ab3335ab0df053898bba..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5331 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 diff --git a/src/main/resources/edu/rpi/legup/images/starbattle/rules/FinishWithStarDirectRule.png b/src/main/resources/edu/rpi/legup/images/starbattle/rules/FinishWithStarDirectRule.png deleted file mode 100644 index 11cfbf89965d94b114cf32be6944f2703f4ee90f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4326 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 E0_Y@20RR91 diff --git a/src/main/resources/edu/rpi/legup/images/starbattle/rules/RowsWithinColumnsDirectRule.png b/src/main/resources/edu/rpi/legup/images/starbattle/rules/RowsWithinColumnsDirectRule.png deleted file mode 100644 index bac64a87c9ae9df53b8be031c17306773ccfba7d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5117 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 diff --git a/src/main/resources/edu/rpi/legup/images/starbattle/rules/RowsWithinRegionsDirectRule.png b/src/main/resources/edu/rpi/legup/images/starbattle/rules/RowsWithinRegionsDirectRule.png deleted file mode 100644 index 8907e047521d5310676821ddb141672f2b5e4d7c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6477 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 F^k2&Gt=s?r diff --git a/src/main/resources/edu/rpi/legup/images/starbattle/rules/SurroundStar.png b/src/main/resources/edu/rpi/legup/images/starbattle/rules/SurroundStar.png deleted file mode 100644 index 13287f779e74d6c70489f32013ec3675b07dfe4c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5102 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 diff --git a/src/main/resources/edu/rpi/legup/images/starbattle/star.gif b/src/main/resources/edu/rpi/legup/images/starbattle/star.gif deleted file mode 100644 index e289b287ae12d06741cf5d97a0413691752c4f49..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 545 zcmV++0^a?JP)Px$+et)0R7gwB)k~;OQ4|O8-%S#Q6f(WuN(@LbxC6?>z|bQh@)#H)BSjf;3uWXn zP!c6GWTuoTBMJi~86e~tQXYG0-#TsIx!*bRl~udbx7OP0zy9m7zdk*dz8=T--vKPZ zNZe}5ye)&{8DLYd0Dk7cjT39^h^+_)Av2;~qv~I+oyO zH;_68qf-gSS5A~<6}DyFAzZ*gyu-&-wh#DP0#*UeVHPIj6985Df-zYUfr3d@-r_ah z<1to;v1D)nd-JVpIkQjs`y%Q0XIp&7Vq88Gu{7JF`N8ys&8EnBIreozzwXyvjSvlDruB;5x!$Xnyj1X!07h$Pn6jcYf6SBM5q!d&djqZoq_nZLnHO!*stxbz$k z^O6OVs+_<8W@9oUnLlJW2AgrJxN#Uiu)EO55S(udFjW7z7Y*E=w)sI0G84zJJpYbF zwzLI!nx2AqGGew**VH(+^=R_>j2PR-CF)OWzawq%uDa$G`gogyQMoI%|H<=lr(y6R jw|ThRX3<*4@9h2yt8`HryKo;Y00000NkvXXu0mjflb`cS diff --git a/src/main/resources/edu/rpi/legup/images/starbattle/white.gif b/src/main/resources/edu/rpi/legup/images/starbattle/white.gif deleted file mode 100644 index fc2c683eb7860f47d4322fe0e73b0508099a89de..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9700 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 diff --git a/src/main/resources/edu/rpi/legup/legup/config b/src/main/resources/edu/rpi/legup/legup/config index 4aef6de60..ccd4f5be3 100644 --- a/src/main/resources/edu/rpi/legup/legup/config +++ b/src/main/resources/edu/rpi/legup/legup/config @@ -31,10 +31,6 @@ - + fileCreationDisabled="false"/> diff --git a/src/test/java/puzzles/starbattle/rules/BlackoutDirectRuleTest.java b/src/test/java/puzzles/starbattle/rules/BlackoutDirectRuleTest.java deleted file mode 100644 index d42f40c87..000000000 --- a/src/test/java/puzzles/starbattle/rules/BlackoutDirectRuleTest.java +++ /dev/null @@ -1,69 +0,0 @@ -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.*; - -public class BlackoutDirectRuleTest { - - private static final BlackoutDirectRule RULE = new BlackoutDirectRule(); - private static StarBattle starbattle; - - @BeforeClass - public static void setUp() { - MockGameBoardFacade.getInstance(); - starbattle = new StarBattle(); - } - - @Test - public void BlackoutDirectRuleTest_ColumnBlackout() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/BlackoutDirectRule/ColumnBlackout", starbattle); - TreeNode rootNode = starbattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - - StarBattleCell cell1 = board.getCell(1, 1); - cell1.setData(StarBattleCellType.BLACK.value); - StarBattleCell cell2 = board.getCell(1, 2); - cell2.setData(StarBattleCellType.BLACK.value); - StarBattleCell cell3 = board.getCell(1, 3); - cell3.setData(StarBattleCellType.BLACK.value); - - board.addModifiedData(cell1); - board.addModifiedData(cell2); - board.addModifiedData(cell3); - - Assert.assertNull(RULE.checkRule(transition)); - - for (int i = 0; i < board.getHeight(); i++) { - for (int k = 0; k < board.getWidth(); k++) { - Point point = new Point(k, i); - if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) || point.equals(cell3.getLocation())) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - } - } - } -} diff --git a/src/test/resources/puzzles/starbattle.rules/BlackoutDirectRule/ColumnBlackout b/src/test/resources/puzzles/starbattle.rules/BlackoutDirectRule/ColumnBlackout deleted file mode 100644 index ddcc4dc9a..000000000 --- a/src/test/resources/puzzles/starbattle.rules/BlackoutDirectRule/ColumnBlackout +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle.rules/BlackoutDirectRule/RegionBlackout b/src/test/resources/puzzles/starbattle.rules/BlackoutDirectRule/RegionBlackout deleted file mode 100644 index f2a5b42d9..000000000 --- a/src/test/resources/puzzles/starbattle.rules/BlackoutDirectRule/RegionBlackout +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle.rules/BlackoutDirectRule/RowBlackout b/src/test/resources/puzzles/starbattle.rules/BlackoutDirectRule/RowBlackout deleted file mode 100644 index f2a5b42d9..000000000 --- a/src/test/resources/puzzles/starbattle.rules/BlackoutDirectRule/RowBlackout +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file From 68e8e67b044f0250b96b235d13bd2f346162638e Mon Sep 17 00:00:00 2001 From: Bram van Heuveln Date: Tue, 16 Apr 2024 21:39:16 +0000 Subject: [PATCH 099/258] Automated Java code formatting changes --- .../rpi/legup/model/gameboard/GridRegion.java | 16 ++-- .../edu/rpi/legup/puzzle/binary/Binary.java | 31 ++++---- .../rpi/legup/puzzle/binary/BinaryBoard.java | 14 ++-- .../rpi/legup/puzzle/binary/BinaryCell.java | 3 +- .../puzzle/binary/BinaryCellFactory.java | 17 ++-- .../legup/puzzle/binary/BinaryController.java | 26 +++---- .../puzzle/binary/BinaryElementView.java | 77 ++++++++++--------- .../legup/puzzle/binary/BinaryExporter.java | 6 +- .../legup/puzzle/binary/BinaryImporter.java | 32 ++++---- .../rpi/legup/puzzle/binary/BinaryType.java | 4 +- .../rpi/legup/puzzle/binary/BinaryView.java | 6 +- .../puzzle/binary/elements/NumberTile.java | 1 + .../rules/CompleteRowColumnDirectRule.java | 30 ++++---- ...plicateRowsOrColumnsContradictionRule.java | 26 +++---- .../binary/rules/OneOrZeroCaseRule.java | 26 ++++--- .../binary/rules/OneTileGapDirectRule.java | 31 ++++---- .../binary/rules/SurroundPairDirectRule.java | 13 ++-- .../rules/ThreeAdjacentContradictionRule.java | 72 +++++++++++------ ...nbalancedRowOrColumnContradictionRule.java | 20 ++--- .../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 +- .../rules/BlackoutDirectRuleTest.java | 26 +++---- 49 files changed, 526 insertions(+), 481 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/binary/Binary.java b/src/main/java/edu/rpi/legup/puzzle/binary/Binary.java index 6730b2806..773513cda 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/Binary.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/Binary.java @@ -17,9 +17,7 @@ public Binary() { this.factory = new BinaryCellFactory(); } - /** - * Initializes the game board. Called by the invoker of the class - */ + /** Initializes the game board. Called by the invoker of the class */ @Override public void initializeView() { boardView = new BinaryView((BinaryBoard) currentBoard); @@ -38,17 +36,17 @@ public Board generatePuzzle(int difficulty) { return null; } -// /** -// * Determines if the given dimensions are valid for Binary -// * -// * @param rows the number of rows -// * @param columns the number of columns -// * @return true if the given dimensions are valid for Binary, false otherwise -// */ -// @Override -// public boolean isValidDimensions(int rows, int columns){ -// return rows >= 2 && rows % 2 == 0 && columns >= 2 && columns % 2 == 0; -// } + // /** + // * Determines if the given dimensions are valid for Binary + // * + // * @param rows the number of rows + // * @param columns the number of columns + // * @return true if the given dimensions are valid for Binary, false otherwise + // */ + // @Override + // public boolean isValidDimensions(int rows, int columns){ + // return rows >= 2 && rows % 2 == 0 && columns >= 2 && columns % 2 == 0; + // } @Override public boolean isBoardComplete(Board board) { @@ -69,6 +67,5 @@ public boolean isBoardComplete(Board board) { } @Override - public void onBoardChange(Board board) { - } -} \ No newline at end of file + public void onBoardChange(Board board) {} +} diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java index b5faa1fef..35c37b1a1 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java @@ -2,13 +2,14 @@ import edu.rpi.legup.model.gameboard.GridBoard; import edu.rpi.legup.model.gameboard.PuzzleElement; - import java.awt.*; import java.util.ArrayList; import java.util.HashSet; import java.util.Set; + public class BinaryBoard extends GridBoard { private int size; + public BinaryBoard(int width, int height) { super(width, height); this.size = width; @@ -21,12 +22,16 @@ public BinaryBoard(int size) { @Override public BinaryCell getCell(int x, int y) { - if (y * dimension.width + x >= puzzleElements.size() || x >= dimension.width || - y >= dimension.height || x < 0 || y < 0) { + if (y * dimension.width + x >= puzzleElements.size() + || x >= dimension.width + || y >= dimension.height + || x < 0 + || y < 0) { return null; } return (BinaryCell) super.getCell(x, y); } + public Set getRowCells(int rowNum) { Set row = new HashSet<>(); for (int i = 0; i < size; i++) { @@ -56,13 +61,12 @@ public ArrayList getColTypes(int colNum) { public Set getCol(int colNum) { Set col = new HashSet<>(); - for (int i = 0; i < size; i ++) { + for (int i = 0; i < size; i++) { col.add(getCell(colNum, i)); } return col; } - @Override public BinaryBoard copy() { System.out.println("BinaryBoard copy()"); diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java index fc68116dc..9007215ad 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java @@ -1,7 +1,6 @@ package edu.rpi.legup.puzzle.binary; import edu.rpi.legup.model.gameboard.GridCell; - import java.awt.Point; public class BinaryCell extends GridCell { @@ -33,4 +32,4 @@ public BinaryCell copy() { copy.setGiven(isGiven); return copy; } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCellFactory.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCellFactory.java index dd25dff10..890c26656 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCellFactory.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCellFactory.java @@ -4,18 +4,18 @@ 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 BinaryCellFactory extends ElementFactory { - + public BinaryCell importCell(Node node, Board board) throws InvalidFileFormatException { try { if (!node.getNodeName().equalsIgnoreCase("cell")) { - throw new InvalidFileFormatException("binary Factory: unknown puzzleElement puzzleElement"); + throw new InvalidFileFormatException( + "binary Factory: unknown puzzleElement puzzleElement"); } BinaryBoard binaryBoard = (BinaryBoard) board; @@ -37,11 +37,10 @@ public BinaryCell importCell(Node node, Board board) throws InvalidFileFormatExc BinaryCell cell = new BinaryCell(value, new Point(x, y)); cell.setIndex(y * height + x); return cell; - } - catch (NumberFormatException e) { - throw new InvalidFileFormatException("binary Factory: unknown value where integer expected"); - } - catch (NullPointerException e) { + } catch (NumberFormatException e) { + throw new InvalidFileFormatException( + "binary Factory: unknown value where integer expected"); + } catch (NullPointerException e) { throw new InvalidFileFormatException("binary Factory: could not find attribute(s)"); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryController.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryController.java index ef519dd16..0bad559d9 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryController.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryController.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 BinaryController extends ElementController { @@ -12,32 +11,31 @@ public void changeCell(MouseEvent e, PuzzleElement data) { BinaryCell cell = (BinaryCell) 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(1); - } - else { + } else { if (cell.getData() == 1) { data.setData(2); - } - else { + } else { data.setData(0); } } } - } - else { + } else { if (e.getButton() == MouseEvent.BUTTON3) { if (cell.getData() == 0) { data.setData(1); - } - else { + } else { if (cell.getData() == 1) { data.setData(2); - } - else { + } else { data.setData(0); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryElementView.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryElementView.java index 5086b2453..9ac99c958 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryElementView.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryElementView.java @@ -1,7 +1,6 @@ package edu.rpi.legup.puzzle.binary; import edu.rpi.legup.ui.boardview.GridElementView; - import java.awt.*; public class BinaryElementView extends GridElementView { @@ -21,11 +20,11 @@ public BinaryElementView(BinaryCell cell) { @Override public BinaryCell getPuzzleElement() { return (BinaryCell) super.getPuzzleElement(); - } + @Override public void drawGiven(Graphics2D graphics2D) { - BinaryCell cell = (BinaryCell) puzzleElement; + BinaryCell cell = (BinaryCell) puzzleElement; BinaryType type = cell.getType(); if (type == BinaryType.ZERO) { graphics2D.setStroke(new BasicStroke(1)); @@ -33,31 +32,33 @@ public void drawGiven(Graphics2D graphics2D) { 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); - FontMetrics metrics = graphics2D.getFontMetrics(FONT); - String value = String.valueOf(puzzleElement.getData()); - int xText = location.x + (size.width - metrics.stringWidth(value)) / 2; - int yText = location.y + ((size.height - metrics.getHeight()) / 2) + metrics.getAscent(); + graphics2D.setColor(FONT_COLOR); + graphics2D.setFont(FONT); + FontMetrics metrics = graphics2D.getFontMetrics(FONT); + String value = String.valueOf(puzzleElement.getData()); + int xText = location.x + (size.width - metrics.stringWidth(value)) / 2; + int yText = + location.y + ((size.height - metrics.getHeight()) / 2) + metrics.getAscent(); graphics2D.drawString(String.valueOf(puzzleElement.getData()), xText, yText); - } - else { + } else { if (type == BinaryType.ONE) { 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); - graphics2D.setColor(FONT_COLOR); - graphics2D.setFont(FONT); - FontMetrics metrics = graphics2D.getFontMetrics(FONT); - String value = String.valueOf(puzzleElement.getData()); - int xText = location.x + (size.width - metrics.stringWidth(value)) / 2; - int yText = location.y + ((size.height - metrics.getHeight()) / 2) + metrics.getAscent(); + graphics2D.setColor(FONT_COLOR); + graphics2D.setFont(FONT); + FontMetrics metrics = graphics2D.getFontMetrics(FONT); + String value = String.valueOf(puzzleElement.getData()); + int xText = location.x + (size.width - metrics.stringWidth(value)) / 2; + int yText = + location.y + + ((size.height - metrics.getHeight()) / 2) + + metrics.getAscent(); graphics2D.drawString(String.valueOf(puzzleElement.getData()), xText, yText); - - } - else { + + } else { if (type == BinaryType.UNKNOWN) { graphics2D.setStroke(new BasicStroke(0)); graphics2D.setColor(Color.WHITE); @@ -79,31 +80,33 @@ public void drawElement(Graphics2D graphics2D) { 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); - FontMetrics metrics = graphics2D.getFontMetrics(FONT); - String value = String.valueOf(puzzleElement.getData()); - int xText = location.x + (size.width - metrics.stringWidth(value)) / 2; - int yText = location.y + ((size.height - metrics.getHeight()) / 2) + metrics.getAscent(); + graphics2D.setColor(FONT_COLOR); + graphics2D.setFont(FONT); + FontMetrics metrics = graphics2D.getFontMetrics(FONT); + String value = String.valueOf(puzzleElement.getData()); + int xText = location.x + (size.width - metrics.stringWidth(value)) / 2; + int yText = + location.y + ((size.height - metrics.getHeight()) / 2) + metrics.getAscent(); graphics2D.drawString(String.valueOf(puzzleElement.getData()), xText, yText); - } - else { + } else { if (type == BinaryType.ONE) { 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); - FontMetrics metrics = graphics2D.getFontMetrics(FONT); - String value = String.valueOf(puzzleElement.getData()); - int xText = location.x + (size.width - metrics.stringWidth(value)) / 2; - int yText = location.y + ((size.height - metrics.getHeight()) / 2) + metrics.getAscent(); + graphics2D.setColor(FONT_COLOR); + graphics2D.setFont(FONT); + FontMetrics metrics = graphics2D.getFontMetrics(FONT); + String value = String.valueOf(puzzleElement.getData()); + int xText = location.x + (size.width - metrics.stringWidth(value)) / 2; + int yText = + location.y + + ((size.height - metrics.getHeight()) / 2) + + metrics.getAscent(); graphics2D.drawString(String.valueOf(puzzleElement.getData()), xText, yText); - - } - else { + + } else { if (type == BinaryType.UNKNOWN) { graphics2D.setStroke(new BasicStroke(0)); graphics2D.setColor(Color.WHITE); diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryExporter.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryExporter.java index 2f79d61b2..cd58314b6 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryExporter.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryExporter.java @@ -15,8 +15,7 @@ protected org.w3c.dom.Element createBoardElement(Document newDocument) { BinaryBoard board; if (puzzle.getTree() != null) { board = (BinaryBoard) puzzle.getTree().getRootNode().getBoard(); - } - else { + } else { board = (BinaryBoard) puzzle.getBoardView().getBoard(); } @@ -28,7 +27,8 @@ protected org.w3c.dom.Element createBoardElement(Document newDocument) { for (PuzzleElement puzzleElement : board.getPuzzleElements()) { BinaryCell cell = (BinaryCell) puzzleElement; if (cell.getData() != -2) { - org.w3c.dom.Element cellElement = puzzle.getFactory().exportCell(newDocument, puzzleElement); + org.w3c.dom.Element cellElement = + puzzle.getFactory().exportCell(newDocument, puzzleElement); cellsElement.appendChild(cellElement); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryImporter.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryImporter.java index c6839e36c..2fc5b09ef 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryImporter.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryImporter.java @@ -2,12 +2,11 @@ import edu.rpi.legup.model.PuzzleImporter; import edu.rpi.legup.save.InvalidFileFormatException; +import java.awt.*; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; -import java.awt.*; - public class BinaryImporter extends PuzzleImporter { public BinaryImporter(Binary binary) { super(binary); @@ -48,11 +47,13 @@ public void initializeBoard(int rows, int columns) { public void initializeBoard(Node node) throws InvalidFileFormatException { try { if (!node.getNodeName().equalsIgnoreCase("board")) { - throw new InvalidFileFormatException("binary Importer: cannot find board puzzleElement"); + throw new InvalidFileFormatException( + "binary Importer: cannot find board puzzleElement"); } Element boardElement = (Element) node; if (boardElement.getElementsByTagName("cells").getLength() == 0) { - throw new InvalidFileFormatException("binary Importer: no puzzleElement found for board"); + throw new InvalidFileFormatException( + "binary Importer: no puzzleElement found for board"); } Element dataElement = (Element) boardElement.getElementsByTagName("cells").item(0); @@ -62,9 +63,9 @@ public void initializeBoard(Node node) throws InvalidFileFormatException { if (!boardElement.getAttribute("size").isEmpty()) { int size = Integer.valueOf(boardElement.getAttribute("size")); binaryBoard = new BinaryBoard(size); - } - else { - if (!boardElement.getAttribute("width").isEmpty() && !boardElement.getAttribute("height").isEmpty()) { + } else { + if (!boardElement.getAttribute("width").isEmpty() + && !boardElement.getAttribute("height").isEmpty()) { int width = Integer.valueOf(boardElement.getAttribute("width")); int height = Integer.valueOf(boardElement.getAttribute("height")); binaryBoard = new BinaryBoard(width, height); @@ -73,14 +74,16 @@ public void initializeBoard(Node node) throws InvalidFileFormatException { int width = binaryBoard.getWidth(); int height = binaryBoard.getHeight(); - + if (binaryBoard == null || width % 2 != 0 || height % 2 != 0) { throw new InvalidFileFormatException("binary Importer: invalid board dimensions"); } - for (int i = 0; i < elementDataList.getLength(); i++) { - BinaryCell cell = (BinaryCell) puzzle.getFactory().importCell(elementDataList.item(i), binaryBoard); + BinaryCell cell = + (BinaryCell) + puzzle.getFactory() + .importCell(elementDataList.item(i), binaryBoard); Point loc = cell.getLocation(); if (cell.getData() != BinaryType.UNKNOWN.toValue()) { cell.setModifiable(false); @@ -92,7 +95,8 @@ public void initializeBoard(Node node) throws InvalidFileFormatException { for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { if (binaryBoard.getCell(x, y) == null) { - BinaryCell cell = new BinaryCell(BinaryType.UNKNOWN.toValue(), new Point(x, y)); + BinaryCell cell = + new BinaryCell(BinaryType.UNKNOWN.toValue(), new Point(x, y)); cell.setIndex(y * height + x); cell.setModifiable(true); binaryBoard.setCell(x, y, cell); @@ -100,9 +104,9 @@ public void initializeBoard(Node node) throws InvalidFileFormatException { } } puzzle.setCurrentBoard(binaryBoard); - } - catch (NumberFormatException e) { - throw new InvalidFileFormatException("binary Importer: unknown value where integer expected"); + } catch (NumberFormatException e) { + throw new InvalidFileFormatException( + "binary Importer: unknown value where integer expected"); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryType.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryType.java index 32792cf1e..6e3413d7a 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryType.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryType.java @@ -1,7 +1,9 @@ package edu.rpi.legup.puzzle.binary; public enum BinaryType { - ZERO, ONE, UNKNOWN; + ZERO, + ONE, + UNKNOWN; public int toValue() { return this.ordinal(); diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryView.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryView.java index 9e678b003..b11554f28 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryView.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryView.java @@ -3,7 +3,6 @@ import edu.rpi.legup.controller.BoardController; import edu.rpi.legup.model.gameboard.PuzzleElement; import edu.rpi.legup.ui.boardview.GridBoardView; - import java.awt.*; public class BinaryView extends GridBoardView { @@ -17,8 +16,9 @@ public BinaryView(BinaryBoard board) { BinaryElementView elementView = new BinaryElementView(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); } } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/elements/NumberTile.java b/src/main/java/edu/rpi/legup/puzzle/binary/elements/NumberTile.java index e69de29bb..8b1378917 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/elements/NumberTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/elements/NumberTile.java @@ -0,0 +1 @@ + diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java index 50a5eb534..e38c6b78d 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java @@ -2,35 +2,31 @@ 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.rules.ContradictionRule; +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.binary.BinaryBoard; import edu.rpi.legup.puzzle.binary.BinaryCell; -import edu.rpi.legup.puzzle.binary.BinaryType; - -import java.util.Set; -import java.util.HashSet; - public class CompleteRowColumnDirectRule extends DirectRule { public CompleteRowColumnDirectRule() { - super("BINA-BASC-0003", + super( + "BINA-BASC-0003", "Complete Row Column", - "If a row/column of length n contains n/2 of a single value, the remaining cells must contain the other value", + "If a row/column of length n contains n/2 of a single value, the remaining cells must contain the other value", "edu/rpi/legup/images/binary/rules/CompleteRowColumnDirectRule.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) { @@ -40,8 +36,8 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem BinaryBoard modified = origBoard.copy(); BinaryCell c = (BinaryCell) modified.getPuzzleElement(puzzleElement); - //System.out.println("ORIG" + binaryCell.getData()); - //System.out.println("AFTER" + Math.abs(binaryCell.getData() - 1)); + // System.out.println("ORIG" + binaryCell.getData()); + // System.out.println("AFTER" + Math.abs(binaryCell.getData() - 1)); modified.getPuzzleElement(puzzleElement).setData(binaryCell.getData()); System.out.println(contraRule.checkContradictionAt(modified, puzzleElement)); @@ -56,4 +52,4 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem public Board getDefaultBoard(TreeNode node) { return null; } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsOrColumnsContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsOrColumnsContradictionRule.java index 45b7f808a..8b0d88ae4 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsOrColumnsContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsOrColumnsContradictionRule.java @@ -6,16 +6,16 @@ import edu.rpi.legup.puzzle.binary.BinaryBoard; import edu.rpi.legup.puzzle.binary.BinaryCell; import edu.rpi.legup.puzzle.binary.BinaryType; - import java.util.ArrayList; -import java.util.Iterator; -import java.util.Set; + public class DuplicateRowsOrColumnsContradictionRule 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 = "Row or column must have a value in each cell"; public DuplicateRowsOrColumnsContradictionRule() { - super("BINA-CONT-0003", + super( + "BINA-CONT-0003", "Duplicate Rows Or Columns", "There must not be two rows or two columns that are duplicates", "edu/rpi/legup/images/binary/rules/DuplicateRowOrColumnContradictionRule.png"); @@ -25,31 +25,31 @@ public DuplicateRowsOrColumnsContradictionRule() { public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { BinaryBoard binaryBoard = (BinaryBoard) board; BinaryCell cell = (BinaryCell) binaryBoard.getPuzzleElement(puzzleElement); - + ArrayList row = binaryBoard.getRowTypes(cell.getLocation().y); - + int size = row.size(); for (int i = 0; i < size; i++) { if (i > cell.getLocation().y) { ArrayList currRow = binaryBoard.getRowTypes(i); - if (currRow.equals(row)){ - return null; + if (currRow.equals(row)) { + return null; } } } ArrayList col = binaryBoard.getColTypes(cell.getLocation().x); - + for (int i = 0; i < size; i++) { if (i > cell.getLocation().x) { ArrayList currCol = binaryBoard.getColTypes(i); - if (currCol.equals(col)){ - return null; + if (currCol.equals(col)) { + return null; } } } - + return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE; } } diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneOrZeroCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneOrZeroCaseRule.java index 192317e9f..70549cd72 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneOrZeroCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneOrZeroCaseRule.java @@ -8,14 +8,14 @@ import edu.rpi.legup.puzzle.binary.BinaryBoard; import edu.rpi.legup.puzzle.binary.BinaryCell; import edu.rpi.legup.puzzle.binary.BinaryType; - import java.util.ArrayList; import java.util.List; public class OneOrZeroCaseRule extends CaseRule { public OneOrZeroCaseRule() { - super("BINA-CASE-0001", + super( + "BINA-CASE-0001", "One or Zero", "Each blank cell is either a one or a zero.", "edu/rpi/legup/images/binary/rules/OneOrZeroCaseRule.png"); @@ -30,20 +30,23 @@ 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."; } BinaryCell mod1 = (BinaryCell) case1.getBoard().getModifiedData().iterator().next(); BinaryCell mod2 = (BinaryCell) 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() == BinaryType.ZERO && mod2.getType() == BinaryType.ONE) || - (mod2.getType() == BinaryType.ZERO && mod1.getType() == BinaryType.ONE))) { - return super.getInvalidUseOfRuleMessage() + ": This case rule must an empty white and black cell."; + if (!((mod1.getType() == BinaryType.ZERO && mod2.getType() == BinaryType.ONE) + || (mod2.getType() == BinaryType.ZERO && mod1.getType() == BinaryType.ONE))) { + return super.getInvalidUseOfRuleMessage() + + ": This case rule must an empty white and black cell."; } return null; @@ -62,7 +65,6 @@ public CaseBoard getCaseBoard(Board board) { return caseBoard; } - @Override public ArrayList getCases(Board board, PuzzleElement puzzleElement) { ArrayList cases = new ArrayList<>(); @@ -78,11 +80,11 @@ public ArrayList getCases(Board board, PuzzleElement puzzleElement) { case2.addModifiedData(data2); cases.add(case2); - return cases; + return cases; } @Override public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { return null; - } + } } diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java index 221fcad3d..2e1e96fa5 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java @@ -2,35 +2,38 @@ 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.rules.ContradictionRule; +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.binary.BinaryBoard; import edu.rpi.legup.puzzle.binary.BinaryCell; -import edu.rpi.legup.puzzle.binary.BinaryType; - -import java.util.Set; public class OneTileGapDirectRule extends DirectRule { private final String INVALID_USE_MESSAGE = "Number at cell is incorrect"; + public OneTileGapDirectRule() { - super("BINA-BASC-0002", + super( + "BINA-BASC-0002", "One Tile Gap", "If an empty tile is in between the same value, fill the gap with the other value.", "edu/rpi/legup/images/binary/rules/OneTileGapDirectRule.png"); } boolean checkLeftRight(BinaryCell c, BinaryBoard board) { - int x = c.getLocation().x; - int y = c.getLocation().y; - return board.getCell(x - 1, y).getType() != c.getType() || board.getCell(x + 1, y).getType() != c.getType(); + int x = c.getLocation().x; + int y = c.getLocation().y; + return board.getCell(x - 1, y).getType() != c.getType() + || board.getCell(x + 1, y).getType() != c.getType(); } + boolean checkUpDown(BinaryCell c, BinaryBoard board) { - int x = c.getLocation().x; - int y = c.getLocation().y; - return board.getCell(x, y - 1).getType() != c.getType() || board.getCell(x, y + 1).getType() != c.getType(); + int x = c.getLocation().x; + int y = c.getLocation().y; + return board.getCell(x, y - 1).getType() != c.getType() + || board.getCell(x, y + 1).getType() != c.getType(); } + @Override public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { BinaryBoard origBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); @@ -38,8 +41,8 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem BinaryCell binaryCell = (BinaryCell) puzzleElement; BinaryBoard modified = origBoard.copy(); - //System.out.println("ORIG" + binaryCell.getData()); - //System.out.println("AFTER" + Math.abs(binaryCell.getData() - 1)); + // System.out.println("ORIG" + binaryCell.getData()); + // System.out.println("AFTER" + Math.abs(binaryCell.getData() - 1)); modified.getPuzzleElement(puzzleElement).setData(Math.abs(binaryCell.getData() - 1)); PuzzleElement newP = binaryCell; @@ -58,4 +61,4 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem public Board getDefaultBoard(TreeNode node) { return null; } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java index b3fc73b00..dc2f07c8b 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java @@ -2,21 +2,18 @@ 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.rules.ContradictionRule; +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.binary.BinaryBoard; import edu.rpi.legup.puzzle.binary.BinaryCell; -import edu.rpi.legup.puzzle.binary.BinaryType; - -import java.util.ArrayList; -import java.util.Set; public class SurroundPairDirectRule extends DirectRule { public SurroundPairDirectRule() { - super("BINA-BASC-0001", + super( + "BINA-BASC-0001", "Surround Pair", "If two adjacent tiles have the same value, surround the tiles with the other value.", "edu/rpi/legup/images/binary/rules/SurroundPairDirectRule.png"); @@ -28,8 +25,8 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem BinaryCell binaryCell = (BinaryCell) puzzleElement; BinaryBoard modified = origBoard.copy(); - //System.out.println("ORIG" + binaryCell.getData()); - //System.out.println("AFTER" + Math.abs(binaryCell.getData() - 1)); + // System.out.println("ORIG" + binaryCell.getData()); + // System.out.println("AFTER" + Math.abs(binaryCell.getData() - 1)); modified.getPuzzleElement(puzzleElement).setData(Math.abs(binaryCell.getData() - 1)); PuzzleElement newP = binaryCell; diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java index a6f89cf11..075642246 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java @@ -1,4 +1,5 @@ package edu.rpi.legup.puzzle.binary.rules; + import edu.rpi.legup.model.gameboard.Board; import edu.rpi.legup.model.gameboard.PuzzleElement; import edu.rpi.legup.model.rules.ContradictionRule; @@ -7,11 +8,13 @@ import edu.rpi.legup.puzzle.binary.BinaryType; public class ThreeAdjacentContradictionRule 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 zero or one"; public ThreeAdjacentContradictionRule() { - super("BINA-CONT-0001", + super( + "BINA-CONT-0001", "Three Adjacent", "There must not be three adjacent zeros or three adjacent ones in a row or column", "edu/rpi/legup/images/binary/rules/ThreeAdjacentContradictionRule.png"); @@ -35,64 +38,85 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { BinaryCell twoDown = null; BinaryCell twoForward = null; BinaryCell twoBackward = null; - if(binaryBoard.getCell(cellX, cellY + 1) != null){ + if (binaryBoard.getCell(cellX, cellY + 1) != null) { oneUp = binaryBoard.getCell(cellX, cellY + 1); } - if(binaryBoard.getCell(cellX, cellY - 1) != null){ + if (binaryBoard.getCell(cellX, cellY - 1) != null) { oneDown = binaryBoard.getCell(cellX, cellY - 1); } - if(binaryBoard.getCell(cellX + 1, cellY) != null){ + if (binaryBoard.getCell(cellX + 1, cellY) != null) { oneForward = binaryBoard.getCell(cellX + 1, cellY); } - if(binaryBoard.getCell(cellX - 1, cellY) != null){ + if (binaryBoard.getCell(cellX - 1, cellY) != null) { oneBackward = binaryBoard.getCell(cellX - 1, cellY); } - if(binaryBoard.getCell(cellX, cellY + 2) != null){ + if (binaryBoard.getCell(cellX, cellY + 2) != null) { twoUp = binaryBoard.getCell(cellX, cellY + 2); } - if(binaryBoard.getCell(cellX, cellY - 2) != null){ + if (binaryBoard.getCell(cellX, cellY - 2) != null) { twoDown = binaryBoard.getCell(cellX, cellY - 2); } - if(binaryBoard.getCell(cellX + 2, cellY) != null){ + if (binaryBoard.getCell(cellX + 2, cellY) != null) { twoForward = binaryBoard.getCell(cellX + 2, cellY); } - if(binaryBoard.getCell(cellX - 2, cellY) != null){ + if (binaryBoard.getCell(cellX - 2, cellY) != null) { twoBackward = binaryBoard.getCell(cellX - 2, cellY); } - if(cell.getType() == BinaryType.ONE || cell.getType() == BinaryType.ZERO) { - if(twoBackward != null && oneBackward != null && twoBackward.getType() != BinaryType.UNKNOWN && oneBackward.getType() != BinaryType.UNKNOWN) { - if(twoBackward.getType() == cell.getType() && oneBackward.getType() == cell.getType()) { + if (cell.getType() == BinaryType.ONE || cell.getType() == BinaryType.ZERO) { + if (twoBackward != null + && oneBackward != null + && twoBackward.getType() != BinaryType.UNKNOWN + && oneBackward.getType() != BinaryType.UNKNOWN) { + if (twoBackward.getType() == cell.getType() + && oneBackward.getType() == cell.getType()) { System.out.println("1"); return null; } } - if(twoForward != null && oneForward != null && twoForward.getType() != BinaryType.UNKNOWN && oneForward.getType() != BinaryType.UNKNOWN){ - if(twoForward.getType() == cell.getType() && oneForward.getType() == cell.getType()) { + if (twoForward != null + && oneForward != null + && twoForward.getType() != BinaryType.UNKNOWN + && oneForward.getType() != BinaryType.UNKNOWN) { + if (twoForward.getType() == cell.getType() + && oneForward.getType() == cell.getType()) { System.out.println("2"); return null; } } - if(twoDown != null && oneDown != null && twoDown.getType() != BinaryType.UNKNOWN && oneDown.getType() != BinaryType.UNKNOWN) { - if(twoDown.getType() == cell.getType() && oneDown.getType() == cell.getType()){ + if (twoDown != null + && oneDown != null + && twoDown.getType() != BinaryType.UNKNOWN + && oneDown.getType() != BinaryType.UNKNOWN) { + if (twoDown.getType() == cell.getType() && oneDown.getType() == cell.getType()) { System.out.println("3"); return null; } } - if(twoUp != null && oneUp != null && twoUp.getType() != BinaryType.UNKNOWN && oneUp.getType() != BinaryType.UNKNOWN) { - if (twoUp.getType() == cell.getType() && oneUp.getType() == cell.getType()){ + if (twoUp != null + && oneUp != null + && twoUp.getType() != BinaryType.UNKNOWN + && oneUp.getType() != BinaryType.UNKNOWN) { + if (twoUp.getType() == cell.getType() && oneUp.getType() == cell.getType()) { System.out.println("4"); return null; } } - if(oneBackward != null && oneForward != null && oneBackward.getType() != BinaryType.UNKNOWN && oneForward.getType() != BinaryType.UNKNOWN) { - if(oneBackward.getType() == cell.getType() && oneForward.getType() == cell.getType()){ + if (oneBackward != null + && oneForward != null + && oneBackward.getType() != BinaryType.UNKNOWN + && oneForward.getType() != BinaryType.UNKNOWN) { + if (oneBackward.getType() == cell.getType() + && oneForward.getType() == cell.getType()) { System.out.println("5"); return null; } } - if(oneUp != null && oneDown != null && oneUp.getType() != BinaryType.UNKNOWN && oneDown.getType() != BinaryType.UNKNOWN) { - if(oneUp.getType() == cell.getType() && oneDown.getType() == cell.getType()){ + if (oneUp != null + && oneDown != null + && oneUp.getType() != BinaryType.UNKNOWN + && oneDown.getType() != BinaryType.UNKNOWN) { + if (oneUp.getType() == cell.getType() && oneDown.getType() == cell.getType()) { System.out.println("6"); return null; } @@ -100,4 +124,4 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { } return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE; } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowOrColumnContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowOrColumnContradictionRule.java index 8c9c5a161..5089b3b5f 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowOrColumnContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowOrColumnContradictionRule.java @@ -6,15 +6,17 @@ import edu.rpi.legup.puzzle.binary.BinaryBoard; import edu.rpi.legup.puzzle.binary.BinaryCell; import edu.rpi.legup.puzzle.binary.BinaryType; - import java.util.Set; + public class UnbalancedRowOrColumnContradictionRule 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 = "Row or column must have a value in each cell"; public UnbalancedRowOrColumnContradictionRule() { - super("BINA-CONT-0002", + super( + "BINA-CONT-0002", "Unbalanced Row Or Column", "Each row or column must contain an equal number of zeros and ones", "edu/rpi/legup/images/binary/rules/UnbalancedRowColumnContradictionRule.png"); @@ -34,13 +36,12 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { for (BinaryCell item : row) { if (item.getType() == BinaryType.ZERO) { rowNumZeros++; - } - else if(item.getType() == BinaryType.ONE) { + } else if (item.getType() == BinaryType.ONE) { rowNumOnes++; } } - if (rowNumZeros == size/2 && rowNumOnes == size/2) { + if (rowNumZeros == size / 2 && rowNumOnes == size / 2) { return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE; } @@ -53,16 +54,15 @@ else if(item.getType() == BinaryType.ONE) { for (BinaryCell item : col) { if (item.getType() == BinaryType.ZERO) { colNumZeros++; - } - else if(item.getType() == BinaryType.ONE) { + } else if (item.getType() == BinaryType.ONE) { colNumOnes++; } } - if (colNumZeros == size/2 && colNumOnes == size/2) { + if (colNumZeros == size / 2 && colNumOnes == size / 2) { return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE; } return null; } -} \ No newline at end of file +} 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/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 9e41523411aa12e1ce0ed33758902e2f58c46166 Mon Sep 17 00:00:00 2001 From: summerhenson Date: Tue, 16 Apr 2024 17:48:26 -0400 Subject: [PATCH 100/258] Comment out nonfunctional test --- .../puzzles/starbattle/rules/BlackoutDirectRuleTest.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/test/java/puzzles/starbattle/rules/BlackoutDirectRuleTest.java b/src/test/java/puzzles/starbattle/rules/BlackoutDirectRuleTest.java index d42f40c87..7931f0c2e 100644 --- a/src/test/java/puzzles/starbattle/rules/BlackoutDirectRuleTest.java +++ b/src/test/java/puzzles/starbattle/rules/BlackoutDirectRuleTest.java @@ -32,7 +32,8 @@ public static void setUp() { starbattle = new StarBattle(); } - @Test + //Intended to test a valid use of Blackout Direct Rule on a column - does not work + /* @Test public void BlackoutDirectRuleTest_ColumnBlackout() throws InvalidFileFormatException { TestUtilities.importTestBoard("puzzles/starbattle/rules/BlackoutDirectRule/ColumnBlackout", starbattle); TreeNode rootNode = starbattle.getTree().getRootNode(); @@ -65,5 +66,5 @@ public void BlackoutDirectRuleTest_ColumnBlackout() throws InvalidFileFormatExce } } } - } + }*/ } From 277a2b93266f9c575f45632c7d533fd84142ec5c Mon Sep 17 00:00:00 2001 From: Bram van Heuveln Date: Sun, 5 May 2024 17:46:57 +0000 Subject: [PATCH 101/258] 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); From 9c121cc5114ac538bc8707fbd49b7ebf9f590e8f Mon Sep 17 00:00:00 2001 From: Bram van Heuveln Date: Sun, 5 May 2024 18:04:06 +0000 Subject: [PATCH 102/258] 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); From d85b9ab82ed0918fdbc02c17e874ab7dda50cedb Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Tue, 4 Jun 2024 15:26:54 -0400 Subject: [PATCH 103/258] Test commit --- src/main/java/edu/rpi/legup/puzzle/binary/Binary.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/Binary.java b/src/main/java/edu/rpi/legup/puzzle/binary/Binary.java index 773513cda..edeeecc83 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/Binary.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/Binary.java @@ -68,4 +68,6 @@ public boolean isBoardComplete(Board board) { @Override public void onBoardChange(Board board) {} + + // TEST } From d2b379857babdf342879d688b429e5f955a91f8d Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Thu, 6 Jun 2024 19:39:30 -0400 Subject: [PATCH 104/258] Fixed Surround Pair bug, worked when one tile gap was supposed to be used --- .../binary/rules/OneTileGapDirectRule.java | 2 +- .../binary/rules/SurroundPairDirectRule.java | 13 ++-- .../rules/ThreeAdjacentContradictionRule.java | 72 ++++++++++++++----- 3 files changed, 62 insertions(+), 25 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java index 2e1e96fa5..07aa8f8b4 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java @@ -47,7 +47,7 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem PuzzleElement newP = binaryCell; - System.out.println(contraRule.checkContradictionAt(modified, newP)); + // System.out.println(contraRule.checkContradictionAt(modified, newP)); if (contraRule.checkContradictionAt(modified, newP) == null) { return null; diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java index dc2f07c8b..84cbaa964 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java @@ -21,21 +21,22 @@ public SurroundPairDirectRule() { public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { BinaryBoard origBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); - ContradictionRule contraRule = new ThreeAdjacentContradictionRule(); + ThreeAdjacentContradictionRule contraRule = new ThreeAdjacentContradictionRule(); BinaryCell binaryCell = (BinaryCell) puzzleElement; BinaryBoard modified = origBoard.copy(); - // System.out.println("ORIG" + binaryCell.getData()); - // System.out.println("AFTER" + Math.abs(binaryCell.getData() - 1)); modified.getPuzzleElement(puzzleElement).setData(Math.abs(binaryCell.getData() - 1)); - PuzzleElement newP = binaryCell; - System.out.println(contraRule.checkContradictionAt(modified, newP)); + //System.out.println(contraRule.checkContradictionAt(modified, newP)); - if (contraRule.checkContradictionAt(modified, newP) == null) { + if (!contraRule.checkSurroundPair(modified, newP)) { return null; } + +// if (contraRule.checkContradictionAt(modified, newP) == null) { +// return null; +// } modified.getPuzzleElement(puzzleElement).setData(Math.abs(binaryCell.getData() - 1)); return "Grouping of Three Ones or Zeros not found"; diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java index 075642246..08a9324f5 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java @@ -20,14 +20,10 @@ public ThreeAdjacentContradictionRule() { "edu/rpi/legup/images/binary/rules/ThreeAdjacentContradictionRule.png"); } - @Override - public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { + public boolean checkSurroundPair(Board board, PuzzleElement puzzleElement) { BinaryBoard binaryBoard = (BinaryBoard) board; - int height = binaryBoard.getHeight(); - int width = binaryBoard.getWidth(); - BinaryCell cell = (BinaryCell) binaryBoard.getPuzzleElement(puzzleElement); - System.out.println("THE CELL IS : " + cell.getType()); + int cellX = cell.getLocation().x; int cellY = cell.getLocation().y; BinaryCell oneUp = null; @@ -70,8 +66,7 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { && oneBackward.getType() != BinaryType.UNKNOWN) { if (twoBackward.getType() == cell.getType() && oneBackward.getType() == cell.getType()) { - System.out.println("1"); - return null; + return false; } } if (twoForward != null @@ -80,8 +75,7 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { && oneForward.getType() != BinaryType.UNKNOWN) { if (twoForward.getType() == cell.getType() && oneForward.getType() == cell.getType()) { - System.out.println("2"); - return null; + return false; } } if (twoDown != null @@ -89,8 +83,7 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { && twoDown.getType() != BinaryType.UNKNOWN && oneDown.getType() != BinaryType.UNKNOWN) { if (twoDown.getType() == cell.getType() && oneDown.getType() == cell.getType()) { - System.out.println("3"); - return null; + return false; } } if (twoUp != null @@ -98,18 +91,47 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { && twoUp.getType() != BinaryType.UNKNOWN && oneUp.getType() != BinaryType.UNKNOWN) { if (twoUp.getType() == cell.getType() && oneUp.getType() == cell.getType()) { - System.out.println("4"); - return null; + return false; } } + } + + return true; + } + + public boolean checkOneTileGap(Board board, PuzzleElement puzzleElement) { + BinaryBoard binaryBoard = (BinaryBoard) board; + + BinaryCell cell = (BinaryCell) binaryBoard.getPuzzleElement(puzzleElement); + + + int cellX = cell.getLocation().x; + int cellY = cell.getLocation().y; + BinaryCell oneUp = null; + BinaryCell oneDown = null; + BinaryCell oneForward = null; + BinaryCell oneBackward = null; + if (binaryBoard.getCell(cellX, cellY + 1) != null) { + oneUp = binaryBoard.getCell(cellX, cellY + 1); + } + if (binaryBoard.getCell(cellX, cellY - 1) != null) { + oneDown = binaryBoard.getCell(cellX, cellY - 1); + } + if (binaryBoard.getCell(cellX + 1, cellY) != null) { + oneForward = binaryBoard.getCell(cellX + 1, cellY); + } + if (binaryBoard.getCell(cellX - 1, cellY) != null) { + oneBackward = binaryBoard.getCell(cellX - 1, cellY); + } + + if (cell.getType() == BinaryType.ONE || cell.getType() == BinaryType.ZERO) { if (oneBackward != null && oneForward != null && oneBackward.getType() != BinaryType.UNKNOWN && oneForward.getType() != BinaryType.UNKNOWN) { if (oneBackward.getType() == cell.getType() && oneForward.getType() == cell.getType()) { - System.out.println("5"); - return null; + return false; } } if (oneUp != null @@ -117,11 +139,25 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { && oneUp.getType() != BinaryType.UNKNOWN && oneDown.getType() != BinaryType.UNKNOWN) { if (oneUp.getType() == cell.getType() && oneDown.getType() == cell.getType()) { - System.out.println("6"); - return null; + return false; } } } + return true; + } + + @Override + public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { + + boolean surroundPairValid = checkSurroundPair(board, puzzleElement); + if (!surroundPairValid) { + return null; + } + boolean oneTileGapValid = checkOneTileGap(board, puzzleElement); + if (!oneTileGapValid) { + return null; + } + return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE; } } From 320d03cc755300cfecbc08a7218eac93411429ef Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Fri, 7 Jun 2024 12:43:58 -0400 Subject: [PATCH 105/258] Fixed One Tile Gap bug, worked when surround pair was supposed to be used --- .../puzzle/binary/rules/OneTileGapDirectRule.java | 11 ++--------- .../puzzle/binary/rules/SurroundPairDirectRule.java | 10 +--------- .../binary/rules/ThreeAdjacentContradictionRule.java | 2 -- 3 files changed, 3 insertions(+), 20 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java index 07aa8f8b4..86e1b3c94 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java @@ -37,22 +37,15 @@ boolean checkUpDown(BinaryCell c, BinaryBoard board) { @Override public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { BinaryBoard origBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); - ContradictionRule contraRule = new ThreeAdjacentContradictionRule(); + ThreeAdjacentContradictionRule contraRule = new ThreeAdjacentContradictionRule(); BinaryCell binaryCell = (BinaryCell) puzzleElement; BinaryBoard modified = origBoard.copy(); - // System.out.println("ORIG" + binaryCell.getData()); - // System.out.println("AFTER" + Math.abs(binaryCell.getData() - 1)); modified.getPuzzleElement(puzzleElement).setData(Math.abs(binaryCell.getData() - 1)); - PuzzleElement newP = binaryCell; - - // System.out.println(contraRule.checkContradictionAt(modified, newP)); - - if (contraRule.checkContradictionAt(modified, newP) == null) { + if (!contraRule.checkOneTileGap(modified, binaryCell)) { return null; } - modified.getPuzzleElement(puzzleElement).setData(Math.abs(binaryCell.getData() - 1)); return "Grouping of Three Ones or Zeros not found"; } diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java index 84cbaa964..15e984faf 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java @@ -26,19 +26,11 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem BinaryBoard modified = origBoard.copy(); modified.getPuzzleElement(puzzleElement).setData(Math.abs(binaryCell.getData() - 1)); - PuzzleElement newP = binaryCell; - //System.out.println(contraRule.checkContradictionAt(modified, newP)); - - if (!contraRule.checkSurroundPair(modified, newP)) { + if (!contraRule.checkSurroundPair(modified, binaryCell)) { return null; } -// if (contraRule.checkContradictionAt(modified, newP) == null) { -// return null; -// } - modified.getPuzzleElement(puzzleElement).setData(Math.abs(binaryCell.getData() - 1)); - return "Grouping of Three Ones or Zeros not found"; } diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java index 08a9324f5..03e9f8280 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java @@ -101,10 +101,8 @@ public boolean checkSurroundPair(Board board, PuzzleElement puzzleElement) { public boolean checkOneTileGap(Board board, PuzzleElement puzzleElement) { BinaryBoard binaryBoard = (BinaryBoard) board; - BinaryCell cell = (BinaryCell) binaryBoard.getPuzzleElement(puzzleElement); - int cellX = cell.getLocation().x; int cellY = cell.getLocation().y; BinaryCell oneUp = null; From 3abd5817bf9b4e8db77084c15a765f7330c3518f Mon Sep 17 00:00:00 2001 From: summerhenson Date: Fri, 7 Jun 2024 14:14:46 -0400 Subject: [PATCH 106/258] Untested fix for StarBattleBoard copy function --- .../rpi/legup/puzzle/starbattle/StarBattleBoard.java | 11 +++++++++++ 1 file changed, 11 insertions(+) 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 5132f33e4..3b91aee35 100644 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleBoard.java +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleBoard.java @@ -97,14 +97,25 @@ public int rowStars(int rowIndex) { public StarBattleBoard copy() { StarBattleBoard copy = new StarBattleBoard(size, puzzleNum); + for (int r = 0; r < this.regions.size(); ++r) { + StarBattleRegion regionCopy = this.regions.get(r).copy(); + for (StarBattleCell cell: regionCopy.getCells()) { + copy.setCell(cell.getLocation().x, cell.getLocation().y, cell); + } + copy.setRegion(r, regionCopy); + } + /* 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()); } + if (x < this.regions.size()) { copy.regions.add(this.getRegion(x).copy()); } + } + */ for (PuzzleElement e : modifiedData) { copy.getPuzzleElement(e).setModifiable(false); } From 5f7b65cc3cecde61342bc4b43b40149b0267635f Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Fri, 7 Jun 2024 14:32:51 -0400 Subject: [PATCH 107/258] Created a more structured way of fixing OneTileGap and SurroundPair direct rules --- .../binary/rules/OneTileGapDirectRule.java | 14 -- .../rules/ThreeAdjacentContradictionRule.java | 145 ++++++++---------- 2 files changed, 64 insertions(+), 95 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java index 86e1b3c94..fb837a771 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java @@ -20,20 +20,6 @@ public OneTileGapDirectRule() { "edu/rpi/legup/images/binary/rules/OneTileGapDirectRule.png"); } - boolean checkLeftRight(BinaryCell c, BinaryBoard board) { - int x = c.getLocation().x; - int y = c.getLocation().y; - return board.getCell(x - 1, y).getType() != c.getType() - || board.getCell(x + 1, y).getType() != c.getType(); - } - - boolean checkUpDown(BinaryCell c, BinaryBoard board) { - int x = c.getLocation().x; - int y = c.getLocation().y; - return board.getCell(x, y - 1).getType() != c.getType() - || board.getCell(x, y + 1).getType() != c.getType(); - } - @Override public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { BinaryBoard origBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java index 03e9f8280..85fcc32ce 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java @@ -20,77 +20,75 @@ public ThreeAdjacentContradictionRule() { "edu/rpi/legup/images/binary/rules/ThreeAdjacentContradictionRule.png"); } - public boolean checkSurroundPair(Board board, PuzzleElement puzzleElement) { + public BinaryCell[] getCellsXAway(Board board, PuzzleElement puzzleElement, int x) { BinaryBoard binaryBoard = (BinaryBoard) board; BinaryCell cell = (BinaryCell) binaryBoard.getPuzzleElement(puzzleElement); - int cellX = cell.getLocation().x; int cellY = cell.getLocation().y; - BinaryCell oneUp = null; - BinaryCell oneDown = null; - BinaryCell oneForward = null; - BinaryCell oneBackward = null; - BinaryCell twoUp = null; - BinaryCell twoDown = null; - BinaryCell twoForward = null; - BinaryCell twoBackward = null; - if (binaryBoard.getCell(cellX, cellY + 1) != null) { - oneUp = binaryBoard.getCell(cellX, cellY + 1); - } - if (binaryBoard.getCell(cellX, cellY - 1) != null) { - oneDown = binaryBoard.getCell(cellX, cellY - 1); - } - if (binaryBoard.getCell(cellX + 1, cellY) != null) { - oneForward = binaryBoard.getCell(cellX + 1, cellY); - } - if (binaryBoard.getCell(cellX - 1, cellY) != null) { - oneBackward = binaryBoard.getCell(cellX - 1, cellY); - } - if (binaryBoard.getCell(cellX, cellY + 2) != null) { - twoUp = binaryBoard.getCell(cellX, cellY + 2); + + BinaryCell[] cells = new BinaryCell[4]; // [0] up x, [1] down x, [2] forward x, [3] backward x + cells[0] = null; + cells[1] = null; + cells[2] = null; + cells[3] = null; + + if (binaryBoard.getCell(cellX, cellY + x) != null) { + cells[0] = binaryBoard.getCell(cellX, cellY + x); } - if (binaryBoard.getCell(cellX, cellY - 2) != null) { - twoDown = binaryBoard.getCell(cellX, cellY - 2); + if (binaryBoard.getCell(cellX, cellY - x) != null) { + cells[1] = binaryBoard.getCell(cellX, cellY - x); } - if (binaryBoard.getCell(cellX + 2, cellY) != null) { - twoForward = binaryBoard.getCell(cellX + 2, cellY); + if (binaryBoard.getCell(cellX + x, cellY) != null) { + cells[2] = binaryBoard.getCell(cellX + x, cellY); } - if (binaryBoard.getCell(cellX - 2, cellY) != null) { - twoBackward = binaryBoard.getCell(cellX - 2, cellY); + if (binaryBoard.getCell(cellX - x, cellY) != null) { + cells[3] = binaryBoard.getCell(cellX - x, cellY); } + return cells; + } + public boolean checkSurroundPair(Board board, PuzzleElement puzzleElement) { + BinaryBoard binaryBoard = (BinaryBoard) board; + BinaryCell cell = (BinaryCell) binaryBoard.getPuzzleElement(puzzleElement); + + // [0] up x, [1] down x, [2] forward x, [3] backward x + BinaryCell[] cellsOneAway = getCellsXAway(board, puzzleElement, 1); + BinaryCell[] cellsTwoAway = getCellsXAway(board, puzzleElement, 2); + if (cell.getType() == BinaryType.ONE || cell.getType() == BinaryType.ZERO) { - if (twoBackward != null - && oneBackward != null - && twoBackward.getType() != BinaryType.UNKNOWN - && oneBackward.getType() != BinaryType.UNKNOWN) { - if (twoBackward.getType() == cell.getType() - && oneBackward.getType() == cell.getType()) { + if (cellsOneAway[3] != null + && cellsTwoAway[3] != null + && cellsOneAway[3].getType() != BinaryType.UNKNOWN + && cellsTwoAway[3].getType() != BinaryType.UNKNOWN) { + if (cellsOneAway[3].getType() == cell.getType() + && cellsTwoAway[3].getType() == cell.getType()) { return false; } } - if (twoForward != null - && oneForward != null - && twoForward.getType() != BinaryType.UNKNOWN - && oneForward.getType() != BinaryType.UNKNOWN) { - if (twoForward.getType() == cell.getType() - && oneForward.getType() == cell.getType()) { + if (cellsOneAway[2] != null + && cellsTwoAway[2] != null + && cellsOneAway[2].getType() != BinaryType.UNKNOWN + && cellsTwoAway[2].getType() != BinaryType.UNKNOWN) { + if (cellsOneAway[2].getType() == cell.getType() + && cellsTwoAway[2].getType() == cell.getType()) { return false; } } - if (twoDown != null - && oneDown != null - && twoDown.getType() != BinaryType.UNKNOWN - && oneDown.getType() != BinaryType.UNKNOWN) { - if (twoDown.getType() == cell.getType() && oneDown.getType() == cell.getType()) { + if (cellsOneAway[1] != null + && cellsTwoAway[1] != null + && cellsOneAway[1].getType() != BinaryType.UNKNOWN + && cellsTwoAway[1].getType() != BinaryType.UNKNOWN) { + if (cellsOneAway[1].getType() == cell.getType() + && cellsTwoAway[1].getType() == cell.getType()) { return false; } } - if (twoUp != null - && oneUp != null - && twoUp.getType() != BinaryType.UNKNOWN - && oneUp.getType() != BinaryType.UNKNOWN) { - if (twoUp.getType() == cell.getType() && oneUp.getType() == cell.getType()) { + if (cellsOneAway[0] != null + && cellsTwoAway[0] != null + && cellsOneAway[0].getType() != BinaryType.UNKNOWN + && cellsTwoAway[0].getType() != BinaryType.UNKNOWN) { + if (cellsOneAway[0].getType() == cell.getType() + && cellsTwoAway[0].getType() == cell.getType()) { return false; } } @@ -103,40 +101,25 @@ public boolean checkOneTileGap(Board board, PuzzleElement puzzleElement) { BinaryBoard binaryBoard = (BinaryBoard) board; BinaryCell cell = (BinaryCell) binaryBoard.getPuzzleElement(puzzleElement); - int cellX = cell.getLocation().x; - int cellY = cell.getLocation().y; - BinaryCell oneUp = null; - BinaryCell oneDown = null; - BinaryCell oneForward = null; - BinaryCell oneBackward = null; - if (binaryBoard.getCell(cellX, cellY + 1) != null) { - oneUp = binaryBoard.getCell(cellX, cellY + 1); - } - if (binaryBoard.getCell(cellX, cellY - 1) != null) { - oneDown = binaryBoard.getCell(cellX, cellY - 1); - } - if (binaryBoard.getCell(cellX + 1, cellY) != null) { - oneForward = binaryBoard.getCell(cellX + 1, cellY); - } - if (binaryBoard.getCell(cellX - 1, cellY) != null) { - oneBackward = binaryBoard.getCell(cellX - 1, cellY); - } + // [0] up x, [1] down x, [2] forward x, [3] backward x + BinaryCell[] cellsOneAway = getCellsXAway(board, puzzleElement, 1); if (cell.getType() == BinaryType.ONE || cell.getType() == BinaryType.ZERO) { - if (oneBackward != null - && oneForward != null - && oneBackward.getType() != BinaryType.UNKNOWN - && oneForward.getType() != BinaryType.UNKNOWN) { - if (oneBackward.getType() == cell.getType() - && oneForward.getType() == cell.getType()) { + if (cellsOneAway[3] != null + && cellsOneAway[2] != null + && cellsOneAway[3].getType() != BinaryType.UNKNOWN + && cellsOneAway[2].getType() != BinaryType.UNKNOWN) { + if (cellsOneAway[3].getType() == cell.getType() + && cellsOneAway[2].getType() == cell.getType()) { return false; } } - if (oneUp != null - && oneDown != null - && oneUp.getType() != BinaryType.UNKNOWN - && oneDown.getType() != BinaryType.UNKNOWN) { - if (oneUp.getType() == cell.getType() && oneDown.getType() == cell.getType()) { + if (cellsOneAway[1] != null + && cellsOneAway[0] != null + && cellsOneAway[1].getType() != BinaryType.UNKNOWN + && cellsOneAway[0].getType() != BinaryType.UNKNOWN) { + if (cellsOneAway[1].getType() == cell.getType() + && cellsOneAway[0].getType() == cell.getType()) { return false; } } From ebc20df69b879199ea7f9286d825e418f957b2e8 Mon Sep 17 00:00:00 2001 From: summerhenson Date: Fri, 7 Jun 2024 15:15:38 -0400 Subject: [PATCH 108/258] Start first Clashing Orbit contradiction rule test --- .../ClashingOrbitContradictionRuleTest.java | 58 +++++++++++++++++++ .../DirectlyAdjacentCenter | 40 +++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 src/test/java/puzzles/starbattle/rules/ClashingOrbitContradictionRuleTest.java create mode 100644 src/test/resources/puzzles/starbattle.rules/ClashingOrbitContradictionRule/DirectlyAdjacentCenter diff --git a/src/test/java/puzzles/starbattle/rules/ClashingOrbitContradictionRuleTest.java b/src/test/java/puzzles/starbattle/rules/ClashingOrbitContradictionRuleTest.java new file mode 100644 index 000000000..9dd2abb06 --- /dev/null +++ b/src/test/java/puzzles/starbattle/rules/ClashingOrbitContradictionRuleTest.java @@ -0,0 +1,58 @@ +package puzzles.starbattle.rules; + +import edu.rpi.legup.puzzle.nurikabe.NurikabeBoard; +import edu.rpi.legup.puzzle.starbattle.rules.ClashingOrbitContradictionRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +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.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 ClashingOrbitContradictionRuleTest { + + private static final ClashingOrbitContradictionRule RULE = new ClashingOrbitContradictionRule(); + private static StarBattle starBattle; + + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + starBattle = new StarBattle(); + } + + /*Tests the Clashing Orbit contradiction rule*/ + @Test + public void ClashingOrbitContradictionRule_DirectlyAdjacentCenter() + throws InvalidFileFormatException + { + TestUtilities.importTestBoard("puzzles/starbattle.rules/ClashingOrbitContradictionRule/DirectlyAdjacentCenter", starBattle); + TreeNode rootNode = starBattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(1,1); + StarBattleCell cell2 = board.getCell(2,1); + + Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); + + for (int i = 0; i < board.getHeight(); ++i) { + for (int j = 0; j < board.getWidth(); ++j) { + Point point = new Point(j,i); + if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + } + } + } +} diff --git a/src/test/resources/puzzles/starbattle.rules/ClashingOrbitContradictionRule/DirectlyAdjacentCenter b/src/test/resources/puzzles/starbattle.rules/ClashingOrbitContradictionRule/DirectlyAdjacentCenter new file mode 100644 index 000000000..5e37c9eca --- /dev/null +++ b/src/test/resources/puzzles/starbattle.rules/ClashingOrbitContradictionRule/DirectlyAdjacentCenter @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 71cae2b6034bdf36425343df4584276562fe3ed9 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Sat, 8 Jun 2024 15:28:45 -0400 Subject: [PATCH 109/258] Modified CompleteRowColumn to allow multiple cells to be selected to work --- .../rpi/legup/puzzle/binary/BinaryBoard.java | 2 +- .../rules/CompleteRowColumnDirectRule.java | 52 ++++++++++++++++--- ...nbalancedRowOrColumnContradictionRule.java | 2 +- 3 files changed, 47 insertions(+), 9 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java index 35c37b1a1..6bc2b98f1 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java @@ -59,7 +59,7 @@ public ArrayList getColTypes(int colNum) { return col; } - public Set getCol(int colNum) { + public Set getColCells(int colNum) { Set col = new HashSet<>(); for (int i = 0; i < size; i++) { col.add(getCell(colNum, i)); diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java index e38c6b78d..795535352 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java @@ -6,8 +6,12 @@ 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.binary.Binary; import edu.rpi.legup.puzzle.binary.BinaryBoard; import edu.rpi.legup.puzzle.binary.BinaryCell; +import edu.rpi.legup.puzzle.binary.BinaryType; + +import java.util.Set; public class CompleteRowColumnDirectRule extends DirectRule { @@ -31,21 +35,55 @@ public CompleteRowColumnDirectRule() { @Override public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { BinaryBoard origBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); - ContradictionRule contraRule = new UnbalancedRowOrColumnContradictionRule(); BinaryCell binaryCell = (BinaryCell) puzzleElement; BinaryBoard modified = origBoard.copy(); - BinaryCell c = (BinaryCell) modified.getPuzzleElement(puzzleElement); - // System.out.println("ORIG" + binaryCell.getData()); - // System.out.println("AFTER" + Math.abs(binaryCell.getData() - 1)); modified.getPuzzleElement(puzzleElement).setData(binaryCell.getData()); - System.out.println(contraRule.checkContradictionAt(modified, puzzleElement)); - if (contraRule.checkContradictionAt(modified, puzzleElement) != null) { + Set row = modified.getRowCells(binaryCell.getLocation().y); + int size = row.size(); + int rowNumZeros = 0; + int rowNumOnes = 0; + + for (BinaryCell item : row) { + if (item.getType() == BinaryType.ZERO) { + rowNumZeros++; + } else if (item.getType() == BinaryType.ONE) { + rowNumOnes++; + } + } + + if (rowNumZeros == size / 2 && binaryCell.getType() == BinaryType.ONE) { return null; } + else if (rowNumOnes == size / 2 && binaryCell.getType() == BinaryType.ZERO) { + return null; + } + + Set col = modified.getColCells(binaryCell.getLocation().x); + int colNumZeros = 0; + int colNumOnes = 0; + + for (BinaryCell item : col) { + if (item.getType() == BinaryType.ZERO) { + colNumZeros++; + } else if (item.getType() == BinaryType.ONE) { + colNumOnes++; + } + } + + if (colNumZeros == size / 2 && binaryCell.getType() == BinaryType.ONE) { + return null; + } + else if (colNumOnes == size / 2 && binaryCell.getType() == BinaryType.ZERO) { + return null; + } + +// if (contraRule.checkContradictionAt(modified, binaryCell) != null) { +// return null; +// } - return "Grouping of Three Ones or Zeros not found"; + return "Row or column unbalanced"; } @Override diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowOrColumnContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowOrColumnContradictionRule.java index 5089b3b5f..301cc6ec1 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowOrColumnContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowOrColumnContradictionRule.java @@ -45,7 +45,7 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE; } - Set col = binaryBoard.getCol(cell.getLocation().x); + Set col = binaryBoard.getColCells(cell.getLocation().x); size = col.size(); int colNumZeros = 0; From 3431226da0f0a08979deb1bcbdb576bcff367b21 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Sun, 9 Jun 2024 13:35:08 -0400 Subject: [PATCH 110/258] Created puzzle editor functionality for the binary puzzle --- .../edu/rpi/legup/puzzle/binary/Binary.java | 24 ++++++------- .../rpi/legup/puzzle/binary/BinaryCell.java | 34 ++++++++++++++++++ .../puzzle/binary/elements/BlankTile.java | 1 - .../puzzle/binary/elements/NumberTile.java | 13 +++++++ .../puzzle/binary/elements/UnknownTile.java | 13 +++++++ .../binary_elements_reference_sheet.txt | 2 ++ ...nbalancedRowOrColumnContradictionRule.java | 3 ++ .../legup/images/binary/tiles/NumberTile.png | Bin 0 -> 317 bytes .../legup/images/binary/tiles/UnknownTile.png | Bin 0 -> 9733 bytes 9 files changed, 76 insertions(+), 14 deletions(-) delete mode 100644 src/main/java/edu/rpi/legup/puzzle/binary/elements/BlankTile.java create mode 100644 src/main/java/edu/rpi/legup/puzzle/binary/elements/UnknownTile.java create mode 100644 src/main/java/edu/rpi/legup/puzzle/binary/elements/binary_elements_reference_sheet.txt create mode 100644 src/main/resources/edu/rpi/legup/images/binary/tiles/NumberTile.png create mode 100644 src/main/resources/edu/rpi/legup/images/binary/tiles/UnknownTile.png diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/Binary.java b/src/main/java/edu/rpi/legup/puzzle/binary/Binary.java index edeeecc83..42fa27474 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/Binary.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/Binary.java @@ -36,18 +36,6 @@ public Board generatePuzzle(int difficulty) { return null; } - // /** - // * Determines if the given dimensions are valid for Binary - // * - // * @param rows the number of rows - // * @param columns the number of columns - // * @return true if the given dimensions are valid for Binary, false otherwise - // */ - // @Override - // public boolean isValidDimensions(int rows, int columns){ - // return rows >= 2 && rows % 2 == 0 && columns >= 2 && columns % 2 == 0; - // } - @Override public boolean isBoardComplete(Board board) { BinaryBoard binaryBoard = (BinaryBoard) board; @@ -69,5 +57,15 @@ public boolean isBoardComplete(Board board) { @Override public void onBoardChange(Board board) {} - // TEST + /** + * Determines if the given dimensions are valid for Binary + * + * @param rows the number of rows + * @param columns the number of columns + * @return true if the given dimensions are valid for Binary, false otherwise + */ + @Override + public boolean isValidDimensions(int rows, int columns){ + return rows >= 4 && rows % 2 == 0 && rows == columns; + } } diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java index 9007215ad..4fc35ae5b 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java @@ -1,7 +1,9 @@ package edu.rpi.legup.puzzle.binary; +import edu.rpi.legup.model.elements.Element; import edu.rpi.legup.model.gameboard.GridCell; import java.awt.Point; +import java.awt.event.MouseEvent; public class BinaryCell extends GridCell { public BinaryCell(int valueInt, Point location) { @@ -32,4 +34,36 @@ public BinaryCell copy() { copy.setGiven(isGiven); return copy; } + + /** + * Sets the type of this BinaryCell + * + * @param e element to set the type of this binary cell to + */ + @Override + public void setType(Element e, MouseEvent m) { + if (e.getElementName().equals("Number Tile")) { + if (m.getButton() == MouseEvent.BUTTON1) { + if (this.data == 2) { + this.data = 0; + } + else { + this.data = this.data + 1; + } + } + else { + if (m.getButton() == MouseEvent.BUTTON3) { + if (this.data > 0) { + this.data = this.data - 1; + } + else { + this.data = 2; + } + } + } + } + else { // unknown tile + this.data = 2; + } + } } diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/elements/BlankTile.java b/src/main/java/edu/rpi/legup/puzzle/binary/elements/BlankTile.java deleted file mode 100644 index 8b1378917..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/binary/elements/BlankTile.java +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/elements/NumberTile.java b/src/main/java/edu/rpi/legup/puzzle/binary/elements/NumberTile.java index 8b1378917..c2fca82a6 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/elements/NumberTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/elements/NumberTile.java @@ -1 +1,14 @@ +package edu.rpi.legup.puzzle.binary.elements; + +import edu.rpi.legup.model.elements.NonPlaceableElement; + +public class NumberTile extends NonPlaceableElement { + public NumberTile() { + super( + "BINA-UNPL-0001", + "Number Tile", + "A number tile", + "edu/rpi/legup/images/binary/tiles/NumberTile.png"); + } +} \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/elements/UnknownTile.java b/src/main/java/edu/rpi/legup/puzzle/binary/elements/UnknownTile.java new file mode 100644 index 000000000..8554ccad0 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/elements/UnknownTile.java @@ -0,0 +1,13 @@ +package edu.rpi.legup.puzzle.binary.elements; + +import edu.rpi.legup.model.elements.NonPlaceableElement; + +public class UnknownTile extends NonPlaceableElement { + public UnknownTile() { + super( + "BINA-UNPL-0002", + "Unknown Tile", + "A blank tile", + "edu/rpi/legup/images/binary/tiles/UnknownTile.png"); + } +} \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/elements/binary_elements_reference_sheet.txt b/src/main/java/edu/rpi/legup/puzzle/binary/elements/binary_elements_reference_sheet.txt new file mode 100644 index 000000000..d4bd9c8d3 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/elements/binary_elements_reference_sheet.txt @@ -0,0 +1,2 @@ +BINA-UNPL-0001 : NumberTile +BINA-UNPL-0002 : UnknownTile \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowOrColumnContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowOrColumnContradictionRule.java index 301cc6ec1..3688c4866 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowOrColumnContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowOrColumnContradictionRule.java @@ -6,6 +6,8 @@ import edu.rpi.legup.puzzle.binary.BinaryBoard; import edu.rpi.legup.puzzle.binary.BinaryCell; import edu.rpi.legup.puzzle.binary.BinaryType; + +import java.util.ArrayList; import java.util.Set; public class UnbalancedRowOrColumnContradictionRule extends ContradictionRule { @@ -22,6 +24,7 @@ public UnbalancedRowOrColumnContradictionRule() { "edu/rpi/legup/images/binary/rules/UnbalancedRowColumnContradictionRule.png"); } + @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { BinaryBoard binaryBoard = (BinaryBoard) board; diff --git a/src/main/resources/edu/rpi/legup/images/binary/tiles/NumberTile.png b/src/main/resources/edu/rpi/legup/images/binary/tiles/NumberTile.png new file mode 100644 index 0000000000000000000000000000000000000000..3747958477df49950cbccc7342aad3dff1742fca GIT binary patch literal 317 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 QTOg2`(SBUvUiYy70dQO53jhEB literal 0 HcmV?d00001 From bd2709468a47c34be93cb3f1dc5e897ebace6db1 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Sun, 9 Jun 2024 16:55:52 -0400 Subject: [PATCH 111/258] Renamed and created more binary files, updated unknowntile image --- .../6x6 Binary Easy 1} | 0 .../6x6 Binary Easy 2} | 0 .../6x6 Binary Easy 3} | 0 .../6x6 Binary Easy 4} | 0 .../binary/6x6 Binary Easy/6x6 Binary Easy 5 | 47 ++++++++++++++++++ .../6x6 Binary Medium/6x6 Binary Medium 1 | 47 ++++++++++++++++++ .../6x6 Binary Medium/6x6 Binary Medium 2 | 47 ++++++++++++++++++ .../6x6 Binary Medium/6x6 Binary Medium 3 | 47 ++++++++++++++++++ .../legup/images/binary/tiles/UnknownTile.png | Bin 9733 -> 7231 bytes 9 files changed, 188 insertions(+) rename puzzles files/binary/{6x6 easy/089764562 => 6x6 Binary Easy/6x6 Binary Easy 1} (100%) rename puzzles files/binary/{6x6 easy/128903434 => 6x6 Binary Easy/6x6 Binary Easy 2} (100%) rename puzzles files/binary/{6x6 easy/876868768 => 6x6 Binary Easy/6x6 Binary Easy 3} (100%) rename puzzles files/binary/{6x6 easy/927364891 => 6x6 Binary Easy/6x6 Binary Easy 4} (100%) create mode 100644 puzzles files/binary/6x6 Binary Easy/6x6 Binary Easy 5 create mode 100644 puzzles files/binary/6x6 Binary Medium/6x6 Binary Medium 1 create mode 100644 puzzles files/binary/6x6 Binary Medium/6x6 Binary Medium 2 create mode 100644 puzzles files/binary/6x6 Binary Medium/6x6 Binary Medium 3 diff --git a/puzzles files/binary/6x6 easy/089764562 b/puzzles files/binary/6x6 Binary Easy/6x6 Binary Easy 1 similarity index 100% rename from puzzles files/binary/6x6 easy/089764562 rename to puzzles files/binary/6x6 Binary Easy/6x6 Binary Easy 1 diff --git a/puzzles files/binary/6x6 easy/128903434 b/puzzles files/binary/6x6 Binary Easy/6x6 Binary Easy 2 similarity index 100% rename from puzzles files/binary/6x6 easy/128903434 rename to puzzles files/binary/6x6 Binary Easy/6x6 Binary Easy 2 diff --git a/puzzles files/binary/6x6 easy/876868768 b/puzzles files/binary/6x6 Binary Easy/6x6 Binary Easy 3 similarity index 100% rename from puzzles files/binary/6x6 easy/876868768 rename to puzzles files/binary/6x6 Binary Easy/6x6 Binary Easy 3 diff --git a/puzzles files/binary/6x6 easy/927364891 b/puzzles files/binary/6x6 Binary Easy/6x6 Binary Easy 4 similarity index 100% rename from puzzles files/binary/6x6 easy/927364891 rename to puzzles files/binary/6x6 Binary Easy/6x6 Binary Easy 4 diff --git a/puzzles files/binary/6x6 Binary Easy/6x6 Binary Easy 5 b/puzzles files/binary/6x6 Binary Easy/6x6 Binary Easy 5 new file mode 100644 index 000000000..a1ea13988 --- /dev/null +++ b/puzzles files/binary/6x6 Binary Easy/6x6 Binary Easy 5 @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/6x6 Binary Medium/6x6 Binary Medium 1 b/puzzles files/binary/6x6 Binary Medium/6x6 Binary Medium 1 new file mode 100644 index 000000000..a5ab8a2dc --- /dev/null +++ b/puzzles files/binary/6x6 Binary Medium/6x6 Binary Medium 1 @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/6x6 Binary Medium/6x6 Binary Medium 2 b/puzzles files/binary/6x6 Binary Medium/6x6 Binary Medium 2 new file mode 100644 index 000000000..4be5fdaad --- /dev/null +++ b/puzzles files/binary/6x6 Binary Medium/6x6 Binary Medium 2 @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/6x6 Binary Medium/6x6 Binary Medium 3 b/puzzles files/binary/6x6 Binary Medium/6x6 Binary Medium 3 new file mode 100644 index 000000000..eba370cab --- /dev/null +++ b/puzzles files/binary/6x6 Binary Medium/6x6 Binary Medium 3 @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/edu/rpi/legup/images/binary/tiles/UnknownTile.png b/src/main/resources/edu/rpi/legup/images/binary/tiles/UnknownTile.png index 850fbf127f04020fe83c6a4f6db75078967916ea..9ab9f74814c5f66917a5cb278eb94fe937256cd4 100644 GIT binary patch delta 2928 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 QTOg2`(SBUvUiYy70dQO53jhEB From 1a54846370d67491d5283b104ba66cb5e7884c70 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Sun, 9 Jun 2024 17:02:19 -0400 Subject: [PATCH 112/258] Made progress toward a create puzzle button from file list --- .../edu/rpi/legup/ui/ProofEditorPanel.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java b/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java index 645a2c0d7..24d5580c9 100644 --- a/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java +++ b/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java @@ -51,6 +51,7 @@ public class ProofEditorPanel extends LegupPanel implements IHistoryListener { private JMenu file; private JMenuItem newPuzzle, resetPuzzle, + //createPuzzle, saveProofAs, saveProofChange, helpTutorial, @@ -135,6 +136,7 @@ public JMenuBar getMenuBar() { file = new JMenu("File"); newPuzzle = new JMenuItem("Open"); resetPuzzle = new JMenuItem("Reset Puzzle"); + //createPuzzle = new JMenuItem("Create Puzzle"); // genPuzzle = new JMenuItem("Puzzle Generators"); // TODO: implement puzzle // generator saveProofAs = new JMenuItem("Save As"); // create a new file to save @@ -310,6 +312,18 @@ public JMenuBar getMenuBar() { } else { resetPuzzle.setAccelerator(KeyStroke.getKeyStroke('R', InputEvent.CTRL_DOWN_MASK)); } + +// file.add(createPuzzle); +// createPuzzle.addActionListener((ActionEvent) -> openNewPuzzleDialog()); +// if (os.equals("mac")) { +// createPuzzle.setAccelerator( +// KeyStroke.getKeyStroke( +// 'C', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); +// } else { +// createPuzzle.setAccelerator(KeyStroke.getKeyStroke('C', InputEvent.CTRL_DOWN_MASK)); +// } + + file.addSeparator(); file.add(saveProofAs); @@ -554,6 +568,11 @@ public void loadPuzzle(String fileName, File puzzleFile) { } } +// public void openNewPuzzleDialog() { +// CreatePuzzleDialog cpd = new CreatePuzzleDialog(this.frame, new HomePanel); +// cpd.setVisible(true); +// } + /** save the proof in the current file */ private void direct_save() { Puzzle puzzle = GameBoardFacade.getInstance().getPuzzleModule(); From e8a7cbe342d1976ceb2b8af048f89b886ee88e48 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Tue, 11 Jun 2024 13:37:37 -0400 Subject: [PATCH 113/258] Updated home page buttons --- src/main/java/edu/rpi/legup/ui/HomePanel.java | 4 ++-- .../edu/rpi/legup/ui/ProofEditorPanel.java | 20 +------------------ .../edu/rpi/legup/ui/PuzzleEditorPanel.java | 15 +++++++------- 3 files changed, 10 insertions(+), 29 deletions(-) diff --git a/src/main/java/edu/rpi/legup/ui/HomePanel.java b/src/main/java/edu/rpi/legup/ui/HomePanel.java index 11f51eb0e..df50eed91 100644 --- a/src/main/java/edu/rpi/legup/ui/HomePanel.java +++ b/src/main/java/edu/rpi/legup/ui/HomePanel.java @@ -136,7 +136,7 @@ private void initButtons() { this.buttons[0].addActionListener(CursorController.createListener(this, openProofListener)); this.buttons[1] = - new JButton("Create Puzzle") { + new JButton("Create New Puzzle") { { setSize(buttonSize, buttonSize); setMaximumSize(getSize()); @@ -153,7 +153,7 @@ private void initButtons() { this.buttons[1].addActionListener(l -> this.openNewPuzzleDialog()); this.buttons[2] = - new JButton("Edit Puzzle") { + new JButton("Edit Existing Puzzle") { { setSize(buttonSize, buttonSize); setMaximumSize(getSize()); diff --git a/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java b/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java index 24d5580c9..64b9f7e70 100644 --- a/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java +++ b/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java @@ -51,7 +51,6 @@ public class ProofEditorPanel extends LegupPanel implements IHistoryListener { private JMenu file; private JMenuItem newPuzzle, resetPuzzle, - //createPuzzle, saveProofAs, saveProofChange, helpTutorial, @@ -136,14 +135,13 @@ public JMenuBar getMenuBar() { file = new JMenu("File"); newPuzzle = new JMenuItem("Open"); resetPuzzle = new JMenuItem("Reset Puzzle"); - //createPuzzle = new JMenuItem("Create Puzzle"); // genPuzzle = new JMenuItem("Puzzle Generators"); // TODO: implement puzzle // generator saveProofAs = new JMenuItem("Save As"); // create a new file to save saveProofChange = new JMenuItem("Save"); // save to the current file preferences = new JMenuItem("Preferences"); helpTutorial = new JMenuItem("Help"); // jump to web page - exit = new JMenuItem("Exit"); + exit = new JMenuItem("Exit Solve Puzzle"); edit = new JMenu("Edit"); undo = new JMenuItem("Undo"); @@ -313,17 +311,6 @@ public JMenuBar getMenuBar() { resetPuzzle.setAccelerator(KeyStroke.getKeyStroke('R', InputEvent.CTRL_DOWN_MASK)); } -// file.add(createPuzzle); -// createPuzzle.addActionListener((ActionEvent) -> openNewPuzzleDialog()); -// if (os.equals("mac")) { -// createPuzzle.setAccelerator( -// KeyStroke.getKeyStroke( -// 'C', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); -// } else { -// createPuzzle.setAccelerator(KeyStroke.getKeyStroke('C', InputEvent.CTRL_DOWN_MASK)); -// } - - file.addSeparator(); file.add(saveProofAs); @@ -568,11 +555,6 @@ public void loadPuzzle(String fileName, File puzzleFile) { } } -// public void openNewPuzzleDialog() { -// CreatePuzzleDialog cpd = new CreatePuzzleDialog(this.frame, new HomePanel); -// cpd.setVisible(true); -// } - /** save the proof in the current file */ private void direct_save() { Puzzle puzzle = GameBoardFacade.getInstance().getPuzzleModule(); diff --git a/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java b/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java index f50c8d6fc..39efe2f31 100644 --- a/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java +++ b/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java @@ -274,10 +274,10 @@ private void setupToolBar() { lastone = i; } - URL check_and_save = + URL save_and_check = ClassLoader.getSystemClassLoader() .getResource("edu/rpi/legup/images/Legup/Check.png"); - ImageIcon imageIcon = new ImageIcon(check_and_save); + ImageIcon imageIcon = new ImageIcon(save_and_check); Image image = imageIcon.getImage(); imageIcon = new ImageIcon( @@ -286,9 +286,9 @@ private void setupToolBar() { this.TOOLBAR_ICON_SCALE, Image.SCALE_SMOOTH)); - JButton checkandsave = new JButton("check and Save", imageIcon); - checkandsave.setFocusPainted(false); - checkandsave.addActionListener( + JButton saveandcheck = new JButton("Save And Check", imageIcon); + saveandcheck.setFocusPainted(false); + saveandcheck.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { @@ -307,8 +307,7 @@ public void actionPerformed(ActionEvent e) { frame.setTitle(puzzleName + " - " + puzzlename.getName()); } }); - getToolBarButtons()[lastone + 1] = checkandsave; - System.out.println("it is create new file"); + getToolBarButtons()[lastone + 1] = saveandcheck; toolBar = new JToolBar(); toolBar.setFloatable(false); @@ -507,7 +506,7 @@ public void setPuzzleView(Puzzle puzzle) { elementFrame.setElements(puzzle); } - toolBarButtons[ToolbarName.CHECK.ordinal()].setEnabled(true); + //toolBarButtons[ToolbarName.CHECK.ordinal()].setEnabled(true); // toolBarButtons[ToolbarName.SAVE.ordinal()].setEnabled(true); } From b192b79bb3e1953ecb0b05fcd25ce8d0b855ee83 Mon Sep 17 00:00:00 2001 From: offline171 <146153141+offline171@users.noreply.github.com> Date: Tue, 11 Jun 2024 14:10:57 -0400 Subject: [PATCH 114/258] Create 6x6 Star Battle Normal1 visualized (DO NOT OPEN AS A PUZZLE).png Committing files onto correct branch after learning about the differences of team branches --- ...al1 visualized (DO NOT OPEN AS A PUZZLE).png | Bin 0 -> 14302 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 puzzles files/starbattle/6x6 Star Battle 1 star Normal/6x6 Star Battle Normal1 visualized (DO NOT OPEN AS A PUZZLE).png diff --git a/puzzles files/starbattle/6x6 Star Battle 1 star Normal/6x6 Star Battle Normal1 visualized (DO NOT OPEN AS A PUZZLE).png b/puzzles files/starbattle/6x6 Star Battle 1 star Normal/6x6 Star Battle Normal1 visualized (DO NOT OPEN AS A PUZZLE).png new file mode 100644 index 0000000000000000000000000000000000000000..584d081539b5d4cf96eee24d5decf73f12076fb4 GIT binary patch literal 14302 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 c4j(W;vBT|k Date: Tue, 11 Jun 2024 14:22:20 -0400 Subject: [PATCH 115/258] Create 5x5 Star Battle Normal visualized (DO NOT OPEN AS A PUZZLE).png Replacing files --- ...mal visualized (DO NOT OPEN AS A PUZZLE).png | Bin 0 -> 13377 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 puzzles files/starbattle/5x5 Star Battle 1 star Normal/5x5 Star Battle Normal visualized (DO NOT OPEN AS A PUZZLE).png diff --git a/puzzles files/starbattle/5x5 Star Battle 1 star Normal/5x5 Star Battle Normal visualized (DO NOT OPEN AS A PUZZLE).png b/puzzles files/starbattle/5x5 Star Battle 1 star Normal/5x5 Star Battle Normal visualized (DO NOT OPEN AS A PUZZLE).png new file mode 100644 index 0000000000000000000000000000000000000000..5e42c203340e6efe38fdd4b9f27e8959b437ae5f GIT binary patch literal 13377 zcmeI3e^gV~9l&2mNGyaPV#`YkgkUFXnTDD{q)N#6A-@D+&Z<@R5+}msK%7{hG$bSw zl=7p+_6(^)ARckGBCS1&LLuS7WUU1eD|AIjRDLPYP#DG#$=*vy!Z};c8QVXuzCUs} z=e|7Nz2AH9_kQxZ_np`tyVc2o<^TYIQ)EPF0s!E&$Vaz~h?G25C1xOhUJ^v?J^}!a zE6@+__Pty^0C)kBq1+u=r^l5zCxE%UP1e~mnnQQgT(JkboyK3;@v2r+t1)nyStMO^Lj?|V4U|I^9>+QoR^0)hOeeU zGI;sONOD58UzYyi+K|*37B`yW&Stg=1GUPTu^#H(v_2qnBw1JM(U9@f0iJt8R}EKf z5*Dg&sbN8Ge7v7jCIh6Eb)ABrW@W_nlaqpx;&Vcs^w{)>OZr+o9&hTV31ul-UE(j; z*^gGjx7*(r1YT^e%Vz}or+takR1UlfLC`|i?fZRzxu;i>0~89yLir2U)i2u6#@dUG zbBX%rpTe*V;K1;WQp3qdJ6`_ncMNK9h>Pa1fY~&sJ$#k~%Lx7b{bY_oPaRVR zyDBP`vk$hDQ;Nsv))K7}pH& z;+0mY+vmX|h|irP!g+X-isIq1T25zYjV=oj?)x@kYSQ>qpaHO8EzR~rUZ|e|*c!5U zZ2#}M1dAsYPi#%b<`I?$p3gkMXWWSEt-A+lr>A|&CsZnC#d_lMB9w^gR1c>f5QJAU zro5S+_A?~;0cRn1|8E>qUU|a;Kud%M??cCPQA!d!oQtapqIvHi(u3Xucg|Do<>D2B z;hD8W7Y6Qru~k?Z#gxo$S0fKjW+qVebI)>iJw3Rx$Sz7z4Hr-)df|xxiCMXsaP41# z(&o@J;hh82)p)S>B)3IX(C$Exz1^zOJNYPCHRCZT-(5&vfFGxo2-{))f_&=7N`K)Nh zi&Cb33F37zY4aJRn42+jb)1i^y1Inl{r$#TFzA^UH}c6Tnsc@Td>?3QXAB5 zGf0>lL?-Twr^B)F@Os zNPEBgOV2@dstb=n-06R%n|anxJN<+{<-b@enSBpre<`sgX-!8LyzZ@?dp6UOGl-N~ zO4|<|7BRI%mZ-@(o~xS~laKKMB}zv9P1&yP&E1+>I_Q+6lZsyJd|D#m5-k2~vC#8H zgkJY~cYC8SuYA=-pYqBW0CJgTHj1&%6&a0+Q){;N>>t6Nk4=~;uFk1|~Wi-iT1jBJ*vI~uW<|ZWY zS<6$%?@aW?HaS@}s1>lb6M{c(MBpyj>o!==JjopG{0}4TwCwyR0N^@;o&_*P$h6yI zYmi{&*dl^0BG@8=nTNx;PB_=v5N}RHrI>z&$Aj|~eQ51A?3lwui2A6b4v(ZAll1QU+f#*uA z6yts6qe|6}E{@@_2;%Ne@hf~rqPTVHUJRuVH|X~ zR6*I>e{X9@ek{cLEX8@(DUizEw29g*G6eO16{rWyl~|`VnLfSyn-vmRtqYY{~ZyQ~s|K2e_q`UZt#s$yU6x(L`IR6H%OrTy6>XgDU5nm8_$> zfG z2R`Ln-evhb!}*R=!{Mql)xcMCtJ-RjPLujXd~ZSy zy@rdAk4N^CjUJDIv$#Im8R@@04Y<@M{l9--awcq$O}mDM2ZRu474TTsQ6c+Rah}@r aW(gi})m)Wk5(|9Lq!$?$8(Q~kNb*l)w!ydn literal 0 HcmV?d00001 From 9dff936d3b07134f1456477b367f1135756b7c2c Mon Sep 17 00:00:00 2001 From: summerhenson Date: Tue, 11 Jun 2024 14:28:58 -0400 Subject: [PATCH 116/258] Fixed first clashing orbit test --- .../ClashingOrbitContradictionRuleTest.java | 2 +- .../DirectlyAdjacentCenter | 40 ------------------- .../rules}/BlackoutDirectRule/ColumnBlackout | 0 .../rules}/BlackoutDirectRule/RegionBlackout | 0 .../rules}/BlackoutDirectRule/RowBlackout | 0 .../DirectlyAdjacentCenter | 40 +++++++++++++++++++ 6 files changed, 41 insertions(+), 41 deletions(-) delete mode 100644 src/test/resources/puzzles/starbattle.rules/ClashingOrbitContradictionRule/DirectlyAdjacentCenter rename src/test/resources/puzzles/{starbattle.rules => starbattle/rules}/BlackoutDirectRule/ColumnBlackout (100%) rename src/test/resources/puzzles/{starbattle.rules => starbattle/rules}/BlackoutDirectRule/RegionBlackout (100%) rename src/test/resources/puzzles/{starbattle.rules => starbattle/rules}/BlackoutDirectRule/RowBlackout (100%) create mode 100644 src/test/resources/puzzles/starbattle/rules/ClashingOrbitContradictionRule/DirectlyAdjacentCenter diff --git a/src/test/java/puzzles/starbattle/rules/ClashingOrbitContradictionRuleTest.java b/src/test/java/puzzles/starbattle/rules/ClashingOrbitContradictionRuleTest.java index 9dd2abb06..9e9d3a26b 100644 --- a/src/test/java/puzzles/starbattle/rules/ClashingOrbitContradictionRuleTest.java +++ b/src/test/java/puzzles/starbattle/rules/ClashingOrbitContradictionRuleTest.java @@ -32,7 +32,7 @@ public static void setUp() { public void ClashingOrbitContradictionRule_DirectlyAdjacentCenter() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle.rules/ClashingOrbitContradictionRule/DirectlyAdjacentCenter", starBattle); + TestUtilities.importTestBoard("puzzles/starbattle/rules/ClashingOrbitContradictionRule/DirectlyAdjacentCenter", starBattle); TreeNode rootNode = starBattle.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); diff --git a/src/test/resources/puzzles/starbattle.rules/ClashingOrbitContradictionRule/DirectlyAdjacentCenter b/src/test/resources/puzzles/starbattle.rules/ClashingOrbitContradictionRule/DirectlyAdjacentCenter deleted file mode 100644 index 5e37c9eca..000000000 --- a/src/test/resources/puzzles/starbattle.rules/ClashingOrbitContradictionRule/DirectlyAdjacentCenter +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle.rules/BlackoutDirectRule/ColumnBlackout b/src/test/resources/puzzles/starbattle/rules/BlackoutDirectRule/ColumnBlackout similarity index 100% rename from src/test/resources/puzzles/starbattle.rules/BlackoutDirectRule/ColumnBlackout rename to src/test/resources/puzzles/starbattle/rules/BlackoutDirectRule/ColumnBlackout diff --git a/src/test/resources/puzzles/starbattle.rules/BlackoutDirectRule/RegionBlackout b/src/test/resources/puzzles/starbattle/rules/BlackoutDirectRule/RegionBlackout similarity index 100% rename from src/test/resources/puzzles/starbattle.rules/BlackoutDirectRule/RegionBlackout rename to src/test/resources/puzzles/starbattle/rules/BlackoutDirectRule/RegionBlackout diff --git a/src/test/resources/puzzles/starbattle.rules/BlackoutDirectRule/RowBlackout b/src/test/resources/puzzles/starbattle/rules/BlackoutDirectRule/RowBlackout similarity index 100% rename from src/test/resources/puzzles/starbattle.rules/BlackoutDirectRule/RowBlackout rename to src/test/resources/puzzles/starbattle/rules/BlackoutDirectRule/RowBlackout diff --git a/src/test/resources/puzzles/starbattle/rules/ClashingOrbitContradictionRule/DirectlyAdjacentCenter b/src/test/resources/puzzles/starbattle/rules/ClashingOrbitContradictionRule/DirectlyAdjacentCenter new file mode 100644 index 000000000..b57a5989e --- /dev/null +++ b/src/test/resources/puzzles/starbattle/rules/ClashingOrbitContradictionRule/DirectlyAdjacentCenter @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 8d1f230750443c85d425e8c4243bb7aacc0a9881 Mon Sep 17 00:00:00 2001 From: summerhenson Date: Tue, 11 Jun 2024 14:56:42 -0400 Subject: [PATCH 117/258] Finished Clashing Orbit contradiction rule test suite --- .../ClashingOrbitContradictionRuleTest.java | 83 ++++++++++++++++++- .../DiagonallyAdjacent | 40 +++++++++ .../DirectlyAdjacentEdge | 40 +++++++++ .../FalseContradiction | 40 +++++++++ 4 files changed, 202 insertions(+), 1 deletion(-) create mode 100644 src/test/resources/puzzles/starbattle/rules/ClashingOrbitContradictionRule/DiagonallyAdjacent create mode 100644 src/test/resources/puzzles/starbattle/rules/ClashingOrbitContradictionRule/DirectlyAdjacentEdge create mode 100644 src/test/resources/puzzles/starbattle/rules/ClashingOrbitContradictionRule/FalseContradiction diff --git a/src/test/java/puzzles/starbattle/rules/ClashingOrbitContradictionRuleTest.java b/src/test/java/puzzles/starbattle/rules/ClashingOrbitContradictionRuleTest.java index 9e9d3a26b..3db8ca1a2 100644 --- a/src/test/java/puzzles/starbattle/rules/ClashingOrbitContradictionRuleTest.java +++ b/src/test/java/puzzles/starbattle/rules/ClashingOrbitContradictionRuleTest.java @@ -27,7 +27,8 @@ public static void setUp() { starBattle = new StarBattle(); } - /*Tests the Clashing Orbit contradiction rule*/ + /*Tests the Clashing Orbit contradiction rule for directly adjacent stars not at the + edge of the board */ @Test public void ClashingOrbitContradictionRule_DirectlyAdjacentCenter() throws InvalidFileFormatException @@ -55,4 +56,84 @@ public void ClashingOrbitContradictionRule_DirectlyAdjacentCenter() } } } + + /* Tests the Clashing Orbit contradiction rule for diagonally adjacent stars */ + @Test + public void ClashingOrbitContradictionRule_DiagonallyAdjacent() + throws InvalidFileFormatException + { + TestUtilities.importTestBoard("puzzles/starbattle/rules/ClashingOrbitContradictionRule/DiagonallyAdjacent", starBattle); + TreeNode rootNode = starBattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(1,1); + StarBattleCell cell2 = board.getCell(2,2); + + Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); + + for (int i = 0; i < board.getHeight(); ++i) { + for (int j = 0; j < board.getWidth(); ++j) { + Point point = new Point(j,i); + if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + } + } + } + + /*Tests the Clashing Orbit contradiction rule for stars at the edge of the board */ + @Test + public void ClashingOrbitContradictionRule_DirectlyAdjacentEdge() + throws InvalidFileFormatException + { + TestUtilities.importTestBoard("puzzles/starbattle/rules/ClashingOrbitContradictionRule/DirectlyAdjacentEdge", starBattle); + TreeNode rootNode = starBattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(0,0); + StarBattleCell cell2 = board.getCell(1,0); + + Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); + + for (int i = 0; i < board.getHeight(); ++i) { + for (int j = 0; j < board.getWidth(); ++j) { + Point point = new Point(j,i); + if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + } + } + } + + /*Tests the Clashing Orbit contradiction rule for a false contradiction. */ + @Test + public void ClashingOrbitContradictionRule_FalseContradiction() + throws InvalidFileFormatException + { + TestUtilities.importTestBoard("puzzles/starbattle/rules/ClashingOrbitContradictionRule/FalseContradiction", starBattle); + TreeNode rootNode = starBattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + + Assert.assertNotNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); + + for (int i = 0; i < board.getHeight(); ++i) { + for (int j = 0; j < board.getWidth(); ++j) { + Point point = new Point(j,i); + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + } + } } diff --git a/src/test/resources/puzzles/starbattle/rules/ClashingOrbitContradictionRule/DiagonallyAdjacent b/src/test/resources/puzzles/starbattle/rules/ClashingOrbitContradictionRule/DiagonallyAdjacent new file mode 100644 index 000000000..f63daad23 --- /dev/null +++ b/src/test/resources/puzzles/starbattle/rules/ClashingOrbitContradictionRule/DiagonallyAdjacent @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/ClashingOrbitContradictionRule/DirectlyAdjacentEdge b/src/test/resources/puzzles/starbattle/rules/ClashingOrbitContradictionRule/DirectlyAdjacentEdge new file mode 100644 index 000000000..f5a23b081 --- /dev/null +++ b/src/test/resources/puzzles/starbattle/rules/ClashingOrbitContradictionRule/DirectlyAdjacentEdge @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/ClashingOrbitContradictionRule/FalseContradiction b/src/test/resources/puzzles/starbattle/rules/ClashingOrbitContradictionRule/FalseContradiction new file mode 100644 index 000000000..04a4a6f6c --- /dev/null +++ b/src/test/resources/puzzles/starbattle/rules/ClashingOrbitContradictionRule/FalseContradiction @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 307d8ef1bfd7fcb4dc27458d9ecd8eaecb3004f3 Mon Sep 17 00:00:00 2001 From: summerhenson Date: Tue, 11 Jun 2024 15:17:48 -0400 Subject: [PATCH 118/258] Start Too Few Stars contradiction rule test --- .../ClashingOrbitContradictionRuleTest.java | 1 - .../TooFewStarsContradictionRuleTest.java | 27 +++++++++++++ .../rules/TooFewStarsContradictionRule/Column | 40 +++++++++++++++++++ .../rules/TooFewStarsContradictionRule/Region | 40 +++++++++++++++++++ .../rules/TooFewStarsContradictionRule/Row | 40 +++++++++++++++++++ 5 files changed, 147 insertions(+), 1 deletion(-) create mode 100644 src/test/java/puzzles/starbattle/rules/TooFewStarsContradictionRuleTest.java create mode 100644 src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/Column create mode 100644 src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/Region create mode 100644 src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/Row diff --git a/src/test/java/puzzles/starbattle/rules/ClashingOrbitContradictionRuleTest.java b/src/test/java/puzzles/starbattle/rules/ClashingOrbitContradictionRuleTest.java index 3db8ca1a2..84be82fb0 100644 --- a/src/test/java/puzzles/starbattle/rules/ClashingOrbitContradictionRuleTest.java +++ b/src/test/java/puzzles/starbattle/rules/ClashingOrbitContradictionRuleTest.java @@ -1,6 +1,5 @@ package puzzles.starbattle.rules; -import edu.rpi.legup.puzzle.nurikabe.NurikabeBoard; import edu.rpi.legup.puzzle.starbattle.rules.ClashingOrbitContradictionRule; import edu.rpi.legup.model.tree.TreeNode; import edu.rpi.legup.model.tree.TreeTransition; diff --git a/src/test/java/puzzles/starbattle/rules/TooFewStarsContradictionRuleTest.java b/src/test/java/puzzles/starbattle/rules/TooFewStarsContradictionRuleTest.java new file mode 100644 index 000000000..8e682ae06 --- /dev/null +++ b/src/test/java/puzzles/starbattle/rules/TooFewStarsContradictionRuleTest.java @@ -0,0 +1,27 @@ +package puzzles.starbattle.rules; + +import edu.rpi.legup.puzzle.starbattle.rules.ClashingOrbitContradictionRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +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.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 TooFewStarsContradictionRuleTest { + /*Too few stars in column */ + + /*Too few stars in row*/ + + /*Too few stars in region*/ + + /*False contradiction*/ + +} diff --git a/src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/Column b/src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/Column new file mode 100644 index 000000000..6d5d920ca --- /dev/null +++ b/src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/Column @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/Region b/src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/Region new file mode 100644 index 000000000..01f9ba680 --- /dev/null +++ b/src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/Region @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/Row b/src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/Row new file mode 100644 index 000000000..70ca07cef --- /dev/null +++ b/src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/Row @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From aabdd05333e03e6a66f6f43e55200c25236d4c31 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Thu, 13 Jun 2024 13:54:07 -0400 Subject: [PATCH 119/258] Updated toolbar in Puzzle Editor to remove unnecessary buttons --- .../edu/rpi/legup/ui/PuzzleEditorPanel.java | 245 +++++++++++------- 1 file changed, 145 insertions(+), 100 deletions(-) diff --git a/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java b/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java index 39efe2f31..2929ef4ec 100644 --- a/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java +++ b/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java @@ -249,107 +249,152 @@ public void makeVisible() { setMenuBar(); } - private void setupToolBar() { - setToolBarButtons(new JButton[ToolbarName.values().length + 1]); - int lastone = 0; - for (int i = 0; i < ToolbarName.values().length - 1; i++) { - String toolBarName = ToolbarName.values()[i].toString(); - URL resourceLocation = - ClassLoader.getSystemClassLoader() - .getResource("edu/rpi/legup/images/Legup/" + toolBarName + ".png"); - - // Scale the image icons down to make the buttons smaller - ImageIcon imageIcon = new ImageIcon(resourceLocation); - Image image = imageIcon.getImage(); - imageIcon = - new ImageIcon( - image.getScaledInstance( - this.TOOLBAR_ICON_SCALE, - this.TOOLBAR_ICON_SCALE, - Image.SCALE_SMOOTH)); - - JButton button = new JButton(toolBarName, imageIcon); - button.setFocusPainted(false); - getToolBarButtons()[i] = button; - lastone = i; - } - - URL save_and_check = - ClassLoader.getSystemClassLoader() - .getResource("edu/rpi/legup/images/Legup/Check.png"); - ImageIcon imageIcon = new ImageIcon(save_and_check); - Image image = imageIcon.getImage(); - imageIcon = - new ImageIcon( - image.getScaledInstance( - this.TOOLBAR_ICON_SCALE, - this.TOOLBAR_ICON_SCALE, - Image.SCALE_SMOOTH)); - - JButton saveandcheck = new JButton("Save And Check", imageIcon); - saveandcheck.setFocusPainted(false); - saveandcheck.addActionListener( - new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - // savePuzzle(); - String filename = savePuzzle(); - File puzzlename = new File(filename); - System.out.println(filename); - - GameBoardFacade.getInstance().getLegupUI().displayPanel(1); - GameBoardFacade.getInstance() - .getLegupUI() - .getProofEditor() - .loadPuzzle(filename, new File(filename)); - String puzzleName = - GameBoardFacade.getInstance().getPuzzleModule().getName(); - frame.setTitle(puzzleName + " - " + puzzlename.getName()); - } - }); - getToolBarButtons()[lastone + 1] = saveandcheck; - - toolBar = new JToolBar(); - toolBar.setFloatable(false); - toolBar.setRollover(true); - - for (int i = 0; i < getToolBarButtons().length - 1; i++) { - for (int s = 0; s < TOOLBAR_SEPARATOR_BEFORE.length; s++) { - if (i == TOOLBAR_SEPARATOR_BEFORE[s]) { - toolBar.addSeparator(); +// private void setupToolBar() { +// setToolBarButtons(new JButton[ToolbarName.values().length + 1]); +// int lastone = 0; +// for (int i = 0; i < ToolbarName.values().length - 1; i++) { +// String toolBarName = ToolbarName.values()[i].toString(); +// URL resourceLocation = +// ClassLoader.getSystemClassLoader() +// .getResource("edu/rpi/legup/images/Legup/" + toolBarName + ".png"); +// +// // Scale the image icons down to make the buttons smaller +// ImageIcon imageIcon = new ImageIcon(resourceLocation); +// Image image = imageIcon.getImage(); +// imageIcon = +// new ImageIcon( +// image.getScaledInstance( +// this.TOOLBAR_ICON_SCALE, +// this.TOOLBAR_ICON_SCALE, +// Image.SCALE_SMOOTH)); +// +// JButton button = new JButton(toolBarName, imageIcon); +// button.setFocusPainted(false); +// getToolBarButtons()[i] = button; +// lastone = i; +// } +// +// URL save_and_check = +// ClassLoader.getSystemClassLoader() +// .getResource("edu/rpi/legup/images/Legup/Check.png"); +// ImageIcon imageIcon = new ImageIcon(save_and_check); +// Image image = imageIcon.getImage(); +// imageIcon = +// new ImageIcon( +// image.getScaledInstance( +// this.TOOLBAR_ICON_SCALE, +// this.TOOLBAR_ICON_SCALE, +// Image.SCALE_SMOOTH)); +// +// JButton saveandcheck = new JButton("Save And Check", imageIcon); +// saveandcheck.setFocusPainted(false); +// saveandcheck.addActionListener( +// new ActionListener() { +// @Override +// public void actionPerformed(ActionEvent e) { +// // savePuzzle(); +// String filename = savePuzzle(); +// File puzzlename = new File(filename); +// System.out.println(filename); +// +// GameBoardFacade.getInstance().getLegupUI().displayPanel(1); +// GameBoardFacade.getInstance() +// .getLegupUI() +// .getProofEditor() +// .loadPuzzle(filename, new File(filename)); +// String puzzleName = +// GameBoardFacade.getInstance().getPuzzleModule().getName(); +// frame.setTitle(puzzleName + " - " + puzzlename.getName()); +// } +// }); +// getToolBarButtons()[lastone + 1] = saveandcheck; +// +// toolBar = new JToolBar(); +// toolBar.setFloatable(false); +// toolBar.setRollover(true); +// +// for (int i = 0; i < getToolBarButtons().length - 1; i++) { +// for (int s = 0; s < TOOLBAR_SEPARATOR_BEFORE.length; s++) { +// if (i == TOOLBAR_SEPARATOR_BEFORE[s]) { +// toolBar.addSeparator(); +// } +// } +// String toolBarName = ToolbarName.values()[i].toString(); +// +// toolBar.add(getToolBarButtons()[i]); +// getToolBarButtons()[i].setToolTipText(toolBarName); +// +// getToolBarButtons()[i].setVerticalTextPosition(SwingConstants.BOTTOM); +// getToolBarButtons()[i].setHorizontalTextPosition(SwingConstants.CENTER); +// } +// +// // toolBarButtons[ToolbarName.OPEN_PUZZLE.ordinal()].addActionListener((ActionEvent +// // e) -> +// // promptPuzzle()); +// // toolBarButtons[ToolbarName.SAVE.ordinal()].addActionListener((ActionEvent e) -> +// // saveProof()); +// // toolBarButtons[ToolbarName.UNDO.ordinal()].addActionListener((ActionEvent e) -> +// // GameBoardFacade.getInstance().getHistory().undo()); +// // toolBarButtons[ToolbarName.REDO.ordinal()].addActionListener((ActionEvent e) -> +// // GameBoardFacade.getInstance().getHistory().redo()); +// toolBarButtons[ToolbarName.HINT.ordinal()].addActionListener((ActionEvent e) -> {}); +// toolBarButtons[ToolbarName.SUBMIT.ordinal()].addActionListener((ActionEvent e) -> {}); +// toolBarButtons[ToolbarName.DIRECTIONS.ordinal()].addActionListener((ActionEvent e) -> {}); +// +// // toolBarButtons[ToolbarName.SAVE.ordinal()].setEnabled(false); +// // toolBarButtons[ToolbarName.UNDO.ordinal()].setEnabled(false); +// // toolBarButtons[ToolbarName.REDO.ordinal()].setEnabled(false); +// toolBarButtons[ToolbarName.HINT.ordinal()].setEnabled(false); +// toolBarButtons[ToolbarName.SUBMIT.ordinal()].setEnabled(false); +// toolBarButtons[ToolbarName.DIRECTIONS.ordinal()].setEnabled(false); +// +// this.add(toolBar, BorderLayout.NORTH); +// } + +private void setupToolBar() { + setToolBarButtons(new JButton[1]); + + URL save_and_solve = + ClassLoader.getSystemClassLoader() + .getResource("edu/rpi/legup/images/Legup/Check.png"); + ImageIcon imageIcon = new ImageIcon(save_and_solve); + Image image = imageIcon.getImage(); + imageIcon = + new ImageIcon( + image.getScaledInstance( + this.TOOLBAR_ICON_SCALE, + this.TOOLBAR_ICON_SCALE, + Image.SCALE_SMOOTH)); + + JButton saveandsolve = new JButton("Save And Solve", imageIcon); + saveandsolve.setFocusPainted(false); + saveandsolve.addActionListener( + new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + // savePuzzle(); + String filename = savePuzzle(); + File puzzlename = new File(filename); + System.out.println(filename); + + GameBoardFacade.getInstance().getLegupUI().displayPanel(1); + GameBoardFacade.getInstance() + .getLegupUI() + .getProofEditor() + .loadPuzzle(filename, new File(filename)); + String puzzleName = + GameBoardFacade.getInstance().getPuzzleModule().getName(); + frame.setTitle(puzzleName + " - " + puzzlename.getName()); } - } - String toolBarName = ToolbarName.values()[i].toString(); - - toolBar.add(getToolBarButtons()[i]); - getToolBarButtons()[i].setToolTipText(toolBarName); - - getToolBarButtons()[i].setVerticalTextPosition(SwingConstants.BOTTOM); - getToolBarButtons()[i].setHorizontalTextPosition(SwingConstants.CENTER); - } - - // toolBarButtons[ToolbarName.OPEN_PUZZLE.ordinal()].addActionListener((ActionEvent - // e) -> - // promptPuzzle()); - // toolBarButtons[ToolbarName.SAVE.ordinal()].addActionListener((ActionEvent e) -> - // saveProof()); - // toolBarButtons[ToolbarName.UNDO.ordinal()].addActionListener((ActionEvent e) -> - // GameBoardFacade.getInstance().getHistory().undo()); - // toolBarButtons[ToolbarName.REDO.ordinal()].addActionListener((ActionEvent e) -> - // GameBoardFacade.getInstance().getHistory().redo()); - toolBarButtons[ToolbarName.HINT.ordinal()].addActionListener((ActionEvent e) -> {}); - toolBarButtons[ToolbarName.SUBMIT.ordinal()].addActionListener((ActionEvent e) -> {}); - toolBarButtons[ToolbarName.DIRECTIONS.ordinal()].addActionListener((ActionEvent e) -> {}); - - // toolBarButtons[ToolbarName.SAVE.ordinal()].setEnabled(false); - // toolBarButtons[ToolbarName.UNDO.ordinal()].setEnabled(false); - // toolBarButtons[ToolbarName.REDO.ordinal()].setEnabled(false); - toolBarButtons[ToolbarName.HINT.ordinal()].setEnabled(false); - toolBarButtons[ToolbarName.SUBMIT.ordinal()].setEnabled(false); - toolBarButtons[ToolbarName.DIRECTIONS.ordinal()].setEnabled(false); - - this.add(toolBar, BorderLayout.NORTH); - } + }); + getToolBarButtons()[0] = saveandsolve; + + toolBar = new JToolBar(); + toolBar.setFloatable(false); + toolBar.setRollover(true); + toolBar.add(getToolBarButtons()[0]); + this.add(toolBar, BorderLayout.NORTH); +} public void loadPuzzleFromHome(String game, int rows, int columns) throws IllegalArgumentException { From f9f8aa667479e7b57dc434ba2f48cd8b7a3dfd39 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Thu, 13 Jun 2024 14:33:55 -0400 Subject: [PATCH 120/258] Modified Puzzle Editor so if there are no non-placeable elements or placeable elements, the corresponding tab does not appear --- .../legup/ui/puzzleeditorui/elementsview/ElementFrame.java | 7 +++++-- .../legup/ui/puzzleeditorui/elementsview/ElementPanel.java | 3 ++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/ElementFrame.java b/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/ElementFrame.java index e0524f84d..496285ece 100644 --- a/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/ElementFrame.java +++ b/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/ElementFrame.java @@ -57,6 +57,7 @@ protected boolean shouldRotateTabRuns(int i) { setMinimumSize(new Dimension(250, 256)); setPreferredSize(new Dimension(330, 256)); + add(tabbedPane); add(status, BorderLayout.SOUTH); @@ -77,8 +78,10 @@ public void resetSize() { } public void setElements(Puzzle puzzle) { - nonPlaceableElementPanel.setElements(puzzle.getNonPlaceableElements()); - placeableElementPanel.setElements(puzzle.getPlaceableElements()); + if (nonPlaceableElementPanel.setElements(puzzle.getNonPlaceableElements()) == 0) + tabbedPane.remove(0); + if (placeableElementPanel.setElements(puzzle.getPlaceableElements()) == 0) + tabbedPane.remove(1); } public EditorElementController getController() { diff --git a/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/ElementPanel.java b/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/ElementPanel.java index 46198e226..70826d25c 100644 --- a/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/ElementPanel.java +++ b/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/ElementPanel.java @@ -20,7 +20,7 @@ public ElementPanel(ElementFrame eFrame) { setLayout(new WrapLayout()); } - public void setElements(List elements) { + public int setElements(List elements) { this.elements = elements; clearButtons(); @@ -38,6 +38,7 @@ public void setElements(List elements) { add(elementButtons[i]); } revalidate(); + return elements.size(); } protected void clearButtons() { From 7c273d4589ee920e45d94c24966594fa894e94ff Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Thu, 13 Jun 2024 15:09:28 -0400 Subject: [PATCH 121/258] Modified Binary Puzzle File Editor Number Tile and Image --- .../edu/rpi/legup/puzzle/binary/BinaryCell.java | 12 ++++++------ .../puzzle/binary/elements/NumberTile.java | 7 +++---- .../puzzle/binary/elements/UnknownTile.java | 6 +++--- .../binary_elements_reference_sheet.txt | 4 ++-- .../legup/images/binary/tiles/NumberTile.png | Bin 317 -> 370 bytes 5 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java index 4fc35ae5b..6c78034d8 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java @@ -44,20 +44,20 @@ public BinaryCell copy() { public void setType(Element e, MouseEvent m) { if (e.getElementName().equals("Number Tile")) { if (m.getButton() == MouseEvent.BUTTON1) { - if (this.data == 2) { - this.data = 0; + if (this.data == 0) { + this.data = 1; } else { - this.data = this.data + 1; + this.data = 0; } } else { if (m.getButton() == MouseEvent.BUTTON3) { - if (this.data > 0) { - this.data = this.data - 1; + if (this.data == 0) { + this.data = 1; } else { - this.data = 2; + this.data = 0; } } } diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/elements/NumberTile.java b/src/main/java/edu/rpi/legup/puzzle/binary/elements/NumberTile.java index c2fca82a6..5e27d458c 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/elements/NumberTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/elements/NumberTile.java @@ -1,12 +1,11 @@ - package edu.rpi.legup.puzzle.binary.elements; -import edu.rpi.legup.model.elements.NonPlaceableElement; +import edu.rpi.legup.model.elements.PlaceableElement; -public class NumberTile extends NonPlaceableElement { +public class NumberTile extends PlaceableElement { public NumberTile() { super( - "BINA-UNPL-0001", + "BINA-PLAC-0001", "Number Tile", "A number tile", "edu/rpi/legup/images/binary/tiles/NumberTile.png"); diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/elements/UnknownTile.java b/src/main/java/edu/rpi/legup/puzzle/binary/elements/UnknownTile.java index 8554ccad0..d6b0da170 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/elements/UnknownTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/elements/UnknownTile.java @@ -1,11 +1,11 @@ package edu.rpi.legup.puzzle.binary.elements; -import edu.rpi.legup.model.elements.NonPlaceableElement; +import edu.rpi.legup.model.elements.PlaceableElement; -public class UnknownTile extends NonPlaceableElement { +public class UnknownTile extends PlaceableElement { public UnknownTile() { super( - "BINA-UNPL-0002", + "BINA-PLAC-0002", "Unknown Tile", "A blank tile", "edu/rpi/legup/images/binary/tiles/UnknownTile.png"); diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/elements/binary_elements_reference_sheet.txt b/src/main/java/edu/rpi/legup/puzzle/binary/elements/binary_elements_reference_sheet.txt index d4bd9c8d3..b31176b84 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/elements/binary_elements_reference_sheet.txt +++ b/src/main/java/edu/rpi/legup/puzzle/binary/elements/binary_elements_reference_sheet.txt @@ -1,2 +1,2 @@ -BINA-UNPL-0001 : NumberTile -BINA-UNPL-0002 : UnknownTile \ No newline at end of file +BINA-PLAC-0001 : NumberTile +BINA-PLAC-0002 : UnknownTile \ No newline at end of file diff --git a/src/main/resources/edu/rpi/legup/images/binary/tiles/NumberTile.png b/src/main/resources/edu/rpi/legup/images/binary/tiles/NumberTile.png index 3747958477df49950cbccc7342aad3dff1742fca..41fb61dfa57c243c91f79eccd78abb00c0926052 100644 GIT binary patch delta 306 zcmdnX^oePLXMGz3gKQgP>>}Yt1_nlUPZ!6K4Cl8q7`YBB@VJ(K-~T!77N?T5TIQBd zzvVeZZyme7WYM!Jmv(PCUce!KPR_#e`IldD_H0~>ofAtmdiYu|E;O(biEGt)^1eaR zt^Lr89WAMcUf#~yQ|NmrSHMzimG1|>1E;Q9WIZ(VsAs$OE#0#|UUY5Fe}4DQu#iL7 z8UmSnMAqiaeONZ{MZL2A?dc^Z&WZVvXEly<%s`m$ocMl{UY4c=uW?VG*Nv!oyQghl zaPGr7A+Z?MyYE|W{aeHTIsbd=-Ki(=~N}3a@vfu8kS++Ta zA7{O2d3mYneBSx4w=zNMHP=@jn|OQMmmlmQzUD_(ov!-HT{pWRHKU_igZm%5;G5uC laGRlwXnuxmrzN+1W7_Rwl^te~-2wC-gQu&X%Q~loCIIwDd@le1 From 62b7811b85e4f2c2d2c4d7b9bcbb93835ea09065 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Thu, 13 Jun 2024 17:40:09 -0400 Subject: [PATCH 122/258] Fixed FinishRoom case rule bug in Nurikabe so cells are modifiable --- .../binary/rules/OneOrZeroCaseRule.java | 9 +- .../nurikabe/rules/FinishRoomCaseRule.java | 123 ++++++------------ 2 files changed, 45 insertions(+), 87 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneOrZeroCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneOrZeroCaseRule.java index 70549cd72..62230f469 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneOrZeroCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneOrZeroCaseRule.java @@ -32,21 +32,18 @@ public String checkRuleRaw(TreeTransition transition) { 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."; + return super.getInvalidUseOfRuleMessage() + ": This case rule must have 1 modified cell for each case."; } BinaryCell mod1 = (BinaryCell) case1.getBoard().getModifiedData().iterator().next(); BinaryCell mod2 = (BinaryCell) 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() == BinaryType.ZERO && mod2.getType() == BinaryType.ONE) || (mod2.getType() == BinaryType.ZERO && mod1.getType() == BinaryType.ONE))) { - return super.getInvalidUseOfRuleMessage() - + ": This case rule must an empty white and black cell."; + return super.getInvalidUseOfRuleMessage() + ": This case rule must modify an empty cell."; } return null; diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/FinishRoomCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/FinishRoomCaseRule.java index 4901cfa6f..e941922fd 100644 --- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/FinishRoomCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/FinishRoomCaseRule.java @@ -54,7 +54,7 @@ public String checkRuleRaw(TreeTransition transition) { if (childTransitions.size() != legitCases) { return super.getInvalidUseOfRuleMessage() + ": Cases can not be removed from the branch."; - } // stops user from deleting 1 or mose generated cases and still having path show as green + } // stops user from deleting 1 or more generated cases and still having path show as green Set locations = new HashSet<>(); for (TreeTransition t1 : childTransitions) { locations.add( @@ -84,31 +84,20 @@ public CaseBoard getCaseBoard(Board board) { DisjointSets regions = NurikabeUtilities.getNurikabeRegions(nurikabeBoard); nurikabeBoard.setModifiable(false); - for (PuzzleElement element : - nurikabeBoard.getPuzzleElements()) { // loops all puzzle elements - if (((NurikabeCell) element).getType() - == NurikabeType.NUMBER) { // if the tile is a white number block - Set disRow = - regions.getSet( - ((NurikabeCell) element)); // store the row of the white region - boolean only = - true; // placeholder boolean of if the element being tested is the only - // number block in the room or not + for (PuzzleElement element : nurikabeBoard.getPuzzleElements()) { // loops all puzzle elements + if (((NurikabeCell) element).getType() == NurikabeType.NUMBER) { // if the tile is a white number block + Set disRow = regions.getSet(((NurikabeCell) element)); // store the row of the white region + boolean only = true; // placeholder boolean of if the element being tested is the only number block in the room or not + for (NurikabeCell d : disRow) { // loops through tiles in the room + // if found another number tile and it's data is different from the element we're working with if ((d.getType() == NurikabeType.NUMBER) - && !(d.getData() - .equals( - ((NurikabeCell) element) - .getData()))) { // if found another number tile - // and it's data is different - // than the element we're - // working with - only = false; // set only to false + && !(d.getData().equals(((NurikabeCell) element).getData()))) { + only = false; } } - if (disRow.size() + 1 == ((NurikabeCell) element).getData() - && only) { // if size of region is 1 less than the number block and the - // number block is only number block in the region + // if size of region is 1 less than the number block and the number block is only number block in the region + if (disRow.size() + 1 == ((NurikabeCell) element).getData() && only) { caseBoard.addPickableElement(element); // add that room as a pickable element } } @@ -127,15 +116,12 @@ public CaseBoard getCaseBoard(Board board) { public ArrayList getCases(Board board, PuzzleElement puzzleElement) { ArrayList cases = new ArrayList<>(); // makes array list of cases NurikabeBoard nuriBoard = (NurikabeBoard) board.copy(); // nurikabe board to edit - NurikabeCell numbaCell = - nuriBoard.getCell( - ((NurikabeCell) puzzleElement).getLocation().x, - ((NurikabeCell) puzzleElement) - .getLocation() - .y); // number cell whose room we want to fill - int filledRoomSize = numbaCell.getData(); // size of room we want afterward - Set locations = - new HashSet<>(); // locations where white space is added to finish room + NurikabeCell numberCell = nuriBoard.getCell(((NurikabeCell) puzzleElement).getLocation().x, + ((NurikabeCell) puzzleElement).getLocation().y); // number cell whose room we want to fill + + int filledRoomSize = numberCell.getData(); // size of room we want afterward + Set locations = new HashSet<>(); // locations where white space is added to finish room + Point left = new Point(-1, 0); Point right = new Point(1, 0); Point bot = new Point(0, -1); @@ -145,12 +131,10 @@ public ArrayList getCases(Board board, PuzzleElement puzzleElement) { directions.add(right); directions.add(top); directions.add(bot); - Set checkedPoints = - new HashSet<>(); // add all into checked points and continue at start of loop if - // inside - DisjointSets regions = - NurikabeUtilities.getNurikabeRegions(nuriBoard); // gathers regions - Set disRow = regions.getSet(numbaCell); // set of white spaces + + Set checkedPoints = new HashSet<>(); // add all into checked points and continue at start of loop if inside + DisjointSets regions = NurikabeUtilities.getNurikabeRegions(nuriBoard); // gathers regions + Set disRow = regions.getSet(numberCell); // set of white spaces for (NurikabeCell d : disRow) { // loops through white spaces if (cases.size() >= 6) { // no need to check this many cases // throw new IllegalStateException("Too many cases"); @@ -167,64 +151,41 @@ public ArrayList getCases(Board board, PuzzleElement puzzleElement) { && (d.getLocation().y + direction.y >= 0)))) { continue; // if next location check would be outside of grid then continue } - NurikabeCell curr = - nuriBoard.getCell( - d.getLocation().x + direction.x, d.getLocation().y + direction.y); + NurikabeCell curr = nuriBoard.getCell(d.getLocation().x + direction.x, d.getLocation().y + direction.y); if (checkedPoints.contains(curr.getLocation())) { - continue; // if we already checked whether or not making this tile white would - // complete the room then continue + continue; // if we already checked whether making this tile white would complete the room then continue } - checkedPoints.add( - curr.getLocation()); // adds location to checkedPoints so we don't check - // it again and accidentally add - if (curr.getType() - == NurikabeType - .UNKNOWN) { // found adjacent space to region that is currently - // unknown - curr.setData( - NurikabeType.WHITE.toValue()); // changes adjacent cell color to white - nuriBoard.addModifiedData(curr); // adds modified before check + checkedPoints.add(curr.getLocation()); // adds location to checkedPoints so we don't check it again and accidentally add + + if (curr.getType() == NurikabeType.UNKNOWN) { // found adjacent space to region that is currently unknown + curr.setData(NurikabeType.WHITE.toValue()); // changes adjacent cell color to white + //nuriBoard.addModifiedData(curr); // adds modified before check regions = NurikabeUtilities.getNurikabeRegions(nuriBoard); // update regions - Set disCreatedRow = - regions.getSet( - curr); // gets set of created row with new white cell added - if (disCreatedRow.size() - == filledRoomSize) { // If adding white fills the room to exact size of - // number block and doesn't connect with another - // room - Point here = curr.getLocation(); // gets current location of new white tile - // that fills room - boolean alreadyIn = - false; // sets whether or not the tile has already been added to - // false - for (Point p : - locations) { // loops through locations of previously added tiles + Set disCreatedRow = regions.getSet(curr); // gets set of created row with new white cell added + + if (disCreatedRow.size() == filledRoomSize) { // If adding white fills the room to exact size of + // number block and doesn't connect with another room + Point here = curr.getLocation(); // gets current location of new white tile that fills room + boolean alreadyIn = false; // sets whether the tile has already been added to false + for (Point p : locations) { // loops through locations of previously added tiles if (p == here) { // if point is already in alreadyIn = true; // change already in to true break; } } + if (!alreadyIn) { // if point wasn't already in - Board casey = - nuriBoard.copy(); // copy the current board with white tile - // changed - PuzzleElement datacasey = - curr; // gets changed white tile as a puzzle element - datacasey.setData( - NurikabeType.WHITE - .toValue()); // ensure set to white, probably redundant + Board casey = nuriBoard.copy(); // copy the current board with white tile changed + PuzzleElement datacasey = curr; // gets changed white tile as a puzzle element + datacasey.setData(NurikabeType.WHITE.toValue()); // ensure set to white, probably redundant casey.addModifiedData(datacasey); // ensure confirmed white change - regions = - NurikabeUtilities.getNurikabeRegions( - nuriBoard); // update regions + regions = NurikabeUtilities.getNurikabeRegions(nuriBoard); // update regions cases.add(casey); // add this case to list of cases - locations.add( - here); // add location of new white tile to list of locations so - // that we don't accidentally add it again later + locations.add(here); // add location of new white tile to list of locations so + // that we don't accidentally add it again later } } curr.setData(NurikabeType.UNKNOWN.toValue()); // set cell type back to unknown - nuriBoard.addModifiedData(curr); // confirms change back to unknown regions = NurikabeUtilities.getNurikabeRegions(nuriBoard); // updates regions } } From cd17e87b122b0f76b90ef68f959a3cbb2525aa63 Mon Sep 17 00:00:00 2001 From: summerhenson Date: Fri, 14 Jun 2024 13:47:09 -0400 Subject: [PATCH 123/258] Create FalseContradiction --- .../FalseContradiction | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/FalseContradiction diff --git a/src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/FalseContradiction b/src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/FalseContradiction new file mode 100644 index 000000000..782c1d37d --- /dev/null +++ b/src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/FalseContradiction @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From ee22ec01e757bcd4e113ed75f84e3bc5b8f3048c Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Fri, 14 Jun 2024 14:06:49 -0400 Subject: [PATCH 124/258] Created EliminateTheImpossible direct rule --- .../binary/rules/EliminateTheImpossible.java | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossible.java diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossible.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossible.java new file mode 100644 index 000000000..311057f94 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossible.java @@ -0,0 +1,35 @@ +package edu.rpi.legup.puzzle.binary.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.binary.BinaryBoard; +import edu.rpi.legup.puzzle.binary.BinaryCell; + +public class EliminateTheImpossible extends DirectRule { + private final String INVALID_USE_MESSAGE = "Number at cell is incorrect"; + + public EliminateTheImpossible() { + super( + "BINA-BASC-0003", + "Eliminate The Impossible", + "If three adjacent empty cells are open, prevents a trio of numbers to exist", + "edu/rpi/legup/images/binary/rules/OneTileGapDirectRule.png"); + } + + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + BinaryBoard origBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); + BinaryCell binaryCell = (BinaryCell) puzzleElement; + + return "Grouping of Three Ones or Zeros not found"; + } + + @Override + public Board getDefaultBoard(TreeNode node) { + return null; + } +} From 7d02f11f288be2c55e8bcdf1391c6255adcf2e1b Mon Sep 17 00:00:00 2001 From: summerhenson Date: Fri, 14 Jun 2024 14:50:02 -0400 Subject: [PATCH 125/258] Finish Too Few Stars contradiction rule tests --- .../rules/TooFewStarsContradictionRule.java | 5 +- .../ClashingOrbitContradictionRuleTest.java | 3 +- .../TooFewStarsContradictionRuleTest.java | 112 ++++++++++++++++++ .../rules/TooFewStarsContradictionRule/Column | 32 ++--- .../FalseContradiction | 28 ++--- .../rules/TooFewStarsContradictionRule/Region | 28 ++--- .../rules/TooFewStarsContradictionRule/Row | 28 ++--- 7 files changed, 174 insertions(+), 62 deletions(-) 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 e88b7c6b9..100243a65 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 @@ -38,13 +38,14 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { int rowCount = 0; int columnCount = 0; for (int i = 0; i < sbBoard.getSize(); ++i) { - if (sbBoard.getCell(row, i).getType() != StarBattleCellType.BLACK) { + if (sbBoard.getCell(i, row).getType() != StarBattleCellType.BLACK) { ++rowCount; } - if (sbBoard.getCell(i, column).getType() != StarBattleCellType.BLACK) { + if (sbBoard.getCell(column, i).getType() != StarBattleCellType.BLACK) { ++columnCount; } } + if (rowCount < sbBoard.getPuzzleNumber() || columnCount < sbBoard.getPuzzleNumber()) { return null; } diff --git a/src/test/java/puzzles/starbattle/rules/ClashingOrbitContradictionRuleTest.java b/src/test/java/puzzles/starbattle/rules/ClashingOrbitContradictionRuleTest.java index 84be82fb0..ae8aaa08e 100644 --- a/src/test/java/puzzles/starbattle/rules/ClashingOrbitContradictionRuleTest.java +++ b/src/test/java/puzzles/starbattle/rules/ClashingOrbitContradictionRuleTest.java @@ -130,8 +130,7 @@ public void ClashingOrbitContradictionRule_FalseContradiction() for (int i = 0; i < board.getHeight(); ++i) { for (int j = 0; j < board.getWidth(); ++j) { - Point point = new Point(j,i); - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); } } } diff --git a/src/test/java/puzzles/starbattle/rules/TooFewStarsContradictionRuleTest.java b/src/test/java/puzzles/starbattle/rules/TooFewStarsContradictionRuleTest.java index 8e682ae06..2e9f3ddef 100644 --- a/src/test/java/puzzles/starbattle/rules/TooFewStarsContradictionRuleTest.java +++ b/src/test/java/puzzles/starbattle/rules/TooFewStarsContradictionRuleTest.java @@ -7,6 +7,7 @@ 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.TooFewStarsContradictionRule; import edu.rpi.legup.save.InvalidFileFormatException; import java.awt.*; import legup.MockGameBoardFacade; @@ -16,12 +17,123 @@ import org.junit.Test; public class TooFewStarsContradictionRuleTest { + private static final TooFewStarsContradictionRule RULE = new TooFewStarsContradictionRule(); + private static StarBattle starBattle; + + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + starBattle = new StarBattle(); + } + /*Too few stars in column */ + @Test + public void TooFewStarsContradictionRule_Column() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/TooFewStarsContradictionRule/Column", starBattle); + TreeNode rootNode = starBattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(0,0); + StarBattleCell cell2 = board.getCell(0,1); + StarBattleCell cell3 = board.getCell(0,2); + StarBattleCell cell4 = board.getCell(0,3); + + Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); + for (int i = 0; i < board.getHeight(); ++i) { + for (int j = 0; j < board.getWidth(); ++j) { + Point point = new Point(j,i); + if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) || + point.equals(cell3.getLocation()) || point.equals(cell4.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + } + } + + } /*Too few stars in row*/ + @Test + public void TooFewStarsContradictionRule_Row() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/TooFewStarsContradictionRule/Row", starBattle); + TreeNode rootNode = starBattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(0,0); + StarBattleCell cell2 = board.getCell(1,0); + StarBattleCell cell3 = board.getCell(2,0); + StarBattleCell cell4 = board.getCell(3,0); + + Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); + for (int i = 0; i < board.getHeight(); ++i) { + for (int j = 0; j < board.getWidth(); ++j) { + Point point = new Point(j,i); + if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) || + point.equals(cell3.getLocation()) || point.equals(cell4.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + } + } + } /*Too few stars in region*/ + @Test + public void TooFewStarsContradictionRule_Region() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/TooFewStarsContradictionRule/Region", starBattle); + TreeNode rootNode = starBattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(0,0); + StarBattleCell cell2 = board.getCell(0,1); + StarBattleCell cell3 = board.getCell(1,0); + StarBattleCell cell4 = board.getCell(1,1); + + Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); + for (int i = 0; i < board.getHeight(); ++i) { + for (int j = 0; j < board.getWidth(); ++j) { + Point point = new Point(j,i); + if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) || + point.equals(cell3.getLocation()) || point.equals(cell4.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + } + } + } /*False contradiction*/ + @Test + public void TooFewStarsContradictionRule_FalseContradiction() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/TooFewStarsContradictionRule/FalseContradiction", starBattle); + TreeNode rootNode = starBattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + + Assert.assertNotNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); + for (int i = 0; i < board.getHeight(); ++i) { + for (int j = 0; j < board.getWidth(); ++j) { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + } + } } diff --git a/src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/Column b/src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/Column index 6d5d920ca..1d1004b8b 100644 --- a/src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/Column +++ b/src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/Column @@ -4,34 +4,34 @@ - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + diff --git a/src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/FalseContradiction b/src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/FalseContradiction index 782c1d37d..0c377a58b 100644 --- a/src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/FalseContradiction +++ b/src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/FalseContradiction @@ -4,34 +4,34 @@ - - - - + + + + - - - - + + + + - - - + + + - - - + + + diff --git a/src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/Region b/src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/Region index 01f9ba680..2594f46e5 100644 --- a/src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/Region +++ b/src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/Region @@ -4,33 +4,33 @@ - - - - + + + + - - + + - + - - - - + + + + - - - + + + diff --git a/src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/Row b/src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/Row index 70ca07cef..67c36c5e8 100644 --- a/src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/Row +++ b/src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/Row @@ -4,34 +4,34 @@ - - - - + + + + - + - - + + - - - + + + - - - - + + + + From d3a677ea3095d89a1338f02ca5dd083efe4fb4b0 Mon Sep 17 00:00:00 2001 From: offline171 <146153141+offline171@users.noreply.github.com> Date: Fri, 14 Jun 2024 15:43:48 -0400 Subject: [PATCH 126/258] Too Many Stars tests Test cases for Too Many Stars contradiction rule started on with boards and a visualization pdf added as well --- .../TooManyStarsContradictionRuleTests.java | 138 ++++++++++++++++++ .../ColumnOverloaded | 41 ++++++ .../TooManyStarsContradictionRule/Correct | 41 ++++++ .../Region Overloaded Visualized-01.png | Bin 0 -> 15488 bytes .../RegionOverloaded | 41 ++++++ .../RowOverloaded | 41 ++++++ 6 files changed, 302 insertions(+) create mode 100644 src/test/java/puzzles/starbattle/rules/TooManyStarsContradictionRuleTests.java create mode 100644 src/test/resources/puzzles/starbattle/rules/TooManyStarsContradictionRule/ColumnOverloaded create mode 100644 src/test/resources/puzzles/starbattle/rules/TooManyStarsContradictionRule/Correct create mode 100644 src/test/resources/puzzles/starbattle/rules/TooManyStarsContradictionRule/Region Overloaded Visualized-01.png create mode 100644 src/test/resources/puzzles/starbattle/rules/TooManyStarsContradictionRule/RegionOverloaded create mode 100644 src/test/resources/puzzles/starbattle/rules/TooManyStarsContradictionRule/RowOverloaded diff --git a/src/test/java/puzzles/starbattle/rules/TooManyStarsContradictionRuleTests.java b/src/test/java/puzzles/starbattle/rules/TooManyStarsContradictionRuleTests.java new file mode 100644 index 000000000..ac9c99329 --- /dev/null +++ b/src/test/java/puzzles/starbattle/rules/TooManyStarsContradictionRuleTests.java @@ -0,0 +1,138 @@ +package puzzles.starbattle.rules; + +import edu.rpi.legup.puzzle.starbattle.rules.TooManyStarsContradictionRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +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.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 TooManyStarsContradictionRuleTests { + private static final TooManyStarsContradictionRule RULE = new TooManyStarsContradictionRule(); + private static StarBattle starBattle; + + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + starBattle = new StarBattle(); + } + + /* Tests the Too Many Stars contradiction rule where a region has + more stars than the puzzle number */ + @Test + public void TooManyStarsContradictionRule_RegionOverloaded() + throws InvalidFileFormatException + { + TestUtilities.importTestBoard("puzzles/starbattle/rules/TooManyStarsContradictionRule/RegionOverloaded", starBattle); + TreeNode rootNode = starBattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(2,1); + StarBattleCell cell2 = board.getCell(0,2); + + Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); + + for (int i = 0; i < board.getHeight(); ++i) { + for (int j = 0; j < board.getWidth(); ++j) { + Point point = new Point(j,i); + if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + } + } + } + + /* Tests the Too Many Stars contradiction rule where a column has + more stars than the puzzle number */ + @Test + public void TooManyStarsContradictionRule_ColumnOverloaded() + throws InvalidFileFormatException + { + TestUtilities.importTestBoard("puzzles/starbattle/rules/TooManyStarsContradictionRule/ColumnOverloaded", starBattle); + TreeNode rootNode = starBattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(0,0); + StarBattleCell cell2 = board.getCell(0,3); + + Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); + + for (int i = 0; i < board.getHeight(); ++i) { + for (int j = 0; j < board.getWidth(); ++j) { + Point point = new Point(j,i); + if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + } + } + } + /* Tests the Too Many Stars contradiction rule where a row has + more stars than the puzzle number */ + @Test + public void TooManyStarsContradictionRule_RowOverloaded() + throws InvalidFileFormatException + { + TestUtilities.importTestBoard("puzzles/starbattle/rules/TooManyStarsContradictionRule/RowOverloaded", starBattle); + TreeNode rootNode = starBattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(0,0); + StarBattleCell cell2 = board.getCell(3,0); + + Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); + + for (int i = 0; i < board.getHeight(); ++i) { + for (int j = 0; j < board.getWidth(); ++j) { + Point point = new Point(j,i); + if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + } + } + } + /* Tests the Too Many Stars contradiction rule where it is used incorrectly */ + @Test + public void TooManyStarsContradictionRule_Correct() + throws InvalidFileFormatException + { + TestUtilities.importTestBoard("puzzles/starbattle/rules/TooManyStarsContradictionRule/Correct", starBattle); + TreeNode rootNode = starBattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + + Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); + + for (int i = 0; i < board.getHeight(); ++i) { + for (int j = 0; j < board.getWidth(); ++j) { + Point point = new Point(j,i); + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + + } + } + } +} diff --git a/src/test/resources/puzzles/starbattle/rules/TooManyStarsContradictionRule/ColumnOverloaded b/src/test/resources/puzzles/starbattle/rules/TooManyStarsContradictionRule/ColumnOverloaded new file mode 100644 index 000000000..3c2a1f658 --- /dev/null +++ b/src/test/resources/puzzles/starbattle/rules/TooManyStarsContradictionRule/ColumnOverloaded @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/starbattle/rules/TooManyStarsContradictionRule/Correct b/src/test/resources/puzzles/starbattle/rules/TooManyStarsContradictionRule/Correct new file mode 100644 index 000000000..f6b8bd5e1 --- /dev/null +++ b/src/test/resources/puzzles/starbattle/rules/TooManyStarsContradictionRule/Correct @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/starbattle/rules/TooManyStarsContradictionRule/Region Overloaded Visualized-01.png b/src/test/resources/puzzles/starbattle/rules/TooManyStarsContradictionRule/Region Overloaded Visualized-01.png new file mode 100644 index 0000000000000000000000000000000000000000..bfe24d1a4d590cb68956d91e1c94f408f0fde414 GIT binary patch literal 15488 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 literal 0 HcmV?d00001 diff --git a/src/test/resources/puzzles/starbattle/rules/TooManyStarsContradictionRule/RegionOverloaded b/src/test/resources/puzzles/starbattle/rules/TooManyStarsContradictionRule/RegionOverloaded new file mode 100644 index 000000000..12e1a5872 --- /dev/null +++ b/src/test/resources/puzzles/starbattle/rules/TooManyStarsContradictionRule/RegionOverloaded @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/starbattle/rules/TooManyStarsContradictionRule/RowOverloaded b/src/test/resources/puzzles/starbattle/rules/TooManyStarsContradictionRule/RowOverloaded new file mode 100644 index 000000000..c193eadff --- /dev/null +++ b/src/test/resources/puzzles/starbattle/rules/TooManyStarsContradictionRule/RowOverloaded @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 9f42c2d0b4a7e2ff7ffca0e322d8b2e3b432b932 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Fri, 14 Jun 2024 15:57:31 -0400 Subject: [PATCH 127/258] Fixed checkstyle errors in ElementFrame --- .../legup/ui/puzzleeditorui/elementsview/ElementFrame.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/ElementFrame.java b/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/ElementFrame.java index 496285ece..8610facbb 100644 --- a/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/ElementFrame.java +++ b/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/ElementFrame.java @@ -78,10 +78,12 @@ public void resetSize() { } public void setElements(Puzzle puzzle) { - if (nonPlaceableElementPanel.setElements(puzzle.getNonPlaceableElements()) == 0) + if (nonPlaceableElementPanel.setElements(puzzle.getNonPlaceableElements()) == 0) { tabbedPane.remove(0); - if (placeableElementPanel.setElements(puzzle.getPlaceableElements()) == 0) + } + if (placeableElementPanel.setElements(puzzle.getPlaceableElements()) == 0) { tabbedPane.remove(1); + } } public EditorElementController getController() { From 71838a5909f19cc6d1b3cadf7ea328a814182643 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Sun, 16 Jun 2024 17:19:49 -0400 Subject: [PATCH 128/258] Combined placeable elements and nonplaceable elements into just elements, updated all element tiles and reference sheets --- src/main/java/edu/rpi/legup/model/Puzzle.java | 13 - .../rpi/legup/model/elements/ElementType.java | 3 +- .../model/elements/NonPlaceableElement.java | 18 +- .../puzzle/binary/elements/NumberTile.java | 2 +- .../puzzle/binary/elements/UnknownTile.java | 2 +- .../binary_elements_reference_sheet.txt | 4 +- .../puzzle/fillapix/elements/BlackTile.java | 2 +- .../puzzle/fillapix/elements/NumberTile.java | 6 +- .../puzzle/fillapix/elements/UnknownTile.java | 6 +- .../puzzle/fillapix/elements/WhiteTile.java | 2 +- .../fillapix_elements_reference_sheet.txt | 9 +- .../legup/puzzle/lightup/LightUpBoard.java | 6 +- .../puzzle/lightup/elements/BlackTile.java | 6 +- .../puzzle/lightup/elements/BulbTile.java | 2 +- .../puzzle/lightup/elements/NumberTile.java | 8 +- .../puzzle/lightup/elements/UnknownTile.java | 6 +- .../lightup_elements_reference_sheet.txt | 4 + .../rules/TooFewBulbsContradictionRule.java | 2 +- .../puzzle/nurikabe/elements/BlackTile.java | 2 +- .../puzzle/nurikabe/elements/NumberTile.java | 6 +- .../puzzle/nurikabe/elements/UnknownTile.java | 6 +- .../puzzle/nurikabe/elements/WhiteTile.java | 2 +- .../nurikabe_elements_reference_sheet.txt | 4 + .../elements/ArgumentElement.java | 6 +- .../elements/GreenElement.java | 2 +- .../elements/LogicSymbolElement.java | 6 +- .../shorttruthtable/elements/RedElement.java | 2 +- .../elements/UnknownElement.java | 2 +- .../shorttruthtable_elements_reference_sheet | 11 +- .../puzzle/skyscrapers/elements/ClueTile.java | 6 +- .../skyscrapers/elements/NumberTile.java | 6 +- .../skyscrapers/elements/UnknownTile.java | 6 +- .../skyscrapers_elements_reference_sheet.txt | 6 +- .../puzzle/starbattle/elements/BlackTile.java | 6 +- .../puzzle/starbattle/elements/StarTile.java | 6 +- .../starbattle/elements/UnknownTile.java | 6 +- .../puzzle/starbattle/elements/WhiteTile.java | 2 +- .../starbattle_elements_reference_sheet.txt | 4 + .../puzzle/sudoku/elements/NumberTile.java | 2 +- .../sudoku_elements_reference_sheet.txt | 1 + .../puzzle/treetent/elements/GrassTile.java | 2 +- .../puzzle/treetent/elements/TentTile.java | 2 +- .../puzzle/treetent/elements/TreeTile.java | 6 +- .../puzzle/treetent/elements/UnknownTile.java | 6 +- .../treetent_elements_reference_sheet.txt | 4 + src/main/java/edu/rpi/legup/ui/HomePanel.java | 5 + .../edu/rpi/legup/ui/PuzzleEditorPanel.java | 251 ++++++------------ .../elementsview/ElementFrame.java | 68 ++--- .../NonPlaceableElementPanel.java | 30 +-- 49 files changed, 241 insertions(+), 334 deletions(-) create mode 100644 src/main/java/edu/rpi/legup/puzzle/lightup/elements/lightup_elements_reference_sheet.txt create mode 100644 src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/nurikabe_elements_reference_sheet.txt create mode 100644 src/main/java/edu/rpi/legup/puzzle/starbattle/elements/starbattle_elements_reference_sheet.txt create mode 100644 src/main/java/edu/rpi/legup/puzzle/sudoku/elements/sudoku_elements_reference_sheet.txt create mode 100644 src/main/java/edu/rpi/legup/puzzle/treetent/elements/treetent_elements_reference_sheet.txt diff --git a/src/main/java/edu/rpi/legup/model/Puzzle.java b/src/main/java/edu/rpi/legup/model/Puzzle.java index 7971c95af..0f6e928f0 100644 --- a/src/main/java/edu/rpi/legup/model/Puzzle.java +++ b/src/main/java/edu/rpi/legup/model/Puzzle.java @@ -53,7 +53,6 @@ public abstract class Puzzle implements IBoardSubject, ITreeSubject { protected List contradictionRules; protected List caseRules; protected List placeableElements; - protected List nonPlaceableElements; /** Puzzle Constructor - creates a new Puzzle */ public Puzzle() { @@ -65,7 +64,6 @@ public Puzzle() { this.caseRules = new ArrayList<>(); this.placeableElements = new ArrayList<>(); - this.nonPlaceableElements = new ArrayList<>(); registerRules(); registerPuzzleElements(); @@ -95,9 +93,6 @@ private void registerPuzzleElements() { case PLACEABLE: this.addPlaceableElement((PlaceableElement) element); break; - case NONPLACEABLE: - this.addNonPlaceableElement((NonPlaceableElement) element); - break; default: break; } @@ -338,10 +333,6 @@ public List getPlaceableElements() { return placeableElements; } - public List getNonPlaceableElements() { - return nonPlaceableElements; - } - /** * Sets the list of direct rules * @@ -364,10 +355,6 @@ public void addPlaceableElement(PlaceableElement element) { placeableElements.add(element); } - public void addNonPlaceableElement(NonPlaceableElement element) { - nonPlaceableElements.add(element); - } - /** * Remove a basic rule from this Puzzle * diff --git a/src/main/java/edu/rpi/legup/model/elements/ElementType.java b/src/main/java/edu/rpi/legup/model/elements/ElementType.java index dff4fe04f..c71e4c7cd 100644 --- a/src/main/java/edu/rpi/legup/model/elements/ElementType.java +++ b/src/main/java/edu/rpi/legup/model/elements/ElementType.java @@ -1,6 +1,5 @@ package edu.rpi.legup.model.elements; public enum ElementType { - PLACEABLE, - NONPLACEABLE + PLACEABLE } diff --git a/src/main/java/edu/rpi/legup/model/elements/NonPlaceableElement.java b/src/main/java/edu/rpi/legup/model/elements/NonPlaceableElement.java index 4ab0ab509..019001128 100644 --- a/src/main/java/edu/rpi/legup/model/elements/NonPlaceableElement.java +++ b/src/main/java/edu/rpi/legup/model/elements/NonPlaceableElement.java @@ -1,9 +1,9 @@ -package edu.rpi.legup.model.elements; - -public abstract class NonPlaceableElement extends Element { - public NonPlaceableElement( - String elementID, String elementName, String description, String imageName) { - super(elementID, elementName, description, imageName); - this.elementType = ElementType.NONPLACEABLE; - } -} +//package edu.rpi.legup.model.elements; +// +//public abstract class NonPlaceableElement extends Element { +// public NonPlaceableElement( +// String elementID, String elementName, String description, String imageName) { +// super(elementID, elementName, description, imageName); +// this.elementType = ElementType.PLACEABLE; +// } +//} diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/elements/NumberTile.java b/src/main/java/edu/rpi/legup/puzzle/binary/elements/NumberTile.java index 5e27d458c..55040bbc9 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/elements/NumberTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/elements/NumberTile.java @@ -5,7 +5,7 @@ public class NumberTile extends PlaceableElement { public NumberTile() { super( - "BINA-PLAC-0001", + "BINA-ELEM-0001", "Number Tile", "A number tile", "edu/rpi/legup/images/binary/tiles/NumberTile.png"); diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/elements/UnknownTile.java b/src/main/java/edu/rpi/legup/puzzle/binary/elements/UnknownTile.java index d6b0da170..8c60ea8c3 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/elements/UnknownTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/elements/UnknownTile.java @@ -5,7 +5,7 @@ public class UnknownTile extends PlaceableElement { public UnknownTile() { super( - "BINA-PLAC-0002", + "BINA-ELEM-0002", "Unknown Tile", "A blank tile", "edu/rpi/legup/images/binary/tiles/UnknownTile.png"); diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/elements/binary_elements_reference_sheet.txt b/src/main/java/edu/rpi/legup/puzzle/binary/elements/binary_elements_reference_sheet.txt index b31176b84..54db0ee0b 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/elements/binary_elements_reference_sheet.txt +++ b/src/main/java/edu/rpi/legup/puzzle/binary/elements/binary_elements_reference_sheet.txt @@ -1,2 +1,2 @@ -BINA-PLAC-0001 : NumberTile -BINA-PLAC-0002 : UnknownTile \ No newline at end of file +BINA-ELEM-0001 : NumberTile +BINA-ELEM-0002 : UnknownTile \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/BlackTile.java b/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/BlackTile.java index 1d7c038a3..a6993778d 100644 --- a/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/BlackTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/BlackTile.java @@ -5,7 +5,7 @@ public class BlackTile extends PlaceableElement { public BlackTile() { super( - "FPIX-PLAC-0001", + "FPIX-ELEM-0001", "Black Tile", "The black tile", "edu/rpi/legup/images/fillapix/tiles/BlackTile.png"); diff --git a/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/NumberTile.java b/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/NumberTile.java index e869aeaf9..5852c1ad7 100644 --- a/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/NumberTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/NumberTile.java @@ -1,13 +1,13 @@ package edu.rpi.legup.puzzle.fillapix.elements; -import edu.rpi.legup.model.elements.NonPlaceableElement; +import edu.rpi.legup.model.elements.PlaceableElement; -public class NumberTile extends NonPlaceableElement { +public class NumberTile extends PlaceableElement { private int object_num; public NumberTile() { super( - "FPIX-UNPL-0001", + "FPIX-ELEM-0002", "Number Tile", "A numbered tile", "edu/rpi/legup/images/fillapix/tiles/NumberTile.png"); diff --git a/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/UnknownTile.java b/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/UnknownTile.java index 6778c1758..82d0dffb9 100644 --- a/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/UnknownTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/UnknownTile.java @@ -1,11 +1,11 @@ package edu.rpi.legup.puzzle.fillapix.elements; -import edu.rpi.legup.model.elements.NonPlaceableElement; +import edu.rpi.legup.model.elements.PlaceableElement; -public class UnknownTile extends NonPlaceableElement { +public class UnknownTile extends PlaceableElement { public UnknownTile() { super( - "FPIX-UNPL-0002", + "FPIX-ELEM-0003", "Unknown Tile", "A blank tile", "edu/rpi/legup/images/fillapix/tiles/UnknownTile.png"); diff --git a/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/WhiteTile.java b/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/WhiteTile.java index 67065a7e9..b2eedfc09 100644 --- a/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/WhiteTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/WhiteTile.java @@ -5,7 +5,7 @@ public class WhiteTile extends PlaceableElement { public WhiteTile() { super( - "FPIX-PLAC-0002", + "FPIX-ELEM-0004", "White Tile", "The white tile", "edu/rpi/legup/images/fillapix/tiles/WhiteTile.png"); diff --git a/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/fillapix_elements_reference_sheet.txt b/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/fillapix_elements_reference_sheet.txt index 0409fa800..1aece4b97 100644 --- a/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/fillapix_elements_reference_sheet.txt +++ b/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/fillapix_elements_reference_sheet.txt @@ -1,5 +1,4 @@ -FPIX-PLAC-0001 : BlackTile -FPIX-PLAC-0002 : WhiteTile - -FPIX-UNPL-0001 : NumberTile -FPIX-UNPL-0002 : UnknownTile \ No newline at end of file +FPIX-ELEM-0001 : BlackTile +FPIX-ELEM-0002 : NumberTile +FPIX-ELEM-0003 : UnknownTile +FPIX-ELEM-0004 : WhiteTile \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/lightup/LightUpBoard.java b/src/main/java/edu/rpi/legup/puzzle/lightup/LightUpBoard.java index 217ef79a8..21084b8c7 100644 --- a/src/main/java/edu/rpi/legup/puzzle/lightup/LightUpBoard.java +++ b/src/main/java/edu/rpi/legup/puzzle/lightup/LightUpBoard.java @@ -134,12 +134,12 @@ public int getNumAdjLite(LightUpCell cell) { } /** - * Gets the number of adjacent cells that are placable + * Gets the number of adjacent cells that are placeable * * @param cell specified cell - * @return number of adjacent cells that are placable + * @return number of adjacent cells that are placeable */ - public int getNumPlacble(LightUpCell cell) { + public int getNumPlaceable(LightUpCell cell) { int num = 0; Set adjCells = getAdj(cell); for (LightUpCell c : adjCells) { diff --git a/src/main/java/edu/rpi/legup/puzzle/lightup/elements/BlackTile.java b/src/main/java/edu/rpi/legup/puzzle/lightup/elements/BlackTile.java index 2ddb4f754..eed3795d7 100644 --- a/src/main/java/edu/rpi/legup/puzzle/lightup/elements/BlackTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/lightup/elements/BlackTile.java @@ -1,11 +1,11 @@ package edu.rpi.legup.puzzle.lightup.elements; -import edu.rpi.legup.model.elements.NonPlaceableElement; +import edu.rpi.legup.model.elements.PlaceableElement; -public class BlackTile extends NonPlaceableElement { +public class BlackTile extends PlaceableElement { public BlackTile() { super( - "LTUP-UNPL-0002", + "LTUP-ELEM-0001", "Black Tile", "The black tile", "edu/rpi/legup/images/lightup/black.gif"); diff --git a/src/main/java/edu/rpi/legup/puzzle/lightup/elements/BulbTile.java b/src/main/java/edu/rpi/legup/puzzle/lightup/elements/BulbTile.java index d238baa56..61ebac3d0 100644 --- a/src/main/java/edu/rpi/legup/puzzle/lightup/elements/BulbTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/lightup/elements/BulbTile.java @@ -5,7 +5,7 @@ public class BulbTile extends PlaceableElement { public BulbTile() { super( - "LTUP-PLAC-0001", + "LTUP-ELEM-0002", "Bulb Tile", "The bulb tile", "edu/rpi/legup/images/lightup/light.png"); diff --git a/src/main/java/edu/rpi/legup/puzzle/lightup/elements/NumberTile.java b/src/main/java/edu/rpi/legup/puzzle/lightup/elements/NumberTile.java index ae314a4cf..26f9be46c 100644 --- a/src/main/java/edu/rpi/legup/puzzle/lightup/elements/NumberTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/lightup/elements/NumberTile.java @@ -1,15 +1,15 @@ package edu.rpi.legup.puzzle.lightup.elements; -import edu.rpi.legup.model.elements.NonPlaceableElement; +import edu.rpi.legup.model.elements.PlaceableElement; -public class NumberTile extends NonPlaceableElement { +public class NumberTile extends PlaceableElement { int object_number; // Follow the default format and resolves the NoSuchMethod error public NumberTile() { super( - "LTUP-UNPL-0001", + "LTUP-ELEM-0003", "Number Tile", "The number tile", "edu/rpi/legup/images/lightup/1.gif"); @@ -17,7 +17,7 @@ public NumberTile() { public NumberTile(int num) { super( - "LTUP-UNPL-0001", + "LTUP-ELEM-0003", "Number Tile", "The number tile", "edu/rpi/legup/images/lightup/" + num + ".gif"); diff --git a/src/main/java/edu/rpi/legup/puzzle/lightup/elements/UnknownTile.java b/src/main/java/edu/rpi/legup/puzzle/lightup/elements/UnknownTile.java index 24d420fe8..a724be600 100644 --- a/src/main/java/edu/rpi/legup/puzzle/lightup/elements/UnknownTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/lightup/elements/UnknownTile.java @@ -1,11 +1,11 @@ package edu.rpi.legup.puzzle.lightup.elements; -import edu.rpi.legup.model.elements.NonPlaceableElement; +import edu.rpi.legup.model.elements.PlaceableElement; -public class UnknownTile extends NonPlaceableElement { +public class UnknownTile extends PlaceableElement { public UnknownTile() { super( - "LTUP-UNPL-0003", + "LTUP-ELEM-0004", "Unknown Tile", "A blank tile", "edu/rpi/legup/images/lightup/UnknownTile.png"); diff --git a/src/main/java/edu/rpi/legup/puzzle/lightup/elements/lightup_elements_reference_sheet.txt b/src/main/java/edu/rpi/legup/puzzle/lightup/elements/lightup_elements_reference_sheet.txt new file mode 100644 index 000000000..93c97de1c --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/lightup/elements/lightup_elements_reference_sheet.txt @@ -0,0 +1,4 @@ +LTUP-ELEM-0001 : BlackTile +LTUP-ELEM-0002 : BulbTile +LTUP-ELEM-0003 : NumberTile +LTUP-ELEM-0004 : UnknownTile \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/lightup/rules/TooFewBulbsContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/lightup/rules/TooFewBulbsContradictionRule.java index 8cf68e570..de1f85edc 100644 --- a/src/main/java/edu/rpi/legup/puzzle/lightup/rules/TooFewBulbsContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/lightup/rules/TooFewBulbsContradictionRule.java @@ -36,7 +36,7 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { } int bulbs = lightUpBoard.getNumAdj(cell, LightUpCellType.BULB); - int placeable = lightUpBoard.getNumPlacble(cell); + int placeable = lightUpBoard.getNumPlaceable(cell); if (bulbs + placeable < cell.getData()) { return null; diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/BlackTile.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/BlackTile.java index 459a809e0..a7972b9b2 100644 --- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/BlackTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/BlackTile.java @@ -5,7 +5,7 @@ public class BlackTile extends PlaceableElement { public BlackTile() { super( - "NURI-PLAC-0001", + "NURI-ELEM-0001", "Black Tile", "The black tile", "edu/rpi/legup/images/nurikabe/tiles/BlackTile.png"); diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/NumberTile.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/NumberTile.java index 475b278da..2015d990b 100644 --- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/NumberTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/NumberTile.java @@ -1,13 +1,13 @@ package edu.rpi.legup.puzzle.nurikabe.elements; -import edu.rpi.legup.model.elements.NonPlaceableElement; +import edu.rpi.legup.model.elements.PlaceableElement; -public class NumberTile extends NonPlaceableElement { +public class NumberTile extends PlaceableElement { private int object_num; public NumberTile() { super( - "NURI-UNPL-0001", + "NURI-ELEM-0002", "Number Tile", "A numbered tile", "edu/rpi/legup/images/nurikabe/tiles/NumberTile.png"); diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/UnknownTile.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/UnknownTile.java index 85d47e208..8a18c80cc 100644 --- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/UnknownTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/UnknownTile.java @@ -1,11 +1,11 @@ package edu.rpi.legup.puzzle.nurikabe.elements; -import edu.rpi.legup.model.elements.NonPlaceableElement; +import edu.rpi.legup.model.elements.PlaceableElement; -public class UnknownTile extends NonPlaceableElement { +public class UnknownTile extends PlaceableElement { public UnknownTile() { super( - "NURI-UNPL-0002", + "NURI-ELEM-0003", "Unknown Tile", "A blank tile", "edu/rpi/legup/images/nurikabe/tiles/UnknownTile.png"); diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/WhiteTile.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/WhiteTile.java index 35eb63b81..ae07c6d76 100644 --- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/WhiteTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/WhiteTile.java @@ -5,7 +5,7 @@ public class WhiteTile extends PlaceableElement { public WhiteTile() { super( - "NURI-PLAC-0002", + "NURI-ELEM-0004", "White Tile", "The white tile", "edu/rpi/legup/images/nurikabe/tiles/WhiteTile.png"); diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/nurikabe_elements_reference_sheet.txt b/src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/nurikabe_elements_reference_sheet.txt new file mode 100644 index 000000000..667972fd6 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/nurikabe_elements_reference_sheet.txt @@ -0,0 +1,4 @@ +NURI-ELEM-0001 : BlackTile +NURI-ELEM-0002 : NumberTile +NURI-ELEM-0003 : UnknownTile +NURI-ELEM-0004 : WhiteTile diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/ArgumentElement.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/ArgumentElement.java index 9294fba4e..912fd2672 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/ArgumentElement.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/ArgumentElement.java @@ -1,11 +1,11 @@ package edu.rpi.legup.puzzle.shorttruthtable.elements; -import edu.rpi.legup.model.elements.NonPlaceableElement; +import edu.rpi.legup.model.elements.PlaceableElement; -public class ArgumentElement extends NonPlaceableElement { +public class ArgumentElement extends PlaceableElement { public ArgumentElement() { super( - "STTT-UNPL-0001", + "STTT-ELEM-0001", "Argument Element", "Argument of logic statement element", "edu/rpi/legup/images/shorttruthtable/tiles/LetterTile.png"); diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/GreenElement.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/GreenElement.java index 783186baa..56221fef3 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/GreenElement.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/GreenElement.java @@ -5,7 +5,7 @@ public class GreenElement extends PlaceableElement { public GreenElement() { super( - "STTT-PLAC-0001", + "STTT-ELEM-0002", "Green Element", "A green tile to set certain tiles to true", "edu/rpi/legup/images/shorttruthtable/tiles/GreenTile.png"); diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/LogicSymbolElement.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/LogicSymbolElement.java index 5fed4b1df..b82ebc2cb 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/LogicSymbolElement.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/LogicSymbolElement.java @@ -1,11 +1,11 @@ package edu.rpi.legup.puzzle.shorttruthtable.elements; -import edu.rpi.legup.model.elements.NonPlaceableElement; +import edu.rpi.legup.model.elements.PlaceableElement; -public class LogicSymbolElement extends NonPlaceableElement { +public class LogicSymbolElement extends PlaceableElement { public LogicSymbolElement() { super( - "STTT-UNPL-0002", + "STTT-ELEM-0003", "Logic Symbol Element", "Logic symbol element", "edu/rpi/legup/images/shorttruthtable/tiles/ConditionalBiconditionalTile.png"); diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/RedElement.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/RedElement.java index e2a589b65..2114e62ec 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/RedElement.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/RedElement.java @@ -5,7 +5,7 @@ public class RedElement extends PlaceableElement { public RedElement() { super( - "STTT-PLAC-0002", + "STTT-ELEM-0004", "Red Element", "A red tile to set certain tiles to false", "edu/rpi/legup/images/shorttruthtable/tiles/RedTile.png"); diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/UnknownElement.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/UnknownElement.java index d475bc05d..52b54f202 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/UnknownElement.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/UnknownElement.java @@ -5,7 +5,7 @@ public class UnknownElement extends PlaceableElement { public UnknownElement() { super( - "STTT-PLAC-0003", + "STTT-ELEM-0005", "Unknown Element", "A blank tile", "edu/rpi/legup/images/shorttruthtable/tiles/UnknownTile.png"); diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/shorttruthtable_elements_reference_sheet b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/shorttruthtable_elements_reference_sheet index 471631553..c5421169f 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/shorttruthtable_elements_reference_sheet +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/shorttruthtable_elements_reference_sheet @@ -1,6 +1,5 @@ -STTT-UNPL-0001 : ArgumentElement -STTT-UNPL-0002 : ConditionalBiconditionalElement - -STTT-PLAC-0001 : GreenElement -STTT-PLAC-0002 : RedElement -STTT-PLAC-0003 : UnknownElement \ No newline at end of file +STTT-ELEM-0001 : ArgumentElement +STTT-ELEM-0002 : GreenElement +STTT-ELEM-0003 : LogicSymbolElement +STTT-ELEM-0004 : RedElement +STTT-ELEM-0005 : UnknownElement \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/ClueTile.java b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/ClueTile.java index 64c9033e6..102bd5833 100644 --- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/ClueTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/ClueTile.java @@ -1,12 +1,12 @@ package edu.rpi.legup.puzzle.skyscrapers.elements; -import edu.rpi.legup.model.elements.NonPlaceableElement; +import edu.rpi.legup.model.elements.PlaceableElement; -public class ClueTile extends NonPlaceableElement { +public class ClueTile extends PlaceableElement { public ClueTile() { super( - "SKYS-UNPL-0003", + "SKYS-ELEM-0001", "Clue Tile", "Clue Updater", "edu/rpi/legup/images/skyscrapers/tiles/ClueTile.png"); diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/NumberTile.java b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/NumberTile.java index 4d6b37c9a..7c7887131 100644 --- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/NumberTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/NumberTile.java @@ -1,11 +1,11 @@ package edu.rpi.legup.puzzle.skyscrapers.elements; -import edu.rpi.legup.model.elements.NonPlaceableElement; +import edu.rpi.legup.model.elements.PlaceableElement; -public class NumberTile extends NonPlaceableElement { +public class NumberTile extends PlaceableElement { public NumberTile() { super( - "SKYS-UNPL-0002", + "SKYS-ELEM-0002", "Number Tile", "A numbered tile", "edu/rpi/legup/images/skyscrapers/tiles/ClueTile.png"); diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/UnknownTile.java b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/UnknownTile.java index 2fb21193a..1c9b6f5f3 100644 --- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/UnknownTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/UnknownTile.java @@ -1,11 +1,11 @@ package edu.rpi.legup.puzzle.skyscrapers.elements; -import edu.rpi.legup.model.elements.NonPlaceableElement; +import edu.rpi.legup.model.elements.PlaceableElement; -public class UnknownTile extends NonPlaceableElement { +public class UnknownTile extends PlaceableElement { public UnknownTile() { super( - "SKYS-UNPL-0001", + "SKYS-ELEM-0003", "Unknown", "A blank tile", "edu/rpi/legup/images/skyscrapers/tiles/UnknownTile.png"); diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/skyscrapers_elements_reference_sheet.txt b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/skyscrapers_elements_reference_sheet.txt index 604e1824e..1cc867f37 100644 --- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/skyscrapers_elements_reference_sheet.txt +++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/skyscrapers_elements_reference_sheet.txt @@ -1,3 +1,3 @@ -SKYS-UNPL-0001: Unknown Tile -SKYS-UNPL-0002: Number Tile -SKYS-UNPL-0003: Clue "Tile" \ No newline at end of file +SKYS-ELEM-0001: ClueTile +SKYS-ELEM-0002: NumberTile +SKYS-ELEM-0003: UnknownTile \ No newline at end of file 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 99f42886e..9c8140588 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 @@ -1,11 +1,11 @@ package edu.rpi.legup.puzzle.starbattle.elements; -import edu.rpi.legup.model.elements.NonPlaceableElement; +import edu.rpi.legup.model.elements.PlaceableElement; -public class BlackTile extends NonPlaceableElement { +public class BlackTile extends PlaceableElement { public BlackTile() { super( - "STBL-PLAC-0002", + "STBL-ELEM-0001", "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 13ada3f4d..266a29758 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 @@ -1,11 +1,11 @@ package edu.rpi.legup.puzzle.starbattle.elements; -import edu.rpi.legup.model.elements.NonPlaceableElement; +import edu.rpi.legup.model.elements.PlaceableElement; -public class StarTile extends NonPlaceableElement { +public class StarTile extends PlaceableElement { public StarTile() { super( - "STBL-PLAC-0001", + "STBL-ELEM-0002", "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 425fb5d5e..37cf0cc15 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 @@ -1,11 +1,11 @@ package edu.rpi.legup.puzzle.starbattle.elements; -import edu.rpi.legup.model.elements.NonPlaceableElement; +import edu.rpi.legup.model.elements.PlaceableElement; -public class UnknownTile extends NonPlaceableElement { +public class UnknownTile extends PlaceableElement { public UnknownTile() { super( - "STBL-UNPL-0001", + "STBL-ELEM-0003", "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 2227eb37a..47414a367 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 @@ -5,7 +5,7 @@ public class WhiteTile extends PlaceableElement { public WhiteTile() { super( - "STBL-PLAC-0001", + "STBL-ELEM-0004", "White Tile", "The white tile", "edu/rpi/legup/images/starbattle/white.gif"); diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/elements/starbattle_elements_reference_sheet.txt b/src/main/java/edu/rpi/legup/puzzle/starbattle/elements/starbattle_elements_reference_sheet.txt new file mode 100644 index 000000000..82352bd04 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/elements/starbattle_elements_reference_sheet.txt @@ -0,0 +1,4 @@ +STBL-ELEM-0001 : BlackTile +STBL-ELEM-0002 : StarTile +STBL-ELEM-0003 : UnknownTile +STBL-ELEM-0004 : WhiteTile \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/elements/NumberTile.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/elements/NumberTile.java index 12183d70d..c8181b9e3 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/elements/NumberTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/elements/NumberTile.java @@ -6,7 +6,7 @@ public class NumberTile extends PlaceableElement { private int object_num; public NumberTile() { - super("SUDO-PLAC-0001", "Number Tile", "A numbered tile", null); + super("SUDO-ELEM-0001", "Number Tile", "A numbered tile", null); object_num = 0; } diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/elements/sudoku_elements_reference_sheet.txt b/src/main/java/edu/rpi/legup/puzzle/sudoku/elements/sudoku_elements_reference_sheet.txt new file mode 100644 index 000000000..5f023a984 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/elements/sudoku_elements_reference_sheet.txt @@ -0,0 +1 @@ +SUDO-ELEM-0001 : NumberTile \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/elements/GrassTile.java b/src/main/java/edu/rpi/legup/puzzle/treetent/elements/GrassTile.java index 5356120a8..1d33b9035 100644 --- a/src/main/java/edu/rpi/legup/puzzle/treetent/elements/GrassTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/treetent/elements/GrassTile.java @@ -6,7 +6,7 @@ public class GrassTile extends PlaceableElement { public GrassTile() { super( - "TREE-PlAC-0002", + "TREE-ELEM-0001", "Grass Tile", "The grass crest tile", "edu/rpi/legup/images/treetent/grass.png"); diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/elements/TentTile.java b/src/main/java/edu/rpi/legup/puzzle/treetent/elements/TentTile.java index 950aebfa7..96124a98d 100644 --- a/src/main/java/edu/rpi/legup/puzzle/treetent/elements/TentTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/treetent/elements/TentTile.java @@ -6,7 +6,7 @@ public class TentTile extends PlaceableElement { public TentTile() { super( - "TREE-PLAC-0001", + "TREE-ELEM-0002", "Tent Tile", "The tent tile", "edu/rpi/legup/images/treetent/tent.png"); diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/elements/TreeTile.java b/src/main/java/edu/rpi/legup/puzzle/treetent/elements/TreeTile.java index d04886ed5..3d94cbfba 100644 --- a/src/main/java/edu/rpi/legup/puzzle/treetent/elements/TreeTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/treetent/elements/TreeTile.java @@ -1,12 +1,12 @@ package edu.rpi.legup.puzzle.treetent.elements; -import edu.rpi.legup.model.elements.NonPlaceableElement; +import edu.rpi.legup.model.elements.PlaceableElement; -public class TreeTile extends NonPlaceableElement { +public class TreeTile extends PlaceableElement { public TreeTile() { super( - "TREE-UNPL-0001", + "TREE-ELEM-0003", "Tree Tile", "The tree tile", "edu/rpi/legup/images/treetent/tree.png"); diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/elements/UnknownTile.java b/src/main/java/edu/rpi/legup/puzzle/treetent/elements/UnknownTile.java index a54240efd..99b75b60c 100644 --- a/src/main/java/edu/rpi/legup/puzzle/treetent/elements/UnknownTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/treetent/elements/UnknownTile.java @@ -1,11 +1,11 @@ package edu.rpi.legup.puzzle.treetent.elements; -import edu.rpi.legup.model.elements.NonPlaceableElement; +import edu.rpi.legup.model.elements.PlaceableElement; -public class UnknownTile extends NonPlaceableElement { +public class UnknownTile extends PlaceableElement { public UnknownTile() { super( - "TREE-UNPL-0002", + "TREE-ELEM-0004", "Unknown Tile", "The blank tile", "edu/rpi/legup/images/treetent/UnknownTile.png"); diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/elements/treetent_elements_reference_sheet.txt b/src/main/java/edu/rpi/legup/puzzle/treetent/elements/treetent_elements_reference_sheet.txt new file mode 100644 index 000000000..e0cfc1dfa --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/treetent/elements/treetent_elements_reference_sheet.txt @@ -0,0 +1,4 @@ +TREE-ELEM-0001 : GrassTile +TREE-ELEM-0002 : TentTile +TREE-ELEM-0003 : TreeTile +TREE-ELEM-0004 : UnknownTile \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/ui/HomePanel.java b/src/main/java/edu/rpi/legup/ui/HomePanel.java index df50eed91..79d27bc87 100644 --- a/src/main/java/edu/rpi/legup/ui/HomePanel.java +++ b/src/main/java/edu/rpi/legup/ui/HomePanel.java @@ -641,6 +641,11 @@ public void openEditorWithNewPuzzle(String game, int rows, int columns) throw new IllegalArgumentException("ERROR: Invalid dimensions given"); } + if (this.legupUI == null) { + System.err.println("Error: legupUI is null in HomePanel"); + return; + } + // Set game type on the puzzle editor this.legupUI.displayPanel(2); this.legupUI.getPuzzleEditor().loadPuzzleFromHome(game, rows, columns); diff --git a/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java b/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java index 2929ef4ec..cfee707f2 100644 --- a/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java +++ b/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java @@ -12,6 +12,7 @@ import edu.rpi.legup.model.PuzzleExporter; import edu.rpi.legup.save.ExportFileException; import edu.rpi.legup.save.InvalidFileFormatException; +import edu.rpi.legup.ui.HomePanel; import edu.rpi.legup.ui.boardview.BoardView; import edu.rpi.legup.ui.puzzleeditorui.elementsview.ElementFrame; import java.awt.*; @@ -103,28 +104,32 @@ public void setMenuBar() { menus[0] = new JMenu("File"); // file>new - JMenuItem newPuzzle = new JMenuItem("New"); - newPuzzle.addActionListener((ActionEvent) -> loadPuzzle()); + JMenuItem openPuzzle = new JMenuItem("Open"); + openPuzzle.addActionListener((ActionEvent) -> loadPuzzle()); if (os.equals("mac")) { - newPuzzle.setAccelerator( + openPuzzle.setAccelerator( KeyStroke.getKeyStroke( - 'N', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); + 'O', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); } else { - newPuzzle.setAccelerator(KeyStroke.getKeyStroke('N', InputEvent.CTRL_DOWN_MASK)); + openPuzzle.setAccelerator(KeyStroke.getKeyStroke('O', InputEvent.CTRL_DOWN_MASK)); } - // file>save - JMenuItem savePuzzle = new JMenuItem("Save As"); - savePuzzle.addActionListener((ActionEvent) -> savePuzzle()); - JMenuItem directSavePuzzle = new JMenuItem("Direct Save Proof "); - directSavePuzzle.addActionListener((ActionEvent) -> direct_save()); + // file>create + JMenuItem createPuzzle = new JMenuItem("Create"); + createPuzzle.addActionListener((ActionEvent) -> { + HomePanel hp = new HomePanel(this.fileDialog, this.frame, this.legupUI); + CreatePuzzleDialog cpd = new CreatePuzzleDialog(this.frame, hp); + cpd.setLocationRelativeTo(null); + cpd.setVisible(true); + }); if (os.equals("mac")) { - newPuzzle.setAccelerator( + createPuzzle.setAccelerator( KeyStroke.getKeyStroke( - 'D', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); + 'C', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); } else { - newPuzzle.setAccelerator(KeyStroke.getKeyStroke('D', InputEvent.CTRL_DOWN_MASK)); + createPuzzle.setAccelerator(KeyStroke.getKeyStroke('C', InputEvent.CTRL_DOWN_MASK)); } + JMenuItem exit = new JMenuItem("Exit"); exit.addActionListener((ActionEvent) -> exitEditor()); if (os.equals("mac")) { @@ -134,9 +139,9 @@ public void setMenuBar() { } else { exit.setAccelerator(KeyStroke.getKeyStroke('Q', InputEvent.CTRL_DOWN_MASK)); } - menus[0].add(newPuzzle); - menus[0].add(savePuzzle); - menus[0].add(directSavePuzzle); + menus[0].add(openPuzzle); + menus[0].add(createPuzzle); + //menus[0].add(directSavePuzzle); menus[0].add(exit); // EDIT @@ -249,152 +254,72 @@ public void makeVisible() { setMenuBar(); } -// private void setupToolBar() { -// setToolBarButtons(new JButton[ToolbarName.values().length + 1]); -// int lastone = 0; -// for (int i = 0; i < ToolbarName.values().length - 1; i++) { -// String toolBarName = ToolbarName.values()[i].toString(); -// URL resourceLocation = -// ClassLoader.getSystemClassLoader() -// .getResource("edu/rpi/legup/images/Legup/" + toolBarName + ".png"); -// -// // Scale the image icons down to make the buttons smaller -// ImageIcon imageIcon = new ImageIcon(resourceLocation); -// Image image = imageIcon.getImage(); -// imageIcon = -// new ImageIcon( -// image.getScaledInstance( -// this.TOOLBAR_ICON_SCALE, -// this.TOOLBAR_ICON_SCALE, -// Image.SCALE_SMOOTH)); -// -// JButton button = new JButton(toolBarName, imageIcon); -// button.setFocusPainted(false); -// getToolBarButtons()[i] = button; -// lastone = i; -// } -// -// URL save_and_check = -// ClassLoader.getSystemClassLoader() -// .getResource("edu/rpi/legup/images/Legup/Check.png"); -// ImageIcon imageIcon = new ImageIcon(save_and_check); -// Image image = imageIcon.getImage(); -// imageIcon = -// new ImageIcon( -// image.getScaledInstance( -// this.TOOLBAR_ICON_SCALE, -// this.TOOLBAR_ICON_SCALE, -// Image.SCALE_SMOOTH)); -// -// JButton saveandcheck = new JButton("Save And Check", imageIcon); -// saveandcheck.setFocusPainted(false); -// saveandcheck.addActionListener( -// new ActionListener() { -// @Override -// public void actionPerformed(ActionEvent e) { -// // savePuzzle(); -// String filename = savePuzzle(); -// File puzzlename = new File(filename); -// System.out.println(filename); -// -// GameBoardFacade.getInstance().getLegupUI().displayPanel(1); -// GameBoardFacade.getInstance() -// .getLegupUI() -// .getProofEditor() -// .loadPuzzle(filename, new File(filename)); -// String puzzleName = -// GameBoardFacade.getInstance().getPuzzleModule().getName(); -// frame.setTitle(puzzleName + " - " + puzzlename.getName()); -// } -// }); -// getToolBarButtons()[lastone + 1] = saveandcheck; -// -// toolBar = new JToolBar(); -// toolBar.setFloatable(false); -// toolBar.setRollover(true); -// -// for (int i = 0; i < getToolBarButtons().length - 1; i++) { -// for (int s = 0; s < TOOLBAR_SEPARATOR_BEFORE.length; s++) { -// if (i == TOOLBAR_SEPARATOR_BEFORE[s]) { -// toolBar.addSeparator(); -// } -// } -// String toolBarName = ToolbarName.values()[i].toString(); -// -// toolBar.add(getToolBarButtons()[i]); -// getToolBarButtons()[i].setToolTipText(toolBarName); -// -// getToolBarButtons()[i].setVerticalTextPosition(SwingConstants.BOTTOM); -// getToolBarButtons()[i].setHorizontalTextPosition(SwingConstants.CENTER); -// } -// -// // toolBarButtons[ToolbarName.OPEN_PUZZLE.ordinal()].addActionListener((ActionEvent -// // e) -> -// // promptPuzzle()); -// // toolBarButtons[ToolbarName.SAVE.ordinal()].addActionListener((ActionEvent e) -> -// // saveProof()); -// // toolBarButtons[ToolbarName.UNDO.ordinal()].addActionListener((ActionEvent e) -> -// // GameBoardFacade.getInstance().getHistory().undo()); -// // toolBarButtons[ToolbarName.REDO.ordinal()].addActionListener((ActionEvent e) -> -// // GameBoardFacade.getInstance().getHistory().redo()); -// toolBarButtons[ToolbarName.HINT.ordinal()].addActionListener((ActionEvent e) -> {}); -// toolBarButtons[ToolbarName.SUBMIT.ordinal()].addActionListener((ActionEvent e) -> {}); -// toolBarButtons[ToolbarName.DIRECTIONS.ordinal()].addActionListener((ActionEvent e) -> {}); -// -// // toolBarButtons[ToolbarName.SAVE.ordinal()].setEnabled(false); -// // toolBarButtons[ToolbarName.UNDO.ordinal()].setEnabled(false); -// // toolBarButtons[ToolbarName.REDO.ordinal()].setEnabled(false); -// toolBarButtons[ToolbarName.HINT.ordinal()].setEnabled(false); -// toolBarButtons[ToolbarName.SUBMIT.ordinal()].setEnabled(false); -// toolBarButtons[ToolbarName.DIRECTIONS.ordinal()].setEnabled(false); -// -// this.add(toolBar, BorderLayout.NORTH); -// } - -private void setupToolBar() { - setToolBarButtons(new JButton[1]); - - URL save_and_solve = - ClassLoader.getSystemClassLoader() - .getResource("edu/rpi/legup/images/Legup/Check.png"); - ImageIcon imageIcon = new ImageIcon(save_and_solve); - Image image = imageIcon.getImage(); - imageIcon = - new ImageIcon( - image.getScaledInstance( - this.TOOLBAR_ICON_SCALE, - this.TOOLBAR_ICON_SCALE, - Image.SCALE_SMOOTH)); - - JButton saveandsolve = new JButton("Save And Solve", imageIcon); - saveandsolve.setFocusPainted(false); - saveandsolve.addActionListener( - new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - // savePuzzle(); - String filename = savePuzzle(); - File puzzlename = new File(filename); - System.out.println(filename); - - GameBoardFacade.getInstance().getLegupUI().displayPanel(1); - GameBoardFacade.getInstance() - .getLegupUI() - .getProofEditor() - .loadPuzzle(filename, new File(filename)); - String puzzleName = - GameBoardFacade.getInstance().getPuzzleModule().getName(); - frame.setTitle(puzzleName + " - " + puzzlename.getName()); - } - }); - getToolBarButtons()[0] = saveandsolve; - - toolBar = new JToolBar(); - toolBar.setFloatable(false); - toolBar.setRollover(true); - toolBar.add(getToolBarButtons()[0]); - this.add(toolBar, BorderLayout.NORTH); -} + private void setupToolBar() { + setToolBarButtons(new JButton[2]); + + URL save_as = + ClassLoader.getSystemClassLoader() + .getResource("edu/rpi/legup/images/Legup/Save.png"); + ImageIcon SaveAsImageIcon = new ImageIcon(save_as); + Image SaveAsImage = SaveAsImageIcon.getImage(); + SaveAsImageIcon = + new ImageIcon( + SaveAsImage.getScaledInstance( + this.TOOLBAR_ICON_SCALE, + this.TOOLBAR_ICON_SCALE, + Image.SCALE_SMOOTH)); + + JButton saveas = new JButton("Save As", SaveAsImageIcon); + saveas.setFocusPainted(false); + saveas.addActionListener((ActionEvent) -> savePuzzle()); + + getToolBarButtons()[0] = saveas; + + toolBar = new JToolBar(); + toolBar.setFloatable(false); + toolBar.setRollover(true); + toolBar.add(getToolBarButtons()[0]); + + URL save_and_solve = + ClassLoader.getSystemClassLoader() + .getResource("edu/rpi/legup/images/Legup/Check.png"); + ImageIcon SaveSolveImageIcon = new ImageIcon(save_and_solve); + Image SaveSolveImage = SaveSolveImageIcon.getImage(); + SaveSolveImageIcon = + new ImageIcon( + SaveSolveImage.getScaledInstance( + this.TOOLBAR_ICON_SCALE, + this.TOOLBAR_ICON_SCALE, + Image.SCALE_SMOOTH)); + + JButton saveandsolve = new JButton("Save And Solve", SaveSolveImageIcon); + saveandsolve.setFocusPainted(false); + saveandsolve.addActionListener( + new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + String filename = savePuzzle(); + File puzzlename = new File(filename); + System.out.println(filename); + + GameBoardFacade.getInstance().getLegupUI().displayPanel(1); + GameBoardFacade.getInstance() + .getLegupUI() + .getProofEditor() + .loadPuzzle(filename, new File(filename)); + String puzzleName = + GameBoardFacade.getInstance().getPuzzleModule().getName(); + frame.setTitle(puzzleName + " - " + puzzlename.getName()); + } + }); + getToolBarButtons()[1] = saveandsolve; + + toolBar.setFloatable(false); + toolBar.setRollover(true); + toolBar.add(getToolBarButtons()[1]); + + this.add(toolBar, BorderLayout.NORTH); + } public void loadPuzzleFromHome(String game, int rows, int columns) throws IllegalArgumentException { @@ -425,7 +350,7 @@ public void loadPuzzleFromHome(String game, String[] statements) { public Object[] promptPuzzle() { GameBoardFacade facade = GameBoardFacade.getInstance(); if (facade.getBoard() != null) { - if (noQuit("Opening a new puzzle?")) { + if (noQuit("Open an existing puzzle?")) { return new Object[0]; } } diff --git a/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/ElementFrame.java b/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/ElementFrame.java index 8610facbb..35ab65ff4 100644 --- a/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/ElementFrame.java +++ b/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/ElementFrame.java @@ -14,53 +14,36 @@ public class ElementFrame extends JPanel { private static final String htmlTail = ""; private PlaceableElementPanel placeableElementPanel; - private NonPlaceableElementPanel nonPlaceableElementPanel; - private JTabbedPane tabbedPane; + //private JTabbedPane tabbedPane; private ButtonGroup buttonGroup; private EditorElementController controller; public ElementFrame(EditorElementController controller) { + this.controller = controller; - MaterialTabbedPaneUI tabOverride = - new MaterialTabbedPaneUI() { - // this prevents the tabs from moving around when you select them - @Override - protected boolean shouldRotateTabRuns(int i) { - return false; - } - }; - - this.tabbedPane = new JTabbedPane(); - tabbedPane.setUI(tabOverride); + JLabel status = new JLabel("", SwingConstants.CENTER); this.buttonGroup = new ButtonGroup(); - nonPlaceableElementPanel = new NonPlaceableElementPanel(this); - // nonPlaceableElementPanel.setMinimumSize(new Dimension(100,200)); - tabbedPane.addTab( - nonPlaceableElementPanel.getName(), - nonPlaceableElementPanel.getIcon(), - new JScrollPane(nonPlaceableElementPanel), - nonPlaceableElementPanel.getToolTip()); + // Parent panel to hold all elements + JPanel elementPanel = new JPanel(); + elementPanel.setLayout(new BoxLayout(elementPanel, BoxLayout.Y_AXIS)); placeableElementPanel = new PlaceableElementPanel(this); - // placeableElementPanel.setMinimuSize(new Dimension(100,200)); - tabbedPane.addTab( - placeableElementPanel.getName(), - placeableElementPanel.getIcon(), - new JScrollPane(placeableElementPanel), - placeableElementPanel.getToolTip()); - tabbedPane.setTabPlacement(JTabbedPane.TOP); + placeableElementPanel.setMinimumSize(new Dimension(100, 200)); + elementPanel.add(new JScrollPane(placeableElementPanel)); + // Set layout and dimensions for the main panel setLayout(new BorderLayout()); setMinimumSize(new Dimension(250, 256)); setPreferredSize(new Dimension(330, 256)); - - add(tabbedPane); + // Add components to the main panel + add(elementPanel, BorderLayout.CENTER); add(status, BorderLayout.SOUTH); + // Center-align the titled border TitledBorder title = BorderFactory.createTitledBorder("Elements"); title.setTitleJustification(TitledBorder.CENTER); setBorder(title); @@ -70,19 +53,16 @@ public ButtonGroup getButtonGroup() { return buttonGroup; } - public void resetSize() { - int buttonWidth = - ((ElementPanel) tabbedPane.getSelectedComponent()) - .getElementButtons()[0].getWidth(); - this.setMinimumSize(new Dimension(2 * buttonWidth + 64, this.getHeight())); - } +// public void resetSize() { +// int buttonWidth = +// ((ElementPanel) tabbedPane.getSelectedComponent()) +// .getElementButtons()[0].getWidth(); +// this.setMinimumSize(new Dimension(2 * buttonWidth + 64, this.getHeight())); +// } public void setElements(Puzzle puzzle) { - if (nonPlaceableElementPanel.setElements(puzzle.getNonPlaceableElements()) == 0) { - tabbedPane.remove(0); - } if (placeableElementPanel.setElements(puzzle.getPlaceableElements()) == 0) { - tabbedPane.remove(1); + } } @@ -90,13 +70,9 @@ public EditorElementController getController() { return controller; } - public JTabbedPane getTabbedPane() { - return tabbedPane; - } - - public NonPlaceableElementPanel getNonPlaceableElementPanel() { - return nonPlaceableElementPanel; - } +// public JTabbedPane getTabbedPane() { +// return tabbedPane; +// } public PlaceableElementPanel getPlaceableElementPanel() { return placeableElementPanel; diff --git a/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/NonPlaceableElementPanel.java b/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/NonPlaceableElementPanel.java index 00b4f5379..796d1ae68 100644 --- a/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/NonPlaceableElementPanel.java +++ b/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/NonPlaceableElementPanel.java @@ -1,15 +1,15 @@ -package edu.rpi.legup.ui.puzzleeditorui.elementsview; - -import javax.swing.*; - -public class NonPlaceableElementPanel extends ElementPanel { - public NonPlaceableElementPanel(ElementFrame elementFrame) { - super(elementFrame); - this.icon = - new ImageIcon( - ClassLoader.getSystemClassLoader() - .getResource("edu/rpi/legup/images/Legup/Direct Rules.gif")); - this.name = "Non-Placeable Elements"; - this.toolTip = "Non-Placeable Elements"; - } -} +//package edu.rpi.legup.ui.puzzleeditorui.elementsview; +// +//import javax.swing.*; +// +//public class NonPlaceableElementPanel extends ElementPanel { +// public NonPlaceableElementPanel(ElementFrame elementFrame) { +// super(elementFrame); +// this.icon = +// new ImageIcon( +// ClassLoader.getSystemClassLoader() +// .getResource("edu/rpi/legup/images/Legup/Direct Rules.gif")); +// this.name = "Non-Placeable Elements"; +// this.toolTip = "Non-Placeable Elements"; +// } +//} From eda8b2263ffc5f32b5411c62f506cd67692453d7 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Sun, 16 Jun 2024 23:57:59 -0400 Subject: [PATCH 129/258] Removed Edit Puzzle button on home page, resized home page --- src/main/java/edu/rpi/legup/ui/HomePanel.java | 7 +++++-- src/main/resources/edu/rpi/legup/legup/config | 15 ++++++++------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/main/java/edu/rpi/legup/ui/HomePanel.java b/src/main/java/edu/rpi/legup/ui/HomePanel.java index 79d27bc87..2e63b91e3 100644 --- a/src/main/java/edu/rpi/legup/ui/HomePanel.java +++ b/src/main/java/edu/rpi/legup/ui/HomePanel.java @@ -70,6 +70,7 @@ public HomePanel(FileDialog fileDialog, JFrame frame, LegupUI legupUI) { this.legupUI = legupUI; this.frame = frame; setLayout(new GridLayout(1, 2)); + setPreferredSize(new Dimension(440, 250)); initText(); initButtons(); } @@ -136,7 +137,7 @@ private void initButtons() { this.buttons[0].addActionListener(CursorController.createListener(this, openProofListener)); this.buttons[1] = - new JButton("Create New Puzzle") { + new JButton("Create Puzzle") { { setSize(buttonSize, buttonSize); setMaximumSize(getSize()); @@ -170,6 +171,8 @@ private void initButtons() { this.buttons[2].addActionListener( CursorController.createListener(this, openPuzzleListener)); // PLACEHOLDER + this.buttons[2].setVisible(false); + for (int i = 0; i < this.buttons.length - 1; i++) { // -1 to avoid the batch grader button this.buttons[i].setBounds(200, 200, 700, 700); } @@ -502,7 +505,7 @@ private void render() { this.removeAll(); this.setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS)); - this.legupUI.setTitle("LEGUP: A Better Way to Learn Formal Logic"); + this.legupUI.setTitle("LEGUP: A Better Way To Learn Formal Logic"); JPanel buttons = new JPanel(); buttons.add(Box.createRigidArea(new Dimension(5, 0))); diff --git a/src/main/resources/edu/rpi/legup/legup/config b/src/main/resources/edu/rpi/legup/legup/config index 07b0b0586..5e45d6f91 100644 --- a/src/main/resources/edu/rpi/legup/legup/config +++ b/src/main/resources/edu/rpi/legup/legup/config @@ -32,20 +32,21 @@ qualifiedClassName="edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTable" fileType=".xml" fileCreationDisabled="false"/> - - + - From 9ae0fae87b2b632088d185b6c5bf40616044926c Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Mon, 17 Jun 2024 21:50:53 -0400 Subject: [PATCH 130/258] Removed extra buttons in proof solver, added directions button that when clicked links to corresponding puzzle wiki page --- .../edu/rpi/legup/ui/ProofEditorPanel.java | 56 +++++++++++++++---- .../java/edu/rpi/legup/ui/ToolbarName.java | 5 +- 2 files changed, 45 insertions(+), 16 deletions(-) diff --git a/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java b/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java index 64b9f7e70..6967d3735 100644 --- a/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java +++ b/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java @@ -81,7 +81,7 @@ public class ProofEditorPanel extends LegupPanel implements IHistoryListener { public static final int IMD_FEEDBACK = 32; public static final int INTERN_RO = 64; public static final int AUTO_JUST = 128; - static final int[] TOOLBAR_SEPARATOR_BEFORE = {2, 4, 8}; + static final int[] TOOLBAR_SEPARATOR_BEFORE = {1}; private static final String[] PROFILES = { "No Assistance", "Rigorous Proof", @@ -167,7 +167,7 @@ public JMenuBar getMenuBar() { } proof.add(add); - delete = new JMenuItem("Delete"); + delete = new JMenuItem("D\"Check All\"elete"); delete.addActionListener(a -> treePanel.delete()); if (os.equals("mac")) { delete.setAccelerator( @@ -792,23 +792,27 @@ private void setupToolBar() { // GameBoardFacade.getInstance().getHistory().undo()); // toolBarButtons[ToolbarName.REDO.ordinal()].addActionListener((ActionEvent e) -> // GameBoardFacade.getInstance().getHistory().redo()); - toolBarButtons[ToolbarName.HINT.ordinal()].addActionListener((ActionEvent e) -> {}); + //toolBarButtons[ToolbarName.HINT.ordinal()].addActionListener((ActionEvent e) -> {}); toolBarButtons[ToolbarName.CHECK.ordinal()].addActionListener( (ActionEvent e) -> checkProof()); - toolBarButtons[ToolbarName.SUBMIT.ordinal()].addActionListener((ActionEvent e) -> {}); - toolBarButtons[ToolbarName.DIRECTIONS.ordinal()].addActionListener((ActionEvent e) -> {}); + //toolBarButtons[ToolbarName.SUBMIT.ordinal()].addActionListener((ActionEvent e) -> {}); + toolBarButtons[ToolbarName.DIRECTIONS.ordinal()].addActionListener((ActionEvent e) -> directionsToolButton()); - toolBarButtons[ToolbarName.CHECK_ALL.ordinal()].addActionListener( - (ActionEvent e) -> checkProofAll()); +// toolBarButtons[ToolbarName.CHECK_ALL.ordinal()].addActionListener( +// (ActionEvent e) -> checkProofAll()); // toolBarButtons[ToolbarName.SAVE.ordinal()].setEnabled(false); // toolBarButtons[ToolbarName.UNDO.ordinal()].setEnabled(false); // toolBarButtons[ToolbarName.REDO.ordinal()].setEnabled(false); - toolBarButtons[ToolbarName.HINT.ordinal()].setEnabled(false); - toolBarButtons[ToolbarName.CHECK.ordinal()].setEnabled(false); - toolBarButtons[ToolbarName.SUBMIT.ordinal()].setEnabled(false); - toolBarButtons[ToolbarName.DIRECTIONS.ordinal()].setEnabled(false); - toolBarButtons[ToolbarName.CHECK_ALL.ordinal()].setEnabled(true); + //toolBarButtons[ToolbarName.HINT.ordinal()].setEnabled(false); + toolBarButtons[ToolbarName.CHECK.ordinal()].setEnabled(true); + //toolBarButtons[ToolbarName.SUBMIT.ordinal()].setEnabled(false); + toolBarButtons[ToolbarName.DIRECTIONS.ordinal()].setEnabled(true); + //toolBarButtons[ToolbarName.CHECK_ALL.ordinal()].setEnabled(false); + +// toolBarButtons[ToolbarName.HINT.ordinal()].setVisible(false); +// toolBarButtons[ToolbarName.SUBMIT.ordinal()].setVisible(false); +// toolBarButtons[ToolbarName.CHECK_ALL.ordinal()].setVisible(false); this.add(toolBar, BorderLayout.NORTH); } @@ -858,6 +862,34 @@ private void checkProof() { } } + private void directionsToolButton() { + String puzzleName = GameBoardFacade.getInstance().getPuzzleModule().getName(); + System.out.println(puzzleName); + try { + if (puzzleName.equals("Fillapix")) { + java.awt.Desktop.getDesktop() + .browse(URI.create("https://github.com/Bram-Hub/LEGUP/wiki/Fill-a-pix-rules")); + } + else if (puzzleName.equals("LightUp")) { + java.awt.Desktop.getDesktop() + .browse(URI.create("https://github.com/Bram-Hub/LEGUP/wiki/Light-up-rules")); + } + else if (puzzleName.equals("TreeTent")) { + java.awt.Desktop.getDesktop() + .browse(URI.create("https://github.com/Bram-Hub/LEGUP/wiki/Tree-tent-rules")); + } + else if (puzzleName.equals("ShortTruthTables")) { + java.awt.Desktop.getDesktop() + .browse(URI.create("https://github.com/Bram-Hub/LEGUP/wiki/Short-truth-table-rules")); + } + else { + java.awt.Desktop.getDesktop() + .browse(URI.create("https://github.com/Bram-Hub/LEGUP/wiki/" + puzzleName + "-rules")); + } + } catch (IOException e) { + LOGGER.error("Can't open web page"); + } + } private void repaintAll() { boardView.repaint(); treePanel.repaint(); diff --git a/src/main/java/edu/rpi/legup/ui/ToolbarName.java b/src/main/java/edu/rpi/legup/ui/ToolbarName.java index ba02ebd2e..00bf7b21d 100644 --- a/src/main/java/edu/rpi/legup/ui/ToolbarName.java +++ b/src/main/java/edu/rpi/legup/ui/ToolbarName.java @@ -1,11 +1,8 @@ package edu.rpi.legup.ui; public enum ToolbarName { - HINT, - CHECK, - SUBMIT, DIRECTIONS, - CHECK_ALL; + CHECK; /** * Gets the String representation of the ToolbarName enum From fac81fb002cc76c197859d71d07526b9ea41d33c Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Mon, 17 Jun 2024 23:55:15 -0400 Subject: [PATCH 131/258] Made progress with binary test suite for surround pair --- .../edu/rpi/legup/ui/ProofEditorPanel.java | 2 +- src/test/java/legup/TestUtilities.java | 10 ++- .../rules/SurroundPairDirectRuleTest.java | 66 +++++++++++++++++++ .../SurroundTwoZerosWithTwoOnes | 10 +++ .../binary.rules/SurroundPairDirectRule/test | 0 5 files changed, 86 insertions(+), 2 deletions(-) create mode 100644 src/test/java/puzzles/binary/rules/SurroundPairDirectRuleTest.java create mode 100644 src/test/resources/puzzles/binary.rules/SurroundPairDirectRule/SurroundTwoZerosWithTwoOnes create mode 100644 src/test/resources/puzzles/binary.rules/SurroundPairDirectRule/test diff --git a/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java b/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java index 6967d3735..99b08f963 100644 --- a/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java +++ b/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java @@ -864,7 +864,7 @@ private void checkProof() { private void directionsToolButton() { String puzzleName = GameBoardFacade.getInstance().getPuzzleModule().getName(); - System.out.println(puzzleName); + //System.out.println(puzzleName); try { if (puzzleName.equals("Fillapix")) { java.awt.Desktop.getDesktop() diff --git a/src/test/java/legup/TestUtilities.java b/src/test/java/legup/TestUtilities.java index 83ce773d4..d48d648d7 100644 --- a/src/test/java/legup/TestUtilities.java +++ b/src/test/java/legup/TestUtilities.java @@ -7,10 +7,18 @@ import edu.rpi.legup.model.tree.TreeTransition; import edu.rpi.legup.save.InvalidFileFormatException; +import java.io.InputStream; + public final class TestUtilities { public static void importTestBoard(String fileName, Puzzle puzzle) throws InvalidFileFormatException { - puzzle.importPuzzle(ClassLoader.getSystemResourceAsStream(fileName)); + InputStream inputStream = ClassLoader.getSystemResourceAsStream(fileName); + + if (inputStream == null) { + throw new IllegalArgumentException("InputStream cannot be null. File not found: " + fileName); + } + + puzzle.importPuzzle(inputStream); Tree tree = puzzle.getTree(); TreeNode rootNode = tree.getRootNode(); Board board = rootNode.getBoard().copy(); diff --git a/src/test/java/puzzles/binary/rules/SurroundPairDirectRuleTest.java b/src/test/java/puzzles/binary/rules/SurroundPairDirectRuleTest.java new file mode 100644 index 000000000..acb9f07de --- /dev/null +++ b/src/test/java/puzzles/binary/rules/SurroundPairDirectRuleTest.java @@ -0,0 +1,66 @@ +package puzzles.binary.rules; + +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.binary.Binary; +import edu.rpi.legup.puzzle.binary.BinaryBoard; +import edu.rpi.legup.puzzle.binary.BinaryCell; +import edu.rpi.legup.puzzle.binary.BinaryType; +import edu.rpi.legup.puzzle.binary.rules.SurroundPairDirectRule; +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 SurroundPairDirectRuleTest { + + private static final SurroundPairDirectRule RULE = new SurroundPairDirectRule(); + private static Binary binary; + + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + binary = new Binary(); + } + + /** + * Tests the SurroundPair direct rule for surrounding a pair of zeros with ones + */ + @Test + public void SurroundPairDirectRule_SurroundTwoZerosWithTwoOnes() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/binary/rules/SurroundPairDirectRule/SurroundTwoZerosWithTwoOnes", binary); + + TreeNode rootNode = binary.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + BinaryBoard board = (BinaryBoard) transition.getBoard(); + BinaryCell cell1 = board.getCell(0, 0); + cell1.setData(BinaryType.ONE.toValue()); + board.addModifiedData(cell1); + + BinaryCell cell2 = board.getCell(3, 0); + cell1.setData(BinaryType.ONE.toValue()); + board.addModifiedData(cell2); + + //Assert.assertNull(RULE.checkRule(transition)); + +// Point location1 = new Point(0, 0); +// Point location2 = new Point(3, 0); +// 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(location1) || point.equals(location2)) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } else { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } +// } +// } + } + +} diff --git a/src/test/resources/puzzles/binary.rules/SurroundPairDirectRule/SurroundTwoZerosWithTwoOnes b/src/test/resources/puzzles/binary.rules/SurroundPairDirectRule/SurroundTwoZerosWithTwoOnes new file mode 100644 index 000000000..026742fea --- /dev/null +++ b/src/test/resources/puzzles/binary.rules/SurroundPairDirectRule/SurroundTwoZerosWithTwoOnes @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/puzzles/binary.rules/SurroundPairDirectRule/test b/src/test/resources/puzzles/binary.rules/SurroundPairDirectRule/test new file mode 100644 index 000000000..e69de29bb From 732bc789b23296e2d4f24d3fe5600aaa4e3e4301 Mon Sep 17 00:00:00 2001 From: offline171 <146153141+offline171@users.noreply.github.com> Date: Tue, 18 Jun 2024 13:47:19 -0400 Subject: [PATCH 132/258] Too Many Stars test suite Test suite works now --- .../rules/TooManyStarsContradictionRuleTests.java | 7 +++---- .../rules/TooManyStarsContradictionRule/ColumnOverloaded | 2 +- .../starbattle/rules/TooManyStarsContradictionRule/Correct | 2 +- .../rules/TooManyStarsContradictionRule/RegionOverloaded | 2 +- .../rules/TooManyStarsContradictionRule/RowOverloaded | 2 +- 5 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/test/java/puzzles/starbattle/rules/TooManyStarsContradictionRuleTests.java b/src/test/java/puzzles/starbattle/rules/TooManyStarsContradictionRuleTests.java index ac9c99329..3424bbaac 100644 --- a/src/test/java/puzzles/starbattle/rules/TooManyStarsContradictionRuleTests.java +++ b/src/test/java/puzzles/starbattle/rules/TooManyStarsContradictionRuleTests.java @@ -113,9 +113,9 @@ public void TooManyStarsContradictionRule_RowOverloaded() } } } - /* Tests the Too Many Stars contradiction rule where it is used incorrectly */ + /*Tests the Too Many Stars contradiction rule for a false contradiction. */ @Test - public void TooManyStarsContradictionRule_Correct() + public void TooManyStarsContradictionRule_FalseContradiction() throws InvalidFileFormatException { TestUtilities.importTestBoard("puzzles/starbattle/rules/TooManyStarsContradictionRule/Correct", starBattle); @@ -125,13 +125,12 @@ public void TooManyStarsContradictionRule_Correct() StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); + Assert.assertNotNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); for (int i = 0; i < board.getHeight(); ++i) { for (int j = 0; j < board.getWidth(); ++j) { Point point = new Point(j,i); Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } } } diff --git a/src/test/resources/puzzles/starbattle/rules/TooManyStarsContradictionRule/ColumnOverloaded b/src/test/resources/puzzles/starbattle/rules/TooManyStarsContradictionRule/ColumnOverloaded index 3c2a1f658..4e7170b3e 100644 --- a/src/test/resources/puzzles/starbattle/rules/TooManyStarsContradictionRule/ColumnOverloaded +++ b/src/test/resources/puzzles/starbattle/rules/TooManyStarsContradictionRule/ColumnOverloaded @@ -31,7 +31,7 @@ - + diff --git a/src/test/resources/puzzles/starbattle/rules/TooManyStarsContradictionRule/Correct b/src/test/resources/puzzles/starbattle/rules/TooManyStarsContradictionRule/Correct index f6b8bd5e1..15921e601 100644 --- a/src/test/resources/puzzles/starbattle/rules/TooManyStarsContradictionRule/Correct +++ b/src/test/resources/puzzles/starbattle/rules/TooManyStarsContradictionRule/Correct @@ -31,7 +31,7 @@ - + diff --git a/src/test/resources/puzzles/starbattle/rules/TooManyStarsContradictionRule/RegionOverloaded b/src/test/resources/puzzles/starbattle/rules/TooManyStarsContradictionRule/RegionOverloaded index 12e1a5872..bcf4a679a 100644 --- a/src/test/resources/puzzles/starbattle/rules/TooManyStarsContradictionRule/RegionOverloaded +++ b/src/test/resources/puzzles/starbattle/rules/TooManyStarsContradictionRule/RegionOverloaded @@ -31,7 +31,7 @@ - + diff --git a/src/test/resources/puzzles/starbattle/rules/TooManyStarsContradictionRule/RowOverloaded b/src/test/resources/puzzles/starbattle/rules/TooManyStarsContradictionRule/RowOverloaded index c193eadff..fdf1adc11 100644 --- a/src/test/resources/puzzles/starbattle/rules/TooManyStarsContradictionRule/RowOverloaded +++ b/src/test/resources/puzzles/starbattle/rules/TooManyStarsContradictionRule/RowOverloaded @@ -31,7 +31,7 @@ - + From 3b64e778970fd5122885ea88d1fce8a77fcdd9c9 Mon Sep 17 00:00:00 2001 From: Bram van Heuveln Date: Tue, 18 Jun 2024 17:50:00 +0000 Subject: [PATCH 133/258] Automated Java code formatting changes --- src/test/java/legup/TestRunner.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/legup/TestRunner.java b/src/test/java/legup/TestRunner.java index 2142f695d..5486a0353 100644 --- a/src/test/java/legup/TestRunner.java +++ b/src/test/java/legup/TestRunner.java @@ -94,7 +94,7 @@ public static void main(String[] args) { printTestResults(result36); Result result37 = JUnitCore.runClasses(TentOrGrassCaseRuleTest.class); printTestResults(result37); - + // Minesweeper Result result38 = JUnitCore.runClasses(MinesweeperUtilitiesTest.class); printTestResults(result38); From a83844ab7f388dee99fd9f7895eb1069ab33c325 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Tue, 18 Jun 2024 14:10:08 -0400 Subject: [PATCH 134/258] Made progress with binary test suite for surround pair --- .../SurroundPairDirectRule/SurroundTwoZerosWithTwoOnes | 0 .../rules}/SurroundPairDirectRule/test | 0 .../SurroundTwoZerosWithTwoOnes | 10 ++++++++++ 3 files changed, 10 insertions(+) rename src/test/resources/puzzles/{binary.rules => binary/rules}/SurroundPairDirectRule/SurroundTwoZerosWithTwoOnes (100%) rename src/test/resources/puzzles/{binary.rules => binary/rules}/SurroundPairDirectRule/test (100%) create mode 100644 src/test/resources/puzzles/nurikabe/rules/BlackBetweenRegionsDirectRule/SurroundTwoZerosWithTwoOnes diff --git a/src/test/resources/puzzles/binary.rules/SurroundPairDirectRule/SurroundTwoZerosWithTwoOnes b/src/test/resources/puzzles/binary/rules/SurroundPairDirectRule/SurroundTwoZerosWithTwoOnes similarity index 100% rename from src/test/resources/puzzles/binary.rules/SurroundPairDirectRule/SurroundTwoZerosWithTwoOnes rename to src/test/resources/puzzles/binary/rules/SurroundPairDirectRule/SurroundTwoZerosWithTwoOnes diff --git a/src/test/resources/puzzles/binary.rules/SurroundPairDirectRule/test b/src/test/resources/puzzles/binary/rules/SurroundPairDirectRule/test similarity index 100% rename from src/test/resources/puzzles/binary.rules/SurroundPairDirectRule/test rename to src/test/resources/puzzles/binary/rules/SurroundPairDirectRule/test diff --git a/src/test/resources/puzzles/nurikabe/rules/BlackBetweenRegionsDirectRule/SurroundTwoZerosWithTwoOnes b/src/test/resources/puzzles/nurikabe/rules/BlackBetweenRegionsDirectRule/SurroundTwoZerosWithTwoOnes new file mode 100644 index 000000000..026742fea --- /dev/null +++ b/src/test/resources/puzzles/nurikabe/rules/BlackBetweenRegionsDirectRule/SurroundTwoZerosWithTwoOnes @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file From 1a1bf5ec6eb047f8bd23beba2186fe8b848dcd94 Mon Sep 17 00:00:00 2001 From: offline171 <146153141+offline171@users.noreply.github.com> Date: Tue, 18 Jun 2024 14:49:26 -0400 Subject: [PATCH 135/258] Editing Blackout test Scraping existing test and starting new --- .../rules/BlackoutDirectRuleTest.java | 136 ++++++++---------- .../Blackout visualized.png | Bin 0 -> 14116 bytes .../{ColumnBlackout => Corner} | 14 +- .../{RegionBlackout => Edge} | 0 .../{RowBlackout => Middle} | 0 5 files changed, 68 insertions(+), 82 deletions(-) create mode 100644 src/test/resources/puzzles/starbattle/rules/BlackoutDirectRule/Blackout visualized.png rename src/test/resources/puzzles/starbattle/rules/BlackoutDirectRule/{ColumnBlackout => Corner} (74%) rename src/test/resources/puzzles/starbattle/rules/BlackoutDirectRule/{RegionBlackout => Edge} (100%) rename src/test/resources/puzzles/starbattle/rules/BlackoutDirectRule/{RowBlackout => Middle} (100%) diff --git a/src/test/java/puzzles/starbattle/rules/BlackoutDirectRuleTest.java b/src/test/java/puzzles/starbattle/rules/BlackoutDirectRuleTest.java index 59d5b37af..4fab421f0 100644 --- a/src/test/java/puzzles/starbattle/rules/BlackoutDirectRuleTest.java +++ b/src/test/java/puzzles/starbattle/rules/BlackoutDirectRuleTest.java @@ -1,76 +1,62 @@ -// This test is for a puzzle that is not fully implemented yet and is causing issues. -// 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.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.*; -// -// public class BlackoutDirectRuleTest { -// -// private static final BlackoutDirectRule RULE = new BlackoutDirectRule(); -// private static StarBattle starbattle; -// -// @BeforeClass -// public static void setUp() { -// MockGameBoardFacade.getInstance(); -// starbattle = new StarBattle(); -// } -// -// @Test -// public void BlackoutDirectRuleTest_ColumnBlackout() throws InvalidFileFormatException { -// -// TestUtilities.importTestBoard("puzzles/starbattle/rules/BlackoutDirectRule/ColumnBlackout", -// starbattle); -// TreeNode rootNode = starbattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// -// StarBattleCell cell1 = board.getCell(1, 1); -// cell1.setData(StarBattleCellType.BLACK.value); -// StarBattleCell cell2 = board.getCell(1, 2); -// cell2.setData(StarBattleCellType.BLACK.value); -// StarBattleCell cell3 = board.getCell(1, 3); -// cell3.setData(StarBattleCellType.BLACK.value); -// -// board.addModifiedData(cell1); -// board.addModifiedData(cell2); -// board.addModifiedData(cell3); -// -// Assert.assertNull(RULE.checkRule(transition)); -// -// for (int i = 0; i < board.getHeight(); i++) { -// for (int k = 0; k < board.getWidth(); k++) { -// Point point = new Point(k, i); -// if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) || -// point.equals(cell3.getLocation())) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } -// else { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } -// } -// } -// } -// } +import edu.rpi.legup.puzzle.starbattle.rules.BlackoutDirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +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.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 { + private static final BlackoutDirectRule RULE = new BlackoutDirectRule(); + private static StarBattle starBattle; + + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + starBattle = new StarBattle(); + } + + /* Blackout Direct Rule where star is in the corner */ + @Test + public void BlackoutDirectRuleTestCorner() + throws InvalidFileFormatException + { + TestUtilities.importTestBoard("puzzles/starbattle/rules/BlackoutDirectRule/Corner", starBattle); + TreeNode rootNode = starBattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(0,0); /* + StarBattleCell cell2 = board.getCell(0,1); + StarBattleCell cell3 = board.getCell(1,0); + StarBattleCell cell4 = board.getCell(1,1); */ + + Assert.assertNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); ++i) { + for (int j = 0; j < board.getWidth(); ++j) { + Point point = new Point(j,i); + if (point.equals(cell1.getLocation()) /*|| point.equals(cell2.getLocation()) || + point.equals(cell3.getLocation()) || point.equals(cell4.getLocation()) */) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + /* + else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + */ + } + } + } + +} diff --git a/src/test/resources/puzzles/starbattle/rules/BlackoutDirectRule/Blackout visualized.png b/src/test/resources/puzzles/starbattle/rules/BlackoutDirectRule/Blackout visualized.png new file mode 100644 index 0000000000000000000000000000000000000000..e8670e07ebc8a447459428eb7fa375dec0672028 GIT binary patch literal 14116 zcmeHN2~<;88h$S;U;r18BrIX6ic-fED4?tn0Z~DykfN;;B5HIPTuVi02us0*9c&#` zco1C5pv3A_1Sy0?)G8#PQ&b|0C{QIpMRsLg9x?c$_MG;#XY@=sCx>%#@BQz;eE;|V z_ud@v@%GTvplSdBpy|1M*(U%14$D4j1o)ei<`YryKlL5U*X{;@X)|RXutCBd2LNNh za~Z>L?=f~{Uza#4-j}Z7E;J|O`79k0t)ij=UIk1{u&GIPQzJ(}0zoDf9-y9S^^i|b zjAewQd$vi(spI#4usmkRjkK0dsho>ZsB9V_j9oBPW5G6vId*ONh|dhRX#4_L9F;&9rwZc#a(P z`$3OnBiH_4lEo3{CS~X<$pE0mLkDJ!`dnUe_mB(|I;79gf!hz%dS_Sua&zRVUgBKd zq&Zl$IRc_{)C+dNrAP{MyYyb^(YA(%7W@M&okSRSmjNsmJEf3-IL|wqT^u!G=+YAH>@U+it3Q!u23o%X0+zo%w07(^w7@Iv*hkN_eFUW#GhZG{VBk0sXI33-e(a*G_sct?C`{xTunuS zBN!B5o03n=!Se=^2PY%%N>x%Bd#futWy3ss#OMZe%mo<8zwf9`DAcr)uP2^#ueFjj zm^j%6i7zF5|C)rdC$}*CvSGyYsdy#NgV4sU-`$Q#h!#H%Mo{HCQ%OJYLa}b>z>+(Y z>v2l!fqbKtD>cYv-eHIrJCq>u+rz2E4%F&=^y*Y%roqaUA1Z_^4-+y`tAiD**_5O+ zzVuAcaZx<@tX(3JkTIATa&dS#d0CtrIW8`aY`1tZ`GYxggxi8Q<$E+XA_b@wjet}D z%6|Hq~c* zYp2Ts4xU573G|mOdOoI2x)|C*O|N zot|SIew_oQtFsP|bp_cW+8vzI4sJQX+tJx)>tJDom#X=pc@y*k3e$=H>-apnVg@?Z zz?;BnWX53!E`8l4gqcojp~wRC0#7$k&vfjJ6<_~KmQF6SltTt@((~8|e;O(%*>_R6XN-=JQaCdIISm6EP(i^xhCy)x)_bcP5>Mg0c|8 zR6U#;gp>xc&q2zML1j8bi6ZnoZOIRm8oxz2rxmT z6c$jQ?MQ1#dpbTM3Y$PsqlN|rJf-)3nLa#ap!>W+Ri)Aa;kVz{>M85sPwPQW09d7N z9>TkRamav___quCNbMz~(J?t}NnX#H>;is!p&C-ZE$onY?}7kW@mOJwxFg zV3oBwB}GT~FekLWYiTLMq!I-!vMHL+eCcH2ZfZ7L z&rrX1dTVE`@qz`F(+$X1ceHoRkHC$?pbp;BV6GQGLf}j8B;z5ir8`G|^ z7!`jVh7`LJC0d3sE#>_Crr!qo;Le)QzfWsEa7LfRjXE!RuvZV#g1^`eO@_!%kl`>2KGahCaP_D(@qF$y}@N{ zlbY2LVNwGxY!$hNozFG7OiNid1OJ0beTw)E(#?Fefv3u^F+yF)pi&@AO63+nlcY9)SPe zp9@V@yj1aehw6-q_ui9-5EXBzctgb-lc(W#*$=WN7=D5ZY7%U13;1EX%C z3l~0wYsytQYDPDES`F{NB@qf(Q@6h7|gO`z!@q6y=-~0%1#PLfb*>S0F z)WX>Oh{?x`xBeB65UTuA)mc@YRn=J)52$!R#RDoHQ1O6@2i_|lc*}2y0Q+gvs(vmC p?B5r6^ytyH&K&2z>^DSMAiV5b(X(G}o4}3(Jl(vPon6X``7dS?MOOd- literal 0 HcmV?d00001 diff --git a/src/test/resources/puzzles/starbattle/rules/BlackoutDirectRule/ColumnBlackout b/src/test/resources/puzzles/starbattle/rules/BlackoutDirectRule/Corner similarity index 74% rename from src/test/resources/puzzles/starbattle/rules/BlackoutDirectRule/ColumnBlackout rename to src/test/resources/puzzles/starbattle/rules/BlackoutDirectRule/Corner index ddcc4dc9a..7216cc43d 100644 --- a/src/test/resources/puzzles/starbattle/rules/BlackoutDirectRule/ColumnBlackout +++ b/src/test/resources/puzzles/starbattle/rules/BlackoutDirectRule/Corner @@ -4,9 +4,9 @@ - + - + @@ -20,16 +20,16 @@ - - - + + + - - + + diff --git a/src/test/resources/puzzles/starbattle/rules/BlackoutDirectRule/RegionBlackout b/src/test/resources/puzzles/starbattle/rules/BlackoutDirectRule/Edge similarity index 100% rename from src/test/resources/puzzles/starbattle/rules/BlackoutDirectRule/RegionBlackout rename to src/test/resources/puzzles/starbattle/rules/BlackoutDirectRule/Edge diff --git a/src/test/resources/puzzles/starbattle/rules/BlackoutDirectRule/RowBlackout b/src/test/resources/puzzles/starbattle/rules/BlackoutDirectRule/Middle similarity index 100% rename from src/test/resources/puzzles/starbattle/rules/BlackoutDirectRule/RowBlackout rename to src/test/resources/puzzles/starbattle/rules/BlackoutDirectRule/Middle From 12038600a6e66811f529fb13867a42ca1f46d146 Mon Sep 17 00:00:00 2001 From: summerhenson Date: Tue, 18 Jun 2024 14:53:26 -0400 Subject: [PATCH 136/258] Basic Surround Star direct rule tests --- .../rules/SurroundStarDirectRuleTest.java | 146 ++++++++++++++++++ .../rules/SurroundStarDirectRule/CenterStar | 29 ++++ .../rules/SurroundStarDirectRule/CornerStar | 29 ++++ 3 files changed, 204 insertions(+) create mode 100644 src/test/java/puzzles/starbattle/rules/SurroundStarDirectRuleTest.java create mode 100644 src/test/resources/puzzles/starbattle/rules/SurroundStarDirectRule/CenterStar create mode 100644 src/test/resources/puzzles/starbattle/rules/SurroundStarDirectRule/CornerStar diff --git a/src/test/java/puzzles/starbattle/rules/SurroundStarDirectRuleTest.java b/src/test/java/puzzles/starbattle/rules/SurroundStarDirectRuleTest.java new file mode 100644 index 000000000..ae7621b31 --- /dev/null +++ b/src/test/java/puzzles/starbattle/rules/SurroundStarDirectRuleTest.java @@ -0,0 +1,146 @@ +package puzzles.starbattle.rules; + +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +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.SurroundStarDirectRule; +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 SurroundStarDirectRuleTest { + + private static final SurroundStarDirectRule RULE = new SurroundStarDirectRule(); + private static StarBattle starbattle; + + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + starbattle = new StarBattle(); + } + + @Test + public void SurroundStarDirectRule_CenterStarOneTile() throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/SurroundStarDirectRule/CenterStar", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell = board.getCell(0,1); + cell.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell); + + Assert.assertNull(RULE.checkRule(transition)); + + Point location = new Point(0, 1); + 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(location)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void SurroundStarDirectRule_CenterStarAllTiles() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/SurroundStarDirectRule/CenterStar", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + for (int i = 0; i < board.getWidth(); i++) { + for (int j = 0; j < board.getHeight(); j++) { + if (i != 1 || j != 1) { + StarBattleCell cell = board.getCell(i,j); + cell.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell); + } + } + } + + Assert.assertNull(RULE.checkRule(transition)); + + Point location = new Point(1, 1); + 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(location)) { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void SurroundStarDirectRule_CornerStar() throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/SurroundStarDirectRule/CornerStar", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(0,1); + cell1.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell1); + StarBattleCell cell2 = board.getCell(1,0); + cell2.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell2); + StarBattleCell cell3 = board.getCell(1,1); + cell3.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell3); + + Assert.assertNull(RULE.checkRule(transition)); + + Point location1 = new Point(0, 1); + Point location2 = new Point(1,0); + Point location3 = new Point(1,1); + 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(location1) || point.equals(location2) || point.equals(location3)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void SurroundStarDirectRule_FalseContradiction() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/SurroundStarDirectRule/CornerStar", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell = board.getCell(2,0); + cell.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell); + + Assert.assertNotNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); i++) { + for (int k = 0; k < board.getWidth(); k++) { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } +} diff --git a/src/test/resources/puzzles/starbattle/rules/SurroundStarDirectRule/CenterStar b/src/test/resources/puzzles/starbattle/rules/SurroundStarDirectRule/CenterStar new file mode 100644 index 000000000..a22f988df --- /dev/null +++ b/src/test/resources/puzzles/starbattle/rules/SurroundStarDirectRule/CenterStar @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/SurroundStarDirectRule/CornerStar b/src/test/resources/puzzles/starbattle/rules/SurroundStarDirectRule/CornerStar new file mode 100644 index 000000000..50558d4c4 --- /dev/null +++ b/src/test/resources/puzzles/starbattle/rules/SurroundStarDirectRule/CornerStar @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 65db0f75fe4339d34df59f0d0f9bc0d7f1ae503a Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Tue, 18 Jun 2024 15:05:15 -0400 Subject: [PATCH 137/258] Made progress with eliminate the impossible direct rule --- ... => EliminateTheImpossibleDirectRule.java} | 38 ++++++++++++++++++- 1 file changed, 36 insertions(+), 2 deletions(-) rename src/main/java/edu/rpi/legup/puzzle/binary/rules/{EliminateTheImpossible.java => EliminateTheImpossibleDirectRule.java} (51%) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossible.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java similarity index 51% rename from src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossible.java rename to src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java index 311057f94..f705b7716 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossible.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java @@ -9,10 +9,12 @@ import edu.rpi.legup.puzzle.binary.BinaryBoard; import edu.rpi.legup.puzzle.binary.BinaryCell; -public class EliminateTheImpossible extends DirectRule { +import java.util.ArrayList; + +public class EliminateTheImpossibleDirectRule extends DirectRule { private final String INVALID_USE_MESSAGE = "Number at cell is incorrect"; - public EliminateTheImpossible() { + public EliminateTheImpossibleDirectRule() { super( "BINA-BASC-0003", "Eliminate The Impossible", @@ -20,6 +22,38 @@ public EliminateTheImpossible() { "edu/rpi/legup/images/binary/rules/OneTileGapDirectRule.png"); } + // Function to generate all binary strings + static String generateAllBinaryStrings(int n, String arr, int i) + { + if (i == n) + { + return arr; + } + + // First assign "0" at ith position + // and try for all other permutations + // for remaining positions + arr = arr + "0"; + generateAllBinaryStrings(n, arr, i + 1); + + // And then assign "1" at ith position + // and try for all other permutations + // for remaining positions + arr = arr + "1"; + generateAllBinaryStrings(n, arr, i + 1); + + return null; + } + + public ArrayList binaryCombiniations(int numEmpty) { + + ArrayList possibilities = new ArrayList<>(); + String arr = ""; + if (generateAllBinaryStrings(numEmpty, arr, 0) != null) { + possibilities.add(arr); + } + return null; + } @Override public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { BinaryBoard origBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); From 02bf6f5f863180eb0519e1a2c46d4b50a85191fd Mon Sep 17 00:00:00 2001 From: offline171 <146153141+offline171@users.noreply.github.com> Date: Tue, 18 Jun 2024 15:15:46 -0400 Subject: [PATCH 138/258] Blackout Test Suite first test First test for Blackout Direct Rule passes --- .../rules/BlackoutDirectRuleTest.java | 30 +++++++++++----- .../rules/BlackoutDirectRule/Corner | 35 ++++++++++--------- 2 files changed, 40 insertions(+), 25 deletions(-) diff --git a/src/test/java/puzzles/starbattle/rules/BlackoutDirectRuleTest.java b/src/test/java/puzzles/starbattle/rules/BlackoutDirectRuleTest.java index 4fab421f0..4c27ffbeb 100644 --- a/src/test/java/puzzles/starbattle/rules/BlackoutDirectRuleTest.java +++ b/src/test/java/puzzles/starbattle/rules/BlackoutDirectRuleTest.java @@ -36,25 +36,39 @@ public void BlackoutDirectRuleTestCorner() transition.setRule(RULE); StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell1 = board.getCell(0,0); /* - StarBattleCell cell2 = board.getCell(0,1); - StarBattleCell cell3 = board.getCell(1,0); - StarBattleCell cell4 = board.getCell(1,1); */ + StarBattleCell cell1 = board.getCell(1,0); + cell1.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell2 = board.getCell(2,0); + cell2.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell3 = board.getCell(3,0); + cell3.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell4 = board.getCell(0,1); + cell4.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell5 = board.getCell(0,2); + cell5.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell6 = board.getCell(0,3); + cell6.setData(StarBattleCellType.BLACK.value); + + board.addModifiedData(cell1); + board.addModifiedData(cell2); + board.addModifiedData(cell3); + board.addModifiedData(cell4); + board.addModifiedData(cell5); + board.addModifiedData(cell6); Assert.assertNull(RULE.checkRule(transition)); for (int i = 0; i < board.getHeight(); ++i) { for (int j = 0; j < board.getWidth(); ++j) { Point point = new Point(j,i); - if (point.equals(cell1.getLocation()) /*|| point.equals(cell2.getLocation()) || - point.equals(cell3.getLocation()) || point.equals(cell4.getLocation()) */) { + if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) || + point.equals(cell3.getLocation()) || point.equals(cell4.getLocation()) || + point.equals(cell5.getLocation()) || point.equals(cell6.getLocation())) { Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); } - /* else { Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); } - */ } } } diff --git a/src/test/resources/puzzles/starbattle/rules/BlackoutDirectRule/Corner b/src/test/resources/puzzles/starbattle/rules/BlackoutDirectRule/Corner index 7216cc43d..d1c6722e4 100644 --- a/src/test/resources/puzzles/starbattle/rules/BlackoutDirectRule/Corner +++ b/src/test/resources/puzzles/starbattle/rules/BlackoutDirectRule/Corner @@ -4,37 +4,38 @@ - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - \ No newline at end of file + + From 3206f46310f93aa40be70e83c7ab813597afdae9 Mon Sep 17 00:00:00 2001 From: Jose Barbiere <117523329+ContemporaryNietzsche@users.noreply.github.com> Date: Tue, 18 Jun 2024 18:59:25 -0400 Subject: [PATCH 139/258] test committ --- .../rpi/legup/puzzle/binary/rules/EliminateTheImpossible.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossible.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossible.java index 311057f94..9dc1c0445 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossible.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossible.java @@ -25,7 +25,7 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem BinaryBoard origBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); BinaryCell binaryCell = (BinaryCell) puzzleElement; - return "Grouping of Three Ones or Zeros not found"; + return "Grouping of Three Ones or Zeros not found TEST"; } @Override From 58ff2bf500260f496fd5b06f0a3ae1bcd80fa539 Mon Sep 17 00:00:00 2001 From: Jose Barbiere <117523329+ContemporaryNietzsche@users.noreply.github.com> Date: Thu, 20 Jun 2024 15:23:25 -0400 Subject: [PATCH 140/258] t --- .../puzzle/binary/rules/EliminateTheImpossibleDirectRule.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java index f7cbbacc9..6b525312f 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java @@ -11,6 +11,8 @@ import java.util.ArrayList; +// dont mind me + public class EliminateTheImpossibleDirectRule extends DirectRule { private final String INVALID_USE_MESSAGE = "Number at cell is incorrect"; From ec8e1d3803ce3b9c06a48be36d31e305f1c4f099 Mon Sep 17 00:00:00 2001 From: ContemporaryNietzsche Date: Fri, 21 Jun 2024 11:44:30 -0400 Subject: [PATCH 141/258] commented before implementation --- .../binary/rules/EliminateTheImpossibleDirectRule.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java index 6b525312f..6f8ee3ea9 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java @@ -1,6 +1,5 @@ package edu.rpi.legup.puzzle.binary.rules; - import edu.rpi.legup.model.gameboard.Board; import edu.rpi.legup.model.gameboard.PuzzleElement; import edu.rpi.legup.model.rules.DirectRule; @@ -11,8 +10,6 @@ import java.util.ArrayList; -// dont mind me - public class EliminateTheImpossibleDirectRule extends DirectRule { private final String INVALID_USE_MESSAGE = "Number at cell is incorrect"; @@ -58,6 +55,11 @@ public ArrayList binaryCombiniations(int numEmpty) { } @Override public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + // This function should first check if there are three open spaces, if so, continue, else figure out + // how many spots are open, all the possible binary combinations that could be put there, and by + // analyzing the common factors, logically determine which number has a set spot, meaning that we know + // that a certain spot must be a zero or a one + BinaryBoard origBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); BinaryCell binaryCell = (BinaryCell) puzzleElement; From b222cdc26325dec58dbe4abf1a13b5b9999f3b45 Mon Sep 17 00:00:00 2001 From: offline171 <146153141+offline171@users.noreply.github.com> Date: Fri, 21 Jun 2024 13:53:43 -0400 Subject: [PATCH 142/258] Finishing Blackout Test Added incorrect use of rule test --- .../rules/BlackoutDirectRuleTest.java | 148 +++++++++++++++++- .../starbattle/rules/BlackoutDirectRule/Edge | 43 ++--- .../rules/BlackoutDirectRule/Middle | 43 ++--- 3 files changed, 192 insertions(+), 42 deletions(-) diff --git a/src/test/java/puzzles/starbattle/rules/BlackoutDirectRuleTest.java b/src/test/java/puzzles/starbattle/rules/BlackoutDirectRuleTest.java index 4c27ffbeb..76367ace5 100644 --- a/src/test/java/puzzles/starbattle/rules/BlackoutDirectRuleTest.java +++ b/src/test/java/puzzles/starbattle/rules/BlackoutDirectRuleTest.java @@ -44,17 +44,71 @@ public void BlackoutDirectRuleTestCorner() cell3.setData(StarBattleCellType.BLACK.value); StarBattleCell cell4 = board.getCell(0,1); cell4.setData(StarBattleCellType.BLACK.value); - StarBattleCell cell5 = board.getCell(0,2); + StarBattleCell cell5 = board.getCell(1,1); cell5.setData(StarBattleCellType.BLACK.value); - StarBattleCell cell6 = board.getCell(0,3); + StarBattleCell cell6 = board.getCell(0,2); cell6.setData(StarBattleCellType.BLACK.value); - + StarBattleCell cell7 = board.getCell(0,3); + cell7.setData(StarBattleCellType.BLACK.value); + + board.addModifiedData(cell1); + board.addModifiedData(cell2); + board.addModifiedData(cell3); + board.addModifiedData(cell4); + board.addModifiedData(cell5); + board.addModifiedData(cell6); + board.addModifiedData(cell7); + + Assert.assertNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); ++i) { + for (int j = 0; j < board.getWidth(); ++j) { + Point point = new Point(j,i); + if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) || + point.equals(cell3.getLocation()) || point.equals(cell4.getLocation()) || + point.equals(cell5.getLocation()) || point.equals(cell6.getLocation()) || + point.equals(cell7.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + } + } + } + /* Blackout Direct Rule where star is on the edge */ + @Test + public void BlackoutDirectRuleTestEdge() + throws InvalidFileFormatException + { + TestUtilities.importTestBoard("puzzles/starbattle/rules/BlackoutDirectRule/Edge", starBattle); + TreeNode rootNode = starBattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(0,0); + cell1.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell2 = board.getCell(2,0); + cell2.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell3 = board.getCell(3,0); + cell3.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell4 = board.getCell(0,1); + cell4.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell5 = board.getCell(1,1); + cell5.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell6 = board.getCell(1,2); + cell6.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell7 = board.getCell(1,3); + cell7.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell1); board.addModifiedData(cell2); board.addModifiedData(cell3); board.addModifiedData(cell4); board.addModifiedData(cell5); board.addModifiedData(cell6); + board.addModifiedData(cell7); Assert.assertNull(RULE.checkRule(transition)); @@ -63,7 +117,8 @@ public void BlackoutDirectRuleTestCorner() Point point = new Point(j,i); if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) || point.equals(cell3.getLocation()) || point.equals(cell4.getLocation()) || - point.equals(cell5.getLocation()) || point.equals(cell6.getLocation())) { + point.equals(cell5.getLocation()) || point.equals(cell6.getLocation()) || + point.equals(cell7.getLocation())) { Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); } else { @@ -73,4 +128,89 @@ public void BlackoutDirectRuleTestCorner() } } + /* Blackout Direct Rule where star is on the edge */ + @Test + public void BlackoutDirectRuleTestMiddle() + throws InvalidFileFormatException + { + TestUtilities.importTestBoard("puzzles/starbattle/rules/BlackoutDirectRule/Middle", starBattle); + TreeNode rootNode = starBattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(0,0); + cell1.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell2 = board.getCell(1,0); + cell2.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell3 = board.getCell(0,1); + cell3.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell4 = board.getCell(2,1); + cell4.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell5 = board.getCell(3,1); + cell5.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell6 = board.getCell(1,2); + cell6.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell7 = board.getCell(1,3); + cell7.setData(StarBattleCellType.BLACK.value); + + board.addModifiedData(cell1); + board.addModifiedData(cell2); + board.addModifiedData(cell3); + board.addModifiedData(cell4); + board.addModifiedData(cell5); + board.addModifiedData(cell6); + board.addModifiedData(cell7); + + Assert.assertNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); ++i) { + for (int j = 0; j < board.getWidth(); ++j) { + Point point = new Point(j,i); + if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) || + point.equals(cell3.getLocation()) || point.equals(cell4.getLocation()) || + point.equals(cell5.getLocation()) || point.equals(cell6.getLocation()) || + point.equals(cell7.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + } + } + } + /* Blackout Direct Rule where rule is called incorrectly */ + @Test + public void BlackoutDirectRuleTestFalse() + throws InvalidFileFormatException + { + TestUtilities.importTestBoard("puzzles/starbattle/rules/BlackoutDirectRule/Middle", starBattle); + TreeNode rootNode = starBattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(2,2); + cell1.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell2 = board.getCell(2,3); + cell2.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell3 = board.getCell(3,2); + cell3.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell4 = board.getCell(3,3); + + board.addModifiedData(cell1); + board.addModifiedData(cell2); + board.addModifiedData(cell3); + board.addModifiedData(cell4); + + Assert.assertNotNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); ++i) { + for (int j = 0; j < board.getWidth(); ++j) { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + } + } + + } diff --git a/src/test/resources/puzzles/starbattle/rules/BlackoutDirectRule/Edge b/src/test/resources/puzzles/starbattle/rules/BlackoutDirectRule/Edge index f2a5b42d9..7995657c9 100644 --- a/src/test/resources/puzzles/starbattle/rules/BlackoutDirectRule/Edge +++ b/src/test/resources/puzzles/starbattle/rules/BlackoutDirectRule/Edge @@ -1,36 +1,41 @@ - - + + + - - - - + + + + - - - - + + + + - - - - + + + + + - - - - + + + + + - \ No newline at end of file + + + diff --git a/src/test/resources/puzzles/starbattle/rules/BlackoutDirectRule/Middle b/src/test/resources/puzzles/starbattle/rules/BlackoutDirectRule/Middle index f2a5b42d9..b6f483244 100644 --- a/src/test/resources/puzzles/starbattle/rules/BlackoutDirectRule/Middle +++ b/src/test/resources/puzzles/starbattle/rules/BlackoutDirectRule/Middle @@ -1,36 +1,41 @@ - - + + + - - - - + + + + - - - - + + + + - - - - + + + + + - - - - + + + + + - \ No newline at end of file + + + From cd42e83f05c4599a5cd90af612b102b24406a161 Mon Sep 17 00:00:00 2001 From: summerhenson Date: Fri, 21 Jun 2024 14:07:06 -0400 Subject: [PATCH 143/258] Added new Surround Star direct rule test --- .../rules/SurroundStarDirectRuleTest.java | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/test/java/puzzles/starbattle/rules/SurroundStarDirectRuleTest.java b/src/test/java/puzzles/starbattle/rules/SurroundStarDirectRuleTest.java index ae7621b31..f6894d6de 100644 --- a/src/test/java/puzzles/starbattle/rules/SurroundStarDirectRuleTest.java +++ b/src/test/java/puzzles/starbattle/rules/SurroundStarDirectRuleTest.java @@ -53,6 +53,33 @@ public void SurroundStarDirectRule_CenterStarOneTile() throws InvalidFileFormatE } } + @Test + public void SurroundStarDirectRule_CenterStarOneTileDiagonal() throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/SurroundStarDirectRule/CenterStar", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell = board.getCell(0,0); + cell.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell); + + Assert.assertNull(RULE.checkRule(transition)); + + Point location = new Point(0, 0); + 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(location)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + @Test public void SurroundStarDirectRule_CenterStarAllTiles() throws InvalidFileFormatException { @@ -136,7 +163,7 @@ public void SurroundStarDirectRule_FalseContradiction() board.addModifiedData(cell); Assert.assertNotNull(RULE.checkRule(transition)); - + for (int i = 0; i < board.getHeight(); i++) { for (int k = 0; k < board.getWidth(); k++) { Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); From 67720714156c0b7b77a5fa3e6b597de5018d3a91 Mon Sep 17 00:00:00 2001 From: offline171 <146153141+offline171@users.noreply.github.com> Date: Fri, 21 Jun 2024 14:29:47 -0400 Subject: [PATCH 144/258] Finish with Stars Tests added for Finish with Stars --- .../rules/FinishWithStarsDirectRuleTest.java | 209 ++++++++++++++++++ .../FinishWithStarsDirectRule/CornerColumn | 41 ++++ .../rules/FinishWithStarsDirectRule/CornerRow | 41 ++++ .../FinishWithStarsDirectRule/CornerRowColumn | 41 ++++ .../FinishWithStarsDirectRule/DoubleRegion | 41 ++++ .../rules/FinishWithStarsDirectRule/False | 41 ++++ .../rules/FinishWithStarsDirectRule/Region | 41 ++++ 7 files changed, 455 insertions(+) create mode 100644 src/test/java/puzzles/starbattle/rules/FinishWithStarsDirectRuleTest.java create mode 100644 src/test/resources/puzzles/starbattle/rules/FinishWithStarsDirectRule/CornerColumn create mode 100644 src/test/resources/puzzles/starbattle/rules/FinishWithStarsDirectRule/CornerRow create mode 100644 src/test/resources/puzzles/starbattle/rules/FinishWithStarsDirectRule/CornerRowColumn create mode 100644 src/test/resources/puzzles/starbattle/rules/FinishWithStarsDirectRule/DoubleRegion create mode 100644 src/test/resources/puzzles/starbattle/rules/FinishWithStarsDirectRule/False create mode 100644 src/test/resources/puzzles/starbattle/rules/FinishWithStarsDirectRule/Region diff --git a/src/test/java/puzzles/starbattle/rules/FinishWithStarsDirectRuleTest.java b/src/test/java/puzzles/starbattle/rules/FinishWithStarsDirectRuleTest.java new file mode 100644 index 000000000..552e3703e --- /dev/null +++ b/src/test/java/puzzles/starbattle/rules/FinishWithStarsDirectRuleTest.java @@ -0,0 +1,209 @@ +package puzzles.starbattle.rules; + +import edu.rpi.legup.puzzle.starbattle.rules.FinishWithStarsDirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +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.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 FinishWithStarsDirectRuleTest { + private static final FinishWithStarsDirectRule RULE = new FinishWithStarsDirectRule(); + private static StarBattle starBattle; + + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + starBattle = new StarBattle(); + } + + /* Finish With Stars Direct Rule where star is in the corner and only the row is blacked out */ + @Test + public void FinishWithStarsDirectRuleTestCornerRow() + throws InvalidFileFormatException + { + TestUtilities.importTestBoard("puzzles/starbattle/rules/FinishWithStarsDirectRule/CornerRow", starBattle); + TreeNode rootNode = starBattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(0,0); + cell1.setData(StarBattleCellType.STAR.value); + + board.addModifiedData(cell1); + + Assert.assertNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); ++i) { + for (int j = 0; j < board.getWidth(); ++j) { + Point point = new Point(j,i); + if (point.equals(cell1.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + } + } + } + + /* Finish With Stars Direct Rule where star is in the corner and only the column is blacked out */ + @Test + public void FinishWithStarsDirectRuleTestCornerColumn() + throws InvalidFileFormatException + { + TestUtilities.importTestBoard("puzzles/starbattle/rules/FinishWithStarsDirectRule/CornerColumn", starBattle); + TreeNode rootNode = starBattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(0,0); + cell1.setData(StarBattleCellType.STAR.value); + + board.addModifiedData(cell1); + + Assert.assertNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); ++i) { + for (int j = 0; j < board.getWidth(); ++j) { + Point point = new Point(j,i); + if (point.equals(cell1.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + } + } + } + + /* Finish With Stars Direct Rule where star is in the corner and only the column is blacked out */ + @Test + public void FinishWithStarsDirectRuleTestCornerRowColumn() + throws InvalidFileFormatException + { + TestUtilities.importTestBoard("puzzles/starbattle/rules/FinishWithStarsDirectRule/CornerRowColumn", starBattle); + TreeNode rootNode = starBattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(0,0); + cell1.setData(StarBattleCellType.STAR.value); + + board.addModifiedData(cell1); + + Assert.assertNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); ++i) { + for (int j = 0; j < board.getWidth(); ++j) { + Point point = new Point(j,i); + if (point.equals(cell1.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + } + } + } + /* Finish With Stars Direct Rule where star is in the corner and only the column is blacked out */ + @Test + public void FinishWithStarsDirectRuleTestRegion() + throws InvalidFileFormatException + { + TestUtilities.importTestBoard("puzzles/starbattle/rules/FinishWithStarsDirectRule/Region", starBattle); + TreeNode rootNode = starBattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(1,1); + cell1.setData(StarBattleCellType.STAR.value); + + board.addModifiedData(cell1); + + Assert.assertNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); ++i) { + for (int j = 0; j < board.getWidth(); ++j) { + Point point = new Point(j,i); + if (point.equals(cell1.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + } + } + } + /* Finish With Stars Direct Rule where there are two stars in two different mostly blacked out regions */ + @Test + public void FinishWithStarsDirectRuleTestDoubleRegion() + throws InvalidFileFormatException + { + TestUtilities.importTestBoard("puzzles/starbattle/rules/FinishWithStarsDirectRule/DoubleRegion", starBattle); + TreeNode rootNode = starBattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(1,1); + cell1.setData(StarBattleCellType.STAR.value); + StarBattleCell cell2 = board.getCell(2,3); + cell2.setData(StarBattleCellType.STAR.value); + + board.addModifiedData(cell1); + board.addModifiedData(cell2); + + Assert.assertNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); ++i) { + for (int j = 0; j < board.getWidth(); ++j) { + Point point = new Point(j,i); + if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + } + } + } + + /* Finish With Stars Direct Rule where there are two stars in two different mostly blacked out regions */ + @Test + public void FinishWithStarsDirectRuleTestFalse() + throws InvalidFileFormatException + { + TestUtilities.importTestBoard("puzzles/starbattle/rules/FinishWithStarsDirectRule/False", starBattle); + TreeNode rootNode = starBattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(2,0); + cell1.setData(StarBattleCellType.STAR.value); + + board.addModifiedData(cell1); + + Assert.assertNotNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); ++i) { + for (int j = 0; j < board.getWidth(); ++j) { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + } + } + +} diff --git a/src/test/resources/puzzles/starbattle/rules/FinishWithStarsDirectRule/CornerColumn b/src/test/resources/puzzles/starbattle/rules/FinishWithStarsDirectRule/CornerColumn new file mode 100644 index 000000000..ac0e35380 --- /dev/null +++ b/src/test/resources/puzzles/starbattle/rules/FinishWithStarsDirectRule/CornerColumn @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/starbattle/rules/FinishWithStarsDirectRule/CornerRow b/src/test/resources/puzzles/starbattle/rules/FinishWithStarsDirectRule/CornerRow new file mode 100644 index 000000000..3fb595a65 --- /dev/null +++ b/src/test/resources/puzzles/starbattle/rules/FinishWithStarsDirectRule/CornerRow @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/starbattle/rules/FinishWithStarsDirectRule/CornerRowColumn b/src/test/resources/puzzles/starbattle/rules/FinishWithStarsDirectRule/CornerRowColumn new file mode 100644 index 000000000..44fe2b9ba --- /dev/null +++ b/src/test/resources/puzzles/starbattle/rules/FinishWithStarsDirectRule/CornerRowColumn @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/starbattle/rules/FinishWithStarsDirectRule/DoubleRegion b/src/test/resources/puzzles/starbattle/rules/FinishWithStarsDirectRule/DoubleRegion new file mode 100644 index 000000000..16171cd01 --- /dev/null +++ b/src/test/resources/puzzles/starbattle/rules/FinishWithStarsDirectRule/DoubleRegion @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/starbattle/rules/FinishWithStarsDirectRule/False b/src/test/resources/puzzles/starbattle/rules/FinishWithStarsDirectRule/False new file mode 100644 index 000000000..16ab2cc7c --- /dev/null +++ b/src/test/resources/puzzles/starbattle/rules/FinishWithStarsDirectRule/False @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/starbattle/rules/FinishWithStarsDirectRule/Region b/src/test/resources/puzzles/starbattle/rules/FinishWithStarsDirectRule/Region new file mode 100644 index 000000000..d3c74607f --- /dev/null +++ b/src/test/resources/puzzles/starbattle/rules/FinishWithStarsDirectRule/Region @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 4db09f95c39234b52f93656a15683da8fb0859ef Mon Sep 17 00:00:00 2001 From: ContemporaryNietzsche Date: Fri, 21 Jun 2024 15:03:22 -0400 Subject: [PATCH 145/258] added generateAllBinaryStrings functions(pair programmed with Zach) --- .../EliminateTheImpossibleDirectRule.java | 64 +++++++++++-------- 1 file changed, 38 insertions(+), 26 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java index 6f8ee3ea9..2898ed084 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java @@ -8,6 +8,9 @@ import edu.rpi.legup.puzzle.binary.BinaryBoard; import edu.rpi.legup.puzzle.binary.BinaryCell; +import java.util.LinkedList; +import java.util.Queue; +import java.lang.Math.*; import java.util.ArrayList; public class EliminateTheImpossibleDirectRule extends DirectRule { @@ -22,37 +25,39 @@ public EliminateTheImpossibleDirectRule() { } // Function to generate all binary strings - static String generateAllBinaryStrings(int n, String arr, int i) + void generateAllBinaryStrings(double x, int poss, ArrayList possibilities) { - if (i == n) - { - return arr; + int count = (int)x; + int finalLen = poss; + + Queue q = new LinkedList(); + q.add("1"); + while (count-- > 0) { + String s1 = q.peek(); + q.remove(); + + String newS1 = s1; + int curLen = newS1.length(); + + int runFor = poss - curLen; + if(curLen < finalLen){ + + + for(int i = 0; i < runFor; i++){ + newS1 = "0" + newS1; + } + + } + + System.out.println(newS1); + possibilities.add(newS1); + String s2 = s1; + q.add(s1 + "0"); + q.add(s2 + "1"); } - // First assign "0" at ith position - // and try for all other permutations - // for remaining positions - arr = arr + "0"; - generateAllBinaryStrings(n, arr, i + 1); - - // And then assign "1" at ith position - // and try for all other permutations - // for remaining positions - arr = arr + "1"; - generateAllBinaryStrings(n, arr, i + 1); - - return null; } - public ArrayList binaryCombiniations(int numEmpty) { - - ArrayList possibilities = new ArrayList<>(); - String arr = ""; - if (generateAllBinaryStrings(numEmpty, arr, 0) != null) { - possibilities.add(arr); - } - return null; - } @Override public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { // This function should first check if there are three open spaces, if so, continue, else figure out @@ -63,6 +68,13 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem BinaryBoard origBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); BinaryCell binaryCell = (BinaryCell) puzzleElement; + ArrayList result = new ArrayList(); + generateAllBinaryStrings(10,4,result); + + for(String s : result){ + System.out.println(s); + } + return "Grouping of Three Ones or Zeros not found TEST"; } From ac95969eac247bb05a83078f26ad64257956c671 Mon Sep 17 00:00:00 2001 From: summerhenson Date: Fri, 21 Jun 2024 15:08:32 -0400 Subject: [PATCH 146/258] Make a rule name more accurate --- .../puzzles/starbattle/rules/SurroundStarDirectRuleTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/puzzles/starbattle/rules/SurroundStarDirectRuleTest.java b/src/test/java/puzzles/starbattle/rules/SurroundStarDirectRuleTest.java index f6894d6de..db55d0f65 100644 --- a/src/test/java/puzzles/starbattle/rules/SurroundStarDirectRuleTest.java +++ b/src/test/java/puzzles/starbattle/rules/SurroundStarDirectRuleTest.java @@ -150,7 +150,7 @@ public void SurroundStarDirectRule_CornerStar() throws InvalidFileFormatExceptio } @Test - public void SurroundStarDirectRule_FalseContradiction() + public void SurroundStarDirectRule_FalseSurroundStar() throws InvalidFileFormatException { TestUtilities.importTestBoard("puzzles/starbattle/rules/SurroundStarDirectRule/CornerStar", starbattle); TreeNode rootNode = starbattle.getTree().getRootNode(); From c3265d3e0c49c9bc0577919cbc8d9d431479bbc2 Mon Sep 17 00:00:00 2001 From: ContemporaryNietzsche Date: Fri, 21 Jun 2024 15:20:33 -0400 Subject: [PATCH 147/258] fixed some variables (extra 0 bug found) and commented/explained some code --- .../rules/EliminateTheImpossibleDirectRule.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java index 2898ed084..0b215d547 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java @@ -25,10 +25,15 @@ public EliminateTheImpossibleDirectRule() { } // Function to generate all binary strings - void generateAllBinaryStrings(double x, int poss, ArrayList possibilities) + void generateAllBinaryStrings(double countTo, int spots, ArrayList possibilities) + // This function generates all the possible combinations of 0s and 1s for a certain size, it does this + // by basically just counting from 0 to the number - 1, so if you want all the possible combinations for 3 + // spots, you can just count in binary from 0 to 7 (taking 3 spots, so from 000 to 111). To be practical, + // the function does not return an array with all the possibilities as an array, but populates the + // arraylist you pass in (possibilities) { - int count = (int)x; - int finalLen = poss; + int count = (int)countTo; + int finalLen = spots; Queue q = new LinkedList(); q.add("1"); @@ -39,7 +44,7 @@ void generateAllBinaryStrings(double x, int poss, ArrayList possibilitie String newS1 = s1; int curLen = newS1.length(); - int runFor = poss - curLen; + int runFor = spots - curLen; if(curLen < finalLen){ @@ -69,7 +74,7 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem BinaryCell binaryCell = (BinaryCell) puzzleElement; ArrayList result = new ArrayList(); - generateAllBinaryStrings(10,4,result); + generateAllBinaryStrings(16,4,result); for(String s : result){ System.out.println(s); From 7049e9f76c1e6f16cf716128415b2ab62859c089 Mon Sep 17 00:00:00 2001 From: ContemporaryNietzsche Date: Sat, 22 Jun 2024 03:46:21 -0400 Subject: [PATCH 148/258] finished the generate possibilites function for ETP --- .../EliminateTheImpossibleDirectRule.java | 52 ++++++++++++++----- 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java index 0b215d547..75bd4633d 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java @@ -25,42 +25,62 @@ public EliminateTheImpossibleDirectRule() { } // Function to generate all binary strings - void generateAllBinaryStrings(double countTo, int spots, ArrayList possibilities) + void generatePossibilitites(int spots, ArrayList possibilities, int zeroCount, int oneCount) // This function generates all the possible combinations of 0s and 1s for a certain size, it does this // by basically just counting from 0 to the number - 1, so if you want all the possible combinations for 3 // spots, you can just count in binary from 0 to 7 (taking 3 spots, so from 000 to 111). To be practical, // the function does not return an array with all the possibilities as an array, but populates the // arraylist you pass in (possibilities) { - int count = (int)countTo; + if(zeroCount + oneCount != spots){ + System.out.println("INVALID INPUT"); + return; + } + + if(zeroCount == spots){ + String zero = ""; + for(int i = 0; i < spots; i++){ + zero = zero + "0"; + } + possibilities.add(zero); + + } + int count = (int)Math.pow(2,spots) -1; int finalLen = spots; - Queue q = new LinkedList(); q.add("1"); + while (count-- > 0) { String s1 = q.peek(); q.remove(); - + String newS1 = s1; int curLen = newS1.length(); - int runFor = spots - curLen; if(curLen < finalLen){ - - for(int i = 0; i < runFor; i++){ newS1 = "0" + newS1; } - } - - System.out.println(newS1); - possibilities.add(newS1); + int curZeros = 0; + int curOnes = 0; + + for(int i = 0; i < spots; i++){ + if(newS1.charAt(i) == '0'){ + curZeros++; + } + if(newS1.charAt(i) == '1'){ + curOnes++; + } + } + + if(zeroCount == curZeros && oneCount == curOnes){ + possibilities.add(newS1); + } String s2 = s1; q.add(s1 + "0"); q.add(s2 + "1"); - } - + } } @Override @@ -74,8 +94,12 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem BinaryCell binaryCell = (BinaryCell) puzzleElement; ArrayList result = new ArrayList(); - generateAllBinaryStrings(16,4,result); + int zerosLeft = 3; + int onesLeft = 1; + generatePossibilitites(4, result, zerosLeft, onesLeft); + + System.out.println("printing result"); for(String s : result){ System.out.println(s); } From a884291a08b4aa9dd92a605cc85a58421f7fd561 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Sun, 23 Jun 2024 13:16:16 -0400 Subject: [PATCH 149/258] Modified "Create Puzzle" to become puzzle editor, when clicked opens a blank puzzle with no elements, removed tool bar until puzzle is clicked --- .../edu/rpi/legup/app/GameBoardFacade.java | 67 ++++++++++--------- .../EliminateTheImpossibleDirectRule.java | 22 ++++-- .../binary/rules/binary_reference_sheet.txt | 1 + .../edu/rpi/legup/puzzle/lightup/LightUp.java | 2 +- .../edu/rpi/legup/ui/CreatePuzzleDialog.java | 3 + src/main/java/edu/rpi/legup/ui/HomePanel.java | 67 +++++++++++++------ .../edu/rpi/legup/ui/PuzzleEditorDialog.java | 20 ++++++ .../edu/rpi/legup/ui/PuzzleEditorPanel.java | 35 +++++----- .../elementsview/ElementFrame.java | 4 +- 9 files changed, 146 insertions(+), 75 deletions(-) create mode 100644 src/main/java/edu/rpi/legup/ui/PuzzleEditorDialog.java diff --git a/src/main/java/edu/rpi/legup/app/GameBoardFacade.java b/src/main/java/edu/rpi/legup/app/GameBoardFacade.java index c928c1209..fbd11fd86 100644 --- a/src/main/java/edu/rpi/legup/app/GameBoardFacade.java +++ b/src/main/java/edu/rpi/legup/app/GameBoardFacade.java @@ -175,44 +175,47 @@ public boolean validateTextInput(String game, String[] statements) throws Runtim * @param columns the number of columns on the board */ public void loadPuzzle(String game, int rows, int columns) throws RuntimeException { - String qualifiedClassName = config.getPuzzleClassForName(game); - LOGGER.debug("Loading " + qualifiedClassName); + if (!game.equals("")) { + String qualifiedClassName = config.getPuzzleClassForName(game); + LOGGER.debug("Loading " + qualifiedClassName); - try { - Class c = Class.forName(qualifiedClassName); - Constructor cons = c.getConstructor(); - Puzzle puzzle = (Puzzle) cons.newInstance(); + try { + Class c = Class.forName(qualifiedClassName); + Constructor cons = c.getConstructor(); + Puzzle puzzle = (Puzzle) cons.newInstance(); - PuzzleImporter importer = puzzle.getImporter(); - if (importer == null) { - LOGGER.error("Puzzle importer is null"); - throw new RuntimeException("Puzzle importer null"); - } + PuzzleImporter importer = puzzle.getImporter(); + if (importer == null) { + LOGGER.error("Puzzle importer is null"); + throw new RuntimeException("Puzzle importer null"); + } - // Theoretically, this exception should never be thrown, since LEGUP should not be - // allowing the user to give row/column input for a puzzle that doesn't support it - if (!importer.acceptsRowsAndColumnsInput()) { - throw new IllegalArgumentException( - puzzle.getName() + " does not accept rows and columns input"); - } + // Theoretically, this exception should never be thrown, since LEGUP should not be + // allowing the user to give row/column input for a puzzle that doesn't support it + if (!importer.acceptsRowsAndColumnsInput()) { + throw new IllegalArgumentException( + puzzle.getName() + " does not accept rows and columns input"); + } - setWindowTitle(puzzle.getName(), "New " + puzzle.getName() + " Puzzle"); - importer.initializePuzzle(rows, columns); + setWindowTitle(puzzle.getName(), "New " + puzzle.getName() + " Puzzle"); + importer.initializePuzzle(rows, columns); - puzzle.initializeView(); - // - // puzzle.getBoardView().onTreeElementChanged(puzzle.getTree().getRootNode()); - setPuzzleEditor(puzzle); - } catch (IllegalArgumentException exception) { - throw new IllegalArgumentException(exception.getMessage()); - } catch (ClassNotFoundException - | NoSuchMethodException - | InvocationTargetException - | IllegalAccessException - | InstantiationException e) { - LOGGER.error(e); - throw new RuntimeException("Puzzle creation error"); + puzzle.initializeView(); + // + // puzzle.getBoardView().onTreeElementChanged(puzzle.getTree().getRootNode()); + setPuzzleEditor(puzzle); + } catch (IllegalArgumentException exception) { + throw new IllegalArgumentException(exception.getMessage()); + } catch (ClassNotFoundException + | NoSuchMethodException + | InvocationTargetException + | IllegalAccessException + | InstantiationException e) { + LOGGER.error(e); + throw new RuntimeException("Puzzle creation error"); + } } + } public void loadPuzzle(String game, String[] statements) { diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java index f705b7716..458d6e39e 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java @@ -16,7 +16,7 @@ public class EliminateTheImpossibleDirectRule extends DirectRule { public EliminateTheImpossibleDirectRule() { super( - "BINA-BASC-0003", + "BINA-BASC-0004", "Eliminate The Impossible", "If three adjacent empty cells are open, prevents a trio of numbers to exist", "edu/rpi/legup/images/binary/rules/OneTileGapDirectRule.png"); @@ -25,6 +25,7 @@ public EliminateTheImpossibleDirectRule() { // Function to generate all binary strings static String generateAllBinaryStrings(int n, String arr, int i) { + System.out.println(i); if (i == n) { return arr; @@ -42,23 +43,34 @@ static String generateAllBinaryStrings(int n, String arr, int i) arr = arr + "1"; generateAllBinaryStrings(n, arr, i + 1); + return null; } public ArrayList binaryCombiniations(int numEmpty) { - + System.out.println("FUNCTION"); ArrayList possibilities = new ArrayList<>(); String arr = ""; - if (generateAllBinaryStrings(numEmpty, arr, 0) != null) { - possibilities.add(arr); + + generateAllBinaryStrings(numEmpty, arr, 0); +// +// if (generateAllBinaryStrings(numEmpty, arr, 0) != null) { +// //System.out.println("T)"); +// possibilities.add(arr); +// } + + for (int i = 0; i < possibilities.size(); i++) { + System.out.println(possibilities.get(i)); } return null; } + @Override public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { BinaryBoard origBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); BinaryCell binaryCell = (BinaryCell) puzzleElement; - + System.out.println("HI"); + binaryCombiniations(4); return "Grouping of Three Ones or Zeros not found"; } diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/binary_reference_sheet.txt b/src/main/java/edu/rpi/legup/puzzle/binary/rules/binary_reference_sheet.txt index c8cb0d1b9..74358a767 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/binary_reference_sheet.txt +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/binary_reference_sheet.txt @@ -1,6 +1,7 @@ BINA-BASC-0001 : SurroundPairDirectRule BINA-BASC-0002 : OneTileGapDirectRule BINA-BASC-0003 : CompleteRowColumnDirectRule +BINA-BASC-0004 : EliminateTheImpossibleDirectRule BINA-CONT-0001 : ThreeAdjacentContradictionRule BINA-CONT-0002 : UnbalancedRowOrColumnContradictionRule diff --git a/src/main/java/edu/rpi/legup/puzzle/lightup/LightUp.java b/src/main/java/edu/rpi/legup/puzzle/lightup/LightUp.java index ab95c4658..a73806cd7 100644 --- a/src/main/java/edu/rpi/legup/puzzle/lightup/LightUp.java +++ b/src/main/java/edu/rpi/legup/puzzle/lightup/LightUp.java @@ -47,7 +47,7 @@ public Board generatePuzzle(int difficulty) { * @return true if the given dimensions are valid for Light Up, false otherwise */ public boolean isValidDimensions(int rows, int columns) { - return rows > 0 && columns > 0; + return rows >= 0 && columns >= 0; } /** diff --git a/src/main/java/edu/rpi/legup/ui/CreatePuzzleDialog.java b/src/main/java/edu/rpi/legup/ui/CreatePuzzleDialog.java index 70fbea033..636d5b36f 100644 --- a/src/main/java/edu/rpi/legup/ui/CreatePuzzleDialog.java +++ b/src/main/java/edu/rpi/legup/ui/CreatePuzzleDialog.java @@ -61,6 +61,9 @@ public void actionPerformed(ActionEvent ae) { Config.convertDisplayNameToClassName( (String) gameBox.getSelectedItem()); + if (game.equals("OpeningPuzzleEditor")) { + + } // Check if all 3 TextFields are filled if (game.equals("ShortTruthTable") && textArea.getText().isEmpty()) { System.out.println("Unfilled fields"); diff --git a/src/main/java/edu/rpi/legup/ui/HomePanel.java b/src/main/java/edu/rpi/legup/ui/HomePanel.java index 2e63b91e3..dd0061feb 100644 --- a/src/main/java/edu/rpi/legup/ui/HomePanel.java +++ b/src/main/java/edu/rpi/legup/ui/HomePanel.java @@ -136,8 +136,25 @@ private void initButtons() { this.buttons[0].setVerticalTextPosition(AbstractButton.BOTTOM); this.buttons[0].addActionListener(CursorController.createListener(this, openProofListener)); +// this.buttons[1] = +// new JButton("Create Puzzle") { +// { +// setSize(buttonSize, buttonSize); +// setMaximumSize(getSize()); +// } +// }; +// URL button1IconLocation = +// ClassLoader.getSystemClassLoader() +// .getResource("edu/rpi/legup/images/Legup/homepanel/new_puzzle_file.png"); +// ImageIcon button1Icon = new ImageIcon(button1IconLocation); +// this.buttons[1].setFocusPainted(false); +// this.buttons[1].setIcon(resizeButtonIcon(button1Icon, this.buttonSize, this.buttonSize)); +// this.buttons[1].setHorizontalTextPosition(AbstractButton.CENTER); +// this.buttons[1].setVerticalTextPosition(AbstractButton.BOTTOM); +// this.buttons[1].addActionListener(l -> this.openNewPuzzleDialog()); + this.buttons[1] = - new JButton("Create Puzzle") { + new JButton("Puzzle Editor") { { setSize(buttonSize, buttonSize); setMaximumSize(getSize()); @@ -151,7 +168,8 @@ private void initButtons() { this.buttons[1].setIcon(resizeButtonIcon(button1Icon, this.buttonSize, this.buttonSize)); this.buttons[1].setHorizontalTextPosition(AbstractButton.CENTER); this.buttons[1].setVerticalTextPosition(AbstractButton.BOTTOM); - this.buttons[1].addActionListener(l -> this.openNewPuzzleDialog()); + this.buttons[1].addActionListener(l -> this.openPuzzleEditorDialog()); + //this.buttons[1].addActionListener(l -> this.openNewPuzzleDialog()); this.buttons[2] = new JButton("Edit Existing Puzzle") { @@ -534,6 +552,10 @@ private void openNewPuzzleDialog() { cpd.setVisible(true); } + private void openPuzzleEditorDialog() { + PuzzleEditorDialog ped = new PuzzleEditorDialog(this); + } + private void checkProofAll() { /* * Select dir to grade; recursively grade sub-dirs using traverseDir() @@ -631,27 +653,34 @@ private void traverseDir(File folder, BufferedWriter writer, String path) throws public void openEditorWithNewPuzzle(String game, int rows, int columns) throws IllegalArgumentException { - // Validate the dimensions - GameBoardFacade facade = GameBoardFacade.getInstance(); - boolean isValidDimensions = facade.validateDimensions(game, rows, columns); - if (!isValidDimensions) { - JOptionPane.showMessageDialog( - null, - "The dimensions you entered are invalid. Please double check \n" - + "the number of rows and columns and try again.", - "ERROR: Invalid Dimensions", - JOptionPane.ERROR_MESSAGE); - throw new IllegalArgumentException("ERROR: Invalid dimensions given"); + if (game.equals("")) { + this.legupUI.displayPanel(2); + this.legupUI.getPuzzleEditor().loadPuzzleFromHome(game, rows, columns); } + else { + // Validate the dimensions + GameBoardFacade facade = GameBoardFacade.getInstance(); + boolean isValidDimensions = facade.validateDimensions(game, rows, columns); + if (!isValidDimensions) { + JOptionPane.showMessageDialog( + null, + "The dimensions you entered are invalid. Please double check \n" + + "the number of rows and columns and try again.", + "ERROR: Invalid Dimensions", + JOptionPane.ERROR_MESSAGE); + throw new IllegalArgumentException("ERROR: Invalid dimensions given"); + } - if (this.legupUI == null) { - System.err.println("Error: legupUI is null in HomePanel"); - return; + if (this.legupUI == null) { + System.err.println("Error: legupUI is null in HomePanel"); + return; + } + + // Set game type on the puzzle editor + this.legupUI.displayPanel(2); + this.legupUI.getPuzzleEditor().loadPuzzleFromHome(game, rows, columns); } - // Set game type on the puzzle editor - this.legupUI.displayPanel(2); - this.legupUI.getPuzzleEditor().loadPuzzleFromHome(game, rows, columns); } /** diff --git a/src/main/java/edu/rpi/legup/ui/PuzzleEditorDialog.java b/src/main/java/edu/rpi/legup/ui/PuzzleEditorDialog.java new file mode 100644 index 000000000..46c811732 --- /dev/null +++ b/src/main/java/edu/rpi/legup/ui/PuzzleEditorDialog.java @@ -0,0 +1,20 @@ +package edu.rpi.legup.ui; + +import javax.swing.*; + +public class PuzzleEditorDialog { + + public PuzzleEditorDialog(HomePanel homePanel) { + String game = ""; + int r = 0; + int c = 0; + + try { + homePanel.openEditorWithNewPuzzle(game, r, c); + } catch (IllegalArgumentException e) { + System.out.println("Failed to open editor with new puzzle"); + e.printStackTrace(System.out); + } + } + +} diff --git a/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java b/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java index cfee707f2..4d40536ad 100644 --- a/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java +++ b/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java @@ -248,10 +248,10 @@ public void exitEditor() { @Override public void makeVisible() { this.removeAll(); - setupToolBar(); setupContent(); setMenuBar(); + toolBar.setVisible(false); } private void setupToolBar() { @@ -292,24 +292,26 @@ private void setupToolBar() { this.TOOLBAR_ICON_SCALE, Image.SCALE_SMOOTH)); - JButton saveandsolve = new JButton("Save And Solve", SaveSolveImageIcon); + JButton saveandsolve = new JButton("Save & Solve", SaveSolveImageIcon); saveandsolve.setFocusPainted(false); saveandsolve.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - String filename = savePuzzle(); - File puzzlename = new File(filename); - System.out.println(filename); - - GameBoardFacade.getInstance().getLegupUI().displayPanel(1); - GameBoardFacade.getInstance() - .getLegupUI() - .getProofEditor() - .loadPuzzle(filename, new File(filename)); - String puzzleName = - GameBoardFacade.getInstance().getPuzzleModule().getName(); - frame.setTitle(puzzleName + " - " + puzzlename.getName()); + if (GameBoardFacade.getInstance().getPuzzleModule() != null) { + String filename = savePuzzle(); + File puzzlename = new File(filename); + System.out.println(filename); + + GameBoardFacade.getInstance().getLegupUI().displayPanel(1); + GameBoardFacade.getInstance() + .getLegupUI() + .getProofEditor() + .loadPuzzle(filename, new File(filename)); + String puzzleName = + GameBoardFacade.getInstance().getPuzzleModule().getName(); + frame.setTitle(puzzleName + " - " + puzzlename.getName()); + } } }); getToolBarButtons()[1] = saveandsolve; @@ -321,6 +323,8 @@ public void actionPerformed(ActionEvent e) { this.add(toolBar, BorderLayout.NORTH); } + public JToolBar getToolBar () { return toolBar; } + public void loadPuzzleFromHome(String game, int rows, int columns) throws IllegalArgumentException { GameBoardFacade facade = GameBoardFacade.getInstance(); @@ -476,8 +480,7 @@ public void setPuzzleView(Puzzle puzzle) { elementFrame.setElements(puzzle); } - //toolBarButtons[ToolbarName.CHECK.ordinal()].setEnabled(true); - // toolBarButtons[ToolbarName.SAVE.ordinal()].setEnabled(true); + toolBar.setVisible(true); } /** Saves a puzzle */ diff --git a/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/ElementFrame.java b/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/ElementFrame.java index 35ab65ff4..97c76919e 100644 --- a/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/ElementFrame.java +++ b/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/ElementFrame.java @@ -61,8 +61,8 @@ public ButtonGroup getButtonGroup() { // } public void setElements(Puzzle puzzle) { - if (placeableElementPanel.setElements(puzzle.getPlaceableElements()) == 0) { - + if (puzzle != null) { + placeableElementPanel.setElements(puzzle.getPlaceableElements()); } } From 3dcc3d582f1fd496d5ce5648161877825e9d96f5 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Sun, 23 Jun 2024 15:54:48 -0400 Subject: [PATCH 150/258] Added create and open toolbar buttons when first opening puzzle editor --- .../edu/rpi/legup/ui/PuzzleEditorPanel.java | 109 ++++++++++++++---- 1 file changed, 84 insertions(+), 25 deletions(-) diff --git a/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java b/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java index 4d40536ad..723085658 100644 --- a/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java +++ b/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java @@ -35,12 +35,14 @@ public class PuzzleEditorPanel extends LegupPanel implements IHistoryListener { private JMenu[] menus; private JMenuItem helpLegup, aboutLegup; private JMenuBar menuBar; - private JToolBar toolBar; + private JToolBar toolBar1; + private JToolBar toolBar2; private JFileChooser folderBrowser; private JFrame frame; private JButton[] buttons; JSplitPane splitPanel; - private JButton[] toolBarButtons; + private JButton[] toolBar1Buttons; + private JButton[] toolBar2Buttons; private JPanel elementPanel; private DynamicView dynamicBoardView; private BoardView boardView; @@ -52,7 +54,6 @@ public class PuzzleEditorPanel extends LegupPanel implements IHistoryListener { private JPanel treePanel; private LegupUI legupUI; private EditorElementController editorElementController; - static final int[] TOOLBAR_SEPARATOR_BEFORE = {2, 4, 8}; public PuzzleEditorPanel(FileDialog fileDialog, JFrame frame, LegupUI legupUI) { this.fileDialog = fileDialog; @@ -248,14 +249,67 @@ public void exitEditor() { @Override public void makeVisible() { this.removeAll(); - setupToolBar(); + setupToolBar1(); setupContent(); setMenuBar(); - toolBar.setVisible(false); } + private void setupToolBar1() { + setToolBar1Buttons(new JButton[2]); - private void setupToolBar() { - setToolBarButtons(new JButton[2]); + URL open_url = + ClassLoader.getSystemClassLoader() + .getResource("edu/rpi/legup/images/Legup/Open.png"); + ImageIcon OpenImageIcon = new ImageIcon(open_url); + Image OpenImage = OpenImageIcon.getImage(); + OpenImageIcon = + new ImageIcon( + OpenImage.getScaledInstance( + this.TOOLBAR_ICON_SCALE, + this.TOOLBAR_ICON_SCALE, + Image.SCALE_SMOOTH)); + + JButton open = new JButton("Open", OpenImageIcon); + open.setFocusPainted(false); + open.addActionListener((ActionEvent) -> loadPuzzle()); + + getToolBar1Buttons()[0] = open; + + toolBar1 = new JToolBar(); + toolBar1.setFloatable(false); + toolBar1.setRollover(true); + toolBar1.add(getToolBar1Buttons()[0]); + + URL create_url = + ClassLoader.getSystemClassLoader() + .getResource("edu/rpi/legup/images/Legup/Open Puzzle.png"); + ImageIcon CreateImageIcon = new ImageIcon(create_url); + Image CreateImage = CreateImageIcon.getImage(); + CreateImageIcon = + new ImageIcon( + CreateImage.getScaledInstance( + this.TOOLBAR_ICON_SCALE, + this.TOOLBAR_ICON_SCALE, + Image.SCALE_SMOOTH)); + + JButton create = new JButton("Create", CreateImageIcon); + create.setFocusPainted(false); + create.addActionListener((ActionEvent) -> { + HomePanel hp = new HomePanel(this.fileDialog, this.frame, this.legupUI); + CreatePuzzleDialog cpd = new CreatePuzzleDialog(this.frame, hp); + cpd.setLocationRelativeTo(null); + cpd.setVisible(true); + }); + getToolBar1Buttons()[1] = create; + + toolBar1.setFloatable(false); + toolBar1.setRollover(true); + toolBar1.add(getToolBar1Buttons()[1]); + + this.add(toolBar1, BorderLayout.NORTH); + } + + private void setupToolBar2() { + setToolBar2Buttons(new JButton[2]); URL save_as = ClassLoader.getSystemClassLoader() @@ -273,12 +327,12 @@ private void setupToolBar() { saveas.setFocusPainted(false); saveas.addActionListener((ActionEvent) -> savePuzzle()); - getToolBarButtons()[0] = saveas; + getToolBar2Buttons()[0] = saveas; - toolBar = new JToolBar(); - toolBar.setFloatable(false); - toolBar.setRollover(true); - toolBar.add(getToolBarButtons()[0]); + toolBar2 = new JToolBar(); + toolBar2.setFloatable(false); + toolBar2.setRollover(true); + toolBar2.add(getToolBar2Buttons()[0]); URL save_and_solve = ClassLoader.getSystemClassLoader() @@ -314,17 +368,15 @@ public void actionPerformed(ActionEvent e) { } } }); - getToolBarButtons()[1] = saveandsolve; + getToolBar2Buttons()[1] = saveandsolve; - toolBar.setFloatable(false); - toolBar.setRollover(true); - toolBar.add(getToolBarButtons()[1]); + toolBar2.setFloatable(false); + toolBar2.setRollover(true); + toolBar2.add(getToolBar2Buttons()[1]); - this.add(toolBar, BorderLayout.NORTH); + this.add(toolBar2, BorderLayout.NORTH); } - public JToolBar getToolBar () { return toolBar; } - public void loadPuzzleFromHome(String game, int rows, int columns) throws IllegalArgumentException { GameBoardFacade facade = GameBoardFacade.getInstance(); @@ -447,13 +499,20 @@ public void onClearHistory() { public BoardView getBoardView() { return boardView; } + public JButton[] getToolBar1Buttons() { + return toolBar1Buttons; + } - public JButton[] getToolBarButtons() { - return toolBarButtons; + public void setToolBar1Buttons(JButton[] toolBar1Buttons) { + this.toolBar1Buttons = toolBar1Buttons; } - public void setToolBarButtons(JButton[] toolBarButtons) { - this.toolBarButtons = toolBarButtons; + public JButton[] getToolBar2Buttons() { + return toolBar2Buttons; + } + + public void setToolBar2Buttons(JButton[] toolBar2Buttons) { + this.toolBar2Buttons = toolBar2Buttons; } private void repaintAll() { @@ -479,8 +538,8 @@ public void setPuzzleView(Puzzle puzzle) { if (this.elementFrame != null) { elementFrame.setElements(puzzle); } - - toolBar.setVisible(true); + toolBar1.setVisible(false); + setupToolBar2(); } /** Saves a puzzle */ From de2b08a713df18f01012694d2ecb65c1b62cd71d Mon Sep 17 00:00:00 2001 From: summerhenson Date: Tue, 25 Jun 2024 14:12:26 -0400 Subject: [PATCH 151/258] Added Too Few Stars contradiction rule test --- .../TooFewStarsContradictionRuleTest.java | 18 +++++++++ .../NotEnoughSpace | 40 +++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/NotEnoughSpace diff --git a/src/test/java/puzzles/starbattle/rules/TooFewStarsContradictionRuleTest.java b/src/test/java/puzzles/starbattle/rules/TooFewStarsContradictionRuleTest.java index 2e9f3ddef..8a5fcfb88 100644 --- a/src/test/java/puzzles/starbattle/rules/TooFewStarsContradictionRuleTest.java +++ b/src/test/java/puzzles/starbattle/rules/TooFewStarsContradictionRuleTest.java @@ -136,4 +136,22 @@ public void TooFewStarsContradictionRule_FalseContradiction() } } + @Test + public void TooFewStarsContradictionRule_NotEnoughSpace() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/TooFewStarsContradictionRule/NotEnoughSpace", starBattle); + TreeNode rootNode = starBattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + + Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); + for (int i = 0; i < board.getHeight(); ++i) { + for (int j = 0; j < board.getWidth(); ++j) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + } + } + } diff --git a/src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/NotEnoughSpace b/src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/NotEnoughSpace new file mode 100644 index 000000000..9280cefdd --- /dev/null +++ b/src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/NotEnoughSpace @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From d30206de313d7a76d336553e4a91801f7be1d81a Mon Sep 17 00:00:00 2001 From: offline171 <146153141+offline171@users.noreply.github.com> Date: Tue, 25 Jun 2024 14:17:08 -0400 Subject: [PATCH 152/258] new 2 star puzzle Started making 2 star puzzle --- .../10x10 Star Battle 2star Normal1.xml | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 puzzles files/starbattle/10x10 Star Battle 2 star Normal/10x10 Star Battle 2star Normal1.xml diff --git a/puzzles files/starbattle/10x10 Star Battle 2 star Normal/10x10 Star Battle 2star Normal1.xml b/puzzles files/starbattle/10x10 Star Battle 2 star Normal/10x10 Star Battle 2star Normal1.xml new file mode 100644 index 000000000..339c7d9c1 --- /dev/null +++ b/puzzles files/starbattle/10x10 Star Battle 2 star Normal/10x10 Star Battle 2star Normal1.xml @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 6e5dc787f59688afa11d77825234c6b071cb4914 Mon Sep 17 00:00:00 2001 From: ContemporaryNietzsche Date: Tue, 25 Jun 2024 14:58:36 -0400 Subject: [PATCH 153/258] added functions to eliminate the impossible (still wip) --- .settings/org.eclipse.buildship.core.prefs | 13 +++ .../rpi/legup/puzzle/binary/BinaryBoard.java | 24 ++++- .../EliminateTheImpossibleDirectRule.java | 87 ++++++++++++++----- 3 files changed, 98 insertions(+), 26 deletions(-) create mode 100644 .settings/org.eclipse.buildship.core.prefs diff --git a/.settings/org.eclipse.buildship.core.prefs b/.settings/org.eclipse.buildship.core.prefs new file mode 100644 index 000000000..ea640e792 --- /dev/null +++ b/.settings/org.eclipse.buildship.core.prefs @@ -0,0 +1,13 @@ +arguments=--init-script /home/gamma/.cache/jdtls/config/org.eclipse.osgi/55/0/.cp/gradle/init/init.gradle +auto.sync=false +build.scans.enabled=false +connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER) +connection.project.dir= +eclipse.preferences.version=1 +gradle.user.home= +java.home=/usr/lib/jvm/java-21-openjdk-amd64 +jvm.arguments= +offline.mode=false +override.workspace.settings=true +show.console.view=true +show.executions.view=true diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java index 6bc2b98f1..543736f42 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java @@ -41,15 +41,16 @@ public Set getRowCells(int rowNum) { return row; } - public ArrayList getRowTypes(int rowNum) { - ArrayList row = new ArrayList(); + public ArrayList listRowCells(int rowNum) { + ArrayList row = new ArrayList<>(); for (int i = 0; i < size; i++) { BinaryCell cell = getCell(i, rowNum); - row.add(cell.getType()); + row.add(cell); } return row; } + public ArrayList getColTypes(int colNum) { ArrayList col = new ArrayList(); for (int i = 0; i < size; i++) { @@ -59,6 +60,15 @@ public ArrayList getColTypes(int colNum) { return col; } + public ArrayList getRowTypes(int rowNum) { + ArrayList row = new ArrayList(); + for (int i = 0; i < size; i++) { + BinaryCell cell = getCell(i, rowNum); + row.add(cell.getType()); + } + return row; + } + public Set getColCells(int colNum) { Set col = new HashSet<>(); for (int i = 0; i < size; i++) { @@ -67,6 +77,14 @@ public Set getColCells(int colNum) { return col; } + public ArrayList listColCells(int colNum) { + ArrayList col = new ArrayList<>(); + for (int i = 0; i < size; i++) { + col.add(getCell(colNum, i)); + } + return col; + } + @Override public BinaryBoard copy() { System.out.println("BinaryBoard copy()"); diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java index 75bd4633d..f938e3119 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java @@ -7,10 +7,12 @@ import edu.rpi.legup.model.tree.TreeTransition; import edu.rpi.legup.puzzle.binary.BinaryBoard; import edu.rpi.legup.puzzle.binary.BinaryCell; +import edu.rpi.legup.puzzle.binary.BinaryType; import java.util.LinkedList; import java.util.Queue; import java.lang.Math.*; +import java.lang.reflect.Array; import java.util.ArrayList; public class EliminateTheImpossibleDirectRule extends DirectRule { @@ -26,26 +28,30 @@ public EliminateTheImpossibleDirectRule() { // Function to generate all binary strings void generatePossibilitites(int spots, ArrayList possibilities, int zeroCount, int oneCount) - // This function generates all the possible combinations of 0s and 1s for a certain size, it does this - // by basically just counting from 0 to the number - 1, so if you want all the possible combinations for 3 - // spots, you can just count in binary from 0 to 7 (taking 3 spots, so from 000 to 111). To be practical, - // the function does not return an array with all the possibilities as an array, but populates the + // This function generates all the possible combinations of 0s and 1s for a + // certain size, it does this + // by basically just counting from 0 to the number - 1, so if you want all the + // possible combinations for 3 + // spots, you can just count in binary from 0 to 7 (taking 3 spots, so from 000 + // to 111). To be practical, + // the function does not return an array with all the possibilities as an array, + // but populates the // arraylist you pass in (possibilities) { - if(zeroCount + oneCount != spots){ + if (zeroCount + oneCount != spots) { System.out.println("INVALID INPUT"); return; } - if(zeroCount == spots){ + if (zeroCount == spots) { String zero = ""; - for(int i = 0; i < spots; i++){ + for (int i = 0; i < spots; i++) { zero = zero + "0"; } possibilities.add(zero); } - int count = (int)Math.pow(2,spots) -1; + int count = (int) Math.pow(2, spots) - 1; int finalLen = spots; Queue q = new LinkedList(); q.add("1"); @@ -57,54 +63,89 @@ void generatePossibilitites(int spots, ArrayList possibilities, int zero String newS1 = s1; int curLen = newS1.length(); int runFor = spots - curLen; - if(curLen < finalLen){ - for(int i = 0; i < runFor; i++){ + if (curLen < finalLen) { + for (int i = 0; i < runFor; i++) { newS1 = "0" + newS1; } } int curZeros = 0; int curOnes = 0; - for(int i = 0; i < spots; i++){ - if(newS1.charAt(i) == '0'){ + for (int i = 0; i < spots; i++) { + if (newS1.charAt(i) == '0') { curZeros++; } - if(newS1.charAt(i) == '1'){ + if (newS1.charAt(i) == '1') { curOnes++; } } - if(zeroCount == curZeros && oneCount == curOnes){ + if (zeroCount == curZeros && oneCount == curOnes) { possibilities.add(newS1); } String s2 = s1; q.add(s1 + "0"); q.add(s2 + "1"); - } + } } @Override public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - // This function should first check if there are three open spaces, if so, continue, else figure out - // how many spots are open, all the possible binary combinations that could be put there, and by - // analyzing the common factors, logically determine which number has a set spot, meaning that we know + // This function should first check if there are three open spaces, if so, + // continue, else figure out + // how many spots are open, all the possible binary combinations that could be + // put there, and by + // analyzing the common factors, logically determine which number has a set + // spot, meaning that we know // that a certain spot must be a zero or a one BinaryBoard origBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); BinaryCell binaryCell = (BinaryCell) puzzleElement; - ArrayList result = new ArrayList(); + ArrayList rowResult = new ArrayList(); int zerosLeft = 3; int onesLeft = 1; - generatePossibilitites(4, result, zerosLeft, onesLeft); - System.out.println("printing result"); - for(String s : result){ - System.out.println(s); + // To call generatePossibilitites(), you must call it and pass in the amount of + // spots left, + // an ArrayList that will be populated with the possible results (in String + // form), the amount of zeros left and ones left + generatePossibilitites(4, rowResult, zerosLeft, onesLeft); + + //Getting the row and col where the user clicked + ArrayList row = origBoard.listRowCells(binaryCell.getLocation().y); + + for(BinaryCell t : row){ + System.out.println(t.getType()); + // if(t.equals(BinaryType.UNKNOWN)); } + // ArrayList> rowCopies = new ArrayList<>(); + // for(int i = 0; i < rowResult.size(); i++){ + // rowCopies.add( new ArrayList(row) ); + // } + + // for(ArrayList curRow : rowCopies){ + // int idx = 0; + // for(int i = 0; i < curRow.size(); i++ ){ + // if(curRow.get(i).getType().equals(BinaryType.UNKNOWN)){ + // curRow.get(i).setType(); + // } + // + // } + // + // } + + + + // System.out.println("printing result"); + // for (String s : rowResult) { + // System.out.println(s); + // } + return "Grouping of Three Ones or Zeros not found TEST"; + } @Override From 9fbb412b51ab6363d183c3971c598fa1921373d1 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Fri, 28 Jun 2024 13:55:02 -0400 Subject: [PATCH 154/258] Modified EliminateTheImpossible so it produces the correct combination of binary possibilities for any input --- .../EliminateTheImpossibleDirectRule.java | 71 +++++++++++-------- 1 file changed, 40 insertions(+), 31 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java index c9a962973..f03e1ad6d 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java @@ -102,42 +102,51 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem BinaryBoard origBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); BinaryCell binaryCell = (BinaryCell) puzzleElement; - ArrayList rowResult = new ArrayList(); + //Getting the row where the user clicked + ArrayList row = origBoard.listRowCells(binaryCell.getLocation().y); + int size = row.size(); + int rowNumZeros = 0; + int rowNumOnes = 0; + + for (BinaryCell item : row) { + if (item.getType() == BinaryType.ZERO) { + rowNumZeros++; + } else if (item.getType() == BinaryType.ONE) { + rowNumOnes++; + } + } - int zerosLeft = 3; - int onesLeft = 1; + ArrayList rowResult = new ArrayList(); // To call generatePossibilitites(), you must call it and pass in the amount of - // spots left, + // unknown spots left, // an ArrayList that will be populated with the possible results (in String // form), the amount of zeros left and ones left - generatePossibilitites(4, rowResult, zerosLeft, onesLeft); - - //Getting the row and col where the user clicked - ArrayList row = origBoard.listRowCells(binaryCell.getLocation().y); - - for(BinaryCell t : row){ - System.out.println(t.getType()); - // if(t.equals(BinaryType.UNKNOWN)); - } - - // ArrayList> rowCopies = new ArrayList<>(); - // for(int i = 0; i < rowResult.size(); i++){ - // rowCopies.add( new ArrayList(row) ); - // } - - // for(ArrayList curRow : rowCopies){ - // int idx = 0; - // for(int i = 0; i < curRow.size(); i++ ){ - // if(curRow.get(i).getType().equals(BinaryType.UNKNOWN)){ - // curRow.get(i).setType(); - // } - // - // } - // - // } - - + generatePossibilitites((size - rowNumZeros - rowNumOnes), rowResult, size / 2 - rowNumZeros, size / 2 - rowNumOnes); + + for (String s : rowResult) + System.out.println(s); + + ArrayList> rowCopies = new ArrayList<>(); + for(int i = 0; i < rowResult.size(); i++){ + rowCopies.add( new ArrayList(row) ); + } + System.out.println("Number of possible binary combinations: " + rowCopies.size()); + +// for(ArrayList curRow : rowCopies){ +// int idx = 0; +// for(int i = 0; i < curRow.size(); i++ ){ +// if(curRow.get(i).getType().equals(BinaryType.UNKNOWN)){ +// if (rowResult.get(i).equals("0")) +// curRow.get(i).setData(0); +// else if (rowResult.get(i).equals("1")) +// curRow.get(i).setData(1); +// idx++; +// } +// System.out.print(curRow.get(i)); +// } +// System.out.println(""); +// } // System.out.println("printing result"); // for (String s : rowResult) { From dbbaca6739d7cd9a625c6e801044795e81814bdb Mon Sep 17 00:00:00 2001 From: offline171 <146153141+offline171@users.noreply.github.com> Date: Fri, 28 Jun 2024 14:05:39 -0400 Subject: [PATCH 155/258] Update 10x10 Star Battle 2star Normal1.xml Completed 10x10 2 star puzzle --- .../10x10 Star Battle 2star Normal1.xml | 67 ++++++++++++++++++- 1 file changed, 64 insertions(+), 3 deletions(-) diff --git a/puzzles files/starbattle/10x10 Star Battle 2 star Normal/10x10 Star Battle 2star Normal1.xml b/puzzles files/starbattle/10x10 Star Battle 2 star Normal/10x10 Star Battle 2star Normal1.xml index 339c7d9c1..aac7dd8f9 100644 --- a/puzzles files/starbattle/10x10 Star Battle 2 star Normal/10x10 Star Battle 2star Normal1.xml +++ b/puzzles files/starbattle/10x10 Star Battle 2 star Normal/10x10 Star Battle 2star Normal1.xml @@ -7,6 +7,7 @@ + @@ -64,21 +65,81 @@ - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 24bd3841facbe4660ee37d3bb536522c30a7b7fd Mon Sep 17 00:00:00 2001 From: summerhenson Date: Fri, 28 Jun 2024 14:17:26 -0400 Subject: [PATCH 156/258] First test case boards for Columns w/in Regions direct rule --- .../ColumnsWithinRegionsDirectRuleTest.java | 32 +++++++++++++++ .../OneColumnOneSquare | 29 ++++++++++++++ .../OnePartialColumnOneSquare | 29 ++++++++++++++ .../OnePartialColumnTwoSquares | 29 ++++++++++++++ .../ColumnsWithinRegionsDirectRule/TwoColumns | 40 +++++++++++++++++++ 5 files changed, 159 insertions(+) create mode 100644 src/test/java/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRuleTest.java create mode 100644 src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/OneColumnOneSquare create mode 100644 src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/OnePartialColumnOneSquare create mode 100644 src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/OnePartialColumnTwoSquares create mode 100644 src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/TwoColumns diff --git a/src/test/java/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRuleTest.java b/src/test/java/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRuleTest.java new file mode 100644 index 000000000..790f993b9 --- /dev/null +++ b/src/test/java/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRuleTest.java @@ -0,0 +1,32 @@ +package puzzles.starbattle.rules; + +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +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.ColumnsWithinRegionsDirectRule; +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 ColumnsWithinRegionsDirectRuleTest { + + private static final ColumnsWithinRegionsDirectRule RULE = new ColumnsWithinRegionsDirectRule(); + private static StarBattle starbattle; + + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + starbattle = new StarBattle(); + } + + //single column w/in single region one square outside + + +} diff --git a/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/OneColumnOneSquare b/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/OneColumnOneSquare new file mode 100644 index 000000000..4d065b28f --- /dev/null +++ b/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/OneColumnOneSquare @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/OnePartialColumnOneSquare b/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/OnePartialColumnOneSquare new file mode 100644 index 000000000..5c3fc22cc --- /dev/null +++ b/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/OnePartialColumnOneSquare @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/OnePartialColumnTwoSquares b/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/OnePartialColumnTwoSquares new file mode 100644 index 000000000..463f3a6d7 --- /dev/null +++ b/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/OnePartialColumnTwoSquares @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/TwoColumns b/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/TwoColumns new file mode 100644 index 000000000..ad5e4d198 --- /dev/null +++ b/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/TwoColumns @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From cf78cacc4132615e0563cbfbcda7188d92931000 Mon Sep 17 00:00:00 2001 From: summerhenson Date: Fri, 28 Jun 2024 14:21:08 -0400 Subject: [PATCH 157/258] Added new Too Few Stars contradiction rule test case --- .../TooFewStarsContradictionRuleTest.java | 30 ++++++++++++++ .../TwoStarColumn | 40 +++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/TwoStarColumn diff --git a/src/test/java/puzzles/starbattle/rules/TooFewStarsContradictionRuleTest.java b/src/test/java/puzzles/starbattle/rules/TooFewStarsContradictionRuleTest.java index 8a5fcfb88..e0aae994e 100644 --- a/src/test/java/puzzles/starbattle/rules/TooFewStarsContradictionRuleTest.java +++ b/src/test/java/puzzles/starbattle/rules/TooFewStarsContradictionRuleTest.java @@ -154,4 +154,34 @@ public void TooFewStarsContradictionRule_NotEnoughSpace() } } + @Test + public void TooFewStarsContradictionRule_TwoStarColumn() + throws InvalidFileFormatException { + + TestUtilities.importTestBoard("puzzles/starbattle/rules/TooFewStarsContradictionRule/TwoStarColumn", starBattle); + TreeNode rootNode = starBattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(0,0); + StarBattleCell cell2 = board.getCell(0,1); + StarBattleCell cell3 = board.getCell(0,2); + StarBattleCell cell4 = board.getCell(0,3); + + Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); + for (int i = 0; i < board.getHeight(); ++i) { + for (int j = 0; j < board.getWidth(); ++j) { + Point point = new Point(j,i); + if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) || + point.equals(cell3.getLocation()) || point.equals(cell4.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + } + } + } + } diff --git a/src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/TwoStarColumn b/src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/TwoStarColumn new file mode 100644 index 000000000..d781b3092 --- /dev/null +++ b/src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/TwoStarColumn @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From dc7394769b4d0d117dbd1e1b354bc71367a69bb4 Mon Sep 17 00:00:00 2001 From: summerhenson Date: Fri, 28 Jun 2024 14:26:25 -0400 Subject: [PATCH 158/258] Added second new test case for Too Few Stars contradiction rule --- .../TooFewStarsContradictionRuleTest.java | 18 +++++++++ .../TwoStarFalseContradiction | 40 +++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/TwoStarFalseContradiction diff --git a/src/test/java/puzzles/starbattle/rules/TooFewStarsContradictionRuleTest.java b/src/test/java/puzzles/starbattle/rules/TooFewStarsContradictionRuleTest.java index e0aae994e..2c90c6fb2 100644 --- a/src/test/java/puzzles/starbattle/rules/TooFewStarsContradictionRuleTest.java +++ b/src/test/java/puzzles/starbattle/rules/TooFewStarsContradictionRuleTest.java @@ -184,4 +184,22 @@ public void TooFewStarsContradictionRule_TwoStarColumn() } } + @Test + public void TooFewStarsContradictionRule_TwoStarFalseContradiction() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/TooFewStarsContradictionRule/TwoStarFalseContradiction", starBattle); + TreeNode rootNode = starBattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + + Assert.assertNotNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); + for (int i = 0; i < board.getHeight(); ++i) { + for (int j = 0; j < board.getWidth(); ++j) { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + } + } + } diff --git a/src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/TwoStarFalseContradiction b/src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/TwoStarFalseContradiction new file mode 100644 index 000000000..5f1d2753f --- /dev/null +++ b/src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/TwoStarFalseContradiction @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 1441f933476f88f097337cc392af3caccee418f2 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Fri, 28 Jun 2024 14:46:15 -0400 Subject: [PATCH 159/258] Each possible binary string combination is added to row --- .../EliminateTheImpossibleDirectRule.java | 56 +++++++++---------- 1 file changed, 26 insertions(+), 30 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java index f03e1ad6d..2cf33d088 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java @@ -124,36 +124,32 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem // form), the amount of zeros left and ones left generatePossibilitites((size - rowNumZeros - rowNumOnes), rowResult, size / 2 - rowNumZeros, size / 2 - rowNumOnes); - for (String s : rowResult) - System.out.println(s); - - ArrayList> rowCopies = new ArrayList<>(); - for(int i = 0; i < rowResult.size(); i++){ - rowCopies.add( new ArrayList(row) ); - } - System.out.println("Number of possible binary combinations: " + rowCopies.size()); - -// for(ArrayList curRow : rowCopies){ -// int idx = 0; -// for(int i = 0; i < curRow.size(); i++ ){ -// if(curRow.get(i).getType().equals(BinaryType.UNKNOWN)){ -// if (rowResult.get(i).equals("0")) -// curRow.get(i).setData(0); -// else if (rowResult.get(i).equals("1")) -// curRow.get(i).setData(1); -// idx++; -// } -// System.out.print(curRow.get(i)); -// } -// System.out.println(""); -// } - - // System.out.println("printing result"); - // for (String s : rowResult) { - // System.out.println(s); - // } - - return "Grouping of Three Ones or Zeros not found TEST"; + ArrayList> rowCopies = new ArrayList<>(); + for(int i = 0; i < rowResult.size(); i++){ + rowCopies.add( new ArrayList(row) ); + } + + System.out.println("Number of possible binary combinations: " + rowCopies.size()); + + int rowIdx = 0; + for(ArrayList curRow : rowCopies){ + int charIdx = 0; + System.out.println(rowResult.get(rowIdx)); + for(int i = 0; i < curRow.size(); i++ ) { + if (curRow.get(i).getData() == 2) { + if (rowResult.get(rowIdx).charAt(charIdx) == '0') + curRow.get(i).setData(0); + else if (rowResult.get(rowIdx).charAt(charIdx) == '1') + curRow.get(i).setData(1); + charIdx++; + } + System.out.print(curRow.get(i).getData() + " "); + } + rowIdx++; + System.out.println(); + } + + return "Grouping of Three Ones or Zeros not found"; } From 541edffa9358a88376b408a6e28e549432995672 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Fri, 28 Jun 2024 14:54:07 -0400 Subject: [PATCH 160/258] Fixed EliminateTheImpossible so each row is a deep copy of original --- .../binary/rules/EliminateTheImpossibleDirectRule.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java index 2cf33d088..aea921766 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java @@ -124,9 +124,14 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem // form), the amount of zeros left and ones left generatePossibilitites((size - rowNumZeros - rowNumOnes), rowResult, size / 2 - rowNumZeros, size / 2 - rowNumOnes); + // Create deep copies of each row ArrayList> rowCopies = new ArrayList<>(); - for(int i = 0; i < rowResult.size(); i++){ - rowCopies.add( new ArrayList(row) ); + for (int i = 0; i < rowResult.size(); i++) { + ArrayList newRow = new ArrayList<>(); + for (BinaryCell cell : row) { + newRow.add(cell.copy()); + } + rowCopies.add(newRow); } System.out.println("Number of possible binary combinations: " + rowCopies.size()); From 7575f17cb46e320bcd4b62002084ad3fa4e0d4c5 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Fri, 28 Jun 2024 16:27:20 -0400 Subject: [PATCH 161/258] Fixed curly brace checkstyle error --- .../binary/rules/EliminateTheImpossibleDirectRule.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java index aea921766..724edf113 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java @@ -142,10 +142,12 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem System.out.println(rowResult.get(rowIdx)); for(int i = 0; i < curRow.size(); i++ ) { if (curRow.get(i).getData() == 2) { - if (rowResult.get(rowIdx).charAt(charIdx) == '0') + if (rowResult.get(rowIdx).charAt(charIdx) == '0') { curRow.get(i).setData(0); - else if (rowResult.get(rowIdx).charAt(charIdx) == '1') + } + else if (rowResult.get(rowIdx).charAt(charIdx) == '1') { curRow.get(i).setData(1); + } charIdx++; } System.out.print(curRow.get(i).getData() + " "); From 81483ded3da2297c13f95410fa3367d6edfa7ca2 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Sun, 30 Jun 2024 00:23:10 -0400 Subject: [PATCH 162/258] Modified Puzzle Solver -> when opened, a blank board is shown with no rules. Added an Open toolbar button --- src/main/java/edu/rpi/legup/ui/HomePanel.java | 76 ++----- .../edu/rpi/legup/ui/ProofEditorPanel.java | 206 ++++++++++-------- .../edu/rpi/legup/ui/PuzzleEditorPanel.java | 10 +- 3 files changed, 134 insertions(+), 158 deletions(-) diff --git a/src/main/java/edu/rpi/legup/ui/HomePanel.java b/src/main/java/edu/rpi/legup/ui/HomePanel.java index dd0061feb..29e3600d8 100644 --- a/src/main/java/edu/rpi/legup/ui/HomePanel.java +++ b/src/main/java/edu/rpi/legup/ui/HomePanel.java @@ -40,14 +40,15 @@ public class HomePanel extends LegupPanel { new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - Object[] items = legupUI.getProofEditor().promptPuzzle(); - if (items == null) { - // The attempt to prompt a puzzle ended gracefully (cancel) - return; - } - String fileName = (String) items[0]; - File puzzleFile = (File) items[1]; - legupUI.getProofEditor().loadPuzzle(fileName, puzzleFile); +// Object[] items = legupUI.getProofEditor().promptPuzzle(); +// if (items == null) { +// // The attempt to prompt a puzzle ended gracefully (cancel) +// return; +// } +// String fileName = (String) items[0]; +// File puzzleFile = (File) items[1]; + legupUI.getProofEditor().loadPuzzle("", null); +// legupUI.getProofEditor().loadPuzzle(); } }; @@ -116,10 +117,10 @@ private static ImageIcon resizeButtonIcon(ImageIcon icon, int width, int height) } private void initButtons() { - this.buttons = new JButton[4]; + this.buttons = new JButton[3]; this.buttons[0] = - new JButton("Solve Puzzle") { + new JButton("Puzzle Solver") { { setSize(buttonSize, buttonSize); setMaximumSize(getSize()); @@ -136,23 +137,6 @@ private void initButtons() { this.buttons[0].setVerticalTextPosition(AbstractButton.BOTTOM); this.buttons[0].addActionListener(CursorController.createListener(this, openProofListener)); -// this.buttons[1] = -// new JButton("Create Puzzle") { -// { -// setSize(buttonSize, buttonSize); -// setMaximumSize(getSize()); -// } -// }; -// URL button1IconLocation = -// ClassLoader.getSystemClassLoader() -// .getResource("edu/rpi/legup/images/Legup/homepanel/new_puzzle_file.png"); -// ImageIcon button1Icon = new ImageIcon(button1IconLocation); -// this.buttons[1].setFocusPainted(false); -// this.buttons[1].setIcon(resizeButtonIcon(button1Icon, this.buttonSize, this.buttonSize)); -// this.buttons[1].setHorizontalTextPosition(AbstractButton.CENTER); -// this.buttons[1].setVerticalTextPosition(AbstractButton.BOTTOM); -// this.buttons[1].addActionListener(l -> this.openNewPuzzleDialog()); - this.buttons[1] = new JButton("Puzzle Editor") { { @@ -169,37 +153,16 @@ private void initButtons() { this.buttons[1].setHorizontalTextPosition(AbstractButton.CENTER); this.buttons[1].setVerticalTextPosition(AbstractButton.BOTTOM); this.buttons[1].addActionListener(l -> this.openPuzzleEditorDialog()); - //this.buttons[1].addActionListener(l -> this.openNewPuzzleDialog()); - - this.buttons[2] = - new JButton("Edit Existing Puzzle") { - { - setSize(buttonSize, buttonSize); - setMaximumSize(getSize()); - } - }; - URL button2IconLocation = - ClassLoader.getSystemClassLoader() - .getResource("edu/rpi/legup/images/Legup/homepanel/puzzle_file.png"); - ImageIcon button2Icon = new ImageIcon(button2IconLocation); - this.buttons[2].setFocusPainted(false); - this.buttons[2].setIcon(resizeButtonIcon(button2Icon, this.buttonSize, this.buttonSize)); - this.buttons[2].setHorizontalTextPosition(AbstractButton.CENTER); - this.buttons[2].setVerticalTextPosition(AbstractButton.BOTTOM); - this.buttons[2].addActionListener( - CursorController.createListener(this, openPuzzleListener)); // PLACEHOLDER - - this.buttons[2].setVisible(false); for (int i = 0; i < this.buttons.length - 1; i++) { // -1 to avoid the batch grader button this.buttons[i].setBounds(200, 200, 700, 700); } - this.buttons[3] = new JButton("Batch Grader"); - this.buttons[3].setFocusPainted(false); - this.buttons[3].setHorizontalTextPosition(AbstractButton.CENTER); - this.buttons[3].setVerticalTextPosition(AbstractButton.BOTTOM); + this.buttons[2] = new JButton("Batch Grader"); + this.buttons[2].setFocusPainted(false); + this.buttons[2].setHorizontalTextPosition(AbstractButton.CENTER); + this.buttons[2].setVerticalTextPosition(AbstractButton.BOTTOM); - this.buttons[3].addActionListener( + this.buttons[2].addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { @@ -293,7 +256,7 @@ public void checkFolder() { } } catch (IOException ex) { LOGGER.error(ex.getMessage()); - this.buttons[3].addActionListener((ActionEvent e) -> use_xml_to_check()); + this.buttons[2].addActionListener((ActionEvent e) -> use_xml_to_check()); } } @@ -531,11 +494,8 @@ private void render() { buttons.add(Box.createRigidArea(new Dimension(5, 0))); buttons.add(this.buttons[1]); buttons.add(Box.createRigidArea(new Dimension(5, 0))); - buttons.add(this.buttons[2]); - buttons.add(Box.createRigidArea(new Dimension(5, 0))); - JPanel batchGraderButton = new JPanel(); - batchGraderButton.add(this.buttons[3]); + batchGraderButton.add(this.buttons[2]); batchGraderButton.setAlignmentX(Component.CENTER_ALIGNMENT); this.add(Box.createRigidArea(new Dimension(0, 5))); diff --git a/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java b/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java index 99b08f963..eba0daba0 100644 --- a/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java +++ b/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java @@ -46,8 +46,8 @@ public class ProofEditorPanel extends LegupPanel implements IHistoryListener { private DynamicView dynamicBoardView; private JSplitPane topHalfPanel, mainPanel; private TitledBorder boardBorder; - - private JButton[] toolBarButtons; + private JButton[] toolBar1Buttons; + private JButton[] toolBar2Buttons; private JMenu file; private JMenuItem newPuzzle, resetPuzzle, @@ -67,7 +67,8 @@ public class ProofEditorPanel extends LegupPanel implements IHistoryListener { private JMenu about, help; private JMenuItem helpLegup, aboutLegup; - private JToolBar toolBar; + private JToolBar toolBar1; + private JToolBar toolBar2; private BoardView boardView; private JFileChooser folderBrowser; @@ -81,7 +82,6 @@ public class ProofEditorPanel extends LegupPanel implements IHistoryListener { public static final int IMD_FEEDBACK = 32; public static final int INTERN_RO = 64; public static final int AUTO_JUST = 128; - static final int[] TOOLBAR_SEPARATOR_BEFORE = {1}; private static final String[] PROFILES = { "No Assistance", "Rigorous Proof", @@ -123,7 +123,7 @@ public ProofEditorPanel(FileDialog fileDialog, JFrame frame, LegupUI legupUI) { public void makeVisible() { this.removeAll(); - setupToolBar(); + setupToolBar1(); setupContent(); frame.setJMenuBar(getMenuBar()); } @@ -521,6 +521,9 @@ public void loadPuzzle() { } public void loadPuzzle(String fileName, File puzzleFile) { + if (puzzleFile == null && fileName.equals("")) { + legupUI.displayPanel(1); + } if (puzzleFile != null && puzzleFile.exists()) { try { legupUI.displayPanel(1); @@ -741,98 +744,122 @@ protected void setupContent() { revalidate(); } - private void setupToolBar() { - setToolBarButtons(new JButton[ToolbarName.values().length]); - for (int i = 0; i < ToolbarName.values().length; i++) { - String toolBarName = ToolbarName.values()[i].toString(); - URL resourceLocation = - ClassLoader.getSystemClassLoader() - .getResource("edu/rpi/legup/images/Legup/" + toolBarName + ".png"); - - // Scale the image icons down to make the buttons smaller - ImageIcon imageIcon = new ImageIcon(resourceLocation); - Image image = imageIcon.getImage(); - imageIcon = - new ImageIcon( - image.getScaledInstance( - this.TOOLBAR_ICON_SCALE, - this.TOOLBAR_ICON_SCALE, - Image.SCALE_SMOOTH)); - - JButton button = new JButton(toolBarName, imageIcon); - button.setFocusPainted(false); - getToolBarButtons()[i] = button; - } + private void setupToolBar1() { + toolBar1 = new JToolBar(); + toolBar1.setFloatable(false); + toolBar1.setRollover(true); + setToolBar2Buttons(new JButton[1]); - toolBar = new JToolBar(); - toolBar.setFloatable(false); - toolBar.setRollover(true); + URL open_url = + ClassLoader.getSystemClassLoader() + .getResource("edu/rpi/legup/images/Legup/Open.png"); - for (int i = 0; i < getToolBarButtons().length; i++) { - for (int s = 0; s < TOOLBAR_SEPARATOR_BEFORE.length; s++) { - if (i == TOOLBAR_SEPARATOR_BEFORE[s]) { - toolBar.addSeparator(); - } - } - String toolBarName = ToolbarName.values()[i].toString(); + // Scale the image icons down to make the buttons smaller + ImageIcon OpenImageIcon = new ImageIcon(open_url); + Image OpenImage = OpenImageIcon.getImage(); + OpenImageIcon = + new ImageIcon( + OpenImage.getScaledInstance( + this.TOOLBAR_ICON_SCALE, + this.TOOLBAR_ICON_SCALE, + Image.SCALE_SMOOTH)); - toolBar.add(getToolBarButtons()[i]); - getToolBarButtons()[i].setToolTipText(toolBarName); + JButton open = new JButton("Open", OpenImageIcon); + open.setFocusPainted(false); - getToolBarButtons()[i].setVerticalTextPosition(SwingConstants.BOTTOM); - getToolBarButtons()[i].setHorizontalTextPosition(SwingConstants.CENTER); - } + open.addActionListener((ActionEvent) -> loadPuzzle()); + + getToolBar2Buttons()[0] = open; + toolBar1.add(getToolBar2Buttons()[0]); + + this.add(toolBar1, BorderLayout.NORTH); + } + + private void setupToolBar2() { + toolBar2 = new JToolBar(); + toolBar2.setFloatable(false); + toolBar2.setRollover(true); + setToolBar2Buttons(new JButton[2]); + + URL directions_url = + ClassLoader.getSystemClassLoader() + .getResource("edu/rpi/legup/images/Legup/Directions.png"); + + // Scale the image icons down to make the buttons smaller + ImageIcon DirectionsImageIcon = new ImageIcon(directions_url); + Image DirectionsImage = DirectionsImageIcon.getImage(); + DirectionsImageIcon = + new ImageIcon( + DirectionsImage.getScaledInstance( + this.TOOLBAR_ICON_SCALE, + this.TOOLBAR_ICON_SCALE, + Image.SCALE_SMOOTH)); + + JButton directions = new JButton("Directions", DirectionsImageIcon); + directions.setFocusPainted(false); + directions.addActionListener((ActionEvent) -> directionsToolButton()); + + getToolBar2Buttons()[0] = directions; + toolBar2.add(getToolBar2Buttons()[0]); + + URL check_url = + ClassLoader.getSystemClassLoader() + .getResource("edu/rpi/legup/images/Legup/Check.png"); + + // Scale the image icons down to make the buttons smaller + ImageIcon CheckImageIcon = new ImageIcon(check_url); + Image CheckImage = CheckImageIcon.getImage(); + CheckImageIcon = + new ImageIcon( + CheckImage.getScaledInstance( + this.TOOLBAR_ICON_SCALE, + this.TOOLBAR_ICON_SCALE, + Image.SCALE_SMOOTH)); + + JButton check = new JButton("Check", CheckImageIcon); + check.setFocusPainted(false); + check.addActionListener((ActionEvent) -> checkProof()); + + getToolBar2Buttons()[1] = check; + toolBar2.add(getToolBar2Buttons()[1]); + + this.add(toolBar2, BorderLayout.NORTH); + } + + /** + * Sets the toolbar1 buttons + * + * @param toolBar1Buttons toolbar buttons + */ + public void setToolBar1Buttons(JButton[] toolBar1Buttons) { + this.toolBar1Buttons = toolBar1Buttons; + } - // toolBarButtons[ToolbarName.OPEN_PUZZLE.ordinal()].addActionListener((ActionEvent - // e) -> - // promptPuzzle()); - // toolBarButtons[ToolbarName.SAVE.ordinal()].addActionListener((ActionEvent e) -> - // saveProof()); - // toolBarButtons[ToolbarName.UNDO.ordinal()].addActionListener((ActionEvent e) -> - // GameBoardFacade.getInstance().getHistory().undo()); - // toolBarButtons[ToolbarName.REDO.ordinal()].addActionListener((ActionEvent e) -> - // GameBoardFacade.getInstance().getHistory().redo()); - //toolBarButtons[ToolbarName.HINT.ordinal()].addActionListener((ActionEvent e) -> {}); - toolBarButtons[ToolbarName.CHECK.ordinal()].addActionListener( - (ActionEvent e) -> checkProof()); - //toolBarButtons[ToolbarName.SUBMIT.ordinal()].addActionListener((ActionEvent e) -> {}); - toolBarButtons[ToolbarName.DIRECTIONS.ordinal()].addActionListener((ActionEvent e) -> directionsToolButton()); - -// toolBarButtons[ToolbarName.CHECK_ALL.ordinal()].addActionListener( -// (ActionEvent e) -> checkProofAll()); - - // toolBarButtons[ToolbarName.SAVE.ordinal()].setEnabled(false); - // toolBarButtons[ToolbarName.UNDO.ordinal()].setEnabled(false); - // toolBarButtons[ToolbarName.REDO.ordinal()].setEnabled(false); - //toolBarButtons[ToolbarName.HINT.ordinal()].setEnabled(false); - toolBarButtons[ToolbarName.CHECK.ordinal()].setEnabled(true); - //toolBarButtons[ToolbarName.SUBMIT.ordinal()].setEnabled(false); - toolBarButtons[ToolbarName.DIRECTIONS.ordinal()].setEnabled(true); - //toolBarButtons[ToolbarName.CHECK_ALL.ordinal()].setEnabled(false); - -// toolBarButtons[ToolbarName.HINT.ordinal()].setVisible(false); -// toolBarButtons[ToolbarName.SUBMIT.ordinal()].setVisible(false); -// toolBarButtons[ToolbarName.CHECK_ALL.ordinal()].setVisible(false); - - this.add(toolBar, BorderLayout.NORTH); + /** + * Sets the toolbar2 buttons + * + * @param toolBar2Buttons toolbar buttons + */ + public void setToolBar2Buttons(JButton[] toolBar2Buttons) { + this.toolBar2Buttons = toolBar2Buttons; } /** - * Sets the toolbar buttons + * Gets the toolbar1 buttons * - * @param toolBarButtons toolbar buttons + * @return toolbar1 buttons */ - public void setToolBarButtons(JButton[] toolBarButtons) { - this.toolBarButtons = toolBarButtons; + public JButton[] getToolBar1Buttons() { + return toolBar1Buttons; } /** - * Gets the toolbar buttons + * Gets the toolbar2 buttons * - * @return toolbar buttons + * @return toolbar2 buttons */ - public JButton[] getToolBarButtons() { - return toolBarButtons; + public JButton[] getToolBar2Buttons() { + return toolBar2Buttons; } /** Checks the proof for correctness */ @@ -918,9 +945,8 @@ public void setPuzzleView(Puzzle puzzle) { ruleFrame.getContradictionPanel().setRules(puzzle.getContradictionRules()); ruleFrame.getSearchPanel().setSearchBar(puzzle); - toolBarButtons[ToolbarName.CHECK.ordinal()].setEnabled(true); - // toolBarButtons[ToolbarName.SAVE.ordinal()].setEnabled(true); - + toolBar1.setVisible(false); + setupToolBar2(); reloadGui(); } @@ -1057,9 +1083,7 @@ public TreePanel getTreePanel() { public void onPushChange(ICommand command) { LOGGER.info("Pushing " + command.getClass().getSimpleName() + " to stack."); undo.setEnabled(true); - // toolBarButtons[ToolbarName.UNDO.ordinal()].setEnabled(true); redo.setEnabled(false); - // toolBarButtons[ToolbarName.REDO.ordinal()].setEnabled(false); String puzzleName = GameBoardFacade.getInstance().getPuzzleModule().getName(); File puzzleFile = new File(GameBoardFacade.getInstance().getCurFileName()); @@ -1070,9 +1094,9 @@ public void onPushChange(ICommand command) { @Override public void onClearHistory() { // undo.setEnabled(false); - // toolBarButtons[ToolbarName.UNDO.ordinal()].setEnabled(false); + // toolBar2Buttons[ToolbarName.UNDO.ordinal()].setEnabled(false); // redo.setEnabled(false); - // toolBarButtons[ToolbarName.REDO.ordinal()].setEnabled(false); + // toolBar2Buttons[ToolbarName.REDO.ordinal()].setEnabled(false); } /** @@ -1084,9 +1108,7 @@ public void onClearHistory() { @Override public void onRedo(boolean isBottom, boolean isTop) { undo.setEnabled(!isBottom); - // toolBarButtons[ToolbarName.UNDO.ordinal()].setEnabled(!isBottom); redo.setEnabled(!isTop); - // toolBarButtons[ToolbarName.REDO.ordinal()].setEnabled(!isTop); if (isBottom) { String puzzleName = GameBoardFacade.getInstance().getPuzzleModule().getName(); File puzzleFile = new File(GameBoardFacade.getInstance().getCurFileName()); @@ -1107,9 +1129,7 @@ public void onRedo(boolean isBottom, boolean isTop) { @Override public void onUndo(boolean isBottom, boolean isTop) { undo.setEnabled(!isBottom); - // toolBarButtons[ToolbarName.UNDO.ordinal()].setEnabled(!isBottom); redo.setEnabled(!isTop); - // toolBarButtons[ToolbarName.REDO.ordinal()].setEnabled(!isTop); String puzzleName = GameBoardFacade.getInstance().getPuzzleModule().getName(); File puzzleFile = new File(GameBoardFacade.getInstance().getCurFileName()); if (isBottom) { diff --git a/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java b/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java index 723085658..6d4c35616 100644 --- a/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java +++ b/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java @@ -309,6 +309,9 @@ private void setupToolBar1() { } private void setupToolBar2() { + toolBar2 = new JToolBar(); + toolBar2.setFloatable(false); + toolBar2.setRollover(true); setToolBar2Buttons(new JButton[2]); URL save_as = @@ -328,10 +331,6 @@ private void setupToolBar2() { saveas.addActionListener((ActionEvent) -> savePuzzle()); getToolBar2Buttons()[0] = saveas; - - toolBar2 = new JToolBar(); - toolBar2.setFloatable(false); - toolBar2.setRollover(true); toolBar2.add(getToolBar2Buttons()[0]); URL save_and_solve = @@ -369,9 +368,6 @@ public void actionPerformed(ActionEvent e) { } }); getToolBar2Buttons()[1] = saveandsolve; - - toolBar2.setFloatable(false); - toolBar2.setRollover(true); toolBar2.add(getToolBar2Buttons()[1]); this.add(toolBar2, BorderLayout.NORTH); From 3b5b7d03c7af190cf9a2b6530a66873e722433f9 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Tue, 2 Jul 2024 15:41:35 -0400 Subject: [PATCH 163/258] Fixed case rule bug that causes proof tree to lock when deleting if the number of case branches is 0 --- .../legup/history/AutoCaseRuleCommand.java | 2 +- .../history/DeleteTreeElementCommand.java | 7 ++--- .../edu/rpi/legup/model/gameboard/Board.java | 2 ++ .../java/edu/rpi/legup/model/tree/Tree.java | 28 ++++++++++++++++++- .../binary/rules/OneOrZeroCaseRule.java | 7 ++++- .../fillapix/rules/BlackOrWhiteCaseRule.java | 3 ++ .../fillapix/rules/SatisfyClueCaseRule.java | 3 ++ .../lightup/rules/LightOrEmptyCaseRule.java | 4 +++ .../lightup/rules/SatisfyNumberCaseRule.java | 6 +++- .../nurikabe/rules/BlackOrWhiteCaseRule.java | 4 +++ .../nurikabe/rules/FinishRoomCaseRule.java | 4 +++ .../rules/caserule/CaseRuleAtomic.java | 3 ++ .../caserule/CaseRule_GenericStatement.java | 5 ++++ .../rules/CellForNumberCaseRule.java | 3 ++ .../rules/NumberForCellCaseRule.java | 3 ++ .../starbattle/rules/StarOrEmptyCaseRule.java | 4 +++ .../sudoku/rules/PossibleCellCaseRule.java | 4 +++ .../sudoku/rules/PossibleNumberCaseRule.java | 4 +++ .../treetent/rules/FillinRowCaseRule.java | 4 +++ .../treetent/rules/LinkTentCaseRule.java | 4 +++ .../treetent/rules/LinkTreeCaseRule.java | 4 +++ .../edu/rpi/legup/ui/ProofEditorPanel.java | 9 ++++++ .../ui/proofeditorui/treeview/TreeView.java | 1 - 23 files changed, 109 insertions(+), 9 deletions(-) diff --git a/src/main/java/edu/rpi/legup/history/AutoCaseRuleCommand.java b/src/main/java/edu/rpi/legup/history/AutoCaseRuleCommand.java index 97192e145..fd15a7ae2 100644 --- a/src/main/java/edu/rpi/legup/history/AutoCaseRuleCommand.java +++ b/src/main/java/edu/rpi/legup/history/AutoCaseRuleCommand.java @@ -60,7 +60,7 @@ public void executeCommand() { caseRule.getCases(caseBoard.getBaseBoard(), elementView.getPuzzleElement()); for (Board board : cases) { final TreeTransition transition = (TreeTransition) tree.addTreeElement(node); - board.setModifiable(false); + //board.setModifiable(false); transition.setBoard(board); transition.setRule(caseRule); transition.setSelection(elementView.getPuzzleElement().copy()); diff --git a/src/main/java/edu/rpi/legup/history/DeleteTreeElementCommand.java b/src/main/java/edu/rpi/legup/history/DeleteTreeElementCommand.java index 0469685c1..258aaacc0 100644 --- a/src/main/java/edu/rpi/legup/history/DeleteTreeElementCommand.java +++ b/src/main/java/edu/rpi/legup/history/DeleteTreeElementCommand.java @@ -39,16 +39,15 @@ public void executeCommand() { } for (TreeElementView selectedView : selectedViews) { + System.out.println("DELETED"); TreeElement element = selectedView.getTreeElement(); tree.removeTreeElement(element); puzzle.notifyTreeListeners(listener -> listener.onTreeElementRemoved(element)); } final TreeViewSelection newSelection = new TreeViewSelection(newSelectedView); - puzzle.notifyBoardListeners( - listener -> listener.onTreeElementChanged(newSelectedView.getTreeElement())); - puzzle.notifyTreeListeners( - (ITreeListener listener) -> listener.onTreeSelectionChanged(newSelection)); + puzzle.notifyBoardListeners(listener -> listener.onTreeElementChanged(newSelectedView.getTreeElement())); + puzzle.notifyTreeListeners((ITreeListener listener) -> listener.onTreeSelectionChanged(newSelection)); } /** diff --git a/src/main/java/edu/rpi/legup/model/gameboard/Board.java b/src/main/java/edu/rpi/legup/model/gameboard/Board.java index d8bdf5199..b6d3ed995 100644 --- a/src/main/java/edu/rpi/legup/model/gameboard/Board.java +++ b/src/main/java/edu/rpi/legup/model/gameboard/Board.java @@ -37,6 +37,8 @@ public Board(int size) { * @return equivalent puzzleElement on this board */ public PuzzleElement getPuzzleElement(PuzzleElement puzzleElement) { + if (puzzleElement == null) + return null; int index = puzzleElement.getIndex(); return index < puzzleElements.size() ? puzzleElements.get(index) : null; } diff --git a/src/main/java/edu/rpi/legup/model/tree/Tree.java b/src/main/java/edu/rpi/legup/model/tree/Tree.java index a0746db87..08e594801 100644 --- a/src/main/java/edu/rpi/legup/model/tree/Tree.java +++ b/src/main/java/edu/rpi/legup/model/tree/Tree.java @@ -46,7 +46,7 @@ public TreeElement addTreeElement(TreeElement element) { } else { TreeTransition transition = (TreeTransition) element; Board copyBoard = transition.board.copy(); - copyBoard.setModifiable(false); + copyBoard.setModifiable(true); return addTreeElement(transition, new TreeNode(copyBoard)); } } @@ -63,17 +63,43 @@ public TreeElement addTreeElement(TreeTransition transition, TreeNode treeNode) return treeNode; } +// public void removeTreeElement(TreeElement element) { +// if (element.getType() == TreeElementType.NODE) { +// TreeNode node = (TreeNode) element; +// node.getParent().setChildNode(null); +// } else { +// TreeTransition transition = (TreeTransition) element; +// System.out.println("DELETED CHILD"); +// transition.getParents().forEach(n -> n.removeChild(transition)); +// transition.getParents().get(0).getChildren().forEach(TreeTransition::reverify); +// } +// } + public void removeTreeElement(TreeElement element) { if (element.getType() == TreeElementType.NODE) { TreeNode node = (TreeNode) element; + + // Output when node has children + if (!node.getChildren().isEmpty()) { + System.out.println("Deleting children of node: " + node); + for (TreeTransition child : new ArrayList<>(node.getChildren())) { + removeTreeElement(child); + } + } + node.getParent().setChildNode(null); + System.out.println("Deleted node: " + node); } else { TreeTransition transition = (TreeTransition) element; + System.out.println("Deleted arrow: " + transition); + transition.getParents().forEach(n -> n.removeChild(transition)); transition.getParents().get(0).getChildren().forEach(TreeTransition::reverify); } } + + /** * Determines if the tree is valid by checking whether this tree puzzleElement and all * descendants of this tree puzzleElement is justified and justified correctly diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneOrZeroCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneOrZeroCaseRule.java index 62230f469..7ce6f1589 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneOrZeroCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneOrZeroCaseRule.java @@ -53,7 +53,8 @@ public String checkRuleRaw(TreeTransition transition) { public CaseBoard getCaseBoard(Board board) { BinaryBoard binaryBoard = (BinaryBoard) board.copy(); CaseBoard caseBoard = new CaseBoard(binaryBoard, this); - binaryBoard.setModifiable(false); + caseBoard.setModifiable(true); + //binaryBoard.setModifiable(false); for (PuzzleElement element : binaryBoard.getPuzzleElements()) { if (((BinaryCell) element).getType() == BinaryType.UNKNOWN) { caseBoard.addPickableElement(element); @@ -65,6 +66,10 @@ public CaseBoard getCaseBoard(Board board) { @Override public ArrayList getCases(Board board, PuzzleElement puzzleElement) { ArrayList cases = new ArrayList<>(); + if (puzzleElement == null) { + return cases; + } + Board case1 = board.copy(); PuzzleElement data1 = case1.getPuzzleElement(puzzleElement); data1.setData(BinaryType.ZERO.toValue()); diff --git a/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/BlackOrWhiteCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/BlackOrWhiteCaseRule.java index 860a6c011..f0194bd39 100644 --- a/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/BlackOrWhiteCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/BlackOrWhiteCaseRule.java @@ -37,6 +37,9 @@ public CaseBoard getCaseBoard(Board board) { @Override public ArrayList getCases(Board board, PuzzleElement puzzleElement) { ArrayList cases = new ArrayList<>(); + if (puzzleElement == null) { + return cases; + } Board case1 = board.copy(); FillapixCell cell1 = (FillapixCell) case1.getPuzzleElement(puzzleElement); diff --git a/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/SatisfyClueCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/SatisfyClueCaseRule.java index 7db833f76..f8bb2d4f5 100644 --- a/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/SatisfyClueCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/SatisfyClueCaseRule.java @@ -45,6 +45,9 @@ public CaseBoard getCaseBoard(Board board) { @Override public ArrayList getCases(Board board, PuzzleElement puzzleElement) { ArrayList cases = new ArrayList(); + if (puzzleElement == null) { + return cases; + } // get value of cell FillapixBoard fillapixBoard = (FillapixBoard) board.copy(); diff --git a/src/main/java/edu/rpi/legup/puzzle/lightup/rules/LightOrEmptyCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/lightup/rules/LightOrEmptyCaseRule.java index 4ba754731..53efb6587 100644 --- a/src/main/java/edu/rpi/legup/puzzle/lightup/rules/LightOrEmptyCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/lightup/rules/LightOrEmptyCaseRule.java @@ -44,6 +44,10 @@ public CaseBoard getCaseBoard(Board board) { @Override public ArrayList getCases(Board board, PuzzleElement puzzleElement) { ArrayList cases = new ArrayList<>(); + if (puzzleElement == null) { + return cases; + } + Board case1 = board.copy(); PuzzleElement data1 = case1.getPuzzleElement(puzzleElement); data1.setData(-4); diff --git a/src/main/java/edu/rpi/legup/puzzle/lightup/rules/SatisfyNumberCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/lightup/rules/SatisfyNumberCaseRule.java index 490122874..f73a34b2d 100644 --- a/src/main/java/edu/rpi/legup/puzzle/lightup/rules/SatisfyNumberCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/lightup/rules/SatisfyNumberCaseRule.java @@ -47,6 +47,11 @@ public CaseBoard getCaseBoard(Board board) { */ @Override public ArrayList getCases(Board board, PuzzleElement puzzleElement) { + ArrayList cases = new ArrayList<>(); + if (puzzleElement == null) { + return cases; + } + LightUpBoard lightUpBoard = (LightUpBoard) board; LightUpCell cell = (LightUpCell) puzzleElement; Point loc = cell.getLocation(); @@ -96,7 +101,6 @@ public ArrayList getCases(Board board, PuzzleElement puzzleElement) { } } - ArrayList cases = new ArrayList<>(); if (numNeeded == 0) { return cases; } diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/BlackOrWhiteCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/BlackOrWhiteCaseRule.java index ac0ab6df6..209ce47d5 100644 --- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/BlackOrWhiteCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/BlackOrWhiteCaseRule.java @@ -84,6 +84,10 @@ public CaseBoard getCaseBoard(Board board) { @Override public ArrayList getCases(Board board, PuzzleElement puzzleElement) { ArrayList cases = new ArrayList<>(); + if (puzzleElement == null) { + return cases; + } + Board case1 = board.copy(); PuzzleElement data1 = case1.getPuzzleElement(puzzleElement); data1.setData(NurikabeType.WHITE.toValue()); diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/FinishRoomCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/FinishRoomCaseRule.java index e941922fd..e1b7ca18d 100644 --- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/FinishRoomCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/FinishRoomCaseRule.java @@ -115,6 +115,10 @@ public CaseBoard getCaseBoard(Board board) { @Override public ArrayList getCases(Board board, PuzzleElement puzzleElement) { ArrayList cases = new ArrayList<>(); // makes array list of cases + if (puzzleElement == null) { + return cases; + } + NurikabeBoard nuriBoard = (NurikabeBoard) board.copy(); // nurikabe board to edit NurikabeCell numberCell = nuriBoard.getCell(((NurikabeCell) puzzleElement).getLocation().x, ((NurikabeCell) puzzleElement).getLocation().y); // number cell whose room we want to fill diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRuleAtomic.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRuleAtomic.java index 58d2068b2..22b49fd77 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRuleAtomic.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRuleAtomic.java @@ -44,6 +44,9 @@ public CaseBoard getCaseBoard(Board board) { @Override public ArrayList getCases(Board board, PuzzleElement puzzleElement) { ArrayList cases = new ArrayList<>(); + if (puzzleElement == null) { + return cases; + } Board case1 = board.copy(); PuzzleElement data1 = case1.getPuzzleElement(puzzleElement); diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRule_GenericStatement.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRule_GenericStatement.java index 99f771246..8aeb51a46 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRule_GenericStatement.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRule_GenericStatement.java @@ -85,6 +85,11 @@ public CaseBoard getCaseBoard(Board board) { @SuppressWarnings("unchecked") @Override public ArrayList getCases(Board board, PuzzleElement puzzleElement) { + + if (puzzleElement == null) { + return new ArrayList(); + } + ShortTruthTableBoard sttBoard = ((ShortTruthTableBoard) board); ShortTruthTableCell cell = sttBoard.getCellFromElement(puzzleElement); diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/CellForNumberCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/CellForNumberCaseRule.java index 45bdadea3..b48962c41 100644 --- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/CellForNumberCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/CellForNumberCaseRule.java @@ -61,6 +61,9 @@ public CaseBoard getCaseBoard(Board board) { public ArrayList getCasesFor(Board board, PuzzleElement puzzleElement, Integer number) { ArrayList cases = new ArrayList<>(); + if (puzzleElement == null) { + return cases; + } SkyscrapersClue clue = (SkyscrapersClue) puzzleElement; SkyscrapersBoard skyscrapersboard = (SkyscrapersBoard) board; diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/NumberForCellCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/NumberForCellCaseRule.java index 145dd6ee2..4f8e1df6b 100644 --- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/NumberForCellCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/NumberForCellCaseRule.java @@ -47,6 +47,9 @@ public CaseBoard getCaseBoard(Board board) { @Override public ArrayList getCases(Board board, PuzzleElement puzzleElement) { ArrayList cases = new ArrayList<>(); + if (puzzleElement == null) { + return cases; + } SkyscrapersCell cell = (SkyscrapersCell) puzzleElement; SkyscrapersBoard skyscrapersboard = (SkyscrapersBoard) board; 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 df900dcd5..efd86bd7b 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 @@ -84,6 +84,10 @@ public CaseBoard getCaseBoard(Board board) { @Override public ArrayList getCases(Board board, PuzzleElement puzzleElement) { ArrayList cases = new ArrayList<>(); + if (puzzleElement == null) { + return cases; + } + Board case1 = board.copy(); PuzzleElement data1 = case1.getPuzzleElement(puzzleElement); data1.setData(StarBattleCellType.STAR.value); diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellCaseRule.java index fb6da62d4..ccc428486 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellCaseRule.java @@ -67,6 +67,10 @@ public CaseBoard getCaseBoard(Board board) { @Override public ArrayList getCases(Board board, PuzzleElement puzzleElement) { ArrayList cases = new ArrayList<>(); + if (puzzleElement == null) { + return cases; + } + SudokuBoard sudokuBoard = (SudokuBoard) board; SudokuCell cell = (SudokuCell) puzzleElement; diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleNumberCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleNumberCaseRule.java index e6ab0e64c..a516a06fb 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleNumberCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleNumberCaseRule.java @@ -84,6 +84,10 @@ public ArrayList getCases(Board board, PuzzleElement puzzleElement) { public ArrayList getCases( Board board, PuzzleElement puzzleElement, int value, GroupType groupType) { ArrayList cases = new ArrayList<>(); + if (puzzleElement == null) { + return cases; + } + SudokuBoard sudokuBoard = (SudokuBoard) board; List caseCells = new ArrayList<>(); SudokuCell cell = (SudokuCell) puzzleElement; 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 aaa1a8fbc..8fe9b6873 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 @@ -61,7 +61,11 @@ public CaseBoard getCaseBoard(Board board) { */ @Override public ArrayList getCases(Board board, PuzzleElement puzzleElement) { + if (puzzleElement == null) { + return new ArrayList(); + } ArrayList cases; + List group; int tentsLeft; TreeTentClue clue = ((TreeTentClue) puzzleElement); diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/rules/LinkTentCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/treetent/rules/LinkTentCaseRule.java index bd303174a..cbe91c3a7 100644 --- a/src/main/java/edu/rpi/legup/puzzle/treetent/rules/LinkTentCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/treetent/rules/LinkTentCaseRule.java @@ -60,6 +60,10 @@ public CaseBoard getCaseBoard(Board board) { @Override public ArrayList getCases(Board board, PuzzleElement puzzleElement) { ArrayList cases = new ArrayList(); + if (puzzleElement == null) { + return cases; + } + TreeTentCell cell = (TreeTentCell) puzzleElement; List adj = ((TreeTentBoard) board).getAdjacent(cell, TreeTentType.TREE); List lines = ((TreeTentBoard) board).getLines(); diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/rules/LinkTreeCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/treetent/rules/LinkTreeCaseRule.java index 03d039898..153692ad0 100644 --- a/src/main/java/edu/rpi/legup/puzzle/treetent/rules/LinkTreeCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/treetent/rules/LinkTreeCaseRule.java @@ -62,6 +62,10 @@ public CaseBoard getCaseBoard(Board board) { @Override public ArrayList getCases(Board board, PuzzleElement puzzleElement) { ArrayList cases = new ArrayList<>(); + if (puzzleElement == null) { + return cases; + } + TreeTentBoard treeTentBoard = (TreeTentBoard) board; TreeTentCell cell = (TreeTentCell) puzzleElement; List adjCells = treeTentBoard.getAdjacent(cell, TreeTentType.TENT); diff --git a/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java b/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java index eba0daba0..3802e4de7 100644 --- a/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java +++ b/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java @@ -9,9 +9,11 @@ import edu.rpi.legup.model.Puzzle; import edu.rpi.legup.model.PuzzleExporter; import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; 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.binary.BinaryType; import edu.rpi.legup.save.ExportFileException; import edu.rpi.legup.save.InvalidFileFormatException; import edu.rpi.legup.ui.boardview.BoardView; @@ -1088,6 +1090,13 @@ public void onPushChange(ICommand command) { String puzzleName = GameBoardFacade.getInstance().getPuzzleModule().getName(); File puzzleFile = new File(GameBoardFacade.getInstance().getCurFileName()); frame.setTitle(puzzleName + " - " + puzzleFile.getName() + " *"); +// Board curBoard = GameBoardFacade.getInstance().getBoard(); +// List allElements = curBoard.getPuzzleElements(); +// for (PuzzleElement p : allElements) { +// if (p.getData() == BinaryType.UNKNOWN) { +// p.setModifiable(true); +// } +// } } /** Called when the history is cleared */ diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeView.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeView.java index f491009b4..ea622881c 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeView.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeView.java @@ -533,7 +533,6 @@ private void addTreeTransition(TreeTransition trans) { PuzzleElement oldElement = ancestor.getParent().getBoard().getPuzzleElement(element); oldElement.setCasesDepended(oldElement.getCasesDepended() + 1); - oldElement.setModifiable(false); } } } From 88c6f69cf658768d27dec342b0b5a1c006c731bf Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Mon, 8 Jul 2024 10:31:18 -0400 Subject: [PATCH 164/258] Enhanced finish room case rule in nurikabe to inlucde options of rooms bigger than 2 --- .../legup/history/AutoCaseRuleCommand.java | 9 +- .../nurikabe/rules/FinishRoomCaseRule.java | 173 +++++++++++------- 2 files changed, 114 insertions(+), 68 deletions(-) diff --git a/src/main/java/edu/rpi/legup/history/AutoCaseRuleCommand.java b/src/main/java/edu/rpi/legup/history/AutoCaseRuleCommand.java index fd15a7ae2..6eccc80ec 100644 --- a/src/main/java/edu/rpi/legup/history/AutoCaseRuleCommand.java +++ b/src/main/java/edu/rpi/legup/history/AutoCaseRuleCommand.java @@ -56,8 +56,7 @@ public void executeCommand() { TreeNode node = (TreeNode) selection.getFirstSelection().getTreeElement(); if (caseTrans.isEmpty()) { - List cases = - caseRule.getCases(caseBoard.getBaseBoard(), elementView.getPuzzleElement()); + List cases = caseRule.getCases(caseBoard.getBaseBoard(), elementView.getPuzzleElement()); for (Board board : cases) { final TreeTransition transition = (TreeTransition) tree.addTreeElement(node); //board.setModifiable(false); @@ -111,13 +110,11 @@ public String getErrorString() { return "The selected data element is not pickable with this case rule."; } - if (caseRule.getCases(caseBoard.getBaseBoard(), elementView.getPuzzleElement()).size() - == 0) { + if (caseRule.getCases(caseBoard.getBaseBoard(), elementView.getPuzzleElement()).size() == 0) { return "The selection must produce at least one case"; } - int numberOfCaseRules = - caseRule.getCases(caseBoard.getBaseBoard(), elementView.getPuzzleElement()).size(); + int numberOfCaseRules = caseRule.getCases(caseBoard.getBaseBoard(), elementView.getPuzzleElement()).size(); System.out.println("Number of cases:" + numberOfCaseRules); if (numberOfCaseRules > caseRule.MAX_CASES) { return "The selection can produce a max of " + caseRule.MAX_CASES + " cases"; diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/FinishRoomCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/FinishRoomCaseRule.java index e1b7ca18d..0dfbc7686 100644 --- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/FinishRoomCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/FinishRoomCaseRule.java @@ -17,24 +17,24 @@ import java.util.Set; public class FinishRoomCaseRule extends CaseRule { - private int legitCases = - 0; // placeholder for amount of cases originally generated in case user tries to delete - + private int legitCases = 0; // placeholder for amount of cases originally generated in case user tries to delete + private Set uniqueCases; // stores the unique case hashes // cases public FinishRoomCaseRule() { super( "NURI-CASE-0002", "Finish Room", - "Room can be finished in up to five ways", + "Room can be finished in up to nine ways", "edu/rpi/legup/images/nurikabe/cases/FinishRoom.png"); - this.MAX_CASES = 5; + this.MAX_CASES = 9; this.MIN_CASES = 2; + this.uniqueCases = new HashSet<>(); } /** * 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. + * rule. This method is the one that should have overridden in child classes. * * @param transition transition to check * @return null if the child node logically follow from the parent node, otherwise error message @@ -43,11 +43,11 @@ public FinishRoomCaseRule() { public String checkRuleRaw(TreeTransition transition) { NurikabeBoard destBoardState = (NurikabeBoard) transition.getBoard(); List childTransitions = transition.getParents().get(0).getChildren(); - if (childTransitions.size() > 5) { + if (childTransitions.size() > MAX_CASES) { return super.getInvalidUseOfRuleMessage() - + ": This case rule must have 5 or less children."; + + ": This case rule must have 9 or less children."; } - if (childTransitions.size() < 2) { + if (childTransitions.size() < MIN_CASES) { return super.getInvalidUseOfRuleMessage() + ": This case rule must have 2 or more children."; } @@ -97,7 +97,7 @@ public CaseBoard getCaseBoard(Board board) { } } // if size of region is 1 less than the number block and the number block is only number block in the region - if (disRow.size() + 1 == ((NurikabeCell) element).getData() && only) { + if (disRow.size() < ((NurikabeCell) element).getData() && only) { caseBoard.addPickableElement(element); // add that room as a pickable element } } @@ -120,11 +120,13 @@ public ArrayList getCases(Board board, PuzzleElement puzzleElement) { } NurikabeBoard nuriBoard = (NurikabeBoard) board.copy(); // nurikabe board to edit - NurikabeCell numberCell = nuriBoard.getCell(((NurikabeCell) puzzleElement).getLocation().x, - ((NurikabeCell) puzzleElement).getLocation().y); // number cell whose room we want to fill + NurikabeCell numberCell = nuriBoard.getCell( + ((NurikabeCell) puzzleElement).getLocation().x, + ((NurikabeCell) puzzleElement).getLocation().y + ); // number cell whose room we want to fill + Point origPoint = new Point(numberCell.getLocation().x, numberCell.getLocation().y); int filledRoomSize = numberCell.getData(); // size of room we want afterward - Set locations = new HashSet<>(); // locations where white space is added to finish room Point left = new Point(-1, 0); Point right = new Point(1, 0); @@ -138,64 +140,111 @@ public ArrayList getCases(Board board, PuzzleElement puzzleElement) { Set checkedPoints = new HashSet<>(); // add all into checked points and continue at start of loop if inside DisjointSets regions = NurikabeUtilities.getNurikabeRegions(nuriBoard); // gathers regions - Set disRow = regions.getSet(numberCell); // set of white spaces - for (NurikabeCell d : disRow) { // loops through white spaces - if (cases.size() >= 6) { // no need to check this many cases - // throw new IllegalStateException("Too many cases"); - continue; // crash/runtime protection + Set numberCellRegion = regions.getSet(numberCell); // set of white spaces + + for (NurikabeCell d : numberCellRegion) { // loops through white spaces + generateCases(nuriBoard, d, filledRoomSize, directions, checkedPoints, cases, origPoint); + } + + legitCases = cases.size(); + return cases; + } + + /** + * Recursively generates possible cases for filling a room with white cells based on the current + * board state and specified parameters. + * + * @param nuriBoard the current Nurikabe board state + * @param currentCell the current cell being evaluated + * @param filledRoomSize the target size for the room being filled + * @param directions the set of possible directions to expand the room + * @param checkedPoints the set of points already evaluated to avoid redundancy + * @param cases the list of valid board cases generated + * @param origPoint the original point of the number cell initiating the room filling + */ + private void generateCases(NurikabeBoard nuriBoard, NurikabeCell currentCell, int filledRoomSize, + Set directions, Set checkedPoints, ArrayList cases, Point origPoint) { + for (Point direction : directions) { + Point newPoint = new Point( + currentCell.getLocation().x + direction.x, + currentCell.getLocation().y + direction.y + ); + + if (newPoint.x < 0 || newPoint.y < 0 || + newPoint.x >= nuriBoard.getWidth() || newPoint.y >= nuriBoard.getHeight()) { + continue; // out of bounds } - for (Point direction : directions) { - if (cases.size() >= 6) { // no need to check this many cases - // throw new IllegalStateException("Too many cases"); - continue; // crash/runtime protection - } - if (!((nuriBoard.getWidth() > (d.getLocation().x + direction.x) - && (nuriBoard.getHeight() > d.getLocation().y + direction.y) - && (d.getLocation().x + direction.x >= 0) - && (d.getLocation().y + direction.y >= 0)))) { - continue; // if next location check would be outside of grid then continue - } - NurikabeCell curr = nuriBoard.getCell(d.getLocation().x + direction.x, d.getLocation().y + direction.y); - if (checkedPoints.contains(curr.getLocation())) { - continue; // if we already checked whether making this tile white would complete the room then continue - } - checkedPoints.add(curr.getLocation()); // adds location to checkedPoints so we don't check it again and accidentally add - - if (curr.getType() == NurikabeType.UNKNOWN) { // found adjacent space to region that is currently unknown - curr.setData(NurikabeType.WHITE.toValue()); // changes adjacent cell color to white - //nuriBoard.addModifiedData(curr); // adds modified before check - regions = NurikabeUtilities.getNurikabeRegions(nuriBoard); // update regions - Set disCreatedRow = regions.getSet(curr); // gets set of created row with new white cell added - - if (disCreatedRow.size() == filledRoomSize) { // If adding white fills the room to exact size of - // number block and doesn't connect with another room - Point here = curr.getLocation(); // gets current location of new white tile that fills room - boolean alreadyIn = false; // sets whether the tile has already been added to false - for (Point p : locations) { // loops through locations of previously added tiles - if (p == here) { // if point is already in - alreadyIn = true; // change already in to true + + NurikabeCell newCell = nuriBoard.getCell(newPoint.x, newPoint.y); + if (checkedPoints.contains(newPoint)) { + continue; // already checked + } + + if (newCell.getType() == NurikabeType.UNKNOWN) { + newCell.setData(NurikabeType.WHITE.toValue()); // changes adjacent cell color to white + newCell.setModifiable(false); + checkedPoints.add(newPoint); + + DisjointSets regions = NurikabeUtilities.getNurikabeRegions(nuriBoard); // update regions variable + Set newRoomSet = regions.getSet(newCell); // gets set of cells in room with new white cell added + + if (!touchesDifferentRoom(nuriBoard, newCell, filledRoomSize, directions, origPoint)) { + if (newRoomSet.size() == filledRoomSize) { // if adding white fills the room to exact size of + // number block and doesn't connect with another room + Board caseBoard = nuriBoard.copy(); + // check if case for board already exists + boolean unique = true; + for (Board board : cases) { + if (caseBoard.equalsBoard(board)) { + unique = false; break; } } - - if (!alreadyIn) { // if point wasn't already in - Board casey = nuriBoard.copy(); // copy the current board with white tile changed - PuzzleElement datacasey = curr; // gets changed white tile as a puzzle element - datacasey.setData(NurikabeType.WHITE.toValue()); // ensure set to white, probably redundant - casey.addModifiedData(datacasey); // ensure confirmed white change - regions = NurikabeUtilities.getNurikabeRegions(nuriBoard); // update regions - cases.add(casey); // add this case to list of cases - locations.add(here); // add location of new white tile to list of locations so - // that we don't accidentally add it again later + if (unique) { + caseBoard.addModifiedData(newCell); + cases.add(caseBoard); } + } else if (newRoomSet.size() < filledRoomSize) { + generateCases(nuriBoard, newCell, filledRoomSize, directions, checkedPoints, cases, origPoint); } - curr.setData(NurikabeType.UNKNOWN.toValue()); // set cell type back to unknown - regions = NurikabeUtilities.getNurikabeRegions(nuriBoard); // updates regions } + newCell.setData(NurikabeType.UNKNOWN.toValue()); + newCell.setModifiable(true); + checkedPoints.remove(newPoint); } - legitCases = cases.size(); } - return cases; + } + + /** + * Determines if a given cell touches a different room by checking adjacent cells in specified directions. + * + * @param board the current Nurikabe board state + * @param cell the cell being evaluated + * @param origRoomSize the size of the original room being filled + * @param directions the set of possible directions to check around the cell + * @param origPoint the original point of the number cell initiating the room filling + * @return true if the cell touches a different room, false otherwise + */ + private boolean touchesDifferentRoom(NurikabeBoard board, NurikabeCell cell, int origRoomSize, Set directions, Point origPoint) { + for (Point direction : directions) { + Point adjacentPoint = new Point( + cell.getLocation().x + direction.x, + cell.getLocation().y + direction.y + ); + + if (adjacentPoint.x >= 0 && adjacentPoint.y >= 0 && + adjacentPoint.x < board.getWidth() && adjacentPoint.y < board.getHeight()) { // check if out of bounds + NurikabeCell adjacentCell = board.getCell(adjacentPoint.x, adjacentPoint.y); + // check if the adjacent cell is a number cell + if (adjacentCell.getType() == NurikabeType.NUMBER) { + // check if it's different from the original number cell + if (origRoomSize != adjacentCell.getData() || (adjacentPoint.x != origPoint.x || adjacentPoint.y != origPoint.y)) { + return true; + } + } + } + } + return false; } /** From 925ff9c902c7e03b18de57b9ca22454d9e3a9c75 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Tue, 9 Jul 2024 13:43:40 -0400 Subject: [PATCH 165/258] Added undo and redo buttons to puzzle solver tool bar, fixed major redo bugs, fixed unbalanced row/col contra rule for binary --- .../edu/rpi/legup/history/PuzzleCommand.java | 10 +- .../ValidateContradictionRuleCommand.java | 7 +- .../history/ValidateDirectRuleCommand.java | 114 +++++++++++++++++- .../java/edu/rpi/legup/model/tree/Tree.java | 1 + ...nbalancedRowOrColumnContradictionRule.java | 10 +- .../edu/rpi/legup/ui/ProofEditorPanel.java | 52 +++++++- 6 files changed, 174 insertions(+), 20 deletions(-) diff --git a/src/main/java/edu/rpi/legup/history/PuzzleCommand.java b/src/main/java/edu/rpi/legup/history/PuzzleCommand.java index 3768e3cbd..fb57e7af2 100644 --- a/src/main/java/edu/rpi/legup/history/PuzzleCommand.java +++ b/src/main/java/edu/rpi/legup/history/PuzzleCommand.java @@ -52,13 +52,13 @@ public final String getError() { */ public abstract String getErrorString(); - /** Executes an command */ + /** Executes a command */ public abstract void executeCommand(); - /** Undoes an command */ + /** Undoes a command */ public abstract void undoCommand(); - /** Redoes an command */ + /** Redoes a command */ public void redoCommand() { if (state == CommandState.UNDOED) { executeCommand(); @@ -68,7 +68,7 @@ public void redoCommand() { } } - /** Undoes an command */ + /** Undoes a command */ @Override public final void undo() { if (state == CommandState.EXECUTED || state == CommandState.REDOED) { @@ -79,7 +79,7 @@ public final void undo() { } } - /** Redoes an command */ + /** Redoes a command */ public final void redo() { if (state == CommandState.UNDOED) { redoCommand(); diff --git a/src/main/java/edu/rpi/legup/history/ValidateContradictionRuleCommand.java b/src/main/java/edu/rpi/legup/history/ValidateContradictionRuleCommand.java index 8737b4008..6c95202c9 100644 --- a/src/main/java/edu/rpi/legup/history/ValidateContradictionRuleCommand.java +++ b/src/main/java/edu/rpi/legup/history/ValidateContradictionRuleCommand.java @@ -84,7 +84,12 @@ public void executeCommand() { final TreeElement finalTreeElement; if (firstSelectedView.getType() == TreeElementType.NODE) { TreeNodeView nodeView = (TreeNodeView) firstSelectedView; - finalTreeElement = nodeView.getChildrenViews().get(0).getTreeElement(); + if (!nodeView.getChildrenViews().isEmpty()) { + finalTreeElement = nodeView.getChildrenViews().get(0).getTreeElement(); + } + else { + finalTreeElement = null; + } } else { TreeTransitionView transitionView = (TreeTransitionView) firstSelectedView; if (transitionView.getChildView() != null) { diff --git a/src/main/java/edu/rpi/legup/history/ValidateDirectRuleCommand.java b/src/main/java/edu/rpi/legup/history/ValidateDirectRuleCommand.java index d9c063464..a2b6632d2 100644 --- a/src/main/java/edu/rpi/legup/history/ValidateDirectRuleCommand.java +++ b/src/main/java/edu/rpi/legup/history/ValidateDirectRuleCommand.java @@ -6,11 +6,15 @@ import edu.rpi.legup.model.rules.Rule; import edu.rpi.legup.model.tree.*; import edu.rpi.legup.ui.proofeditorui.treeview.*; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + import java.util.HashMap; import java.util.List; import java.util.Map; public class ValidateDirectRuleCommand extends PuzzleCommand { + private static final Logger LOGGER = LogManager.getLogger(History.class.getName()); private TreeViewSelection selection; private Map oldRules; @@ -30,7 +34,60 @@ public ValidateDirectRuleCommand(TreeViewSelection selection, DirectRule rule) { this.addNode = new HashMap<>(); } - /** Executes an command */ +// /** Executes a command */ +// @Override +// public void executeCommand() { +// Tree tree = GameBoardFacade.getInstance().getTree(); +// TreeView treeView = GameBoardFacade.getInstance().getLegupUI().getTreePanel().getTreeView(); +// Puzzle puzzle = GameBoardFacade.getInstance().getPuzzleModule(); +// final TreeViewSelection newSelection = new TreeViewSelection(); +// +// List selectedViews = selection.getSelectedViews(); +// int count = 1; +// for (TreeElementView selectedView : selectedViews) { +// System.out.println(count); +// count++; +// TreeElement element = selectedView.getTreeElement(); +// TreeTransitionView transitionView; +// if (element.getType() == TreeElementType.NODE) { +// TreeNodeView nodeView = (TreeNodeView) selectedView; +// transitionView = nodeView.getChildrenViews().get(0); +// } else { +// transitionView = (TreeTransitionView) selectedView; +// } +// TreeTransition transition = transitionView.getTreeElement(); +// +// oldRules.put(transition, transition.getRule()); +// transition.setRule(newRule); +// +// TreeNode childNode = transition.getChildNode(); +// if (childNode == null) { +// childNode = addNode.get(transition); +// if (childNode == null) { +// childNode = (TreeNode) tree.addTreeElement(transition); +// addNode.put(transition, childNode); +// } else { +// tree.addTreeElement(transition, childNode); +// } +// +// final TreeNode finalNode = childNode; +// puzzle.notifyTreeListeners(listener -> listener.onTreeElementAdded(finalNode)); +// } +// newSelection.addToSelection(treeView.getElementView(childNode)); +// } +// TreeElementView firstSelectedView = selection.getFirstSelection(); +// final TreeElement finalTreeElement; +// if (firstSelectedView.getType() == TreeElementType.NODE) { +// TreeNodeView nodeView = (TreeNodeView) firstSelectedView; +// finalTreeElement = nodeView.getChildrenViews().get(0).getTreeElement(); +// } else { +// TreeTransitionView transitionView = (TreeTransitionView) firstSelectedView; +// finalTreeElement = transitionView.getChildView().getTreeElement(); +// } +// puzzle.notifyBoardListeners(listener -> listener.onTreeElementChanged(finalTreeElement)); +// puzzle.notifyTreeListeners(listener -> listener.onTreeSelectionChanged(newSelection)); +// } + /** Executes a command */ @Override public void executeCommand() { Tree tree = GameBoardFacade.getInstance().getTree(); @@ -42,14 +99,24 @@ public void executeCommand() { for (TreeElementView selectedView : selectedViews) { TreeElement element = selectedView.getTreeElement(); TreeTransitionView transitionView; + if (element.getType() == TreeElementType.NODE) { TreeNodeView nodeView = (TreeNodeView) selectedView; + if (nodeView.getChildrenViews().isEmpty()) { + LOGGER.error("NodeView has no children views"); + continue; + } transitionView = nodeView.getChildrenViews().get(0); } else { transitionView = (TreeTransitionView) selectedView; } - TreeTransition transition = transitionView.getTreeElement(); + if (transitionView == null) { + LOGGER.error("Transition view is null"); + continue; + } + + TreeTransition transition = transitionView.getTreeElement(); oldRules.put(transition, transition.getRule()); transition.setRule(newRule); @@ -66,21 +133,58 @@ public void executeCommand() { final TreeNode finalNode = childNode; puzzle.notifyTreeListeners(listener -> listener.onTreeElementAdded(finalNode)); } - newSelection.addToSelection(treeView.getElementView(childNode)); + + TreeElementView childView = treeView.getElementView(childNode); + if (childView == null) { + LOGGER.error("Child view is null for child node: " + childNode); + continue; + } + newSelection.addToSelection(childView); } + TreeElementView firstSelectedView = selection.getFirstSelection(); + if (firstSelectedView == null) { + LOGGER.error("First selected view is null"); + return; + } + final TreeElement finalTreeElement; if (firstSelectedView.getType() == TreeElementType.NODE) { TreeNodeView nodeView = (TreeNodeView) firstSelectedView; + if (nodeView.getChildrenViews().isEmpty()) { + LOGGER.error("NodeView has no children views"); + return; + } finalTreeElement = nodeView.getChildrenViews().get(0).getTreeElement(); } else { TreeTransitionView transitionView = (TreeTransitionView) firstSelectedView; + TreeNodeView childView = transitionView.getChildView(); + if (childView == null) { + LOGGER.error("Child view is null for transition view: " + transitionView); + TreeNode childNode = transitionView.getTreeElement().getChildNode(); + if (childNode == null) { + LOGGER.error("Child node is null for transition: " + transitionView.getTreeElement()); + return; + } + childView = (TreeNodeView) treeView.getElementView(childNode); + if (childView == null) { + LOGGER.error("Failed to initialize child view for node: " + childNode); + return; + } + transitionView.setChildView(childView); + } + TreeTransition transition = transitionView.getTreeElement(); + if (transition.getParents().get(0).getChildren().isEmpty()) { + transition.getParents().get(0).addChild(transition); + } finalTreeElement = transitionView.getChildView().getTreeElement(); } + puzzle.notifyBoardListeners(listener -> listener.onTreeElementChanged(finalTreeElement)); puzzle.notifyTreeListeners(listener -> listener.onTreeSelectionChanged(newSelection)); } + /** * Gets the reason why the command cannot be executed * @@ -110,7 +214,7 @@ public String getErrorString() { return null; } - /** Undoes an command */ + /** Undoes a command */ @Override public void undoCommand() { Tree tree = GameBoardFacade.getInstance().getTree(); @@ -124,8 +228,10 @@ public void undoCommand() { transitionView = nodeView.getChildrenViews().get(0); } else { transitionView = (TreeTransitionView) selectedView; + } TreeTransition transition = transitionView.getTreeElement(); + transition.setRule(oldRules.get(transition)); if (addNode.get(transition) != null) { diff --git a/src/main/java/edu/rpi/legup/model/tree/Tree.java b/src/main/java/edu/rpi/legup/model/tree/Tree.java index 08e594801..3cdab80c2 100644 --- a/src/main/java/edu/rpi/legup/model/tree/Tree.java +++ b/src/main/java/edu/rpi/legup/model/tree/Tree.java @@ -88,6 +88,7 @@ public void removeTreeElement(TreeElement element) { } node.getParent().setChildNode(null); + System.out.println("Deleted node: " + node); } else { TreeTransition transition = (TreeTransition) element; diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowOrColumnContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowOrColumnContradictionRule.java index 3688c4866..ea110ef2c 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowOrColumnContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowOrColumnContradictionRule.java @@ -44,8 +44,8 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { } } - if (rowNumZeros == size / 2 && rowNumOnes == size / 2) { - return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE; + if (rowNumZeros > size / 2 || rowNumOnes > size / 2) { + return null; } Set col = binaryBoard.getColCells(cell.getLocation().x); @@ -62,10 +62,10 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { } } - if (colNumZeros == size / 2 && colNumOnes == size / 2) { - return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE; + if (colNumZeros > size / 2 || colNumOnes > size / 2) { + return null; } - return null; + return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE; } } diff --git a/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java b/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java index 3802e4de7..f78281c89 100644 --- a/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java +++ b/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java @@ -19,6 +19,7 @@ import edu.rpi.legup.ui.boardview.BoardView; import edu.rpi.legup.ui.proofeditorui.rulesview.RuleFrame; import edu.rpi.legup.ui.proofeditorui.treeview.TreePanel; +import edu.rpi.legup.ui.proofeditorui.treeview.TreeTransitionView; import edu.rpi.legup.ui.proofeditorui.treeview.TreeViewSelection; import edu.rpi.legup.user.Submission; import java.awt.*; @@ -781,13 +782,12 @@ private void setupToolBar2() { toolBar2 = new JToolBar(); toolBar2.setFloatable(false); toolBar2.setRollover(true); - setToolBar2Buttons(new JButton[2]); + setToolBar2Buttons(new JButton[4]); URL directions_url = ClassLoader.getSystemClassLoader() .getResource("edu/rpi/legup/images/Legup/Directions.png"); - // Scale the image icons down to make the buttons smaller ImageIcon DirectionsImageIcon = new ImageIcon(directions_url); Image DirectionsImage = DirectionsImageIcon.getImage(); DirectionsImageIcon = @@ -804,11 +804,52 @@ private void setupToolBar2() { getToolBar2Buttons()[0] = directions; toolBar2.add(getToolBar2Buttons()[0]); + URL undo_url = + ClassLoader.getSystemClassLoader() + .getResource("edu/rpi/legup/images/Legup/Undo.png"); + + ImageIcon UndoImageIcon = new ImageIcon(undo_url); + Image UndoImage = UndoImageIcon.getImage(); + UndoImageIcon = + new ImageIcon( + UndoImage.getScaledInstance( + this.TOOLBAR_ICON_SCALE, + this.TOOLBAR_ICON_SCALE, + Image.SCALE_SMOOTH)); + + JButton undo = new JButton("Undo", UndoImageIcon); + undo.setFocusPainted(false); + undo.addActionListener((ActionEvent) -> GameBoardFacade.getInstance().getHistory().undo()); + + getToolBar2Buttons()[1] = undo; + toolBar2.add(getToolBar2Buttons()[1]); + + URL redo_url = + ClassLoader.getSystemClassLoader() + .getResource("edu/rpi/legup/images/Legup/Redo.png"); + + ImageIcon RedoImageIcon = new ImageIcon(redo_url); + Image RedoImage = RedoImageIcon.getImage(); + RedoImageIcon = + new ImageIcon( + RedoImage.getScaledInstance( + this.TOOLBAR_ICON_SCALE, + this.TOOLBAR_ICON_SCALE, + Image.SCALE_SMOOTH)); + + JButton redo = new JButton("Redo", RedoImageIcon); + redo.setFocusPainted(false); + redo.addActionListener((ActionEvent) -> { + GameBoardFacade.getInstance().getHistory().redo(); + }); + + getToolBar2Buttons()[2] = redo; + toolBar2.add(getToolBar2Buttons()[2]); + URL check_url = ClassLoader.getSystemClassLoader() .getResource("edu/rpi/legup/images/Legup/Check.png"); - // Scale the image icons down to make the buttons smaller ImageIcon CheckImageIcon = new ImageIcon(check_url); Image CheckImage = CheckImageIcon.getImage(); CheckImageIcon = @@ -822,8 +863,9 @@ private void setupToolBar2() { check.setFocusPainted(false); check.addActionListener((ActionEvent) -> checkProof()); - getToolBar2Buttons()[1] = check; - toolBar2.add(getToolBar2Buttons()[1]); + getToolBar2Buttons()[3] = check; + toolBar2.add(getToolBar2Buttons()[3]); + this.add(toolBar2, BorderLayout.NORTH); } From d69e6341d52dad596524c1b95ab2c34aabbd5903 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Tue, 9 Jul 2024 13:45:27 -0400 Subject: [PATCH 166/258] Removed unnecessary logger error info --- .../history/ValidateDirectRuleCommand.java | 21 ------------------- 1 file changed, 21 deletions(-) diff --git a/src/main/java/edu/rpi/legup/history/ValidateDirectRuleCommand.java b/src/main/java/edu/rpi/legup/history/ValidateDirectRuleCommand.java index a2b6632d2..c5a36ddb3 100644 --- a/src/main/java/edu/rpi/legup/history/ValidateDirectRuleCommand.java +++ b/src/main/java/edu/rpi/legup/history/ValidateDirectRuleCommand.java @@ -102,20 +102,11 @@ public void executeCommand() { if (element.getType() == TreeElementType.NODE) { TreeNodeView nodeView = (TreeNodeView) selectedView; - if (nodeView.getChildrenViews().isEmpty()) { - LOGGER.error("NodeView has no children views"); - continue; - } transitionView = nodeView.getChildrenViews().get(0); } else { transitionView = (TreeTransitionView) selectedView; } - if (transitionView == null) { - LOGGER.error("Transition view is null"); - continue; - } - TreeTransition transition = transitionView.getTreeElement(); oldRules.put(transition, transition.getRule()); transition.setRule(newRule); @@ -143,10 +134,6 @@ public void executeCommand() { } TreeElementView firstSelectedView = selection.getFirstSelection(); - if (firstSelectedView == null) { - LOGGER.error("First selected view is null"); - return; - } final TreeElement finalTreeElement; if (firstSelectedView.getType() == TreeElementType.NODE) { @@ -162,15 +149,7 @@ public void executeCommand() { if (childView == null) { LOGGER.error("Child view is null for transition view: " + transitionView); TreeNode childNode = transitionView.getTreeElement().getChildNode(); - if (childNode == null) { - LOGGER.error("Child node is null for transition: " + transitionView.getTreeElement()); - return; - } childView = (TreeNodeView) treeView.getElementView(childNode); - if (childView == null) { - LOGGER.error("Failed to initialize child view for node: " + childNode); - return; - } transitionView.setChildView(childView); } TreeTransition transition = transitionView.getTreeElement(); From b5c10beeafc560fd7c44b7a23afbb0bc264e7e2f Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Tue, 9 Jul 2024 13:47:18 -0400 Subject: [PATCH 167/258] Fixed checkStyle error in Board --- src/main/java/edu/rpi/legup/model/gameboard/Board.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/edu/rpi/legup/model/gameboard/Board.java b/src/main/java/edu/rpi/legup/model/gameboard/Board.java index b6d3ed995..5ad6fcf60 100644 --- a/src/main/java/edu/rpi/legup/model/gameboard/Board.java +++ b/src/main/java/edu/rpi/legup/model/gameboard/Board.java @@ -37,8 +37,9 @@ public Board(int size) { * @return equivalent puzzleElement on this board */ public PuzzleElement getPuzzleElement(PuzzleElement puzzleElement) { - if (puzzleElement == null) + if (puzzleElement == null) { return null; + } int index = puzzleElement.getIndex(); return index < puzzleElements.size() ? puzzleElements.get(index) : null; } From 5f73f44d3f3e6b6d33435fae2b1efc5bd24f8b94 Mon Sep 17 00:00:00 2001 From: summerhenson Date: Tue, 9 Jul 2024 14:16:32 -0400 Subject: [PATCH 168/258] Fix bug with iterating through and modifying collections in Star Battle direct rules --- .../rules/ColumnsWithinRegionsDirectRule.java | 19 ++++++++---- .../rules/ColumnsWithinRowsDirectRule.java | 19 ++++++++---- .../rules/RowsWithinRegionsDirectRule.java | 19 ++++++++---- .../ColumnsWithinRegionsDirectRuleTest.java | 30 ++++++++++++++++++- .../{OneColumnOneSquare => OneColumnOneCell} | 0 ...alColumnOneSquare => PartialColumnOneCell} | 0 6 files changed, 68 insertions(+), 19 deletions(-) rename src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/{OneColumnOneSquare => OneColumnOneCell} (100%) rename src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/{OnePartialColumnOneSquare => PartialColumnOneCell} (100%) 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 433567460..428bbefcf 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 @@ -8,7 +8,10 @@ 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.HashSet; +import java.util.List; import java.util.Set; public class ColumnsWithinRegionsDirectRule extends DirectRule { @@ -43,15 +46,16 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem // the regions that contain them Set regions = new HashSet(); // columns and regions to process - Set columnsToCheck = new HashSet(); - Set regionsToCheck = new HashSet(); + List columnsToCheck = new ArrayList(); + List regionsToCheck = new ArrayList(); int columnStars = 0; int regionStars = 0; regions.add(cell.getGroupIndex()); regionsToCheck.add(cell.getGroupIndex()); while (!columnsToCheck.isEmpty() || !regionsToCheck.isEmpty()) { - for (int r : regionsToCheck) { + for (int i = 0; i < regionsToCheck.size(); ++i) { + int r = regionsToCheck.get(i); regionStars += board.getRegion(r).numStars(); for (PuzzleElement c : board.getRegion(r).getCells()) { int column = ((StarBattleCell) c).getLocation().x; @@ -59,9 +63,11 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem columnsToCheck.add(column); } } - regionsToCheck.remove(r); + regionsToCheck.remove(i); + --i; } - for (int c : columnsToCheck) { + for (int j = 0; j < columnsToCheck.size(); ++j) { + int c = columnsToCheck.get(j); columnStars += board.columnStars(c); for (int i = 0; i < board.getSize(); ++i) { int region = board.getCell(c, i).getGroupIndex(); @@ -69,7 +75,8 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem regionsToCheck.add(region); } } - columnsToCheck.remove(c); + columnsToCheck.remove(j); + --j; } } // are the columns and regions missing an equal amount of stars 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 5d108a0cd..61e6a3988 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,7 +8,10 @@ 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.HashSet; +import java.util.List; import java.util.Set; public class ColumnsWithinRowsDirectRule extends DirectRule { @@ -46,8 +49,8 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem // the rows that contain them Set rows = new HashSet(); // columns and rows to process - Set columnsToCheck = new HashSet(); - Set rowsToCheck = new HashSet(); + List columnsToCheck = new ArrayList(); + List rowsToCheck = new ArrayList(); int columnStars = 0; int rowStars = 0; int firstRow = cell.getLocation().y; @@ -55,7 +58,8 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem rowsToCheck.add(firstRow); while (!columnsToCheck.isEmpty() || !rowsToCheck.isEmpty()) { - for (int r : rowsToCheck) { + for (int i = 0; i < rowsToCheck.size(); ++i) { + int r = rowsToCheck.get(i); rowStars += board.rowStars(r); for (PuzzleElement c : board.getRow(r)) { int column = ((StarBattleCell) c).getLocation().x; @@ -63,9 +67,11 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem columnsToCheck.add(column); } } - rowsToCheck.remove(r); + rowsToCheck.remove(i); + --i; } - for (int c : columnsToCheck) { + for (int i = 0; i < columnsToCheck.size(); ++i) { + int c = columnsToCheck.get(i); columnStars += board.columnStars(c); for (PuzzleElement r : board.getCol(c)) { int row = ((StarBattleCell) r).getLocation().y; @@ -73,7 +79,8 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem rowsToCheck.add(row); } } - columnsToCheck.remove(c); + columnsToCheck.remove(i); + --i; } } // are the columns and regions missing an equal amount of stars 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 78f8f00e7..79948a5c6 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,7 +8,10 @@ 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.HashSet; +import java.util.List; import java.util.Set; public class RowsWithinRegionsDirectRule extends DirectRule { @@ -44,15 +47,16 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem // the regions that contain them Set regions = new HashSet(); // rows and regions to process - Set rowsToCheck = new HashSet(); - Set regionsToCheck = new HashSet(); + List rowsToCheck = new ArrayList(); + List regionsToCheck = new ArrayList(); int rowStars = 0; int regionStars = 0; regions.add(cell.getGroupIndex()); regionsToCheck.add(cell.getGroupIndex()); while (!rowsToCheck.isEmpty() || !regionsToCheck.isEmpty()) { - for (int r : regionsToCheck) { + for (int i = 0; i < regionsToCheck.size(); ++i) { + int r = regionsToCheck.get(i); regionStars += board.getRegion(r).numStars(); for (PuzzleElement ro : board.getRegion(r).getCells()) { int row = ((StarBattleCell) ro).getLocation().y; @@ -60,9 +64,11 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem rowsToCheck.add(row); } } - regionsToCheck.remove(r); + regionsToCheck.remove(i); + --i; } - for (int r : rowsToCheck) { + for (int j = 0; j < rowsToCheck.size(); ++j) { + int r = rowsToCheck.get(j); rowStars += board.rowStars(r); for (int i = 0; i < board.getSize(); ++i) { int region = board.getCell(i, r).getGroupIndex(); @@ -70,7 +76,8 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem regionsToCheck.add(region); } } - rowsToCheck.remove(r); + rowsToCheck.remove(j); + --j; } } // are the columns and regions missing an equal amount of stars diff --git a/src/test/java/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRuleTest.java b/src/test/java/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRuleTest.java index 790f993b9..a5d521e67 100644 --- a/src/test/java/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRuleTest.java +++ b/src/test/java/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRuleTest.java @@ -8,13 +8,14 @@ import edu.rpi.legup.puzzle.starbattle.StarBattleCellType; import edu.rpi.legup.puzzle.starbattle.rules.ColumnsWithinRegionsDirectRule; 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; +import java.awt.*; + public class ColumnsWithinRegionsDirectRuleTest { private static final ColumnsWithinRegionsDirectRule RULE = new ColumnsWithinRegionsDirectRule(); @@ -27,6 +28,33 @@ public static void setUp() { } //single column w/in single region one square outside + @Test + public void ColumnsWithinRegionsDirectRule_OneColumnOneCell() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/OneColumnOneCell", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell = board.getCell(1,0); + cell.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell); + + Assert.assertNull(RULE.checkRule(transition)); + + Point location = new Point(1, 0); + 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(location)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } } diff --git a/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/OneColumnOneSquare b/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/OneColumnOneCell similarity index 100% rename from src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/OneColumnOneSquare rename to src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/OneColumnOneCell diff --git a/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/OnePartialColumnOneSquare b/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/PartialColumnOneCell similarity index 100% rename from src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/OnePartialColumnOneSquare rename to src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/PartialColumnOneCell From b527b9a999295c13f100f241b28fd0bb400f49a7 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Tue, 9 Jul 2024 14:59:39 -0400 Subject: [PATCH 169/258] Added row functionality for eliminate the impossible --- .../EliminateTheImpossibleDirectRule.java | 36 ++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java index 724edf113..cb4aab59a 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java @@ -136,11 +136,12 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem System.out.println("Number of possible binary combinations: " + rowCopies.size()); + ArrayList> nonContraRows = new ArrayList<>(); int rowIdx = 0; for(ArrayList curRow : rowCopies){ int charIdx = 0; System.out.println(rowResult.get(rowIdx)); - for(int i = 0; i < curRow.size(); i++ ) { + for(int i = 0; i < curRow.size(); i++) { if (curRow.get(i).getData() == 2) { if (rowResult.get(rowIdx).charAt(charIdx) == '0') { curRow.get(i).setData(0); @@ -152,10 +153,43 @@ else if (rowResult.get(rowIdx).charAt(charIdx) == '1') { } System.out.print(curRow.get(i).getData() + " "); } + + boolean threeAdjacent = false; + int count = 1; + for(int i = 1; i < curRow.size(); i++) { + if (curRow.get(i).getData() == curRow.get(i-1).getData()) { + count++; + if (count == 3) { + threeAdjacent = true; + break; + } + } else { + count = 1; + } + } + + if (!threeAdjacent) { + nonContraRows.add(curRow); + } + rowIdx++; System.out.println(); } + System.out.println("Number of non contradiction rows: " + nonContraRows.size()); + int colNum = binaryCell.getLocation().x; + boolean invalid = false; + for(int i = 0; i < nonContraRows.size(); i++) { + if (nonContraRows.get(i).get(colNum).getData() != binaryCell.getData()) { + invalid = true; + break; + } + } + + if (!invalid) { + return null; + } + return "Grouping of Three Ones or Zeros not found"; } From 34b166a89e7e0aca777988f9ec84de7e41eed549 Mon Sep 17 00:00:00 2001 From: summerhenson Date: Tue, 9 Jul 2024 15:15:07 -0400 Subject: [PATCH 170/258] Started Columns Within Regions direct rule test suite --- .../rules/ColumnsWithinRegionsDirectRule.java | 10 +- .../ColumnsWithinRegionsDirectRuleTest.java | 124 +++++++++++++++++- ...ColumnTwoSquares => PartialColumnTwoCells} | 0 3 files changed, 131 insertions(+), 3 deletions(-) rename src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/{OnePartialColumnTwoSquares => PartialColumnTwoCells} (100%) 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 428bbefcf..ba6ef9629 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 @@ -38,6 +38,7 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem // are now mutually encompassing StarBattleBoard board = (StarBattleBoard) transition.getBoard(); StarBattleCell cell = (StarBattleCell) board.getPuzzleElement(puzzleElement); + System.out.println(cell.getLocation().x + "," + cell.getLocation().y); if (cell.getType() != StarBattleCellType.BLACK) { return "Only black cells are allowed for this rule!"; } @@ -59,7 +60,7 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem regionStars += board.getRegion(r).numStars(); for (PuzzleElement c : board.getRegion(r).getCells()) { int column = ((StarBattleCell) c).getLocation().x; - if (columns.add(column)) { + if (((StarBattleCell) c).getType() != StarBattleCellType.BLACK && columns.add(column)) { columnsToCheck.add(column); } } @@ -71,7 +72,7 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem columnStars += board.columnStars(c); for (int i = 0; i < board.getSize(); ++i) { int region = board.getCell(c, i).getGroupIndex(); - if (regions.add(region)) { + if (board.getCell(c,i).getType() != StarBattleCellType.BLACK && regions.add(region)) { regionsToCheck.add(region); } } @@ -84,6 +85,11 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem != 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!"; } + for (int c: columns) { + if (c == cell.getLocation().x) { + return "Only black out cells outside the column(s)!"; + } + } return null; } diff --git a/src/test/java/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRuleTest.java b/src/test/java/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRuleTest.java index a5d521e67..49e1d1f40 100644 --- a/src/test/java/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRuleTest.java +++ b/src/test/java/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRuleTest.java @@ -27,7 +27,6 @@ public static void setUp() { starbattle = new StarBattle(); } - //single column w/in single region one square outside @Test public void ColumnsWithinRegionsDirectRule_OneColumnOneCell() throws InvalidFileFormatException { @@ -56,5 +55,128 @@ public void ColumnsWithinRegionsDirectRule_OneColumnOneCell() } } + @Test + public void ColumnsWithinRegionsDirectRule_PartialColumnOneCell() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/PartialColumnOneCell", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell = board.getCell(1,2); + cell.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell); + + Assert.assertNull(RULE.checkRule(transition)); + + Point location = new Point(1, 2); + 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(location)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void ColumnsWithinRegionsDirectRule_PartialColumnTwoCells() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/PartialColumnTwoCells", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(0,1); + cell1.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell1); + StarBattleCell cell2 = board.getCell(2,1); + cell2.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell2); + + Assert.assertNull(RULE.checkRule(transition)); + + Point location1 = new Point(0, 1); + Point location2 = new Point(2,1); + 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(location1) || point.equals(location2)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void ColumnsWithinRegionsDirectRule_TwoColumns() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/TwoColumns", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(2,1); + cell1.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell1); + StarBattleCell cell2 = board.getCell(2,2); + cell2.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell2); + + Assert.assertNull(RULE.checkRule(transition)); + + Point location1 = new Point(2, 1); + Point location2 = new Point(2,2); + 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(location1) || point.equals(location2)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void ColumnsWithinRegionsDirectRule_FalseColumnsWithinRegions1() + throws InvalidFileFormatException { + System.out.println("Starting false CWR:"); + TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/OneColumnOneCell", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(1,0); + cell1.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell1); + StarBattleCell cell2 = board.getCell(0,0); + cell2.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell2); + + Assert.assertNotNull(RULE.checkRule(transition)); + + Point location = new Point(1, 0); + 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(location)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } } diff --git a/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/OnePartialColumnTwoSquares b/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/PartialColumnTwoCells similarity index 100% rename from src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/OnePartialColumnTwoSquares rename to src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/PartialColumnTwoCells From c2687b78cabb06b805543b9e4d43ce1a1b46c1bd Mon Sep 17 00:00:00 2001 From: summerhenson Date: Fri, 12 Jul 2024 14:37:22 -0400 Subject: [PATCH 171/258] Fixed bug with XWithinY direct rules --- .../rules/ColumnsWithinRegionsDirectRule.java | 6 +++- .../rules/ColumnsWithinRowsDirectRule.java | 3 ++ .../rules/RowsWithinRegionsDirectRule.java | 3 ++ .../ColumnsWithinRegionsDirectRuleTest.java | 31 +++++++++++++++++++ 4 files changed, 42 insertions(+), 1 deletion(-) 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 ba6ef9629..43e9a1df9 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 @@ -38,7 +38,6 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem // are now mutually encompassing StarBattleBoard board = (StarBattleBoard) transition.getBoard(); StarBattleCell cell = (StarBattleCell) board.getPuzzleElement(puzzleElement); - System.out.println(cell.getLocation().x + "," + cell.getLocation().y); if (cell.getType() != StarBattleCellType.BLACK) { return "Only black cells are allowed for this rule!"; } @@ -85,11 +84,16 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem != 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!"; } + if (columns.contains(cell.getLocation().x)) { + return "Only black out cells outside the column(s)!"; + } + /* for (int c: columns) { if (c == cell.getLocation().x) { return "Only black out cells outside the column(s)!"; } } + */ return null; } 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 61e6a3988..01853a2d1 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 @@ -88,6 +88,9 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem != 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!"; } + if (columns.contains(cell.getLocation().x)) { + return "Only black out cells outside the column(s)!"; + } return null; } 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 79948a5c6..33948deff 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 @@ -85,6 +85,9 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem != 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!"; } + if (rows.contains(cell.getLocation().y)) { + return "Only black out cells outside the row(s)!"; + } return null; } diff --git a/src/test/java/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRuleTest.java b/src/test/java/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRuleTest.java index 49e1d1f40..69ad49b14 100644 --- a/src/test/java/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRuleTest.java +++ b/src/test/java/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRuleTest.java @@ -179,4 +179,35 @@ public void ColumnsWithinRegionsDirectRule_FalseColumnsWithinRegions1() } } + @Test + public void ColumnsWithinRegionsDirectRule_FalseColumnsWithinRegions2() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/OneColumnOneCell", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(1,0); + cell1.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell1); + StarBattleCell cell2 = board.getCell(1,1); + cell2.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell2); + + Assert.assertNotNull(RULE.checkRule(transition)); + + Point location = new Point(1, 0); + 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(location)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + } From d37284cac41b3634efb2d2e832e8137baafb0fba Mon Sep 17 00:00:00 2001 From: summerhenson Date: Fri, 12 Jul 2024 14:43:01 -0400 Subject: [PATCH 172/258] Fixed return strings for some X Within Y direct rules --- .../starbattle/rules/RegionsWithinColumnsDirectRule.java | 6 +++++- .../starbattle/rules/RegionsWithinRowsDirectRule.java | 6 +++++- .../starbattle/rules/RowsWithinColumnsDirectRule.java | 8 ++++++-- 3 files changed, 16 insertions(+), 4 deletions(-) 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 7022a06ac..25177c816 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 @@ -27,7 +27,11 @@ public RegionsWithinColumnsDirectRule() { @Override public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { ColumnsWithinRegionsDirectRule correspondingRule = new ColumnsWithinRegionsDirectRule(); - return correspondingRule.checkRuleRawAt(transition, puzzleElement); + String result = correspondingRule.checkRuleRawAt(transition, puzzleElement); + if (result.equals("Only black out cells outside the column(s)!")) { + return "Only black out cells outside the region(s)!"; + } + return result; } /** 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 7ab50d42b..2635c40cf 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 @@ -28,7 +28,11 @@ public RegionsWithinRowsDirectRule() { public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { RowsWithinRegionsDirectRule correspondingRule = new RowsWithinRegionsDirectRule(); - return correspondingRule.checkRuleRawAt(transition, puzzleElement); + String result = correspondingRule.checkRuleRawAt(transition, puzzleElement); + if (result.equals("Only black out cells outside the row(s)!")) { + return "Only black out cells outside the region(s)!"; + } + return result; } /** 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 2df20e464..3f56f33a1 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 @@ -11,7 +11,7 @@ public class RowsWithinColumnsDirectRule extends DirectRule { public RowsWithinColumnsDirectRule() { super( "STBL-BASC-0007", - "Rows Withing Columns", + "Rows Within 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"); } @@ -29,7 +29,11 @@ public RowsWithinColumnsDirectRule() { public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { ColumnsWithinRowsDirectRule correspondingRule = new ColumnsWithinRowsDirectRule(); - return correspondingRule.checkRuleRawAt(transition, puzzleElement); + String result = correspondingRule.checkRuleRawAt(transition, puzzleElement); + if (result.equals("Only black out cells outside the column(s)!")) { + return "Only black out cells outside the row(s)!"; + } + return result; } /** From 453fe305816e7ec0a4e738a4207da528329d7f3a Mon Sep 17 00:00:00 2001 From: offline171 <146153141+offline171@users.noreply.github.com> Date: Fri, 12 Jul 2024 14:50:00 -0400 Subject: [PATCH 173/258] Added Image for PushoutAdjacentDirectRule Icon for new rule added --- .../rules/PushoutAdjacentDirectRule.png | Bin 0 -> 1822 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/main/resources/edu/rpi/legup/images/starbattle/rules/PushoutAdjacentDirectRule.png diff --git a/src/main/resources/edu/rpi/legup/images/starbattle/rules/PushoutAdjacentDirectRule.png b/src/main/resources/edu/rpi/legup/images/starbattle/rules/PushoutAdjacentDirectRule.png new file mode 100644 index 0000000000000000000000000000000000000000..db3c0d9d56b4d727026e600e2f9df3db6e251c5c GIT binary patch literal 1822 zcmY+_cQhN0767C+ zYuBijNF6bQQhSyDyx;Hjo%8;<_nz;+_jB&K32;+=PPQv-004l~&_EY)F;V|17W#|+ zD~6uoVhH1)HaH7EcU*{T02-i;@^eFr8Tz_n&XCmxS{(pjdT*$!Z5cYV@o#${ zeyGp~Ot5>%X!Xieps9W0Ga!@QW-M?_C@tmy0szSwBz2r%BW|^=W~QpM@QQLv*6Z?? zxo~>2j2A!c#Lvo1k>(NUkP_%jAbBvU0b}n`eBBE}&W&(3Rl=;yYhj{xheMQ(J0b{V zGMNVwo0c$5zh)9Y(AlesnC#0IkGj}>I%80MPx z3y@_1u@VPk0qtq{1r0^3Hf}TqNFZG$&7XTmh1Kkb9Y*cUr*I(>Vg+w|Pb?4X+uO$x z%#~lHis)FC+@oz>(MvKGhZ1?^4l6b5=~CENwG~1oGKCfRp#yZQZ4V!zoJ82`Ji1SMcz^yzMlrcYbRh8jLY?Hha(q%9&HXR7FRgE%zKZ}WA)hF2suzrZmojX6)t69;{ z9tBRvi33-IgMzGv3#6iyt81(Ib=-@O>>dWIINYfJwmPO&1Nok)NfF#RmMB!5uH&NsLt|E%&rJLvXmKC9T;lr@EM>u9Z6ATqE(d^VyP5sR}=A#041I zPho{@QD_gC!{>+<9H&G%av*FX!he5FvD{1zq>qLA#M9!^JdroG5DL8kZMH-11OxD| zxk|C&aoQU<9(k99%Hm6m%|9-2{o~~FH{suELcc*{7@2+}y8J;`6^%hAhqEz?H@l3l z2u<`jt+wK+Yf78iHUWBJ5ep*u{iq%o30~Wot4|A;LT^b<`;rNJ?P(<8K~zIeA8D~A zb8N4@crojmFV+Xw2SiteS&7*!#~mg*j-r{R_bsk08U*umBEZ%$2(3CNn)Cb?!?8#w(*2n`K~Nzyc=rV$heMg>3;5 zaHE7*VxUhs>Q{H-9(#!;KD)I7jTDTJ-&!m^lE<`3(+V0L3gcO}GdnxQjfjG04Lw%y zd?F|-o~t8}M_d(z(fwQy43?>u3Gibu-=F-pPMM=*G-jyEXIWPp!zeGi|8)w=E)^CA zmVqqmY_3MH#>yWh5-m_N717!7g(Nd!aHurnKlk_lT;Sgq_+Q!m=s#Hz2pj)zR(Fpr zzY<4~k3*^3zlf>j`~n!Fn`h5}v4=$$crz8Dp(`3}S|yT$Oq=B5Q+ATBqfCnGVm()=;Z@H@&HYIX9um+k+Xi>wP!* zvRI8SS1mIzJB+$Lb<{B6<8qoVe|;x}i|eOumiHtH^h6l)vAy-=Y){m=@eT3y09tV2 zE&jQ(vYKOxX^}e3^sU!${>$oWk#^Mv|MjW(mKHe}%&ARv7j8UQ)E*wPHDi@w^vE2# zYZMuIy1kHsNlvwODtvUuI-6#0!h_#j4ln Date: Fri, 12 Jul 2024 15:04:33 -0400 Subject: [PATCH 174/258] Name change Simple name change --- ...ntDirectRule.png => EmptyAdjacentDirectRule.png} | Bin 1 file changed, 0 insertions(+), 0 deletions(-) rename src/main/resources/edu/rpi/legup/images/starbattle/rules/{PushoutAdjacentDirectRule.png => EmptyAdjacentDirectRule.png} (100%) diff --git a/src/main/resources/edu/rpi/legup/images/starbattle/rules/PushoutAdjacentDirectRule.png b/src/main/resources/edu/rpi/legup/images/starbattle/rules/EmptyAdjacentDirectRule.png similarity index 100% rename from src/main/resources/edu/rpi/legup/images/starbattle/rules/PushoutAdjacentDirectRule.png rename to src/main/resources/edu/rpi/legup/images/starbattle/rules/EmptyAdjacentDirectRule.png From 45b594e89ad7316d969b27a60e12accd57118f44 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Sun, 14 Jul 2024 10:13:28 -0400 Subject: [PATCH 175/258] Lock transition states before a future case rule, flash background red when an error occurs --- .../edu/rpi/legup/history/CommandError.java | 1 + .../rpi/legup/history/EditDataCommand.java | 37 ++++++++++---- .../java/edu/rpi/legup/history/History.java | 2 + .../edu/rpi/legup/history/MergeCommand.java | 2 +- .../legup/model/gameboard/PuzzleElement.java | 20 ++++++++ .../java/edu/rpi/legup/model/tree/Tree.java | 7 +++ .../edu/rpi/legup/ui/ProofEditorPanel.java | 2 - .../ui/proofeditorui/treeview/TreeView.java | 50 ++++++++++++++++--- 8 files changed, 99 insertions(+), 22 deletions(-) diff --git a/src/main/java/edu/rpi/legup/history/CommandError.java b/src/main/java/edu/rpi/legup/history/CommandError.java index 35b7bb15b..093143704 100644 --- a/src/main/java/edu/rpi/legup/history/CommandError.java +++ b/src/main/java/edu/rpi/legup/history/CommandError.java @@ -5,6 +5,7 @@ public enum CommandError { ONE_SELECTED_VIEW("The selection must have exactly one tree element."), UNMODIFIABLE_BOARD("The selection contains a board which is not modifiable."), UNMODIFIABLE_DATA("The selection contains a board where the data element is not modifiable."), + UNMODIFIABLE_DATA_CASE_RULE("The proof tree contains a future case rule, causing previous transitions to become unmodifiable."), CONTAINS_ROOT("The selection contains the root tree node."), ONE_CHILD("The selection contains a tree node that does not have exactly one child."), ADD_WITH_CHILD("The selection contains a tree transition that already has a child tree node."), diff --git a/src/main/java/edu/rpi/legup/history/EditDataCommand.java b/src/main/java/edu/rpi/legup/history/EditDataCommand.java index d65f03d66..511cd803f 100644 --- a/src/main/java/edu/rpi/legup/history/EditDataCommand.java +++ b/src/main/java/edu/rpi/legup/history/EditDataCommand.java @@ -9,7 +9,11 @@ import edu.rpi.legup.model.tree.*; import edu.rpi.legup.ui.boardview.BoardView; import edu.rpi.legup.ui.boardview.ElementView; +import edu.rpi.legup.ui.lookandfeel.materialdesign.MaterialColors; import edu.rpi.legup.ui.proofeditorui.treeview.*; + +import javax.swing.*; +import java.awt.*; import java.awt.event.MouseEvent; import java.util.List; @@ -26,7 +30,7 @@ public class EditDataCommand extends PuzzleCommand { * EditDataCommand Constructor create a puzzle command for editing a board * * @param elementView currently selected puzzle puzzleElement view that is being edited - * @param selection currently selected tree puzzleElement views that is being edited + * @param selection currently selected tree puzzleElement views that are being edited * @param event mouse event */ public EditDataCommand(ElementView elementView, TreeViewSelection selection, MouseEvent event) { @@ -54,16 +58,13 @@ public void executeCommand() { if (treeElement.getType() == TreeElementType.NODE) { TreeNode treeNode = (TreeNode) treeElement; - if (treeNode.getChildren().isEmpty()) { if (transition == null) { transition = tree.addNewTransition(treeNode); } puzzle.notifyTreeListeners(listener -> listener.onTreeElementAdded(transition)); } - board = transition.getBoard(); - puzzleElement = board.getPuzzleElement(selectedPuzzleElement); savePuzzleElement = puzzleElement.copy(); } else { @@ -73,7 +74,6 @@ public void executeCommand() { } Board prevBoard = transition.getParents().get(0).getBoard(); - boardView.getElementController().changeCell(event, puzzleElement); if (prevBoard.getPuzzleElement(selectedPuzzleElement).equalsData(puzzleElement)) { @@ -102,35 +102,50 @@ public void executeCommand() { public String getErrorString() { List selectedViews = selection.getSelectedViews(); if (selectedViews.size() != 1) { + flashTreeViewRed(); return CommandError.ONE_SELECTED_VIEW.toString(); } TreeElementView selectedView = selection.getFirstSelection(); Board board = selectedView.getTreeElement().getBoard(); PuzzleElement selectedPuzzleElement = elementView.getPuzzleElement(); if (selectedView.getType() == TreeElementType.NODE) { - TreeNodeView nodeView = (TreeNodeView) selectedView; if (!nodeView.getChildrenViews().isEmpty()) { + flashTreeViewRed(); return CommandError.UNMODIFIABLE_BOARD.toString(); - } else { - if (!board.getPuzzleElement(selectedPuzzleElement).isModifiable()) { - return CommandError.UNMODIFIABLE_DATA.toString(); - } + } else if (!board.getPuzzleElement(selectedPuzzleElement).isModifiable()) { + flashTreeViewRed(); + return CommandError.UNMODIFIABLE_DATA.toString(); } } else { TreeTransitionView transitionView = (TreeTransitionView) selectedView; if (!transitionView.getTreeElement().getBoard().isModifiable()) { + flashTreeViewRed(); return CommandError.UNMODIFIABLE_BOARD.toString(); } else { if (!board.getPuzzleElement(selectedPuzzleElement).isModifiable()) { + flashTreeViewRed(); return CommandError.UNMODIFIABLE_DATA.toString(); + } else if (!board.getPuzzleElement(selectedPuzzleElement).isModifiableCaseRule()) { + flashTreeViewRed(); + return CommandError.UNMODIFIABLE_DATA_CASE_RULE.toString(); } } } return null; } - /** Undoes an command */ + /** Causes the TreeView background to flash red for a short duration. */ + private void flashTreeViewRed() { + TreeView treeView = getInstance().getLegupUI().getTreePanel().getTreeView(); + Color originalColor = treeView.getBackground(); + treeView.setBackground(MaterialColors.RED_700); + Timer timer = new Timer(400, e -> treeView.setBackground(originalColor)); + timer.setRepeats(false); + timer.start(); + } + + /** Undoes a command */ @SuppressWarnings("unchecked") @Override public void undoCommand() { diff --git a/src/main/java/edu/rpi/legup/history/History.java b/src/main/java/edu/rpi/legup/history/History.java index 371284f8c..dca6af3f3 100644 --- a/src/main/java/edu/rpi/legup/history/History.java +++ b/src/main/java/edu/rpi/legup/history/History.java @@ -51,6 +51,8 @@ public void undo() { ICommand command = history.get(curIndex--); command.undo(); LOGGER.info("Undoed " + command.getClass().getSimpleName()); + + GameBoardFacade.getInstance() .notifyHistoryListeners( l -> l.onUndo(curIndex < 0, curIndex == history.size() - 1)); diff --git a/src/main/java/edu/rpi/legup/history/MergeCommand.java b/src/main/java/edu/rpi/legup/history/MergeCommand.java index f234a0884..d7a7f97f1 100644 --- a/src/main/java/edu/rpi/legup/history/MergeCommand.java +++ b/src/main/java/edu/rpi/legup/history/MergeCommand.java @@ -24,7 +24,7 @@ public MergeCommand(TreeViewSelection selection) { this.transition = null; } - /** Executes an command */ + /** Executes a command */ @Override public void executeCommand() { List selectedViews = selection.getSelectedViews(); diff --git a/src/main/java/edu/rpi/legup/model/gameboard/PuzzleElement.java b/src/main/java/edu/rpi/legup/model/gameboard/PuzzleElement.java index 4ce030a04..719d524da 100644 --- a/src/main/java/edu/rpi/legup/model/gameboard/PuzzleElement.java +++ b/src/main/java/edu/rpi/legup/model/gameboard/PuzzleElement.java @@ -8,6 +8,7 @@ public abstract class PuzzleElement { protected T data; protected boolean isModifiable; protected boolean isModified; + protected boolean isModifiableCaseRule; protected boolean isGiven; protected boolean isValid; protected int casesDepended; @@ -17,6 +18,7 @@ public PuzzleElement() { this.index = -1; this.data = null; this.isModifiable = true; + this.isModifiableCaseRule = true; this.isModified = false; this.isGiven = false; this.isValid = true; @@ -73,6 +75,24 @@ public void setModifiable(boolean isModifiable) { this.isModifiable = isModifiable; } + /** + * Gets whether this puzzle element is modifiable as a result of a case rule. + * + * @return true if this puzzle element is modifiable, false otherwise + */ + public boolean isModifiableCaseRule() { + return isModifiableCaseRule; + } + + /** + * Sets whether this puzzle element is modifiable as a result of a case rule. + * + * @param isModifiableCaseRule true if this puzzle element is modifiable, false otherwise + */ + public void setModifiableCaseRule(boolean isModifiableCaseRule) { + this.isModifiableCaseRule = isModifiableCaseRule; + } + /** * Gets whether the puzzle element has been modified. * diff --git a/src/main/java/edu/rpi/legup/model/tree/Tree.java b/src/main/java/edu/rpi/legup/model/tree/Tree.java index 3cdab80c2..56cfbff07 100644 --- a/src/main/java/edu/rpi/legup/model/tree/Tree.java +++ b/src/main/java/edu/rpi/legup/model/tree/Tree.java @@ -1,6 +1,10 @@ package edu.rpi.legup.model.tree; +import edu.rpi.legup.controller.TreeController; import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.rules.CaseRule; +import edu.rpi.legup.ui.proofeditorui.treeview.TreeView; + import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -95,6 +99,9 @@ public void removeTreeElement(TreeElement element) { System.out.println("Deleted arrow: " + transition); transition.getParents().forEach(n -> n.removeChild(transition)); + TreeController treeController = new TreeController(); + TreeView treeView = new TreeView(treeController); + treeView.removeTreeTransition(transition); transition.getParents().get(0).getChildren().forEach(TreeTransition::reverify); } } diff --git a/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java b/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java index f78281c89..b6117cb4f 100644 --- a/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java +++ b/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java @@ -9,11 +9,9 @@ import edu.rpi.legup.model.Puzzle; import edu.rpi.legup.model.PuzzleExporter; import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; 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.binary.BinaryType; import edu.rpi.legup.save.ExportFileException; import edu.rpi.legup.save.InvalidFileFormatException; import edu.rpi.legup.ui.boardview.BoardView; diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeView.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeView.java index ea622881c..5a7af1e95 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeView.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeView.java @@ -460,11 +460,41 @@ private void removeTreeNode(TreeNode node) { node.getChildren().forEach(t -> removeTreeTransition(t)); } - private void removeTreeTransition(TreeTransition trans) { + public void removeTreeTransition(TreeTransition trans) { viewMap.remove(trans); if (trans.getChildNode() != null) { removeTreeNode(trans.getChildNode()); } + + // Update transition modifiability if removing a case rule + List parents = trans.getParents(); + for (TreeNode parent : parents) { + System.out.println(parent.getParent().getRule()); + + // if transition is a case rule, unlock ancestor elements up until latest case rule or root node + boolean nextAncestorIsCaseRule = false; + Rule rule = trans.getRule(); + if (rule instanceof CaseRule) { + List ancestors = parent.getAncestors(); + for (int i = 0; i < ancestors.size(); i++) { + if (ancestors.get(i).getParent() == null) { + continue; + } + if (nextAncestorIsCaseRule) { + break; + } + for (PuzzleElement element : parent.getBoard().getPuzzleElements()) { + PuzzleElement curElement = ancestors.get(i).getParent().getBoard().getPuzzleElement(element); + if (!curElement.isModifiableCaseRule()) { + curElement.setModifiableCaseRule(true); + } + } + if (ancestors.get(i).getParent().getRule() instanceof CaseRule) { + nextAncestorIsCaseRule = true; + } + } + } + } } private void addTreeNode(TreeNode node) { @@ -519,7 +549,7 @@ private void addTreeTransition(TreeTransition trans) { // if transition is a new case rule, lock dependent ancestor elements Rule rule = trans.getRule(); if (rule instanceof CaseRule && parent.getChildren().size() == 1) { - CaseRule caseRule = (CaseRule) rule; + //CaseRule caseRule = (CaseRule) rule; List ancestors = parent.getAncestors(); for (TreeNode ancestor : ancestors) { @@ -527,13 +557,17 @@ private void addTreeTransition(TreeTransition trans) { if (ancestor.getParent() == null) { continue; } - for (PuzzleElement element : - caseRule.dependentElements(parent.getBoard(), trans.getSelection())) { - // increment and lock - PuzzleElement oldElement = - ancestor.getParent().getBoard().getPuzzleElement(element); - oldElement.setCasesDepended(oldElement.getCasesDepended() + 1); + + for (PuzzleElement element : parent.getBoard().getPuzzleElements()) { + PuzzleElement curElement = ancestor.getParent().getBoard().getPuzzleElement(element); + curElement.setModifiableCaseRule(false); } +// for (PuzzleElement element : caseRule.dependentElements(parent.getBoard(), trans.getSelection())) { +// // increment and lock +// PuzzleElement oldElement = ancestor.getParent().getBoard().getPuzzleElement(element); +// oldElement.setCasesDepended(oldElement.getCasesDepended() + 1); +// oldElement.setModifiable(false); +// } } } } From 39dbef4f3e918e5a6d3fe6b62b6155ac27c4b7f9 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Sun, 14 Jul 2024 10:13:53 -0400 Subject: [PATCH 176/258] Modified finish room case rule to allow a minimum of only one state --- .../rpi/legup/puzzle/nurikabe/rules/FinishRoomCaseRule.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/FinishRoomCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/FinishRoomCaseRule.java index 0dfbc7686..dd8943cdb 100644 --- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/FinishRoomCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/FinishRoomCaseRule.java @@ -28,7 +28,7 @@ public FinishRoomCaseRule() { "Room can be finished in up to nine ways", "edu/rpi/legup/images/nurikabe/cases/FinishRoom.png"); this.MAX_CASES = 9; - this.MIN_CASES = 2; + this.MIN_CASES = 1; this.uniqueCases = new HashSet<>(); } @@ -49,7 +49,7 @@ public String checkRuleRaw(TreeTransition transition) { } if (childTransitions.size() < MIN_CASES) { return super.getInvalidUseOfRuleMessage() - + ": This case rule must have 2 or more children."; + + ": This case rule must have 1 or more children."; } if (childTransitions.size() != legitCases) { return super.getInvalidUseOfRuleMessage() From c2c3aab82bdc583ad586415265d991ec2039b895 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Sun, 14 Jul 2024 10:19:56 -0400 Subject: [PATCH 177/258] Updated finish room case rule test to match current functionality --- .../rules/FinishRoomCaseRuleTest.java | 37 ++----------------- 1 file changed, 4 insertions(+), 33 deletions(-) diff --git a/src/test/java/puzzles/nurikabe/rules/FinishRoomCaseRuleTest.java b/src/test/java/puzzles/nurikabe/rules/FinishRoomCaseRuleTest.java index 5f5b6d35a..a29a1c934 100644 --- a/src/test/java/puzzles/nurikabe/rules/FinishRoomCaseRuleTest.java +++ b/src/test/java/puzzles/nurikabe/rules/FinishRoomCaseRuleTest.java @@ -28,13 +28,12 @@ public static void setUp() { } /** - * Tests the Finish Room case rule by ensuring that it results in 5 or less children, that - * contain a modified cell that is white + * Tests the Finish Room case rule by ensuring it produces the correct number of children */ + @Test public void FinishRoomCaseRule_FinishRoomCaseRuleBaseTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard( - "puzzles/nurikabe/rules/FinishRoomCaseRule/FinishRoomCaseRuleBase", nurikabe); + TestUtilities.importTestBoard("puzzles/nurikabe/rules/FinishRoomCaseRule/FinishRoomCaseRuleBase", nurikabe); TreeNode rootNode = nurikabe.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -81,34 +80,6 @@ public void FinishRoomCaseRule_FinishRoomCaseRuleBaseTest() throws InvalidFileFo NurikabeCell cell2 = board.getCell(4, 2); ArrayList cases2 = RULE.getCases(board, cell2); - Assert.assertEquals(6, cases2.size()); // correctly stops generating possible cases after - // more than 5 (the max) is found. Would have generated 8 cases - // FinishRoomCaseRule finny = new FinishRoomCaseRule(); - // finny.checkRuleRaw(); - // "Invalid use of the case rule FinishRoom: This case rule must have 5 or less children." - - // getErrorString in auto case rule - // should display "The selection can produce a max of 5 cases." - // AutoCaseRuleCommand autoCaseRuleCommand = new AutoCaseRuleCommand(elementView, selection, - // caseBoard.getCaseRule(), caseBoard, e); - - // NurikabeBoard caseyBoard = (NurikabeBoard) cases2.get(0); - // NurikabeBoard caseyBoard2 = (NurikabeBoard) cases2.get(1); - // NurikabeBoard caseyBoard3 = (NurikabeBoard) cases2.get(2); - // NurikabeBoard caseyBoard4 = (NurikabeBoard) cases2.get(3); - // NurikabeBoard caseyBoard5 = (NurikabeBoard) cases2.get(4); - // NurikabeBoard caseyBoard6 = (NurikabeBoard) cases2.get(5); - // NurikabeBoard caseyBoard7 = (NurikabeBoard) cases2.get(6); - // NurikabeBoard caseyBoard8 = (NurikabeBoard) cases2.get(7); - // - // NurikabeType boardy1Type = caseyBoard.getCell(5,5).getType(); - // NurikabeType boardy2Type = caseyBoard2.getCell(6,6).getType(); - // NurikabeType boardy3Type = caseyBoard.getCell(5,5).getType(); - // NurikabeType boardy4Type = caseyBoard2.getCell(6,6).getType(); - // NurikabeType boardy5Type = caseyBoard.getCell(5,5).getType(); - // NurikabeType boardy6Type = caseyBoard2.getCell(6,6).getType(); - // NurikabeType boardy7Type = caseyBoard.getCell(5,5).getType(); - // NurikabeType boardy8Type = caseyBoard2.getCell(6,6).getType(); - + Assert.assertEquals(9, cases2.size()); } } From 3e8a438658b511f3b4f6b4717f681267cf31a18b Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Sun, 14 Jul 2024 10:41:09 -0400 Subject: [PATCH 178/258] Fixed bug that prevented user from deleting transition from the root node --- .../java/edu/rpi/legup/history/DeleteTreeElementCommand.java | 2 +- src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java | 2 +- .../java/edu/rpi/legup/ui/proofeditorui/treeview/TreeView.java | 2 -- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/java/edu/rpi/legup/history/DeleteTreeElementCommand.java b/src/main/java/edu/rpi/legup/history/DeleteTreeElementCommand.java index 258aaacc0..35a56c652 100644 --- a/src/main/java/edu/rpi/legup/history/DeleteTreeElementCommand.java +++ b/src/main/java/edu/rpi/legup/history/DeleteTreeElementCommand.java @@ -72,7 +72,7 @@ public String getErrorString() { return null; } - /** Undoes an command */ + /** Undoes a command */ @Override public void undoCommand() { Puzzle puzzle = GameBoardFacade.getInstance().getPuzzleModule(); diff --git a/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java b/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java index b6117cb4f..624ac102a 100644 --- a/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java +++ b/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java @@ -168,7 +168,7 @@ public JMenuBar getMenuBar() { } proof.add(add); - delete = new JMenuItem("D\"Check All\"elete"); + delete = new JMenuItem("Delete"); delete.addActionListener(a -> treePanel.delete()); if (os.equals("mac")) { delete.setAccelerator( diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeView.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeView.java index 5a7af1e95..d7fffd1bf 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeView.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeView.java @@ -469,8 +469,6 @@ public void removeTreeTransition(TreeTransition trans) { // Update transition modifiability if removing a case rule List parents = trans.getParents(); for (TreeNode parent : parents) { - System.out.println(parent.getParent().getRule()); - // if transition is a case rule, unlock ancestor elements up until latest case rule or root node boolean nextAncestorIsCaseRule = false; Rule rule = trans.getRule(); From 616ff8883e3111f137dc2bf96aeacc710ce67b13 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Sun, 14 Jul 2024 20:03:01 -0400 Subject: [PATCH 179/258] Updated images to binary puzzle --- .../EliminateTheImpossibleDirectRule.java | 2 +- .../rules/CompleteRowColumnDirectRule.png | Bin 2835 -> 2174 bytes .../EliminateTheImpossibleDirectRule.png | Bin 0 -> 2204 bytes .../binary/rules/OneTileGapDirectRule.png | Bin 2751 -> 1944 bytes .../binary/rules/SurroundPairDirectRule.png | Bin 2982 -> 2251 bytes 5 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 src/main/resources/edu/rpi/legup/images/binary/rules/EliminateTheImpossibleDirectRule.png diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java index cb4aab59a..14bcafc4e 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java @@ -23,7 +23,7 @@ public EliminateTheImpossibleDirectRule() { "BINA-BASC-0004", "Eliminate The Impossible", "If three adjacent empty cells are open, prevents a trio of numbers to exist", - "edu/rpi/legup/images/binary/rules/OneTileGapDirectRule.png"); + "edu/rpi/legup/images/binary/rules/EliminateTheImpossibleDirectRule.png"); } // Function to generate all binary strings diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/CompleteRowColumnDirectRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/CompleteRowColumnDirectRule.png index a74654d4301f75defc639727604f3d59f05612a3..27ccec97290109fe20d727d468465a57af330906 100644 GIT binary patch literal 2174 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 W-$D%jr3*N)f}HK$?8r8Oq<;bxYC}%| diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/EliminateTheImpossibleDirectRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/EliminateTheImpossibleDirectRule.png new file mode 100644 index 0000000000000000000000000000000000000000..7695ae2da1303c723d962d0da95bbb4fb9abee98 GIT binary patch literal 2204 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 TsFd*d-xT0zciFbm8lC(vAL*4l literal 2751 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 diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/SurroundPairDirectRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/SurroundPairDirectRule.png index 67a4e47f363222af68afe45acacd0783f0f35319..ecbed51abe90907b89be11f355ac3ab7c9751c63 100644 GIT binary patch literal 2251 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 From 621b5812ab39a275a32a9f25d479b2229cdf923d Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Tue, 16 Jul 2024 12:27:29 -0400 Subject: [PATCH 180/258] Updated binary contradiction images --- .../rules/CompleteRowColumnDirectRule.java | 2 +- ...uplicateRowsColumnsContradictionRule.java} | 10 +++++----- .../EliminateTheImpossibleDirectRule.java | 2 +- ...UnbalancedRowColumnContradictionRule.java} | 7 +++---- .../DuplicateRowOrColumnContradictionRule.png | Bin 3455 -> 0 bytes .../DuplicateRowsColumnsContradictionRule.png | Bin 0 -> 2124 bytes .../rules/ThreeAdjacentContradictionRule.png | Bin 2508 -> 2071 bytes .../UnbalancedRowColumnContradictionRule.png | Bin 2793 -> 1783 bytes 8 files changed, 10 insertions(+), 11 deletions(-) rename src/main/java/edu/rpi/legup/puzzle/binary/rules/{DuplicateRowsOrColumnsContradictionRule.java => DuplicateRowsColumnsContradictionRule.java} (82%) rename src/main/java/edu/rpi/legup/puzzle/binary/rules/{UnbalancedRowOrColumnContradictionRule.java => UnbalancedRowColumnContradictionRule.java} (91%) delete mode 100644 src/main/resources/edu/rpi/legup/images/binary/rules/DuplicateRowOrColumnContradictionRule.png create mode 100644 src/main/resources/edu/rpi/legup/images/binary/rules/DuplicateRowsColumnsContradictionRule.png diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java index 795535352..527223f5c 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java @@ -18,7 +18,7 @@ public class CompleteRowColumnDirectRule extends DirectRule { public CompleteRowColumnDirectRule() { super( "BINA-BASC-0003", - "Complete Row Column", + "Complete Row/Column", "If a row/column of length n contains n/2 of a single value, the remaining cells must contain the other value", "edu/rpi/legup/images/binary/rules/CompleteRowColumnDirectRule.png"); } diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsOrColumnsContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsColumnsContradictionRule.java similarity index 82% rename from src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsOrColumnsContradictionRule.java rename to src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsColumnsContradictionRule.java index 8b0d88ae4..575c62d92 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsOrColumnsContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsColumnsContradictionRule.java @@ -8,17 +8,17 @@ import edu.rpi.legup.puzzle.binary.BinaryType; import java.util.ArrayList; -public class DuplicateRowsOrColumnsContradictionRule extends ContradictionRule { +public class DuplicateRowsColumnsContradictionRule extends ContradictionRule { private final String NO_CONTRADICTION_MESSAGE = "Does not contain a contradiction at this index"; private final String INVALID_USE_MESSAGE = "Row or column must have a value in each cell"; - public DuplicateRowsOrColumnsContradictionRule() { + public DuplicateRowsColumnsContradictionRule() { super( "BINA-CONT-0003", - "Duplicate Rows Or Columns", - "There must not be two rows or two columns that are duplicates", - "edu/rpi/legup/images/binary/rules/DuplicateRowOrColumnContradictionRule.png"); + "Duplicate Rows/Columns", + "There must not be two of the same row or two of the same column in the puzzle", + "edu/rpi/legup/images/binary/rules/DuplicateRowsColumnsContradictionRule.png"); } @Override diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java index 14bcafc4e..117a639cb 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java @@ -22,7 +22,7 @@ public EliminateTheImpossibleDirectRule() { super( "BINA-BASC-0004", "Eliminate The Impossible", - "If three adjacent empty cells are open, prevents a trio of numbers to exist", + "Out of the remaining empty cells in this row or column, this digit must go here, otherwise there will be a future contradiction", "edu/rpi/legup/images/binary/rules/EliminateTheImpossibleDirectRule.png"); } diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowOrColumnContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowColumnContradictionRule.java similarity index 91% rename from src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowOrColumnContradictionRule.java rename to src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowColumnContradictionRule.java index ea110ef2c..388528c8b 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowOrColumnContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowColumnContradictionRule.java @@ -7,19 +7,18 @@ import edu.rpi.legup.puzzle.binary.BinaryCell; import edu.rpi.legup.puzzle.binary.BinaryType; -import java.util.ArrayList; import java.util.Set; -public class UnbalancedRowOrColumnContradictionRule extends ContradictionRule { +public class UnbalancedRowColumnContradictionRule extends ContradictionRule { private final String NO_CONTRADICTION_MESSAGE = "Does not contain a contradiction at this index"; private final String INVALID_USE_MESSAGE = "Row or column must have a value in each cell"; - public UnbalancedRowOrColumnContradictionRule() { + public UnbalancedRowColumnContradictionRule() { super( "BINA-CONT-0002", - "Unbalanced Row Or Column", + "Unbalanced Row/Column", "Each row or column must contain an equal number of zeros and ones", "edu/rpi/legup/images/binary/rules/UnbalancedRowColumnContradictionRule.png"); } diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/DuplicateRowOrColumnContradictionRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/DuplicateRowOrColumnContradictionRule.png deleted file mode 100644 index 214aa53483ccc0f6749bffda004ccfc2f70ded29..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3455 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 diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/DuplicateRowsColumnsContradictionRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/DuplicateRowsColumnsContradictionRule.png new file mode 100644 index 0000000000000000000000000000000000000000..5cc030a7671f6e567d56c9d71ddd640bd5a33336 GIT binary patch literal 2124 zcmai0dpHy7AK#k$t&OG`5l(UtO|E4!*H&_gL#7RLmI>}({(;9>v(KoWh< z@)AFL^MfEF#9!U;*d%@ek}lbp1Ij)s%=3YO59%Tc04Prv-}4gWW6>Mu+(-bxk;K0O zn9g1!006?1XiJnc8Ml<@cP`si;eAxdTlw4PoMme-AL_3WIsbEx`aO5Z9S5;G;v)n& zyu8*yZ*W+w$t10wU^;F$H_Lsq5Vh_Z>5vOty! zH$*BKk?HSeL$8mISDVc46dI{4NC`KBgr3#M3R||!EiZ>i`FzZ$hL7v%85mgC21<|B zQfzF}6ejDtxPj8K)9K*XT==}4qB5QwpELTc`V6`Zybm({wV&ATmrn8^7$^pPWT+-}W<4rav_N-04uiopVBb`D!IC6EO@!pk9(TKYRcH{co<$T`mUOF)%prE2wwz&_NyoPge()RX^(*3lPC+#F* zt3^9_@<}7eCI!~G?ccBga~iLUV0mwRdSFr712gc4rOKU3V0n5c`y@)pHL+kQ50SV6yzwyg2mOQ6=NX!w7J+d_NHhp=#zB85< z+ZGfQ^r^qpJ*+i$(>8`o%h+BS?-UmhFp8J_!0X5}?CtHf9H|WO_OhkO`4^f-v~7*O z3)MM8@UVnh_+Z@J&{Qfl|I z(nBPL^C|PV{fqTPnVRz?|2dn}J|&s^_K=Y-D?_gn4cju=9ZeBd%7|vDHjv4iAMw^I=~I z1j5|}1Zq1ac(H%&GBR+?1XCNXZ!I{hwmWnDvCQ!{z_b9FNTapY=-Jr1XM!tGUj z6yh=l!|x2exzMM%WjS6HT7aZvsoB!Z0^Bc0j#oP5Kw6b=k6JFmJK-+vgFH}G{A(MF6^7^@DCQ4CadHYILqr2V zY^6_DY(4;&ZI;mR$rPgBK2cL$dcrKuvkM5s8UTUeDhtu{nM+ZFjbknSFFM6n1V6M^ z_-0^7?huTf!-`SZp+|;dSkaor?*Wavy9)yr{2?yzJNrm~B+A*9v*$NZ`NtnEWRn$1 zwQ3G0Bv;=rYvUDU95nN>;Q2BQ0S>t7m$PtY^9Qe-lSJ?pmRAl>tpv7eZLHM;>b~2o>t&zStShF+ zRLJ53$f}k_0t+&kY0uDm27`>QpV?1;V*2 z95`PwLykw*&51?soQ&8F3ML$k@3U7J!Ag|>iX|v literal 0 HcmV?d00001 diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/ThreeAdjacentContradictionRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/ThreeAdjacentContradictionRule.png index 862408b63a9c6d72d815b79064ea587657bc5e5e..e292ec9faabb7c263093b94a3bacdaf56e0d05d7 100644 GIT binary patch literal 2071 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 HUy1z(|GtR) diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/UnbalancedRowColumnContradictionRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/UnbalancedRowColumnContradictionRule.png index 029bd12ac8782f97428d092ee56187d0aa7d77cf..bd66c16a7fdb3b876bf8e39b54c9a84d2928a3e9 100644 GIT binary patch literal 1783 zcmeAS@N?(olHy`uVBq!ia0vp^sUXb31|&mjbk74R#^NA%Cx&(BWL^R}Ea{HEjtmSN z`?>!lvI6;>1s;*b3=FdEAk5hR^dnF^TaTxUV@O5Z+qtnBA?_l_`#aUNvW^_-pP<1p zal!872SaxB0&~Jselbu9a!kszQbh58x zsH{|SIl4hf`h*noN9E3&&+O0TWbclAe?~4Eue)&J^5x0K_8AWzG%HS-W@KyYJ9+YC ztJL$ix98tCKE-1t%^!q&MqQt9U44>ff7oK3=k3vJ2n+O zbc))NG12d4a72X1(W6JLp0ee9Xl&+hd!u%JYxebm!lZz0~kUwa{Az2VK> zyLWwidwZ>p%l&aQ%fGiK_*=mTM*ddDMJY8q>i$-#P4#*?MOs!?*6P`@UTO1^GrW9u z61q;3!5^mh`1-z_Vyn^rz**wy^IPoAXZE4GAJbzV8jEydcTJh58@(*}TY`Sl$w{gR zA6@#pv-o+&JsXv`2Od2;+|HkQv`bWLM}yU`-@jMx+js9~+rfj5t5&V*+QP4^tE)9n z^y!a}kH5USs_n8?LrZH>gw8Uv@@e|`SyQje0y_qaoM>TnM3QI zFZG`OqTT-SIkP_%KZ<`nJM(_xw}Tx*84Jo^Djz;}y-nligm4iayJs!z^VsHGbC}2b zV!h#J$NkySVn1#PxXOR(YU+A-XQ#8ce%zAJ&(B|;tnR<2@1lr^NPyAICEvc4y?Xt6 z@zHMa*VYF=ZdL5EJEO(bb8zEKVRgR?zrMZ>wXgp5<>i`3@=X3mPEXf=`R3+ktvwYV zo5XY?7QAOWe7$YOFN4(@0Yb(97cNx1TH@{Hb!Ch3R4>hBdzL!OWz*aFWP>uNFMFTu z98!DYcF?io$EONPESS(Xaee&$ZBiz&&)%@bOD}qLc+H{*%py}v6?m^+Tz<<&_nG+Z zKY~2_%v`RvN4i#ie#V=7V?(1^-klX}yDnY~ytOS?dTq?kAWc~oi^eL3Uun_HYjQhQ z@o(;85;b&?wJdVkE61F*ecLvz!%YqU#Mx{rJ~YglH7g?}#bxQmn&wAf$3$EI+FSbi z+Qol=e_s_kvMO{n)A#im%Vykve|PtEzj-#E?0hl-{*pXf4jyL%hhfqzJuQRq+0VM? zwA2lj7Xn+5g`9J^kF)=Qq-Kzq}zo9h|5B zX})XMu97poyUX9dnjtMyV-WR3_C<4({~E{TGj|?vcoi)7W7>0I;UN;(Qh;6}V9ikv z8fLv!+*;r4J5S;HhEESa|7HZ1FgO2BIo>b-_z}y!t)Y>TE6qA$4sd1L$Snuviq|sL z1v({{m-&LzbU~9)it9o9(n8kz35UWtPMtbc(kE-t(J*~M?%iFX&u=uF-@bbFDlnhR z)Eu~|-27eb`kCNqp35&=J#|Y@U*5OV@Ny8MOeknM_B1<}&7^kDrw@!~KMouurceMD zgA>+hL@X)c-SOnBEV>r&6` YvemvPddB(hz{-lj)78&qol`;+093R}SpWb4 literal 2793 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 From f32fe76b1d7f5f8e891fc2149c7d728b869d4071 Mon Sep 17 00:00:00 2001 From: summerhenson Date: Tue, 16 Jul 2024 14:10:31 -0400 Subject: [PATCH 181/258] Wrote test for Columns Within Regions direct rule and fixed the bug it revealed --- .../rules/ColumnsWithinRegionsDirectRule.java | 4 +- .../ColumnsWithinRegionsDirectRuleTest.java | 50 +++++++++++++++++++ .../TwoColumnsStarOverlap | 40 +++++++++++++++ 3 files changed, 92 insertions(+), 2 deletions(-) create mode 100644 src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/TwoColumnsStarOverlap 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 43e9a1df9..d1e6fdc72 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 @@ -59,7 +59,7 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem regionStars += board.getRegion(r).numStars(); for (PuzzleElement c : board.getRegion(r).getCells()) { int column = ((StarBattleCell) c).getLocation().x; - if (((StarBattleCell) c).getType() != StarBattleCellType.BLACK && columns.add(column)) { + if (column != cell.getLocation().x && ((StarBattleCell) c).getType() == StarBattleCellType.UNKNOWN && columns.add(column)) { columnsToCheck.add(column); } } @@ -71,7 +71,7 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem columnStars += board.columnStars(c); for (int i = 0; i < board.getSize(); ++i) { int region = board.getCell(c, i).getGroupIndex(); - if (board.getCell(c,i).getType() != StarBattleCellType.BLACK && regions.add(region)) { + if (board.getCell(c,i).getType() == StarBattleCellType.UNKNOWN && regions.add(region)) { regionsToCheck.add(region); } } diff --git a/src/test/java/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRuleTest.java b/src/test/java/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRuleTest.java index 69ad49b14..3a115530e 100644 --- a/src/test/java/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRuleTest.java +++ b/src/test/java/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRuleTest.java @@ -147,6 +147,34 @@ public void ColumnsWithinRegionsDirectRule_TwoColumns() } } + @Test + public void ColumnsWithinRegionsDirectRule_TwoColumnsStarOverlap() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/TwoColumnsStarOverlap", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(2,3); + cell1.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell1); + + Assert.assertNull(RULE.checkRule(transition)); + + Point location1 = new Point(2, 3); + 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(location1)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + @Test public void ColumnsWithinRegionsDirectRule_FalseColumnsWithinRegions1() throws InvalidFileFormatException { @@ -210,4 +238,26 @@ public void ColumnsWithinRegionsDirectRule_FalseColumnsWithinRegions2() } } + @Test + public void ColumnsWithinRegionsDirectRule_FalseColumnsWithinRegions3() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/PartialColumnTwoCells", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(0,1); + cell1.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell1); + + Assert.assertNotNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); i++) { + for (int k = 0; k < board.getWidth(); k++) { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } diff --git a/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/TwoColumnsStarOverlap b/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/TwoColumnsStarOverlap new file mode 100644 index 000000000..8562a47a8 --- /dev/null +++ b/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/TwoColumnsStarOverlap @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 2e62d411a58720b03c6e8e0066c10e31a66591eb Mon Sep 17 00:00:00 2001 From: summerhenson Date: Tue, 16 Jul 2024 14:30:57 -0400 Subject: [PATCH 182/258] Bug fix for X Within Y direct rules --- .../rules/ColumnsWithinRegionsDirectRule.java | 4 +-- .../rules/ColumnsWithinRowsDirectRule.java | 12 ++++---- .../rules/RowsWithinRegionsDirectRule.java | 8 +++--- .../ColumnsWithinRegionsDirectRuleTest.java | 28 +++++++++++++++++++ 4 files changed, 40 insertions(+), 12 deletions(-) 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 d1e6fdc72..6e4830138 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 @@ -57,9 +57,9 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem for (int i = 0; i < regionsToCheck.size(); ++i) { int r = regionsToCheck.get(i); regionStars += board.getRegion(r).numStars(); - for (PuzzleElement c : board.getRegion(r).getCells()) { + for (StarBattleCell c : board.getRegion(r).getCells()) { int column = ((StarBattleCell) c).getLocation().x; - if (column != cell.getLocation().x && ((StarBattleCell) c).getType() == StarBattleCellType.UNKNOWN && columns.add(column)) { + if (column != cell.getLocation().x && c.getType() == StarBattleCellType.UNKNOWN && columns.add(column)) { columnsToCheck.add(column); } } 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 01853a2d1..765a84d5b 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 @@ -61,9 +61,9 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem for (int i = 0; i < rowsToCheck.size(); ++i) { int r = rowsToCheck.get(i); rowStars += board.rowStars(r); - for (PuzzleElement c : board.getRow(r)) { - int column = ((StarBattleCell) c).getLocation().x; - if (columns.add(column)) { + for (StarBattleCell c : board.getRow(r)) { + int column = c.getLocation().x; + if (c.getType() == StarBattleCellType.UNKNOWN && columns.add(column)) { columnsToCheck.add(column); } } @@ -73,9 +73,9 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem for (int i = 0; i < columnsToCheck.size(); ++i) { int c = columnsToCheck.get(i); columnStars += board.columnStars(c); - for (PuzzleElement r : board.getCol(c)) { - int row = ((StarBattleCell) r).getLocation().y; - if (rows.add(row)) { + for (StarBattleCell r : board.getCol(c)) { + int row = r.getLocation().y; + if (r.getType() == StarBattleCellType.UNKNOWN && rows.add(row)) { rowsToCheck.add(row); } } 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 33948deff..faa75d01c 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 @@ -58,9 +58,9 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem for (int i = 0; i < regionsToCheck.size(); ++i) { int r = regionsToCheck.get(i); regionStars += board.getRegion(r).numStars(); - for (PuzzleElement ro : board.getRegion(r).getCells()) { - int row = ((StarBattleCell) ro).getLocation().y; - if (rows.add(row)) { + for (StarBattleCell ro : board.getRegion(r).getCells()) { + int row = ro.getLocation().y; + if (ro.getType() == StarBattleCellType.UNKNOWN && rows.add(row)) { rowsToCheck.add(row); } } @@ -72,7 +72,7 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem rowStars += board.rowStars(r); for (int i = 0; i < board.getSize(); ++i) { int region = board.getCell(i, r).getGroupIndex(); - if (regions.add(region)) { + if (board.getCell(i,r).getType() == StarBattleCellType.UNKNOWN && regions.add(region)) { regionsToCheck.add(region); } } diff --git a/src/test/java/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRuleTest.java b/src/test/java/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRuleTest.java index 3a115530e..df9d10635 100644 --- a/src/test/java/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRuleTest.java +++ b/src/test/java/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRuleTest.java @@ -147,6 +147,34 @@ public void ColumnsWithinRegionsDirectRule_TwoColumns() } } + @Test + public void ColumnsWithinRegionsDirectRule_TwoColumnsWaitAMinute() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/TwoColumns", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(2,1); + cell1.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell1); + + Assert.assertNull(RULE.checkRule(transition)); + + Point location1 = new Point(2, 1); + 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(location1)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + @Test public void ColumnsWithinRegionsDirectRule_TwoColumnsStarOverlap() throws InvalidFileFormatException { From 060897a4589cae27f8b793384328c0aa569b7887 Mon Sep 17 00:00:00 2001 From: summerhenson Date: Tue, 16 Jul 2024 14:42:21 -0400 Subject: [PATCH 183/258] Finish ColumnsWithinRegions direct rule tests --- .../ColumnsWithinRegionsDirectRuleTest.java | 25 ++++++++++++ .../FalseStarOverlap | 40 +++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/FalseStarOverlap diff --git a/src/test/java/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRuleTest.java b/src/test/java/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRuleTest.java index df9d10635..e834828ad 100644 --- a/src/test/java/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRuleTest.java +++ b/src/test/java/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRuleTest.java @@ -288,4 +288,29 @@ public void ColumnsWithinRegionsDirectRule_FalseColumnsWithinRegions3() } } + @Test + public void ColumnsWithinRegionsDirectRule_FalseColumnsWithinRegions4() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/FalseStarOverlap", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(2,2); + cell1.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell1); + StarBattleCell cell2 = board.getCell(2,3); + cell2.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell2); + + Assert.assertNotNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); i++) { + for (int k = 0; k < board.getWidth(); k++) { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } diff --git a/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/FalseStarOverlap b/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/FalseStarOverlap new file mode 100644 index 000000000..8a435e5d7 --- /dev/null +++ b/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/FalseStarOverlap @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 5d767a705555f485a683e8d1c30070bc63696004 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Thu, 18 Jul 2024 10:32:02 -0400 Subject: [PATCH 184/258] Refactored ZeroOrOneCaseRule --- ...eroCaseRule.java => ZeroOrOneCaseRule.java} | 17 ++++++++--------- .../images/binary/rules/OneOrZeroCaseRule.png | Bin 5578 -> 0 bytes .../images/binary/rules/ZeroOrOneCaseRule.png | Bin 0 -> 5581 bytes 3 files changed, 8 insertions(+), 9 deletions(-) rename src/main/java/edu/rpi/legup/puzzle/binary/rules/{OneOrZeroCaseRule.java => ZeroOrOneCaseRule.java} (88%) delete mode 100644 src/main/resources/edu/rpi/legup/images/binary/rules/OneOrZeroCaseRule.png create mode 100644 src/main/resources/edu/rpi/legup/images/binary/rules/ZeroOrOneCaseRule.png diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneOrZeroCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ZeroOrOneCaseRule.java similarity index 88% rename from src/main/java/edu/rpi/legup/puzzle/binary/rules/OneOrZeroCaseRule.java rename to src/main/java/edu/rpi/legup/puzzle/binary/rules/ZeroOrOneCaseRule.java index 7ce6f1589..87d82a736 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneOrZeroCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ZeroOrOneCaseRule.java @@ -11,14 +11,14 @@ import java.util.ArrayList; import java.util.List; -public class OneOrZeroCaseRule extends CaseRule { +public class ZeroOrOneCaseRule extends CaseRule { - public OneOrZeroCaseRule() { + public ZeroOrOneCaseRule() { super( "BINA-CASE-0001", - "One or Zero", - "Each blank cell is either a one or a zero.", - "edu/rpi/legup/images/binary/rules/OneOrZeroCaseRule.png"); + "Zero Or One", + "Each blank cell is either a zero or a one.", + "edu/rpi/legup/images/binary/rules/ZeroOrOneCaseRule.png"); } @Override @@ -53,8 +53,7 @@ public String checkRuleRaw(TreeTransition transition) { public CaseBoard getCaseBoard(Board board) { BinaryBoard binaryBoard = (BinaryBoard) board.copy(); CaseBoard caseBoard = new CaseBoard(binaryBoard, this); - caseBoard.setModifiable(true); - //binaryBoard.setModifiable(false); + binaryBoard.setModifiable(false); for (PuzzleElement element : binaryBoard.getPuzzleElements()) { if (((BinaryCell) element).getType() == BinaryType.UNKNOWN) { caseBoard.addPickableElement(element); @@ -72,13 +71,13 @@ public ArrayList getCases(Board board, PuzzleElement puzzleElement) { Board case1 = board.copy(); PuzzleElement data1 = case1.getPuzzleElement(puzzleElement); - data1.setData(BinaryType.ZERO.toValue()); + data1.setData(BinaryType.ONE.toValue()); case1.addModifiedData(data1); cases.add(case1); Board case2 = board.copy(); PuzzleElement data2 = case2.getPuzzleElement(puzzleElement); - data2.setData(BinaryType.ONE.toValue()); + data2.setData(BinaryType.ZERO.toValue()); case2.addModifiedData(data2); cases.add(case2); diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/OneOrZeroCaseRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/OneOrZeroCaseRule.png deleted file mode 100644 index 73072f2ce5ea9d189fe55058aa6a4fa09ecc3979..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5578 zcmeHLS6Gua1NITq|r&3D;J@a#3&8%oE^*aPE2aE0z&p z7D|>oj>@7*G!MyXM#j%n=)qEIf=0?Q0yN~@Ne#;2)^M(9wT!Ub#X0-NIk(1bSBKYg zJN(xb(tH~cXEP4-8Bh7UL>9IYiZ>7_)jcT{x^U;HYoIY2IH;5f4MOn{ zK?F4%nSR2*sBlYIK;Ruj($TuGpg>&UhJ=K~pm9{%lOF{=%b!4Pv9Yn`gM&HzaMj*cGDDyPr{(;Nw zF;g3xynRE3saNAwRvvD%OUAk!k(T(cGyhsBb_Hjbh2mHUpu5>YNz9OyP5Nhy}iA^ zuCA_UGo8%*ll(TnP2*ZB{h+988+IQeDgDjO&Be3j{Wk16E>1Tw>$FP04w6H9ZU#hA zPE|C{J9{j&&y|ynGC;BB10+%->CXP3wSeE+@CQ)=0dZ~NnFhD4kO7fKKszU3-YG35 zC0!~!lZU7;Y~YsT^I7hLxbsv^VVmcoO0DGkp)8phWHbZ)l^UB**eQj8ACfL0DI_kh zdp>AKvBhPg@&ovE;rE3DDMw)fRxuy25aM7JFz08Z?7!1?G~IE&7iUI+y9vcYPIf;r zZdk{Ww0=Tl?`Y4K=3>26=mbom(Ry4;&|=+W^DGY&!{aZrq~NoAc_^D_S3 zx4wY^gtm+O_H_NBk;!A$!<~d%iqrFr9=T=|gj-N-dbwF`cl%PT@JDioC1T8B*zaEs z20M5WQ=-Iaq&oK0FfcRAUbGvcDSpFdSjhydVqFKJXafP}4(awU>)&i$e zXluxFFH~-*-W-SXY9*n%-;=k=pE-b0<-to&n zsOQB^Ov15gHClCYijw6J#Og3cxpXg;|qf>t>|7h8oZwuND zka3@#d@b#kX?8h^hX_`KZ1%)ozshDkLJ&(h`?(I>V>NI$9KrMtG9{~XLr%O07l27#_DU?(WMP`6 zGdnA5M&bOEl~*QPwWPZW$C;Tj9_~s z;MD^zj)I_@PH}rYCGF<*&aA-|200>THAI+d4L1>=&QWBvHL5Q!e}HgeRQMi`h^#W3 z9#q%u$X0K93O4-MmzeiXWo9H+`fJYr;&npM`Oi$oW<&N zywoZ%T4IYKvPu)IbU0~iv$L}lC+2@DfL!7sGFycBIj_~{tG|?Q`+#jH4T!c3?#~o~ z!=g;dliNGE{hS3tp7Xs0XgyFOj$GJTNwabf`@4%BL(j{t0#nx9DPvWTO1T#oP>i*l z=?LrCCl(AJiRhtDH_EC8AsUi^89Y)|&W`REmv%9B?_k?*_iU%bB=Gmh?I!m*`C2Mw zT4<{E`AA9L#NpPI?E*koo3Q8)&!}f^NV|%=a6JU0X?e|oe-8HA9qf~oOymnvV-Elm zGA>+9fUE#rjPqS`~BVh^(Gor%62$y@pDmu*?Igk;N z2X)}tsOheO+3fPw6118gRpTk4MTvKyEx;D;ysX9)n7kCO zYL$TX-U{ATKI@F2z|cD?;{>mk7$Tp}LY#j9yKk(msR1I>)?_v9*B12}E+R{kOZ##} zLmsF6Hn7Bli=vSk)wP9#FY282zc0=_YN^g&fDO5m6r>KOdpN^fk2WX7wmi;`zrUOT zD35UIB+PJ8$HyIFzb__F4;Fx%1 zli8>TQblTm4%V2?6=Yl|heJ0?iU$pjS)r@8BS&eox2{60V`c%AwgM;R-{?LU8Mc$G zD<5-}|E@aj1XZU?-@G7pF(0@oa@M;4`O3wdp5jl`Uvg=?{3?Ud7w7vVt(;R$r4w(* znA5+fU8Q>*1itYI=<)OWcazxT~EL~`P{M**IH^T%UHVVf@v-FmW`g>ka;_L5kN2FK-xU7Yl|&$l*T)fp*s zR0V>{Ac-WSy=daS7Pi;NPu-a18&~JMZcrW)AFqh{o<6-I-qB(o*S6ruPwhXT*tPqdEw}nRl8u#gTU*J)o2MD|jWy`SD=~Or7miT{rfcWG zFc(9C1Q7jENPKdQvJqq&GjZR)eFN5YHVES@gnsmfB_l9FOP$^>y1zH3di2rAQ9A%n{wVn z2#^zh0@5tGFCtd$vr|7j^(gkQiUK#EbiHgkmQ}cX4@rlhtYF}fwXOh?u#S-%P@G`s z-1C@yroQB>R{-hNjGFP5q)(}g%Q(yh;1T9>=GJWUSD>;_thf0@g(wc(9IvSDXA~J? z*@)E|w2xyKt9%$9R5NAA`jKZ14I?{RYF$yiZIp5Y&@AX{`VT5>j zXAdW3+YR`j^rxmVjQ9mm4Wm1B4mfQLq+q~kq}HJ7NVicINc+Kq`rA6`-%xhLHVf?` z#-!JZL#UyL3C+=f#xrWhhE$P9n4;2&CNJB~#b{1{Y+aosf<3d`s$)J=A)wO8)YNg6 zsMc@ZW;LhCe;Hdncl`U=?%GWtBXCgF(2nnLX~b0n4yZb+aPg0pL|vWawd$6x=B zvIJ^9IviD}b*NyBOyZCkb6JbaY6snfT*CyqWNe3P{mX((ePTA0kUy^hgAM76*s`uZX zwttW%EmE$S;#}^&WEr!vvSJ1l=NO^C|HKa6v*_8~xk7FBGJtNF829z{bz^`3hW)Q% zmoHz=7Q@}2%w4wScaXG~1&S~!-?ibWsQ{tavvyu6n^>7iRcg4MzWnm?a=OU6;<}E+ zh>P7Y+zx}u6j^U?x~1E{j#;aB9uq>Wwk<885mX6F&0<|YJq;?+qQ9jBx(icadbSQ6 z7ktsq5jS-k%rrG)5I>}xQWK>M!#hJM!;)`@hc~GvM47hsehpqW>E(*PeE|OvwpUl! zDJ{$hM@$5bP*ieSvA->wyaX1@&bjpOX>b4A{x6M%g~im&%*+@7%YSZ_9aj$YxcvhI zKG@FC?85NMhx}&hOG=9U*GNrgeyzS|Idu^AOQo3y~4KZ!5^9_{i8w@c3c85G)0SW_Dzy zWRNQ972+Y5aw)`bg-d`f3G^p>acp;3g)2d{H5vottQja5pel{KM=lJu4BpRcSl$(z zPP3{5UFrS&S=x4yw-?LEscWc4qXLWC@{H&X{CLHWwS*q_ChYeG239jnbrH+k>By-N z0Y<2hB>Ni+fK^cS2(mAziF5tAP@_5T6MP{=;RP5`05_V3xX$=PEbPs(csyRH<6(qG zX;}*T#JhZQjWgDH>ypY~;)d|FE{~1z;~P|9E+f+rlqSlyhY1ZYt)!=*@hnp*tu#*t z@epa?oqpAq;vTtGa2PP7!^=uth68TAx(20cDs5_-j2~m9t+wmnz=7kE9<3-bXR${Z zEPPm(iMsZUTa00cKm;|tZJ+r>j&FM$52mo#n{vp_s4nfAmSoxtWJdRK*!?p$>EyFC zMxxN5H!OhND6PR8QP&bd{r&xerh8B#D2>-gYMD=kP6GtYEeKaj#dpByaJ@0!Ysn|` zmMV0f5fjjnYFl+gYB1m|-+}KE{XYYlZ_HxC@acbMF$9EIE>0CkMnF`lz@~Czv~Xmi zf0shER)ur`W7@nrZxvPVrp%Ze@$XBaBLP>JRgH*?yr2m?2ZyZcQzq?|v^BuGYPB)i z{iea~prCXvB8Xj+F#6ZxT!CgX;3zi{ecwbFX9SB*ao^HoPDP=CLy&hW_Rg;;ea{~h z^wg^&7mW70H--fUGzc~`FR$wBah0XNG*l#}NLo~2G+b+y8vbT=SzJs;WF zId-U<4L=|%)%0T>XoNB6)+MMal$X1Q3Bh2Jwy!k9y_~veqfFyV&sOR9HoY}yOS<3Q zH15B6ICj@aU*Ed>qvn%`&z}RZ6?dI{2YHS!7hWj1be*?XOG|4IB|BBc4YZeWO*

      1Py^S`;#>S%_U8Nd9xUGVS()fGYmJwV7y}jZ-FOox4R{KJ^ z&(fpP;?1R3$?B`FrmAZ>5_pDXrLt?bdhu2rOJ5@;E3S?m(VI zlLmjjKA$^3e((JDPVdKgb=b4kiM?Hk-;ttw?~x1Itp&Yd{b9-$y-=fXlJCwffKtjs z+vdc$T(iZ*t*@~r_lA8THx0+?B_SH6L?J%?yyJDhG3=Jh-V{x1uEw&W)=b*!fWY!T zuet=8R~&@4`pFkm%%ZGN^(o(21`4(pkd|v+R;jU3#+?6vZZ{ESVUVHS#i#VkqVSCM z-!aMiuTWPp{~9Dp`kKrS`Lqxl7Z-9;upO%hB9TY|-HTRvXL#JBQ4L&|_S)6X>j(6q zA>^{pK0_^+0%fP(s$KyC{rQ39#*3Q@nQ$%(3nY-1Lv_~~L+o1Y0dxxP{EZ8nTY7rT oIUx-P;bcDlpAGlY?SFA5ULqfe>5_2<=C2@4Ro(lQD%O$z0U~M-n*aa+ diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/ZeroOrOneCaseRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/ZeroOrOneCaseRule.png new file mode 100644 index 0000000000000000000000000000000000000000..9432265747969d9ad7f3ac88161534ae80b9a870 GIT binary patch literal 5581 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 Date: Thu, 18 Jul 2024 23:59:39 -0400 Subject: [PATCH 185/258] Created PreventWastedDigitDirectRule and WastedDigitContradictionRule --- .../EliminateTheImpossibleDirectRule.java | 402 +++++++++--------- .../rules/PreventWastedDigitDirectRule.java | 44 ++ .../rules/WastedDigitContradictionRule.java | 166 ++++++++ ...e.png => PreventWastedDigitDirectRule.png} | Bin .../rules/WastedDigitContradictionRule.png | Bin 0 -> 2041 bytes 5 files changed, 411 insertions(+), 201 deletions(-) create mode 100644 src/main/java/edu/rpi/legup/puzzle/binary/rules/PreventWastedDigitDirectRule.java create mode 100644 src/main/java/edu/rpi/legup/puzzle/binary/rules/WastedDigitContradictionRule.java rename src/main/resources/edu/rpi/legup/images/binary/rules/{EliminateTheImpossibleDirectRule.png => PreventWastedDigitDirectRule.png} (100%) create mode 100644 src/main/resources/edu/rpi/legup/images/binary/rules/WastedDigitContradictionRule.png diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java index 117a639cb..02c1c2c31 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java @@ -1,201 +1,201 @@ -package edu.rpi.legup.puzzle.binary.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.binary.BinaryBoard; -import edu.rpi.legup.puzzle.binary.BinaryCell; -import edu.rpi.legup.puzzle.binary.BinaryType; - -import java.util.LinkedList; -import java.util.Queue; -import java.lang.Math.*; -import java.lang.reflect.Array; -import java.util.ArrayList; - -public class EliminateTheImpossibleDirectRule extends DirectRule { - private final String INVALID_USE_MESSAGE = "Number at cell is incorrect"; - - public EliminateTheImpossibleDirectRule() { - super( - "BINA-BASC-0004", - "Eliminate The Impossible", - "Out of the remaining empty cells in this row or column, this digit must go here, otherwise there will be a future contradiction", - "edu/rpi/legup/images/binary/rules/EliminateTheImpossibleDirectRule.png"); - } - - // Function to generate all binary strings - void generatePossibilitites(int spots, ArrayList possibilities, int zeroCount, int oneCount) - // This function generates all the possible combinations of 0s and 1s for a - // certain size, it does this - // by basically just counting from 0 to the number - 1, so if you want all the - // possible combinations for 3 - // spots, you can just count in binary from 0 to 7 (taking 3 spots, so from 000 - // to 111). To be practical, - // the function does not return an array with all the possibilities as an array, - // but populates the - // arraylist you pass in (possibilities) - { - if (zeroCount + oneCount != spots) { - System.out.println("INVALID INPUT"); - return; - } - - if (zeroCount == spots) { - String zero = ""; - for (int i = 0; i < spots; i++) { - zero = zero + "0"; - } - possibilities.add(zero); - - } - int count = (int) Math.pow(2, spots) - 1; - int finalLen = spots; - Queue q = new LinkedList(); - q.add("1"); - - while (count-- > 0) { - String s1 = q.peek(); - q.remove(); - - String newS1 = s1; - int curLen = newS1.length(); - int runFor = spots - curLen; - if (curLen < finalLen) { - for (int i = 0; i < runFor; i++) { - newS1 = "0" + newS1; - } - } - int curZeros = 0; - int curOnes = 0; - - for (int i = 0; i < spots; i++) { - if (newS1.charAt(i) == '0') { - curZeros++; - } - if (newS1.charAt(i) == '1') { - curOnes++; - } - } - - if (zeroCount == curZeros && oneCount == curOnes) { - possibilities.add(newS1); - } - String s2 = s1; - q.add(s1 + "0"); - q.add(s2 + "1"); - } - } - - @Override - public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - // This function should first check if there are three open spaces, if so, - // continue, else figure out - // how many spots are open, all the possible binary combinations that could be - // put there, and by - // analyzing the common factors, logically determine which number has a set - // spot, meaning that we know - // that a certain spot must be a zero or a one - - BinaryBoard origBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); - BinaryCell binaryCell = (BinaryCell) puzzleElement; - - //Getting the row where the user clicked - ArrayList row = origBoard.listRowCells(binaryCell.getLocation().y); - int size = row.size(); - int rowNumZeros = 0; - int rowNumOnes = 0; - - for (BinaryCell item : row) { - if (item.getType() == BinaryType.ZERO) { - rowNumZeros++; - } else if (item.getType() == BinaryType.ONE) { - rowNumOnes++; - } - } - - ArrayList rowResult = new ArrayList(); - - // To call generatePossibilitites(), you must call it and pass in the amount of - // unknown spots left, - // an ArrayList that will be populated with the possible results (in String - // form), the amount of zeros left and ones left - generatePossibilitites((size - rowNumZeros - rowNumOnes), rowResult, size / 2 - rowNumZeros, size / 2 - rowNumOnes); - - // Create deep copies of each row - ArrayList> rowCopies = new ArrayList<>(); - for (int i = 0; i < rowResult.size(); i++) { - ArrayList newRow = new ArrayList<>(); - for (BinaryCell cell : row) { - newRow.add(cell.copy()); - } - rowCopies.add(newRow); - } - - System.out.println("Number of possible binary combinations: " + rowCopies.size()); - - ArrayList> nonContraRows = new ArrayList<>(); - int rowIdx = 0; - for(ArrayList curRow : rowCopies){ - int charIdx = 0; - System.out.println(rowResult.get(rowIdx)); - for(int i = 0; i < curRow.size(); i++) { - if (curRow.get(i).getData() == 2) { - if (rowResult.get(rowIdx).charAt(charIdx) == '0') { - curRow.get(i).setData(0); - } - else if (rowResult.get(rowIdx).charAt(charIdx) == '1') { - curRow.get(i).setData(1); - } - charIdx++; - } - System.out.print(curRow.get(i).getData() + " "); - } - - boolean threeAdjacent = false; - int count = 1; - for(int i = 1; i < curRow.size(); i++) { - if (curRow.get(i).getData() == curRow.get(i-1).getData()) { - count++; - if (count == 3) { - threeAdjacent = true; - break; - } - } else { - count = 1; - } - } - - if (!threeAdjacent) { - nonContraRows.add(curRow); - } - - rowIdx++; - System.out.println(); - } - - System.out.println("Number of non contradiction rows: " + nonContraRows.size()); - int colNum = binaryCell.getLocation().x; - boolean invalid = false; - for(int i = 0; i < nonContraRows.size(); i++) { - if (nonContraRows.get(i).get(colNum).getData() != binaryCell.getData()) { - invalid = true; - break; - } - } - - if (!invalid) { - return null; - } - - return "Grouping of Three Ones or Zeros not found"; - - } - - @Override - public Board getDefaultBoard(TreeNode node) { - return null; - } -} +//package edu.rpi.legup.puzzle.binary.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.binary.BinaryBoard; +//import edu.rpi.legup.puzzle.binary.BinaryCell; +//import edu.rpi.legup.puzzle.binary.BinaryType; +// +//import java.util.LinkedList; +//import java.util.Queue; +//import java.lang.Math.*; +//import java.lang.reflect.Array; +//import java.util.ArrayList; +// +//public class EliminateTheImpossibleDirectRule extends DirectRule { +// private final String INVALID_USE_MESSAGE = "Number at cell is incorrect"; +// +// public EliminateTheImpossibleDirectRule() { +// super( +// "BINA-BASC-0004", +// "Eliminate The Impossible", +// "Out of the remaining empty cells in this row or column, this digit must go here, otherwise there will be a future contradiction", +// "edu/rpi/legup/images/binary/rules/EliminateTheImpossibleDirectRule.png"); +// } +// +// // Function to generate all binary strings +// void generatePossibilitites(int spots, ArrayList possibilities, int zeroCount, int oneCount) +// // This function generates all the possible combinations of 0s and 1s for a +// // certain size, it does this +// // by basically just counting from 0 to the number - 1, so if you want all the +// // possible combinations for 3 +// // spots, you can just count in binary from 0 to 7 (taking 3 spots, so from 000 +// // to 111). To be practical, +// // the function does not return an array with all the possibilities as an array, +// // but populates the +// // arraylist you pass in (possibilities) +// { +// if (zeroCount + oneCount != spots) { +// System.out.println("INVALID INPUT"); +// return; +// } +// +// if (zeroCount == spots) { +// String zero = ""; +// for (int i = 0; i < spots; i++) { +// zero = zero + "0"; +// } +// possibilities.add(zero); +// +// } +// int count = (int) Math.pow(2, spots) - 1; +// int finalLen = spots; +// Queue q = new LinkedList(); +// q.add("1"); +// +// while (count-- > 0) { +// String s1 = q.peek(); +// q.remove(); +// +// String newS1 = s1; +// int curLen = newS1.length(); +// int runFor = spots - curLen; +// if (curLen < finalLen) { +// for (int i = 0; i < runFor; i++) { +// newS1 = "0" + newS1; +// } +// } +// int curZeros = 0; +// int curOnes = 0; +// +// for (int i = 0; i < spots; i++) { +// if (newS1.charAt(i) == '0') { +// curZeros++; +// } +// if (newS1.charAt(i) == '1') { +// curOnes++; +// } +// } +// +// if (zeroCount == curZeros && oneCount == curOnes) { +// possibilities.add(newS1); +// } +// String s2 = s1; +// q.add(s1 + "0"); +// q.add(s2 + "1"); +// } +// } +// +// @Override +// public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { +// // This function should first check if there are three open spaces, if so, +// // continue, else figure out +// // how many spots are open, all the possible binary combinations that could be +// // put there, and by +// // analyzing the common factors, logically determine which number has a set +// // spot, meaning that we know +// // that a certain spot must be a zero or a one +// +// BinaryBoard origBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); +// BinaryCell binaryCell = (BinaryCell) puzzleElement; +// +// //Getting the row where the user clicked +// ArrayList row = origBoard.listRowCells(binaryCell.getLocation().y); +// int size = row.size(); +// int rowNumZeros = 0; +// int rowNumOnes = 0; +// +// for (BinaryCell item : row) { +// if (item.getType() == BinaryType.ZERO) { +// rowNumZeros++; +// } else if (item.getType() == BinaryType.ONE) { +// rowNumOnes++; +// } +// } +// +// ArrayList rowResult = new ArrayList(); +// +// // To call generatePossibilitites(), you must call it and pass in the amount of +// // unknown spots left, +// // an ArrayList that will be populated with the possible results (in String +// // form), the amount of zeros left and ones left +// generatePossibilitites((size - rowNumZeros - rowNumOnes), rowResult, size / 2 - rowNumZeros, size / 2 - rowNumOnes); +// +// // Create deep copies of each row +// ArrayList> rowCopies = new ArrayList<>(); +// for (int i = 0; i < rowResult.size(); i++) { +// ArrayList newRow = new ArrayList<>(); +// for (BinaryCell cell : row) { +// newRow.add(cell.copy()); +// } +// rowCopies.add(newRow); +// } +// +// System.out.println("Number of possible binary combinations: " + rowCopies.size()); +// +// ArrayList> nonContraRows = new ArrayList<>(); +// int rowIdx = 0; +// for(ArrayList curRow : rowCopies){ +// int charIdx = 0; +// System.out.println(rowResult.get(rowIdx)); +// for(int i = 0; i < curRow.size(); i++) { +// if (curRow.get(i).getData() == 2) { +// if (rowResult.get(rowIdx).charAt(charIdx) == '0') { +// curRow.get(i).setData(0); +// } +// else if (rowResult.get(rowIdx).charAt(charIdx) == '1') { +// curRow.get(i).setData(1); +// } +// charIdx++; +// } +// System.out.print(curRow.get(i).getData() + " "); +// } +// +// boolean threeAdjacent = false; +// int count = 1; +// for(int i = 1; i < curRow.size(); i++) { +// if (curRow.get(i).getData() == curRow.get(i-1).getData()) { +// count++; +// if (count == 3) { +// threeAdjacent = true; +// break; +// } +// } else { +// count = 1; +// } +// } +// +// if (!threeAdjacent) { +// nonContraRows.add(curRow); +// } +// +// rowIdx++; +// System.out.println(); +// } +// +// System.out.println("Number of non contradiction rows: " + nonContraRows.size()); +// int colNum = binaryCell.getLocation().x; +// boolean invalid = false; +// for(int i = 0; i < nonContraRows.size(); i++) { +// if (nonContraRows.get(i).get(colNum).getData() != binaryCell.getData()) { +// invalid = true; +// break; +// } +// } +// +// if (!invalid) { +// return null; +// } +// +// return "This cell can either be a 0 or a 1"; +// +// } +// +// @Override +// public Board getDefaultBoard(TreeNode node) { +// return null; +// } +//} diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/PreventWastedDigitDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/PreventWastedDigitDirectRule.java new file mode 100644 index 000000000..28da47833 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/PreventWastedDigitDirectRule.java @@ -0,0 +1,44 @@ +package edu.rpi.legup.puzzle.binary.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.binary.BinaryBoard; +import edu.rpi.legup.puzzle.binary.BinaryCell; + +public class PreventWastedDigitDirectRule extends DirectRule { + + private final String INVALID_USE_MESSAGE = "Number at cell is incorrect"; + + public PreventWastedDigitDirectRule() { + super( + "BINA-BASC-0004", + "Prevent Wasted Digit", + "If somewhere in a row/col a future trio must be blocked, insert th", + "edu/rpi/legup/images/binary/rules/PreventWastedDigitDirectRule.png"); + } + + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + BinaryBoard origBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); + WastedDigitContradictionRule contraRule = new WastedDigitContradictionRule(); + BinaryCell binaryCell = (BinaryCell) puzzleElement; + BinaryBoard modified = origBoard.copy(); + + modified.getPuzzleElement(puzzleElement).setData(Math.abs(binaryCell.getData() - 1)); + + if (contraRule.checkContradictionAt(modified, binaryCell) == null) { + return null; + } + + return "Wasted Digit Found"; + } + + @Override + public Board getDefaultBoard(TreeNode node) { + return null; + } + + +} diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/WastedDigitContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/WastedDigitContradictionRule.java new file mode 100644 index 000000000..720cdb760 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/WastedDigitContradictionRule.java @@ -0,0 +1,166 @@ +package edu.rpi.legup.puzzle.binary.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.binary.BinaryBoard; +import edu.rpi.legup.puzzle.binary.BinaryCell; +import edu.rpi.legup.puzzle.binary.BinaryType; + +import java.util.ArrayList; + +public class WastedDigitContradictionRule extends ContradictionRule { + private final String NO_CONTRADICTION_MESSAGE = "Does not contain a contradiction at this index"; + + public WastedDigitContradictionRule() { + super( + "BINA-CONT-0004", + "Wasted Digit", + "There exists a cell in this row/column that allocates a digit unnecessarily and will cause a future trio to appear", + "edu/rpi/legup/images/binary/rules/WastedDigitContradictionRule.png"); + } + + + private int calculateNeededZeros(int leftVal, int rightVal, int emptyCellsInCurSec) { + int leftCopy = leftVal; + int rightCopy = rightVal; + if (leftCopy == -1) { + leftCopy = 0; + } + if (rightCopy == -1) { + rightCopy = 0; + } + return ((emptyCellsInCurSec + leftCopy + rightCopy) / 3); + } + + private int calculateNeededOnes(int leftVal, int rightVal, int emptyCellsInCurSec) { + int leftCopy = leftVal; + int rightCopy = rightVal; + if (leftCopy == -1) { + leftCopy = 1; + } + if (rightCopy == -1) { + rightCopy = 1; + } + return ((emptyCellsInCurSec + (1 - leftCopy) + (1 - rightCopy)) / 3); + } + + private int convertTypeToInt(BinaryType type) { + if (type.equals(BinaryType.ZERO)) { + return 0; + } else if (type.equals(BinaryType.ONE)) { + return 1; + } else { + return -1; + } + } + + private String checkSequence(ArrayList seq) { + int numZeros = 0; + int numOnes = 0; + boolean emptyCell = false; + int emptyCellsInCurSec = 0; + int neededZeros = 0; + int neededOnes = 0; + + for (int i = 0; i < seq.size(); i++) { + if (seq.get(i).equals(BinaryType.ZERO) || seq.get(i).equals(BinaryType.ONE)) { + if (seq.get(i).equals(BinaryType.ZERO)) { + numZeros++; + } else if (seq.get(i).equals(BinaryType.ONE)) { + numOnes++; + } + + if (emptyCell) { + if (emptyCellsInCurSec > 1) { + if (i-emptyCellsInCurSec-1 < 0) { + int leftVal = -1; + int rightVal = convertTypeToInt(seq.get(i)); + neededZeros += calculateNeededZeros(leftVal, rightVal, emptyCellsInCurSec); + neededOnes += calculateNeededOnes(leftVal, rightVal, emptyCellsInCurSec); +// System.out.println("NEEDED ZEROS: " + calculateNeededZeros(leftVal, rightVal, emptyCellsInCurSec); +// System.out.println("NEEDED ONES: " + calculateNeededOnes(leftVal, rightVal, emptyCellsInCurSec); +// System.out.println("NUM EMPTY BEFORE THIS : " + emptyCellsInCurSec + ", surrounded by " + leftVal + " and " + rightVal); + } else { + int leftVal = convertTypeToInt(seq.get(i-emptyCellsInCurSec-1)); + int rightVal = convertTypeToInt(seq.get(i)); + neededZeros += calculateNeededZeros(leftVal, rightVal, emptyCellsInCurSec); + neededOnes += calculateNeededOnes(leftVal, rightVal, emptyCellsInCurSec); +// System.out.println("NEEDED ZEROS: " + calculateNeededZeros(leftVal, rightVal, emptyCellsInCurSec); +// System.out.println("NEEDED ONES: " + calculateNeededOnes(leftVal, rightVal, emptyCellsInCurSec); +// System.out.println("NUM EMPTY BEFORE THIS : " + emptyCellsInCurSec + ", surrounded by " + leftVal + " and " + rightVal); + } + } + emptyCell = false; + emptyCellsInCurSec = 0; + } + } else { + if (!emptyCell) { + emptyCell = true; + } + emptyCellsInCurSec++; + } + //System.out.println(seq.get(i).toString()); + } + + // check if empty cells surrounded by out of bounds + if (emptyCell) { + if (emptyCellsInCurSec > 1) { + if (seq.size()-1-emptyCellsInCurSec-1 < 0) { + int leftVal = -1; + int rightVal = -1; + neededZeros += calculateNeededZeros(leftVal, rightVal, emptyCellsInCurSec); + neededOnes += calculateNeededOnes(leftVal, rightVal, emptyCellsInCurSec); +// System.out.println("NEEDED ZEROS: " + calculateNeededZeros(leftVal, rightVal, emptyCellsInCurSec); +// System.out.println("NEEDED ONES: " + calculateNeededOnes(leftVal, rightVal, emptyCellsInCurSec); +// System.out.println("NUM EMPTY BEFORE THIS : " + emptyCellsInCurSec+ ", surrounded by " + leftVal + " and " + rightVal); + } else { + int leftVal = convertTypeToInt(seq.get(seq.size()-1-emptyCellsInCurSec)); + int rightVal = -1; + neededZeros += calculateNeededZeros(leftVal, rightVal, emptyCellsInCurSec); + neededOnes += calculateNeededOnes(leftVal, rightVal, emptyCellsInCurSec); +// System.out.println("NEEDED ZEROS: " + calculateNeededZeros(leftVal, rightVal, emptyCellsInCurSec); +// System.out.println("NEEDED ONES: " + calculateNeededOnes(leftVal, rightVal, emptyCellsInCurSec); +// System.out.println("NUM EMPTY BEFORE THIS : " + emptyCellsInCurSec+ ", surrounded by " + leftVal + " and " + rightVal); + } + } + emptyCell = false; + emptyCellsInCurSec = 0; + } + +// if (numZeros + neededZeros > seq.size()/2) { +// System.out.println("NEED TOO MANY ZEROS"); +// return null; +// } +// +// if (numOnes + neededOnes > seq.size()/2) { +// System.out.println("NEED TOO MANY ONES"); +// return null; +// } + + if ((numZeros + neededZeros > seq.size()/2) || (numOnes + neededOnes > seq.size()/2)) { + return null; + } + + return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE; + } + + @Override + public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { + + BinaryBoard binaryBoard = (BinaryBoard) board; + BinaryCell cell = (BinaryCell) binaryBoard.getPuzzleElement(puzzleElement); + + ArrayList row = binaryBoard.getRowTypes(cell.getLocation().y); + if (checkSequence(row) == null) { + return null; + } + + ArrayList col = binaryBoard.getColTypes(cell.getLocation().x); + if (checkSequence(col) == null) { + return null; + } + + return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE; + } +} diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/EliminateTheImpossibleDirectRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/PreventWastedDigitDirectRule.png similarity index 100% rename from src/main/resources/edu/rpi/legup/images/binary/rules/EliminateTheImpossibleDirectRule.png rename to src/main/resources/edu/rpi/legup/images/binary/rules/PreventWastedDigitDirectRule.png diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/WastedDigitContradictionRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/WastedDigitContradictionRule.png new file mode 100644 index 0000000000000000000000000000000000000000..c101b734f32785071ef7bd4a5a1a8c0fd98fbbc7 GIT binary patch literal 2041 zcmai#eK-?pAIIld^B#(tFiCWJI(A}1-sYvHNhFLT#;l``4hdskwxTIph>p_HnjNoC zDlSQj`Y)|K5z?!^~F#Q zz5+`8fl_A$wJ4%nblkZD&cRFzQ&En4qBdhQ*osJJ}P z3|Z!UH-dX+mz-^7Z|~{v@9!`JlAO*v#Iih>M$R$F(Xj%X;tsq2iOr<6sOpk+_kqli znjRGJ-;LIgoT0k&X+QqfqBv->(KqOqw4+ZO-UX1aLaS_812V`dAfK;UW%xF3(88&<0+1S{)MJi?Shd!^#rvBjZ z!e=A~V6f`*#>PZGq%33gci9W*6{1*Hn-ycapk+M=>iu;%i=-&beHZK7B&M~-$rnmii%}82m}KU$}Hupi$R^JoJPXp zn=EY;skJS~ESyX9q|@nmiO_0eX|4dVQyY%>vngre-V;Lb7P97f{Cjn}bDAI}L5=1= z8*F29F?U^FqqZTt%ShxGKjeK0=tOC5VyCy{tH}n2W}r-`lu!Ffn`@^T)GS@)+?36= zIP`~o9q(V=o!eah{1iXuhq<7V^e@qc(DpS;y{Rn5y$A8q1}L@nmqhRV9@D!gpxyMj z--rvOg6wQ~v!D|)$WZ&_5QPulKd4c<+Rbnoe+ijVioV4Xx%iuG@IWC?Q0u=3YQm8z zDGl*Qx3;!?>a^gKQt4sm)TOS}j%(t!T+^RQUcA6;CA}sH0#*06R(RcgP+xDecsL)e z*{>5+6Ncs*<jcgWslSz1`Q>v^KMP(77%Np$s-xE++q zNtTsfP$u3CJvjoKILeM4_ZjDs65@4PBTXrF^%Q`evU@r+oX0$eqHH$rkHBJ^#d23u zRuuU$?hjEPEU@}a1(BOwbG_$={-OIF8li^$(0ntVdcnZWR*_H5d^rhi_96RBK!yg9OcnFJCV zDp_efQA}&9Dv8iA^$m>vA@~WBw=pA*R@~TIyH>v?KWZ_g^J@l5a|tj?eWunYMln~w zLM&q;boA$av#@JyPsB4+!On3ugf)AfW=#!@(KbQk9PNvjPPm|G#OoPXg8zI%xigPlM($su77%3FV|Zb(;e9sq8ahw zA8_~WqqD)n!6dc7F5rr-eCjKxF&|;-bnTfPQf`3grMaWF6d1x&omIa+uBjpH0uFYD zW&Wz?&^Y7$Uc>qRcA@@8ia!U@nq2r}IMYiaC5`FrGdAsd7BhlZAS&Wf7|p8$+>&c( zhv#bv^U|DRAJ*0R7u#*~9bDZQl~tDs|CvGxNRQ#L?R~54Ar=8syN$cTTCQJ>QP#06 zneqfeu`XvVzPKpM4VWemgkN3GD*Ry{OqG3n=VJ_iweXpjIg6RZyNJ) z6G8Q2L3P5HubLDp2(L_K95W!92{H Date: Thu, 18 Jul 2024 23:59:59 -0400 Subject: [PATCH 186/258] Refactored ThreeAdjacentContradictionRule to TrioContradictionRule --- .../puzzle/binary/rules/OneTileGapDirectRule.java | 5 ++--- .../puzzle/binary/rules/SurroundPairDirectRule.java | 5 ++--- ...adictionRule.java => TrioContradictionRule.java} | 8 ++++---- .../puzzle/binary/rules/binary_reference_sheet.txt | 8 ++++---- ...tradictionRule.png => TrioContradictionRule.png} | Bin 5 files changed, 12 insertions(+), 14 deletions(-) rename src/main/java/edu/rpi/legup/puzzle/binary/rules/{ThreeAdjacentContradictionRule.java => TrioContradictionRule.java} (96%) rename src/main/resources/edu/rpi/legup/images/binary/rules/{ThreeAdjacentContradictionRule.png => TrioContradictionRule.png} (100%) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java index fb837a771..383e4b72a 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java @@ -2,7 +2,6 @@ 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.rules.DirectRule; import edu.rpi.legup.model.tree.TreeNode; import edu.rpi.legup.model.tree.TreeTransition; @@ -23,7 +22,7 @@ public OneTileGapDirectRule() { @Override public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { BinaryBoard origBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); - ThreeAdjacentContradictionRule contraRule = new ThreeAdjacentContradictionRule(); + TrioContradictionRule contraRule = new TrioContradictionRule(); BinaryCell binaryCell = (BinaryCell) puzzleElement; BinaryBoard modified = origBoard.copy(); @@ -33,7 +32,7 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem return null; } - return "Grouping of Three Ones or Zeros not found"; + return "Trio Found"; } @Override diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java index 15e984faf..6b8ed83be 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java @@ -2,7 +2,6 @@ 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.rules.DirectRule; import edu.rpi.legup.model.tree.TreeNode; import edu.rpi.legup.model.tree.TreeTransition; @@ -21,7 +20,7 @@ public SurroundPairDirectRule() { public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { BinaryBoard origBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); - ThreeAdjacentContradictionRule contraRule = new ThreeAdjacentContradictionRule(); + TrioContradictionRule contraRule = new TrioContradictionRule(); BinaryCell binaryCell = (BinaryCell) puzzleElement; BinaryBoard modified = origBoard.copy(); @@ -31,7 +30,7 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem return null; } - return "Grouping of Three Ones or Zeros not found"; + return "Trio Found"; } @Override diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/TrioContradictionRule.java similarity index 96% rename from src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java rename to src/main/java/edu/rpi/legup/puzzle/binary/rules/TrioContradictionRule.java index 85fcc32ce..20df01539 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/TrioContradictionRule.java @@ -7,17 +7,17 @@ import edu.rpi.legup.puzzle.binary.BinaryCell; import edu.rpi.legup.puzzle.binary.BinaryType; -public class ThreeAdjacentContradictionRule extends ContradictionRule { +public class TrioContradictionRule 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 zero or one"; - public ThreeAdjacentContradictionRule() { + public TrioContradictionRule() { super( "BINA-CONT-0001", - "Three Adjacent", + "Trio", "There must not be three adjacent zeros or three adjacent ones in a row or column", - "edu/rpi/legup/images/binary/rules/ThreeAdjacentContradictionRule.png"); + "edu/rpi/legup/images/binary/rules/TrioContradictionRule.png"); } public BinaryCell[] getCellsXAway(Board board, PuzzleElement puzzleElement, int x) { diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/binary_reference_sheet.txt b/src/main/java/edu/rpi/legup/puzzle/binary/rules/binary_reference_sheet.txt index 74358a767..6b21e31d0 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/binary_reference_sheet.txt +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/binary_reference_sheet.txt @@ -1,10 +1,10 @@ BINA-BASC-0001 : SurroundPairDirectRule BINA-BASC-0002 : OneTileGapDirectRule BINA-BASC-0003 : CompleteRowColumnDirectRule -BINA-BASC-0004 : EliminateTheImpossibleDirectRule +BINA-BASC-0004 : PreventWastedDigitDirectRule -BINA-CONT-0001 : ThreeAdjacentContradictionRule -BINA-CONT-0002 : UnbalancedRowOrColumnContradictionRule -BINA-CONT-0003 : DuplicateRowsOrColumnsContradictionRule +BINA-CONT-0001 : TrioContradictionRule +BINA-CONT-0002 : UnbalancedRowColumnContradictionRule +BINA-CONT-0003 : DuplicateRowsColumnsContradictionRule BINA-CASE-0001 : OneOrZeroCaseRule \ No newline at end of file diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/ThreeAdjacentContradictionRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/TrioContradictionRule.png similarity index 100% rename from src/main/resources/edu/rpi/legup/images/binary/rules/ThreeAdjacentContradictionRule.png rename to src/main/resources/edu/rpi/legup/images/binary/rules/TrioContradictionRule.png From 7d9d2d52bc949cea530a67c5048f0e58318eb6d8 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Fri, 19 Jul 2024 11:40:32 -0400 Subject: [PATCH 187/258] Refactored PreventWastedDigitDirectRule to SaveBlockerDirectRule, WastedDigitContradictionRule to WastedBlockerContradictionRule --- .../java/edu/rpi/legup/puzzle/binary/Binary.java | 2 +- ...itDirectRule.java => SaveBlockerDirectRule.java} | 12 ++++++------ ...ule.java => WastedBlockerContradictionRule.java} | 8 ++++---- .../puzzle/binary/rules/binary_reference_sheet.txt | 5 +++-- ...igitDirectRule.png => SaveBlockerDirectRule.png} | Bin ...nRule.png => WastedBlockerContradictionRule.png} | Bin 6 files changed, 14 insertions(+), 13 deletions(-) rename src/main/java/edu/rpi/legup/puzzle/binary/rules/{PreventWastedDigitDirectRule.java => SaveBlockerDirectRule.java} (73%) rename src/main/java/edu/rpi/legup/puzzle/binary/rules/{WastedDigitContradictionRule.java => WastedBlockerContradictionRule.java} (96%) rename src/main/resources/edu/rpi/legup/images/binary/rules/{PreventWastedDigitDirectRule.png => SaveBlockerDirectRule.png} (100%) rename src/main/resources/edu/rpi/legup/images/binary/rules/{WastedDigitContradictionRule.png => WastedBlockerContradictionRule.png} (100%) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/Binary.java b/src/main/java/edu/rpi/legup/puzzle/binary/Binary.java index 42fa27474..d5d018112 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/Binary.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/Binary.java @@ -66,6 +66,6 @@ public void onBoardChange(Board board) {} */ @Override public boolean isValidDimensions(int rows, int columns){ - return rows >= 4 && rows % 2 == 0 && rows == columns; + return rows >= 2 && rows % 2 == 0 && rows == columns; } } diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/PreventWastedDigitDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/SaveBlockerDirectRule.java similarity index 73% rename from src/main/java/edu/rpi/legup/puzzle/binary/rules/PreventWastedDigitDirectRule.java rename to src/main/java/edu/rpi/legup/puzzle/binary/rules/SaveBlockerDirectRule.java index 28da47833..24306e6c4 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/PreventWastedDigitDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/SaveBlockerDirectRule.java @@ -8,21 +8,21 @@ import edu.rpi.legup.puzzle.binary.BinaryBoard; import edu.rpi.legup.puzzle.binary.BinaryCell; -public class PreventWastedDigitDirectRule extends DirectRule { +public class SaveBlockerDirectRule extends DirectRule { private final String INVALID_USE_MESSAGE = "Number at cell is incorrect"; - public PreventWastedDigitDirectRule() { + public SaveBlockerDirectRule() { super( "BINA-BASC-0004", - "Prevent Wasted Digit", - "If somewhere in a row/col a future trio must be blocked, insert th", - "edu/rpi/legup/images/binary/rules/PreventWastedDigitDirectRule.png"); + "Save Blocker", + "If a future trio could appear in this row/col, save the digit that could block that trio", + "edu/rpi/legup/images/binary/rules/SaveBlockerDirectRule.png"); } public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { BinaryBoard origBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); - WastedDigitContradictionRule contraRule = new WastedDigitContradictionRule(); + WastedBlockerContradictionRule contraRule = new WastedBlockerContradictionRule(); BinaryCell binaryCell = (BinaryCell) puzzleElement; BinaryBoard modified = origBoard.copy(); diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/WastedDigitContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/WastedBlockerContradictionRule.java similarity index 96% rename from src/main/java/edu/rpi/legup/puzzle/binary/rules/WastedDigitContradictionRule.java rename to src/main/java/edu/rpi/legup/puzzle/binary/rules/WastedBlockerContradictionRule.java index 720cdb760..f45eb5dba 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/WastedDigitContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/WastedBlockerContradictionRule.java @@ -9,15 +9,15 @@ import java.util.ArrayList; -public class WastedDigitContradictionRule extends ContradictionRule { +public class WastedBlockerContradictionRule extends ContradictionRule { private final String NO_CONTRADICTION_MESSAGE = "Does not contain a contradiction at this index"; - public WastedDigitContradictionRule() { + public WastedBlockerContradictionRule() { super( "BINA-CONT-0004", - "Wasted Digit", + "Wasted Blocker", "There exists a cell in this row/column that allocates a digit unnecessarily and will cause a future trio to appear", - "edu/rpi/legup/images/binary/rules/WastedDigitContradictionRule.png"); + "edu/rpi/legup/images/binary/rules/WastedBlockerContradictionRule.png"); } diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/binary_reference_sheet.txt b/src/main/java/edu/rpi/legup/puzzle/binary/rules/binary_reference_sheet.txt index 6b21e31d0..b6d5c094d 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/binary_reference_sheet.txt +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/binary_reference_sheet.txt @@ -1,10 +1,11 @@ BINA-BASC-0001 : SurroundPairDirectRule BINA-BASC-0002 : OneTileGapDirectRule BINA-BASC-0003 : CompleteRowColumnDirectRule -BINA-BASC-0004 : PreventWastedDigitDirectRule +BINA-BASC-0004 : SaveBlockerDirectRule BINA-CONT-0001 : TrioContradictionRule BINA-CONT-0002 : UnbalancedRowColumnContradictionRule BINA-CONT-0003 : DuplicateRowsColumnsContradictionRule +BINA-CONT-0004 : WastedBlockerContradictionRule -BINA-CASE-0001 : OneOrZeroCaseRule \ No newline at end of file +BINA-CASE-0001 : ZeroOrOneCaseRule \ No newline at end of file diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/PreventWastedDigitDirectRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/SaveBlockerDirectRule.png similarity index 100% rename from src/main/resources/edu/rpi/legup/images/binary/rules/PreventWastedDigitDirectRule.png rename to src/main/resources/edu/rpi/legup/images/binary/rules/SaveBlockerDirectRule.png diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/WastedDigitContradictionRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/WastedBlockerContradictionRule.png similarity index 100% rename from src/main/resources/edu/rpi/legup/images/binary/rules/WastedDigitContradictionRule.png rename to src/main/resources/edu/rpi/legup/images/binary/rules/WastedBlockerContradictionRule.png From e8bd65eeb7da140d28f9bac30ba4b12ed2d42109 Mon Sep 17 00:00:00 2001 From: summerhenson Date: Fri, 19 Jul 2024 14:11:30 -0400 Subject: [PATCH 188/258] Test case files for Columns Within Rows direct rule --- .../ColumnsWithinRegionsDirectRuleTest.java | 2 + .../ColumnsWithinRowsDirectRuleTest.java | 29 ++++++++++++++ .../ColumnsWithinRowsDirectRule/OneColumn | 29 ++++++++++++++ .../ColumnsWithinRowsDirectRule/TwoColumns | 29 ++++++++++++++ .../TwoColumnsStarOverlap | 40 +++++++++++++++++++ 5 files changed, 129 insertions(+) create mode 100644 src/test/java/puzzles/starbattle/rules/ColumnsWithinRowsDirectRuleTest.java create mode 100644 src/test/resources/puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/OneColumn create mode 100644 src/test/resources/puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/TwoColumns create mode 100644 src/test/resources/puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/TwoColumnsStarOverlap diff --git a/src/test/java/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRuleTest.java b/src/test/java/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRuleTest.java index e834828ad..2f9ed2596 100644 --- a/src/test/java/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRuleTest.java +++ b/src/test/java/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRuleTest.java @@ -147,6 +147,8 @@ public void ColumnsWithinRegionsDirectRule_TwoColumns() } } + /* Wrote this to figure out the specifics of how the rule is functioning - might change + * what the expected result is. */ @Test public void ColumnsWithinRegionsDirectRule_TwoColumnsWaitAMinute() throws InvalidFileFormatException { diff --git a/src/test/java/puzzles/starbattle/rules/ColumnsWithinRowsDirectRuleTest.java b/src/test/java/puzzles/starbattle/rules/ColumnsWithinRowsDirectRuleTest.java new file mode 100644 index 000000000..16b7452a0 --- /dev/null +++ b/src/test/java/puzzles/starbattle/rules/ColumnsWithinRowsDirectRuleTest.java @@ -0,0 +1,29 @@ +package puzzles.starbattle.rules; + +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +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.ColumnsWithinRowsDirectRule; +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.awt.*; + +public class ColumnsWithinRowsDirectRuleTest { + + private static final ColumnsWithinRowsDirectRule RULE = new ColumnsWithinRowsDirectRule(); + private static StarBattle starbattle; + + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + starbattle = new StarBattle(); + } +} diff --git a/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/OneColumn b/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/OneColumn new file mode 100644 index 000000000..9a4dccefd --- /dev/null +++ b/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/OneColumn @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/TwoColumns b/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/TwoColumns new file mode 100644 index 000000000..5c13d38e6 --- /dev/null +++ b/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/TwoColumns @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/TwoColumnsStarOverlap b/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/TwoColumnsStarOverlap new file mode 100644 index 000000000..fac44ff20 --- /dev/null +++ b/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/TwoColumnsStarOverlap @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From d2347f3401bfe88e5be5f54dce7704f294eea558 Mon Sep 17 00:00:00 2001 From: offline171 <146153141+offline171@users.noreply.github.com> Date: Fri, 19 Jul 2024 14:13:35 -0400 Subject: [PATCH 189/258] EmptyAdjacentDirectRule added Basic form of EmptyAdjacentDirectRule implemented, tests coming soon --- .../rules/EmptyAdjacentDirectRule.java | 76 +++++++++++++++++++ .../rules/starbattle_reference_sheet.txt | 1 + 2 files changed, 77 insertions(+) create mode 100644 src/main/java/edu/rpi/legup/puzzle/starbattle/rules/EmptyAdjacentDirectRule.java diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/EmptyAdjacentDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/EmptyAdjacentDirectRule.java new file mode 100644 index 000000000..93c600dd2 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/EmptyAdjacentDirectRule.java @@ -0,0 +1,76 @@ +package edu.rpi.legup.puzzle.starbattle.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.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; + +public class EmptyAdjacentDirectRule extends DirectRule { + + public EmptyAdjacentDirectRule() { + super( + "STBL-BASC-0010", + "Empty Adjacent", + "Tiles next to other tiles that need to contain a star to reach the puzzle number for their region/row/column need to be blacked out.", + "edu/rpi/legup/images/starbattle/rules/EmptyAdjacent.png"); + } + + /** + * 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) { + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleBoard origBoard = (StarBattleBoard) transition.getParents().get(0).getBoard(); + ContradictionRule contraRule = new TooFewStarsContradictionRule(); + + StarBattleCell cell = (StarBattleCell) board.getPuzzleElement(puzzleElement); + + if (cell.getType() != StarBattleCellType.BLACK) { + return "Only black cells are allowed for this rule!"; + } + + StarBattleBoard modified = (StarBattleBoard) origBoard.copy(); + int X = cell.getLocation().x; + int Y = cell.getLocation().y; + for(int i = X-1; i <= X+1; i++){ + for(int j = Y-1; j <= Y+1; j++){ + if(i < 0 || i >= modified.getPuzzleNumber() || j < 0 || j >= modified.getPuzzleNumber()){ + continue; + } //else + if(modified.getCell(i,j).getType() == StarBattleCellType.UNKNOWN){ + modified.getCell(i,j).setData(StarBattleCellType.BLACK.value); + }//only modify empty cells, star cells remain as is and black cells ignored in case they're unmodifiable + } + } + + if (contraRule.checkContradictionAt(modified, puzzleElement) != null) { + return "Black cells must be placed adjacent to a tile(s) where a star is needed!"; + } + return null; + } + + /** + * 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) { + + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/starbattle_reference_sheet.txt b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/starbattle_reference_sheet.txt index f18965fd6..c332fcee0 100644 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/starbattle_reference_sheet.txt +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/starbattle_reference_sheet.txt @@ -12,6 +12,7 @@ Regions Within Rows: STBL-BASC-0006 Rows Within Columns: STBL-BASC-0007 Rows Within Regions: STBL-BASC-0008 Surround Star: STBL-BASC-0009 +Empty Adjacent: STBL-BASC-0010 Contradiction Rules: Too Many Stars: STBL-CONT-0001 From cf121b63b98b7e91c5fb7092b18f8969eba7858b Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Fri, 19 Jul 2024 14:17:28 -0400 Subject: [PATCH 190/258] Made progress toward UniqueRowColumnDirectRule --- .../rules/UniqueRowColumnDirectRule.java | 103 ++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 src/main/java/edu/rpi/legup/puzzle/binary/rules/UniqueRowColumnDirectRule.java diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UniqueRowColumnDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UniqueRowColumnDirectRule.java new file mode 100644 index 000000000..4c15b4bbb --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UniqueRowColumnDirectRule.java @@ -0,0 +1,103 @@ +package edu.rpi.legup.puzzle.binary.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.binary.Binary; +import edu.rpi.legup.puzzle.binary.BinaryBoard; +import edu.rpi.legup.puzzle.binary.BinaryCell; +import edu.rpi.legup.puzzle.binary.BinaryType; + +import java.lang.reflect.Array; +import java.util.ArrayList; + +public class UniqueRowColumnDirectRule extends DirectRule { + private final String INVALID_USE_MESSAGE = "Number at cell is incorrect"; + + public UniqueRowColumnDirectRule() { + super( + "BINA-BASC-0005", + "Unique Row/Column", + "If an unfinished row/column only differs by two empty cells from a finished one, fill empty cells with the opposite digits", + "edu/rpi/legup/images/binary/rules/UniqueRowColumnDirectRule.png"); + } + + private int getNumEmpty(ArrayList seq) { + int numEmpty = 0; + for (BinaryType t : seq) { + if (t.equals(BinaryType.UNKNOWN)) { + numEmpty++; + if (numEmpty > 2) { + break; + } + } + } + return numEmpty; + } + + private String checkSequence(ArrayList seq, BinaryBoard origBoard, BinaryCell binaryCell, int rowOrColumn) { + // rowOrColumn : 0 = row, 1 = column + int numEmptyInRow = getNumEmpty(seq); + if (numEmptyInRow == 2) { + for (int i = 0; i < seq.size(); i++) { + if (rowOrColumn == 0) { + if (i == binaryCell.getLocation().y) { + continue; + } + } else { + if (i == binaryCell.getLocation().x) { + continue; + } + } + + ArrayList currSeq; + if (rowOrColumn == 0) { + currSeq = origBoard.getRowTypes(i); + } else { + currSeq = origBoard.getColTypes(i); + } + + if (getNumEmpty(currSeq) != 0) { + continue; + } + + for (int j = 0; j < seq.size(); j++) { + if (seq.get(j).equals(currSeq.get(j))) { + continue; + } + if (seq.get(j).equals(BinaryType.UNKNOWN)) { + if ((currSeq.get(j).equals(BinaryType.ZERO) && binaryCell.getType().equals(BinaryType.ONE) && binaryCell.getLocation().x == j) || + (currSeq.get(j).equals(BinaryType.ONE) && binaryCell.getType().equals(BinaryType.ZERO) && binaryCell.getLocation().x == j)) { + continue; + } + else { + return "Duplicate row/column found"; + } + } + } + } + } + + return null; + } + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + BinaryBoard origBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); + BinaryCell binaryCell = (BinaryCell) puzzleElement; + + + ArrayList row = origBoard.getRowTypes(binaryCell.getLocation().y); + int numEmptyInRow = getNumEmpty(row); + if (numEmptyInRow != 2) { + return "Row or column must have 2 empty cells"; + } + + return null; + } + + @Override + public Board getDefaultBoard(TreeNode node) { + return null; + } +} From 4b7e1e96546069c1c7f45e722b9b3f3ef68d609c Mon Sep 17 00:00:00 2001 From: summerhenson Date: Fri, 19 Jul 2024 14:39:20 -0400 Subject: [PATCH 191/258] Columns Within Rows direct rule tests --- .../ColumnsWithinRowsDirectRuleTest.java | 209 ++++++++++++++++++ .../FalseStarOverlap | 40 ++++ .../NonAdjacentColumns | 29 +++ 3 files changed, 278 insertions(+) create mode 100644 src/test/resources/puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/FalseStarOverlap create mode 100644 src/test/resources/puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/NonAdjacentColumns diff --git a/src/test/java/puzzles/starbattle/rules/ColumnsWithinRowsDirectRuleTest.java b/src/test/java/puzzles/starbattle/rules/ColumnsWithinRowsDirectRuleTest.java index 16b7452a0..a0906c3cf 100644 --- a/src/test/java/puzzles/starbattle/rules/ColumnsWithinRowsDirectRuleTest.java +++ b/src/test/java/puzzles/starbattle/rules/ColumnsWithinRowsDirectRuleTest.java @@ -15,6 +15,7 @@ import org.junit.Test; import java.awt.*; +import java.io.FileNotFoundException; public class ColumnsWithinRowsDirectRuleTest { @@ -26,4 +27,212 @@ public static void setUp() { MockGameBoardFacade.getInstance(); starbattle = new StarBattle(); } + + @Test + public void ColumnsWithinRowsDirectRule_OneColumn() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/OneColumn", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(1,0); + cell1.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell1); + StarBattleCell cell2 = board.getCell(2,0); + cell2.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell2); + + Assert.assertNull(RULE.checkRule(transition)); + + Point location1 = new Point(1, 0); + Point location2 = new Point(2,0); + 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(location1) || point.equals(location2)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void ColumnsWithinRowsDirectRule_TwoColumns() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/TwoColumns", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(2,1); + cell1.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell1); + StarBattleCell cell2 = board.getCell(2,0); + cell2.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell2); + + Assert.assertNull(RULE.checkRule(transition)); + + Point location1 = new Point(2, 1); + Point location2 = new Point(2,0); + 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(location1) || point.equals(location2)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void ColumnsWithinRowsDirectRule_NonAdjacentColumns() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/NonAdjacentColumns", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(1,0); + cell1.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell1); + StarBattleCell cell2 = board.getCell(1,2); + cell2.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell2); + + Assert.assertNull(RULE.checkRule(transition)); + + Point location1 = new Point(1, 0); + Point location2 = new Point(1,2); + 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(location1) || point.equals(location2)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void ColumnsWithinRowsDirectRule_TwoColumnsStarOverlap() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/TwoColumnsStarOverlap", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(2,1); + cell1.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell1); + StarBattleCell cell2 = board.getCell(3,0); + cell2.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell2); + + Assert.assertNull(RULE.checkRule(transition)); + + Point location1 = new Point(2, 1); + Point location2 = new Point(3,0); + 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(location1) || point.equals(location2)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void ColumnsWithinRowsDirectRule_FalseColumnsWithinRows1() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/OneColumn", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(1,0); + cell1.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell1); + StarBattleCell cell2 = board.getCell(2,0); + cell2.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell2); + StarBattleCell cell3 = board.getCell(1,1); + cell3.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell3); + + Assert.assertNotNull(RULE.checkRule(transition)); + + Point location1 = new Point(1, 0); + Point location2 = new Point(2,0); + 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(location1) || point.equals(location2)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void ColumnsWithinRowsDirectRule_FalseColumnsWithinRows2() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/OneColumn", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(1,0); + cell1.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell1); + + Assert.assertNotNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); i++) { + for (int k = 0; k < board.getWidth(); k++) { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + + @Test + public void ColumnsWithinRowsDirectRule_FalseColumnsWithinRows3() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/FalseStarOverlap", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(1,0); + cell1.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell1); + + Assert.assertNotNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); i++) { + for (int k = 0; k < board.getWidth(); k++) { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } diff --git a/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/FalseStarOverlap b/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/FalseStarOverlap new file mode 100644 index 000000000..c0ac99a0b --- /dev/null +++ b/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/FalseStarOverlap @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/NonAdjacentColumns b/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/NonAdjacentColumns new file mode 100644 index 000000000..8d71ffa4f --- /dev/null +++ b/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/NonAdjacentColumns @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 4d8a7c745e2dfdc699440c946dfad2f6493c2496 Mon Sep 17 00:00:00 2001 From: summerhenson Date: Fri, 19 Jul 2024 14:54:23 -0400 Subject: [PATCH 192/258] Fixed null reference bug in some direct rules --- .../puzzle/starbattle/rules/RegionsWithinColumnsDirectRule.java | 2 +- .../puzzle/starbattle/rules/RegionsWithinRowsDirectRule.java | 2 +- .../puzzle/starbattle/rules/RowsWithinColumnsDirectRule.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) 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 25177c816..ac2f0da9a 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 @@ -28,7 +28,7 @@ public RegionsWithinColumnsDirectRule() { public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { ColumnsWithinRegionsDirectRule correspondingRule = new ColumnsWithinRegionsDirectRule(); String result = correspondingRule.checkRuleRawAt(transition, puzzleElement); - if (result.equals("Only black out cells outside the column(s)!")) { + if (result != null && result.equals("Only black out cells outside the column(s)!")) { return "Only black out cells outside the region(s)!"; } return result; 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 2635c40cf..8219f9c01 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 @@ -29,7 +29,7 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem RowsWithinRegionsDirectRule correspondingRule = new RowsWithinRegionsDirectRule(); String result = correspondingRule.checkRuleRawAt(transition, puzzleElement); - if (result.equals("Only black out cells outside the row(s)!")) { + if (result != null && result.equals("Only black out cells outside the row(s)!")) { return "Only black out cells outside the region(s)!"; } return result; 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 3f56f33a1..39e3b46c4 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 @@ -30,7 +30,7 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem ColumnsWithinRowsDirectRule correspondingRule = new ColumnsWithinRowsDirectRule(); String result = correspondingRule.checkRuleRawAt(transition, puzzleElement); - if (result.equals("Only black out cells outside the column(s)!")) { + if (result != null && result.equals("Only black out cells outside the column(s)!")) { return "Only black out cells outside the row(s)!"; } return result; From eac5fd549341775beb327665e83e5d970aaab84e Mon Sep 17 00:00:00 2001 From: offline171 <146153141+offline171@users.noreply.github.com> Date: Fri, 19 Jul 2024 14:59:49 -0400 Subject: [PATCH 193/258] Added tests (function not working) Added some tests that revealed there is a problem with how the program retrieves the location of the tile in question. --- .../rules/EmptyAdjacentDirectRuleTest.java | 174 ++++++++++++++++++ .../ImproperUseFourLeft | 40 ++++ .../rules/EmptyAdjacentDirectRule/OneLeft | 40 ++++ .../rules/EmptyAdjacentDirectRule/ThreeLeft | 40 ++++ .../rules/EmptyAdjacentDirectRule/TwoLeft | 40 ++++ 5 files changed, 334 insertions(+) create mode 100644 src/test/java/puzzles/starbattle/rules/EmptyAdjacentDirectRuleTest.java create mode 100644 src/test/resources/puzzles/starbattle/rules/EmptyAdjacentDirectRule/ImproperUseFourLeft create mode 100644 src/test/resources/puzzles/starbattle/rules/EmptyAdjacentDirectRule/OneLeft create mode 100644 src/test/resources/puzzles/starbattle/rules/EmptyAdjacentDirectRule/ThreeLeft create mode 100644 src/test/resources/puzzles/starbattle/rules/EmptyAdjacentDirectRule/TwoLeft diff --git a/src/test/java/puzzles/starbattle/rules/EmptyAdjacentDirectRuleTest.java b/src/test/java/puzzles/starbattle/rules/EmptyAdjacentDirectRuleTest.java new file mode 100644 index 000000000..785e1afd7 --- /dev/null +++ b/src/test/java/puzzles/starbattle/rules/EmptyAdjacentDirectRuleTest.java @@ -0,0 +1,174 @@ +package puzzles.starbattle.rules; + +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +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.EmptyAdjacentDirectRule; +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 EmptyAdjacentDirectRuleTest { + + private static final EmptyAdjacentDirectRule RULE = new EmptyAdjacentDirectRule(); + private static StarBattle starbattle; + + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + starbattle = new StarBattle(); + } + + @Test + public void EmptyAdjacentDirectRule_OneLeft() throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/EmptyAdjacentDirectRule/OneLeft", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(1,1); + cell1.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell2 = board.getCell(2,1); + cell2.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell3 = board.getCell(3,1); + cell3.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell4 = board.getCell(1,3); + cell4.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell5 = board.getCell(2,3); + cell5.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell6 = board.getCell(3,3); + cell6.setData(StarBattleCellType.BLACK.value); + + board.addModifiedData(cell1); + board.addModifiedData(cell2); + board.addModifiedData(cell3); + board.addModifiedData(cell4); + board.addModifiedData(cell5); + board.addModifiedData(cell6); + + Assert.assertNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); ++i) { + for (int j = 0; j < board.getWidth(); ++j) { + Point point = new Point(j,i); + if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) || + point.equals(cell3.getLocation()) || point.equals(cell4.getLocation()) || + point.equals(cell5.getLocation()) || point.equals(cell6.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + } + } + } + + @Test + public void EmptyAdjacentDirectRule_TwoLeft() throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/EmptyAdjacentDirectRule/TwoLeft", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(1,1); + cell1.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell2 = board.getCell(2,1); + cell2.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell3 = board.getCell(1,3); + cell3.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell4 = board.getCell(2,3); + cell4.setData(StarBattleCellType.BLACK.value); + + board.addModifiedData(cell1); + board.addModifiedData(cell2); + board.addModifiedData(cell3); + board.addModifiedData(cell4); + + Assert.assertNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); ++i) { + for (int j = 0; j < board.getWidth(); ++j) { + Point point = new Point(j,i); + if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) || + point.equals(cell3.getLocation()) || point.equals(cell4.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + } + } + } + + @Test + public void EmptyAdjacentDirectRule_ThreeLeft() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/EmptyAdjacentDirectRule/TwoLeft", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(1,1); + cell1.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell2 = board.getCell(2,1); + cell2.setData(StarBattleCellType.BLACK.value); + + board.addModifiedData(cell1); + board.addModifiedData(cell2); + + Assert.assertNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); ++i) { + for (int j = 0; j < board.getWidth(); ++j) { + Point point = new Point(j,i); + if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + } + } + } + + @Test + public void EmptyAdjacentDirectRule_ImproperUseFourLeft() throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/EmptyAdjacentDirectRule/ImproperUseFourLeft", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(1,1); + cell1.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell2 = board.getCell(2,1); + cell2.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell3 = board.getCell(1,3); + cell3.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell4 = board.getCell(2,3); + cell4.setData(StarBattleCellType.BLACK.value); + + board.addModifiedData(cell1); + board.addModifiedData(cell2); + board.addModifiedData(cell3); + board.addModifiedData(cell4); + + Assert.assertNotNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); ++i) { + for (int j = 0; j < board.getWidth(); ++j) { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + } + } +} diff --git a/src/test/resources/puzzles/starbattle/rules/EmptyAdjacentDirectRule/ImproperUseFourLeft b/src/test/resources/puzzles/starbattle/rules/EmptyAdjacentDirectRule/ImproperUseFourLeft new file mode 100644 index 000000000..782c1d37d --- /dev/null +++ b/src/test/resources/puzzles/starbattle/rules/EmptyAdjacentDirectRule/ImproperUseFourLeft @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/EmptyAdjacentDirectRule/OneLeft b/src/test/resources/puzzles/starbattle/rules/EmptyAdjacentDirectRule/OneLeft new file mode 100644 index 000000000..29005798d --- /dev/null +++ b/src/test/resources/puzzles/starbattle/rules/EmptyAdjacentDirectRule/OneLeft @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/EmptyAdjacentDirectRule/ThreeLeft b/src/test/resources/puzzles/starbattle/rules/EmptyAdjacentDirectRule/ThreeLeft new file mode 100644 index 000000000..ab6f4b178 --- /dev/null +++ b/src/test/resources/puzzles/starbattle/rules/EmptyAdjacentDirectRule/ThreeLeft @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/EmptyAdjacentDirectRule/TwoLeft b/src/test/resources/puzzles/starbattle/rules/EmptyAdjacentDirectRule/TwoLeft new file mode 100644 index 000000000..5e8d71fbb --- /dev/null +++ b/src/test/resources/puzzles/starbattle/rules/EmptyAdjacentDirectRule/TwoLeft @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 36090d05306ce5eaaf57ef3a4678d70cf829fc93 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Fri, 19 Jul 2024 15:27:52 -0400 Subject: [PATCH 194/258] Created solution for rows in UniqueRowColumnDirectRule --- .../rules/UniqueRowColumnDirectRule.java | 39 ++++++++++++++++++- .../binary/rules/binary_reference_sheet.txt | 1 + 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UniqueRowColumnDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UniqueRowColumnDirectRule.java index 4c15b4bbb..0af99db09 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UniqueRowColumnDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UniqueRowColumnDirectRule.java @@ -90,9 +90,46 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem ArrayList row = origBoard.getRowTypes(binaryCell.getLocation().y); int numEmptyInRow = getNumEmpty(row); if (numEmptyInRow != 2) { - return "Row or column must have 2 empty cells"; + return "Row must have 2 empty cells"; } + boolean valid = false; + for (int i = 0; i < row.size(); i++) { + if (i == binaryCell.getLocation().y) { + continue; + } + ArrayList currRow; + currRow = origBoard.getRowTypes(i); + for (int j = 0; j < currRow.size(); j++) { + int numEmptyInCurrRow = getNumEmpty(currRow); + if (numEmptyInCurrRow != 0) { + continue; + } + if (!row.get(j).equals(currRow.get(j)) && !row.get(j).equals(BinaryType.UNKNOWN)) { + valid = false; + break; + } + System.out.println(" POS X: " + j + " Y: " + i); + System.out.println(" CEL X: " + binaryCell.getLocation().x + " Y: " + binaryCell.getLocation().y); + + if (currRow.get(j).equals(BinaryType.ZERO) && row.get(j).equals(BinaryType.UNKNOWN) && binaryCell.getType().equals(BinaryType.ONE) && binaryCell.getLocation().x == j) { + System.out.println("ROW: " + i + " " + row.get(j).toString() + " = " + currRow.get(j).toString() + "?"); + valid = true; + } + else if (currRow.get(j).equals(BinaryType.ONE) && row.get(j).equals(BinaryType.UNKNOWN) && binaryCell.getType().equals(BinaryType.ZERO) && binaryCell.getLocation().x == j) { + System.out.println("ROW: " + i + " " + row.get(j).toString() + " = " + currRow.get(j).toString() + "?"); + valid = true; + } + System.out.println(j); + } + if (valid) { + break; + } + } + + if (!valid) { + return "Duplicate Row Found"; + } return null; } diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/binary_reference_sheet.txt b/src/main/java/edu/rpi/legup/puzzle/binary/rules/binary_reference_sheet.txt index b6d5c094d..c3194e349 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/binary_reference_sheet.txt +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/binary_reference_sheet.txt @@ -2,6 +2,7 @@ BINA-BASC-0001 : SurroundPairDirectRule BINA-BASC-0002 : OneTileGapDirectRule BINA-BASC-0003 : CompleteRowColumnDirectRule BINA-BASC-0004 : SaveBlockerDirectRule +BINA-BASC-0005 : UniqueRowColumnDirectRule BINA-CONT-0001 : TrioContradictionRule BINA-CONT-0002 : UnbalancedRowColumnContradictionRule From 82e0e979351ccd9f7e2b8ddbf3674f0679a45e08 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Fri, 19 Jul 2024 15:34:18 -0400 Subject: [PATCH 195/258] Fixed bug in duplicate rows columns --- .../binary/rules/DuplicateRowsColumnsContradictionRule.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsColumnsContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsColumnsContradictionRule.java index 575c62d92..3ece0bae4 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsColumnsContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsColumnsContradictionRule.java @@ -31,7 +31,7 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { int size = row.size(); for (int i = 0; i < size; i++) { - if (i > cell.getLocation().y) { + if (i != cell.getLocation().y) { ArrayList currRow = binaryBoard.getRowTypes(i); if (currRow.equals(row)) { return null; @@ -42,7 +42,7 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { ArrayList col = binaryBoard.getColTypes(cell.getLocation().x); for (int i = 0; i < size; i++) { - if (i > cell.getLocation().x) { + if (i != cell.getLocation().x) { ArrayList currCol = binaryBoard.getColTypes(i); if (currCol.equals(col)) { return null; From 9010903d1b4a01c2374c154b47ae048e4b3dbfa1 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Fri, 19 Jul 2024 15:34:30 -0400 Subject: [PATCH 196/258] Created image for unique row column direct rule --- .../binary/rules/UniqueRowColumnDirectRule.png | Bin 0 -> 3304 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/main/resources/edu/rpi/legup/images/binary/rules/UniqueRowColumnDirectRule.png diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/UniqueRowColumnDirectRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/UniqueRowColumnDirectRule.png new file mode 100644 index 0000000000000000000000000000000000000000..7785d198c051b4d12db29f526f8cd33d2cd3dadd GIT binary patch literal 3304 zcmaJ^cQ71Y*Ip6bA~BLhY>4P(^^(|#mgrU|dRfs$kCj-lda#03gJAXOqW8|~y@vdd zEP@a<%D$VK_mA(L`QG=Bd!Bpd-nsYAIdh)#+$fm#b09SfH2?qrs;MgL5z*oApd=?+ z+0_kOB9M6NJy!&jkKWrNIyYY`Xej^yRcM+^8#1C#^-9&$8vtO7_&Z3@n+I?JfcCAL zvVy^D%iTJJGEt?5}?u2 zgNbS9hqrX&B@BepBhTFJ-&QypNF2159+bIETde9t3xU0sTe{`;0b@Uf{vo&2IA-X<^9g?`-7ni5o^6BD4$(5D|F zl65=uAc;Mu@TQF%7v(yi0!W9d>-GOxs-@H~)MoQ-(EH+SI5;#EUA|moR_~tw`|lk+ ziVMSO;`vx?sJ?)hnApbU`R~aFPrDhJd@GBLr+;{KvIZKxe_$<|{bsjv)G_>CzrSmp ze~Y+}_1&2r^M!sN%dQw@>~fv2?A*fmj-*S%H-|8j?MS54Vr?=1N8n6}VWP`i`QXX! z68s21p=WM>@2wr3QB%Ng2Sd@J1Gzc7fq0H>Iga5uE97o%mTsw$kZHAj6fKK{YPz(? zouq{rHyW2HdeLDdj{O>x8M*uZ%{-G!O{=_Hzz$b^?pKH z8efXAg&wKE4`EVUKfk)_PzrjmiL~HpcW)&f^5mx}kLLiYT0A@+?S}XydTWCiv%|9k zJ43pRy0!WZ1v8Or%pUWmZn?-=^GvBRuI=qb65(r|TgHq*LiG5TxiT}J^}g6d&gXF^ zI$TcUcKvaK(M$pcc_QTF9a7`#^!J|#67!n^$0eKUL=^YuJx6bJ)5|B}QXsfomG{%^ zXqf_7IIFaKksP;HI+mNfxCN$Xqw4cxl+E;uGlnH5UBc-BakKID)bu}RY+dH+|QJvD9GWldgdKE;2;sxoq2VG%JYaF(h`^ZRUwM`g-r9zo5hhkyixhlKoTN8N^ zRi4~T&jdb?`8r62aRA#ZG-c>xRb|zU3x0l~Isy&ZW@zgpG}-ABMRO&v3I=pje_yfF z({*I6p}->L$_r$XsJuh*o>Xw878cCg@F7{qtmGmQe0RLWPyqf;3LiK{BkTI94bpm) zp#D728uVw8JgCAVHEK>R{V`J^2{}FZ^BZy0%6N{_OeytBqFxSJ>#J`eO?^yWZv1h6 zN^&Yl!qurWV1KqO!)I@KVf$O`g{Y%=O$*|<#A{3{RvrDr?dejT8~k){#o3|P1a+Lz zb=3e7H;>7pm@t6zo|-igh(VcY=3%k_IbUU@8@-&m#b+e;a`Ybj+<*V;mu<pT)ouZ?W1mK*(iXW(5ti`Sc5l4!Zhe8t(TUEV@(- z{#>ZR%oo$PEZ^2+7sJ{xknc#kF|749mjh^|qtmT!eh6R*f8%Oy|QK?dP2X7$8 zYhIZSwu#HCYJiCVRn3l*3;Kz0jMqx@e7(EBTfvELW z^^~}k2E<7Ymo$z0KxW9}$vUlOJfoS|#&jd29w7`dS^3TdYP;=G;JZCN*eDbMWGx_) z-*Dz*VG)8`eStV1#uAb8&uIn{(E<~`1NqREm<7;?{ zy(%h8GywnW`x9~fjX&vv=PD6V2{V-i`cP_WYJ=37U=q^LcB{c_nA26HRVGg;M_Z~S z&@8f#fX_o4EHiuKk*hkQ*jeHzTI^Xt{l(=^y=4W89IZs_jej>_2VkbGv7!XuouuX}gG#s0wIs(TVW zqT)li(2mRuDp>Kx=xX3Tl*a~?P02*+;Q(hoAY}CoueYk}3#trt$;kM>3)Byfe#I

      3^OO&BOjP}zSC5JN_KiD2ywWf#>L;c0osmZd;B@eIJNOMOK)8D zm^{J!iwD0=BDK<(wTneiP@9*M>(ktKlmk+3_j>G?$VtAfZ4XiQfMva~iA5c*i6h!c z`MP<}s(p8iN*8$Cs$PzP;hT}lSN^+;@EJSG>vhi%YsIM(f%<;yU5STeYb+^Un%xCY ztrz+2Tmjh`qgDA@z*nF@_>xhXO>Tr#g5+~^)V?Jc7kH&V5A1~HA}JRmFv`8n9;^YQeKFZ-u*~ z;f}tEyE{er!E8B(NM1jLW_49aXFLyK!3vlnirj)E*32od%Aw?j3ixme=MkDOj^Z9! z$sLPtac~j~1KBLCX>{#gdRcWUPxvvIEe4}d&TYFitLulMqq8p0p-Lo5iUEoAc|1rK zQVvH=sC9w!r|MsU)XEC36>S&msLOs2hRz+!I4!y$Yrf^^!?^CDyFP5Zmxr^SANZ@Gv3h!4#%2}Z!1fD zoDRf`Gu;T5u;$0$;bxyL+tw`7NE|CUk;XeV{~0R=AVcHcWea)L1;jt$=BkG97=Oht zK>keAE&ghDIo}>po*TV1jmOhyc%kp!?7AE!o6PJ-gyGjZ;B#jIfYR2!sER_XZ#69jUFRJO62BP>6+>e zB;)_qv;U@f4qC{XIeqdA*@U+*5m?SvNWjC3<)iUR$4|3%^KUk&Z?S*w#e;;+if9S? z;pG<1&$8#cU(o8x?k?4%pH%fnAbzDdNMbC}3(fu>KZh^^6BwwcMwHt^H5aidK_HMi zB;guA1iZhUbF7L3DFuxk`s7t_bwXK`LE}{Rg*8Yzc^luq{dq(^b literal 0 HcmV?d00001 From f371ee2b91c0b6115099eb6b81a5345534c228f5 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Fri, 19 Jul 2024 15:34:58 -0400 Subject: [PATCH 197/258] Updated rule descriptions for zero or one case rule and surround pair direct rule --- .../rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java | 2 +- .../edu/rpi/legup/puzzle/binary/rules/ZeroOrOneCaseRule.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java index 6b8ed83be..75ed34921 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java @@ -14,7 +14,7 @@ public SurroundPairDirectRule() { super( "BINA-BASC-0001", "Surround Pair", - "If two adjacent tiles have the same value, surround the tiles with the other value.", + "If two adjacent tiles have the same value, surround the tiles with the other value", "edu/rpi/legup/images/binary/rules/SurroundPairDirectRule.png"); } diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ZeroOrOneCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ZeroOrOneCaseRule.java index 87d82a736..6fefd3947 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ZeroOrOneCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ZeroOrOneCaseRule.java @@ -17,7 +17,7 @@ public ZeroOrOneCaseRule() { super( "BINA-CASE-0001", "Zero Or One", - "Each blank cell is either a zero or a one.", + "Each blank cell is either a zero or a one", "edu/rpi/legup/images/binary/rules/ZeroOrOneCaseRule.png"); } From a3e1ca78e7a42a044dcf932e6df1040f74209d83 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Sat, 20 Jul 2024 00:52:41 -0400 Subject: [PATCH 198/258] Changed rule name sizes for buttons so names fit within button box --- .../ui/proofeditorui/rulesview/RulePanel.java | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RulePanel.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RulePanel.java index 5d985d5c2..5a26b49fb 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RulePanel.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RulePanel.java @@ -55,14 +55,21 @@ public void setRules(List rules) { Rule rule = rules.get(i); ruleButtons[i] = new RuleButton(rule); - ruleButtons[i].setPreferredSize( - new Dimension(150, 150)); // adjust the size of each RuleButton + ruleButtons[i].setPreferredSize(new Dimension(150, 150)); // adjust the size of each RuleButton + + if (rule.getRuleName().length() > 18) { + ruleButtons[i].setFont(new Font("Segoe UI", Font.PLAIN, 11)); + } + if (rule.getRuleName().length() > 20) { + ruleButtons[i].setFont(new Font("Segoe UI", Font.PLAIN, 10)); + } + System.out.println(ruleButtons[i].getFont().getName()); + ruleButtons[i].setHorizontalTextPosition(JButton.CENTER); ruleButtons[i].setVerticalTextPosition(JButton.BOTTOM); ruleFrame.getButtonGroup().add(ruleButtons[i]); - ruleButtons[i].setToolTipText( - rule.getRuleName() + ": " + rule.getDescription()); // showing description + ruleButtons[i].setToolTipText(rule.getRuleName() + ": " + rule.getDescription()); // showing description ruleButtons[i].addActionListener(ruleFrame.getController()); add(ruleButtons[i]); } From 44de9898ca559e634e5fdd79363bd40648c584fb Mon Sep 17 00:00:00 2001 From: summerhenson Date: Tue, 23 Jul 2024 14:13:11 -0400 Subject: [PATCH 199/258] Test case files for Regions Within Columns direct rule --- .../ColumnsWithinRowsDirectRuleTest.java | 1 - .../RegionsWithinColumnsDirectRuleTest.java | 29 ++++++++++++++ .../FalseStarOverlap | 40 +++++++++++++++++++ .../OneRegionOneCell | 29 ++++++++++++++ .../OneRegionTwoCells | 29 ++++++++++++++ .../PartialRegionOneCell | 29 ++++++++++++++ .../TwoColumnsStarOverlap | 40 +++++++++++++++++++ .../TwoColumnsTwoCells | 40 +++++++++++++++++++ .../TwoRegionsOneCell | 40 +++++++++++++++++++ 9 files changed, 276 insertions(+), 1 deletion(-) create mode 100644 src/test/java/puzzles/starbattle/rules/RegionsWithinColumnsDirectRuleTest.java create mode 100644 src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/FalseStarOverlap create mode 100644 src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/OneRegionOneCell create mode 100644 src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/OneRegionTwoCells create mode 100644 src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/PartialRegionOneCell create mode 100644 src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoColumnsStarOverlap create mode 100644 src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoColumnsTwoCells create mode 100644 src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoRegionsOneCell diff --git a/src/test/java/puzzles/starbattle/rules/ColumnsWithinRowsDirectRuleTest.java b/src/test/java/puzzles/starbattle/rules/ColumnsWithinRowsDirectRuleTest.java index a0906c3cf..89986b57c 100644 --- a/src/test/java/puzzles/starbattle/rules/ColumnsWithinRowsDirectRuleTest.java +++ b/src/test/java/puzzles/starbattle/rules/ColumnsWithinRowsDirectRuleTest.java @@ -15,7 +15,6 @@ import org.junit.Test; import java.awt.*; -import java.io.FileNotFoundException; public class ColumnsWithinRowsDirectRuleTest { diff --git a/src/test/java/puzzles/starbattle/rules/RegionsWithinColumnsDirectRuleTest.java b/src/test/java/puzzles/starbattle/rules/RegionsWithinColumnsDirectRuleTest.java new file mode 100644 index 000000000..39896cb55 --- /dev/null +++ b/src/test/java/puzzles/starbattle/rules/RegionsWithinColumnsDirectRuleTest.java @@ -0,0 +1,29 @@ +package puzzles.starbattle.rules; + +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +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.RegionsWithinColumnsDirectRule; +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.awt.*; + +public class RegionsWithinColumnsDirectRuleTest { + + private static final RegionsWithinColumnsDirectRule RULE = new RegionsWithinColumnsDirectRule(); + private static StarBattle starbattle; + + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + starbattle = new StarBattle(); + } +} diff --git a/src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/FalseStarOverlap b/src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/FalseStarOverlap new file mode 100644 index 000000000..812f00b66 --- /dev/null +++ b/src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/FalseStarOverlap @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/OneRegionOneCell b/src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/OneRegionOneCell new file mode 100644 index 000000000..c459a9231 --- /dev/null +++ b/src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/OneRegionOneCell @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/OneRegionTwoCells b/src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/OneRegionTwoCells new file mode 100644 index 000000000..50a775d0b --- /dev/null +++ b/src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/OneRegionTwoCells @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/PartialRegionOneCell b/src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/PartialRegionOneCell new file mode 100644 index 000000000..057dc96f0 --- /dev/null +++ b/src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/PartialRegionOneCell @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoColumnsStarOverlap b/src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoColumnsStarOverlap new file mode 100644 index 000000000..e7495cabf --- /dev/null +++ b/src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoColumnsStarOverlap @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoColumnsTwoCells b/src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoColumnsTwoCells new file mode 100644 index 000000000..cea670809 --- /dev/null +++ b/src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoColumnsTwoCells @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoRegionsOneCell b/src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoRegionsOneCell new file mode 100644 index 000000000..0ee0205ab --- /dev/null +++ b/src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoRegionsOneCell @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 9d950459eeae2f05b63e3566cc0a06cf778b8c58 Mon Sep 17 00:00:00 2001 From: offline171 <146153141+offline171@users.noreply.github.com> Date: Tue, 23 Jul 2024 14:34:27 -0400 Subject: [PATCH 200/258] Fixed an issue where tests wouldn't run An issue where the test file would fail before any of the tests started was fixed --- .../rules/EmptyAdjacentDirectRule.java | 36 ++++++++++++------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/EmptyAdjacentDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/EmptyAdjacentDirectRule.java index 93c600dd2..0f82f8b1e 100644 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/EmptyAdjacentDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/EmptyAdjacentDirectRule.java @@ -6,6 +6,8 @@ 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.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; @@ -17,7 +19,7 @@ public EmptyAdjacentDirectRule() { "STBL-BASC-0010", "Empty Adjacent", "Tiles next to other tiles that need to contain a star to reach the puzzle number for their region/row/column need to be blacked out.", - "edu/rpi/legup/images/starbattle/rules/EmptyAdjacent.png"); + "edu/rpi/legup/images/starbattle/rules/EmptyAdjacentDirectRule.png"); } /** @@ -38,20 +40,30 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem StarBattleCell cell = (StarBattleCell) board.getPuzzleElement(puzzleElement); if (cell.getType() != StarBattleCellType.BLACK) { - return "Only black cells are allowed for this rule!"; + return super.getInvalidUseOfRuleMessage() + + ": Only black cells are allowed for this rule!"; } + int x = cell.getLocation().x; + int y = cell.getLocation().y; + + StarBattleCell northWest = board.getCell(x - 1, y - 1); + StarBattleCell north = board.getCell(x, y - 1); + StarBattleCell northEast = board.getCell(x + 1, y - 1); + StarBattleCell west = board.getCell(x - 1, y); + StarBattleCell east = board.getCell(x + 1, y); + StarBattleCell southWest = board.getCell(x - 1, y + 1); + StarBattleCell south = board.getCell(x, y + 1); + StarBattleCell southEast = board.getCell(x + 1, y + 1); + + StarBattleCell[] adjacent = {northWest, north, northEast, west, east, southWest, south, southEast}; + StarBattleBoard modified = (StarBattleBoard) origBoard.copy(); - int X = cell.getLocation().x; - int Y = cell.getLocation().y; - for(int i = X-1; i <= X+1; i++){ - for(int j = Y-1; j <= Y+1; j++){ - if(i < 0 || i >= modified.getPuzzleNumber() || j < 0 || j >= modified.getPuzzleNumber()){ - continue; - } //else - if(modified.getCell(i,j).getType() == StarBattleCellType.UNKNOWN){ - modified.getCell(i,j).setData(StarBattleCellType.BLACK.value); - }//only modify empty cells, star cells remain as is and black cells ignored in case they're unmodifiable + for(int i = 0; i < 8; i++){ //sets each spot to a black square if not filled + StarBattleCell temp = adjacent[i]; + + if (temp != null && temp.getType() == StarBattleCellType.UNKNOWN) { + modified.getCell(temp.getLocation().x, temp.getLocation().y).setData(-1); } } From 4fa089a1f23fe7badb55850eee75722cce425745 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Tue, 23 Jul 2024 14:38:12 -0400 Subject: [PATCH 201/258] Made progress toward a reset button for puzzle editor that clears all changes to board --- .../rules/UniqueRowColumnDirectRule.java | 120 ++++++++---------- .../edu/rpi/legup/ui/CreatePuzzleDialog.java | 27 ++-- .../edu/rpi/legup/ui/PuzzleEditorPanel.java | 47 ++++++- 3 files changed, 107 insertions(+), 87 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UniqueRowColumnDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UniqueRowColumnDirectRule.java index 0af99db09..2f8b8310c 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UniqueRowColumnDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UniqueRowColumnDirectRule.java @@ -36,89 +36,52 @@ private int getNumEmpty(ArrayList seq) { } return numEmpty; } - private String checkSequence(ArrayList seq, BinaryBoard origBoard, BinaryCell binaryCell, int rowOrColumn) { - // rowOrColumn : 0 = row, 1 = column - int numEmptyInRow = getNumEmpty(seq); - if (numEmptyInRow == 2) { - for (int i = 0; i < seq.size(); i++) { - if (rowOrColumn == 0) { - if (i == binaryCell.getLocation().y) { - continue; - } - } else { - if (i == binaryCell.getLocation().x) { - continue; - } - } - - ArrayList currSeq; - if (rowOrColumn == 0) { - currSeq = origBoard.getRowTypes(i); - } else { - currSeq = origBoard.getColTypes(i); - } + // rowOrColumn : 0 for row, 1 for column + int numEmpty = getNumEmpty(seq); + if (numEmpty > 2) { + return "Row/Col must have at most 2 empty cells"; + } - if (getNumEmpty(currSeq) != 0) { + boolean valid = false; + for (int i = 0; i < seq.size(); i++) { + ArrayList currSeq; + if (rowOrColumn == 0) { + if (i == binaryCell.getLocation().y) { continue; } - - for (int j = 0; j < seq.size(); j++) { - if (seq.get(j).equals(currSeq.get(j))) { - continue; - } - if (seq.get(j).equals(BinaryType.UNKNOWN)) { - if ((currSeq.get(j).equals(BinaryType.ZERO) && binaryCell.getType().equals(BinaryType.ONE) && binaryCell.getLocation().x == j) || - (currSeq.get(j).equals(BinaryType.ONE) && binaryCell.getType().equals(BinaryType.ZERO) && binaryCell.getLocation().x == j)) { - continue; - } - else { - return "Duplicate row/column found"; - } - } + currSeq = origBoard.getRowTypes(i); + } else { + if (i == binaryCell.getLocation().x) { + continue; } + currSeq = origBoard.getColTypes(i); } - } - - return null; - } - public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - BinaryBoard origBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); - BinaryCell binaryCell = (BinaryCell) puzzleElement; - - ArrayList row = origBoard.getRowTypes(binaryCell.getLocation().y); - int numEmptyInRow = getNumEmpty(row); - if (numEmptyInRow != 2) { - return "Row must have 2 empty cells"; - } - - boolean valid = false; - for (int i = 0; i < row.size(); i++) { - if (i == binaryCell.getLocation().y) { - continue; - } - ArrayList currRow; - currRow = origBoard.getRowTypes(i); - for (int j = 0; j < currRow.size(); j++) { - int numEmptyInCurrRow = getNumEmpty(currRow); - if (numEmptyInCurrRow != 0) { + int numDifferentCells = 0; + for (int j = 0; j < currSeq.size(); j++) { + int numEmptyInCurrSeq = getNumEmpty(currSeq); + if (numEmptyInCurrSeq != 0) { continue; } - if (!row.get(j).equals(currRow.get(j)) && !row.get(j).equals(BinaryType.UNKNOWN)) { - valid = false; - break; + if (!seq.get(j).equals(currSeq.get(j)) && !seq.get(j).equals(BinaryType.UNKNOWN)) { + if (++numDifferentCells > 1 || numEmpty != 1) { + valid = false; + break; + } } System.out.println(" POS X: " + j + " Y: " + i); System.out.println(" CEL X: " + binaryCell.getLocation().x + " Y: " + binaryCell.getLocation().y); - if (currRow.get(j).equals(BinaryType.ZERO) && row.get(j).equals(BinaryType.UNKNOWN) && binaryCell.getType().equals(BinaryType.ONE) && binaryCell.getLocation().x == j) { - System.out.println("ROW: " + i + " " + row.get(j).toString() + " = " + currRow.get(j).toString() + "?"); - valid = true; + if (currSeq.get(j).equals(BinaryType.ZERO) && seq.get(j).equals(BinaryType.UNKNOWN) && binaryCell.getType().equals(BinaryType.ONE)) { + if ((rowOrColumn == 0 && binaryCell.getLocation().x == j) || rowOrColumn == 1 && binaryCell.getLocation().y == j) { + valid = true; + } } - else if (currRow.get(j).equals(BinaryType.ONE) && row.get(j).equals(BinaryType.UNKNOWN) && binaryCell.getType().equals(BinaryType.ZERO) && binaryCell.getLocation().x == j) { - System.out.println("ROW: " + i + " " + row.get(j).toString() + " = " + currRow.get(j).toString() + "?"); - valid = true; + else if (currSeq.get(j).equals(BinaryType.ONE) && seq.get(j).equals(BinaryType.UNKNOWN) && binaryCell.getType().equals(BinaryType.ZERO)) { + if ((rowOrColumn == 0 && binaryCell.getLocation().x == j) || rowOrColumn == 1 && binaryCell.getLocation().y == j) { + valid = true; + } } System.out.println(j); } @@ -128,10 +91,27 @@ else if (currRow.get(j).equals(BinaryType.ONE) && row.get(j).equals(BinaryType.U } if (!valid) { - return "Duplicate Row Found"; + return "Rule is not applicable"; } return null; } + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + BinaryBoard origBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); + BinaryCell binaryCell = (BinaryCell) puzzleElement; + + + ArrayList row = origBoard.getRowTypes(binaryCell.getLocation().y); + if (checkSequence(row, origBoard, binaryCell, 0) == null) { + return null; + } + + ArrayList col = origBoard.getColTypes(binaryCell.getLocation().x); + if (checkSequence(col, origBoard, binaryCell, 1) == null) { + return null; + } + + return "Rule is not applicable"; + } @Override public Board getDefaultBoard(TreeNode node) { diff --git a/src/main/java/edu/rpi/legup/ui/CreatePuzzleDialog.java b/src/main/java/edu/rpi/legup/ui/CreatePuzzleDialog.java index 636d5b36f..0ae48955a 100644 --- a/src/main/java/edu/rpi/legup/ui/CreatePuzzleDialog.java +++ b/src/main/java/edu/rpi/legup/ui/CreatePuzzleDialog.java @@ -57,13 +57,8 @@ public void actionPerformed(ActionEvent e) { */ @Override public void actionPerformed(ActionEvent ae) { - String game = - Config.convertDisplayNameToClassName( - (String) gameBox.getSelectedItem()); + String game = getGame(); - if (game.equals("OpeningPuzzleEditor")) { - - } // Check if all 3 TextFields are filled if (game.equals("ShortTruthTable") && textArea.getText().isEmpty()) { System.out.println("Unfilled fields"); @@ -71,8 +66,8 @@ public void actionPerformed(ActionEvent ae) { } if (!game.equals("ShortTruthTable") && (game.isEmpty() - || rows.getText().isEmpty() - || columns.getText().isEmpty())) { + || getRows().isEmpty() + || getColumns().isEmpty())) { System.out.println("Unfilled fields"); return; } @@ -84,8 +79,8 @@ public void actionPerformed(ActionEvent ae) { } else { homePanel.openEditorWithNewPuzzle( game, - Integer.valueOf(rows.getText()), - Integer.valueOf(columns.getText())); + Integer.valueOf(getRows()), + Integer.valueOf(getColumns())); } setVisible(false); } catch (IllegalArgumentException e) { @@ -226,4 +221,16 @@ public void actionPerformed(ActionEvent e) { } } } + + public String getGame() { + return Config.convertDisplayNameToClassName((String) gameBox.getSelectedItem()); + } + + public String getRows() { + return rows.getText(); + } + + public String getColumns() { + return columns.getText(); + } } diff --git a/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java b/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java index 6d4c35616..480c4685c 100644 --- a/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java +++ b/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java @@ -10,10 +10,14 @@ import edu.rpi.legup.history.IHistoryListener; import edu.rpi.legup.model.Puzzle; import edu.rpi.legup.model.PuzzleExporter; +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.save.ExportFileException; import edu.rpi.legup.save.InvalidFileFormatException; import edu.rpi.legup.ui.HomePanel; import edu.rpi.legup.ui.boardview.BoardView; +import edu.rpi.legup.ui.proofeditorui.treeview.TreeViewSelection; import edu.rpi.legup.ui.puzzleeditorui.elementsview.ElementFrame; import java.awt.*; import java.awt.event.ActionEvent; @@ -23,6 +27,7 @@ import java.io.IOException; import java.net.URI; import java.net.URL; +import java.util.List; import java.util.Objects; import javax.swing.*; import javax.swing.border.TitledBorder; @@ -54,6 +59,8 @@ public class PuzzleEditorPanel extends LegupPanel implements IHistoryListener { private JPanel treePanel; private LegupUI legupUI; private EditorElementController editorElementController; + private CreatePuzzleDialog cpd; + private HomePanel hp; public PuzzleEditorPanel(FileDialog fileDialog, JFrame frame, LegupUI legupUI) { this.fileDialog = fileDialog; @@ -117,8 +124,8 @@ public void setMenuBar() { // file>create JMenuItem createPuzzle = new JMenuItem("Create"); createPuzzle.addActionListener((ActionEvent) -> { - HomePanel hp = new HomePanel(this.fileDialog, this.frame, this.legupUI); - CreatePuzzleDialog cpd = new CreatePuzzleDialog(this.frame, hp); + hp = new HomePanel(this.fileDialog, this.frame, this.legupUI); + cpd = new CreatePuzzleDialog(this.frame, hp); cpd.setLocationRelativeTo(null); cpd.setVisible(true); }); @@ -312,7 +319,33 @@ private void setupToolBar2() { toolBar2 = new JToolBar(); toolBar2.setFloatable(false); toolBar2.setRollover(true); - setToolBar2Buttons(new JButton[2]); + setToolBar2Buttons(new JButton[3]); + + URL reset = + ClassLoader.getSystemClassLoader() + .getResource("edu/rpi/legup/images/Legup/Reset.png"); + ImageIcon ResetImageIcon = new ImageIcon(reset); + Image ResetImage = ResetImageIcon.getImage(); + ResetImageIcon = + new ImageIcon( + ResetImage.getScaledInstance( + this.TOOLBAR_ICON_SCALE, + this.TOOLBAR_ICON_SCALE, + Image.SCALE_SMOOTH)); + + JButton resetButton = new JButton("Reset", ResetImageIcon); + resetButton.setFocusPainted(false); + + resetButton.addActionListener( + a -> { + hp.openEditorWithNewPuzzle( + cpd.getGame(), + Integer.valueOf(cpd.getRows()), + Integer.valueOf(cpd.getColumns())); + }); + + getToolBar2Buttons()[0] = resetButton; + toolBar2.add(getToolBar2Buttons()[0]); URL save_as = ClassLoader.getSystemClassLoader() @@ -330,8 +363,8 @@ private void setupToolBar2() { saveas.setFocusPainted(false); saveas.addActionListener((ActionEvent) -> savePuzzle()); - getToolBar2Buttons()[0] = saveas; - toolBar2.add(getToolBar2Buttons()[0]); + getToolBar2Buttons()[1] = saveas; + toolBar2.add(getToolBar2Buttons()[1]); URL save_and_solve = ClassLoader.getSystemClassLoader() @@ -367,8 +400,8 @@ public void actionPerformed(ActionEvent e) { } } }); - getToolBar2Buttons()[1] = saveandsolve; - toolBar2.add(getToolBar2Buttons()[1]); + getToolBar2Buttons()[2] = saveandsolve; + toolBar2.add(getToolBar2Buttons()[2]); this.add(toolBar2, BorderLayout.NORTH); } From d92d5670152f5211b7b7edd9d92d4e7a0b04168d Mon Sep 17 00:00:00 2001 From: summerhenson Date: Tue, 23 Jul 2024 14:51:05 -0400 Subject: [PATCH 202/258] Regions Within Columns direct rule test suite --- .../ColumnsWithinRegionsDirectRuleTest.java | 1 - .../RegionsWithinColumnsDirectRuleTest.java | 317 ++++++++++++++++++ ...lumnsStarOverlap => TwoRegionsStarOverlap} | 0 ...{TwoColumnsTwoCells => TwoRegionsTwoCells} | 0 .../TwoRegionsTwoCells2 | 40 +++ 5 files changed, 357 insertions(+), 1 deletion(-) rename src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/{TwoColumnsStarOverlap => TwoRegionsStarOverlap} (100%) rename src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/{TwoColumnsTwoCells => TwoRegionsTwoCells} (100%) create mode 100644 src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoRegionsTwoCells2 diff --git a/src/test/java/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRuleTest.java b/src/test/java/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRuleTest.java index 2f9ed2596..3297b1d5e 100644 --- a/src/test/java/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRuleTest.java +++ b/src/test/java/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRuleTest.java @@ -208,7 +208,6 @@ public void ColumnsWithinRegionsDirectRule_TwoColumnsStarOverlap() @Test public void ColumnsWithinRegionsDirectRule_FalseColumnsWithinRegions1() throws InvalidFileFormatException { - System.out.println("Starting false CWR:"); TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/OneColumnOneCell", starbattle); TreeNode rootNode = starbattle.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); diff --git a/src/test/java/puzzles/starbattle/rules/RegionsWithinColumnsDirectRuleTest.java b/src/test/java/puzzles/starbattle/rules/RegionsWithinColumnsDirectRuleTest.java index 39896cb55..68b11d091 100644 --- a/src/test/java/puzzles/starbattle/rules/RegionsWithinColumnsDirectRuleTest.java +++ b/src/test/java/puzzles/starbattle/rules/RegionsWithinColumnsDirectRuleTest.java @@ -26,4 +26,321 @@ public static void setUp() { MockGameBoardFacade.getInstance(); starbattle = new StarBattle(); } + + @Test + public void RegionsWithinColumnsDirectRule_OneRegionOneCell() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/OneRegionOneCell", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell = board.getCell(0,2); + cell.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell); + + Assert.assertNull(RULE.checkRule(transition)); + + Point location = new Point(0,2); + 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(location)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void RegionsWithinColumnsDirectRule_OneRegionTwoCells() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/OneRegionTwoCells", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(0,1); + cell1.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell1); + StarBattleCell cell2 = board.getCell(0,2); + cell2.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell2); + + Assert.assertNull(RULE.checkRule(transition)); + + Point location1 = new Point(0,1); + Point location2 = new Point(0,2); + 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(location1) || point.equals(location2)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void RegionsWithinColumnsDirectRule_PartialRegionOneCell() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/PartialRegionOneCell", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell = board.getCell(0,2); + cell.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell); + + Assert.assertNull(RULE.checkRule(transition)); + + Point location = new Point(0,2); + 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(location)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void RegionsWithinColumnsDirectRule_TwoRegionsOneCell() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoRegionsOneCell", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell = board.getCell(1,3); + cell.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell); + + Assert.assertNull(RULE.checkRule(transition)); + + Point location = new Point(1,3); + 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(location)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void RegionsWithinColumnsDirectRule_TwoRegionsTwoCells() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoRegionsTwoCells", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(1,1); + cell1.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell1); + StarBattleCell cell2 = board.getCell(1,3); + cell2.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell2); + + Assert.assertNull(RULE.checkRule(transition)); + + Point location1 = new Point(1,1); + Point location2 = new Point(1,3); + 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(location1) || point.equals(location2)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void RegionsWithinColumnsDirectRule_TwoRegionsTwoCells2() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoRegionsTwoCells2", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(0,3); + cell1.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell1); + StarBattleCell cell2 = board.getCell(1,3); + cell2.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell2); + + Assert.assertNull(RULE.checkRule(transition)); + + Point location1 = new Point(0,3); + Point location2 = new Point(1,3); + 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(location1) || point.equals(location2)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void RegionsWithinColumnsDirectRule_TwoRegionsStarOverlap() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoRegionsStarOverlap", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell = board.getCell(1,1); + cell.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell); + + Assert.assertNull(RULE.checkRule(transition)); + + Point location = new Point(1,1); + 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(location)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void RegionsWithinColumnsDirectRule_FalseRegionsWithinColumns1() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/OneRegionOneCell", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell = board.getCell(0,2); + cell.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell); + StarBattleCell cell2 = board.getCell(1,2); + cell2.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell2); + + Assert.assertNotNull(RULE.checkRule(transition)); + + Point location = new Point(0,2); + 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(location)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void RegionsWithinColumnsDirectRule_FalseRegionsWithinColumns2() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/OneRegionOneCell", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell = board.getCell(0,2); + cell.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell); + StarBattleCell cell2 = board.getCell(0,1); + cell2.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell2); + + Assert.assertNotNull(RULE.checkRule(transition)); + + Point location = new Point(0,2); + 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(location)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void RegionsWithinColumnsDirectRule_FalseRegionsWithinColumns3() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/FalseStarOverlap", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell = board.getCell(1,1); + cell.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell); + StarBattleCell cell2 = board.getCell(1,3); + cell2.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell2); + + Assert.assertNotNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); i++) { + for (int k = 0; k < board.getWidth(); k++) { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + + @Test + public void RegionsWithinColumnsDirectRule_FalseRegionsWithinColumns4() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoRegionsTwoCells2", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell = board.getCell(0,3); + cell.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell); + + Assert.assertNotNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); i++) { + for (int k = 0; k < board.getWidth(); k++) { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } } diff --git a/src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoColumnsStarOverlap b/src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoRegionsStarOverlap similarity index 100% rename from src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoColumnsStarOverlap rename to src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoRegionsStarOverlap diff --git a/src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoColumnsTwoCells b/src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoRegionsTwoCells similarity index 100% rename from src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoColumnsTwoCells rename to src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoRegionsTwoCells diff --git a/src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoRegionsTwoCells2 b/src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoRegionsTwoCells2 new file mode 100644 index 000000000..01ecce3ee --- /dev/null +++ b/src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoRegionsTwoCells2 @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From c1510b7e8d8ee628563234dd9fac082d86c968a3 Mon Sep 17 00:00:00 2001 From: summerhenson Date: Fri, 26 Jul 2024 14:04:33 -0400 Subject: [PATCH 203/258] New 5x5 1 star puzzle file --- ...Star Battle 1 star Normal 1.xml => 050101} | 0 ... visualized (DO NOT OPEN AS A PUZZLE).png} | Bin .../5x5 Star Battle 1 star Normal/050102 | 53 ++++++++++++++++++ .../RegionsWithinRowsDirectRuleTest.java | 30 ++++++++++ 4 files changed, 83 insertions(+) rename puzzles files/starbattle/5x5 Star Battle 1 star Normal/{5x5 Star Battle 1 star Normal 1.xml => 050101} (100%) rename puzzles files/starbattle/5x5 Star Battle 1 star Normal/{5x5 Star Battle Normal visualized (DO NOT OPEN AS A PUZZLE).png => 050101 visualized (DO NOT OPEN AS A PUZZLE).png} (100%) create mode 100644 puzzles files/starbattle/5x5 Star Battle 1 star Normal/050102 create mode 100644 src/test/java/puzzles/starbattle/rules/RegionsWithinRowsDirectRuleTest.java diff --git a/puzzles files/starbattle/5x5 Star Battle 1 star Normal/5x5 Star Battle 1 star Normal 1.xml b/puzzles files/starbattle/5x5 Star Battle 1 star Normal/050101 similarity index 100% rename from puzzles files/starbattle/5x5 Star Battle 1 star Normal/5x5 Star Battle 1 star Normal 1.xml rename to puzzles files/starbattle/5x5 Star Battle 1 star Normal/050101 diff --git a/puzzles files/starbattle/5x5 Star Battle 1 star Normal/5x5 Star Battle Normal visualized (DO NOT OPEN AS A PUZZLE).png b/puzzles files/starbattle/5x5 Star Battle 1 star Normal/050101 visualized (DO NOT OPEN AS A PUZZLE).png similarity index 100% rename from puzzles files/starbattle/5x5 Star Battle 1 star Normal/5x5 Star Battle Normal visualized (DO NOT OPEN AS A PUZZLE).png rename to puzzles files/starbattle/5x5 Star Battle 1 star Normal/050101 visualized (DO NOT OPEN AS A PUZZLE).png diff --git a/puzzles files/starbattle/5x5 Star Battle 1 star Normal/050102 b/puzzles files/starbattle/5x5 Star Battle 1 star Normal/050102 new file mode 100644 index 000000000..73d131d69 --- /dev/null +++ b/puzzles files/starbattle/5x5 Star Battle 1 star Normal/050102 @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/java/puzzles/starbattle/rules/RegionsWithinRowsDirectRuleTest.java b/src/test/java/puzzles/starbattle/rules/RegionsWithinRowsDirectRuleTest.java new file mode 100644 index 000000000..716e65c9a --- /dev/null +++ b/src/test/java/puzzles/starbattle/rules/RegionsWithinRowsDirectRuleTest.java @@ -0,0 +1,30 @@ +package puzzles.starbattle.rules; + +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +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.RegionsWithinRowsDirectRule; +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.awt.*; + +public class RegionsWithinRowsDirectRuleTest { + + private static final RegionsWithinRowsDirectRule RULE = new RegionsWithinRowsDirectRule(); + private static StarBattle starbattle; + + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + starbattle = new StarBattle(); + } + +} From f99a1d190fa42b1d0719196a48938414cb36ee4d Mon Sep 17 00:00:00 2001 From: offline171 <146153141+offline171@users.noreply.github.com> Date: Fri, 26 Jul 2024 14:45:56 -0400 Subject: [PATCH 204/258] Debugging process rooted out issue Issue has been found where changes that are meant to be isolated within the rule's temporary board are instead permanent, considering if copy constructor is the problem --- .../rules/EmptyAdjacentDirectRule.java | 17 ++++++++++++----- .../rules/TooFewStarsContradictionRule.java | 3 ++- .../rules/EmptyAdjacentDirectRuleTest.java | 13 ++++++++----- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/EmptyAdjacentDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/EmptyAdjacentDirectRule.java index 0f82f8b1e..17909e233 100644 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/EmptyAdjacentDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/EmptyAdjacentDirectRule.java @@ -59,18 +59,25 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem StarBattleCell[] adjacent = {northWest, north, northEast, west, east, southWest, south, southEast}; StarBattleBoard modified = (StarBattleBoard) origBoard.copy(); + modified.getPuzzleElement(puzzleElement).setData(StarBattleCellType.STAR.value); for(int i = 0; i < 8; i++){ //sets each spot to a black square if not filled StarBattleCell temp = adjacent[i]; if (temp != null && temp.getType() == StarBattleCellType.UNKNOWN) { - modified.getCell(temp.getLocation().x, temp.getLocation().y).setData(-1); + temp.setData(StarBattleCellType.BLACK.value); + int X = temp.getLocation().x; + int Y = temp.getLocation().y; + modified.getCell(X,Y).setData(StarBattleCellType.BLACK.value); + System.out.println("covering square " + X + " " + Y + " type " + modified.getCell(X,Y).getType() + " i = " + i + "\n"); + if(contraRule.checkContradictionAt(modified, temp) == null){ + System.out.println("Good job!"); + return null; //used correctly if even one space causes a toofewstars issue + } } } + System.out.println("Wait why did this exit?\n"); - if (contraRule.checkContradictionAt(modified, puzzleElement) != null) { - return "Black cells must be placed adjacent to a tile(s) where a star is needed!"; - } - return null; + return "Black cells must be placed adjacent to a tile(s) where a star is needed!"; } /** 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 100243a65..358e5b9bd 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 @@ -45,8 +45,9 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { ++columnCount; } } - + System.out.println("rowCount = " + rowCount + " columnCount = " + columnCount + " at " + column + "," + row + "\n"); if (rowCount < sbBoard.getPuzzleNumber() || columnCount < sbBoard.getPuzzleNumber()) { + System.out.println("Returning Null\n"); return null; } StarBattleRegion region = sbBoard.getRegion(cell); diff --git a/src/test/java/puzzles/starbattle/rules/EmptyAdjacentDirectRuleTest.java b/src/test/java/puzzles/starbattle/rules/EmptyAdjacentDirectRuleTest.java index 785e1afd7..c81c74657 100644 --- a/src/test/java/puzzles/starbattle/rules/EmptyAdjacentDirectRuleTest.java +++ b/src/test/java/puzzles/starbattle/rules/EmptyAdjacentDirectRuleTest.java @@ -81,30 +81,33 @@ public void EmptyAdjacentDirectRule_TwoLeft() throws InvalidFileFormatException StarBattleBoard board = (StarBattleBoard) transition.getBoard(); StarBattleCell cell1 = board.getCell(1,1); cell1.setData(StarBattleCellType.BLACK.value); + /* StarBattleCell cell2 = board.getCell(2,1); cell2.setData(StarBattleCellType.BLACK.value); StarBattleCell cell3 = board.getCell(1,3); cell3.setData(StarBattleCellType.BLACK.value); StarBattleCell cell4 = board.getCell(2,3); cell4.setData(StarBattleCellType.BLACK.value); + */ board.addModifiedData(cell1); + /* board.addModifiedData(cell2); board.addModifiedData(cell3); board.addModifiedData(cell4); + */ Assert.assertNull(RULE.checkRule(transition)); - + System.out.println("General Case is done\n"); for (int i = 0; i < board.getHeight(); ++i) { for (int j = 0; j < board.getWidth(); ++j) { Point point = new Point(j,i); - if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) || - point.equals(cell3.getLocation()) || point.equals(cell4.getLocation())) { + if (point.equals(cell1.getLocation())) { Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } + } /* else { Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } + } */ } } } From b0afc3634263ca54811253eb87f3c0942e0be923 Mon Sep 17 00:00:00 2001 From: summerhenson Date: Fri, 26 Jul 2024 14:55:23 -0400 Subject: [PATCH 205/258] First half of Regions Within Rows direct rule test suite --- .../RegionsWithinRowsDirectRuleTest.java | 143 ++++++++++++++++++ .../OneRegionOneCell | 29 ++++ .../PartialRegionOneCell | 29 ++++ .../PartialRegionTwoCells | 29 ++++ .../RegionsWithinRowsDirectRule/StarOverlap | 40 +++++ .../TwoRegionsOneCell | 40 +++++ 6 files changed, 310 insertions(+) create mode 100644 src/test/resources/puzzles/starbattle/rules/RegionsWithinRowsDirectRule/OneRegionOneCell create mode 100644 src/test/resources/puzzles/starbattle/rules/RegionsWithinRowsDirectRule/PartialRegionOneCell create mode 100644 src/test/resources/puzzles/starbattle/rules/RegionsWithinRowsDirectRule/PartialRegionTwoCells create mode 100644 src/test/resources/puzzles/starbattle/rules/RegionsWithinRowsDirectRule/StarOverlap create mode 100644 src/test/resources/puzzles/starbattle/rules/RegionsWithinRowsDirectRule/TwoRegionsOneCell diff --git a/src/test/java/puzzles/starbattle/rules/RegionsWithinRowsDirectRuleTest.java b/src/test/java/puzzles/starbattle/rules/RegionsWithinRowsDirectRuleTest.java index 716e65c9a..b78ad9fb3 100644 --- a/src/test/java/puzzles/starbattle/rules/RegionsWithinRowsDirectRuleTest.java +++ b/src/test/java/puzzles/starbattle/rules/RegionsWithinRowsDirectRuleTest.java @@ -27,4 +27,147 @@ public static void setUp() { starbattle = new StarBattle(); } + @Test + public void RegionsWithinRowsDirectRule_OneRegionOneCell() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinRowsDirectRule/OneRegionOneCell", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell = board.getCell(2,0); + cell.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell); + + Assert.assertNull(RULE.checkRule(transition)); + + Point location = new Point(2,0); + 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(location)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void RegionsWithinRowsDirectRule_PartialRegionOneCell() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinRowsDirectRule/PartialRegionOneCell", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell = board.getCell(2,0); + cell.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell); + + Assert.assertNull(RULE.checkRule(transition)); + + Point location = new Point(2,0); + 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(location)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void RegionsWithinRowsDirectRule_PartialRegionTwo() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinRowsDirectRule/PartialRegionTwoCells", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(1,0); + cell1.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell1); + StarBattleCell cell2 = board.getCell(2,0); + cell2.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell2); + + Assert.assertNull(RULE.checkRule(transition)); + + Point location1 = new Point(1,0); + Point location2 = new Point(2,0); + 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(location1) || point.equals(location2)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void RegionsWithinRowsDirectRule_TwoRegionsOneCell() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinRowsDirectRule/TwoRegionsOneCell", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell = board.getCell(3,1); + cell.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell); + + Assert.assertNull(RULE.checkRule(transition)); + + Point location = new Point(3,1); + 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(location)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void RegionsWithinRowsDirectRule_StarOverlap() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinRowsDirectRule/StarOverlap", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell = board.getCell(3,1); + cell.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell); + + Assert.assertNull(RULE.checkRule(transition)); + + Point location = new Point(3,1); + 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(location)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } } diff --git a/src/test/resources/puzzles/starbattle/rules/RegionsWithinRowsDirectRule/OneRegionOneCell b/src/test/resources/puzzles/starbattle/rules/RegionsWithinRowsDirectRule/OneRegionOneCell new file mode 100644 index 000000000..056b67059 --- /dev/null +++ b/src/test/resources/puzzles/starbattle/rules/RegionsWithinRowsDirectRule/OneRegionOneCell @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/RegionsWithinRowsDirectRule/PartialRegionOneCell b/src/test/resources/puzzles/starbattle/rules/RegionsWithinRowsDirectRule/PartialRegionOneCell new file mode 100644 index 000000000..eb9a69787 --- /dev/null +++ b/src/test/resources/puzzles/starbattle/rules/RegionsWithinRowsDirectRule/PartialRegionOneCell @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/RegionsWithinRowsDirectRule/PartialRegionTwoCells b/src/test/resources/puzzles/starbattle/rules/RegionsWithinRowsDirectRule/PartialRegionTwoCells new file mode 100644 index 000000000..0654ed4dc --- /dev/null +++ b/src/test/resources/puzzles/starbattle/rules/RegionsWithinRowsDirectRule/PartialRegionTwoCells @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/RegionsWithinRowsDirectRule/StarOverlap b/src/test/resources/puzzles/starbattle/rules/RegionsWithinRowsDirectRule/StarOverlap new file mode 100644 index 000000000..5a6901ead --- /dev/null +++ b/src/test/resources/puzzles/starbattle/rules/RegionsWithinRowsDirectRule/StarOverlap @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/RegionsWithinRowsDirectRule/TwoRegionsOneCell b/src/test/resources/puzzles/starbattle/rules/RegionsWithinRowsDirectRule/TwoRegionsOneCell new file mode 100644 index 000000000..4e19386e4 --- /dev/null +++ b/src/test/resources/puzzles/starbattle/rules/RegionsWithinRowsDirectRule/TwoRegionsOneCell @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From e8de3de502845e28fe8f286cb4be560e6493d82d Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Sat, 27 Jul 2024 10:28:52 -0400 Subject: [PATCH 206/258] Created puzzle files for binary --- .../binary/6x6 Binary Hard/6x6 Binary Hard 1 | 47 ++++++++++++ .../binary/6x6 Binary Hard/6x6 Binary Hard 2 | 47 ++++++++++++ .../binary/6x6 Binary Hard/6x6 Binary Hard 3 | 47 ++++++++++++ .../6x6 Binary Very Hard 1 | 47 ++++++++++++ .../binary/8x8 Binary Easy/8x8 Binary Easy 1 | 75 +++++++++++++++++++ .../binary/8x8 Binary Easy/8x8 Binary Easy 2 | 75 +++++++++++++++++++ .../binary/8x8 Binary Easy/8x8 Binary Easy 3 | 75 +++++++++++++++++++ .../8x8 Binary Medium/8x8 Binary Medium 1 | 75 +++++++++++++++++++ .../8x8 Binary Medium/8x8 Binary Medium 2 | 75 +++++++++++++++++++ .../8x8 Binary Medium/8x8 Binary Medium 3 | 75 +++++++++++++++++++ 10 files changed, 638 insertions(+) create mode 100644 puzzles files/binary/6x6 Binary Hard/6x6 Binary Hard 1 create mode 100644 puzzles files/binary/6x6 Binary Hard/6x6 Binary Hard 2 create mode 100644 puzzles files/binary/6x6 Binary Hard/6x6 Binary Hard 3 create mode 100644 puzzles files/binary/6x6 Binary Very Hard/6x6 Binary Very Hard 1 create mode 100644 puzzles files/binary/8x8 Binary Easy/8x8 Binary Easy 1 create mode 100644 puzzles files/binary/8x8 Binary Easy/8x8 Binary Easy 2 create mode 100644 puzzles files/binary/8x8 Binary Easy/8x8 Binary Easy 3 create mode 100644 puzzles files/binary/8x8 Binary Medium/8x8 Binary Medium 1 create mode 100644 puzzles files/binary/8x8 Binary Medium/8x8 Binary Medium 2 create mode 100644 puzzles files/binary/8x8 Binary Medium/8x8 Binary Medium 3 diff --git a/puzzles files/binary/6x6 Binary Hard/6x6 Binary Hard 1 b/puzzles files/binary/6x6 Binary Hard/6x6 Binary Hard 1 new file mode 100644 index 000000000..5f7f72a8a --- /dev/null +++ b/puzzles files/binary/6x6 Binary Hard/6x6 Binary Hard 1 @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/6x6 Binary Hard/6x6 Binary Hard 2 b/puzzles files/binary/6x6 Binary Hard/6x6 Binary Hard 2 new file mode 100644 index 000000000..a4ed30c31 --- /dev/null +++ b/puzzles files/binary/6x6 Binary Hard/6x6 Binary Hard 2 @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/6x6 Binary Hard/6x6 Binary Hard 3 b/puzzles files/binary/6x6 Binary Hard/6x6 Binary Hard 3 new file mode 100644 index 000000000..fc0e413c1 --- /dev/null +++ b/puzzles files/binary/6x6 Binary Hard/6x6 Binary Hard 3 @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/6x6 Binary Very Hard/6x6 Binary Very Hard 1 b/puzzles files/binary/6x6 Binary Very Hard/6x6 Binary Very Hard 1 new file mode 100644 index 000000000..faa68fa5e --- /dev/null +++ b/puzzles files/binary/6x6 Binary Very Hard/6x6 Binary Very Hard 1 @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/8x8 Binary Easy/8x8 Binary Easy 1 b/puzzles files/binary/8x8 Binary Easy/8x8 Binary Easy 1 new file mode 100644 index 000000000..befd674f9 --- /dev/null +++ b/puzzles files/binary/8x8 Binary Easy/8x8 Binary Easy 1 @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/8x8 Binary Easy/8x8 Binary Easy 2 b/puzzles files/binary/8x8 Binary Easy/8x8 Binary Easy 2 new file mode 100644 index 000000000..724426c26 --- /dev/null +++ b/puzzles files/binary/8x8 Binary Easy/8x8 Binary Easy 2 @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/8x8 Binary Easy/8x8 Binary Easy 3 b/puzzles files/binary/8x8 Binary Easy/8x8 Binary Easy 3 new file mode 100644 index 000000000..92a96c72b --- /dev/null +++ b/puzzles files/binary/8x8 Binary Easy/8x8 Binary Easy 3 @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/8x8 Binary Medium/8x8 Binary Medium 1 b/puzzles files/binary/8x8 Binary Medium/8x8 Binary Medium 1 new file mode 100644 index 000000000..47dae23dc --- /dev/null +++ b/puzzles files/binary/8x8 Binary Medium/8x8 Binary Medium 1 @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/8x8 Binary Medium/8x8 Binary Medium 2 b/puzzles files/binary/8x8 Binary Medium/8x8 Binary Medium 2 new file mode 100644 index 000000000..ae4cb8bb0 --- /dev/null +++ b/puzzles files/binary/8x8 Binary Medium/8x8 Binary Medium 2 @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/8x8 Binary Medium/8x8 Binary Medium 3 b/puzzles files/binary/8x8 Binary Medium/8x8 Binary Medium 3 new file mode 100644 index 000000000..2f951ecc4 --- /dev/null +++ b/puzzles files/binary/8x8 Binary Medium/8x8 Binary Medium 3 @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From af6fd7280f7dc3cd714b404492f35285006b6993 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Sat, 27 Jul 2024 10:29:37 -0400 Subject: [PATCH 207/258] Combined SurroundPair and OneTileGap direct rules into PreventTrio direct rule --- .../binary/rules/OneTileGapDirectRule.java | 84 +++++++++--------- .../binary/rules/PreventTrioDirectRule.java | 42 +++++++++ .../binary/rules/SurroundPairDirectRule.java | 80 ++++++++--------- ...rectRule.png => PreventTrioDirectRule.png} | Bin 4 files changed, 124 insertions(+), 82 deletions(-) create mode 100644 src/main/java/edu/rpi/legup/puzzle/binary/rules/PreventTrioDirectRule.java rename src/main/resources/edu/rpi/legup/images/binary/rules/{OneTileGapDirectRule.png => PreventTrioDirectRule.png} (100%) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java index 383e4b72a..a8f59b1e8 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java @@ -1,42 +1,42 @@ -package edu.rpi.legup.puzzle.binary.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.binary.BinaryBoard; -import edu.rpi.legup.puzzle.binary.BinaryCell; - -public class OneTileGapDirectRule extends DirectRule { - private final String INVALID_USE_MESSAGE = "Number at cell is incorrect"; - - public OneTileGapDirectRule() { - super( - "BINA-BASC-0002", - "One Tile Gap", - "If an empty tile is in between the same value, fill the gap with the other value.", - "edu/rpi/legup/images/binary/rules/OneTileGapDirectRule.png"); - } - - @Override - public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - BinaryBoard origBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); - TrioContradictionRule contraRule = new TrioContradictionRule(); - BinaryCell binaryCell = (BinaryCell) puzzleElement; - BinaryBoard modified = origBoard.copy(); - - modified.getPuzzleElement(puzzleElement).setData(Math.abs(binaryCell.getData() - 1)); - - if (!contraRule.checkOneTileGap(modified, binaryCell)) { - return null; - } - - return "Trio Found"; - } - - @Override - public Board getDefaultBoard(TreeNode node) { - return null; - } -} +//package edu.rpi.legup.puzzle.binary.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.binary.BinaryBoard; +//import edu.rpi.legup.puzzle.binary.BinaryCell; +// +//public class OneTileGapDirectRule extends DirectRule { +// private final String INVALID_USE_MESSAGE = "Number at cell is incorrect"; +// +// public OneTileGapDirectRule() { +// super( +// "BINA-BASC-0002", +// "One Tile Gap", +// "If an empty tile is in between the same value, fill the gap with the other value.", +// "edu/rpi/legup/images/binary/rules/OneTileGapDirectRule.png"); +// } +// +// @Override +// public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { +// BinaryBoard origBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); +// TrioContradictionRule contraRule = new TrioContradictionRule(); +// BinaryCell binaryCell = (BinaryCell) puzzleElement; +// BinaryBoard modified = origBoard.copy(); +// +// modified.getPuzzleElement(puzzleElement).setData(Math.abs(binaryCell.getData() - 1)); +// +// if (!contraRule.checkOneTileGap(modified, binaryCell)) { +// return null; +// } +// +// return "Trio Found"; +// } +// +// @Override +// public Board getDefaultBoard(TreeNode node) { +// return null; +// } +//} diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/PreventTrioDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/PreventTrioDirectRule.java new file mode 100644 index 000000000..cff326e81 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/PreventTrioDirectRule.java @@ -0,0 +1,42 @@ +package edu.rpi.legup.puzzle.binary.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.binary.BinaryBoard; +import edu.rpi.legup.puzzle.binary.BinaryCell; + +public class PreventTrioDirectRule extends DirectRule { + private final String INVALID_USE_MESSAGE = "Number at cell is incorrect"; + + public PreventTrioDirectRule() { + super( + "BINA-BASC-0001", + "Prevent Trio", + "If a trio contradiction state could appear, use the opposite digit to prevent the trio", + "edu/rpi/legup/images/binary/rules/PreventTrioDirectRule.png"); + } + + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + BinaryBoard origBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); + TrioContradictionRule contraRule = new TrioContradictionRule(); + BinaryCell binaryCell = (BinaryCell) puzzleElement; + BinaryBoard modified = origBoard.copy(); + + modified.getPuzzleElement(puzzleElement).setData(Math.abs(binaryCell.getData() - 1)); + + if (contraRule.checkContradictionAt(modified, binaryCell) == null) { + return null; + } + + return "Trio Found"; + } + + @Override + public Board getDefaultBoard(TreeNode node) { + return null; + } +} \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java index 75ed34921..08031ecef 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java @@ -1,40 +1,40 @@ -package edu.rpi.legup.puzzle.binary.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.binary.BinaryBoard; -import edu.rpi.legup.puzzle.binary.BinaryCell; - -public class SurroundPairDirectRule extends DirectRule { - - public SurroundPairDirectRule() { - super( - "BINA-BASC-0001", - "Surround Pair", - "If two adjacent tiles have the same value, surround the tiles with the other value", - "edu/rpi/legup/images/binary/rules/SurroundPairDirectRule.png"); - } - - public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - BinaryBoard origBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); - TrioContradictionRule contraRule = new TrioContradictionRule(); - BinaryCell binaryCell = (BinaryCell) puzzleElement; - BinaryBoard modified = origBoard.copy(); - - modified.getPuzzleElement(puzzleElement).setData(Math.abs(binaryCell.getData() - 1)); - - if (!contraRule.checkSurroundPair(modified, binaryCell)) { - return null; - } - - return "Trio Found"; - } - - @Override - public Board getDefaultBoard(TreeNode node) { - return null; - } -} +//package edu.rpi.legup.puzzle.binary.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.binary.BinaryBoard; +//import edu.rpi.legup.puzzle.binary.BinaryCell; +// +//public class SurroundPairDirectRule extends DirectRule { +// +// public SurroundPairDirectRule() { +// super( +// "BINA-BASC-0001", +// "Surround Pair", +// "If two adjacent tiles have the same value, surround the tiles with the other value", +// "edu/rpi/legup/images/binary/rules/SurroundPairDirectRule.png"); +// } +// +// public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { +// BinaryBoard origBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); +// TrioContradictionRule contraRule = new TrioContradictionRule(); +// BinaryCell binaryCell = (BinaryCell) puzzleElement; +// BinaryBoard modified = origBoard.copy(); +// +// modified.getPuzzleElement(puzzleElement).setData(Math.abs(binaryCell.getData() - 1)); +// +// if (!contraRule.checkSurroundPair(modified, binaryCell)) { +// return null; +// } +// +// return "Trio Found"; +// } +// +// @Override +// public Board getDefaultBoard(TreeNode node) { +// return null; +// } +//} diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/OneTileGapDirectRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/PreventTrioDirectRule.png similarity index 100% rename from src/main/resources/edu/rpi/legup/images/binary/rules/OneTileGapDirectRule.png rename to src/main/resources/edu/rpi/legup/images/binary/rules/PreventTrioDirectRule.png From 75e74c7043e2511501d0507fc8a3a41d48d27ac4 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Sat, 27 Jul 2024 10:30:17 -0400 Subject: [PATCH 208/258] Fully implemented UniqueRowColumn direct rule and organized code --- .../legup/puzzle/binary/rules/UniqueRowColumnDirectRule.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UniqueRowColumnDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UniqueRowColumnDirectRule.java index 2f8b8310c..5dc2d4f38 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UniqueRowColumnDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UniqueRowColumnDirectRule.java @@ -18,7 +18,7 @@ public class UniqueRowColumnDirectRule extends DirectRule { public UniqueRowColumnDirectRule() { super( - "BINA-BASC-0005", + "BINA-BASC-0004", "Unique Row/Column", "If an unfinished row/column only differs by two empty cells from a finished one, fill empty cells with the opposite digits", "edu/rpi/legup/images/binary/rules/UniqueRowColumnDirectRule.png"); From e5bbc51bf05f0ec28bd2e9a75d8d54e38a098a0d Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Sun, 28 Jul 2024 19:49:28 -0400 Subject: [PATCH 209/258] Added more puzzle files to binary --- .../10x10 Binary Hard/10x10 Binary Hard 1 | 111 ++++++++++++++++++ .../10x10 Binary Hard/10x10 Binary Hard 2 | 111 ++++++++++++++++++ .../10x10 Binary Hard/10x10 Binary Hard 3 | 111 ++++++++++++++++++ .../10x10 Binary Medium/10x10 Binary Medium 1 | 111 ++++++++++++++++++ .../10x10 Binary Medium/10x10 Binary Medium 2 | 111 ++++++++++++++++++ .../10x10 Binary Medium/10x10 Binary Medium 3 | 111 ++++++++++++++++++ .../10x10 Binary Very Hard 1 | 111 ++++++++++++++++++ .../6x6 Binary Very Hard 2 | 47 ++++++++ .../6x6 Binary Very Hard 3 | 47 ++++++++ .../binary/8x8 Binary Hard/8x8 Binary Hard 1 | 75 ++++++++++++ .../binary/8x8 Binary Hard/8x8 Binary Hard 2 | 75 ++++++++++++ .../binary/8x8 Binary Hard/8x8 Binary Hard 3 | 75 ++++++++++++ .../8x8 Binary Very Hard 1 | 75 ++++++++++++ .../8x8 Binary Very Hard 2 | 75 ++++++++++++ .../8x8 Binary Very Hard 3 | 75 ++++++++++++ 15 files changed, 1321 insertions(+) create mode 100644 puzzles files/binary/10x10 Binary Hard/10x10 Binary Hard 1 create mode 100644 puzzles files/binary/10x10 Binary Hard/10x10 Binary Hard 2 create mode 100644 puzzles files/binary/10x10 Binary Hard/10x10 Binary Hard 3 create mode 100644 puzzles files/binary/10x10 Binary Medium/10x10 Binary Medium 1 create mode 100644 puzzles files/binary/10x10 Binary Medium/10x10 Binary Medium 2 create mode 100644 puzzles files/binary/10x10 Binary Medium/10x10 Binary Medium 3 create mode 100644 puzzles files/binary/10x10 Binary Very Hard/10x10 Binary Very Hard 1 create mode 100644 puzzles files/binary/6x6 Binary Very Hard/6x6 Binary Very Hard 2 create mode 100644 puzzles files/binary/6x6 Binary Very Hard/6x6 Binary Very Hard 3 create mode 100644 puzzles files/binary/8x8 Binary Hard/8x8 Binary Hard 1 create mode 100644 puzzles files/binary/8x8 Binary Hard/8x8 Binary Hard 2 create mode 100644 puzzles files/binary/8x8 Binary Hard/8x8 Binary Hard 3 create mode 100644 puzzles files/binary/8x8 Binary Very Hard/8x8 Binary Very Hard 1 create mode 100644 puzzles files/binary/8x8 Binary Very Hard/8x8 Binary Very Hard 2 create mode 100644 puzzles files/binary/8x8 Binary Very Hard/8x8 Binary Very Hard 3 diff --git a/puzzles files/binary/10x10 Binary Hard/10x10 Binary Hard 1 b/puzzles files/binary/10x10 Binary Hard/10x10 Binary Hard 1 new file mode 100644 index 000000000..42ccf371b --- /dev/null +++ b/puzzles files/binary/10x10 Binary Hard/10x10 Binary Hard 1 @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/10x10 Binary Hard/10x10 Binary Hard 2 b/puzzles files/binary/10x10 Binary Hard/10x10 Binary Hard 2 new file mode 100644 index 000000000..d73caa5d2 --- /dev/null +++ b/puzzles files/binary/10x10 Binary Hard/10x10 Binary Hard 2 @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/10x10 Binary Hard/10x10 Binary Hard 3 b/puzzles files/binary/10x10 Binary Hard/10x10 Binary Hard 3 new file mode 100644 index 000000000..99ec9769b --- /dev/null +++ b/puzzles files/binary/10x10 Binary Hard/10x10 Binary Hard 3 @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/10x10 Binary Medium/10x10 Binary Medium 1 b/puzzles files/binary/10x10 Binary Medium/10x10 Binary Medium 1 new file mode 100644 index 000000000..d203617c8 --- /dev/null +++ b/puzzles files/binary/10x10 Binary Medium/10x10 Binary Medium 1 @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/10x10 Binary Medium/10x10 Binary Medium 2 b/puzzles files/binary/10x10 Binary Medium/10x10 Binary Medium 2 new file mode 100644 index 000000000..db56f04f3 --- /dev/null +++ b/puzzles files/binary/10x10 Binary Medium/10x10 Binary Medium 2 @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/10x10 Binary Medium/10x10 Binary Medium 3 b/puzzles files/binary/10x10 Binary Medium/10x10 Binary Medium 3 new file mode 100644 index 000000000..11940a6eb --- /dev/null +++ b/puzzles files/binary/10x10 Binary Medium/10x10 Binary Medium 3 @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/10x10 Binary Very Hard/10x10 Binary Very Hard 1 b/puzzles files/binary/10x10 Binary Very Hard/10x10 Binary Very Hard 1 new file mode 100644 index 000000000..828a450cf --- /dev/null +++ b/puzzles files/binary/10x10 Binary Very Hard/10x10 Binary Very Hard 1 @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/6x6 Binary Very Hard/6x6 Binary Very Hard 2 b/puzzles files/binary/6x6 Binary Very Hard/6x6 Binary Very Hard 2 new file mode 100644 index 000000000..3c707bdaa --- /dev/null +++ b/puzzles files/binary/6x6 Binary Very Hard/6x6 Binary Very Hard 2 @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/6x6 Binary Very Hard/6x6 Binary Very Hard 3 b/puzzles files/binary/6x6 Binary Very Hard/6x6 Binary Very Hard 3 new file mode 100644 index 000000000..217a032d8 --- /dev/null +++ b/puzzles files/binary/6x6 Binary Very Hard/6x6 Binary Very Hard 3 @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/8x8 Binary Hard/8x8 Binary Hard 1 b/puzzles files/binary/8x8 Binary Hard/8x8 Binary Hard 1 new file mode 100644 index 000000000..34eaf8388 --- /dev/null +++ b/puzzles files/binary/8x8 Binary Hard/8x8 Binary Hard 1 @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/8x8 Binary Hard/8x8 Binary Hard 2 b/puzzles files/binary/8x8 Binary Hard/8x8 Binary Hard 2 new file mode 100644 index 000000000..9ef23277e --- /dev/null +++ b/puzzles files/binary/8x8 Binary Hard/8x8 Binary Hard 2 @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/8x8 Binary Hard/8x8 Binary Hard 3 b/puzzles files/binary/8x8 Binary Hard/8x8 Binary Hard 3 new file mode 100644 index 000000000..287ff6f68 --- /dev/null +++ b/puzzles files/binary/8x8 Binary Hard/8x8 Binary Hard 3 @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/8x8 Binary Very Hard/8x8 Binary Very Hard 1 b/puzzles files/binary/8x8 Binary Very Hard/8x8 Binary Very Hard 1 new file mode 100644 index 000000000..9c875523b --- /dev/null +++ b/puzzles files/binary/8x8 Binary Very Hard/8x8 Binary Very Hard 1 @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/8x8 Binary Very Hard/8x8 Binary Very Hard 2 b/puzzles files/binary/8x8 Binary Very Hard/8x8 Binary Very Hard 2 new file mode 100644 index 000000000..14f2e4ad2 --- /dev/null +++ b/puzzles files/binary/8x8 Binary Very Hard/8x8 Binary Very Hard 2 @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/8x8 Binary Very Hard/8x8 Binary Very Hard 3 b/puzzles files/binary/8x8 Binary Very Hard/8x8 Binary Very Hard 3 new file mode 100644 index 000000000..ad319a4b7 --- /dev/null +++ b/puzzles files/binary/8x8 Binary Very Hard/8x8 Binary Very Hard 3 @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 543626efa5eafc5e5a4e043d8f30a31a490780da Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Sun, 28 Jul 2024 19:51:33 -0400 Subject: [PATCH 210/258] Added right click functionality to binary to cycle backwards compared to left click --- .../java/edu/rpi/legup/puzzle/binary/BinaryController.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryController.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryController.java index 0bad559d9..03566f0d2 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryController.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryController.java @@ -31,10 +31,10 @@ public void changeCell(MouseEvent e, PuzzleElement data) { } else { if (e.getButton() == MouseEvent.BUTTON3) { if (cell.getData() == 0) { - data.setData(1); + data.setData(2); } else { - if (cell.getData() == 1) { - data.setData(2); + if (cell.getData() == 2) { + data.setData(1); } else { data.setData(0); } From dd0e37ba3b46417e434f23db17ef8d96135ce31a Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Sun, 28 Jul 2024 19:54:28 -0400 Subject: [PATCH 211/258] Added reset functionality for puzzle editor --- .../java/edu/rpi/legup/ui/CreatePuzzleDialog.java | 2 ++ .../java/edu/rpi/legup/ui/PuzzleEditorPanel.java | 14 ++++++++------ .../edu/rpi/legup/images/Legup/Reset.png | Bin 0 -> 662 bytes 3 files changed, 10 insertions(+), 6 deletions(-) create mode 100644 src/main/resources/edu/rpi/legup/images/Legup/Reset.png diff --git a/src/main/java/edu/rpi/legup/ui/CreatePuzzleDialog.java b/src/main/java/edu/rpi/legup/ui/CreatePuzzleDialog.java index 0ae48955a..a5afa2ff0 100644 --- a/src/main/java/edu/rpi/legup/ui/CreatePuzzleDialog.java +++ b/src/main/java/edu/rpi/legup/ui/CreatePuzzleDialog.java @@ -233,4 +233,6 @@ public String getRows() { public String getColumns() { return columns.getText(); } + + public String[] getTextArea() { return textArea.getText().split("\n"); } } diff --git a/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java b/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java index 480c4685c..1176f28fa 100644 --- a/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java +++ b/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java @@ -301,8 +301,8 @@ private void setupToolBar1() { JButton create = new JButton("Create", CreateImageIcon); create.setFocusPainted(false); create.addActionListener((ActionEvent) -> { - HomePanel hp = new HomePanel(this.fileDialog, this.frame, this.legupUI); - CreatePuzzleDialog cpd = new CreatePuzzleDialog(this.frame, hp); + hp = new HomePanel(this.fileDialog, this.frame, this.legupUI); + cpd = new CreatePuzzleDialog(this.frame, hp); cpd.setLocationRelativeTo(null); cpd.setVisible(true); }); @@ -338,10 +338,12 @@ private void setupToolBar2() { resetButton.addActionListener( a -> { - hp.openEditorWithNewPuzzle( - cpd.getGame(), - Integer.valueOf(cpd.getRows()), - Integer.valueOf(cpd.getColumns())); + if (cpd.getGame().equals("ShortTruthTable")) { + GameBoardFacade.getInstance().loadPuzzle(cpd.getGame(), cpd.getTextArea()); + } + else { + GameBoardFacade.getInstance().loadPuzzle(cpd.getGame(), Integer.valueOf(cpd.getRows()), Integer.valueOf(cpd.getColumns())); + } }); getToolBar2Buttons()[0] = resetButton; diff --git a/src/main/resources/edu/rpi/legup/images/Legup/Reset.png b/src/main/resources/edu/rpi/legup/images/Legup/Reset.png new file mode 100644 index 0000000000000000000000000000000000000000..fd6ffefa0fd001bd771519e6094c57919b51f2ba GIT binary patch literal 662 zcmV;H0%`q;P)(^b8FWQhbW?9;ba!ELWdL_~cP?peYja~^aAhuUa%Y?FJQ@H10ryEnK~z{r?UqSO z#6TEE+hL&~;Jf$e3Vblb4i~dmL!9j@J(*YIms31lg-lTkxUpb^2)X4Dqu}o z(3TvO)t~@=^_R498?s&U9g}QguSKwN%OB=r+gBXy{GGua~04_B}z_KKR zEHb^>l?>b|fAYr)K>iIt23cf!!HVY|QguHK0Z_oZ)BYV~kVPihzlg73V_vdQ_T&W( z0q{#%^~i)k23cf!t%UB)ckXuV<3Z!!#7ckR+3A=7>n%f(}Xb zukwzDf*^}bvY8_yZ4LYfnVV0t0RBEy+a{^DD99p{Z03ka7VsfYDyO9hcPs+SBAYoP z(r&?_JI=Uc5zM-yWmlz^jVO((8&MW{x8gK{w_?cqFiOH$GRO*g7(t%LaU7c*$;!p5 zv=E;c5}*%#Z5$aj@z*OEa!woH(TBc_VQe8}y_CKWWh72gaC{&})GxDgXcg07*qoM6N<$f~1Tez5oCK literal 0 HcmV?d00001 From 412ea9e0f3bf6127e4f0ecc2e03f90e1a0e3c6b3 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Sun, 28 Jul 2024 19:55:15 -0400 Subject: [PATCH 212/258] Updated binary reference sheet --- .../rules/CompleteRowColumnDirectRule.java | 2 +- .../binary/rules/SaveBlockerDirectRule.java | 2 +- .../binary/rules/binary_reference_sheet.txt | 9 ++- .../rules/SurroundPairDirectRuleTest.java | 66 ------------------- 4 files changed, 6 insertions(+), 73 deletions(-) delete mode 100644 src/test/java/puzzles/binary/rules/SurroundPairDirectRuleTest.java diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java index 527223f5c..37adac329 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java @@ -17,7 +17,7 @@ public class CompleteRowColumnDirectRule extends DirectRule { public CompleteRowColumnDirectRule() { super( - "BINA-BASC-0003", + "BINA-BASC-0002", "Complete Row/Column", "If a row/column of length n contains n/2 of a single value, the remaining cells must contain the other value", "edu/rpi/legup/images/binary/rules/CompleteRowColumnDirectRule.png"); diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/SaveBlockerDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/SaveBlockerDirectRule.java index 24306e6c4..bc4e9716f 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/SaveBlockerDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/SaveBlockerDirectRule.java @@ -14,7 +14,7 @@ public class SaveBlockerDirectRule extends DirectRule { public SaveBlockerDirectRule() { super( - "BINA-BASC-0004", + "BINA-BASC-0003", "Save Blocker", "If a future trio could appear in this row/col, save the digit that could block that trio", "edu/rpi/legup/images/binary/rules/SaveBlockerDirectRule.png"); diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/binary_reference_sheet.txt b/src/main/java/edu/rpi/legup/puzzle/binary/rules/binary_reference_sheet.txt index c3194e349..fd786bcc9 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/binary_reference_sheet.txt +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/binary_reference_sheet.txt @@ -1,8 +1,7 @@ -BINA-BASC-0001 : SurroundPairDirectRule -BINA-BASC-0002 : OneTileGapDirectRule -BINA-BASC-0003 : CompleteRowColumnDirectRule -BINA-BASC-0004 : SaveBlockerDirectRule -BINA-BASC-0005 : UniqueRowColumnDirectRule +BINA-BASC-0001 : PreventTrioContradictionRule +BINA-BASC-0002 : CompleteRowColumnDirectRule +BINA-BASC-0003 : SaveBlockerDirectRule +BINA-BASC-0004 : UniqueRowColumnDirectRule BINA-CONT-0001 : TrioContradictionRule BINA-CONT-0002 : UnbalancedRowColumnContradictionRule diff --git a/src/test/java/puzzles/binary/rules/SurroundPairDirectRuleTest.java b/src/test/java/puzzles/binary/rules/SurroundPairDirectRuleTest.java deleted file mode 100644 index acb9f07de..000000000 --- a/src/test/java/puzzles/binary/rules/SurroundPairDirectRuleTest.java +++ /dev/null @@ -1,66 +0,0 @@ -package puzzles.binary.rules; - -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -import edu.rpi.legup.puzzle.binary.Binary; -import edu.rpi.legup.puzzle.binary.BinaryBoard; -import edu.rpi.legup.puzzle.binary.BinaryCell; -import edu.rpi.legup.puzzle.binary.BinaryType; -import edu.rpi.legup.puzzle.binary.rules.SurroundPairDirectRule; -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 SurroundPairDirectRuleTest { - - private static final SurroundPairDirectRule RULE = new SurroundPairDirectRule(); - private static Binary binary; - - @BeforeClass - public static void setUp() { - MockGameBoardFacade.getInstance(); - binary = new Binary(); - } - - /** - * Tests the SurroundPair direct rule for surrounding a pair of zeros with ones - */ - @Test - public void SurroundPairDirectRule_SurroundTwoZerosWithTwoOnes() throws InvalidFileFormatException { - TestUtilities.importTestBoard( - "puzzles/binary/rules/SurroundPairDirectRule/SurroundTwoZerosWithTwoOnes", binary); - - TreeNode rootNode = binary.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - BinaryBoard board = (BinaryBoard) transition.getBoard(); - BinaryCell cell1 = board.getCell(0, 0); - cell1.setData(BinaryType.ONE.toValue()); - board.addModifiedData(cell1); - - BinaryCell cell2 = board.getCell(3, 0); - cell1.setData(BinaryType.ONE.toValue()); - board.addModifiedData(cell2); - - //Assert.assertNull(RULE.checkRule(transition)); - -// Point location1 = new Point(0, 0); -// Point location2 = new Point(3, 0); -// 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(location1) || point.equals(location2)) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } else { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } -// } -// } - } - -} From f3a97e6230044f3d77458aaddf44f01b16a2f07c Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Sun, 28 Jul 2024 19:56:22 -0400 Subject: [PATCH 213/258] Fixed undo redo error when deleting nodes --- .../history/DeleteTreeElementCommand.java | 10 +++- .../java/edu/rpi/legup/model/tree/Tree.java | 16 ++----- .../rpi/legup/model/tree/TreeTransition.java | 19 ++++++++ .../ui/proofeditorui/treeview/TreeView.java | 46 +++++++++---------- 4 files changed, 54 insertions(+), 37 deletions(-) diff --git a/src/main/java/edu/rpi/legup/history/DeleteTreeElementCommand.java b/src/main/java/edu/rpi/legup/history/DeleteTreeElementCommand.java index 35a56c652..ece424e7e 100644 --- a/src/main/java/edu/rpi/legup/history/DeleteTreeElementCommand.java +++ b/src/main/java/edu/rpi/legup/history/DeleteTreeElementCommand.java @@ -20,20 +20,25 @@ public DeleteTreeElementCommand(TreeViewSelection selection) { this.selection = selection.copy(); } - /** Executes an command */ + /** Executes a command */ @Override public void executeCommand() { Tree tree = GameBoardFacade.getInstance().getTree(); Puzzle puzzle = GameBoardFacade.getInstance().getPuzzleModule(); List selectedViews = selection.getSelectedViews(); + if (selectedViews.isEmpty()) { + return; + } TreeElementView firstSelectedView = selectedViews.get(0); TreeElementView newSelectedView; if (firstSelectedView.getType() == TreeElementType.NODE) { + //System.out.println("FIRST SELECTION NODE, total selection views: " + selectedViews.size()); TreeNodeView nodeView = (TreeNodeView) firstSelectedView; newSelectedView = nodeView.getParentView(); } else { + //System.out.println("FIRST SELECTION TRANS, total selection views: " + selectedViews.size()); TreeTransitionView transitionView = (TreeTransitionView) firstSelectedView; newSelectedView = transitionView.getParentViews().get(0); } @@ -75,17 +80,20 @@ public String getErrorString() { /** Undoes a command */ @Override public void undoCommand() { + System.out.println("UNDOED"); Puzzle puzzle = GameBoardFacade.getInstance().getPuzzleModule(); List selectedViews = selection.getSelectedViews(); for (TreeElementView selectedView : selectedViews) { TreeElement element = selectedView.getTreeElement(); if (element.getType() == TreeElementType.NODE) { + System.out.println("ADDING A NODE"); TreeNode node = (TreeNode) element; node.getParent().setChildNode(node); puzzle.notifyTreeListeners(listener -> listener.onTreeElementAdded(node)); } else { + System.out.println("ADDING A TRANSITION"); TreeTransition transition = (TreeTransition) element; transition.getParents().forEach(node -> node.addChild(transition)); transition.getParents().get(0).getChildren().forEach(TreeTransition::reverify); diff --git a/src/main/java/edu/rpi/legup/model/tree/Tree.java b/src/main/java/edu/rpi/legup/model/tree/Tree.java index 56cfbff07..471d8ccb6 100644 --- a/src/main/java/edu/rpi/legup/model/tree/Tree.java +++ b/src/main/java/edu/rpi/legup/model/tree/Tree.java @@ -82,21 +82,13 @@ public TreeElement addTreeElement(TreeTransition transition, TreeNode treeNode) public void removeTreeElement(TreeElement element) { if (element.getType() == TreeElementType.NODE) { TreeNode node = (TreeNode) element; + System.out.println("Recognized node: " + node); - // Output when node has children - if (!node.getChildren().isEmpty()) { - System.out.println("Deleting children of node: " + node); - for (TreeTransition child : new ArrayList<>(node.getChildren())) { - removeTreeElement(child); - } - } - + node.getParent().removeChild(node); node.getParent().setChildNode(null); - - System.out.println("Deleted node: " + node); } else { TreeTransition transition = (TreeTransition) element; - System.out.println("Deleted arrow: " + transition); + System.out.println("Recognized transition: " + transition); transition.getParents().forEach(n -> n.removeChild(transition)); TreeController treeController = new TreeController(); @@ -106,8 +98,6 @@ public void removeTreeElement(TreeElement element) { } } - - /** * Determines if the tree is valid by checking whether this tree puzzleElement and all * descendants of this tree puzzleElement is justified and justified correctly diff --git a/src/main/java/edu/rpi/legup/model/tree/TreeTransition.java b/src/main/java/edu/rpi/legup/model/tree/TreeTransition.java index e79cd4b96..22ea33466 100644 --- a/src/main/java/edu/rpi/legup/model/tree/TreeTransition.java +++ b/src/main/java/edu/rpi/legup/model/tree/TreeTransition.java @@ -332,6 +332,25 @@ public void setChildNode(TreeNode childNode) { this.childNode = childNode; } + /** + * Removes the child to this tree transition + * + * @param child child to remove + */ + public void removeChild(TreeNode child) { + parents.remove(child); + } + + /** + * Add the child to this tree transition + * + * @param child child to add + */ + public void addChild(TreeNode child) { + parents.add(child); + } + + /** * Gets the rule associated with this transition * diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeView.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeView.java index d7fffd1bf..38cb20abd 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeView.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeView.java @@ -407,8 +407,13 @@ public TreeElementView getElementView(TreeElement element) { return viewMap.get(element); } - private void removeTreeNode(TreeNode node) { + public void removeTreeNode(TreeNode node) { + System.out.println("DELETED NODE"); viewMap.remove(node); + if (node.getChildren() != null) { + node.getChildren().forEach(t -> removeTreeTransition(t)); + } + List children = node.getChildren(); // if child is a case rule, unlock ancestor elements @@ -435,11 +440,13 @@ private void removeTreeNode(TreeNode node) { } // set modifiable if started modifiable - boolean modifiable = - tree.getRootNode() - .getBoard() - .getPuzzleElement(oldElement) - .isModifiable(); + boolean modifiable = false; + if (tree != null) { + tree.getRootNode() + .getBoard() + .getPuzzleElement(oldElement) + .isModifiable(); + } // unmodifiable if already modified TreeNode modNode = ancestor.getParent().getParents().get(0); @@ -457,10 +464,10 @@ private void removeTreeNode(TreeNode node) { } } } - node.getChildren().forEach(t -> removeTreeTransition(t)); } public void removeTreeTransition(TreeTransition trans) { + System.out.println("DELETED TRANS"); viewMap.remove(trans); if (trans.getChildNode() != null) { removeTreeNode(trans.getChildNode()); @@ -497,10 +504,9 @@ public void removeTreeTransition(TreeTransition trans) { private void addTreeNode(TreeNode node) { TreeTransition parent = node.getParent(); - TreeNodeView nodeView = new TreeNodeView(node); - TreeTransitionView parentView = (TreeTransitionView) viewMap.get(parent); + TreeTransitionView parentView = (TreeTransitionView) viewMap.get(parent); nodeView.setParentView(parentView); parentView.setChildView(nodeView); @@ -520,8 +526,7 @@ private void addTreeNode(TreeNode node) { continue; } for (PuzzleElement element : - caseRule.dependentElements( - node.getBoard(), node.getChildren().get(0).getSelection())) { + caseRule.dependentElements(node.getBoard(), node.getChildren().get(0).getSelection())) { // increment and lock PuzzleElement oldElement = ancestor.getParent().getBoard().getPuzzleElement(element); @@ -532,23 +537,27 @@ private void addTreeNode(TreeNode node) { } node.getChildren().forEach(t -> addTreeTransition(t)); + } else { + System.out.println("NO CHILDREN"); } } private void addTreeTransition(TreeTransition trans) { - List parents = trans.getParents(); + System.out.println("HI"); + List parents = trans.getParents(); TreeTransitionView transView = new TreeTransitionView(trans); + for (TreeNode parent : parents) { TreeNodeView parentNodeView = (TreeNodeView) viewMap.get(parent); transView.addParentView(parentNodeView); parentNodeView.addChildrenView(transView); + viewMap.put(trans, transView); + // if transition is a new case rule, lock dependent ancestor elements Rule rule = trans.getRule(); if (rule instanceof CaseRule && parent.getChildren().size() == 1) { - //CaseRule caseRule = (CaseRule) rule; - List ancestors = parent.getAncestors(); for (TreeNode ancestor : ancestors) { // for all ancestors but root @@ -560,25 +569,16 @@ private void addTreeTransition(TreeTransition trans) { PuzzleElement curElement = ancestor.getParent().getBoard().getPuzzleElement(element); curElement.setModifiableCaseRule(false); } -// for (PuzzleElement element : caseRule.dependentElements(parent.getBoard(), trans.getSelection())) { -// // increment and lock -// PuzzleElement oldElement = ancestor.getParent().getBoard().getPuzzleElement(element); -// oldElement.setCasesDepended(oldElement.getCasesDepended() + 1); -// oldElement.setModifiable(false); -// } } } } - viewMap.put(trans, transView); - if (trans.getChildNode() != null) { addTreeNode(trans.getChildNode()); } } /// New Draw Methods - public void drawTree(Graphics2D graphics2D) { if (tree == null) { LOGGER.error("Unable to draw tree."); From b2ba642fe62154590d03eb3697c8c006cf513154 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Mon, 29 Jul 2024 11:48:10 -0400 Subject: [PATCH 214/258] Enhanced UniqueRowColumn direct rule --- .../rules/UniqueRowColumnDirectRule.java | 120 ++++++++++++++++-- 1 file changed, 108 insertions(+), 12 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UniqueRowColumnDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UniqueRowColumnDirectRule.java index 5dc2d4f38..2f8a95a8a 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UniqueRowColumnDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UniqueRowColumnDirectRule.java @@ -20,7 +20,7 @@ public UniqueRowColumnDirectRule() { super( "BINA-BASC-0004", "Unique Row/Column", - "If an unfinished row/column only differs by two empty cells from a finished one, fill empty cells with the opposite digits", + "If an unfinished row/column only differs by empty cells from a finished one, fill contradicting empty cells with opposite digit to prevent a repeated row/column", "edu/rpi/legup/images/binary/rules/UniqueRowColumnDirectRule.png"); } @@ -36,8 +36,9 @@ private int getNumEmpty(ArrayList seq) { } return numEmpty; } - private String checkSequence(ArrayList seq, BinaryBoard origBoard, BinaryCell binaryCell, int rowOrColumn) { + private String checkOppositeDigitDifference(ArrayList seq, BinaryBoard origBoard, BinaryCell binaryCell, int rowOrColumn) { // rowOrColumn : 0 for row, 1 for column + int numEmpty = getNumEmpty(seq); if (numEmpty > 2) { return "Row/Col must have at most 2 empty cells"; @@ -62,7 +63,8 @@ private String checkSequence(ArrayList seq, BinaryBoard origBoard, B for (int j = 0; j < currSeq.size(); j++) { int numEmptyInCurrSeq = getNumEmpty(currSeq); if (numEmptyInCurrSeq != 0) { - continue; + valid = false; + break; } if (!seq.get(j).equals(currSeq.get(j)) && !seq.get(j).equals(BinaryType.UNKNOWN)) { if (++numDifferentCells > 1 || numEmpty != 1) { @@ -70,8 +72,6 @@ private String checkSequence(ArrayList seq, BinaryBoard origBoard, B break; } } - System.out.println(" POS X: " + j + " Y: " + i); - System.out.println(" CEL X: " + binaryCell.getLocation().x + " Y: " + binaryCell.getLocation().y); if (currSeq.get(j).equals(BinaryType.ZERO) && seq.get(j).equals(BinaryType.UNKNOWN) && binaryCell.getType().equals(BinaryType.ONE)) { if ((rowOrColumn == 0 && binaryCell.getLocation().x == j) || rowOrColumn == 1 && binaryCell.getLocation().y == j) { @@ -83,33 +83,129 @@ else if (currSeq.get(j).equals(BinaryType.ONE) && seq.get(j).equals(BinaryType.U valid = true; } } - System.out.println(j); } if (valid) { break; } } - if (!valid) { - return "Rule is not applicable"; + if (valid) { + return null; } - return null; + return "Rule is not applicable"; + } + + private String checkRemainingOneDigitDifference(ArrayList seq, BinaryBoard origBoard, BinaryCell binaryCell, int rowOrColumn, int zeroOrOne) { + // zeroOrOne: zero for 0, one for 1 + + for (int i = 0; i < seq.size(); i++) { + ArrayList currSeq; + if (rowOrColumn == 0) { + if (i == binaryCell.getLocation().y) { + continue; + } + currSeq = origBoard.getRowTypes(i); + } + else { + if (i == binaryCell.getLocation().x) { + continue; + } + currSeq = origBoard.getColTypes(i); + } + + boolean valid = true; + for (int j = 0; j < currSeq.size(); j++) { + int numEmptyInCurrSeq = getNumEmpty(currSeq); + if (numEmptyInCurrSeq != 0) { + valid = false; + break; + } + if (!seq.get(j).equals(currSeq.get(j)) && !seq.get(j).equals(BinaryType.UNKNOWN)) { + valid = false; + break; + } + } + if (valid) { + BinaryType currSeqCell = currSeq.get(binaryCell.getLocation().x); + if (rowOrColumn == 0) { + currSeqCell = currSeq.get(binaryCell.getLocation().x); + } else if (rowOrColumn == 1) { + currSeqCell = currSeq.get(binaryCell.getLocation().y); + } + + if (zeroOrOne == 0) { + if (currSeqCell.equals(BinaryType.ZERO) && binaryCell.getType().equals(BinaryType.ONE)) { + return null; + } + } + else if (zeroOrOne == 1) { + if (currSeqCell.equals(BinaryType.ONE) && binaryCell.getType().equals(BinaryType.ZERO)) { + return null; + } + } + } + } + return "Rule is not applicable"; } + + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { BinaryBoard origBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); BinaryCell binaryCell = (BinaryCell) puzzleElement; - ArrayList row = origBoard.getRowTypes(binaryCell.getLocation().y); - if (checkSequence(row, origBoard, binaryCell, 0) == null) { + if (checkOppositeDigitDifference(row, origBoard, binaryCell, 0) == null) { return null; } + int numZeros = 0; + int numOnes = 0; + for (int i = 0; i < row.size(); i++) { + if (row.get(i).equals(BinaryType.ZERO)) { + numZeros++; + } + else if (row.get(i).equals(BinaryType.ONE)) { + numOnes++; + } + } + + if (numZeros == row.size()/2 - 1) { + if (checkRemainingOneDigitDifference(row, origBoard, binaryCell, 0, 0) == null) { + return null; + } + } + if (numOnes == row.size()/2 - 1) { + if (checkRemainingOneDigitDifference(row, origBoard, binaryCell, 0, 1) == null) { + return null; + } + } ArrayList col = origBoard.getColTypes(binaryCell.getLocation().x); - if (checkSequence(col, origBoard, binaryCell, 1) == null) { + if (checkOppositeDigitDifference(col, origBoard, binaryCell, 1) == null) { return null; } + numZeros = 0; + numOnes = 0; + for (int i = 0; i < col.size(); i++) { + if (col.get(i).equals(BinaryType.ZERO)) { + numZeros++; + } + else if (col.get(i).equals(BinaryType.ONE)) { + numOnes++; + } + } + + if (numZeros == col.size()/2 - 1) { + if (checkRemainingOneDigitDifference(col, origBoard, binaryCell, 1, 0) == null) { + return null; + } + } + if (numOnes == col.size()/2 - 1) { + if (checkRemainingOneDigitDifference(col, origBoard, binaryCell, 1, 1) == null) { + return null; + } + } + return "Rule is not applicable"; } From b2c93b9397c22d9a59697fb6f661b7936bed5689 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Mon, 29 Jul 2024 11:48:52 -0400 Subject: [PATCH 215/258] Fixed reset button for both opening existing file or creating new file for puzzle editor --- .../edu/rpi/legup/ui/PuzzleEditorPanel.java | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java b/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java index 1176f28fa..651c443fa 100644 --- a/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java +++ b/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java @@ -61,6 +61,9 @@ public class PuzzleEditorPanel extends LegupPanel implements IHistoryListener { private EditorElementController editorElementController; private CreatePuzzleDialog cpd; private HomePanel hp; + private boolean existingPuzzle; + private String fileName; + private File puzzleFile; public PuzzleEditorPanel(FileDialog fileDialog, JFrame frame, LegupUI legupUI) { this.fileDialog = fileDialog; @@ -128,6 +131,7 @@ public void setMenuBar() { cpd = new CreatePuzzleDialog(this.frame, hp); cpd.setLocationRelativeTo(null); cpd.setVisible(true); + existingPuzzle = false; }); if (os.equals("mac")) { createPuzzle.setAccelerator( @@ -305,6 +309,7 @@ private void setupToolBar1() { cpd = new CreatePuzzleDialog(this.frame, hp); cpd.setLocationRelativeTo(null); cpd.setVisible(true); + existingPuzzle = false; }); getToolBar1Buttons()[1] = create; @@ -338,11 +343,16 @@ private void setupToolBar2() { resetButton.addActionListener( a -> { - if (cpd.getGame().equals("ShortTruthTable")) { - GameBoardFacade.getInstance().loadPuzzle(cpd.getGame(), cpd.getTextArea()); + if (existingPuzzle) { + legupUI.getPuzzleEditor().loadPuzzle(fileName, puzzleFile); } else { - GameBoardFacade.getInstance().loadPuzzle(cpd.getGame(), Integer.valueOf(cpd.getRows()), Integer.valueOf(cpd.getColumns())); + if (cpd.getGame().equals("ShortTruthTable")) { + GameBoardFacade.getInstance().loadPuzzle(cpd.getGame(), cpd.getTextArea()); + } + else { + GameBoardFacade.getInstance().loadPuzzle(cpd.getGame(), Integer.valueOf(cpd.getRows()), Integer.valueOf(cpd.getColumns())); + } } }); @@ -494,6 +504,9 @@ public void loadPuzzle(String fileName, File puzzleFile) { GameBoardFacade.getInstance().loadPuzzleEditor(fileName); String puzzleName = GameBoardFacade.getInstance().getPuzzleModule().getName(); frame.setTitle(puzzleName + " - " + puzzleFile.getName()); + existingPuzzle = true; + this.fileName = fileName; + this.puzzleFile = puzzleFile; } catch (InvalidFileFormatException e) { legupUI.displayPanel(0); LOGGER.error(e.getMessage()); From d22226d3e3cffd274e6dadc3dff604c7a0d81233 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Mon, 29 Jul 2024 11:55:40 -0400 Subject: [PATCH 216/258] Fixed puzzle editor malfunction under multiple puzzles --- .../java/edu/rpi/legup/puzzle/binary/BinaryCell.java | 6 +++--- .../edu/rpi/legup/puzzle/fillapix/FillapixCell.java | 6 +++--- .../java/edu/rpi/legup/puzzle/lightup/LightUpCell.java | 8 ++++---- .../edu/rpi/legup/puzzle/nurikabe/NurikabeCell.java | 6 +++--- .../puzzle/shorttruthtable/ShortTruthTableCell.java | 10 +++++----- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java index 6c78034d8..7a2abf64e 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java @@ -53,11 +53,11 @@ public void setType(Element e, MouseEvent m) { } else { if (m.getButton() == MouseEvent.BUTTON3) { - if (this.data == 0) { - this.data = 1; + if (this.data == 1) { + this.data = 0; } else { - this.data = 0; + this.data = 1; } } } diff --git a/src/main/java/edu/rpi/legup/puzzle/fillapix/FillapixCell.java b/src/main/java/edu/rpi/legup/puzzle/fillapix/FillapixCell.java index a9e5aa2df..40c5e4a54 100644 --- a/src/main/java/edu/rpi/legup/puzzle/fillapix/FillapixCell.java +++ b/src/main/java/edu/rpi/legup/puzzle/fillapix/FillapixCell.java @@ -42,13 +42,13 @@ public void setCellType(FillapixCellType type) { @Override public void setType(Element e, MouseEvent m) { switch (e.getElementID()) { - case "FPIX-PLAC-0001": + case "FPIX-ELEM-0001": this.setCellType(FillapixCellType.BLACK); break; - case "FPIX-PLAC-0002": + case "FPIX-ELEM-0004": this.setCellType(FillapixCellType.WHITE); break; - case "FPIX-UNPL-0001": + case "FPIX-ELEM-0002": int n = this.getNumber(); switch (m.getButton()) { case MouseEvent.BUTTON1: diff --git a/src/main/java/edu/rpi/legup/puzzle/lightup/LightUpCell.java b/src/main/java/edu/rpi/legup/puzzle/lightup/LightUpCell.java index 8adf84cb4..6d890e67b 100644 --- a/src/main/java/edu/rpi/legup/puzzle/lightup/LightUpCell.java +++ b/src/main/java/edu/rpi/legup/puzzle/lightup/LightUpCell.java @@ -16,16 +16,16 @@ public LightUpCell(int valueInt, Point location) { @Override public void setType(Element e, MouseEvent m) { switch (e.getElementID()) { - case "LTUP-PLAC-0001": + case "LTUP-ELEM-0002": this.data = -4; break; - case "LTUP-UNPL-0002": + case "LTUP-ELEM-0001": this.data = -1; break; - case "LTUP-UNPL-0003": + case "LTUP-ELEM-0004": this.data = -2; break; - case "LTUP-UNPL-0001": + case "LTUP-ELEM-0003": switch (m.getButton()) { case MouseEvent.BUTTON1: if (this.data < 0 || this.data > 3) { diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeCell.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeCell.java index c6cd2c64e..1e0e85ed8 100644 --- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeCell.java +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeCell.java @@ -46,13 +46,13 @@ public NurikabeType getType() { @Override public void setType(Element e, MouseEvent m) { switch (e.getElementID()) { - case "NURI-PLAC-0001": + case "NURI-ELEM-0001": this.data = -1; break; - case "NURI-PLAC-0002": + case "NURI-ELEM-0004": this.data = 0; break; - case "NURI-UNPL-0001": + case "NURI-ELEM-0002": switch (m.getButton()) { case MouseEvent.BUTTON1: if (this.data <= 0 || this.data > 8) { diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/ShortTruthTableCell.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/ShortTruthTableCell.java index 75bba369f..ffd7c491d 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/ShortTruthTableCell.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/ShortTruthTableCell.java @@ -135,22 +135,22 @@ public void setType(Element e, MouseEvent m) { } // Red Element - if (e.getElementID().equals("STTT-PLAC-0002")) { + if (e.getElementID().equals("STTT-ELEM-0004")) { this.data = ShortTruthTableCellType.FALSE; } // Green Element else { - if (e.getElementID().equals("STTT-PLAC-0001")) { + if (e.getElementID().equals("STTT-ELEM-0002")) { this.data = ShortTruthTableCellType.TRUE; } // Unknown Element else { - if (e.getElementID().equals("STTT-PLAC-0003")) { + if (e.getElementID().equals("STTT-ELEM-0005")) { this.data = ShortTruthTableCellType.UNKNOWN; } // Argument Element else { - if (e.getElementID().equals("STTT-UNPL-0001")) { + if (e.getElementID().equals("STTT-ELEM-0001")) { // Prevents non-argument symbols from being changed if (!(this.symbol >= 'A' && this.symbol <= 'Z')) { return; @@ -172,7 +172,7 @@ public void setType(Element e, MouseEvent m) { } // And/Or Element else { - if (e.getElementID().equals("STTT-UNPL-0002")) { + if (e.getElementID().equals("STTT-ELEM-0003")) { if (m.getButton() == MouseEvent.BUTTON1) { if (this.symbol == '^') { this.symbol = '|'; From f61454c3154fc2c99b0bab6ec2f9ceb0e1da62d6 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Mon, 29 Jul 2024 21:49:14 -0400 Subject: [PATCH 217/258] Updated sudoku image directories --- .../rpi/legup/controller/ElementController.java | 2 ++ src/main/java/edu/rpi/legup/model/Puzzle.java | 8 ++++++++ .../edu/rpi/legup/puzzle/sudoku/Sudoku.java | 1 + .../rpi/legup/puzzle/sudoku/SudokuImporter.java | 1 + .../puzzle/sudoku/elements/NumberTile.java | 2 +- .../rules/AdvancedDeductionDirectRule.java | 2 +- .../rules/LastCellForNumberDirectRule.java | 2 +- .../rules/LastNumberForCellDirectRule.java | 2 +- .../rules/NoSolutionContradictionRule.java | 2 +- .../sudoku/rules/PossibleCellCaseRule.java | 2 +- .../sudoku/rules/PossibleNumberCaseRule.java | 2 +- .../rules/RepeatedNumberContradictionRule.java | 2 +- .../edu/rpi/legup/ui/PuzzleEditorPanel.java | 1 - .../legup/images/sudoku/elements/NumberTile.png | Bin 0 -> 10067 bytes .../sudoku/{ => rules}/AdvancedDeduction.png | Bin .../images/sudoku/{ => rules}/NoSolution.png | Bin .../sudoku/{ => rules}/PossibleValues.png | Bin .../sudoku/{ => rules}/RepeatedNumber.png | Bin .../sudoku/{ => rules}/forcedByDeduction.png | Bin .../sudoku/{ => rules}/forcedByElimination.png | Bin .../{ => rules}/possible_cells_number.png | Bin .../rpi/legup/images/sudoku/{ => rules}/tem.png | Bin .../legup/images/sudoku/tiles/NumberTile.png | Bin 0 -> 10067 bytes src/main/resources/edu/rpi/legup/legup/config | 2 +- 24 files changed, 21 insertions(+), 10 deletions(-) create mode 100644 src/main/resources/edu/rpi/legup/images/sudoku/elements/NumberTile.png rename src/main/resources/edu/rpi/legup/images/sudoku/{ => rules}/AdvancedDeduction.png (100%) rename src/main/resources/edu/rpi/legup/images/sudoku/{ => rules}/NoSolution.png (100%) rename src/main/resources/edu/rpi/legup/images/sudoku/{ => rules}/PossibleValues.png (100%) rename src/main/resources/edu/rpi/legup/images/sudoku/{ => rules}/RepeatedNumber.png (100%) rename src/main/resources/edu/rpi/legup/images/sudoku/{ => rules}/forcedByDeduction.png (100%) rename src/main/resources/edu/rpi/legup/images/sudoku/{ => rules}/forcedByElimination.png (100%) rename src/main/resources/edu/rpi/legup/images/sudoku/{ => rules}/possible_cells_number.png (100%) rename src/main/resources/edu/rpi/legup/images/sudoku/{ => rules}/tem.png (100%) create mode 100644 src/main/resources/edu/rpi/legup/images/sudoku/tiles/NumberTile.png diff --git a/src/main/java/edu/rpi/legup/controller/ElementController.java b/src/main/java/edu/rpi/legup/controller/ElementController.java index 5840650e1..8b361f123 100644 --- a/src/main/java/edu/rpi/legup/controller/ElementController.java +++ b/src/main/java/edu/rpi/legup/controller/ElementController.java @@ -86,6 +86,7 @@ public void mouseReleased(MouseEvent e) { if (boardView == null) { boardView = getInstance().getLegupUI().getEditorBoardView(); } + Board board = boardView.getBoard(); ElementView elementView = boardView.getElement(e.getPoint()); TreeViewSelection selection = null; @@ -137,6 +138,7 @@ public void mouseReleased(MouseEvent e) { if (this.boardView.getBoard() instanceof TreeTentBoard) { scaledPoint.setLocation(scaledPoint.getX() - 1, scaledPoint.getY() - 1); } + System.out.printf( "selected Element is NOT null, attempting to change board at (%d, %d)\n", scaledPoint.x, scaledPoint.y); diff --git a/src/main/java/edu/rpi/legup/model/Puzzle.java b/src/main/java/edu/rpi/legup/model/Puzzle.java index 0f6e928f0..a7cea6587 100644 --- a/src/main/java/edu/rpi/legup/model/Puzzle.java +++ b/src/main/java/edu/rpi/legup/model/Puzzle.java @@ -77,6 +77,10 @@ private void registerPuzzleElements() { for (Class c : possElements) { + String classPackageName = c.getPackage().getName(); + if (!classPackageName.startsWith("edu.rpi.legup.puzzle.") || !classPackageName.endsWith(".elements")) { + continue; + } System.out.println("possible element: " + c.getName()); // check that the element is not abstract @@ -124,6 +128,10 @@ private void registerRules() { for (Class c : possRules) { + String classPackageName = c.getPackage().getName(); + if (!classPackageName.startsWith("edu.rpi.legup.puzzle.") || !classPackageName.endsWith(".rules")) { + continue; + } System.out.println("possible rule: " + c.getName()); // check that the rule is not abstract diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/Sudoku.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/Sudoku.java index 877c92665..d6e8a08e2 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/Sudoku.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/Sudoku.java @@ -29,6 +29,7 @@ public BoardView getBoardView() { @Override public void initializeView() { boardView = new SudokuView((SudokuBoard) currentBoard); + boardView.setBoard(currentBoard); } /** diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuImporter.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuImporter.java index 68bf1e795..837eb7315 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuImporter.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuImporter.java @@ -48,6 +48,7 @@ public void initializeBoard(int rows, int columns) { } puzzle.setCurrentBoard(sudokuBoard); + System.out.println(sudokuBoard); } /** diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/elements/NumberTile.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/elements/NumberTile.java index c8181b9e3..681583022 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/elements/NumberTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/elements/NumberTile.java @@ -6,7 +6,7 @@ public class NumberTile extends PlaceableElement { private int object_num; public NumberTile() { - super("SUDO-ELEM-0001", "Number Tile", "A numbered tile", null); + super("SUDO-ELEM-0001", "Number Tile", "A numbered tile", "edu/rpi/legup/images/sudoku/tiles/NumberTile.png"); object_num = 0; } diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/AdvancedDeductionDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/AdvancedDeductionDirectRule.java index 190679b41..51f68c8b8 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/AdvancedDeductionDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/AdvancedDeductionDirectRule.java @@ -16,7 +16,7 @@ public AdvancedDeductionDirectRule() { "Advanced Deduction", "Use of group logic deduces more answers by means of forced by Location and forced" + " by Deduction", - "edu/rpi/legup/images/sudoku/AdvancedDeduction.png"); + "edu/rpi/legup/images/sudoku/rules/AdvancedDeduction.png"); } /** diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/LastCellForNumberDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/LastCellForNumberDirectRule.java index fd03ef36c..5209d72eb 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/LastCellForNumberDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/LastCellForNumberDirectRule.java @@ -15,7 +15,7 @@ public LastCellForNumberDirectRule() { "SUDO-BASC-0002", "Last Cell for Number", "This is the only cell open in its group for some number.", - "edu/rpi/legup/images/sudoku/forcedByElimination.png"); + "edu/rpi/legup/images/sudoku/rules/forcedByElimination.png"); } /** diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/LastNumberForCellDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/LastNumberForCellDirectRule.java index ca0ac3023..be84680d7 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/LastNumberForCellDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/LastNumberForCellDirectRule.java @@ -16,7 +16,7 @@ public LastNumberForCellDirectRule() { "SUDO-BASC-0003", "Last Number for Cell", "This is the only number left that can fit in the cell of a group.", - "edu/rpi/legup/images/sudoku/forcedByDeduction.png"); + "edu/rpi/legup/images/sudoku/rules/forcedByDeduction.png"); } /** diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoSolutionContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoSolutionContradictionRule.java index e44728d3e..0c83de4a6 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoSolutionContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoSolutionContradictionRule.java @@ -15,7 +15,7 @@ public NoSolutionContradictionRule() { "SUDO-CONT-0001", "No Solution for Cell", "Process of elimination yields no valid numbers for an empty cell.", - "edu/rpi/legup/images/sudoku/NoSolution.png"); + "edu/rpi/legup/images/sudoku/rules/NoSolution.png"); } /** diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellCaseRule.java index ccc428486..7279ae595 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellCaseRule.java @@ -17,7 +17,7 @@ public PossibleCellCaseRule() { "SUDO-CASE-0001", "Possible Cells for Number", "A number has a limited set of cells in which it can be placed.", - "edu/rpi/legup/images/sudoku/possible_cells_number.png"); + "edu/rpi/legup/images/sudoku/rules/possible_cells_number.png"); } /** diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleNumberCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleNumberCaseRule.java index a516a06fb..5ed3a29cb 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleNumberCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleNumberCaseRule.java @@ -20,7 +20,7 @@ public PossibleNumberCaseRule() { "SUDO-CASE-0002", "Possible Numbers for Cell", "An empty cell has a limited set of possible numbers that can fill it.", - "edu/rpi/legup/images/sudoku/PossibleValues.png"); + "edu/rpi/legup/images/sudoku/rules/PossibleValues.png"); } /** diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/RepeatedNumberContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/RepeatedNumberContradictionRule.java index 955414e8e..860f41e5e 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/RepeatedNumberContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/RepeatedNumberContradictionRule.java @@ -15,7 +15,7 @@ public RepeatedNumberContradictionRule() { "SUDO-CONT-0002", "Repeated Numbers", "Two identical numbers are placed in the same group.", - "edu/rpi/legup/images/sudoku/RepeatedNumber.png"); + "edu/rpi/legup/images/sudoku/rules/RepeatedNumber.png"); } /** diff --git a/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java b/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java index 651c443fa..c631990d0 100644 --- a/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java +++ b/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java @@ -578,7 +578,6 @@ public void setPuzzleView(Puzzle puzzle) { dynamicBoardView.setBorder(titleBoard); puzzle.addBoardListener(puzzle.getBoardView()); - System.out.println("Setting elements"); if (this.elementFrame != null) { elementFrame.setElements(puzzle); } diff --git a/src/main/resources/edu/rpi/legup/images/sudoku/elements/NumberTile.png b/src/main/resources/edu/rpi/legup/images/sudoku/elements/NumberTile.png new file mode 100644 index 0000000000000000000000000000000000000000..5a8540d02b509f12c7f059648bbadf021efcedda GIT binary patch literal 10067 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/edu/rpi/legup/images/sudoku/AdvancedDeduction.png b/src/main/resources/edu/rpi/legup/images/sudoku/rules/AdvancedDeduction.png similarity index 100% rename from src/main/resources/edu/rpi/legup/images/sudoku/AdvancedDeduction.png rename to src/main/resources/edu/rpi/legup/images/sudoku/rules/AdvancedDeduction.png diff --git a/src/main/resources/edu/rpi/legup/images/sudoku/NoSolution.png b/src/main/resources/edu/rpi/legup/images/sudoku/rules/NoSolution.png similarity index 100% rename from src/main/resources/edu/rpi/legup/images/sudoku/NoSolution.png rename to src/main/resources/edu/rpi/legup/images/sudoku/rules/NoSolution.png diff --git a/src/main/resources/edu/rpi/legup/images/sudoku/PossibleValues.png b/src/main/resources/edu/rpi/legup/images/sudoku/rules/PossibleValues.png similarity index 100% rename from src/main/resources/edu/rpi/legup/images/sudoku/PossibleValues.png rename to src/main/resources/edu/rpi/legup/images/sudoku/rules/PossibleValues.png diff --git a/src/main/resources/edu/rpi/legup/images/sudoku/RepeatedNumber.png b/src/main/resources/edu/rpi/legup/images/sudoku/rules/RepeatedNumber.png similarity index 100% rename from src/main/resources/edu/rpi/legup/images/sudoku/RepeatedNumber.png rename to src/main/resources/edu/rpi/legup/images/sudoku/rules/RepeatedNumber.png diff --git a/src/main/resources/edu/rpi/legup/images/sudoku/forcedByDeduction.png b/src/main/resources/edu/rpi/legup/images/sudoku/rules/forcedByDeduction.png similarity index 100% rename from src/main/resources/edu/rpi/legup/images/sudoku/forcedByDeduction.png rename to src/main/resources/edu/rpi/legup/images/sudoku/rules/forcedByDeduction.png diff --git a/src/main/resources/edu/rpi/legup/images/sudoku/forcedByElimination.png b/src/main/resources/edu/rpi/legup/images/sudoku/rules/forcedByElimination.png similarity index 100% rename from src/main/resources/edu/rpi/legup/images/sudoku/forcedByElimination.png rename to src/main/resources/edu/rpi/legup/images/sudoku/rules/forcedByElimination.png diff --git a/src/main/resources/edu/rpi/legup/images/sudoku/possible_cells_number.png b/src/main/resources/edu/rpi/legup/images/sudoku/rules/possible_cells_number.png similarity index 100% rename from src/main/resources/edu/rpi/legup/images/sudoku/possible_cells_number.png rename to src/main/resources/edu/rpi/legup/images/sudoku/rules/possible_cells_number.png diff --git a/src/main/resources/edu/rpi/legup/images/sudoku/tem.png b/src/main/resources/edu/rpi/legup/images/sudoku/rules/tem.png similarity index 100% rename from src/main/resources/edu/rpi/legup/images/sudoku/tem.png rename to src/main/resources/edu/rpi/legup/images/sudoku/rules/tem.png diff --git a/src/main/resources/edu/rpi/legup/images/sudoku/tiles/NumberTile.png b/src/main/resources/edu/rpi/legup/images/sudoku/tiles/NumberTile.png new file mode 100644 index 0000000000000000000000000000000000000000..5a8540d02b509f12c7f059648bbadf021efcedda GIT binary patch literal 10067 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/edu/rpi/legup/legup/config b/src/main/resources/edu/rpi/legup/legup/config index 5e45d6f91..456064239 100644 --- a/src/main/resources/edu/rpi/legup/legup/config +++ b/src/main/resources/edu/rpi/legup/legup/config @@ -43,7 +43,7 @@ + fileCreationDisabled="false"/> Date: Mon, 29 Jul 2024 21:49:33 -0400 Subject: [PATCH 218/258] Removed debug print statements --- .../edu/rpi/legup/ui/proofeditorui/treeview/TreeView.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeView.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeView.java index 38cb20abd..12f8df428 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeView.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeView.java @@ -467,7 +467,6 @@ public void removeTreeNode(TreeNode node) { } public void removeTreeTransition(TreeTransition trans) { - System.out.println("DELETED TRANS"); viewMap.remove(trans); if (trans.getChildNode() != null) { removeTreeNode(trans.getChildNode()); @@ -537,14 +536,10 @@ private void addTreeNode(TreeNode node) { } node.getChildren().forEach(t -> addTreeTransition(t)); - } else { - System.out.println("NO CHILDREN"); } } private void addTreeTransition(TreeTransition trans) { - - System.out.println("HI"); List parents = trans.getParents(); TreeTransitionView transView = new TreeTransitionView(trans); From 60f1a73f063a7a3c625e6289671d06b0f8b841ef Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Mon, 29 Jul 2024 22:51:24 -0400 Subject: [PATCH 219/258] Fixed merge conflicts --- .../rpi/legup/puzzle/binary/BinaryCell.java | 35 +++++ .../puzzle/binary/elements/BlankTile.java | 1 - .../puzzle/binary/elements/NumberTile.java | 13 ++ .../rules/CompleteRowColumnDirectRule.java | 8 +- ...plicateRowsOrColumnsContradictionRule.java | 55 -------- .../binary/rules/OneOrZeroCaseRule.java | 90 ------------- .../binary/rules/OneTileGapDirectRule.java | 64 --------- .../binary/rules/SurroundPairDirectRule.java | 48 ------- .../rules/ThreeAdjacentContradictionRule.java | 127 ------------------ .../UnbalancedRowColumnContradictionRule.java | 3 +- ...nbalancedRowOrColumnContradictionRule.java | 68 ---------- .../puzzle/minesweeper/elements/BombTile.java | 4 +- .../minesweeper/elements/UnsetTile.java | 4 +- .../puzzle/starbattle/elements/BlackTile.java | 4 +- .../puzzle/starbattle/elements/StarTile.java | 4 +- .../starbattle/elements/UnknownTile.java | 4 +- ...oCellForNumberColumnContradictionRule.java | 2 +- ...oCellForNumberRegionContradictionRule.java | 2 +- .../NoCellForNumberRowContradictionRule.java | 2 +- .../PossibleCellsForNumberColumnCaseRule.java | 2 +- .../PossibleCellsForNumberRegionCaseRule.java | 2 +- .../PossibleCellsForNumberRowCaseRule.java | 2 +- .../rules/CompleteRowColumnDirectRule.png | Bin 2835 -> 0 bytes .../DuplicateRowOrColumnContradictionRule.png | Bin 3455 -> 0 bytes .../images/binary/rules/OneOrZeroCaseRule.png | Bin 5578 -> 0 bytes .../binary/rules/OneTileGapDirectRule.png | Bin 2751 -> 0 bytes .../binary/rules/SurroundPairDirectRule.png | Bin 2982 -> 0 bytes .../rules/ThreeAdjacentContradictionRule.png | Bin 2508 -> 0 bytes .../UnbalancedRowColumnContradictionRule.png | Bin 2793 -> 1783 bytes .../images/sudoku/elements/NumberTile.png | Bin 10067 -> 0 bytes .../{ => rules}/NoCellForNumberColumn.png | Bin .../{ => rules}/NoCellForNumberRegion.png | Bin .../sudoku/{ => rules}/NoCellForNumberRow.png | Bin .../possible_cells_number_column.png | Bin .../possible_cells_number_region.png | Bin .../{ => rules}/possible_cells_number_row.png | Bin 36 files changed, 68 insertions(+), 476 deletions(-) delete mode 100644 src/main/java/edu/rpi/legup/puzzle/binary/elements/BlankTile.java delete mode 100644 src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsOrColumnsContradictionRule.java delete mode 100644 src/main/java/edu/rpi/legup/puzzle/binary/rules/OneOrZeroCaseRule.java delete mode 100644 src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java delete mode 100644 src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java delete mode 100644 src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java delete mode 100644 src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowOrColumnContradictionRule.java delete mode 100644 src/main/resources/edu/rpi/legup/images/binary/rules/CompleteRowColumnDirectRule.png delete mode 100644 src/main/resources/edu/rpi/legup/images/binary/rules/DuplicateRowOrColumnContradictionRule.png delete mode 100644 src/main/resources/edu/rpi/legup/images/binary/rules/OneOrZeroCaseRule.png delete mode 100644 src/main/resources/edu/rpi/legup/images/binary/rules/OneTileGapDirectRule.png delete mode 100644 src/main/resources/edu/rpi/legup/images/binary/rules/SurroundPairDirectRule.png delete mode 100644 src/main/resources/edu/rpi/legup/images/binary/rules/ThreeAdjacentContradictionRule.png delete mode 100644 src/main/resources/edu/rpi/legup/images/sudoku/elements/NumberTile.png rename src/main/resources/edu/rpi/legup/images/sudoku/{ => rules}/NoCellForNumberColumn.png (100%) rename src/main/resources/edu/rpi/legup/images/sudoku/{ => rules}/NoCellForNumberRegion.png (100%) rename src/main/resources/edu/rpi/legup/images/sudoku/{ => rules}/NoCellForNumberRow.png (100%) rename src/main/resources/edu/rpi/legup/images/sudoku/{ => rules}/possible_cells_number_column.png (100%) rename src/main/resources/edu/rpi/legup/images/sudoku/{ => rules}/possible_cells_number_region.png (100%) rename src/main/resources/edu/rpi/legup/images/sudoku/{ => rules}/possible_cells_number_row.png (100%) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java index 9007215ad..29e8640b1 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java @@ -1,7 +1,9 @@ package edu.rpi.legup.puzzle.binary; +import edu.rpi.legup.model.elements.Element; import edu.rpi.legup.model.gameboard.GridCell; import java.awt.Point; +import java.awt.event.MouseEvent; public class BinaryCell extends GridCell { public BinaryCell(int valueInt, Point location) { @@ -32,4 +34,37 @@ public BinaryCell copy() { copy.setGiven(isGiven); return copy; } + + /** + * Sets the type of this BinaryCell + * + * @param e element to set the type of this binary cell to + */ + @Override + public void setType(Element e, MouseEvent m) { + if (e.getElementName().equals("Number Tile")) { + if (m.getButton() == MouseEvent.BUTTON1) { + if (this.data == 2) { + this.data = 0; + } + else { + this.data = this.data + 1; + } + } + else { + if (m.getButton() == MouseEvent.BUTTON3) { + if (this.data > 0) { + this.data = this.data - 1; + } + else { + this.data = 2; + } + } + } + } + else { // unknown tile + this.data = 2; + } + } + } diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/elements/BlankTile.java b/src/main/java/edu/rpi/legup/puzzle/binary/elements/BlankTile.java deleted file mode 100644 index 8b1378917..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/binary/elements/BlankTile.java +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/elements/NumberTile.java b/src/main/java/edu/rpi/legup/puzzle/binary/elements/NumberTile.java index 8b1378917..e996e246b 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/elements/NumberTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/elements/NumberTile.java @@ -1 +1,14 @@ +package edu.rpi.legup.puzzle.binary.elements; + +import edu.rpi.legup.model.elements.PlaceableElement; + +public class NumberTile extends PlaceableElement { + public NumberTile() { + super( + "BINA-ELEM-0001", + "Number Tile", + "A number tile", + "edu/rpi/legup/images/binary/tiles/NumberTile.png"); + } +} \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java index e38c6b78d..22fda93f1 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java @@ -14,7 +14,7 @@ public class CompleteRowColumnDirectRule extends DirectRule { public CompleteRowColumnDirectRule() { super( "BINA-BASC-0003", - "Complete Row Column", + "Complete Row/Column", "If a row/column of length n contains n/2 of a single value, the remaining cells must contain the other value", "edu/rpi/legup/images/binary/rules/CompleteRowColumnDirectRule.png"); } @@ -31,15 +31,11 @@ public CompleteRowColumnDirectRule() { @Override public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { BinaryBoard origBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); - ContradictionRule contraRule = new UnbalancedRowOrColumnContradictionRule(); + ContradictionRule contraRule = new UnbalancedRowColumnContradictionRule(); BinaryCell binaryCell = (BinaryCell) puzzleElement; BinaryBoard modified = origBoard.copy(); - BinaryCell c = (BinaryCell) modified.getPuzzleElement(puzzleElement); - // System.out.println("ORIG" + binaryCell.getData()); - // System.out.println("AFTER" + Math.abs(binaryCell.getData() - 1)); modified.getPuzzleElement(puzzleElement).setData(binaryCell.getData()); - System.out.println(contraRule.checkContradictionAt(modified, puzzleElement)); if (contraRule.checkContradictionAt(modified, puzzleElement) != null) { return null; diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsOrColumnsContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsOrColumnsContradictionRule.java deleted file mode 100644 index 8b0d88ae4..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsOrColumnsContradictionRule.java +++ /dev/null @@ -1,55 +0,0 @@ -package edu.rpi.legup.puzzle.binary.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.binary.BinaryBoard; -import edu.rpi.legup.puzzle.binary.BinaryCell; -import edu.rpi.legup.puzzle.binary.BinaryType; -import java.util.ArrayList; - -public class DuplicateRowsOrColumnsContradictionRule extends ContradictionRule { - private final String NO_CONTRADICTION_MESSAGE = - "Does not contain a contradiction at this index"; - private final String INVALID_USE_MESSAGE = "Row or column must have a value in each cell"; - - public DuplicateRowsOrColumnsContradictionRule() { - super( - "BINA-CONT-0003", - "Duplicate Rows Or Columns", - "There must not be two rows or two columns that are duplicates", - "edu/rpi/legup/images/binary/rules/DuplicateRowOrColumnContradictionRule.png"); - } - - @Override - public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { - BinaryBoard binaryBoard = (BinaryBoard) board; - BinaryCell cell = (BinaryCell) binaryBoard.getPuzzleElement(puzzleElement); - - ArrayList row = binaryBoard.getRowTypes(cell.getLocation().y); - - int size = row.size(); - - for (int i = 0; i < size; i++) { - if (i > cell.getLocation().y) { - ArrayList currRow = binaryBoard.getRowTypes(i); - if (currRow.equals(row)) { - return null; - } - } - } - - ArrayList col = binaryBoard.getColTypes(cell.getLocation().x); - - for (int i = 0; i < size; i++) { - if (i > cell.getLocation().x) { - ArrayList currCol = binaryBoard.getColTypes(i); - if (currCol.equals(col)) { - return null; - } - } - } - - return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE; - } -} diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneOrZeroCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneOrZeroCaseRule.java deleted file mode 100644 index 70549cd72..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneOrZeroCaseRule.java +++ /dev/null @@ -1,90 +0,0 @@ -package edu.rpi.legup.puzzle.binary.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.binary.BinaryBoard; -import edu.rpi.legup.puzzle.binary.BinaryCell; -import edu.rpi.legup.puzzle.binary.BinaryType; -import java.util.ArrayList; -import java.util.List; - -public class OneOrZeroCaseRule extends CaseRule { - - public OneOrZeroCaseRule() { - super( - "BINA-CASE-0001", - "One or Zero", - "Each blank cell is either a one or a zero.", - "edu/rpi/legup/images/binary/rules/OneOrZeroCaseRule.png"); - } - - @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."; - } - - BinaryCell mod1 = (BinaryCell) case1.getBoard().getModifiedData().iterator().next(); - BinaryCell mod2 = (BinaryCell) 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.getType() == BinaryType.ZERO && mod2.getType() == BinaryType.ONE) - || (mod2.getType() == BinaryType.ZERO && mod1.getType() == BinaryType.ONE))) { - return super.getInvalidUseOfRuleMessage() - + ": This case rule must an empty white and black cell."; - } - - return null; - } - - @Override - public CaseBoard getCaseBoard(Board board) { - BinaryBoard binaryBoard = (BinaryBoard) board.copy(); - CaseBoard caseBoard = new CaseBoard(binaryBoard, this); - binaryBoard.setModifiable(false); - for (PuzzleElement element : binaryBoard.getPuzzleElements()) { - if (((BinaryCell) element).getType() == BinaryType.UNKNOWN) { - caseBoard.addPickableElement(element); - } - } - return caseBoard; - } - - @Override - public ArrayList getCases(Board board, PuzzleElement puzzleElement) { - ArrayList cases = new ArrayList<>(); - Board case1 = board.copy(); - PuzzleElement data1 = case1.getPuzzleElement(puzzleElement); - data1.setData(BinaryType.ZERO.toValue()); - case1.addModifiedData(data1); - cases.add(case1); - - Board case2 = board.copy(); - PuzzleElement data2 = case2.getPuzzleElement(puzzleElement); - data2.setData(BinaryType.ONE.toValue()); - case2.addModifiedData(data2); - cases.add(case2); - - return cases; - } - - @Override - public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - return null; - } -} diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java deleted file mode 100644 index 2e1e96fa5..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java +++ /dev/null @@ -1,64 +0,0 @@ -package edu.rpi.legup.puzzle.binary.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.model.rules.DirectRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -import edu.rpi.legup.puzzle.binary.BinaryBoard; -import edu.rpi.legup.puzzle.binary.BinaryCell; - -public class OneTileGapDirectRule extends DirectRule { - private final String INVALID_USE_MESSAGE = "Number at cell is incorrect"; - - public OneTileGapDirectRule() { - super( - "BINA-BASC-0002", - "One Tile Gap", - "If an empty tile is in between the same value, fill the gap with the other value.", - "edu/rpi/legup/images/binary/rules/OneTileGapDirectRule.png"); - } - - boolean checkLeftRight(BinaryCell c, BinaryBoard board) { - int x = c.getLocation().x; - int y = c.getLocation().y; - return board.getCell(x - 1, y).getType() != c.getType() - || board.getCell(x + 1, y).getType() != c.getType(); - } - - boolean checkUpDown(BinaryCell c, BinaryBoard board) { - int x = c.getLocation().x; - int y = c.getLocation().y; - return board.getCell(x, y - 1).getType() != c.getType() - || board.getCell(x, y + 1).getType() != c.getType(); - } - - @Override - public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - BinaryBoard origBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); - ContradictionRule contraRule = new ThreeAdjacentContradictionRule(); - BinaryCell binaryCell = (BinaryCell) puzzleElement; - BinaryBoard modified = origBoard.copy(); - - // System.out.println("ORIG" + binaryCell.getData()); - // System.out.println("AFTER" + Math.abs(binaryCell.getData() - 1)); - modified.getPuzzleElement(puzzleElement).setData(Math.abs(binaryCell.getData() - 1)); - - PuzzleElement newP = binaryCell; - - System.out.println(contraRule.checkContradictionAt(modified, newP)); - - if (contraRule.checkContradictionAt(modified, newP) == null) { - return null; - } - modified.getPuzzleElement(puzzleElement).setData(Math.abs(binaryCell.getData() - 1)); - - return "Grouping of Three Ones or Zeros not found"; - } - - @Override - public Board getDefaultBoard(TreeNode node) { - return null; - } -} diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java deleted file mode 100644 index dc2f07c8b..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java +++ /dev/null @@ -1,48 +0,0 @@ -package edu.rpi.legup.puzzle.binary.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.model.rules.DirectRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -import edu.rpi.legup.puzzle.binary.BinaryBoard; -import edu.rpi.legup.puzzle.binary.BinaryCell; - -public class SurroundPairDirectRule extends DirectRule { - - public SurroundPairDirectRule() { - super( - "BINA-BASC-0001", - "Surround Pair", - "If two adjacent tiles have the same value, surround the tiles with the other value.", - "edu/rpi/legup/images/binary/rules/SurroundPairDirectRule.png"); - } - - public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - BinaryBoard origBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); - ContradictionRule contraRule = new ThreeAdjacentContradictionRule(); - BinaryCell binaryCell = (BinaryCell) puzzleElement; - BinaryBoard modified = origBoard.copy(); - - // System.out.println("ORIG" + binaryCell.getData()); - // System.out.println("AFTER" + Math.abs(binaryCell.getData() - 1)); - modified.getPuzzleElement(puzzleElement).setData(Math.abs(binaryCell.getData() - 1)); - - PuzzleElement newP = binaryCell; - - System.out.println(contraRule.checkContradictionAt(modified, newP)); - - if (contraRule.checkContradictionAt(modified, newP) == null) { - return null; - } - modified.getPuzzleElement(puzzleElement).setData(Math.abs(binaryCell.getData() - 1)); - - return "Grouping of Three Ones or Zeros not found"; - } - - @Override - public Board getDefaultBoard(TreeNode node) { - return null; - } -} diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java deleted file mode 100644 index 075642246..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java +++ /dev/null @@ -1,127 +0,0 @@ -package edu.rpi.legup.puzzle.binary.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.binary.BinaryBoard; -import edu.rpi.legup.puzzle.binary.BinaryCell; -import edu.rpi.legup.puzzle.binary.BinaryType; - -public class ThreeAdjacentContradictionRule 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 zero or one"; - - public ThreeAdjacentContradictionRule() { - super( - "BINA-CONT-0001", - "Three Adjacent", - "There must not be three adjacent zeros or three adjacent ones in a row or column", - "edu/rpi/legup/images/binary/rules/ThreeAdjacentContradictionRule.png"); - } - - @Override - public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { - BinaryBoard binaryBoard = (BinaryBoard) board; - int height = binaryBoard.getHeight(); - int width = binaryBoard.getWidth(); - - BinaryCell cell = (BinaryCell) binaryBoard.getPuzzleElement(puzzleElement); - System.out.println("THE CELL IS : " + cell.getType()); - int cellX = cell.getLocation().x; - int cellY = cell.getLocation().y; - BinaryCell oneUp = null; - BinaryCell oneDown = null; - BinaryCell oneForward = null; - BinaryCell oneBackward = null; - BinaryCell twoUp = null; - BinaryCell twoDown = null; - BinaryCell twoForward = null; - BinaryCell twoBackward = null; - if (binaryBoard.getCell(cellX, cellY + 1) != null) { - oneUp = binaryBoard.getCell(cellX, cellY + 1); - } - if (binaryBoard.getCell(cellX, cellY - 1) != null) { - oneDown = binaryBoard.getCell(cellX, cellY - 1); - } - if (binaryBoard.getCell(cellX + 1, cellY) != null) { - oneForward = binaryBoard.getCell(cellX + 1, cellY); - } - if (binaryBoard.getCell(cellX - 1, cellY) != null) { - oneBackward = binaryBoard.getCell(cellX - 1, cellY); - } - if (binaryBoard.getCell(cellX, cellY + 2) != null) { - twoUp = binaryBoard.getCell(cellX, cellY + 2); - } - if (binaryBoard.getCell(cellX, cellY - 2) != null) { - twoDown = binaryBoard.getCell(cellX, cellY - 2); - } - if (binaryBoard.getCell(cellX + 2, cellY) != null) { - twoForward = binaryBoard.getCell(cellX + 2, cellY); - } - if (binaryBoard.getCell(cellX - 2, cellY) != null) { - twoBackward = binaryBoard.getCell(cellX - 2, cellY); - } - - if (cell.getType() == BinaryType.ONE || cell.getType() == BinaryType.ZERO) { - if (twoBackward != null - && oneBackward != null - && twoBackward.getType() != BinaryType.UNKNOWN - && oneBackward.getType() != BinaryType.UNKNOWN) { - if (twoBackward.getType() == cell.getType() - && oneBackward.getType() == cell.getType()) { - System.out.println("1"); - return null; - } - } - if (twoForward != null - && oneForward != null - && twoForward.getType() != BinaryType.UNKNOWN - && oneForward.getType() != BinaryType.UNKNOWN) { - if (twoForward.getType() == cell.getType() - && oneForward.getType() == cell.getType()) { - System.out.println("2"); - return null; - } - } - if (twoDown != null - && oneDown != null - && twoDown.getType() != BinaryType.UNKNOWN - && oneDown.getType() != BinaryType.UNKNOWN) { - if (twoDown.getType() == cell.getType() && oneDown.getType() == cell.getType()) { - System.out.println("3"); - return null; - } - } - if (twoUp != null - && oneUp != null - && twoUp.getType() != BinaryType.UNKNOWN - && oneUp.getType() != BinaryType.UNKNOWN) { - if (twoUp.getType() == cell.getType() && oneUp.getType() == cell.getType()) { - System.out.println("4"); - return null; - } - } - if (oneBackward != null - && oneForward != null - && oneBackward.getType() != BinaryType.UNKNOWN - && oneForward.getType() != BinaryType.UNKNOWN) { - if (oneBackward.getType() == cell.getType() - && oneForward.getType() == cell.getType()) { - System.out.println("5"); - return null; - } - } - if (oneUp != null - && oneDown != null - && oneUp.getType() != BinaryType.UNKNOWN - && oneDown.getType() != BinaryType.UNKNOWN) { - if (oneUp.getType() == cell.getType() && oneDown.getType() == cell.getType()) { - System.out.println("6"); - return null; - } - } - } - return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE; - } -} diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowColumnContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowColumnContradictionRule.java index 388528c8b..7c76f8e9f 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowColumnContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowColumnContradictionRule.java @@ -47,7 +47,8 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { return null; } - Set col = binaryBoard.getColCells(cell.getLocation().x); + + Set col = binaryBoard.getCol(cell.getLocation().x); size = col.size(); int colNumZeros = 0; diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowOrColumnContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowOrColumnContradictionRule.java deleted file mode 100644 index 5089b3b5f..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowOrColumnContradictionRule.java +++ /dev/null @@ -1,68 +0,0 @@ -package edu.rpi.legup.puzzle.binary.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.binary.BinaryBoard; -import edu.rpi.legup.puzzle.binary.BinaryCell; -import edu.rpi.legup.puzzle.binary.BinaryType; -import java.util.Set; - -public class UnbalancedRowOrColumnContradictionRule extends ContradictionRule { - - private final String NO_CONTRADICTION_MESSAGE = - "Does not contain a contradiction at this index"; - private final String INVALID_USE_MESSAGE = "Row or column must have a value in each cell"; - - public UnbalancedRowOrColumnContradictionRule() { - super( - "BINA-CONT-0002", - "Unbalanced Row Or Column", - "Each row or column must contain an equal number of zeros and ones", - "edu/rpi/legup/images/binary/rules/UnbalancedRowColumnContradictionRule.png"); - } - - @Override - public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { - BinaryBoard binaryBoard = (BinaryBoard) board; - - BinaryCell cell = (BinaryCell) binaryBoard.getPuzzleElement(puzzleElement); - Set row = binaryBoard.getRowCells(cell.getLocation().y); - - int size = row.size(); - int rowNumZeros = 0; - int rowNumOnes = 0; - - for (BinaryCell item : row) { - if (item.getType() == BinaryType.ZERO) { - rowNumZeros++; - } else if (item.getType() == BinaryType.ONE) { - rowNumOnes++; - } - } - - if (rowNumZeros == size / 2 && rowNumOnes == size / 2) { - return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE; - } - - Set col = binaryBoard.getCol(cell.getLocation().x); - - size = col.size(); - int colNumZeros = 0; - int colNumOnes = 0; - - for (BinaryCell item : col) { - if (item.getType() == BinaryType.ZERO) { - colNumZeros++; - } else if (item.getType() == BinaryType.ONE) { - colNumOnes++; - } - } - - if (colNumZeros == size / 2 && colNumOnes == size / 2) { - return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE; - } - - return null; - } -} 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..cd5577eeb 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,8 @@ package edu.rpi.legup.puzzle.minesweeper.elements; -import edu.rpi.legup.model.elements.NonPlaceableElement; +import edu.rpi.legup.model.elements.PlaceableElement; -public class BombTile extends NonPlaceableElement { +public class BombTile extends PlaceableElement { public BombTile() { super( "MINE-UNPL-0001", 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..6cfc34c8d 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 @@ -1,8 +1,8 @@ package edu.rpi.legup.puzzle.minesweeper.elements; -import edu.rpi.legup.model.elements.NonPlaceableElement; +import edu.rpi.legup.model.elements.PlaceableElement; -public class UnsetTile extends NonPlaceableElement { +public class UnsetTile extends PlaceableElement { public UnsetTile() { super( 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 99f42886e..c4bbf7297 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 @@ -1,8 +1,8 @@ package edu.rpi.legup.puzzle.starbattle.elements; -import edu.rpi.legup.model.elements.NonPlaceableElement; +import edu.rpi.legup.model.elements.PlaceableElement; -public class BlackTile extends NonPlaceableElement { +public class BlackTile extends PlaceableElement { public BlackTile() { super( "STBL-PLAC-0002", 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 13ada3f4d..793d4dbeb 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 @@ -1,8 +1,8 @@ package edu.rpi.legup.puzzle.starbattle.elements; -import edu.rpi.legup.model.elements.NonPlaceableElement; +import edu.rpi.legup.model.elements.PlaceableElement; -public class StarTile extends NonPlaceableElement { +public class StarTile extends PlaceableElement { public StarTile() { super( "STBL-PLAC-0001", 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 425fb5d5e..30921de8d 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 @@ -1,8 +1,8 @@ package edu.rpi.legup.puzzle.starbattle.elements; -import edu.rpi.legup.model.elements.NonPlaceableElement; +import edu.rpi.legup.model.elements.PlaceableElement; -public class UnknownTile extends NonPlaceableElement { +public class UnknownTile extends PlaceableElement { public UnknownTile() { super( "STBL-UNPL-0001", diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberColumnContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberColumnContradictionRule.java index 86d2c8dac..c8d627634 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberColumnContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberColumnContradictionRule.java @@ -15,7 +15,7 @@ public NoCellForNumberColumnContradictionRule() { "SUDO-CONT-0003", "No Cell for Number (Column)", "Process of elimination yields no valid numbers for an empty cell in a column.", - "edu/rpi/legup/images/sudoku/NoCellForNumberColumn.png"); + "edu/rpi/legup/images/sudoku/rules/NoCellForNumberColumn.png"); } /** diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberRegionContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberRegionContradictionRule.java index 714395cab..f5106b858 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberRegionContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberRegionContradictionRule.java @@ -15,7 +15,7 @@ public NoCellForNumberRegionContradictionRule() { "SUDO-CONT-0001", "No Cell for Number (Region)", "Process of elimination yields no valid numbers for an empty cell in a region.", - "edu/rpi/legup/images/sudoku/NoCellForNumberRegion.png"); + "edu/rpi/legup/images/sudoku/rules/NoCellForNumberRegion.png"); } /** diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberRowContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberRowContradictionRule.java index e768405fd..e3f9f764a 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberRowContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberRowContradictionRule.java @@ -15,7 +15,7 @@ public NoCellForNumberRowContradictionRule() { "SUDO-CONT-0002", "No Cell for Number (Row)", "Process of elimination yields no valid numbers for an empty cell in a row.", - "edu/rpi/legup/images/sudoku/NoCellForNumberRow.png"); + "edu/rpi/legup/images/sudoku/rules/NoCellForNumberRow.png"); } /** diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberColumnCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberColumnCaseRule.java index 9c4045fbb..bab0bc79b 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberColumnCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberColumnCaseRule.java @@ -25,7 +25,7 @@ public PossibleCellsForNumberColumnCaseRule() { "SUDO-CASE-0004", "Possible Cells for Number - Column", "An empty cell has a limited set of possible numbers that can fill it.", - "edu/rpi/legup/images/sudoku/possible_cells_number_column.png"); + "edu/rpi/legup/images/sudoku/rules/possible_cells_number_column.png"); } /** diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberRegionCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberRegionCaseRule.java index 43f27e888..47e408369 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberRegionCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberRegionCaseRule.java @@ -22,7 +22,7 @@ public PossibleCellsForNumberRegionCaseRule() { "SUDO-CASE-0002", "Possible Cells for Number - Region", "An empty cell has a limited set of possible numbers that can fill it.", - "edu/rpi/legup/images/sudoku/possible_cells_number_region.png"); + "edu/rpi/legup/images/sudoku/rules/possible_cells_number_region.png"); } /** diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberRowCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberRowCaseRule.java index 5308b84fa..868541377 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberRowCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberRowCaseRule.java @@ -25,7 +25,7 @@ public PossibleCellsForNumberRowCaseRule() { "SUDO-CASE-0003", "Possible Cells for Number - Row", "An empty cell has a limited set of possible numbers that can fill it.", - "edu/rpi/legup/images/sudoku/possible_cells_number_row.png"); + "edu/rpi/legup/images/sudoku/rules/possible_cells_number_row.png"); } /** diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/CompleteRowColumnDirectRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/CompleteRowColumnDirectRule.png deleted file mode 100644 index a74654d4301f75defc639727604f3d59f05612a3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2835 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 W-$D%jr3*N)f}HK$?8r8Oq<;bxYC}%| diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/DuplicateRowOrColumnContradictionRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/DuplicateRowOrColumnContradictionRule.png deleted file mode 100644 index 214aa53483ccc0f6749bffda004ccfc2f70ded29..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3455 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 diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/OneOrZeroCaseRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/OneOrZeroCaseRule.png deleted file mode 100644 index 73072f2ce5ea9d189fe55058aa6a4fa09ecc3979..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5578 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 diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/OneTileGapDirectRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/OneTileGapDirectRule.png deleted file mode 100644 index b68f67e441d3519f17daffd48da37f35e9b3bcfb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2751 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 diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/SurroundPairDirectRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/SurroundPairDirectRule.png deleted file mode 100644 index 67a4e47f363222af68afe45acacd0783f0f35319..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2982 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 diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/ThreeAdjacentContradictionRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/ThreeAdjacentContradictionRule.png deleted file mode 100644 index 862408b63a9c6d72d815b79064ea587657bc5e5e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2508 zcma)83p|@y7Ee`YLd#NAwMww9R6QD{q}w7D)x;~}Q4+LDWE9aRD2<}VdY5`@Cdjr$ zsd(1An4yAr^?auDb%+7wl`+eu$bI-ZId(Ziw|NW9M_SQ1e zhonIukPPY~5(`K+@b-Ye0={nIfiOTwQqH5C!N3y<_DuxFDj`;GAx^=5Ave9r1Q3xF z97NEg_>c(%66KrVkmcPSW`L32j*%sq;2q*0OoBN32N6Kdp#%u*Gz4*-3^6=uXaqTF zbjHvWXb_AY#0u$rWbU932qbkBg+w@q(*=_V@=TKwOIYe$UWan6V+SG&kZ({(I`Rby zS%`dL_q|fY>b!I3C71W4_u`ar}h@v4pK0QUV^9La|f%4u<^=c~2Ow|#Iq?KfBMVYT^ zjWv5!y=n-0S%27P_PXgKePXWhh#A2UD&F#3mz$+>`l2l_da}RnP)}bGyfofo%ViJTUOuytPATheT2gm8x^1TBlve|e#U@S_ zWJUXthgY>ErAGbW?AuC!E||;w)So{>NKEWi=auSv-#B|+QV}f8u)u)!0H={tw7A0n zNlWg*K%g<5(+GdAYeoGuU17N`PNL|2yxen~jbN{hyZ9b23>T^-WM zbURm&+-$2T4=);SjlrzWyK`t+OC3hW&#zMCC5zWr7y~NCXneJ7mDUpmsCjdR5!i@d9j4j3 zs_f$7Ba!@hwWEOY8!ooIToc+ms#$dF?j;lTbm$CchNpH#H^ISLSt^-gpBBw@ua z<(X54*XF`qvJmfDDx2yX;>~I^0}P7mZU(;npx3;H63Q-kD9X#G<(;8ZMALFUsW-?- ze_BaXj$o!;*X0JFb`6WM=PwPY20e|KsGj@sB^dV zzrjiZvFrB`CxM8N?|Q%)f(v=Xnw-wz>d|9m1&oS`YHCdV+G)Y}xbJ?76RYs3HKT05 zI#k1^nbVz1x^a+EoRHVyex&^ujAaV!iC-Y*K0xzDy4N%W1#6FmzaIMnuvYWrde=%7 zy_DyPwOEZfZknHFaO3#FbV%uIRNL@;CJV3hKCE>%FDVszF=~Hq45MO%zO*T9r@`6Y zPqm;YjEUJ-kP&H&3TOWS+8iJiwb%=q&=cK#+s$A$da!wyU*7z}PEU%x?)~TYUtHj0 zs%BAxM-c91aBXwMj(0X}-VUTTIdRFQ`&_aF!o9}&2|K-LJg<5sQnu)ge6|v0s83iW zm|+F!SYE1xU7%Brqn-9@M1s-D4b<3LvZY(Rlt-v%ipVRi=b?vw-pJfJqk-OvrOhr; ze3b#*D(19U`3;?VYLDqc%s!UFAlU-r1vU|wr`s6(Q8u#lbUisrjXw>(aL17aa9#8{ z&I>-CEXbNZGSm#!R8=(yHC=e$t-(4tGn@FzXt1K018@2lrzPiOj2r$pAO_F=Cgc1H z8XEqXiu&W*5f(v0M)-0!?!q$d@0yce5^OaTv-^OQbe6-?DN_%tck7{__jJYlYTaK*ZfEMipV;Cys58|Gl%#h^@%$aE-m7yH4NQ+JPAkQ6 zvE_h|Z3frqO{nhv>=J+Qu4LB#wR_vOTb@;%;>C3%%NasneS%yv{$2DsHP1u*C_I6p zpA7!G#|DTd^+qC$WeR^_Wal)2`+-Ll@{~PWVHZ+iW&QUFGW8Dk_o2%u$Y&xe4k#?_yKc7UweQ3_)RWjD(}SUUa{2X#QFp@fT z*x%8;JS?^rOR;D0HN28?fgM&TYH#lpt1%JT$ILSA8JA+CReX5#>*=I>Ps-W)Q23}l z#x-!l*7S4~L-dx2?PrF?K2SWr{$VJ0rYGNLsF|Dmc}DgvAO6>!l9bY+4#98YmCO^y z@AKE=L|!eGt%s!pn5wb~6~ujo!$kRwZ90u#54)hBXTyF~NFG8>iQGr*F@=xI%bT{$ zc!v{?#z7W7!dr>j>9bfML=UnR&{`Zv2dz-S#KV7H#lM&3{6O!%pf>Hhf0JpQ9jACH ztY`3-J%6)KkFgHU70AVgFS{dU3<%{mpGX+cv+n;uGC!IZ*`n}x&#E=>rv*Y;*&{2@ HUy1z(|GtR) diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/UnbalancedRowColumnContradictionRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/UnbalancedRowColumnContradictionRule.png index 029bd12ac8782f97428d092ee56187d0aa7d77cf..bd66c16a7fdb3b876bf8e39b54c9a84d2928a3e9 100644 GIT binary patch literal 1783 zcmeAS@N?(olHy`uVBq!ia0vp^sUXb31|&mjbk74R#^NA%Cx&(BWL^R}Ea{HEjtmSN z`?>!lvI6;>1s;*b3=FdEAk5hR^dnF^TaTxUV@O5Z+qtnBA?_l_`#aUNvW^_-pP<1p zal!872SaxB0&~Jselbu9a!kszQbh58x zsH{|SIl4hf`h*noN9E3&&+O0TWbclAe?~4Eue)&J^5x0K_8AWzG%HS-W@KyYJ9+YC ztJL$ix98tCKE-1t%^!q&MqQt9U44>ff7oK3=k3vJ2n+O zbc))NG12d4a72X1(W6JLp0ee9Xl&+hd!u%JYxebm!lZz0~kUwa{Az2VK> zyLWwidwZ>p%l&aQ%fGiK_*=mTM*ddDMJY8q>i$-#P4#*?MOs!?*6P`@UTO1^GrW9u z61q;3!5^mh`1-z_Vyn^rz**wy^IPoAXZE4GAJbzV8jEydcTJh58@(*}TY`Sl$w{gR zA6@#pv-o+&JsXv`2Od2;+|HkQv`bWLM}yU`-@jMx+js9~+rfj5t5&V*+QP4^tE)9n z^y!a}kH5USs_n8?LrZH>gw8Uv@@e|`SyQje0y_qaoM>TnM3QI zFZG`OqTT-SIkP_%KZ<`nJM(_xw}Tx*84Jo^Djz;}y-nligm4iayJs!z^VsHGbC}2b zV!h#J$NkySVn1#PxXOR(YU+A-XQ#8ce%zAJ&(B|;tnR<2@1lr^NPyAICEvc4y?Xt6 z@zHMa*VYF=ZdL5EJEO(bb8zEKVRgR?zrMZ>wXgp5<>i`3@=X3mPEXf=`R3+ktvwYV zo5XY?7QAOWe7$YOFN4(@0Yb(97cNx1TH@{Hb!Ch3R4>hBdzL!OWz*aFWP>uNFMFTu z98!DYcF?io$EONPESS(Xaee&$ZBiz&&)%@bOD}qLc+H{*%py}v6?m^+Tz<<&_nG+Z zKY~2_%v`RvN4i#ie#V=7V?(1^-klX}yDnY~ytOS?dTq?kAWc~oi^eL3Uun_HYjQhQ z@o(;85;b&?wJdVkE61F*ecLvz!%YqU#Mx{rJ~YglH7g?}#bxQmn&wAf$3$EI+FSbi z+Qol=e_s_kvMO{n)A#im%Vykve|PtEzj-#E?0hl-{*pXf4jyL%hhfqzJuQRq+0VM? zwA2lj7Xn+5g`9J^kF)=Qq-Kzq}zo9h|5B zX})XMu97poyUX9dnjtMyV-WR3_C<4({~E{TGj|?vcoi)7W7>0I;UN;(Qh;6}V9ikv z8fLv!+*;r4J5S;HhEESa|7HZ1FgO2BIo>b-_z}y!t)Y>TE6qA$4sd1L$Snuviq|sL z1v({{m-&LzbU~9)it9o9(n8kz35UWtPMtbc(kE-t(J*~M?%iFX&u=uF-@bbFDlnhR z)Eu~|-27eb`kCNqp35&=J#|Y@U*5OV@Ny8MOeknM_B1<}&7^kDrw@!~KMouurceMD zgA>+hL@X)c-SOnBEV>r&6` YvemvPddB(hz{-lj)78&qol`;+093R}SpWb4 literal 2793 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 diff --git a/src/main/resources/edu/rpi/legup/images/sudoku/elements/NumberTile.png b/src/main/resources/edu/rpi/legup/images/sudoku/elements/NumberTile.png deleted file mode 100644 index 5a8540d02b509f12c7f059648bbadf021efcedda..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10067 zcmeHLc{G&m`ya9|k!(qtrq^0yR%T2F*_AcQ9%Bq9W`>!uhGfYSMY3cIp_Hs8S)yze zQFgLK$`Y?VO7a`(ecw92?>WEop7ZST^wwTUz(raG628=^E0!cpTcd>Ri7Xt6^<~q4zLUSOyHD@f4Z5cU$zhkeuntC`(0FsR_V@+&$Uf~hYaZE9 z-lUWAdQCv`dO}Y;>QTn0Yk1D3{YthXEFi6-^{&ON3vo-`b;E?{Z!caGX!4J^7c63Z zoG1HqrL!Zm4_xXX*nVd93O5g!Yhk5+tL*mTgH+NCoi8FZ^L<_NbmKT!=Pq?XwQBOps1;40m5i7EO7FOOZU^TdS=D6>L4~w^2_ZtYd+da;`>=KrtQ)|v_Z5;`Vq=wdD>xzSe!Nq>NtM?g-I~H(A@xXcI*9xs67zdh0+!eiHn>?Oe=yQe8;aoju3x&wq|LV zoucw}oc8)%FyF=CFyCT=DeWUT+46y-(mDE@W`1x}vV-9@!HEo`LzYppxoIWNmp()% z(QC*&xU%2dd>~@+K19J%-vC=x%9h`6@>*9UMO(_*USB-KV;5_5XyS{0 z;eMqXtp;u7f861M0H&l-G17SZ*Pc=fAqyYdhD2zPCGA80EvePd#0{oZ?EieZ-}9Ky z`8uoAk@8B>xA)w8-sRmqiVm!qT#M%1(@RkZLZ`KMn6g&K{5{nfRcxm1s9-82r=)>@5R*?sq^ zkR)h#qn%%QLb(aNKCtEFArjLO{+ynZ28YO)N3p>*#xs3h{V7;mwvlCX|9i-`(4v$t z9XS*OWun!|iw45Mp7nPwILwI89Lp?vpF^xVEqfZL%jJmF|2dzinPO2?=k zo*r-Q`R=4iB`tY0h;JsSpkh9hwyZMx2#e)PyEF)pOjMW!kI(AZFCXn}p0|!z4p~3^ z#ZvU4SEhR3V%>y`9o%J+j9zetj1goFR%uc-=T?1-e)hfYc~Q}awwa5kCrBj(D7gpTl6JR2`DNo$o{EB zEHJadUeLtE7g2hK{^3JSQqssl=K$B6HLFGPXb14%8^s}E{c z3j)Mt7mi%njABg_zqodaJhkt!KiT10P+?2QtDEE8UBXcx$2V$x-nGX}`1?V4mh zY`@zr2H2_S3aoa z9j1bb9KvqT5*;#O&sNQ}#Lt2|1lPPM2t2LJ4G(HP#5T_1tM=WPLy)!ccqBicfclr$ zQg>M7!tZ8b?r?sUz_8i|6{?54#<~cm1P6u>*K_Cx=NH2ZcvI_m`dB}Q)W1t`2UUx; zg>a9~x(nIx9SnIp%02J7rl`!U8t%L&h<}e*_9f9nJPo{@n%QwIp;rquqT){ENDz-# z#-1IQf(Pp#o--B|WYyBymo;NDeCLCV@HvHZ2kr`R9y8YBdu~S|ntjKzJ(O*j3I)6cy@gSssdca3 z=gwRC9PKRDJFp!`;5P~kyrgvES;uF`r53do@r%}+ zQK2QFS6QqbYBXass~Tb(xb>=Y5_2w(%e_#3apFb%wO!XbPx;7_WKpttU6_2aeA83) zr^-46iHIq+Ddg0tsaqZ9xzdDU_yAl2?sh}{h6Y@O&?Lj56*8ucGf^}VlSz_!Z^m;v zd|JaGFVVR6)@M^^M}i}mP*0#ax;nN$zw(+tMe$X5;)x@-(ldv$YLZM7X>sqLlj2?D z_Fqelw*$=`ZI6Q_QW9#xn`bW;zRQZuE;h~57>xs+FtLMKz^oU7#v~i3B)cR(pR_m` zm6T>dwc|X~Va{b@b&IZ>Z$vy}snvf{NyE2jQR@RyC?%@wMCpmJmzD{#r=#xPk~4p( zzLGYLs609pmT{sed-b(**Y&RI?$C3d=QhqQO=G58y1BcoyAKlik)mRpVnSj=Vu+Nx zDNHF}QeLI3KAgAWx&Oy~tW}K_Z2&W{XTbWwu?NzgsWQ_G(}4ZRLuxxXC0?7Ga(W53IFSK-sZkmDK;vhE*hFCKR9i*OuwxK8MDL!Q$| zd`8Jb|AYqOvWWtu($1XT@%a1%;$33M)Gow6gk2ePnS9yEtCd%l9~C}6I{I8VL--RI z13qgdWShhxI`=v3m<-XCw?Bds8vXIj&_ z*O}M3oOWv|^m4|@(iT{fNMT-~f3IS%66)BahvbQ&J>HO2ht)v7eOEt7bW2>tc4PNq zQ?bs~1=T%1>8sl3*L~-fB|e*c#(hD4X*;muLhtItx;JYb(-WpD zW(oODt0wE7Jsivd%-*ajTpgTN2bS?rDYQ(5)EY6uQa4bSA|r`ZTy~jEh4vPg7PGf_ zCUGZuho8LE9Eu8S*Q(IDt`n`9qFESIEs-nQ7&9H+q#dq<(rz!Dw>XWu86K4q>Yu$fNTa2 zB&;{S@LEQ^N-{3ihx#r>^yJ zF`+TC`!C2r!7>n^8d(QZ^DOGrJK z8FQ7)lT462c)~Kb_X%u0Z#p$>mh!Iz zMxi3_=0BfU5iKpN!i#k(oO52*-lY|N96oSf)lB;INTJ7l;?V5}l($bFZ_I3Hu&41o z=#uMA?0Ta59P9I_?OtKc*{Uat{2z^bvTpN^^45&NpODU(xg8~b^GWvh8P|Otmm!s! zmv`%gPD{$D6K<)iBpHu-Lfb4XYrKP zK!(&fYkZ!(uCH^dS=ZTY;+^b>>5%PbTav2Srq9}gfvFTksq@P=fi~d`TXd2)`Llo1 zmnrT@k)}#~)j^x+YM*=36}LC9jpQCl!b0q3Jg2bUjiWE8?s=IT+2U z%}U?9Iq>!V`dfB4HVmb2cv8#;j zm@i~yxMkgPb>g6#Peh=_H{EHI5BS{X71d80gBS-a)u}7s!JOV?JUhOiWTMvb`y#G- zUiJ&|L+G?-XU>=LDcSb?{q1Lz_g~0Z@DHqkeG%BsyPfToN?`nFr@+Fs`_JAUo)ew(8_}u0ncV(8Xv28LWDegeU2DWA(jhGT zopo38(l>qjM+`Wc$x{ao=%jv!SPE@dAK1As)J}G%0t0gK144#NQDciOm%d^oYK_(3Bh>7 zf?ViycMJsL?d>h^jgY5MogpwKB_#+H4uQkL3=1&LmrTd`fXTGOTM$1mGzm03mFP|< zQpmt9Oq>J7la2*}7<%Ae@sZpO4E}~E(|)qR-~-}=bBDm>p%4-Y@~a1puI0r5`5DlE z^q`qBPV$gb1RBMYiYI7!5yAsaf)~x67R4L<%q{Y{yV>*c> zoHGI9PIlf_Y!Qw*Zmfp|!R4Xx9VXJmuXpb~I&3e}84 zal?YPf&y-NZWlOE`Ny>A5@`$z->sVeS@os_j~{P87J(aaTLlDe7cK^e|1k&+=S6Vb z9*E)hLxp$2k(~*Q75=lN{*n{_!*nUYppI}j3I|5v9UQ<&CnZI&0}Q4Jh9MOYP6#{# zfpft9j!vUE(Yxc)ir5Xg*wK;DeQ%)M&)od2WKt{b`2 zY2WFz?{wOCI_*21_MJ}qPN#jR)4tPb-|4jf)@hgY7WQPc)7czO>SzKsx4xM*x8oTS zPIp~P8UVn(ck5yTq@;;5gzR)Z11X)Mw#L5Aqd4>u1nx~+9&qjS7;LL@$?Ml-=9E`eOn%o{;5(}Es?OtI^YVE zhY(Q9WU%tK3Lx#gpLnx)^C(6554|yIR@+{t*X6V4_1A1Wk(@xw#G%h^q#zG*$taLs zXV;7BM}SK>eziqqZ^Nq!b;|9`=$b*zn%3^fbY?SuaZCP#qg diff --git a/src/main/resources/edu/rpi/legup/images/sudoku/NoCellForNumberColumn.png b/src/main/resources/edu/rpi/legup/images/sudoku/rules/NoCellForNumberColumn.png similarity index 100% rename from src/main/resources/edu/rpi/legup/images/sudoku/NoCellForNumberColumn.png rename to src/main/resources/edu/rpi/legup/images/sudoku/rules/NoCellForNumberColumn.png diff --git a/src/main/resources/edu/rpi/legup/images/sudoku/NoCellForNumberRegion.png b/src/main/resources/edu/rpi/legup/images/sudoku/rules/NoCellForNumberRegion.png similarity index 100% rename from src/main/resources/edu/rpi/legup/images/sudoku/NoCellForNumberRegion.png rename to src/main/resources/edu/rpi/legup/images/sudoku/rules/NoCellForNumberRegion.png diff --git a/src/main/resources/edu/rpi/legup/images/sudoku/NoCellForNumberRow.png b/src/main/resources/edu/rpi/legup/images/sudoku/rules/NoCellForNumberRow.png similarity index 100% rename from src/main/resources/edu/rpi/legup/images/sudoku/NoCellForNumberRow.png rename to src/main/resources/edu/rpi/legup/images/sudoku/rules/NoCellForNumberRow.png diff --git a/src/main/resources/edu/rpi/legup/images/sudoku/possible_cells_number_column.png b/src/main/resources/edu/rpi/legup/images/sudoku/rules/possible_cells_number_column.png similarity index 100% rename from src/main/resources/edu/rpi/legup/images/sudoku/possible_cells_number_column.png rename to src/main/resources/edu/rpi/legup/images/sudoku/rules/possible_cells_number_column.png diff --git a/src/main/resources/edu/rpi/legup/images/sudoku/possible_cells_number_region.png b/src/main/resources/edu/rpi/legup/images/sudoku/rules/possible_cells_number_region.png similarity index 100% rename from src/main/resources/edu/rpi/legup/images/sudoku/possible_cells_number_region.png rename to src/main/resources/edu/rpi/legup/images/sudoku/rules/possible_cells_number_region.png diff --git a/src/main/resources/edu/rpi/legup/images/sudoku/possible_cells_number_row.png b/src/main/resources/edu/rpi/legup/images/sudoku/rules/possible_cells_number_row.png similarity index 100% rename from src/main/resources/edu/rpi/legup/images/sudoku/possible_cells_number_row.png rename to src/main/resources/edu/rpi/legup/images/sudoku/rules/possible_cells_number_row.png From 513f2280ce7e01a257d7fe1a9f799bad78381994 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Mon, 29 Jul 2024 22:55:22 -0400 Subject: [PATCH 220/258] Fixed image bug for complete row column direct rule --- .../binary/rules/CompleteRowColumnDirectRule.png | Bin 0 -> 2174 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/main/resources/edu/rpi/legup/images/binary/rules/CompleteRowColumnDirectRule.png diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/CompleteRowColumnDirectRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/CompleteRowColumnDirectRule.png new file mode 100644 index 0000000000000000000000000000000000000000..27ccec97290109fe20d727d468465a57af330906 GIT binary patch literal 2174 zcmaKudpr{g8^A*B@sD|a!VF!E=R?2zs)#jZ9*Y;N$w*`M9ejp z%*y>3JIq{GL=HBrNM_-+cYQwZ=Y9V<=l$b(p3m=j{&+sW=a28_dEjV|l92>U0ssIR z8*3{kVZHf1fa1cOah8%JEFuw3C`&-?h#E&I#C$F6EC7J|45__e4hr?5P;0jc0046T zdx)&78ms{TKm{8s3+HGLZn3-dH5=uA*f1?)Ptu6dPA-$FIj)ZY1b9Yy)Qqug*T4Zd?jq}Ef+^1Tk9x>^w)FU zpZ2_vhRb{!4Zpt`>9eF3k#t-InE?pj8r8UKoqEe)FucT!P&P3!(KKlbS<}+eVt5#a zak<>DJnlPT3lkC&!rH8;t*$=7{q3sKM~tE3N!RmjZNZ~d=tgMl%j!XHg)Vnb>4Kbxv_LqXG++4M`MX9GCShJxjU7Jf`mrxaI;DhZ`FyKD(uY51xH(bK_O;v!7EGIfl6RT`?us z>OAana&mT3Ap`=UDQw{)nv694{c92;WR}*FAqY;&`b$13D=;XC35SwpCF4QUjM-U| z8W=nV$3xADH3ZZ4_V%U>RAp>LNmlX@WHK7F*0`mL*(lfkKc>H*!{f>tc61hnDl<28G`=edHprD~cqOI-BSBgGeTcG7Yvi&Cdyr(tlGnBwz z7xB31sP0L*V*`Oeuya%qFbp>7LOZ_%Us@c>%{k}e5ajE4rCJZuI#)y-rpGvyMW=@M zE3H=h9Q&f>x1K1D+kZ3LiD#aY7u8QqO;3LtV0&ErUSM!=MScA#LT~E259W1r76@uu zITF@`jQUg*v9oB7V{CtDdK#Q?uxktUe7g%#znRhXfkNo`g4&W~8aqE;z;NA*19r5- ztFkD@I5_8{VPu#ABAl%}?*lG~V_kK19cVz|C2t@D!E-&oWD}28@or1J+oS7ooD~XGh1< zI-fpc!ur;#3+q(~4DI4__3~vY_b#Hl=b*Hfpm9RF>CM!}UFom_;FPhEk!uRjQJKv6 zxWcUV-<81;y)xHVm?sv%D-Vf4TxaP~?`0rSz+pV!%4wTlGJmOTt!!LgQE{=kt;G^B zRce*rG8vYMNT`aBkH5m~8-_rkh~Qw%nCu&(&QmG;Ve5N#b4xKJpgaElmv*D6B)mo@ zCv;A(FZL(@8f`sJJo(y_ryA~s73tZ6GiO7slF}s{mWp&UE78B|U%4H$mIY;D0t34n zWxtRErw!0EL5SoqhU|1pP$8>|zp;R79@M{s91=S%XvEDOM^9C`czV{U-`QMBW6D~h z3F~vQti{BN18B9={fA9cA!ov^(%59e*QxrO*NnT333pYaSH`tXB9^4Nvz>(?m|0ET zt%Pg=`;c097at3Jp?C@H=U1h3B_b}yP;PGd$*_Z(Ab))l)tyntuS%pyk*Eu@5pZks8SBbKqKm_vMwd~;rtJQfn3;mI z1$ta=9Jt5k%bpV94M^wxreP5Kb(Hf4+S2OBAr4?#pThcmtRZg)1w{~~0n7vxhMzs_L1aj`<8*wN{zL7Y|#o8S&OuDcwSA! z4pTSA(GM+h#LjuOI$uR?_e7+r2YtkRs?j&YT z*N9oSSgO+!_-x_bQLwlqCezFWRV!r^HQZz8P$=`taQ$G832!(;u3ycaKY2z{Wn@|h+-h26p%Q`$+nw_AA|#<=Ib&(5d*m8N)yb(DR7{E!ruxvX&Un5 zu$qz=y}15hEl;n7$}~GxVA)@|r$#1ar3p%6x1?(;r}+Yv$jHc*MHP@MotjdF*@c|N zRo*<-H!uJMO?ZJ|A-xIuhr(M4yNICahWonWv;OXF;hMVw-}AJ{)d^1KIX-_n`N#?E z04W+Cr);C=n)qu#0OLFL{quy>pPtTFgF+|Z_??}dri}j8NlTB%Hpk>gRi9xn3j+zA zQnfrd(Ma>3O#IhgsG{hq3Li_7B1gF?P_>pHpL7$RDb!OFIB!2g7y8 Date: Tue, 30 Jul 2024 15:03:13 -0400 Subject: [PATCH 221/258] Finish Regions Within Rows inference rule tests --- .../rules/EmptyAdjacentDirectRule.java | 2 +- .../RegionsWithinRowsDirectRuleTest.java | 85 +++++++++++++++++++ .../FalseStarOverlap | 40 +++++++++ 3 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 src/test/resources/puzzles/starbattle/rules/RegionsWithinRowsDirectRule/FalseStarOverlap diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/EmptyAdjacentDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/EmptyAdjacentDirectRule.java index 17909e233..0cb43ce06 100644 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/EmptyAdjacentDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/EmptyAdjacentDirectRule.java @@ -64,7 +64,7 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem StarBattleCell temp = adjacent[i]; if (temp != null && temp.getType() == StarBattleCellType.UNKNOWN) { - temp.setData(StarBattleCellType.BLACK.value); + //temp.setData(StarBattleCellType.BLACK.value); int X = temp.getLocation().x; int Y = temp.getLocation().y; modified.getCell(X,Y).setData(StarBattleCellType.BLACK.value); diff --git a/src/test/java/puzzles/starbattle/rules/RegionsWithinRowsDirectRuleTest.java b/src/test/java/puzzles/starbattle/rules/RegionsWithinRowsDirectRuleTest.java index b78ad9fb3..3ffaa82fd 100644 --- a/src/test/java/puzzles/starbattle/rules/RegionsWithinRowsDirectRuleTest.java +++ b/src/test/java/puzzles/starbattle/rules/RegionsWithinRowsDirectRuleTest.java @@ -170,4 +170,89 @@ public void RegionsWithinRowsDirectRule_StarOverlap() } } } + + @Test + public void RegionsWithinRowsDirectRule_FalseRegionsWithinRows1() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinRowsDirectRule/OneRegionOneCell", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(2,0); + cell1.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell1); + StarBattleCell cell2 = board.getCell(2,1); + cell2.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell2); + + Assert.assertNotNull(RULE.checkRule(transition)); + + Point location = new Point(2,0); + 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(location)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void RegionsWithinRowsDirectRule_FalseRegionsWithinRows2() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinRowsDirectRule/OneRegionOneCell", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(2,0); + cell1.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell1); + StarBattleCell cell2 = board.getCell(1,0); + cell2.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell2); + + Assert.assertNotNull(RULE.checkRule(transition)); + + Point location = new Point(2,0); + 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(location)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void RegionsWithinRowsDirectRule_FalseStarOverlap() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinRowsDirectRule/FalseStarOverlap", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell = board.getCell(3,1); + cell.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell); + + Assert.assertNotNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); i++) { + for (int k = 0; k < board.getWidth(); k++) { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } diff --git a/src/test/resources/puzzles/starbattle/rules/RegionsWithinRowsDirectRule/FalseStarOverlap b/src/test/resources/puzzles/starbattle/rules/RegionsWithinRowsDirectRule/FalseStarOverlap new file mode 100644 index 000000000..a582d1c46 --- /dev/null +++ b/src/test/resources/puzzles/starbattle/rules/RegionsWithinRowsDirectRule/FalseStarOverlap @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 485791f4596b056a152bb1eb5a544a76c0df033d Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Wed, 31 Jul 2024 16:41:20 -0400 Subject: [PATCH 222/258] Implemented skyscrapers puzzle editor functionality, created no clue view, made slight progress for implementation of solving puzzles with missing clues --- .../puzzle/skyscrapers/SkyscrapersBoard.java | 6 +++--- .../puzzle/skyscrapers/SkyscrapersCell.java | 4 ++-- .../skyscrapers/SkyscrapersClueView.java | 19 ++++++++++++++++--- .../puzzle/skyscrapers/elements/ClueTile.java | 14 -------------- .../skyscrapers/elements/NumberTile.java | 2 +- .../skyscrapers/elements/UnknownTile.java | 2 +- .../skyscrapers_elements_reference_sheet.txt | 5 ++--- src/main/resources/edu/rpi/legup/legup/config | 4 ++-- 8 files changed, 27 insertions(+), 29 deletions(-) delete mode 100644 src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/ClueTile.java diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersBoard.java b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersBoard.java index 4cd09b254..0fc133786 100644 --- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersBoard.java +++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersBoard.java @@ -209,7 +209,7 @@ public void setCell(int x, int y, Element e, MouseEvent m) { SkyscrapersClue clue = this.getClue(x, y); if (e == null) return; if (clue != null) { - if (!e.getElementID().equals("SKYS-UNPL-0003")) { + if (!e.getElementID().equals("SKYS-ELEM-0001")) { return; } @@ -217,10 +217,10 @@ public void setCell(int x, int y, Element e, MouseEvent m) { if (clue.getData() < dimension.height) { clue.setData(clue.getData() + 1); } else { - clue.setData(0); + clue.setData(1); } } else { - if (clue.getData() > 0) { + if (clue.getData() > 1) { clue.setData(clue.getData() - 1); } else { clue.setData(dimension.height); diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersCell.java b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersCell.java index 1cf9a357b..9e7283b20 100644 --- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersCell.java +++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersCell.java @@ -27,10 +27,10 @@ public SkyscrapersType getType() { @Override public void setType(Element e, MouseEvent m) { switch (e.getElementID()) { - case "SKYS-UNPL-0001": + case "SKYS-ELEM-0002": this.data = 0; break; - case "SKYS-UNPL-0002": + case "SKYS-ELEM-0001": switch (m.getButton()) { case MouseEvent.BUTTON1: if (this.data <= 0 || this.data >= this.max) { diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersClueView.java b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersClueView.java index 5a49a1476..0e6345ff1 100644 --- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersClueView.java +++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersClueView.java @@ -25,11 +25,11 @@ public SkyscrapersClue getPuzzleElement() { @Override public void draw(Graphics2D graphics2D) { drawElement(graphics2D); + if (this.isHover()) { + drawHover(graphics2D); + } if (this.isShowCasePicker() && this.isCaseRulePickable()) { drawCase(graphics2D); - if (this.isHover()) { - drawHover(graphics2D); - } } } @@ -54,6 +54,19 @@ public void drawElement(Graphics2D graphics2D) { int xText = location.x + (size.width - metrics.stringWidth(value)) / 2; int yText = location.y + ((size.height - metrics.getHeight()) / 2) + metrics.getAscent(); + + // REPRESENT NO CLUE AS EMPTY STRING INSTEAD OF 0, SOLVING PUZZLES WITH NO CLUE IS CURRENTLY NOT WORKING + // IF YOU ARE IMPLEMENTING NO CLUE FUNCTIONALITY, UNCOMMENT BELOW CODE AND DELETE OTHER IF STATEMENT, + // ADDITIONALLY, GO TO SkyscrapersBoard AND EDIT LINES 220 AND 223 SO YOU CAN CYCLE FOR NO CLUE + // IN THE SKYSCRAPERS PUZZLE EDITOR +// if (value.equals("0")) { +// value = ""; +// } + if (value.equals("0")) { + value = "1"; + clue.setData(1); + } + graphics2D.drawString(value, xText, yText); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/ClueTile.java b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/ClueTile.java deleted file mode 100644 index 102bd5833..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/ClueTile.java +++ /dev/null @@ -1,14 +0,0 @@ -package edu.rpi.legup.puzzle.skyscrapers.elements; - -import edu.rpi.legup.model.elements.PlaceableElement; - -public class ClueTile extends PlaceableElement { - - public ClueTile() { - super( - "SKYS-ELEM-0001", - "Clue Tile", - "Clue Updater", - "edu/rpi/legup/images/skyscrapers/tiles/ClueTile.png"); - } -} diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/NumberTile.java b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/NumberTile.java index 7c7887131..f60e5fe8b 100644 --- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/NumberTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/NumberTile.java @@ -5,7 +5,7 @@ public class NumberTile extends PlaceableElement { public NumberTile() { super( - "SKYS-ELEM-0002", + "SKYS-ELEM-0001", "Number Tile", "A numbered tile", "edu/rpi/legup/images/skyscrapers/tiles/ClueTile.png"); diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/UnknownTile.java b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/UnknownTile.java index 1c9b6f5f3..07f6a1238 100644 --- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/UnknownTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/UnknownTile.java @@ -5,7 +5,7 @@ public class UnknownTile extends PlaceableElement { public UnknownTile() { super( - "SKYS-ELEM-0003", + "SKYS-ELEM-0002", "Unknown", "A blank tile", "edu/rpi/legup/images/skyscrapers/tiles/UnknownTile.png"); diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/skyscrapers_elements_reference_sheet.txt b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/skyscrapers_elements_reference_sheet.txt index 1cc867f37..14e76a29d 100644 --- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/skyscrapers_elements_reference_sheet.txt +++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/skyscrapers_elements_reference_sheet.txt @@ -1,3 +1,2 @@ -SKYS-ELEM-0001: ClueTile -SKYS-ELEM-0002: NumberTile -SKYS-ELEM-0003: UnknownTile \ No newline at end of file +SKYS-ELEM-0001: NumberTile +SKYS-ELEM-0002: UnknownTile \ No newline at end of file diff --git a/src/main/resources/edu/rpi/legup/legup/config b/src/main/resources/edu/rpi/legup/legup/config index 4b69da044..e01767677 100644 --- a/src/main/resources/edu/rpi/legup/legup/config +++ b/src/main/resources/edu/rpi/legup/legup/config @@ -34,7 +34,7 @@ fileCreationDisabled="false"/> + fileCreationDisabled="false"/> + fileCreationDisabled="false"/> Date: Wed, 31 Jul 2024 16:42:41 -0400 Subject: [PATCH 223/258] Implemented sudoku puzzle editor functionality --- .../edu/rpi/legup/puzzle/sudoku/Sudoku.java | 1 + .../rpi/legup/puzzle/sudoku/SudokuCell.java | 40 ++++++++++++++++-- .../puzzle/sudoku/SudokuCellController.java | 2 +- .../legup/puzzle/sudoku/SudokuImporter.java | 11 ----- .../rpi/legup/puzzle/sudoku/SudokuView.java | 9 +++- .../puzzle/sudoku/elements/NumberTile.java | 26 +++--------- .../puzzle/sudoku/elements/UnknownTile.java | 13 ++++++ .../sudoku_elements_reference_sheet.txt | 3 +- .../legup/images/sudoku/tiles/UnknownTile.png | Bin 0 -> 9733 bytes 9 files changed, 68 insertions(+), 37 deletions(-) create mode 100644 src/main/java/edu/rpi/legup/puzzle/sudoku/elements/UnknownTile.java create mode 100644 src/main/resources/edu/rpi/legup/images/sudoku/tiles/UnknownTile.png diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/Sudoku.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/Sudoku.java index d6e8a08e2..c27269536 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/Sudoku.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/Sudoku.java @@ -30,6 +30,7 @@ public BoardView getBoardView() { public void initializeView() { boardView = new SudokuView((SudokuBoard) currentBoard); boardView.setBoard(currentBoard); + addBoardListener(boardView); } /** diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuCell.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuCell.java index 006e6c0a5..4e194ae2c 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuCell.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuCell.java @@ -1,7 +1,9 @@ package edu.rpi.legup.puzzle.sudoku; +import edu.rpi.legup.model.elements.Element; import edu.rpi.legup.model.gameboard.GridCell; import java.awt.*; +import java.awt.event.MouseEvent; import java.util.HashSet; import java.util.Set; @@ -13,10 +15,10 @@ public class SudokuCell extends GridCell { /** * SudokuCell Constructor - creates a new Sudoku cell to hold the puzzleElement * - * @param value value of the sudoku cell - * @param location location of the cell on the board + * @param value value of the sudoku cell + * @param location location of the cell on the board * @param groupIndex index of the group the cell is in on the board - * @param size size of the sudoku cell + * @param size size of the sudoku cell */ public SudokuCell(int value, Point location, int groupIndex, int size) { super(value, location); @@ -59,4 +61,36 @@ public SudokuCell copy() { copy.setGiven(isGiven); return copy; } + + /** + * Sets the type of this NurikabeCell + * + * @param e element to set the type of this nurikabe cell to + */ + @Override + public void setType(Element e, MouseEvent m) { + if (e.getElementName().equals("Number Tile")) { + if (m.getButton() == MouseEvent.BUTTON1) { + if (this.data <= 0 || this.data > 8) { + this.data = 1; + } + else { + this.data = this.data + 1; + } + } + else { + if (m.getButton() == MouseEvent.BUTTON3) { + if (this.data > 1) { + this.data = this.data - 1; + } + else { + this.data = 9; + } + } + } + } + else if (e.getElementName().equals("Unknown Tile")) { + this.data = 0; + } + } } diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuCellController.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuCellController.java index 9b24f13da..bcad1a0ce 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuCellController.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuCellController.java @@ -8,7 +8,7 @@ public class SudokuCellController extends ElementController { @Override public void changeCell(MouseEvent e, PuzzleElement data) { SudokuCell cell = (SudokuCell) data; - System.out.print(111); + if (e.getButton() == MouseEvent.BUTTON1) { if (e.isControlDown()) { this.boardView diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuImporter.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuImporter.java index 837eb7315..5084279c3 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuImporter.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuImporter.java @@ -48,7 +48,6 @@ public void initializeBoard(int rows, int columns) { } puzzle.setCurrentBoard(sudokuBoard); - System.out.println(sudokuBoard); } /** @@ -111,16 +110,6 @@ public void initializeBoard(Node node) throws InvalidFileFormatException { } } } - // - // for(int y = 0; y < size; y++) - // { - // for(int x = 0; x < size; x++) - // { - // SudokuCell cell = sudokuBoard.getCell(x, y); - // System.err.println("(" + x + ", " + y + ") - " + - // cell.getGroupIndex()); - // } - // } puzzle.setCurrentBoard(sudokuBoard); } catch (NumberFormatException e) { diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuView.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuView.java index aa58f9a23..d2a8d95ab 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuView.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuView.java @@ -22,10 +22,15 @@ public SudokuView(SudokuBoard board) { for (int k = 0; k < gridSize.width; k++) { Point location = new Point( - k * elementSize.width + (k / minorSize) * 4 + 5, - i * elementSize.height + (i / minorSize) * 4 + 5); + k * elementSize.width + (k / minorSize) * 4 + 5,// + i * elementSize.height + (i / minorSize) * 4 + 5); +// Point location = +// new Point( +// k * elementSize.width, +// i * elementSize.height); SudokuElementView element = new SudokuElementView(board.getCell(k, i)); element.setIndex(i * gridSize.width + k); + element.setIndex(i * gridSize.width); element.setSize(elementSize); element.setLocation(location); elementViews.add(element); diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/elements/NumberTile.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/elements/NumberTile.java index 681583022..b8f4a596c 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/elements/NumberTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/elements/NumberTile.java @@ -1,26 +1,14 @@ + package edu.rpi.legup.puzzle.sudoku.elements; import edu.rpi.legup.model.elements.PlaceableElement; public class NumberTile extends PlaceableElement { - private int object_num; - public NumberTile() { - super("SUDO-ELEM-0001", "Number Tile", "A numbered tile", "edu/rpi/legup/images/sudoku/tiles/NumberTile.png"); - object_num = 0; - } - - /** - * @return this object's tile number... - */ - public int getTileNumber() { - return object_num; - } - - /** - * @param num Amount to set tile object to. - */ - public void setTileNumber(int num) { - object_num = num; + super( + "SUDO-ELEM-0001", + "Number Tile", + "A number tile", + "edu/rpi/legup/images/sudoku/tiles/NumberTile.png"); } -} +} \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/elements/UnknownTile.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/elements/UnknownTile.java new file mode 100644 index 000000000..162ba46d1 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/elements/UnknownTile.java @@ -0,0 +1,13 @@ +package edu.rpi.legup.puzzle.sudoku.elements; + +import edu.rpi.legup.model.elements.PlaceableElement; + +public class UnknownTile extends PlaceableElement { + public UnknownTile() { + super( + "SUDO-ELEM-0002", + "Unknown Tile", + "A blank tile", + "edu/rpi/legup/images/sudoku/tiles/UnknownTile.png"); + } +} \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/elements/sudoku_elements_reference_sheet.txt b/src/main/java/edu/rpi/legup/puzzle/sudoku/elements/sudoku_elements_reference_sheet.txt index 5f023a984..b8df27eb6 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/elements/sudoku_elements_reference_sheet.txt +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/elements/sudoku_elements_reference_sheet.txt @@ -1 +1,2 @@ -SUDO-ELEM-0001 : NumberTile \ No newline at end of file +SUDO-ELEM-0001 : NumberTile +SUDO-ELEM-0002 : UnknownTile \ No newline at end of file diff --git a/src/main/resources/edu/rpi/legup/images/sudoku/tiles/UnknownTile.png b/src/main/resources/edu/rpi/legup/images/sudoku/tiles/UnknownTile.png new file mode 100644 index 0000000000000000000000000000000000000000..850fbf127f04020fe83c6a4f6db75078967916ea GIT binary patch literal 9733 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 QTOg2`(SBUvUiYy70dQO53jhEB literal 0 HcmV?d00001 From 9f6de7daa141630f063365fdbdd1f2a4df83a06f Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Wed, 31 Jul 2024 16:42:55 -0400 Subject: [PATCH 224/258] Renamed menu buttons in puzzle solver --- src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java b/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java index 624ac102a..47512466d 100644 --- a/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java +++ b/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java @@ -135,14 +135,14 @@ public JMenuBar getMenuBar() { file = new JMenu("File"); newPuzzle = new JMenuItem("Open"); - resetPuzzle = new JMenuItem("Reset Puzzle"); + resetPuzzle = new JMenuItem("Reset"); // genPuzzle = new JMenuItem("Puzzle Generators"); // TODO: implement puzzle // generator saveProofAs = new JMenuItem("Save As"); // create a new file to save saveProofChange = new JMenuItem("Save"); // save to the current file preferences = new JMenuItem("Preferences"); helpTutorial = new JMenuItem("Help"); // jump to web page - exit = new JMenuItem("Exit Solve Puzzle"); + exit = new JMenuItem("Exit"); edit = new JMenu("Edit"); undo = new JMenuItem("Undo"); @@ -967,6 +967,7 @@ private void repaintAll() { public void setPuzzleView(Puzzle puzzle) { this.boardView = puzzle.getBoardView(); + dynamicBoardView = new DynamicView(boardView, DynamicViewType.BOARD); this.topHalfPanel.setRightComponent(dynamicBoardView); this.topHalfPanel.setVisible(true); From abbe5504ce9203ec47ef911326984a3e7f765cff Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Wed, 31 Jul 2024 20:09:43 -0400 Subject: [PATCH 225/258] Added documentation to binary main files --- .../edu/rpi/legup/puzzle/binary/Binary.java | 11 ++ .../rpi/legup/puzzle/binary/BinaryBoard.java | 54 ++++++-- .../rpi/legup/puzzle/binary/BinaryCell.java | 21 ++- .../puzzle/binary/BinaryCellFactory.java | 16 ++- .../legup/puzzle/binary/BinaryController.java | 16 ++- .../puzzle/binary/BinaryElementView.java | 129 +++++++----------- .../legup/puzzle/binary/BinaryExporter.java | 9 +- .../legup/puzzle/binary/BinaryImporter.java | 28 +++- .../rpi/legup/puzzle/binary/BinaryType.java | 19 ++- .../rpi/legup/puzzle/binary/BinaryView.java | 7 + .../UnbalancedRowColumnContradictionRule.java | 2 +- .../puzzle/nurikabe/NurikabeController.java | 10 ++ .../puzzle/nurikabe/NurikabeExporter.java | 7 + 13 files changed, 225 insertions(+), 104 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/Binary.java b/src/main/java/edu/rpi/legup/puzzle/binary/Binary.java index 4daddba2a..d2dd0b181 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/Binary.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/Binary.java @@ -36,6 +36,12 @@ public Board generatePuzzle(int difficulty) { return null; } + /** + * Determines if the current board is a valid state + * + * @param board board to check for validity + * @return true if board is valid, false otherwise + */ @Override public boolean isBoardComplete(Board board) { BinaryBoard binaryBoard = (BinaryBoard) board; @@ -54,6 +60,11 @@ public boolean isBoardComplete(Board board) { return true; } + /** + * Callback for when the board puzzleElement changes + * + * @param board the board that has changed + */ @Override public void onBoardChange(Board board) {} diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java index 35c37b1a1..34819410b 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java @@ -2,7 +2,7 @@ import edu.rpi.legup.model.gameboard.GridBoard; import edu.rpi.legup.model.gameboard.PuzzleElement; -import java.awt.*; + import java.util.ArrayList; import java.util.HashSet; import java.util.Set; @@ -20,6 +20,13 @@ public BinaryBoard(int size) { this.size = size; } + /** + * Gets the cell at the (x,y) position + * + * @param x x-coordinate + * @param y y-coordinate + * @return BinaryCell cell at (x,y) + */ @Override public BinaryCell getCell(int x, int y) { if (y * dimension.width + x >= puzzleElements.size() @@ -32,6 +39,12 @@ public BinaryCell getCell(int x, int y) { return (BinaryCell) super.getCell(x, y); } + /** + * Get all the binary cells in a row + * + * @param rowNum row number + * @return set of all binary cells in specified rowNum + */ public Set getRowCells(int rowNum) { Set row = new HashSet<>(); for (int i = 0; i < size; i++) { @@ -41,6 +54,26 @@ public Set getRowCells(int rowNum) { return row; } + /** + * Get all the binary cells in a column + * + * @param colNum column number + * @return set of all binary cells in specified colNum + */ + public Set getColCells(int colNum) { + Set col = new HashSet<>(); + for (int i = 0; i < size; i++) { + col.add(getCell(colNum, i)); + } + return col; + } + + /** + * Get all the binary types in a row + * + * @param rowNum row number + * @return ArrayList of all binary types in specified rowNum + */ public ArrayList getRowTypes(int rowNum) { ArrayList row = new ArrayList(); for (int i = 0; i < size; i++) { @@ -50,6 +83,12 @@ public ArrayList getRowTypes(int rowNum) { return row; } + /** + * Get all the binary types in a column + * + * @param colNum column number + * @return ArrayList of all binary types in specified colNum + */ public ArrayList getColTypes(int colNum) { ArrayList col = new ArrayList(); for (int i = 0; i < size; i++) { @@ -59,17 +98,12 @@ public ArrayList getColTypes(int colNum) { return col; } - public Set getCol(int colNum) { - Set col = new HashSet<>(); - for (int i = 0; i < size; i++) { - col.add(getCell(colNum, i)); - } - return col; - } - + /** + * Get a copy of the binary board + * @return copy of current BinaryBoard + */ @Override public BinaryBoard copy() { - System.out.println("BinaryBoard copy()"); BinaryBoard copy = new BinaryBoard(dimension.width, dimension.height); for (int x = 0; x < this.dimension.width; x++) { for (int y = 0; y < this.dimension.height; y++) { diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java index 29e8640b1..3d4be02a1 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java @@ -6,10 +6,22 @@ import java.awt.event.MouseEvent; public class BinaryCell extends GridCell { - public BinaryCell(int valueInt, Point location) { - super(valueInt, location); + + /** + * BinaryCell Constructor - creates a BinaryCell from the specified value and location + * + * @param value value of the BinaryCell + * @param location position of the BinaryCell + */ + public BinaryCell(int value, Point location) { + super(value, location); } + /** + * Gets the type of this BinaryCell + * + * @return type of BinaryCell + */ public BinaryType getType() { switch (data) { case 0: @@ -26,6 +38,11 @@ public BinaryType getType() { return null; } + /** + * Performs a deep copy on the BinaryCell + * + * @return a new copy of the BinaryCell that is independent of this one + */ @Override public BinaryCell copy() { BinaryCell copy = new BinaryCell(data, (Point) location.clone()); diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCellFactory.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCellFactory.java index 890c26656..a819177d6 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCellFactory.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCellFactory.java @@ -10,7 +10,14 @@ import org.w3c.dom.Node; public class BinaryCellFactory extends ElementFactory { - + /** + * Creates a puzzleElement based on the xml document Node and adds it to the board + * + * @param node node that represents the puzzleElement + * @param board board to add the newly created cell + * @return newly created cell from the xml document Node + * @throws InvalidFileFormatException if file is invalid + */ public BinaryCell importCell(Node node, Board board) throws InvalidFileFormatException { try { if (!node.getNodeName().equalsIgnoreCase("cell")) { @@ -45,6 +52,13 @@ public BinaryCell importCell(Node node, Board board) throws InvalidFileFormatExc } } + /** + * Creates a xml document puzzleElement from a cell for exporting + * + * @param document xml document + * @param puzzleElement PuzzleElement cell + * @return xml PuzzleElement + */ public org.w3c.dom.Element exportCell(Document document, PuzzleElement puzzleElement) { org.w3c.dom.Element cellElement = document.createElement("cell"); diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryController.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryController.java index 0bad559d9..caf62f3fe 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryController.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryController.java @@ -6,6 +6,16 @@ public class BinaryController extends ElementController { + /** + * Handles cell state changes in the binary puzzle when a mouse event occurs + * If the left mouse button is clicked: + * - If the control key is held down, shows a context menu at the mouse position + * - Otherwise, toggles the cell data state between 0, 1, and 2 in a cyclic manner + * If the right mouse button is clicked, the cell state is also toggled between 2, 1, and 0 + * + * @param e MouseEvent triggered by the user interaction + * @param data PuzzleElement representing the cell being modified + */ @Override public void changeCell(MouseEvent e, PuzzleElement data) { BinaryCell cell = (BinaryCell) data; @@ -30,13 +40,13 @@ public void changeCell(MouseEvent e, PuzzleElement data) { } } else { if (e.getButton() == MouseEvent.BUTTON3) { - if (cell.getData() == 0) { + if (cell.getData() == 2) { data.setData(1); } else { if (cell.getData() == 1) { - data.setData(2); - } else { data.setData(0); + } else { + data.setData(2); } } } diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryElementView.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryElementView.java index 9ac99c958..f5ea33d4a 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryElementView.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryElementView.java @@ -7,6 +7,8 @@ public class BinaryElementView extends GridElementView { private static final Font FONT = new Font("TimesRoman", Font.BOLD, 17); private static final Color FONT_COLOR = Color.BLACK; + private static final Color GIVEN_COLOR = Color.LIGHT_GRAY; + private static final Color ELEMENT_COLOR = Color.WHITE; public BinaryElementView(BinaryCell cell) { super(cell); @@ -22,99 +24,66 @@ public BinaryCell getPuzzleElement() { return (BinaryCell) super.getPuzzleElement(); } + + /** + * Draws the cells provided in the puzzle's .xml file with light gray background + * + * @param graphics2D The graphics object to draw on + */ @Override public void drawGiven(Graphics2D graphics2D) { - BinaryCell cell = (BinaryCell) puzzleElement; - BinaryType type = cell.getType(); - if (type == BinaryType.ZERO) { - 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); - graphics2D.setColor(FONT_COLOR); - graphics2D.setFont(FONT); - FontMetrics metrics = graphics2D.getFontMetrics(FONT); - String value = String.valueOf(puzzleElement.getData()); - int xText = location.x + (size.width - metrics.stringWidth(value)) / 2; - int yText = - location.y + ((size.height - metrics.getHeight()) / 2) + metrics.getAscent(); - graphics2D.drawString(String.valueOf(puzzleElement.getData()), xText, yText); - } else { - if (type == BinaryType.ONE) { - 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); - graphics2D.setColor(FONT_COLOR); - graphics2D.setFont(FONT); - FontMetrics metrics = graphics2D.getFontMetrics(FONT); - String value = String.valueOf(puzzleElement.getData()); - int xText = location.x + (size.width - metrics.stringWidth(value)) / 2; - int yText = - location.y - + ((size.height - metrics.getHeight()) / 2) - + metrics.getAscent(); - graphics2D.drawString(String.valueOf(puzzleElement.getData()), xText, yText); - - } else { - if (type == BinaryType.UNKNOWN) { - graphics2D.setStroke(new BasicStroke(0)); - 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); - } - } - } + drawCell(graphics2D, GIVEN_COLOR); } + /** + * Draws new cells being added to board with white background + * + * @param graphics2D The graphics object to draw on + */ @Override public void drawElement(Graphics2D graphics2D) { + drawCell(graphics2D, ELEMENT_COLOR); + } + + /** + * Helper method to handle drawing the cell based on its type and background color + * + * @param graphics2D The graphics object to draw on + * @param bgColor The background color for the cell + */ + private void drawCell(Graphics2D graphics2D, Color bgColor) { BinaryCell cell = (BinaryCell) puzzleElement; BinaryType type = cell.getType(); - if (type == BinaryType.ZERO) { + + if (type == BinaryType.ZERO || type == BinaryType.ONE) { graphics2D.setStroke(new BasicStroke(1)); + graphics2D.setColor(bgColor); + graphics2D.fillRect(location.x, location.y, size.width, size.height); + graphics2D.setColor(Color.BLACK); + graphics2D.drawRect(location.x, location.y, size.width, size.height); + drawCenteredText(graphics2D); + } else if (type == BinaryType.UNKNOWN) { + graphics2D.setStroke(new BasicStroke(0)); 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); - FontMetrics metrics = graphics2D.getFontMetrics(FONT); - String value = String.valueOf(puzzleElement.getData()); - int xText = location.x + (size.width - metrics.stringWidth(value)) / 2; - int yText = - location.y + ((size.height - metrics.getHeight()) / 2) + metrics.getAscent(); - graphics2D.drawString(String.valueOf(puzzleElement.getData()), xText, yText); - } else { - if (type == BinaryType.ONE) { - 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); - FontMetrics metrics = graphics2D.getFontMetrics(FONT); - String value = String.valueOf(puzzleElement.getData()); - int xText = location.x + (size.width - metrics.stringWidth(value)) / 2; - int yText = - location.y - + ((size.height - metrics.getHeight()) / 2) - + metrics.getAscent(); - graphics2D.drawString(String.valueOf(puzzleElement.getData()), xText, yText); - - } else { - if (type == BinaryType.UNKNOWN) { - graphics2D.setStroke(new BasicStroke(0)); - 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); - } - } } } + + /** + * Helper method to draw the centered text within the cell + * + * @param graphics2D The graphics object to draw on + */ + private void drawCenteredText(Graphics2D graphics2D) { + graphics2D.setColor(FONT_COLOR); + graphics2D.setFont(FONT); + FontMetrics metrics = graphics2D.getFontMetrics(FONT); + String value = String.valueOf(puzzleElement.getData()); + int xText = location.x + (size.width - metrics.stringWidth(value)) / 2; + int yText = location.y + ((size.height - metrics.getHeight()) / 2) + metrics.getAscent(); + graphics2D.drawString(value, xText, yText); + } } + diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryExporter.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryExporter.java index cd58314b6..f12a07378 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryExporter.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryExporter.java @@ -10,6 +10,13 @@ public BinaryExporter(Binary binary) { super(binary); } + /** + * Generates an XML element for the binary puzzle board, including its dimensions and the + * state of each cell. Binary cells that are not in the `UNKNOWN` state are included in the XML. + * + * @param newDocument The XML document to which the board element belongs. + * @return The XML element representing the board. + */ @Override protected org.w3c.dom.Element createBoardElement(Document newDocument) { BinaryBoard board; @@ -26,7 +33,7 @@ protected org.w3c.dom.Element createBoardElement(Document newDocument) { org.w3c.dom.Element cellsElement = newDocument.createElement("cells"); for (PuzzleElement puzzleElement : board.getPuzzleElements()) { BinaryCell cell = (BinaryCell) puzzleElement; - if (cell.getData() != -2) { + if (cell.getData() != BinaryType.UNKNOWN.toValue()) { org.w3c.dom.Element cellElement = puzzle.getFactory().exportCell(newDocument, puzzleElement); cellsElement.appendChild(cellElement); diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryImporter.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryImporter.java index 2fc5b09ef..8a4bad01e 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryImporter.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryImporter.java @@ -12,16 +12,33 @@ public BinaryImporter(Binary binary) { super(binary); } + /** + * Determines if puzzle uses row and column input + * + * @return true if row and column input is used, false otherwise + */ @Override public boolean acceptsRowsAndColumnsInput() { return true; } + /** + * Determines if puzzle uses text input + * + * @return true if text input is used, false otherwise + */ @Override public boolean acceptsTextInput() { return false; } + /** + * Creates an empty board for building + * + * @param rows the number of rows on the board + * @param columns the number of columns on the board + * @throws RuntimeException if board can not be created + */ @Override public void initializeBoard(int rows, int columns) { BinaryBoard binaryBoard = new BinaryBoard(columns, rows); @@ -48,12 +65,12 @@ public void initializeBoard(Node node) throws InvalidFileFormatException { try { if (!node.getNodeName().equalsIgnoreCase("board")) { throw new InvalidFileFormatException( - "binary Importer: cannot find board puzzleElement"); + "Binary Importer: cannot find board puzzleElement"); } Element boardElement = (Element) node; if (boardElement.getElementsByTagName("cells").getLength() == 0) { throw new InvalidFileFormatException( - "binary Importer: no puzzleElement found for board"); + "Binary Importer: no puzzleElement found for board"); } Element dataElement = (Element) boardElement.getElementsByTagName("cells").item(0); @@ -76,7 +93,7 @@ public void initializeBoard(Node node) throws InvalidFileFormatException { int height = binaryBoard.getHeight(); if (binaryBoard == null || width % 2 != 0 || height % 2 != 0) { - throw new InvalidFileFormatException("binary Importer: invalid board dimensions"); + throw new InvalidFileFormatException("Binary Importer: invalid board dimensions"); } for (int i = 0; i < elementDataList.getLength(); i++) { @@ -110,6 +127,11 @@ public void initializeBoard(Node node) throws InvalidFileFormatException { } } + /** + * Initializes a board with text + * @param statements the text being used + * @throws UnsupportedOperationException Binary does not use text input + */ @Override public void initializeBoard(String[] statements) throws UnsupportedOperationException { throw new UnsupportedOperationException("Binary cannot accept text input"); diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryType.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryType.java index 6e3413d7a..f03f2ee08 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryType.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryType.java @@ -1,10 +1,23 @@ package edu.rpi.legup.puzzle.binary; +/** + * Enum representing the possible states of a binary puzzle cell + * + * The states include: + * - ZERO: Represents a cell with a value of 0 + * - ONE: Represents a cell with a value of 1 + * - UNKNOWN: Represents an empty cell + * + */ public enum BinaryType { - ZERO, - ONE, - UNKNOWN; + ZERO, // Enum constant 0 + ONE, // Enum constant 1 + UNKNOWN; // Enum constant 2 + /** + * The `toValue` method returns the ordinal value of the enum constant, + * which can be used to convert the enum to an integer representation. + */ public int toValue() { return this.ordinal(); } diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryView.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryView.java index b11554f28..e1869de6b 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryView.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryView.java @@ -7,6 +7,13 @@ public class BinaryView extends GridBoardView { + /** Creates and arranges the visual components for each cell in the binary puzzle. Initializes + * the view by setting up the board controller, binary controller, and the grid dimensions. + * For each cell in the BinaryBoard, it creates a corresponding BinaryElementView, sets its index, + * size, and location, and adds it to the list of element views to be displayed. + * + * @param board The BinaryBoard representing the current state of the binary puzzle + */ public BinaryView(BinaryBoard board) { super(new BoardController(), new BinaryController(), board.getDimension()); diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowColumnContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowColumnContradictionRule.java index 7c76f8e9f..195350137 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowColumnContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowColumnContradictionRule.java @@ -48,7 +48,7 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { } - Set col = binaryBoard.getCol(cell.getLocation().x); + Set col = binaryBoard.getColCells(cell.getLocation().x); size = col.size(); int colNumZeros = 0; diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeController.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeController.java index 158abe7b4..f2fad0d50 100644 --- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeController.java +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeController.java @@ -6,6 +6,16 @@ public class NurikabeController extends ElementController { + /** + * Handles cell state changes in the nurikabe puzzle when a mouse event occurs + * If the left mouse button is clicked: + * - If the control key is held down, shows a context menu at the mouse position + * - Otherwise, toggles the cell data state between 0, -1, and -2 in a cyclic manner + * If the right mouse button is clicked, the cell data state is also toggled between -2, -1, and 0 + * + * @param e MouseEvent triggered by the user interaction + * @param data PuzzleElement representing the cell being modified + */ @Override public void changeCell(MouseEvent e, PuzzleElement data) { NurikabeCell cell = (NurikabeCell) data; diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeExporter.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeExporter.java index 23efd4724..e01821639 100644 --- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeExporter.java +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeExporter.java @@ -10,6 +10,13 @@ public NurikabeExporter(Nurikabe nurikabe) { super(nurikabe); } + /** + * Generates an XML element for the nurikabe puzzle board, including its dimensions and the + * state of each cell. Nurikabe cells that are not empty are included in the XML. + * + * @param newDocument The XML document to which the board element belongs. + * @return The XML element representing the board. + */ @Override protected org.w3c.dom.Element createBoardElement(Document newDocument) { NurikabeBoard board; From fe42b93a2282e2bda9cb56ec87246e085a1e0117 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Thu, 1 Aug 2024 10:40:28 -0400 Subject: [PATCH 226/258] Added documentation to binary rules and reorganized/restructured bits of code --- .../rules/CompleteRowColumnDirectRule.java | 19 ++- .../binary/rules/PreventTrioDirectRule.java | 18 ++- ...> RepeatedRowColumnContradictionRule.java} | 22 +++- .../binary/rules/SaveBlockerDirectRule.java | 18 ++- .../binary/rules/TrioContradictionRule.java | 71 +++++++--- .../UnbalancedRowColumnContradictionRule.java | 12 +- .../rules/UniqueRowColumnDirectRule.java | 102 +++++++++++--- .../rules/WastedBlockerContradictionRule.java | 124 ++++++++++-------- .../binary/rules/ZeroOrOneCaseRule.java | 30 +++++ .../binary/rules/binary_reference_sheet.txt | 2 +- .../nurikabe/rules/BlackOrWhiteCaseRule.java | 2 +- ...=> RepeatedRowColumnContradictionRule.png} | Bin 12 files changed, 317 insertions(+), 103 deletions(-) rename src/main/java/edu/rpi/legup/puzzle/binary/rules/{DuplicateRowsColumnsContradictionRule.java => RepeatedRowColumnContradictionRule.java} (67%) rename src/main/resources/edu/rpi/legup/images/binary/rules/{DuplicateRowsColumnsContradictionRule.png => RepeatedRowColumnContradictionRule.png} (100%) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java index 22fda93f1..359433685 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java @@ -15,7 +15,8 @@ public CompleteRowColumnDirectRule() { super( "BINA-BASC-0003", "Complete Row/Column", - "If a row/column of length n contains n/2 of a single value, the remaining cells must contain the other value", + "If a row/column of length n contains n/2 of a single value, the remaining " + + "cells must contain the other value", "edu/rpi/legup/images/binary/rules/CompleteRowColumnDirectRule.png"); } @@ -35,15 +36,23 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem BinaryCell binaryCell = (BinaryCell) puzzleElement; BinaryBoard modified = origBoard.copy(); - modified.getPuzzleElement(puzzleElement).setData(binaryCell.getData()); - - if (contraRule.checkContradictionAt(modified, puzzleElement) != null) { + // Flip the cell and check to see if there will be an unbalanced row/column contradiction, + // if so the rule is applied correctly + modified.getPuzzleElement(puzzleElement).setData(Math.abs(binaryCell.getData() - 1)); + if (contraRule.checkContradictionAt(modified, puzzleElement) == null) { return null; } - return "Grouping of Three Ones or Zeros not found"; + return "Unbalanced row/column found"; } + /** + * 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) { return null; diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/PreventTrioDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/PreventTrioDirectRule.java index cff326e81..745e35d4e 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/PreventTrioDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/PreventTrioDirectRule.java @@ -19,6 +19,15 @@ public PreventTrioDirectRule() { "edu/rpi/legup/images/binary/rules/PreventTrioDirectRule.png"); } + /** + * 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) { BinaryBoard origBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); @@ -26,8 +35,8 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem BinaryCell binaryCell = (BinaryCell) puzzleElement; BinaryBoard modified = origBoard.copy(); + // Flip the cell and check to see if there will be a trio contradiction, if so the rule is applied correctly modified.getPuzzleElement(puzzleElement).setData(Math.abs(binaryCell.getData() - 1)); - if (contraRule.checkContradictionAt(modified, binaryCell) == null) { return null; } @@ -35,6 +44,13 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem return "Trio Found"; } + /** + * 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) { return null; diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsColumnsContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/RepeatedRowColumnContradictionRule.java similarity index 67% rename from src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsColumnsContradictionRule.java rename to src/main/java/edu/rpi/legup/puzzle/binary/rules/RepeatedRowColumnContradictionRule.java index 3ece0bae4..13eb35283 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsColumnsContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/RepeatedRowColumnContradictionRule.java @@ -8,28 +8,36 @@ import edu.rpi.legup.puzzle.binary.BinaryType; import java.util.ArrayList; -public class DuplicateRowsColumnsContradictionRule extends ContradictionRule { +public class RepeatedRowColumnContradictionRule extends ContradictionRule { private final String NO_CONTRADICTION_MESSAGE = "Does not contain a contradiction at this index"; private final String INVALID_USE_MESSAGE = "Row or column must have a value in each cell"; - public DuplicateRowsColumnsContradictionRule() { + public RepeatedRowColumnContradictionRule() { super( "BINA-CONT-0003", - "Duplicate Rows/Columns", + "Repeated Row/Column", "There must not be two of the same row or two of the same column in the puzzle", - "edu/rpi/legup/images/binary/rules/DuplicateRowsColumnsContradictionRule.png"); + "edu/rpi/legup/images/binary/rules/RepeatedRowColumnContradictionRule.png"); } + /** + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule + * + * @param board board to check contradiction + * @param puzzleElement equivalent puzzleElement + * @return null if the transition contains a contradiction at the specified puzzleElement, + * otherwise error message + */ @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { BinaryBoard binaryBoard = (BinaryBoard) board; BinaryCell cell = (BinaryCell) binaryBoard.getPuzzleElement(puzzleElement); + // Compare each row with row of current cell to see if they are equal, if so the rule is applied correctly ArrayList row = binaryBoard.getRowTypes(cell.getLocation().y); - int size = row.size(); - for (int i = 0; i < size; i++) { if (i != cell.getLocation().y) { ArrayList currRow = binaryBoard.getRowTypes(i); @@ -39,8 +47,8 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { } } + // Compare each column with column of current cell to see if they are equal, if so the rule is applied correctly ArrayList col = binaryBoard.getColTypes(cell.getLocation().x); - for (int i = 0; i < size; i++) { if (i != cell.getLocation().x) { ArrayList currCol = binaryBoard.getColTypes(i); diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/SaveBlockerDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/SaveBlockerDirectRule.java index bc4e9716f..5f76c4f59 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/SaveBlockerDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/SaveBlockerDirectRule.java @@ -20,14 +20,23 @@ public SaveBlockerDirectRule() { "edu/rpi/legup/images/binary/rules/SaveBlockerDirectRule.png"); } + /** + * 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 + */ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { BinaryBoard origBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); WastedBlockerContradictionRule contraRule = new WastedBlockerContradictionRule(); BinaryCell binaryCell = (BinaryCell) puzzleElement; BinaryBoard modified = origBoard.copy(); + // Flip the cell and check to see if a blocker digit is wasted, if so the rule is applied correctly modified.getPuzzleElement(puzzleElement).setData(Math.abs(binaryCell.getData() - 1)); - if (contraRule.checkContradictionAt(modified, binaryCell) == null) { return null; } @@ -35,6 +44,13 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem return "Wasted Digit Found"; } + /** + * 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) { return null; diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/TrioContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/TrioContradictionRule.java index 20df01539..dce7fe371 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/TrioContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/TrioContradictionRule.java @@ -20,42 +20,61 @@ public TrioContradictionRule() { "edu/rpi/legup/images/binary/rules/TrioContradictionRule.png"); } - public BinaryCell[] getCellsXAway(Board board, PuzzleElement puzzleElement, int x) { + /** + * This method checks the surrounding cells of a given puzzle element at a specified distance + * in both the vertical and horizontal directions + * + * @param board The board where the puzzle elements are located + * @param puzzleElement The puzzle element from which the distance is calculated + * @param n The distance away from the puzzle element to retrieve the surrounding cells + * @return An array of BinaryCells representing the surrounding cells + */ + public BinaryCell[] getCellsNAway(Board board, PuzzleElement puzzleElement, int n) { BinaryBoard binaryBoard = (BinaryBoard) board; BinaryCell cell = (BinaryCell) binaryBoard.getPuzzleElement(puzzleElement); int cellX = cell.getLocation().x; int cellY = cell.getLocation().y; - BinaryCell[] cells = new BinaryCell[4]; // [0] up x, [1] down x, [2] forward x, [3] backward x + BinaryCell[] cells = new BinaryCell[4]; // [0] up x, [1] down x, [2] right x, [3] left x cells[0] = null; cells[1] = null; cells[2] = null; cells[3] = null; - if (binaryBoard.getCell(cellX, cellY + x) != null) { - cells[0] = binaryBoard.getCell(cellX, cellY + x); + if (binaryBoard.getCell(cellX, cellY + n) != null) { + cells[0] = binaryBoard.getCell(cellX, cellY + n); } - if (binaryBoard.getCell(cellX, cellY - x) != null) { - cells[1] = binaryBoard.getCell(cellX, cellY - x); + if (binaryBoard.getCell(cellX, cellY - n) != null) { + cells[1] = binaryBoard.getCell(cellX, cellY - n); } - if (binaryBoard.getCell(cellX + x, cellY) != null) { - cells[2] = binaryBoard.getCell(cellX + x, cellY); + if (binaryBoard.getCell(cellX + n, cellY) != null) { + cells[2] = binaryBoard.getCell(cellX + n, cellY); } - if (binaryBoard.getCell(cellX - x, cellY) != null) { - cells[3] = binaryBoard.getCell(cellX - x, cellY); + if (binaryBoard.getCell(cellX - n, cellY) != null) { + cells[3] = binaryBoard.getCell(cellX - n, cellY); } return cells; } + + /** + * Checks whether the cell and its two surrounding cells form a trio of zeros or ones; + * If a trio is found, it indicates a contradiction + * + * @param board The board where the puzzle elements are located + * @param puzzleElement The puzzle element to check for contradiction + * @return true if no contradiction is found, false if contradiction detected + */ public boolean checkSurroundPair(Board board, PuzzleElement puzzleElement) { BinaryBoard binaryBoard = (BinaryBoard) board; BinaryCell cell = (BinaryCell) binaryBoard.getPuzzleElement(puzzleElement); - // [0] up x, [1] down x, [2] forward x, [3] backward x - BinaryCell[] cellsOneAway = getCellsXAway(board, puzzleElement, 1); - BinaryCell[] cellsTwoAway = getCellsXAway(board, puzzleElement, 2); + // [0] up n, [1] down n, [2] right n, [3] left n + BinaryCell[] cellsOneAway = getCellsNAway(board, puzzleElement, 1); + BinaryCell[] cellsTwoAway = getCellsNAway(board, puzzleElement, 2); if (cell.getType() == BinaryType.ONE || cell.getType() == BinaryType.ZERO) { + // left one and left two if (cellsOneAway[3] != null && cellsTwoAway[3] != null && cellsOneAway[3].getType() != BinaryType.UNKNOWN @@ -65,6 +84,7 @@ public boolean checkSurroundPair(Board board, PuzzleElement puzzleElement) { return false; } } + // right one and right two if (cellsOneAway[2] != null && cellsTwoAway[2] != null && cellsOneAway[2].getType() != BinaryType.UNKNOWN @@ -74,6 +94,7 @@ public boolean checkSurroundPair(Board board, PuzzleElement puzzleElement) { return false; } } + // down one and down two if (cellsOneAway[1] != null && cellsTwoAway[1] != null && cellsOneAway[1].getType() != BinaryType.UNKNOWN @@ -83,6 +104,7 @@ public boolean checkSurroundPair(Board board, PuzzleElement puzzleElement) { return false; } } + // up one and up two if (cellsOneAway[0] != null && cellsTwoAway[0] != null && cellsOneAway[0].getType() != BinaryType.UNKNOWN @@ -97,14 +119,23 @@ public boolean checkSurroundPair(Board board, PuzzleElement puzzleElement) { return true; } + /** + * Checks whether there are two of the same cell type separated by one cell that also has + * the same type in any direction. If a trio is found, it indicates a contradiction + * + * @param board The board where the puzzle elements are located + * @param puzzleElement The puzzle element to check for contradiction + * @return true if no contradiction is found, false if contradiction detected + */ public boolean checkOneTileGap(Board board, PuzzleElement puzzleElement) { BinaryBoard binaryBoard = (BinaryBoard) board; BinaryCell cell = (BinaryCell) binaryBoard.getPuzzleElement(puzzleElement); - // [0] up x, [1] down x, [2] forward x, [3] backward x - BinaryCell[] cellsOneAway = getCellsXAway(board, puzzleElement, 1); + // [0] up n, [1] down n, [2] right n, [3] left n + BinaryCell[] cellsOneAway = getCellsNAway(board, puzzleElement, 1); if (cell.getType() == BinaryType.ONE || cell.getType() == BinaryType.ZERO) { + // left one and right one if (cellsOneAway[3] != null && cellsOneAway[2] != null && cellsOneAway[3].getType() != BinaryType.UNKNOWN @@ -114,6 +145,7 @@ public boolean checkOneTileGap(Board board, PuzzleElement puzzleElement) { return false; } } + // down one and up one if (cellsOneAway[1] != null && cellsOneAway[0] != null && cellsOneAway[1].getType() != BinaryType.UNKNOWN @@ -127,6 +159,15 @@ public boolean checkOneTileGap(Board board, PuzzleElement puzzleElement) { return true; } + /** + * 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) { diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowColumnContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowColumnContradictionRule.java index 195350137..82f658013 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowColumnContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowColumnContradictionRule.java @@ -23,7 +23,15 @@ public UnbalancedRowColumnContradictionRule() { "edu/rpi/legup/images/binary/rules/UnbalancedRowColumnContradictionRule.png"); } - + /** + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule + * + * @param board board to check contradiction + * @param puzzleElement equivalent puzzleElement + * @return null if the transition contains a contradiction at the specified puzzleElement, + * otherwise error message + */ @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { BinaryBoard binaryBoard = (BinaryBoard) board; @@ -43,6 +51,7 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { } } + // if there are too many zeros or ones in this row if (rowNumZeros > size / 2 || rowNumOnes > size / 2) { return null; } @@ -62,6 +71,7 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { } } + // if there are too many zeros or ones in this column if (colNumZeros > size / 2 || colNumOnes > size / 2) { return null; } diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UniqueRowColumnDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UniqueRowColumnDirectRule.java index 2f8a95a8a..3f90510e3 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UniqueRowColumnDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UniqueRowColumnDirectRule.java @@ -20,33 +20,49 @@ public UniqueRowColumnDirectRule() { super( "BINA-BASC-0004", "Unique Row/Column", - "If an unfinished row/column only differs by empty cells from a finished one, fill contradicting empty cells with opposite digit to prevent a repeated row/column", + "If an unfinished row/column only differs by empty cells from a finished one, " + + "fill contradicting empty cells with opposite digit to prevent a repeated row/column", "edu/rpi/legup/images/binary/rules/UniqueRowColumnDirectRule.png"); } + /** + * Counts the number of empty (UNKNOWN) cells in a given sequence + * + * @param seq The sequence of BinaryType elements to check + * @return The number of empty (UNKNOWN) cells in the sequence + */ private int getNumEmpty(ArrayList seq) { int numEmpty = 0; for (BinaryType t : seq) { if (t.equals(BinaryType.UNKNOWN)) { numEmpty++; - if (numEmpty > 2) { - break; - } } } return numEmpty; } - private String checkOppositeDigitDifference(ArrayList seq, BinaryBoard origBoard, BinaryCell binaryCell, int rowOrColumn) { + + /** + * Checks if there is a valid opposite digit to prevent a repeated row/column + * + * @param seq The sequence (row or column) to check + * @param origBoard The original board + * @param binaryCell The binary cell being checked + * @param rowOrColumn Flag to indicate whether checking a row (0) or a column (1) + * @return Null if a valid opposite digit is found, otherwise an error message + */ + private String checkOppositeDigitDifference(ArrayList seq, BinaryBoard origBoard, + BinaryCell binaryCell, int rowOrColumn) { // rowOrColumn : 0 for row, 1 for column int numEmpty = getNumEmpty(seq); if (numEmpty > 2) { - return "Row/Col must have at most 2 empty cells"; + return "Row/Column must have at most 2 empty cells"; } boolean valid = false; for (int i = 0; i < seq.size(); i++) { ArrayList currSeq; + // Get the sequence (row or column) from the original board to compare if (rowOrColumn == 0) { if (i == binaryCell.getLocation().y) { continue; @@ -62,10 +78,12 @@ private String checkOppositeDigitDifference(ArrayList seq, BinaryBoa int numDifferentCells = 0; for (int j = 0; j < currSeq.size(); j++) { int numEmptyInCurrSeq = getNumEmpty(currSeq); + // If the current sequence has empty cells, it's not valid for comparison if (numEmptyInCurrSeq != 0) { valid = false; break; } + // Count differences between the sequences, stopping if more than 1 difference is found if (!seq.get(j).equals(currSeq.get(j)) && !seq.get(j).equals(BinaryType.UNKNOWN)) { if (++numDifferentCells > 1 || numEmpty != 1) { valid = false; @@ -73,17 +91,23 @@ private String checkOppositeDigitDifference(ArrayList seq, BinaryBoa } } - if (currSeq.get(j).equals(BinaryType.ZERO) && seq.get(j).equals(BinaryType.UNKNOWN) && binaryCell.getType().equals(BinaryType.ONE)) { - if ((rowOrColumn == 0 && binaryCell.getLocation().x == j) || rowOrColumn == 1 && binaryCell.getLocation().y == j) { + // Check if there's a contradiction with the current cell, if not mark as valid + if (currSeq.get(j).equals(BinaryType.ZERO) && seq.get(j).equals(BinaryType.UNKNOWN) + && binaryCell.getType().equals(BinaryType.ONE)) { + if ((rowOrColumn == 0 && binaryCell.getLocation().x == j) || rowOrColumn == 1 + && binaryCell.getLocation().y == j) { valid = true; } } - else if (currSeq.get(j).equals(BinaryType.ONE) && seq.get(j).equals(BinaryType.UNKNOWN) && binaryCell.getType().equals(BinaryType.ZERO)) { - if ((rowOrColumn == 0 && binaryCell.getLocation().x == j) || rowOrColumn == 1 && binaryCell.getLocation().y == j) { + else if (currSeq.get(j).equals(BinaryType.ONE) && seq.get(j).equals(BinaryType.UNKNOWN) + && binaryCell.getType().equals(BinaryType.ZERO)) { + if ((rowOrColumn == 0 && binaryCell.getLocation().x == j) || rowOrColumn == 1 + && binaryCell.getLocation().y == j) { valid = true; } } } + // Exit if a valid sequence is found if (valid) { break; } @@ -92,10 +116,22 @@ else if (currSeq.get(j).equals(BinaryType.ONE) && seq.get(j).equals(BinaryType.U if (valid) { return null; } - return "Rule is not applicable"; + return "There does not exist an opposite digit difference in "; } - private String checkRemainingOneDigitDifference(ArrayList seq, BinaryBoard origBoard, BinaryCell binaryCell, int rowOrColumn, int zeroOrOne) { + /** + * Checks if there is one digit remaining in a sequence that can be filled to avoid repeating + * another sequence on the board + * + * @param seq The sequence (row or column) to check + * @param origBoard The original board + * @param binaryCell The binary cell being checked + * @param rowOrColumn Flag to indicate whether checking a row (0) or a column (1) + * @param zeroOrOne Flag to indicate whether checking for 0s (0) or 1s (1) + * @return Null if the rule can be applied, otherwise an error message + */ + private String checkRemainingOneDigitDifference(ArrayList seq, BinaryBoard origBoard, + BinaryCell binaryCell, int rowOrColumn, int zeroOrOne) { // zeroOrOne: zero for 0, one for 1 for (int i = 0; i < seq.size(); i++) { @@ -116,15 +152,18 @@ private String checkRemainingOneDigitDifference(ArrayList seq, Binar boolean valid = true; for (int j = 0; j < currSeq.size(); j++) { int numEmptyInCurrSeq = getNumEmpty(currSeq); + // If the current sequence has empty cells, it's not valid for comparison if (numEmptyInCurrSeq != 0) { valid = false; break; } + // Check if there is a cell difference from this seq and current seq if (!seq.get(j).equals(currSeq.get(j)) && !seq.get(j).equals(BinaryType.UNKNOWN)) { valid = false; break; } } + // Determine if the current sequence can be modified to prevent repetition if (valid) { BinaryType currSeqCell = currSeq.get(binaryCell.getLocation().x); if (rowOrColumn == 0) { @@ -133,11 +172,15 @@ private String checkRemainingOneDigitDifference(ArrayList seq, Binar currSeqCell = currSeq.get(binaryCell.getLocation().y); } + // Check if this sequence has only one more zero remaining and current sequence fills that zero in, + // if so, zero in this seq must go in another cell to prevent repetition if (zeroOrOne == 0) { if (currSeqCell.equals(BinaryType.ZERO) && binaryCell.getType().equals(BinaryType.ONE)) { return null; } } + // Check if this sequence has only one more one remaining and current sequence fills that one in, + // if so, one in this seq must go in another cell to prevent repetition else if (zeroOrOne == 1) { if (currSeqCell.equals(BinaryType.ONE) && binaryCell.getType().equals(BinaryType.ZERO)) { return null; @@ -145,14 +188,25 @@ else if (zeroOrOne == 1) { } } } - return "Rule is not applicable"; - } + return "There does not exist a sequence that can be prevented by a remaining digit difference"; + } + + /** + * 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 + */ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { BinaryBoard origBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); BinaryCell binaryCell = (BinaryCell) puzzleElement; + // Check if filling the current cell with the opposite digit would prevent repetition with another row ArrayList row = origBoard.getRowTypes(binaryCell.getLocation().y); if (checkOppositeDigitDifference(row, origBoard, binaryCell, 0) == null) { return null; @@ -168,17 +222,23 @@ else if (row.get(i).equals(BinaryType.ONE)) { } } + // Check if only one more zero is needed, then see this row will be repeated by another row + // if current cell is filled in with last zero as well if (numZeros == row.size()/2 - 1) { if (checkRemainingOneDigitDifference(row, origBoard, binaryCell, 0, 0) == null) { return null; } } + + // Check if only one more one is needed, then see this row will be repeated by another row + // if current cell is filled in with last one as well if (numOnes == row.size()/2 - 1) { if (checkRemainingOneDigitDifference(row, origBoard, binaryCell, 0, 1) == null) { return null; } } + // Check if filling the current cell with the opposite digit would prevent repetition with another column ArrayList col = origBoard.getColTypes(binaryCell.getLocation().x); if (checkOppositeDigitDifference(col, origBoard, binaryCell, 1) == null) { return null; @@ -195,20 +255,32 @@ else if (col.get(i).equals(BinaryType.ONE)) { } } + // Check if only one more zero is needed, then see this column will be repeated by another column + // if current cell is filled in with last zero as well if (numZeros == col.size()/2 - 1) { if (checkRemainingOneDigitDifference(col, origBoard, binaryCell, 1, 0) == null) { return null; } } + + // Check if only one more one is needed, then see this column will be repeated by another column + // if current cell is filled in with last one as well if (numOnes == col.size()/2 - 1) { if (checkRemainingOneDigitDifference(col, origBoard, binaryCell, 1, 1) == null) { return null; } } - return "Rule is not applicable"; + return "There is no row/column that forces this cell to be a " + binaryCell.getData().toString(); } + /** + * 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) { return null; diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/WastedBlockerContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/WastedBlockerContradictionRule.java index f45eb5dba..e7ab51b41 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/WastedBlockerContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/WastedBlockerContradictionRule.java @@ -16,11 +16,26 @@ public WastedBlockerContradictionRule() { super( "BINA-CONT-0004", "Wasted Blocker", - "There exists a cell in this row/column that allocates a digit unnecessarily and will cause a future trio to appear", + "There exists a cell in this row/column that allocates a digit unnecessarily and" + + " will cause a future trio to appear", "edu/rpi/legup/images/binary/rules/WastedBlockerContradictionRule.png"); } - + /* + i [ n ] j + i -> digit on left (0 if no digit exists) + n -> number of empty cells + j -> digit on right (0 if no digit exists) + neededZeros = ( n + i + j ) / 3 + */ + /** + * Calculates the number of zeros needed in a sequence based on the values on either side and the number of empty cells. + * + * @param leftVal The value on the left side of the empty cells + * @param rightVal The value on the right side of the empty cells + * @param emptyCellsInCurSec The number of empty cells in the current section + * @return The number of zeros needed in the sequence + */ private int calculateNeededZeros(int leftVal, int rightVal, int emptyCellsInCurSec) { int leftCopy = leftVal; int rightCopy = rightVal; @@ -33,6 +48,21 @@ private int calculateNeededZeros(int leftVal, int rightVal, int emptyCellsInCurS return ((emptyCellsInCurSec + leftCopy + rightCopy) / 3); } + /* + i [ n ] j + i -> digit on left (1 if no digit exists) + n -> number of empty cells + j -> digit on right (1 if no digit exists) + neededOnes = ( n + ( 1 - i ) + ( 1 - j ) ) / 3 + */ + /** + * Calculates the number of ones needed in a sequence based on the values on either side and the number of empty cells + * + * @param leftVal The value on the left side of the empty cells + * @param rightVal The value on the right side of the empty cells + * @param emptyCellsInCurSec The number of empty cells in the current section + * @return The number of ones needed in the sequence + */ private int calculateNeededOnes(int leftVal, int rightVal, int emptyCellsInCurSec) { int leftCopy = leftVal; int rightCopy = rightVal; @@ -45,16 +75,12 @@ private int calculateNeededOnes(int leftVal, int rightVal, int emptyCellsInCurSe return ((emptyCellsInCurSec + (1 - leftCopy) + (1 - rightCopy)) / 3); } - private int convertTypeToInt(BinaryType type) { - if (type.equals(BinaryType.ZERO)) { - return 0; - } else if (type.equals(BinaryType.ONE)) { - return 1; - } else { - return -1; - } - } - + /** + * Checks a sequence (row or column) to see if a wasted blocker digit is used + * + * @param seq The sequence to check + * @return Null if the sequence contains a contradiction, otherwise an error message + */ private String checkSequence(ArrayList seq) { int numZeros = 0; int numOnes = 0; @@ -72,24 +98,18 @@ private String checkSequence(ArrayList seq) { } if (emptyCell) { - if (emptyCellsInCurSec > 1) { + if (emptyCellsInCurSec > 1) { // Ignore case where there is only one empty cell + int leftVal; + int rightVal; + // Check if left cell is out of bounds if (i-emptyCellsInCurSec-1 < 0) { - int leftVal = -1; - int rightVal = convertTypeToInt(seq.get(i)); - neededZeros += calculateNeededZeros(leftVal, rightVal, emptyCellsInCurSec); - neededOnes += calculateNeededOnes(leftVal, rightVal, emptyCellsInCurSec); -// System.out.println("NEEDED ZEROS: " + calculateNeededZeros(leftVal, rightVal, emptyCellsInCurSec); -// System.out.println("NEEDED ONES: " + calculateNeededOnes(leftVal, rightVal, emptyCellsInCurSec); -// System.out.println("NUM EMPTY BEFORE THIS : " + emptyCellsInCurSec + ", surrounded by " + leftVal + " and " + rightVal); + leftVal = -1; } else { - int leftVal = convertTypeToInt(seq.get(i-emptyCellsInCurSec-1)); - int rightVal = convertTypeToInt(seq.get(i)); - neededZeros += calculateNeededZeros(leftVal, rightVal, emptyCellsInCurSec); - neededOnes += calculateNeededOnes(leftVal, rightVal, emptyCellsInCurSec); -// System.out.println("NEEDED ZEROS: " + calculateNeededZeros(leftVal, rightVal, emptyCellsInCurSec); -// System.out.println("NEEDED ONES: " + calculateNeededOnes(leftVal, rightVal, emptyCellsInCurSec); -// System.out.println("NUM EMPTY BEFORE THIS : " + emptyCellsInCurSec + ", surrounded by " + leftVal + " and " + rightVal); + leftVal = seq.get(i-emptyCellsInCurSec-1).toValue(); } + rightVal = seq.get(i).toValue(); + neededZeros += calculateNeededZeros(leftVal, rightVal, emptyCellsInCurSec); + neededOnes += calculateNeededOnes(leftVal, rightVal, emptyCellsInCurSec); } emptyCell = false; emptyCellsInCurSec = 0; @@ -100,44 +120,27 @@ private String checkSequence(ArrayList seq) { } emptyCellsInCurSec++; } - //System.out.println(seq.get(i).toString()); } - // check if empty cells surrounded by out of bounds + // Check last cell is empty if (emptyCell) { - if (emptyCellsInCurSec > 1) { + if (emptyCellsInCurSec > 1) { // Ignore case where there is only one empty cell + int leftVal; + int rightVal; + // Check if left cell is out of bounds if (seq.size()-1-emptyCellsInCurSec-1 < 0) { - int leftVal = -1; - int rightVal = -1; - neededZeros += calculateNeededZeros(leftVal, rightVal, emptyCellsInCurSec); - neededOnes += calculateNeededOnes(leftVal, rightVal, emptyCellsInCurSec); -// System.out.println("NEEDED ZEROS: " + calculateNeededZeros(leftVal, rightVal, emptyCellsInCurSec); -// System.out.println("NEEDED ONES: " + calculateNeededOnes(leftVal, rightVal, emptyCellsInCurSec); -// System.out.println("NUM EMPTY BEFORE THIS : " + emptyCellsInCurSec+ ", surrounded by " + leftVal + " and " + rightVal); + leftVal = -1; } else { - int leftVal = convertTypeToInt(seq.get(seq.size()-1-emptyCellsInCurSec)); - int rightVal = -1; - neededZeros += calculateNeededZeros(leftVal, rightVal, emptyCellsInCurSec); - neededOnes += calculateNeededOnes(leftVal, rightVal, emptyCellsInCurSec); -// System.out.println("NEEDED ZEROS: " + calculateNeededZeros(leftVal, rightVal, emptyCellsInCurSec); -// System.out.println("NEEDED ONES: " + calculateNeededOnes(leftVal, rightVal, emptyCellsInCurSec); -// System.out.println("NUM EMPTY BEFORE THIS : " + emptyCellsInCurSec+ ", surrounded by " + leftVal + " and " + rightVal); + leftVal = seq.get(seq.size()-1-emptyCellsInCurSec).toValue(); } + rightVal = -1; + neededZeros += calculateNeededZeros(leftVal, rightVal, emptyCellsInCurSec); + neededOnes += calculateNeededOnes(leftVal, rightVal, emptyCellsInCurSec); } - emptyCell = false; - emptyCellsInCurSec = 0; } -// if (numZeros + neededZeros > seq.size()/2) { -// System.out.println("NEED TOO MANY ZEROS"); -// return null; -// } -// -// if (numOnes + neededOnes > seq.size()/2) { -// System.out.println("NEED TOO MANY ONES"); -// return null; -// } - + // Check if the number of needed zeros or ones exceeds half the sequence length + // If so, return null to indicate contradiction has occurred if ((numZeros + neededZeros > seq.size()/2) || (numOnes + neededOnes > seq.size()/2)) { return null; } @@ -145,6 +148,15 @@ private String checkSequence(ArrayList seq) { return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE; } + /** + * 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) { diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ZeroOrOneCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ZeroOrOneCaseRule.java index 6fefd3947..3ae7a424d 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ZeroOrOneCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ZeroOrOneCaseRule.java @@ -21,6 +21,13 @@ public ZeroOrOneCaseRule() { "edu/rpi/legup/images/binary/rules/ZeroOrOneCaseRule.png"); } + /** + * Checks whether the {@link TreeTransition} logically follows from the parent node using this + * rule. This method is the one that should be 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(); @@ -49,6 +56,13 @@ public String checkRuleRaw(TreeTransition transition) { return null; } + /** + * Generates a {@link CaseBoard} that includes all blank cells from the given board that this + * case rule can be applied to + * + * @param board The board to find locations where this case rule can be applied + * @return A CaseBoard containing pickable elements where the case rule can be applied + */ @Override public CaseBoard getCaseBoard(Board board) { BinaryBoard binaryBoard = (BinaryBoard) board.copy(); @@ -62,6 +76,13 @@ public CaseBoard getCaseBoard(Board board) { 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<>(); @@ -84,6 +105,15 @@ public ArrayList getCases(Board board, PuzzleElement puzzleElement) { 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/binary/rules/binary_reference_sheet.txt b/src/main/java/edu/rpi/legup/puzzle/binary/rules/binary_reference_sheet.txt index fd786bcc9..619d183a5 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/binary_reference_sheet.txt +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/binary_reference_sheet.txt @@ -5,7 +5,7 @@ BINA-BASC-0004 : UniqueRowColumnDirectRule BINA-CONT-0001 : TrioContradictionRule BINA-CONT-0002 : UnbalancedRowColumnContradictionRule -BINA-CONT-0003 : DuplicateRowsColumnsContradictionRule +BINA-CONT-0003 : RepeatedRowColumnContradictionRule BINA-CONT-0004 : WastedBlockerContradictionRule BINA-CASE-0001 : ZeroOrOneCaseRule \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/BlackOrWhiteCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/BlackOrWhiteCaseRule.java index 209ce47d5..1c87d5cfa 100644 --- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/BlackOrWhiteCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/BlackOrWhiteCaseRule.java @@ -24,7 +24,7 @@ public BlackOrWhiteCaseRule() { /** * 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. + * rule. This method is the one that should be overridden in child classes. * * @param transition transition to check * @return null if the child node logically follow from the parent node, otherwise error message diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/DuplicateRowsColumnsContradictionRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/RepeatedRowColumnContradictionRule.png similarity index 100% rename from src/main/resources/edu/rpi/legup/images/binary/rules/DuplicateRowsColumnsContradictionRule.png rename to src/main/resources/edu/rpi/legup/images/binary/rules/RepeatedRowColumnContradictionRule.png From 965b66d4a5e6daf1f5fe0ad743d6c0fb38f8e699 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Thu, 1 Aug 2024 16:10:45 -0400 Subject: [PATCH 227/258] Added treeTent isBoardComplete function --- .../edu/rpi/legup/puzzle/treetent/TreeTent.java | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTent.java b/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTent.java index 68c97865d..4b0113232 100644 --- a/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTent.java +++ b/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTent.java @@ -3,6 +3,8 @@ 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 java.util.List; public class TreeTent extends Puzzle { @@ -58,7 +60,20 @@ public boolean isValidDimensions(int rows, int columns) { */ @Override public boolean isBoardComplete(Board board) { - return false; + TreeTentBoard treeTentBoard = (TreeTentBoard) board; + + for (ContradictionRule rule : contradictionRules) { + if (rule.checkContradiction(treeTentBoard) == null) { + return false; + } + } + for (PuzzleElement data : treeTentBoard.getPuzzleElements()) { + TreeTentCell cell = (TreeTentCell) data; + if (cell.getType() == TreeTentType.UNKNOWN) { + return false; + } + } + return true; } /** From b1708f36924dc1b67c1e64d46f51ba149455640b Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Thu, 1 Aug 2024 16:11:03 -0400 Subject: [PATCH 228/258] Fixed resize proof functionality --- .../edu/rpi/legup/ui/proofeditorui/treeview/TreeView.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeView.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeView.java index 12f8df428..f426168c8 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeView.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeView.java @@ -162,8 +162,9 @@ public void reset() { } public void zoomFit() { - double fitWidth = (viewport.getWidth() - 8.0) / (getSize().width - 200); - double fitHeight = (viewport.getHeight() - 8.0) / (getSize().height - 120); + final int MIN_HEIGHT = 200; + double fitWidth = (viewport.getWidth() - 7.0) / (getSize().width - 75); + double fitHeight = (viewport.getHeight()) / Math.max((getSize().height - 115), MIN_HEIGHT); zoomTo(Math.min(fitWidth, fitHeight)); viewport.setViewPosition(new Point(0, viewport.getHeight() / 2)); } From 9dbd831ea734fcbaa4b0ac05b639ba38c3395358 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Thu, 1 Aug 2024 16:11:23 -0400 Subject: [PATCH 229/258] Changed Skyscrapers valid dimensions to minimum 3x3 --- src/main/java/edu/rpi/legup/puzzle/skyscrapers/Skyscrapers.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/Skyscrapers.java b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/Skyscrapers.java index df5ba78a3..44f416cef 100644 --- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/Skyscrapers.java +++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/Skyscrapers.java @@ -46,7 +46,7 @@ public Board generatePuzzle(int difficulty) { * @return true if the given dimensions are valid for Skyscrapers, false otherwise */ public boolean isValidDimensions(int rows, int columns) { - return rows >= 4 && rows == columns; + return rows >= 3 && rows == columns; } /** From eac3c6bf0d57823633c7d526dfb0640a9336a08c Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Fri, 2 Aug 2024 13:52:55 -0400 Subject: [PATCH 230/258] Added new skyscrapers contradiction rule images --- .../contradictions/DuplicateNumber.png | Bin 954 -> 1991 bytes .../contradictions/ExceedingVisibility.png | Bin 1184 -> 1956 bytes .../contradictions/InsufficientVisibility.png | Bin 1291 -> 2071 bytes .../contradictions/PreemptiveVisibility.png | Bin 1101 -> 1784 bytes .../contradictions/UnresolvedCell.png | Bin 1165 -> 2108 bytes .../contradictions/UnresolvedNumber.png | Bin 1357 -> 2658 bytes 6 files changed, 0 insertions(+), 0 deletions(-) diff --git a/src/main/resources/edu/rpi/legup/images/skyscrapers/contradictions/DuplicateNumber.png b/src/main/resources/edu/rpi/legup/images/skyscrapers/contradictions/DuplicateNumber.png index 7ba489c2bb1b9dbdf7669a1f69c06abfc111e1a0..6ab3cd769669c4269dfbed60c311fcd7629d644f 100644 GIT binary patch literal 1991 zcmb`IX*e6`7RO_zwl=L0OSD{jFtnAZp{O>oM2Ib!d#83%5o?1`s+OT>?M!OlO1YBh zjH0#*?X4t&Xc$5Xy&bhz?RrCKJ8|#*bm!yT59dA4dH&};&-0%5Ilq(X>Wn&l^6W_f z0B{;@Z-W*2z+;n=5S^FbF5pE@jEqGg0Zm+$RZ(z)h;Tvx04@2aj{L<%v2=vJI~f2_ zy?1P4`HR~G06@|UZG-qO&S$-HI#l6%6}GLKJj)wlD{s2>Qb{QxTH{}~gV>64Xn0WQ zBlQ^TNVcTxiI*saZMO$Vgdt*2MoPQ%62jUB<0TjCMxHOWbxNulx!fB;Im9(RGp2Y7 z&+YqRxC?^bWn=Qv>|mvZ;S_TK%_E()&i_*P(@zc?|LisBy!j@psJK{>*3?vdbd*ps z$E~smq3hK`+Xt^H!h_fA(w^&DmqU`aR>yU3fBBsFbHe@>g3ssIQ>g=l{r&An{0k0L zbU3^q9pfRowmDb;l?c5QL?Y!Eb&}q8Yqd2uj}qbp8&&_C=ZD7{!A?T^Z{X!IIjNc3 zr4VuOBR{+))b1ryuN0D>>GuDTqdb5vJ-bFGweRZbbWaaYPw&Qp+QvpyxRMU9{#)e% zB=i^W2cv=jdoYf?Ufy;kUi-XYgXOSxR}$;#dr@3m+={`t_ur1VdU~!cL@Y4}?>IUPjoIXeP8pO(&6h^zgTj5Y=;c^ zVmJ80WJA&{QJeH9w(Db;k*Rp)krAvcqv|x;5Ti(J$&S3xb-4J2+Z2X%^%v z2Sem$snwfO4}!+?vHP#imel406(R%mVoVAd)8l7>pOQfgyebpdKt?#&K9OqUjAK%olYaTzcr>-Zx-8Np~rYRsP7yLNJ!X+q;7DJJk6 zYkR!Ui=_4U)+p3H{*q(bHyO_A_9W61%jC~qKFhM(fh+}s`r2BAxrN0<;@ALIRNxxi zGEw-QbCtP{!S_uM`upt!n(hCVB*kOvE_!z_Y{Z=R>T*>)@1ec8xY*>oq7{BM*OdvX z9P!fE*DoY+iU*mQU;@7_80+i1Y3?win`_7_NI7(5u~@CqtJpFl|J32i%eb4fUE48| zY;~4;x;Z;fmD1V@r#*g5(L&`7@Mt&!kLuQXdp9t)LT9|zL>{IhJ^T7u)MD1pzAt>B zF4czQrQt{-rV?LXQL(tQ$l1s8Mlm=<4W zf$nFk&QxEy6ENEq*^-Su(-=0>Ns3i|Cr?SM&4~}wb*?O!eoEvV>@HV=PbF1JFKW&U6-Nv6ORePy;XSpUXXixND*B^(|LxZ4uuwhm;i>NCk{s$t}t~8d{w^4 ztsWY3C~=t~{zu)4r@WR6^gk4AmY^xnXMn5#oK}>Dq4^u4+!u4jq6gr5=SDwB< z7vs|#|JT1`$~5V>)}vytPIYaK*APdlU-ex43MotJ`E8pzBI+w)VW4m$HFj^s&9reO zXrsCT0`H02?n`{X_Kub9Es@8YXXn!`#FUAUdPv83qYJ&9aZe_e1Q%?)F>ow4EW9fz z(+%`B*3Qt(!0j)+s)$+{)tK%GuQ=6qM{rZ{@fmp;PFE;wfcQu;22#G3oIQlVBNl#~ z>q|dX7UQ6ZH#358%|fXo(PexL0P^lYwamFlLmnot4Y8Kc_#t<^>?^)iaDaXW&?{Q` zLhF!`J#5hGw_b-R$4Tx=nCdk>JW|6ER$Gu>+6;ryj*)phVnfNOoGV);75ERb)3e|k zGDXWP){7lLEmVpBR9}ONcUOSpr>JO}+Wfgr)2=O+bmyh8$PY@2Y&aKYJQ@geL+a&0 z%+rBhQth|gkWL|#6vKcqzU?59NPzY;_ZZB$V?c|h_%FwR7SWo03}|uiJWRxI5v~8U zjC9WSPn4+PAn%&Z`G;8b7ZRib{KWDn|FBsyY>kfqp^<&EL+rffZ_|L5+fD7+av|6X tV1Ncil)iE&X70yAGWG4Hj0gTZGHWRGnasA}Wzq5lplzLPnvi~}zXNXnt#JSV delta 930 zcmV;T16};b54r~-iBL{Q4GJ0x0000DNk~Le0001F0000Q2nGNE071(6<&hyLe9qmNt0sJv`SJzp%fDk_2NZ^qDT!nTBJx? zdQqsL(1Vxs(5s+Ak?Of1v3L|Mr1UEEALv2+ps9g0Vne#6Nz=61&Bw0uPPU-XgOu4Y z+C1>G%M3faJI{P3t7I}63l5+te+oZ7j>n;Pb@Owl=yEC0YjreKmz^RW(=u_Y!;Kd+ zGboixcB*(B6=Ikso{rwdo2!?AYMs56Y3B-poO?W&Ui*oMH?L!0Jq1|obwt0Bi-~rt zxb-=U56L8U3I#huJPr%7@MJuOx0lbOM7^ZjFHQ>ez(xc9%^c$E8tx5Ve?vI4irU%! zW(ATM5l~s$Cj4~+k<|^nUs(7Lgj^Uv@y;mB+amxQT7=+oL(%d$IrRu}ZNDkx>k9N& zuVDpGGg*S}!-gsM%jfWa`-Dh(({UlHeRLe9Y5)}-N_kgEpv=bc{XM(%-=H*>ci1&Y z2~=x9okfdinUFSrM_Y(we;ivO2g`EVkWPr(?S|jaR$~r9<@fgX@}rDWq!FU3DtdZ) zplKQ=CMI}=iN@>oBArfSa&i)ZK!A&p4Jm|>3=%OrJBx5QjQRO_bar+MZNV`vGNcva#H34Q(rSz5E6e^hShl^0G(xDNXu{pv+Ja#i$mjDy z_aX;N>qH^}kH>>rt;Uzv^kU}$KF?-%;|`h+frsVrUBQ79C6 z(78-92x*2as+elE$}5S2hOJiYO=LqFA#IwpOo&AjC!4q}RZQ^zx(}OQC{6TzS~%&q zMu@6FVMCBoEI=t0#l#Ma-O`^@*g2)~yu+?JO0Z|9k13dyc;-DE#_^9Fo{f(papfYg zw+|S)oht}xy=;{<{e1%uZVV!nT>~l=y8;Drq6_eLAo}G8-u=s8oix})eSc&G(f%`B zjuUuT!(Ay?a4r~tZ*Lc-;!LOa!otV0js+&9=$H`T7Zs%k0Plyy0{{R307*qoM6N<$ Ef<;BAh5!Hn diff --git a/src/main/resources/edu/rpi/legup/images/skyscrapers/contradictions/ExceedingVisibility.png b/src/main/resources/edu/rpi/legup/images/skyscrapers/contradictions/ExceedingVisibility.png index ff999f4bc3b1e829029189e50cc9104fe20b0280..b607be60fe260ac37df4182095894d379866de55 100644 GIT binary patch literal 1956 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 Hu0mjfny)QA diff --git a/src/main/resources/edu/rpi/legup/images/skyscrapers/contradictions/InsufficientVisibility.png b/src/main/resources/edu/rpi/legup/images/skyscrapers/contradictions/InsufficientVisibility.png index cfe04a503d478bcbf64d4484aa0cb57583efb426..285451ba1668936a8a70b3cce7f8dda36ea8e791 100644 GIT binary patch literal 2071 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 SQ+B7!0giUA=mwi$%6|cppUP(d delta 1270 zcmV5Q_>SiBL{Q4GJ0x0000DNk~Le0001F0000P2nGNE0LNa7OOYWbeDaS%kSh2Z}i=7Ao}`@^`b zfFR-&Qy6hZBYX&fgCQ1&e~?T_6-%VV!Ac(IEdQ)V{bc=B5ak7V$y0eLh|0LIf(R6_ zRfy^Yp@A|O3@9xv6*p1*yGQ3Ds@rHZvd@Bo0x5?dHk*yrO=dQmrBr#SN)QqwBW{Nm z7Z*`gRRyot%Lb4aR97$J4=aTTSktPCwJEwETDf6OK)Cs~?YR42&B z#s+3*XW2mM^?E6X4<#ifXm4*vZ*MR9`ucEmbcFi)dYDWmsl@X^UN<;6$m$yz8DVMD z)6-a6TSJk|TMAVPk`~V<4u=EP)z#dWD-xSLZh3hb{r&xzo0~&ZQxhVQh*aYFNhA_* zI-OWuUB%eg7@Jr`e;^Q$9kWy=NS1uu712^iGuLXhA`}X-G#Wti7|P>8DwRTAT^;;> zKWiiV9BplFtSvdHQjmN>15aK^-j_@!+44y7>hMrJ0CIvvAt<0vO-*5GX^FKZSM&=d zNEQmVw6yH(>@ab7ZX5`ze`aO|U0q%1=;)AA<#FKzp_xnTfBWd@C|km|wzlAQyVjcUsbK+~^5mc@L8#;F>+7)F?HC#w!ph1D_V@R>h(dKA92{VK zdmAp73&X?1f9#WXTr_Yz1Su{qX4~BE?r!w-^f2q}>_ls8E8_9ERO;y{fBpXXm&g?B zAw1#woepXAU<7#y?M^5V=Ys0d-dTp_=ez%1zh8SBsZRzV{Yj9QO9Y3$YQbBe-p(x546+C)_vM|LgyOV@}9P5 zd4HnH7;=$OUJwdyqDyBu7^~-Oe4!KZnR4efs)zMgL6j9ltApV4LhyR{*q?ik-|S^Y z(THLs;t)I!a+g1k{pDl*Rtm*}y5^e&ynp#silBV|6+)MGVjHa~1Mcdgv=e|Be56bc zkcXH`Oz_ox56b&*ycmCSxF;Tz7CxKAYgP+5O7Sl=fB(n`ctgnG@x=vS$p1WnAZ|>2 gifeCP$)g~^KlLY+KFX1xy8r+H07*qoM6N<$f-iqn&;S4c diff --git a/src/main/resources/edu/rpi/legup/images/skyscrapers/contradictions/PreemptiveVisibility.png b/src/main/resources/edu/rpi/legup/images/skyscrapers/contradictions/PreemptiveVisibility.png index 6d330baa6e76585ea860dd7d758c51d841081675..6c4a6e4574f8154ce20de311be3f35f38bc1bb09 100644 GIT binary patch literal 1784 zcma)7c~sJg7DiD@!!1OlM8#1{)3JW0Vj6BZxs*$4;$&`slxf*BBh6Q-|iSciwqt&imuud+xdSp7Y&v&-Y!rpU(+3 z)qScU5J=6_19w^;314kDMDFt)T1ws51S5S>WPa;p0$S$W`Kp;;3o-dKg@?0g} zBP0O?LS=n5h5YFy5(osz^TfFXUJsK#@bw5iq1UUd5!QTz+wEki|H7TyURl2q$hn=Z zudVI)*3HH+W+}o*_aBRsA%hjS^L{*od$bqF#>ZCBcfk{bgJCd zb=v=?&|!_7o13ezt8?4j+^lbCm{kdzQ4CvG6LmL|R$sPTBgJ?xFW!!N?%6XMC`ShM zp3&SNrRqJFKWC|z^|d|OFPV7#8lKS^8Rz5cD;Z+>4hw~zRA*;B{$!xbjVTwb-Z!ll zJ|%oUe~uG1R+}s?&_s&k59ef8)nn*3iE5st_40XZ9IOx!dfz6wnb@;GEByiTdKca1dxV8qi!{!^t^0D$LBG#x8{RFZJCuDG z>0hvt3d7f$s$=a%Ik~ICV5g+aW_~e4RA^o4&t2qNX(z89$e4*1^ubxmNXjcU zJCJp@=U1ov!Jo&&VrXkBj1PUUiy2^VXf);g2NPxbL0xQ~0SlFGsIiQ;TIOSeOJMQ| zi0bp!S(Y>|d`xM5t77Y2;ZpCyP57C;`(Z4Upa93;t&}qOyeq0#s{8i9SNMBBUM z0kL$nVGyI~oq3R5w}B4!_RisEwelgBQ4B-ymT+wBQA-Q<$fYqo-ee##HZG3-IWaNO zKOg}1?}34#-zW>)COA*Xv8T_Udp&*nwD^Y~yi80?I@lIET}9O2mOp%m{J5~d%F-~% zZY(cHAK6n$V4%TU`;o}D+Bu3v_S>-cJOEZiq z?}~|S=3yUE1_p?}>gsCTERo|(y4TT(yl5F48d0D!oiwrgdwJLi6B zy)n1Vp&ky0_W&T{h>+fU`45_!nxe*U9i)VY0za`>#~IYi4ojz3KFtpNT8cf(G>cD7 z^_iZYF5`kQpAZOy*`Y(;CmpATezyh@`vrn*jephD=yVr%Q}F;BSwY}ZS2x}_-v|s2 zCYL}@7V~&sat>(`>0o!*?P4*YYZ}G~gCQn*g!nz_R ztE#H#dvu1|&)JzEJsN9kU40*7t7c}RW8&hf=ya7ObggWZ7_q4P$JCUu{CNJpzWJJY zbyE`)69$|@+0OS6+shUvzGaSDrIj=qZF08uEgm?00imPwn8Wc89kD%n^fn>(W20BX zn^Q^m6lF1btV7XuBd_jX`VwUs(Du(x%Ftd=5gN=;B)d*&FbBnVcXNoiOEN#}Tx-SD zpPI>Cv}|Zl5&9ebK)ZPOd>M3m#1=aS$dbNGFHql!_SuT9DTvB-JE`Hk{9A!M-F z4l0%+v`7>PdNofT0{e&BS7{z-nbMZX82` z&`3#1NyyF3mGQV4MoUOYe?VqtCQihe;v$NYm6av0ySuy6PDTk?5E_Ru{^;nad}v=^ zA5v3O^;R{+$H!xSejc^8wPq>D=U$movpWqM#zG2 z2|ArlxLht7`q}Mvy+sYD{d46lE-o4#$a#|}4yZ#zLvpfCPEH~xeP=x&Na z!(-G-B$5huuLsCyAZUWV*jTU!_z8G*y$!1D64%zve%r092? zjUhppXydm5;`MrEn5q(P=3MsNM-C1S^xBI7H*dasMMVYX=H^gRQiAI0YV7RnNV|nf z$b!&VD=RD5-rknq1sLWnEG!s$*x%rQHa9o1w6rAsFJt(bf0-HBY&QLl$cB@1e0&`3 z?d|C4>5-+QqXVt2t%fqhhSKj8h0Bsx`bI_%XGKLnrQfe!gTMCyH21#V`ZE-T1Ea|7 zpP}UGiu?^8RK!#gyRSmLoSQa0$*rxe6>&O&^~`sP@G}|bV_le ziLiZBf01|u1cfLbg`Zt1vgrT8+jTTQc`i3~v;I0^!Z2!na=6>u3!ifx7P=Y5ScN8E xJYHnv=fkE)e=4CM+?=bbs?gHXVzMB>cPIA=MhldS4QK!W002ovPDHLkV1nN70}ucJ diff --git a/src/main/resources/edu/rpi/legup/images/skyscrapers/contradictions/UnresolvedCell.png b/src/main/resources/edu/rpi/legup/images/skyscrapers/contradictions/UnresolvedCell.png index 76947671dcfb96d6293f4a081d5f40e39ce2659e..ae78caf499ba352bc3c9227d1428b464832363e9 100644 GIT binary patch literal 2108 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 JPDHLkV1nhw1L^<( diff --git a/src/main/resources/edu/rpi/legup/images/skyscrapers/contradictions/UnresolvedNumber.png b/src/main/resources/edu/rpi/legup/images/skyscrapers/contradictions/UnresolvedNumber.png index 8862702f182093687b4fecb187ff755e7b4569cd..602f6270205809d635d11aba725e56ade53f80e5 100644 GIT binary patch literal 2658 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 From 54184dfd9dcf51aa7bbaaeb55b59c6519cac69d8 Mon Sep 17 00:00:00 2001 From: summerhenson Date: Fri, 2 Aug 2024 15:09:45 -0400 Subject: [PATCH 231/258] Rewrite Columns Within Regions inference rule --- .../rules/ColumnsWithinRegionsDirectRule.java | 66 +++++++++++++++++-- .../ColumnsWithinRegionsDirectRuleTest.java | 13 +++- .../RegionsWithinColumnsDirectRuleTest.java | 11 +++- 3 files changed, 78 insertions(+), 12 deletions(-) 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 6e4830138..db8f12f23 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 @@ -8,11 +8,9 @@ import edu.rpi.legup.puzzle.starbattle.StarBattleBoard; import edu.rpi.legup.puzzle.starbattle.StarBattleCell; import edu.rpi.legup.puzzle.starbattle.StarBattleCellType; +import io.opencensus.trace.Link; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import java.util.*; public class ColumnsWithinRegionsDirectRule extends DirectRule { public ColumnsWithinRegionsDirectRule() { @@ -23,6 +21,25 @@ public ColumnsWithinRegionsDirectRule() { "edu/rpi/legup/images/starbattle/rules/ColumnsWithinRegionsDirectRule.png"); } + private void generateSubsets(List> subsets, int current, int skip, int size) { + if (current == size) { + return; + } + List> newSubsets = new LinkedList>(); + if (current != skip) { + for (List subset: subsets) { + List copy = new LinkedList(subset); + copy.add(current); + newSubsets.add(copy); + } + subsets.addAll(newSubsets); + List oneMember = new LinkedList(); + oneMember.add(current); + subsets.add(oneMember); + } + generateSubsets(subsets, current + 1 == skip ? current + 2 : current + 1, skip, size); + } + /** * Checks whether the child node logically follows from the parent node at the specific * puzzleElement index using this rule @@ -34,13 +51,48 @@ public ColumnsWithinRegionsDirectRule() { */ @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 + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleBoard origBoard = (StarBattleBoard) transition.getParents().get(0).getBoard(); StarBattleCell cell = (StarBattleCell) board.getPuzzleElement(puzzleElement); + int dim = board.getSize(); + int region = cell.getGroupIndex(); + int column = cell.getLocation().x; + if (cell.getType() != StarBattleCellType.BLACK) { return "Only black cells are allowed for this rule!"; } + + List> subsets = new LinkedList>(); + generateSubsets(subsets,0, column, dim); + + for (List columnSubset: subsets) { + Set regions = new HashSet(); + boolean containsRegion = false; + int columnStars = 0; + int regionStars = 0; + for (int c: columnSubset) { + columnStars += board.columnStars(c); + for (StarBattleCell ce: origBoard.getCol(c)) { + if (ce.getType() == StarBattleCellType.UNKNOWN) { + if (regions.add(ce.getGroupIndex())) { + regionStars += board.getRegion(ce.getGroupIndex()).numStars(); + } + if (ce.getGroupIndex() == region) { + containsRegion = true; + } + } + } + } + if (containsRegion && board.getPuzzleNumber() * columnSubset.size() - columnStars + >= board.getPuzzleNumber() * regions.size() - regionStars) { + return null; + } + } + /* + //StarBattleBoard modified = (StarBattleBoard) origBoard.copy(); + //modified.getPuzzleElement(puzzleElement).setData(StarBattleCellType.BLACK.value); + // the columns that are contained Set columns = new HashSet(); // the regions that contain them @@ -94,7 +146,7 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem } } */ - return null; + return "Wrong!"; } /** diff --git a/src/test/java/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRuleTest.java b/src/test/java/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRuleTest.java index 3297b1d5e..185d31f5c 100644 --- a/src/test/java/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRuleTest.java +++ b/src/test/java/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRuleTest.java @@ -268,7 +268,7 @@ public void ColumnsWithinRegionsDirectRule_FalseColumnsWithinRegions2() } @Test - public void ColumnsWithinRegionsDirectRule_FalseColumnsWithinRegions3() + public void ColumnsWithinRegionsDirectRule_PartialRemoval() throws InvalidFileFormatException { TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/PartialColumnTwoCells", starbattle); TreeNode rootNode = starbattle.getTree().getRootNode(); @@ -280,11 +280,18 @@ public void ColumnsWithinRegionsDirectRule_FalseColumnsWithinRegions3() cell1.setData(StarBattleCellType.BLACK.value); board.addModifiedData(cell1); - Assert.assertNotNull(RULE.checkRule(transition)); + Assert.assertNull(RULE.checkRule(transition)); + Point location1 = new Point(0, 1); for (int i = 0; i < board.getHeight(); i++) { for (int k = 0; k < board.getWidth(); k++) { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + Point point = new Point(k,i); + if (point.equals(location1)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } } } } diff --git a/src/test/java/puzzles/starbattle/rules/RegionsWithinColumnsDirectRuleTest.java b/src/test/java/puzzles/starbattle/rules/RegionsWithinColumnsDirectRuleTest.java index 68b11d091..a45f7455f 100644 --- a/src/test/java/puzzles/starbattle/rules/RegionsWithinColumnsDirectRuleTest.java +++ b/src/test/java/puzzles/starbattle/rules/RegionsWithinColumnsDirectRuleTest.java @@ -335,11 +335,18 @@ public void RegionsWithinColumnsDirectRule_FalseRegionsWithinColumns4() cell.setData(StarBattleCellType.BLACK.value); board.addModifiedData(cell); - Assert.assertNotNull(RULE.checkRule(transition)); + Assert.assertNull(RULE.checkRule(transition)); + Point location = new Point(0,3); for (int i = 0; i < board.getHeight(); i++) { for (int k = 0; k < board.getWidth(); k++) { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + Point point = new Point(k,i); + if (point.equals(location)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } } } } From 4fe7e5f4e949c99a340e8df524ae8bd05c13a6b8 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Fri, 2 Aug 2024 18:49:33 -0400 Subject: [PATCH 232/258] Added new skyscrapers direct rule images --- .../rules/WastedBlockerContradictionRule.png | Bin 2041 -> 2030 bytes .../contradictions/ExceedingVisibility.png | Bin 1956 -> 1949 bytes .../images/skyscrapers/rules/FixedMax.png | Bin 1225 -> 1783 bytes .../images/skyscrapers/rules/LastCell.png | Bin 1352 -> 2174 bytes .../images/skyscrapers/rules/LastNumber.png | Bin 1335 -> 2083 bytes .../legup/images/skyscrapers/rules/NEdge.png | Bin 1523 -> 2027 bytes .../images/skyscrapers/rules/OneEdge.png | Bin 934 -> 1455 bytes 7 files changed, 0 insertions(+), 0 deletions(-) diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/WastedBlockerContradictionRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/WastedBlockerContradictionRule.png index c101b734f32785071ef7bd4a5a1a8c0fd98fbbc7..beca66eb81b23ae182a35aac37944910367a4f98 100644 GIT binary patch literal 2030 zcmZvdc{CJy6vxLhW1BKX3}Tv84B?HDM`J8Agh&l4N%qVT8e3$Lb&RdCCB@4e^#KEI@MHs*W8<;4L2z#dBr zQ(M0G_}fH5{GEob&*nRUAX{@RpseTM96t~yn4B>I04it_+ipO9EJm`p6a)Y$QvNo9 zD-We&005CVOH&j3Fz2N_E8+o5X$oy+9i>_?`!&ea3BABa6)|9>7AN$5mK_Ks2zGrs)+dTv6yOd>&49ct(xJxR&SCbdph1>LiJ$w{ufV_ z*1g^-GcS0u3|4-qs*rnlpV_`W3LrTurR|oY)MRrsHj_O!sPd$&OtV(YFZ#z!Z-K31zO6l~3_~~)@|YJq3eNfmBC7rY8^m(q~vr z{)CUc#d!b6kJdpmJ&(KxOA@4&6crV9ZtZMCCIm))JoxoGadUMFp3ug8b~z}^N*`Gt zu^9`~y_ZNN5~--{z_t1Fte4(WX>zDz#cZOlZ?Rd5On<5z3M)=yGA}q*dRkIBVVkQ* z8R2Wm%%_*6Y{OEOFeg<&(a?-LPoembkPvD|bR^eH6lusm;|T-;mE-O0Ep|DgvP!Kk za_a`Q!$RlWy4;s<14Z5D9?vV*HdA*I|Ec?@h77qkbY!p0W)^ni$Pwy~TN(`Fy)*?I zoL_{=mxa>XWE+Cird;m#>IKh2K8z=zD__4x=Sw^a`MD=4V4`(T`0fry*Demd+L5JV@8WXyb?8b74Q52a z%o&g4-tiN(a@qNTn8%OL^H=cVD3UWdP-IRca=x~}TPK!2)C7N@#q$^?$YM5v{8?sq zy16!VMTtRP-}``W*&Lm|#a$}m&rCdK&Z61aZTbBR6`L$-z|QtfH7%`Dx?L&7UP&IA zZ*#U{6K)ku5D>AalnV9dhq)X0}W_emDe{_bSY9pPsTU5gy5aGFNWjf1f7Mx{FN zf&$%vS?E5VLJ6>n@Ub@FF!{SkxtXyF0+Z;TRSgD73jvW)+Z(lVKHlE@()37zd3kxk z>&sWTREak86RqwEEEa3ylgZNKXHZgSVIkDg#Hp49_wT|(rBrOdIz34ilWTA@v-P&30{1u2M{Q`iSE1skayOyKE$*2i(}un3$7&A? zegr!R2JclV`gLNlx7bzgXOpB}!z6=`ez zMb64K^GTY-!u-4%y(IZEDDK7>27__40xcfJ3QC7-lPp$^olvU?P_8!grI2|{;Y2h0 z%xXK$F@dXeW^bEP8?GQG!7q&aR{vc-2JK&#ei88&5hs8qsU~NKt6z9Zl@L~+(E}!z zl+fu2=cz;=-Uer4qj?}U@vV@^-e%>K$6=U=4N}K2*k2AjN;ve?nUT|ztB(_rR7yon zOA9YA10`h6nVA6DZC2GaS-%g}X}Z@xAC#~^P3m&(^AZm|nu=HM z^L*sDwcoWsl!}M&h}vZf}|LjOv?^h2Pro zqfDlZkIDkpkthffOo47wyD zB8tsg9<2~EI@-lu`ry4f*#U1A${)G;Z8`xeX^kEmw{LnCG}FioMOOY=oa(D`;L4v- zm}bu*CiB$$dPMVv=e3YKk;bW&elJuF!q|nb;W>T%{YpR9X1p`%HO$Me5mAgTmM5t?s~Yy|E1Y~UbU+YuF?Sx8x5Ln+ltfQBaCpo zoEB;LY7^YOUczRSR$UvRNEQ=%r!=PoeYu(2E|WVBBpLj6?mRA)9MOMuKzIKQxv!e!9;gtD`<`xim& z3*@N4mp8!)4C$qcZ=C)+Ke6{Gwf{i*TuO}WRMm=ClkI3y)r#mM*crj~y&MD~U9; x9YIHH+%}S)begpZh#u4p_??Wp3VL`8AS&C^cerd@nEyuuEX{08%doDoe*yBs$Q1wp literal 2041 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 RNkU5nIM^X=o8f-R{{UTqkxT#p literal 1956 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 delta 1204 zcmV;l1WWt(4ao^1iBL{Q4GJ0x0000DNk~Le0001F0000L2nGNE0I-}(Fp(iAe3`Im_)Oe-IiPipIu9Bqb%m<#LHv{YRxzVSjHQUuJ&=rz7z9 zDT9>w?dTAneQsv&cDn=Xwo<8t#bQBwdpqLegdn3$N5#kioL zAPjsrjPnmeu-@6=2+&G{UW4C94EVL_PZ&(W0Z$sTZ)Ro&X0sWosi}Mlf709Ai}CSs z+~41eSN+FeFreQf$Y0<8h_4+D$WoWV0jqfT-=P!2G48B}WkQYF`hDn(YP`I>h~lnK?oO|uzQ4| z72;2$wcvgia=a5k{!jQ6e?+U*vJ8qc6CR=9O7Tml(?Jjf@hU%1Hb(J~?E5E33Su&u zFf}!Wwzf8$pP#cp#uFNi2A-q@Jv}`b8yiDNNC;P=sMTuR-QA(PyBi}TBZ!QQ6z_P) zt01&0YHDgQIy%bIyPTXHTwh-^#d+Yh4%ph-LSkYfIyySg)YQagek+hf;ucXyeK-~p;55)u+nS69dE zG#ZU4FE5APZWo_;TWF;o92~F`;Pmtq1qB6IUtjm>`n?K5d38oc1{36!ii!$uI!sV4 z@$m3~va&MfzOu5ie`MJukOQ(KJ3E_smB+_NHl7U)4Q$m&AsIvHCE?-Wtl(Q(T7uPT z4S35zPRJHYI%xZXI-Z}O&jLIzkSOH3Zf|dyd!;x>;z%JW2xSJFo13Vutwm*JC3`6^ zF@y*U3u7*zsHlk9=xg@91+=v?I5>#Q%S$$CuCA^m6A!O~e^5t{j*d`TT8jSueir0u ztAH{Y9w0G_i;L0K)x~~qZ*QZsvl9-7gZ<`#sHi9u78YV*VF9tRv51b2MoLPGq?hq3 z2nFwb`LJZsC#%ScX6=4J*`Jfq37v$KQ4!$Z{9*W>2qM!fs> z&^YDh=3;Ga4RdpISX^9WF@)+8DI{YE{h2!X+IVsY1c~x$8>Q*ILF4u5`1ulpkQ9U` z0;#|G+feb&yAVVJ9YO>Z3_^rojglILz)yB4g>Za)e=OSpRbO8pCMPFlIjo_iqObJ_ zT>bO`4|k8S1!$#FuZ87jEq-bKgPj-#dO$_?O;1m=v^Fg*O|}Cn!BdILA_(mvksu_D z9K|EmJJ**taGN}S*Cm6~@%RG!tsCaBSO}i)f!as~-^IlR%k*MmVq_8o_z24s^+gWr SyFCB^3IG5}MNUMnLSTaQ;veGx diff --git a/src/main/resources/edu/rpi/legup/images/skyscrapers/rules/LastCell.png b/src/main/resources/edu/rpi/legup/images/skyscrapers/rules/LastCell.png index 216a0f3a1209d7b126eb41f358c417c5a999e974..8db8a3bbfd06e118b5052015f9e885c05aed2992 100644 GIT binary patch literal 2174 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 diff --git a/src/main/resources/edu/rpi/legup/images/skyscrapers/rules/LastNumber.png b/src/main/resources/edu/rpi/legup/images/skyscrapers/rules/LastNumber.png index 1e0555648434f497b65bd92d8c00607ebad0310c..dcf4cb2b8eb02a9029fc3da7f03e9c05f7e2a414 100644 GIT binary patch literal 2083 zcmai#cTm%58poqj1Oj9UNRSAEAv7sJ6(a~lrA9)FxEQJgkj_Fxnusga&;vn|qlt^6 zEXXPngA90>A_QeskRC+{A~8fnrGuC3&CSi;?aco1zVAHm%scPXzMqHW;pU_$zgr#z z0x4pg?Q!DsoMi2k5$~37`2_K??L5xu1n6!*d`@ggg&lW24g%dPR@exV7Ta=h&iL~n z(4Jh$+EzUCITQqvWnk=&dnE_VS7E|c@vxs?=Ocmm;6cWfNg{+T?Fn&DH3#yq%TR#S z14glXO|PnV_erT*8{E)Wb2qKf*rA2Io&o4gU)R;eAmjjTzqHUYzY!uj)M)oj3d>m>%Z<)5a zb~;8K!9pCiEK#tGn9s=S($5Vb{N|WB+!Cl?p7iNW`@RPZ#>mXV*5<`F{}M>q2>+NV zzrIaDWvvE|#i}A5yIILpm^Ad4vjl5wK?cdw9MFm|dH=i;_3Guzx~*n3w&2NG_TH)a z@rNRr`I)|oMZs(1Hvh}wH;)OBpG(|pZF}?8&G=8U74ApAHcHu8iJ$nyWErfeG1ChR z3-3n^An{#k?FE`Bw_9%2M#|c@lwxgk8D^Vwbhj{2r1tZ87EFd*qVQJj@Ppvt7Wx;l1bZELe5ZGGwaW?x=K^3fql zm}SnAw0$-QW9vP2zylVNcq#J_L>x9L!H;sz0#R$1AqtJzT@G4VA` zCMOTr{LwHsW?+ZD+9;)xG`LUniiS2aEO0oov2Ub)Z_9F-0zfLPTDNI0DZ3U`@?tsi zoyxRk@j(Uz3FR!$)}2e@$F4?|Qa0D~qZMYIBMeTRWNsUP2KycvXCn@WxiRjH&eYHB zMtto|E$klic+Q2*{=j_c;=~Kzblr+=p$O>c?b$GtPhY67!Be&)*3SQzK1`p5GmiKO zZgT5T)ysjP%XtZT2^SJ%<$)3=Eto*~V1jI&4d3Ejs2Z{*LoyFG9HN902mqjkM9M=4 zl#v`J%bq+$SV^w1U>$o`GIR^AqLafQ!>90BWIEx@fP>Q^6v`zk>eqEz<;~>0Tp8mW z_>m(%K0XryYVr`}W;IMIt|9fydsjn4Lvs81S?lyP<>keAIvs88>qC#G6~KTK z^jMz2_V=AQu$?+{hFfktBOGlNJ@aS8)nRD|95_XLKGr~#5xEakpjS}+$^D6<2}_#o zrANPJ)-$JQQY$vWW8>qzQEmx0aeXP~Vd83oy4_-0_MnK@!OMtc!EMt<%HIM@$_d*i zoxm^V$O<;Cfaym5E)$~NcyF0L4-fAUhi8~m6y*GFKfW`yjsO1rqc$cu!o9{?VFSe5`ln;Vvr3fvE!RpU9*>WmH}5;$wscRdxiF+A z6w-f9Ac#a|YxQVUUL(L9b%#}~rdTBCf%J`J6eqBqsAov{ke1UV7B6FTSj7EiqaySn7ar7>+Ff;r0m1--r(diR2-HG1> zr%|WuO6WgjJy2m*hRU!kvKM8G&K%BB3CLYjHQgHP+MUk+O&h1Q#|m*Ute>*asfba# zEF9gJl9F=wzR>BD_(Km-+}tZY?{15>OS@vCnZnqudq^^2_kfl*J)Oc=et@=jK~Pq?J>O+hwaXI;DkN=y z^n~>_Q^F5VDm7gU-|ssB`lOj2dqiav2GDO$K+A~v+-C4Thd%SBI70`8il#v`2bWFQ z+hj_2wi#_9Jhy1_wvH?(srk=%59s8W_ba|`D%h9frXy>bC7vWY$a}q4{CY4^>Ig$i z|HA;%k(is#u$WnmfbOA>U= c2J-v1plu?8L5$z3c(8*o4sP~$Pn^y87ys4PegFUf delta 1314 zcmV+-1>O3i5Vr~;iBL{Q4GJ0x0000DNk~Le0001F0000h2nGNE0FLY}?U5lTeQf4*;`bGzLEe+Y!tYQ@sh5;itA*ylii&+vRcAM*3_QC?mSuh%QJ ziUU2T*=&Yzg4k>}jE#+FMzM{n8zI7z_q#78W$HA+^+lkd)BY$h(E&r8DT*LBP@tus8$f2PKU_INW{m-OD)r! z$H$S7kbtA3BN&ZF>8`p_tssw&k2p9uz{$x8+plN^RSH64q@<)EF)>kU(GIGOA+%xS zwTl-C)e53j!h#5fY6YR(R4C6y4vPZ47Eq-il#|-s-G#|yLT_&`R#sM6zDf(Cs8SGe zS;@)CXl`ysXJ;oWD=QHZe-WXHAg|gbi$uA(xxv-d6{~M(#c_p$x?qF_5sa`Pf+4$v zOC?vHP;ed{9fk7?C(@p$;nB}0Hs}pH^!4?jqoaex9$t{+BZns!E;V%$V`^%OJs>a3 zNmlmFFK;M=2&>r=9H?|dCI+J(9?x$`vcJa;Jn(>?`TYDG)6>(ke?{RUNK{l5nwpw0 zJ3Gs2);yp=efRAY_CIyuZPIJpad>%Voe}zIAD(^LjS<(^Tn|oES65?rc$m38IdBuC zwY8PYe@F;gvc_M{!2QV&@FscSu)cyf@btb-IxBv@{}Hdvb9naEOMElg$8D@JF)^sE zt;NX52sc554eE~wf3TPNk@YitXmLFG`q=V0(u^O#AM8;L2<@^0!Iwxe{T??@zV6@) zit!-zC_Z7^D;WQZAe4=zc*ENw6I!XIhfrJ)3ex-g`{?QEVQwroHdeYL4{|tk;)Lqz z^q1_i7En|Wat(BFdTnhD$H&L)yl!J-BXcKmATcg4FWEjIe>XRm%|1HppoQ6@s35dA zDJv^OeSJM9CMH;0W@e`BeE^*@>F@8y-rgQoS6A8L>9)2uCXCuqe93xvcwjquN?BxO zWud*jUH0j7I+I1|6}#Pzl9Cc+XJ>N}S_Bjqgq9WBG#wru!sGEEFE5Wv93fFiY+`3; z2i@J>tWE7Ge=Z0)tGKv0EG#Ur8M3{-E!~k11@nf62KM6~G7nU=Qag$YLT7KO=6!c} z$G&G|WT3RPlzo;98H2^eML3;K6c!d@Zf*`1i$%JtUKACCT-MOg5K>c9QCC-o&CN~B z&(F)wB~iaLD=I1~P*haJmc@aA0X9q2j-rB`ot-hKf3>{4%mkqrLe^An@Fm;3wY7!G z$w`*}cez|F!N;@C@n4~+Ae6zRdO<-!0djJ3aC&;m#R-v1BP&g(O&ksfs;a6`TwMHa zX;d?c2XzvKW(lvNPzVx*W<==Hf*6G2f`s{J2rY;KCK!SvjMK+I`LgMauqs? z#gKO1cr!CIT+5kNbCc6aIkD9DK+CpGh1r`e4|7ju*M_zuV!+8%#l3|g<--4L& Y7pr?>TTCw0P5=M^07*qoM6N<$f|9&w@Bjb+ diff --git a/src/main/resources/edu/rpi/legup/images/skyscrapers/rules/NEdge.png b/src/main/resources/edu/rpi/legup/images/skyscrapers/rules/NEdge.png index d3dd36bbc10fb66ad83d8c04d0214e5f25836739..b238b36aa4cd9478d1c76172df4d667b0d9ec138 100644 GIT binary patch literal 2027 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 delta 909 zcmV;819JSY3#JDkiBL{Q4GJ0x0000DNk~Le0001F0000K2nGNE0DHigksv64B1=)oRBDdZqtik|dPs^CRWD%R*Fl4{Iu$Y=A0Sp`9p%#Kj( z{>ZR9GhvvW|Gs^1-YEO~`$b59Kv5Lr^Lc#z5`kOs@m6an-V74SIImelRaMl~)IisD z-Xc!1SVUc29s2wGVHgH)m4h@v=z;Y_7H_@8X z42Q#kcs!29#YK#bjae4O=kp;P4r6+H8mUx@x5`1PAjY2@2EISV!vPI{uhlsig)`n; z9UiqFp9-(=`~7_^&;3N=EWvxkAVE$}P7sMiFg!eLc@fDvhK7bPH8mw&5S3r0LFVj) z3y-yzXxBnQ<&pNHG!7e${j5TBGOy;n6=aNY9nu9MN{@|vY0eoKLZ!gR_#e3yL2SgS zND%T54D+n!GE|MA-qI?&bC zg`=Y*Ta+u@CFFtpCg$honKPp{5on*1NFxj*c?xh(@Ef54l2FK`5Kq*Vl*R<70Gp zcO#un^PcLUoX_}w_&9cUcF@z)gTuo^W+5cF%_U_8p^Y4crnGRBRCBppyr+67Yunh^ zh+r_tLSR|J!d;>wA3~9qS*${vOxr51ry@bBMTHZN(#Z9SU#O@Gjd3ee`{z;i_V%Qt zRVjRB=ONK2?0_n#Q^r=zqLh*tj@mq86D?T&_)FMtnb6#1%mXS4D6Ec00m|UuASNd# zjS$*omRsC=vJzNuhHZzlE}i00000NkvXXu0mjf&Kau* From 2d0026e64094acecc3adaf2e7788d89169a9a487 Mon Sep 17 00:00:00 2001 From: summerhenson Date: Tue, 6 Aug 2024 14:26:34 -0400 Subject: [PATCH 233/258] Finish reworking X Within Y rules --- .../rules/ColumnsWithinRegionsDirectRule.java | 63 +------------ .../rules/ColumnsWithinRowsDirectRule.java | 92 +++++++++---------- .../rules/RegionsWithinColumnsDirectRule.java | 4 +- .../rules/RegionsWithinRowsDirectRule.java | 4 +- .../rules/RowsWithinColumnsDirectRule.java | 4 +- .../rules/RowsWithinRegionsDirectRule.java | 61 +++++++++++- .../ColumnsWithinRowsDirectRuleTest.java | 13 ++- 7 files changed, 122 insertions(+), 119 deletions(-) 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 db8f12f23..9fdaa23a8 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 @@ -72,11 +72,11 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem int columnStars = 0; int regionStars = 0; for (int c: columnSubset) { - columnStars += board.columnStars(c); + columnStars += origBoard.columnStars(c); for (StarBattleCell ce: origBoard.getCol(c)) { if (ce.getType() == StarBattleCellType.UNKNOWN) { if (regions.add(ce.getGroupIndex())) { - regionStars += board.getRegion(ce.getGroupIndex()).numStars(); + regionStars += origBoard.getRegion(ce.getGroupIndex()).numStars(); } if (ce.getGroupIndex() == region) { containsRegion = true; @@ -89,64 +89,7 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem return null; } } - /* - //StarBattleBoard modified = (StarBattleBoard) origBoard.copy(); - //modified.getPuzzleElement(puzzleElement).setData(StarBattleCellType.BLACK.value); - - // the columns that are contained - Set columns = new HashSet(); - // the regions that contain them - Set regions = new HashSet(); - // columns and regions to process - List columnsToCheck = new ArrayList(); - List regionsToCheck = new ArrayList(); - int columnStars = 0; - int regionStars = 0; - regions.add(cell.getGroupIndex()); - regionsToCheck.add(cell.getGroupIndex()); - - while (!columnsToCheck.isEmpty() || !regionsToCheck.isEmpty()) { - for (int i = 0; i < regionsToCheck.size(); ++i) { - int r = regionsToCheck.get(i); - regionStars += board.getRegion(r).numStars(); - for (StarBattleCell c : board.getRegion(r).getCells()) { - int column = ((StarBattleCell) c).getLocation().x; - if (column != cell.getLocation().x && c.getType() == StarBattleCellType.UNKNOWN && columns.add(column)) { - columnsToCheck.add(column); - } - } - regionsToCheck.remove(i); - --i; - } - for (int j = 0; j < columnsToCheck.size(); ++j) { - int c = columnsToCheck.get(j); - columnStars += board.columnStars(c); - for (int i = 0; i < board.getSize(); ++i) { - int region = board.getCell(c, i).getGroupIndex(); - if (board.getCell(c,i).getType() == StarBattleCellType.UNKNOWN && regions.add(region)) { - regionsToCheck.add(region); - } - } - columnsToCheck.remove(j); - --j; - } - } - // are the columns and regions missing an equal amount of stars - 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!"; - } - if (columns.contains(cell.getLocation().x)) { - return "Only black out cells outside the column(s)!"; - } - /* - for (int c: columns) { - if (c == cell.getLocation().x) { - return "Only black out cells outside the column(s)!"; - } - } - */ - return "Wrong!"; + return "The columns must fully fit within regions with the same number of stars missing!"; } /** 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 765a84d5b..da5c7bfd3 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 @@ -9,10 +9,7 @@ import edu.rpi.legup.puzzle.starbattle.StarBattleCell; import edu.rpi.legup.puzzle.starbattle.StarBattleCellType; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import java.util.*; public class ColumnsWithinRowsDirectRule extends DirectRule { @@ -24,6 +21,25 @@ public ColumnsWithinRowsDirectRule() { "edu/rpi/legup/images/starbattle/rules/ColumnsWithinRowsDirectRule.png"); } + private void generateSubsets(List> subsets, int current, int skip, int size) { + if (current == size) { + return; + } + List> newSubsets = new LinkedList>(); + if (current != skip) { + for (List subset: subsets) { + List copy = new LinkedList(subset); + copy.add(current); + newSubsets.add(copy); + } + subsets.addAll(newSubsets); + List oneMember = new LinkedList(); + oneMember.add(current); + subsets.add(oneMember); + } + generateSubsets(subsets, current + 1 == skip ? current + 2 : current + 1, skip, size); + } + /** * Checks whether the child node logically follows from the parent node at the specific * puzzleElement index using this rule @@ -39,59 +55,43 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem // assumption: the rule has been applied to its fullest extent and the rows and columns // are now mutually encompassing StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleBoard origBoard = (StarBattleBoard) transition.getParents().get(0).getBoard(); StarBattleCell cell = (StarBattleCell) board.getPuzzleElement(puzzleElement); + int dim = board.getSize(); + int row = cell.getLocation().y; + int column = cell.getLocation().x; + if (cell.getType() != StarBattleCellType.BLACK) { return "Only black cells are allowed for this rule!"; } - // the columns that are contained - Set columns = new HashSet(); - // the rows that contain them - Set rows = new HashSet(); - // columns and rows to process - List columnsToCheck = new ArrayList(); - List rowsToCheck = new ArrayList(); - int columnStars = 0; - int rowStars = 0; - int firstRow = cell.getLocation().y; - rows.add(firstRow); - rowsToCheck.add(firstRow); + List> subsets = new LinkedList>(); + generateSubsets(subsets,0, column, dim); - while (!columnsToCheck.isEmpty() || !rowsToCheck.isEmpty()) { - for (int i = 0; i < rowsToCheck.size(); ++i) { - int r = rowsToCheck.get(i); - rowStars += board.rowStars(r); - for (StarBattleCell c : board.getRow(r)) { - int column = c.getLocation().x; - if (c.getType() == StarBattleCellType.UNKNOWN && columns.add(column)) { - columnsToCheck.add(column); + for (List columnSubset: subsets) { + Set rows = new HashSet(); + boolean containsRow = false; + int columnStars = 0; + int rowStars = 0; + for (int c: columnSubset) { + columnStars += origBoard.columnStars(c); + for (StarBattleCell ce: origBoard.getCol(c)) { + if (ce.getType() == StarBattleCellType.UNKNOWN) { + if (rows.add(ce.getLocation().y)) { + rowStars += origBoard.rowStars(ce.getLocation().y); + } + if (ce.getLocation().y == row) { + containsRow = true; + } } } - rowsToCheck.remove(i); - --i; } - for (int i = 0; i < columnsToCheck.size(); ++i) { - int c = columnsToCheck.get(i); - columnStars += board.columnStars(c); - for (StarBattleCell r : board.getCol(c)) { - int row = r.getLocation().y; - if (r.getType() == StarBattleCellType.UNKNOWN && rows.add(row)) { - rowsToCheck.add(row); - } - } - columnsToCheck.remove(i); - --i; + if (containsRow && board.getPuzzleNumber() * columnSubset.size() - columnStars + >= board.getPuzzleNumber() * rows.size() - rowStars) { + return null; } } - // are the columns and regions missing an equal amount of stars - 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!"; - } - if (columns.contains(cell.getLocation().x)) { - return "Only black out cells outside the column(s)!"; - } - return null; + return "The columns must fully fit within rows with the same number of stars missing!"; } /** 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 ac2f0da9a..06d73cc1f 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 @@ -28,8 +28,8 @@ public RegionsWithinColumnsDirectRule() { public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { ColumnsWithinRegionsDirectRule correspondingRule = new ColumnsWithinRegionsDirectRule(); String result = correspondingRule.checkRuleRawAt(transition, puzzleElement); - if (result != null && result.equals("Only black out cells outside the column(s)!")) { - return "Only black out cells outside the region(s)!"; + if (result != null && result.equals("The columns must fully fit within regions with the same number of stars missing!")) { + return "The regions must fully fit within columns with the same number of stars missing!"; } return result; } 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 8219f9c01..012dc0640 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 @@ -29,8 +29,8 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem RowsWithinRegionsDirectRule correspondingRule = new RowsWithinRegionsDirectRule(); String result = correspondingRule.checkRuleRawAt(transition, puzzleElement); - if (result != null && result.equals("Only black out cells outside the row(s)!")) { - return "Only black out cells outside the region(s)!"; + if (result != null && result.equals("The rows must fully fit within regions with the same number of stars missing!")) { + return "The regions must fully fit within rows with the same number of stars missing!"; } return result; } 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 39e3b46c4..a22c31a59 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 @@ -30,8 +30,8 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem ColumnsWithinRowsDirectRule correspondingRule = new ColumnsWithinRowsDirectRule(); String result = correspondingRule.checkRuleRawAt(transition, puzzleElement); - if (result != null && result.equals("Only black out cells outside the column(s)!")) { - return "Only black out cells outside the row(s)!"; + if (result != null && result.equals("The columns must fully fit within rows with the same number of stars missing!")) { + return "The rows must fully fit within columns with the same number of stars missing!"; } return result; } 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 faa75d01c..de9aaf044 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 @@ -9,10 +9,7 @@ import edu.rpi.legup.puzzle.starbattle.StarBattleCell; import edu.rpi.legup.puzzle.starbattle.StarBattleCellType; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import java.util.*; public class RowsWithinRegionsDirectRule extends DirectRule { public RowsWithinRegionsDirectRule() { @@ -23,6 +20,25 @@ public RowsWithinRegionsDirectRule() { "edu/rpi/legup/images/starbattle/rules/RowsWithinRegionsDirectRule.png"); } + private void generateSubsets(List> subsets, int current, int skip, int size) { + if (current == size) { + return; + } + List> newSubsets = new LinkedList>(); + if (current != skip) { + for (List subset: subsets) { + List copy = new LinkedList(subset); + copy.add(current); + newSubsets.add(copy); + } + subsets.addAll(newSubsets); + List oneMember = new LinkedList(); + oneMember.add(current); + subsets.add(oneMember); + } + generateSubsets(subsets, current + 1 == skip ? current + 2 : current + 1, skip, size); + } + /** * Checks whether the child node logically follows from the parent node at the specific * puzzleElement index using this rule @@ -38,10 +54,45 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem // assumption: the rule has been applied to its fullest extent and the rows and regions // are now mutually encompassing StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleBoard origBoard = (StarBattleBoard) transition.getParents().get(0).getBoard(); StarBattleCell cell = (StarBattleCell) board.getPuzzleElement(puzzleElement); + int dim = board.getSize(); + int region = cell.getGroupIndex(); + int row = cell.getLocation().y; + if (cell.getType() != StarBattleCellType.BLACK) { return "Only black cells are allowed for this rule!"; } + + List> subsets = new LinkedList>(); + generateSubsets(subsets,0, row, dim); + + for (List rowSubset: subsets) { + Set regions = new HashSet(); + boolean containsRegion = false; + int rowStars = 0; + int regionStars = 0; + for (int r: rowSubset) { + rowStars += origBoard.rowStars(r); + for (StarBattleCell ce: origBoard.getRow(r)) { + if (ce.getType() == StarBattleCellType.UNKNOWN) { + if (regions.add(ce.getGroupIndex())) { + regionStars += origBoard.getRegion(ce.getGroupIndex()).numStars(); + } + if (ce.getGroupIndex() == region) { + containsRegion = true; + } + } + } + } + if (containsRegion && board.getPuzzleNumber() * rowSubset.size() - rowStars + >= board.getPuzzleNumber() * regions.size() - regionStars) { + return null; + } + } + return "The rows must fully fit within regions with the same number of stars missing!"; + + /* // the rows that are contained Set rows = new HashSet(); // the regions that contain them @@ -89,6 +140,8 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem return "Only black out cells outside the row(s)!"; } return null; + + */ } /** diff --git a/src/test/java/puzzles/starbattle/rules/ColumnsWithinRowsDirectRuleTest.java b/src/test/java/puzzles/starbattle/rules/ColumnsWithinRowsDirectRuleTest.java index 89986b57c..8f9c938cb 100644 --- a/src/test/java/puzzles/starbattle/rules/ColumnsWithinRowsDirectRuleTest.java +++ b/src/test/java/puzzles/starbattle/rules/ColumnsWithinRowsDirectRuleTest.java @@ -191,7 +191,7 @@ public void ColumnsWithinRowsDirectRule_FalseColumnsWithinRows1() } @Test - public void ColumnsWithinRowsDirectRule_FalseColumnsWithinRows2() + public void ColumnsWithinRowsDirectRule_PartialCover() throws InvalidFileFormatException { TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/OneColumn", starbattle); TreeNode rootNode = starbattle.getTree().getRootNode(); @@ -203,11 +203,18 @@ public void ColumnsWithinRowsDirectRule_FalseColumnsWithinRows2() cell1.setData(StarBattleCellType.BLACK.value); board.addModifiedData(cell1); - Assert.assertNotNull(RULE.checkRule(transition)); + Assert.assertNull(RULE.checkRule(transition)); + Point location = new Point(1,0); for (int i = 0; i < board.getHeight(); i++) { for (int k = 0; k < board.getWidth(); k++) { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + Point point = new Point(k,i); + if (point.equals(location)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } } } } From 9e9d8b27b5cb2b2e5903420416a9f297cf5a668e Mon Sep 17 00:00:00 2001 From: summerhenson Date: Tue, 6 Aug 2024 14:58:38 -0400 Subject: [PATCH 234/258] Star or Empty case rule test --- .../rules/StarOrEmptyCaseRuleTest.java | 68 +++++++++++++++++++ .../StarOrEmptyCaseRule/SimpleStarOrEmpty | 29 ++++++++ 2 files changed, 97 insertions(+) create mode 100644 src/test/java/puzzles/starbattle/rules/StarOrEmptyCaseRuleTest.java create mode 100644 src/test/resources/puzzles/starbattle/rules/StarOrEmptyCaseRule/SimpleStarOrEmpty diff --git a/src/test/java/puzzles/starbattle/rules/StarOrEmptyCaseRuleTest.java b/src/test/java/puzzles/starbattle/rules/StarOrEmptyCaseRuleTest.java new file mode 100644 index 000000000..e1f9cb990 --- /dev/null +++ b/src/test/java/puzzles/starbattle/rules/StarOrEmptyCaseRuleTest.java @@ -0,0 +1,68 @@ +package puzzles.starbattle.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.nurikabe.NurikabeType; +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.StarOrEmptyCaseRule; +import edu.rpi.legup.save.InvalidFileFormatException; +import java.awt.*; +import java.util.ArrayList; +import legup.MockGameBoardFacade; +import legup.TestUtilities; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class StarOrEmptyCaseRuleTest { + + private static final StarOrEmptyCaseRule RULE = new StarOrEmptyCaseRule(); + private static StarBattle starBattle; + + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + starBattle = new StarBattle(); + } + + @Test + public void StarOrEmptyCaseRuleTest_SimpleStarOrEmpty() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/StarOrEmptyCaseRule/SimpleStarOrEmpty", starBattle); + TreeNode rootNode = starBattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell = board.getCell(0,0); + ArrayList cases = RULE.getCases(board, cell); + + StarBattleBoard caseBoard1 = (StarBattleBoard) cases.get(0); + StarBattleBoard caseBoard2 = (StarBattleBoard) cases.get(1); + StarBattleCellType board1Type = caseBoard1.getCell(0, 0).getType(); + StarBattleCellType board2Type = caseBoard2.getCell(0, 0).getType(); + + Assert.assertTrue( + (board1Type.equals(StarBattleCellType.BLACK) || board1Type.equals(StarBattleCellType.STAR)) + && (board2Type.equals(StarBattleCellType.BLACK) + || board2Type.equals(StarBattleCellType.STAR))); + Assert.assertFalse(board1Type.equals(board2Type)); + Assert.assertEquals(caseBoard1.getHeight(), caseBoard2.getHeight(), board.getHeight()); + Assert.assertEquals(caseBoard1.getWidth(), caseBoard2.getWidth(), board.getWidth()); + + for (int i = 0; i < caseBoard1.getHeight(); i++) { + for (int k = 0; k < caseBoard1.getWidth(); k++) { + Point point = new Point(k, i); + if (point.equals(caseBoard1.getCell(k, i).getLocation())) { + continue; + } + Assert.assertTrue(caseBoard1.getCell(k, i).equals(caseBoard2.getCell(k, i))); + } + } + } + +} diff --git a/src/test/resources/puzzles/starbattle/rules/StarOrEmptyCaseRule/SimpleStarOrEmpty b/src/test/resources/puzzles/starbattle/rules/StarOrEmptyCaseRule/SimpleStarOrEmpty new file mode 100644 index 000000000..4d065b28f --- /dev/null +++ b/src/test/resources/puzzles/starbattle/rules/StarOrEmptyCaseRule/SimpleStarOrEmpty @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From c4ce4cc8614a752b462c3ac51039e739afcafec1 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Thu, 8 Aug 2024 19:07:33 -0400 Subject: [PATCH 235/258] Updated several image files --- .../edu/rpi/legup/ui/ProofEditorPanel.java | 1 + .../rules/WastedBlockerContradictionRule.png | Bin 2030 -> 2006 bytes .../images/binary/rules/ZeroOrOneCaseRule.png | Bin 5581 -> 2186 bytes .../skyscrapers/cases/CellForNumber.png | Bin 1871 -> 1531 bytes 4 files changed, 1 insertion(+) diff --git a/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java b/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java index 47512466d..441b00c32 100644 --- a/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java +++ b/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java @@ -507,6 +507,7 @@ public Object[] promptPuzzle() { return null; } + System.out.println(preferences.getSavedPath()); return new Object[] {fileName, puzzleFile}; } diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/WastedBlockerContradictionRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/WastedBlockerContradictionRule.png index beca66eb81b23ae182a35aac37944910367a4f98..8813d79560f6a76fb82ef540090b7a0733a9cfe7 100644 GIT binary patch delta 1731 zcmV;!20Z!h57rNmNq>a^03C$^@EbDh000MTNklmc$ zdhXw;zFgu>>~l_La;}^YirZDqsqU`7>(QsG`;H)@C>tCDjDHNjjsbFFL{TIPpFe-5 z%F4=u`_cy3fBEvI;J!4WrlyA8ym?b_Uz+gv@#BK&X~Og8&*}E<+XeTf4GHR+F>2H( z8aYyz4eXJR6xeF*rD%_xk6MhLo*wG$?F}&*utz>pV5_y4qCIv#-e(xX#V~}6VF(w) z5H5xxTnt0F7?YL<4u7>6qeqWcJIY{>e57cdby{1EeLlI#rA#J+A2#2q82kd-v|q>eZ`h%$PADg-2s!Bh8&Vm!?mj9#VL;wYAaw`SU}J2VD1W-@c{g%a?}~ zKHIl%kAHJweEs?rKWs1$QCC+-+qP{BDSWP9zfPMsZ>DkM#%_fa9`*J0v}n;HnlWQW zNa4}k+)PWBED13luU@^P*RNmG+O=y#3Xid4$I^%qkf9HV5lP945mi=JhL{Z4XK#iO z<5N>p6LoZSgczTurlzpPCtItcyLaz~n2baNb)V6fmmY0C8heec&u9FilOYBclTZN$ ze^847Cs)3sOM*5J?eVRk76bDTnz;x7d(Gl$xZb56UjWakl>cNt_Q;;K2iW|NcETQOML3^i7ihtzc7fBIMa z_Ipl@T)TkklH8e+ptaWqNfVKvu|?C4pvy1F`kcThWO z8xA;SP*9AdATC|H6u0FljLDNHe}}#4KyAW`ll}Ym$9)2Kq%&p86uNTd3RP8A#fu(J zpFU0F$Bz$tivw;M3|KSJj&9tzk-mTbE@~oRhZPfC5dm%nECITD^=dpq!paW}5?;J` zp?W6xzu}faK`~J9s2OwS%!%7ONm~t@S+i!PYAgGLV`G?%B``_V#)WluAa)j2Q^hTV zK|Ap7?(VQ91NIUj0SY}CI3#%>t{M3Z2a|mSDSt7+DT4t!a43qEdMj71j0*%S=Qst5 zrlz5xAztN&YWno))A+>Ff``FFhYrOfIxHVOdh}?~)eLSK4A^HNtXZ>$&Ye3)hYuf) zGv*Wo?(PK(7EoDP8J#?NGQQI}%^v!Ql9CeIvu6+O*s+7QY}pbER7`NoV9;g?cO{Hb zBa7v+O-QmMa#~e zJ8A0FsUgM#p4WNv=7ks!OgrG=RKtY}7s6Jb7*W|9Qbx9uif-P#8DcW3tE;1I-xOke zvb8$OJ|ITfwpkP&J$h6yJxyq9YmNT?>z{BYG7=32?K9GV@w0a9j~8_~Bdz}6_~_h+ zBlPt2Qdc*V31;<|Cx5(9L~s3d>0(z;3v|H-+P48PCj_ zGeZgw&G)9T$`OKW*svj_@W3_06`!D*T*`_OUAuNI#ALu;^S!Cs+S+0J-c(kMsG*@D z#AGBIsQV1$)t8?flYR#-f8a%V?Yr5qmwIf0)?RC?z5axp3msn~kbwD&q4@s{%x6e1 zs+j*jqqn#B$N3C=H%S7P^W&}9ty{N-6h1d@+@MXHHi^Z+8>I^uE)@TN2Hw8He24@H ziEo2wZpQqZ2x3H1Fb|Q*WI{{^?6Wm2#Q47z%qS+GFSAqbZXh1{af10SPam76bDc(oYK|z+N+_@T-t>p*zEmH&bRH Z`WNSM#Mjm?Iw$}D002ovPDHLkV1kd%PR;-T delta 1769 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 Sv5EbE0GOFrq3V$CN&f<_R|ZM| literal 5581 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 delta 1821 zcmaKtX*Amj7sgF(QN|LIFq)FI#q`)ht3xeK1+hfOT9nqVmfBM?$bTB4W+JxEkW_3z z)leO^E3qVYLoH>frPffj*1oiFKELNZ@5g)2bMAT0eeV6;6VXBOG}w77kPsgqUp5>p zk&d_q2rZgp(Du>y*BNFHA#O5VcRXKL%Ew4bowUzDAXny11t3$a){zD3Vk%5gm`;-D z4Wx?2Z75nK>G`ir#jA~WXu&{9(S5L&=e3=iO-HS%i!mcw5i{Jgwj~4Ykjb+_gY|*y zo2w%w|IBL|6PHIk1eB9dwo;chG&J^n|K!90SR#>idc0>z{CY}1vJBOG{8@!crP2Yx z61TUHzqvlW4u+6ZqIVX5W9SoXm2l55<8U~-+E;Wk1*XwE-$60{ZI~4o(-5_pTkhIm z+ewv&efnWCgCj^d+$xAY*~k4(p%fPsAgVfya&AUtHpd+FroeA5o*Zn_TaJa%uL0Kv zCO7w|Fs3frb{i2X#2g(T7YY$ z>AgAA?6ddj{TrV?DBUowG4^l^QT1M-A4)vhG09YQMxGt-X)9Y@)lSr(Mt8Wku;Na7 zTc7abNdY4-a9V+5suL|hOB3--@7=a!!cKFCO-6kWQ<~=FY26-jvc2#$a%~Lv%kByS zrtX@CFiz|)w#+ID9Iw#w^c$0+tN^yu`cs@%ECR2;5X)KYos zXs*+L{&tD@MSUlD2p(S}1BHG?Bnq=Wu79Z8Io$RtEh`%#gqzww6^CoJ0NrX<&s90H z*B+*c!S(ECf2Ql<|B5|3zFt*>|7Gvfm8gxWbQ21+lpwDgUX+sS+CBx^=CtlI^zglP zvbV4X0i!B}FU!<&ml}(d3%blg)hx{`Nyf}C2E)IC3k2*fs)Zh;0WepXYt;tg#3C?XT^<}-EyChBr81q0EI^YsVn%$>8=^_?= zu#sbxt%JMY6kXse^`-l|6B2?B{g`~dcW(3r$l-&Fm_$E}i!>@NEgc#nJt)9l>? zc(4;o2Y-rKP9Dq40JG!UkqDGIw-LV<`3G3tuE;7IBZw9QvzSbzZrD6o@85iaDI@Kc zx?7|DIK>Lc)ptH~np9Fnp(W$XbBzZ3k#Z0MXO)-NeKXYq(q^ph9GIvL>*mJXO)^;Ml-4P)&u^KC?0X*33m3+nKze zgv!>9@LdUNC=S>J=I{?Cw=U6ab_%?@QdWl>UIK>d-FQEU07@rhMs=YpRifsUV%Vuyy?BdITBxZ_~mefwz$UXSnbn=@b*zp(h>{-4f* z1;(it4gR{(HD&xW&1kkRBrj-|Wia}+6=h*z;r*fZ5i8HJLjFs=-{3`RKB=9*)dd5P zJyH_<7xP1tr{6~P@$eC6gk{Bo?#Sl!jKHfa6)J&$&-_2jclLm1-e@3&9x-4>+_-NC zkBz7i!tk6`GC0LCjD-2s#?XLMN# z0Th)*hr^EV<#oE-;)RV9#$QPR=8_knQlKF$1Lgw<8-|xPL~sKxLzL46=Gy0L3mVQz zx!yaiyO17-rR}tS6Y0Opz(6@)-Cjx3|1W~*D-6r)90(?ff%l~ATNC$^C12_d|M~ugin8(Li z0p=E8__r|iM@fDRT~BtF;vebe=S0Hdb@tig3i Date: Thu, 8 Aug 2024 19:08:18 -0400 Subject: [PATCH 236/258] Updated number for cell case rule image --- .../skyscrapers/cases/NumberForCell.png | Bin 1875 -> 1603 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/src/main/resources/edu/rpi/legup/images/skyscrapers/cases/NumberForCell.png b/src/main/resources/edu/rpi/legup/images/skyscrapers/cases/NumberForCell.png index fedbbbac856e3f5cd1679977ceb0685336bba8ac..307d0d754ce4ec8aecdfda71936ecb67fec0c3a7 100644 GIT binary patch literal 1603 zcmb7^`!^E`0LRy9W+oZQP|8HvY?epdL++i~HS@?Lq~tN9mPaPC?ka_OMs8lo`?1tg z9+&beOj^ie@_yxUG4hDo^nYil8 z3NDVJfkUNe0li6&??biaP$>0bN@@$?js<3~f~N=znMh7G^-uZ6rk*|FcD08#A3WH( z{Cs6)MO%Ity7Crc1BG|~EMAoi6GKCb^z`)5;Na=m+EY3@4_#bbp0il--QC?emxbf? zHy;=p8C|1Nx$U~r((rQ6rjqGtlCi1j%^Tw(+usA}TN|25iHY3y_W0DLW8mDJ9Oj!h zhNnKFQ1z(l#N)q(bNT#A9>XPKiBF$cn_%wl-hHMq|45gitp0zX7)&P99*2ue7^mCD z4bITtdI-0(<$qwxB*7oDW4h>VQIfI?Upw3!yuH1((CDPmu`yOtQ$7R&anigEM0xz%j75pD8| zNAIgT#c&i60Sqi>qJiezB23&CuI=6MTY?>7RzQm+sX(w?Hd0&rLG1w<8iEtOz(OPE zcejO34i5Y=AIdM*x=8#d?1Rkg?BZv3`7b&k`^y{?rF!+OtgQzko^UuEZqGGpnm0Z! zBjUqT77O7=p_~q*#AGX+z^Uyw+MDk>Lf@DrQYQM#r!+J};c>%7zFwWpM$|q%11*BH zb9ykM5Ynqh?c2oPcvQ$Co2D*6DlsTHF51pQ6K_D#d?2NYu z%R-`F6%D^wnD5yLugBBXf<@MwzKxs_F>29%FfR?ONJu1)41ZD{WFBa@>6Q%Z90vdG>=;6u-Oq-CBA?LQDzfh2*))o%>R}J zUBP><2#M0QI$BC&>$EcMNn0tQ>Xj|`=t;h+j`#qS`=7vZnLm%KnLsu- WkIb#St||U~0D$=WIeZz;EAn4d&G7yJ delta 1825 zcmai#`9IT-1ILH3v*1TY^61bQna0;S7b1Ngq< zZyEeSeXx;k7e#cu+y!We?{)f3DY55&!IzRv&{nY`W>=`Qc-eWbdY4!751OcOEcFLm zGe=3HKAiu}q3e{ZJw-w-wzu!-@JP?@AmHSbF*@zGHPd}CvWhue@3qOS4ympFtVCrm z;$x_3pXERdy~;nvy1J9wP%br|5w@%iU4J zaHR2`c?7TYiuCu^Uk$;}OC8S#%-I7fOGRjrkA#R&gI|9bm@$h7$~w<^>MPaQFHNaXnQo%+|(FyY>ObI z{zXbru|xRz`B^$Rs63r%_Ol%Y2`nA9gmhp&OjLX2m%ZRSpZHq(rgFlQZ%jOq7>Ba0 zGA(szKya!i^k?2&J7n7c%Ncr@R3Z<*;G32HOr+4r!c0?8K4a-?&TaLOBdRWCG3w{W zq_)q!lb&lr1j&s4zE*734Dmt{a5LnHl;pQPZ>*%E@@L5LfybAGGIg)YP+Eqxo^L@T zb=z=5KjYMKb)1o(em%fq`Ev$xw9GMOx+!QS_pFAl5yq-G2r3C^5!_AC;@}Hf{_FPx z_u09GbRBa175#swAo?x~QNllGTt5w?MfdQ^2{n+$uw3bb`FDEz(ll~`)005gHUd}H zg6RQ9yY|U9%hNd~F>*Y7XQl;cDRyYM$MoO$Km(QS!!>YW>r&#{Po}<S1>J-Y%9!2Hc$sn zfZ$zK1qFq|)bd+yrXU`EvoI~{k6D%zi3uGvmG6p^%#Y}U(;?aA-doT~dzk0T1WDGu z1>DW^_m4TsY%5oscXmA1I?CmwRDe5vsW-(d(f01$+&mSt6+TMfW;!mk!gE+zLYMO1 z$KhXa_M-?vz_HndXhPiyw-58FlEXZ_sW()b6aiD z-sTr`E?pX?=hwz$zBJnGT`RMbLxi8R;SlzPm-kq?!AOanm>zhxesA*|5(b0O6N!AF zG<}BaPyv}9`p>w>lQrG1U`Rvgd(w??VH0hJ9Z<{2l0iqP5e-O|x1*=+`3yH4BCLJIY!K zP9Ij1tgcov19$Q`TV@iFk8)rR#X7&{Jp&$l817Sh)b7+0vvR|KJr!-?w>pFmxSq(e zA)(;G;F<}inv1CWLWPY9FMo*H)p*l4CTqPi3X6-2hey~B0Bq8QYpFdFYAgKdDp@dV zmB8TU>EN5+b%zOnU0o7!hW4YKfn)0hD}y@PuM|xw=#aK*ax-+ZzlG6s)p}vN)c7lD zO@_nS8xGgEDZy|4LL!l_pVM{eL>``bj_pkAl=tY^@2nEL+Ep`!z{sMy6^_H2ST`tc z$O{Vu|0elwOynZeV=3G+lAXJ}!EIP76EisOQs=M?pkA z&x#3oL{|9{nh{xO0bUkTcVDqLm2)U;Tx>Uw8Uo7te}RBslvXqLQ{A(gsfKW_5QI0j KxK(QC6!u@kxo!{u From e89393f42b7596966d2b05ef2f78487e3bac3591 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Thu, 8 Aug 2024 19:09:07 -0400 Subject: [PATCH 237/258] Fixed save file bug in puzzle editor that did not save most recent path selection --- src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java b/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java index c631990d0..c1d402d2d 100644 --- a/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java +++ b/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java @@ -471,7 +471,6 @@ public Object[] promptPuzzle() { fileBrowser.setAcceptAllFileFilterUsed(false); File puzzlePath = fileBrowser.getSelectedFile(); - System.out.println(puzzlePath.getAbsolutePath()); if (puzzlePath != null) { fileName = puzzlePath.getAbsolutePath(); @@ -641,7 +640,7 @@ private String savePuzzle() { folderBrowser.setAcceptAllFileFilterUsed(false); String path = folderBrowser.getSelectedFile().getAbsolutePath(); - + preferences.setSavedPath(path); if (path != null) { try { PuzzleExporter exporter = puzzle.getExporter(); From 5e7cef7ff895c3ba016d0189989d50a6c23809a4 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Thu, 8 Aug 2024 19:11:18 -0400 Subject: [PATCH 238/258] Added code specifications to all methods in all classes in app directory --- src/main/java/edu/rpi/legup/app/Config.java | 18 +++++++ .../edu/rpi/legup/app/GameBoardFacade.java | 48 +++++++++++++++++-- .../rpi/legup/app/InvalidConfigException.java | 8 ++++ .../edu/rpi/legup/app/LegupPreferences.java | 35 +++++++++++--- 4 files changed, 99 insertions(+), 10 deletions(-) diff --git a/src/main/java/edu/rpi/legup/app/Config.java b/src/main/java/edu/rpi/legup/app/Config.java index 8a8e9665d..95bc7db70 100644 --- a/src/main/java/edu/rpi/legup/app/Config.java +++ b/src/main/java/edu/rpi/legup/app/Config.java @@ -74,6 +74,13 @@ public static String convertClassNameToDisplayName(String className) { return displayName; } + /** + * Converts the display name of the puzzle back to its corresponding class name. + * For example: convertDisplayNameToClassName("Tree Tent") returns "TreeTent" + * + * @param displayName the display name of the puzzle + * @return the class name of the puzzle as a String + */ public static String convertDisplayNameToClassName(String displayName) { String className = ""; for (int i = 0; i < displayName.length(); i++) { @@ -84,6 +91,11 @@ public static String convertDisplayNameToClassName(String displayName) { return className; } + /** + * Gets a list of all available puzzle display names + * + * @return a List of puzzle display names as Strings + */ public List getPuzzleNames() { List names = new LinkedList(); for (String puzzle : this.getPuzzleClassNames()) { @@ -92,6 +104,12 @@ public List getPuzzleNames() { return names; } + /** + * Returns a list of the display names of the puzzles that can have files created and edited within + * the proof editor + * + * @return a List of puzzle display names as Strings with file creation enabled + */ public List getFileCreationEnabledPuzzleNames() { List names = new LinkedList(); for (String puzzle : this.getFileCreationEnabledPuzzles()) { diff --git a/src/main/java/edu/rpi/legup/app/GameBoardFacade.java b/src/main/java/edu/rpi/legup/app/GameBoardFacade.java index fbd11fd86..8faae7623 100644 --- a/src/main/java/edu/rpi/legup/app/GameBoardFacade.java +++ b/src/main/java/edu/rpi/legup/app/GameBoardFacade.java @@ -72,6 +72,9 @@ public static synchronized GameBoardFacade getInstance() { return instance; } + /** + * Initializes the UI components + */ public void initializeUI() { EventQueue.invokeLater( () -> { @@ -83,18 +86,29 @@ public void initializeUI() { }); } + /** + * Sets the current puzzle in the game board + * + * @param puzzle the Puzzle to set + */ public void setPuzzle(Puzzle puzzle) { this.puzzle = puzzle; this.puzzleSolver.setPuzzleView(puzzle); this.history.clear(); } + /** + * Clears the current puzzle + */ public void clearPuzzle() { this.puzzle = null; this.curFileName = null; this.history.clear(); } + /** + * Sets up the configuration by initializing the Config object + */ public static void setupConfig() { Config config = null; try { @@ -105,11 +119,21 @@ public static void setupConfig() { GameBoardFacade.getInstance().setConfig(config); } + /** + * Sets the current puzzle editor with the given puzzle + * + * @param puzzle the Puzzle to set in the editor + */ public void setPuzzleEditor(Puzzle puzzle) { this.puzzle = puzzle; this.puzzleEditor.setPuzzleView(puzzle); } + /** + * Sets the configuration object for the GameBoardFacade + * + * @param config config the Config object to set + */ public void setConfig(Config config) { this.config = config; } @@ -168,7 +192,7 @@ public boolean validateTextInput(String game, String[] statements) throws Runtim } /** - * Loads an empty puzzle + * Loads an empty puzzle with the specified dimensions * * @param game name of the puzzle * @param rows the number of rows on the board @@ -218,6 +242,12 @@ public void loadPuzzle(String game, int rows, int columns) throws RuntimeExcepti } + /** + * Loads an empty puzzle with the specified input + * + * @param game name of the puzzle + * @param statements an array of statements to load the puzzle with + */ public void loadPuzzle(String game, String[] statements) { String qualifiedClassName = config.getPuzzleClassForName(game); LOGGER.debug("Loading " + qualifiedClassName); @@ -260,10 +290,10 @@ public void loadPuzzle(String game, String[] statements) { } /** - * Loads a puzzle file + * Loads a puzzle file from the specified file * * @param fileName file name of the board file - * @throws InvalidFileFormatException if input is invalid + * @throws InvalidFileFormatException if the file format is invalid or if the file cannot be created */ public void loadPuzzle(String fileName) throws InvalidFileFormatException { try { @@ -276,6 +306,12 @@ public void loadPuzzle(String fileName) throws InvalidFileFormatException { } } + /** + * Loads a puzzle into the editor from the specified file name + * + * @param fileName the name of the file to load + * @throws InvalidFileFormatException if the file format is invalid or if the file cannot be created + */ public void loadPuzzleEditor(String fileName) throws InvalidFileFormatException { try { loadPuzzleEditor(new FileInputStream(fileName)); @@ -287,6 +323,12 @@ public void loadPuzzleEditor(String fileName) throws InvalidFileFormatException } } + /** + * Loads a puzzle into the editor from the specified input stream + * + * @param inputStream the input stream to load the puzzle from + * @throws InvalidFileFormatException if the input stream cannot be processed or the file format is invalid + */ public void loadPuzzleEditor(InputStream inputStream) throws InvalidFileFormatException { Document document; try { diff --git a/src/main/java/edu/rpi/legup/app/InvalidConfigException.java b/src/main/java/edu/rpi/legup/app/InvalidConfigException.java index a570e7d44..c273bed7c 100644 --- a/src/main/java/edu/rpi/legup/app/InvalidConfigException.java +++ b/src/main/java/edu/rpi/legup/app/InvalidConfigException.java @@ -1,6 +1,14 @@ package edu.rpi.legup.app; +/** + * Custom exception class for handling invalid configuration errors + */ public class InvalidConfigException extends Exception { + /** + * Constructs a new InvalidConfigException with the specified detail message + * + * @param message the detail message + */ public InvalidConfigException(String message) { super(message); } diff --git a/src/main/java/edu/rpi/legup/app/LegupPreferences.java b/src/main/java/edu/rpi/legup/app/LegupPreferences.java index 12433d7e4..26d874d83 100644 --- a/src/main/java/edu/rpi/legup/app/LegupPreferences.java +++ b/src/main/java/edu/rpi/legup/app/LegupPreferences.java @@ -73,9 +73,10 @@ public class LegupPreferences { } /** - * Gets the legup preferences singleton instance. + * Gets the legup preferences singleton instance + * This method ensures that only one instance of LegupPreferences exists * - * @return legup preferences + * @return the singleton instance of LegupPreferences */ public static LegupPreferences getInstance() { if (instance == null) { @@ -84,30 +85,40 @@ public static LegupPreferences getInstance() { return instance; } - /** Private LegupPreferences Singleton Constructor */ + /** + * Private constructor to prevent instantiation from outside the class + * Use {@link #getInstance()} to access the singleton instance + */ private LegupPreferences() {} /** * Gets the user preference by the string key * * @param key key name of the preference - * @return value of the preference + * @return value of the preference or {@code null} if the preference does not exist */ public String getUserPref(String key) { return preferencesMap.get(key); } /** - * Gets the user preference by the string key, value pair + * Sets the user preference for the specified key to the provided value * - * @param key key name of the preference - * @param value value of the preference + * @param key key to set for the preference + * @param value value to set for the preference */ public void setUserPref(String key, String value) { preferences.put(key, value); preferencesMap.put(key, value); } + /** + * Retrieves the user preference associated with the specified key as a boolean + * + * @param key the key for the preference to retrieve + * @return the boolean value of the preference + * @throws RuntimeException if the preference value cannot be interpreted as a boolean + */ public boolean getUserPrefAsBool(String key) { if (preferencesMap.get(key).equalsIgnoreCase(Boolean.toString(true))) { return true; @@ -120,10 +131,20 @@ public boolean getUserPrefAsBool(String key) { } } + /** + * Gets the saved path + * + * @return the saved path as a String + */ public String getSavedPath() { return SAVED_PATH; } + /** + * Sets the saved path to the specified value + * + * @param path the new saved path + */ public void setSavedPath(String path) { SAVED_PATH = path; } From fb5df3da172d3db7d8e5abea7312e585ffe745a6 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Thu, 8 Aug 2024 19:21:12 -0400 Subject: [PATCH 239/258] Added code specifications to the classes themselves in app directory --- src/main/java/edu/rpi/legup/app/Config.java | 5 +++++ src/main/java/edu/rpi/legup/app/GameBoardFacade.java | 4 ++++ src/main/java/edu/rpi/legup/app/InvalidConfigException.java | 2 +- src/main/java/edu/rpi/legup/app/LegupPreferences.java | 4 ++++ 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/main/java/edu/rpi/legup/app/Config.java b/src/main/java/edu/rpi/legup/app/Config.java index 95bc7db70..1016838c7 100644 --- a/src/main/java/edu/rpi/legup/app/Config.java +++ b/src/main/java/edu/rpi/legup/app/Config.java @@ -12,6 +12,11 @@ import org.w3c.dom.NodeList; import org.xml.sax.SAXException; +/** + * The {@code Config} class manages the configuration for puzzles by loading configuration data + * from an XML file. It provides methods to access puzzle class names, display names, and their + * file creation statuses + */ public class Config { private static final Logger Logger = LogManager.getLogger(Config.class.getName()); diff --git a/src/main/java/edu/rpi/legup/app/GameBoardFacade.java b/src/main/java/edu/rpi/legup/app/GameBoardFacade.java index 8faae7623..835041c3c 100644 --- a/src/main/java/edu/rpi/legup/app/GameBoardFacade.java +++ b/src/main/java/edu/rpi/legup/app/GameBoardFacade.java @@ -31,6 +31,10 @@ import org.w3c.dom.Node; import org.xml.sax.SAXException; +/** + * {@code GameBoardFacade} is a class designed to manage the game board operations within the application. + * It integrates various components such as UI elements, puzzle management, and history tracking + */ public class GameBoardFacade implements IHistorySubject { private static final Logger LOGGER = LogManager.getLogger(GameBoardFacade.class.getName()); diff --git a/src/main/java/edu/rpi/legup/app/InvalidConfigException.java b/src/main/java/edu/rpi/legup/app/InvalidConfigException.java index c273bed7c..c66b23ec2 100644 --- a/src/main/java/edu/rpi/legup/app/InvalidConfigException.java +++ b/src/main/java/edu/rpi/legup/app/InvalidConfigException.java @@ -1,7 +1,7 @@ package edu.rpi.legup.app; /** - * Custom exception class for handling invalid configuration errors + * {@code InvalidConfigException} is a custom exception class for handling invalid configuration errors */ public class InvalidConfigException extends Exception { /** diff --git a/src/main/java/edu/rpi/legup/app/LegupPreferences.java b/src/main/java/edu/rpi/legup/app/LegupPreferences.java index 26d874d83..03b8be8d9 100644 --- a/src/main/java/edu/rpi/legup/app/LegupPreferences.java +++ b/src/main/java/edu/rpi/legup/app/LegupPreferences.java @@ -4,6 +4,10 @@ import java.util.Map; import java.util.prefs.Preferences; +/** + * {@code LegupPreferences} is a class responsible for managing user preferences within the application. + * It uses Java's Preferences API to store and retrieve preferences, and it provides methods for accessing and updating these preferences. + */ public class LegupPreferences { private static LegupPreferences instance; From 8180f7ce835804110d21ccf23307a7a7e3b771b2 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Fri, 9 Aug 2024 12:04:30 -0400 Subject: [PATCH 240/258] Added code specifications to all missing methods and class descriptions in all classes in controller directory --- .../edu/rpi/legup/controller/Controller.java | 9 +++++++++ .../legup/controller/CursorController.java | 4 ++++ .../controller/EditorElementController.java | 20 ++++++++++++++++++- .../legup/controller/ElementController.java | 16 +++++---------- .../rpi/legup/controller/RuleController.java | 5 +++++ .../rpi/legup/controller/TreeController.java | 4 ++++ 6 files changed, 46 insertions(+), 12 deletions(-) diff --git a/src/main/java/edu/rpi/legup/controller/Controller.java b/src/main/java/edu/rpi/legup/controller/Controller.java index 57ce107ac..47ef70e17 100644 --- a/src/main/java/edu/rpi/legup/controller/Controller.java +++ b/src/main/java/edu/rpi/legup/controller/Controller.java @@ -5,6 +5,10 @@ import java.awt.event.*; import javax.swing.*; +/** + * {@code Controller} is an abstract class designed to handle various mouse events and provide control functionality for a {@code ScrollView}. + * It implements several mouse event interfaces to manage interactions such as panning and zooming within a {@code ScrollView} + */ public abstract class Controller implements MouseMotionListener, MouseListener, MouseWheelListener { protected ScrollView viewer; private int x, y; @@ -19,6 +23,11 @@ public Controller() { pan = false; } + /** + * Sets the ScrollView instance that this controller manages + * + * @param viewer The ScrollView instance to be set + */ public void setViewer(ScrollView viewer) { this.viewer = viewer; } diff --git a/src/main/java/edu/rpi/legup/controller/CursorController.java b/src/main/java/edu/rpi/legup/controller/CursorController.java index 2706bd522..6a3ab018d 100644 --- a/src/main/java/edu/rpi/legup/controller/CursorController.java +++ b/src/main/java/edu/rpi/legup/controller/CursorController.java @@ -6,6 +6,10 @@ import java.util.Timer; import java.util.TimerTask; +/** + * {@code CursorController} provides functionality for managing the cursor appearance during actions that take a certain amount of time. + * It allows for the display of a busy cursor while an action is being processed and reverts to the default cursor afterward + */ public class CursorController { public static final Cursor BUSY_CURSOR = new Cursor(Cursor.WAIT_CURSOR); public static final Cursor DEFAULT_CURSOR = new Cursor(Cursor.DEFAULT_CURSOR); diff --git a/src/main/java/edu/rpi/legup/controller/EditorElementController.java b/src/main/java/edu/rpi/legup/controller/EditorElementController.java index 5a23885af..040610137 100644 --- a/src/main/java/edu/rpi/legup/controller/EditorElementController.java +++ b/src/main/java/edu/rpi/legup/controller/EditorElementController.java @@ -9,6 +9,10 @@ import java.awt.event.ActionListener; import javax.swing.*; +/** + * {@code EditorElementController} manages actions related to UI elements within the puzzle editor environment. + * It handles button presses, updates element selection, and manages visual states of buttons + */ public class EditorElementController implements ActionListener { protected Object lastSource; protected ElementController elementController; @@ -20,19 +24,33 @@ public EditorElementController() { prevButton = null; } + /** + * Sets the ElementController instance for this controller + * + * @param elementController the ElementController instance to be set + */ public void setElementController(ElementController elementController) { this.elementController = elementController; } + /** + * Handles the event when a button associated with an Element is pressed + * + * @param element the Element associated with the button that was pressed + */ public void buttonPressed(Element element) { // TODO: implement what happens when element is pressed - System.out.printf("%s button pressed!\n", element.getElementName()); if (elementController != null) { elementController.setSelectedElement(element); } } + /** + * Handles action events triggered by buttons + * + * @param e the event to be processed + */ @Override public void actionPerformed(ActionEvent e) { lastSource = e.getSource(); diff --git a/src/main/java/edu/rpi/legup/controller/ElementController.java b/src/main/java/edu/rpi/legup/controller/ElementController.java index 8b361f123..436b078b9 100644 --- a/src/main/java/edu/rpi/legup/controller/ElementController.java +++ b/src/main/java/edu/rpi/legup/controller/ElementController.java @@ -26,13 +26,17 @@ import java.awt.*; import java.awt.event.*; +/** + * The ElementController class manages UI interactions related to elements in a {@link BoardView}. + * It handles mouse events, key events, and actions related to element selection and manipulation + */ public class ElementController implements MouseListener, MouseMotionListener, ActionListener, KeyListener { protected BoardView boardView; private Element selectedElement; /** - * ElementController Constructor controller to handles ui events associated interacting with a + * ElementController Constructor controller to handle ui events associated interacting with a * {@link BoardView} */ public ElementController() { @@ -139,17 +143,7 @@ public void mouseReleased(MouseEvent e) { scaledPoint.setLocation(scaledPoint.getX() - 1, scaledPoint.getY() - 1); } - System.out.printf( - "selected Element is NOT null, attempting to change board at (%d, %d)\n", - scaledPoint.x, scaledPoint.y); - // System.out.println("Before: " + b.getCell(scaledPoint.x, - // scaledPoint.y).getData()); b.setCell(scaledPoint.x, scaledPoint.y, this.selectedElement, e); - // System.out.println("After: " + b.getCell(scaledPoint.x, - // scaledPoint.y).getData()); - // } else { - // System.out.println("selected Element is null!"); - // } boardView.repaint(); } diff --git a/src/main/java/edu/rpi/legup/controller/RuleController.java b/src/main/java/edu/rpi/legup/controller/RuleController.java index 6e88dc4be..491e02f74 100644 --- a/src/main/java/edu/rpi/legup/controller/RuleController.java +++ b/src/main/java/edu/rpi/legup/controller/RuleController.java @@ -16,6 +16,11 @@ import java.awt.event.ActionListener; import java.util.List; +/** + * The RuleController class is responsible for handling UI events related to rule buttons + * in the RulePanel of the Legup application. It implements ActionListener to process action + * events triggered by rule buttons and applies rules to the puzzle accordingly + */ public class RuleController implements ActionListener { protected Object lastSource; diff --git a/src/main/java/edu/rpi/legup/controller/TreeController.java b/src/main/java/edu/rpi/legup/controller/TreeController.java index 80fdee1af..2b12268ac 100644 --- a/src/main/java/edu/rpi/legup/controller/TreeController.java +++ b/src/main/java/edu/rpi/legup/controller/TreeController.java @@ -11,6 +11,10 @@ import java.awt.event.MouseWheelEvent; import javax.swing.*; +/** + * The TreeController class handles UI events from a TreePanel. + * It extends the Controller class to provide specific behavior for tree interactions + */ public class TreeController extends Controller { /** * TreeController Constructor creates a controller object to listen to ui events from a {@link From 760b493a7109ef9ee531cc7b94092f14b905cae2 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Fri, 9 Aug 2024 13:47:55 -0400 Subject: [PATCH 241/258] Added code specifications to all missing methods and class descriptions in all classes in history directory --- .../legup/history/AddTreeElementCommand.java | 15 ++++- .../ApplyDefaultDirectRuleCommand.java | 15 ++++- .../legup/history/AutoCaseRuleCommand.java | 15 ++++- .../edu/rpi/legup/history/CommandError.java | 15 +++++ .../edu/rpi/legup/history/CommandState.java | 14 ++++ .../history/DeleteTreeElementCommand.java | 16 +++-- .../rpi/legup/history/EditDataCommand.java | 17 ++++- .../java/edu/rpi/legup/history/History.java | 23 +++++-- .../java/edu/rpi/legup/history/ICommand.java | 16 ++++- .../rpi/legup/history/IHistoryListener.java | 18 +++-- .../rpi/legup/history/IHistorySubject.java | 18 +++-- .../InvalidCommandStateTransition.java | 11 ++++ .../edu/rpi/legup/history/MergeCommand.java | 12 +++- .../edu/rpi/legup/history/PuzzleCommand.java | 39 ++++++++--- .../history/ValidateCaseRuleCommand.java | 13 +++- .../ValidateContradictionRuleCommand.java | 12 +++- .../history/ValidateDirectRuleCommand.java | 65 +++---------------- 17 files changed, 231 insertions(+), 103 deletions(-) diff --git a/src/main/java/edu/rpi/legup/history/AddTreeElementCommand.java b/src/main/java/edu/rpi/legup/history/AddTreeElementCommand.java index 12b39cd85..92a887f71 100644 --- a/src/main/java/edu/rpi/legup/history/AddTreeElementCommand.java +++ b/src/main/java/edu/rpi/legup/history/AddTreeElementCommand.java @@ -10,6 +10,11 @@ import java.util.List; import java.util.Map; + +/** + * The AddTreeElementCommand class represents a command to add tree elements to the proof tree. + * It extends the PuzzleCommand class to handle the addition of tree elements and undo operation. + */ public class AddTreeElementCommand extends PuzzleCommand { private TreeViewSelection selection; @@ -27,7 +32,10 @@ public AddTreeElementCommand(TreeViewSelection selection) { this.addChild = new HashMap<>(); } - /** Executes an command */ + /** + * Executes the command to add selected tree elements to the tree. + * Updates the puzzle and tree view accordingly + */ @Override public void executeCommand() { Tree tree = GameBoardFacade.getInstance().getTree(); @@ -95,7 +103,10 @@ public String getErrorString() { return null; } - /** Undoes an command */ + /** + * Undoes the command by removing the added tree elements. + * Updates the puzzle and tree view accordingly + */ @Override public void undoCommand() { Tree tree = GameBoardFacade.getInstance().getTree(); diff --git a/src/main/java/edu/rpi/legup/history/ApplyDefaultDirectRuleCommand.java b/src/main/java/edu/rpi/legup/history/ApplyDefaultDirectRuleCommand.java index 02dffae44..ad89ab636 100644 --- a/src/main/java/edu/rpi/legup/history/ApplyDefaultDirectRuleCommand.java +++ b/src/main/java/edu/rpi/legup/history/ApplyDefaultDirectRuleCommand.java @@ -10,6 +10,11 @@ import java.util.List; import java.util.Map; +/** + * The ApplyDefaultDirectRuleCommand class represents a command to apply a default direct rule + * to selected tree nodes in the proof tree. + * It extends the PuzzleCommand class to handle rule application and undo operation. + */ public class ApplyDefaultDirectRuleCommand extends PuzzleCommand { private TreeViewSelection selection; @@ -69,7 +74,10 @@ public String getErrorString() { return null; } - /** Executes an command */ + /** + * Executes the command to apply the default rule to the selected tree nodes. + * Updates the puzzle and tree view accordingly. + */ @Override public void executeCommand() { Tree tree = GameBoardFacade.getInstance().getTree(); @@ -109,7 +117,10 @@ public void executeCommand() { puzzle.notifyTreeListeners(listener -> listener.onTreeSelectionChanged(newSelection)); } - /** Undoes an command */ + /** + * Undoes the command by removing the applied default rule from the tree nodes. + * Updates the puzzle and tree view accordingly. + */ @Override public void undoCommand() { Puzzle puzzle = GameBoardFacade.getInstance().getPuzzleModule(); diff --git a/src/main/java/edu/rpi/legup/history/AutoCaseRuleCommand.java b/src/main/java/edu/rpi/legup/history/AutoCaseRuleCommand.java index 6eccc80ec..b86cda6ea 100644 --- a/src/main/java/edu/rpi/legup/history/AutoCaseRuleCommand.java +++ b/src/main/java/edu/rpi/legup/history/AutoCaseRuleCommand.java @@ -13,6 +13,11 @@ import java.awt.event.MouseEvent; import java.util.*; +/** + * The AutoCaseRuleCommand class represents a command to automatically apply a case rule to a + * selected tree node in the proof tree. + * It extends the PuzzleCommand class to handle case rule application and undo operation. + */ public class AutoCaseRuleCommand extends PuzzleCommand { private ElementView elementView; @@ -46,7 +51,10 @@ public AutoCaseRuleCommand( this.caseTrans = new ArrayList<>(); } - /** Executes an command */ + /** + * Executes the command to apply the case rule to the selected tree node. + * Updates the puzzle and tree view accordingly. + */ @Override public void executeCommand() { Tree tree = getInstance().getTree(); @@ -126,7 +134,10 @@ public String getErrorString() { return null; } - /** Undoes an command */ + /** + * Undoes the command by removing the applied case rules from the tree node. + * Updates the puzzle and tree view accordingly + */ @Override public void undoCommand() { Puzzle puzzle = GameBoardFacade.getInstance().getPuzzleModule(); diff --git a/src/main/java/edu/rpi/legup/history/CommandError.java b/src/main/java/edu/rpi/legup/history/CommandError.java index 093143704..26959cccd 100644 --- a/src/main/java/edu/rpi/legup/history/CommandError.java +++ b/src/main/java/edu/rpi/legup/history/CommandError.java @@ -1,5 +1,10 @@ package edu.rpi.legup.history; +/** + * The CommandError enum represents various error conditions that can occur when executing or + * validating commands related to tree elements in the proof tree. + * Each error condition is associated with a descriptive message. + */ public enum CommandError { NO_SELECTED_VIEWS("The selection does not have any tree elements."), ONE_SELECTED_VIEW("The selection must have exactly one tree element."), @@ -19,10 +24,20 @@ public enum CommandError { private String value; + /** + * Constructs a CommandError with the specified error message + * + * @param value The error message associated with the command error + */ CommandError(String value) { this.value = value; } + /** + * Returns the error message associated with this CommandError + * + * @return The error message + */ @Override public String toString() { return value; diff --git a/src/main/java/edu/rpi/legup/history/CommandState.java b/src/main/java/edu/rpi/legup/history/CommandState.java index f47c0405d..326490e28 100644 --- a/src/main/java/edu/rpi/legup/history/CommandState.java +++ b/src/main/java/edu/rpi/legup/history/CommandState.java @@ -1,5 +1,9 @@ package edu.rpi.legup.history; +/** + * The CommandState enum represents the various states that a command can be in during its lifecycle. + * Each state is associated with a descriptive name. + */ public enum CommandState { CREATED("Created"), EXECUTED("Executed"), @@ -8,10 +12,20 @@ public enum CommandState { private String value; + /** + * Constructs a CommandState with the specified state name + * + * @param value The name associated with the command state + */ CommandState(String value) { this.value = value; } + /** + * Returns the name associated with this CommandState + * + * @return The state name + */ @Override public String toString() { return value; diff --git a/src/main/java/edu/rpi/legup/history/DeleteTreeElementCommand.java b/src/main/java/edu/rpi/legup/history/DeleteTreeElementCommand.java index ece424e7e..e82197898 100644 --- a/src/main/java/edu/rpi/legup/history/DeleteTreeElementCommand.java +++ b/src/main/java/edu/rpi/legup/history/DeleteTreeElementCommand.java @@ -7,6 +7,11 @@ import edu.rpi.legup.ui.proofeditorui.treeview.*; import java.util.List; +/** + * The DeleteTreeElementCommand class represents a command to delete tree elements from a proof tree. + * It extends PuzzleCommand and implements the functionality to remove selected tree elements and + * handle undo operations. + */ public class DeleteTreeElementCommand extends PuzzleCommand { private TreeViewSelection selection; @@ -20,7 +25,9 @@ public DeleteTreeElementCommand(TreeViewSelection selection) { this.selection = selection.copy(); } - /** Executes a command */ + /** + * Executes the delete command, removing the selected tree elements from the tree. + */ @Override public void executeCommand() { Tree tree = GameBoardFacade.getInstance().getTree(); @@ -77,23 +84,22 @@ public String getErrorString() { return null; } - /** Undoes a command */ + /** + * Undoes the delete command, re-adding the previously deleted tree elements. + */ @Override public void undoCommand() { - System.out.println("UNDOED"); Puzzle puzzle = GameBoardFacade.getInstance().getPuzzleModule(); List selectedViews = selection.getSelectedViews(); for (TreeElementView selectedView : selectedViews) { TreeElement element = selectedView.getTreeElement(); if (element.getType() == TreeElementType.NODE) { - System.out.println("ADDING A NODE"); TreeNode node = (TreeNode) element; node.getParent().setChildNode(node); puzzle.notifyTreeListeners(listener -> listener.onTreeElementAdded(node)); } else { - System.out.println("ADDING A TRANSITION"); TreeTransition transition = (TreeTransition) element; transition.getParents().forEach(node -> node.addChild(transition)); transition.getParents().get(0).getChildren().forEach(TreeTransition::reverify); diff --git a/src/main/java/edu/rpi/legup/history/EditDataCommand.java b/src/main/java/edu/rpi/legup/history/EditDataCommand.java index 511cd803f..a629aa085 100644 --- a/src/main/java/edu/rpi/legup/history/EditDataCommand.java +++ b/src/main/java/edu/rpi/legup/history/EditDataCommand.java @@ -17,6 +17,11 @@ import java.awt.event.MouseEvent; import java.util.List; +/** + * The EditDataCommand class represents a command to edit the data of a puzzle element within + * a tree transition. It extends PuzzleCommand and provides functionality to execute and undo + * changes made to puzzle elements. + */ public class EditDataCommand extends PuzzleCommand { private TreeTransition transition; private PuzzleElement savePuzzleElement; @@ -42,7 +47,9 @@ public EditDataCommand(ElementView elementView, TreeViewSelection selection, Mou this.transition = null; } - /** Executes a command */ + /** + * Executes the edit data command, modifying the puzzle element and propagating changes + */ @SuppressWarnings("unchecked") @Override public void executeCommand() { @@ -135,7 +142,9 @@ public String getErrorString() { return null; } - /** Causes the TreeView background to flash red for a short duration. */ + /** + * Causes the TreeView background to flash red for a short duration when an error occurs. + */ private void flashTreeViewRed() { TreeView treeView = getInstance().getLegupUI().getTreePanel().getTreeView(); Color originalColor = treeView.getBackground(); @@ -145,7 +154,9 @@ private void flashTreeViewRed() { timer.start(); } - /** Undoes a command */ + /** + * Undoes the edit data command, restoring the previous state of the puzzle element. + */ @SuppressWarnings("unchecked") @Override public void undoCommand() { diff --git a/src/main/java/edu/rpi/legup/history/History.java b/src/main/java/edu/rpi/legup/history/History.java index dca6af3f3..b244e8f88 100644 --- a/src/main/java/edu/rpi/legup/history/History.java +++ b/src/main/java/edu/rpi/legup/history/History.java @@ -6,6 +6,10 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +/** + * The History class manages a stack of commands for undo and redo operations on the board and tree structure. + * It maintains a list of commands and a current index to track the position in the history stack. + */ public class History { private static final Logger LOGGER = LogManager.getLogger(History.class.getName()); @@ -14,9 +18,8 @@ public class History { private int curIndex; /** - * History Constructor this holds information about changes to the board and Tree structure for - * undoing and redoing operations. Though history is an List, it is implemented like a stack. - * The curIndex points to the top of the stack (where the last change was made). + * Constructs a History object to keep track of changes and allow undo and redo operations. + * The history is implemented as a stack, with curIndex pointing to the top of the stack. */ public History() { history = new ArrayList<>(); @@ -44,7 +47,10 @@ public void pushChange(ICommand command) { } } - /** Undoes an action */ + /** + * Undoes the last action by calling the undo method of the command at the current index. + * Updates the current index and notifies listeners. + */ public void undo() { synchronized (lock) { if (curIndex > -1) { @@ -60,7 +66,10 @@ public void undo() { } } - /** Redoes an action */ + /** + * Redoes the next action by calling the redo method of the command at the current index. + * Updates the current index and notifies listeners. + */ public void redo() { synchronized (lock) { if (curIndex < history.size() - 1) { @@ -74,7 +83,9 @@ public void redo() { } } - /** Clears all actions from the history stack */ + /** + * Clears all actions from the history stack and resets the current index + */ public void clear() { history.clear(); curIndex = -1; diff --git a/src/main/java/edu/rpi/legup/history/ICommand.java b/src/main/java/edu/rpi/legup/history/ICommand.java index 913d9daaf..4f867dbab 100644 --- a/src/main/java/edu/rpi/legup/history/ICommand.java +++ b/src/main/java/edu/rpi/legup/history/ICommand.java @@ -1,7 +1,13 @@ package edu.rpi.legup.history; +/** + * The ICommand interface defines the structure for command objects in a command pattern. + * It provides methods to execute, undo, redo commands, and to check if a command can be executed. + */ public interface ICommand { - /** Executes a command */ + /** + * Executes the command. The specific behavior depends on the implementation + */ void execute(); /** @@ -19,9 +25,13 @@ public interface ICommand { */ String getError(); - /** Undoes a command */ + /** + * Undoes the command. Reverts the changes made by the execute method + */ void undo(); - /** Redoes a command */ + /** + * Redoes the command. Re-applies the changes made by the execute method after undoing + */ void redo(); } diff --git a/src/main/java/edu/rpi/legup/history/IHistoryListener.java b/src/main/java/edu/rpi/legup/history/IHistoryListener.java index f464941d6..48690168d 100644 --- a/src/main/java/edu/rpi/legup/history/IHistoryListener.java +++ b/src/main/java/edu/rpi/legup/history/IHistoryListener.java @@ -1,15 +1,21 @@ package edu.rpi.legup.history; +/** + * The IHistoryListener interface defines methods for listening to changes in the history of commands. + * Implementations of this interface can respond to events related to command history such as pushing, + * undoing, redoing commands, and clearing the history. + */ public interface IHistoryListener { + /** - * Called when a action is pushed onto the edu.rpi.legup.history stack + * Called when a command is pushed onto the history stack. * - * @param command action to push onto the stack + * @param command the command that was pushed onto the stack */ void onPushChange(ICommand command); /** - * Called when an action is undone + * Called when a command is undone. * * @param isBottom true if there are no more actions to undo, false otherwise * @param isTop true if there are no more changes to redo, false otherwise @@ -17,13 +23,15 @@ public interface IHistoryListener { void onUndo(boolean isBottom, boolean isTop); /** - * Called when an action is redone + * Called when a command is redone. * * @param isBottom true if there are no more actions to undo, false otherwise * @param isTop true if there are no more changes to redo, false otherwise */ void onRedo(boolean isBottom, boolean isTop); - /** Called when the edu.rpi.legup.history is cleared */ + /** + * Called when the history stack is cleared. + */ void onClearHistory(); } diff --git a/src/main/java/edu/rpi/legup/history/IHistorySubject.java b/src/main/java/edu/rpi/legup/history/IHistorySubject.java index 78fefff00..431adbb93 100644 --- a/src/main/java/edu/rpi/legup/history/IHistorySubject.java +++ b/src/main/java/edu/rpi/legup/history/IHistorySubject.java @@ -2,25 +2,31 @@ import java.util.function.Consumer; +/** + * The IHistorySubject interface defines methods for managing and notifying listeners + * about changes in the command history. Implementations of this interface can add, remove, + * and notify history listeners. + */ public interface IHistorySubject { + /** - * Adds a history listener + * Adds a history listener to receive updates about changes in the command history. * - * @param listener listener to add + * @param listener the listener to add */ void addHistoryListener(IHistoryListener listener); /** - * Removes a history listener + * Removes a history listener, so it no longer receives updates about changes in the command history. * - * @param listener listener to remove + * @param listener the listener to remove */ void removeHistoryListener(IHistoryListener listener); /** - * Notifies listeners + * Notifies all registered listeners about a change in the command history. * - * @param algorithm algorithm to notify the listeners with + * @param algorithm a Consumer function that takes an IHistoryListener and performs some action with it */ void notifyHistoryListeners(Consumer algorithm); } diff --git a/src/main/java/edu/rpi/legup/history/InvalidCommandStateTransition.java b/src/main/java/edu/rpi/legup/history/InvalidCommandStateTransition.java index 71d072328..201babb9e 100644 --- a/src/main/java/edu/rpi/legup/history/InvalidCommandStateTransition.java +++ b/src/main/java/edu/rpi/legup/history/InvalidCommandStateTransition.java @@ -1,7 +1,18 @@ package edu.rpi.legup.history; +/** + * The InvalidCommandStateTransition exception is thrown when an invalid state transition + * is attempted on a PuzzleCommand + */ public class InvalidCommandStateTransition extends RuntimeException { + /** + * Constructs a new InvalidCommandStateTransition exception with a detailed message + * + * @param puzzleCommand the PuzzleCommand involved in the invalid transition + * @param from the state from which the transition was attempted + * @param to the state to which the transition was attempted + */ public InvalidCommandStateTransition( PuzzleCommand puzzleCommand, CommandState from, CommandState to) { super( diff --git a/src/main/java/edu/rpi/legup/history/MergeCommand.java b/src/main/java/edu/rpi/legup/history/MergeCommand.java index d7a7f97f1..c2851bced 100644 --- a/src/main/java/edu/rpi/legup/history/MergeCommand.java +++ b/src/main/java/edu/rpi/legup/history/MergeCommand.java @@ -10,6 +10,10 @@ import java.util.List; import java.util.Set; +/** + * The MergeCommand class represents a command to merge selected tree nodes into a single node + * and create a transition to represent the merge + */ public class MergeCommand extends PuzzleCommand { private TreeViewSelection selection; private TreeTransition transition; @@ -24,7 +28,9 @@ public MergeCommand(TreeViewSelection selection) { this.transition = null; } - /** Executes a command */ + /** + * Executes the merge command + */ @Override public void executeCommand() { List selectedViews = selection.getSelectedViews(); @@ -71,7 +77,9 @@ public void executeCommand() { puzzle.notifyTreeListeners(listener -> listener.onTreeSelectionChanged(newSelection)); } - /** Undoes an command */ + /** + * Undoes the merge command + */ @Override public void undoCommand() { Tree tree = GameBoardFacade.getInstance().getTree(); diff --git a/src/main/java/edu/rpi/legup/history/PuzzleCommand.java b/src/main/java/edu/rpi/legup/history/PuzzleCommand.java index fb57e7af2..d4385b3e8 100644 --- a/src/main/java/edu/rpi/legup/history/PuzzleCommand.java +++ b/src/main/java/edu/rpi/legup/history/PuzzleCommand.java @@ -1,18 +1,27 @@ package edu.rpi.legup.history; +/** + * The PuzzleCommand class is an abstract base class for commands that can be executed, undone, and redone + * within the puzzle model. It implements the ICommand interface and maintains the state and error handling + * for the command. + */ public abstract class PuzzleCommand implements ICommand { private CommandState state; private boolean isCached; private String cachedError; - /** Puzzle Command Constructor for creating an undoable and redoable change to the model. */ + /** + * Puzzle Command Constructor for creating an undoable and redoable change to the model + */ protected PuzzleCommand() { this.state = CommandState.CREATED; this.isCached = false; this.cachedError = null; } - /** Executes an command */ + /** + * Executes the command if it can be executed + */ @Override public final void execute() { if (canExecute()) { @@ -21,7 +30,9 @@ public final void execute() { } } - /** Determines whether this command can be executed */ + /** + * Determines whether the command can be executed by checking the error state + */ @Override public final boolean canExecute() { cachedError = getError(); @@ -52,13 +63,21 @@ public final String getError() { */ public abstract String getErrorString(); - /** Executes a command */ + /** + * Executes the command. + * This method must be implemented by subclasses to define the command's execution behavior. + */ public abstract void executeCommand(); - /** Undoes a command */ + /** + * Undoes the command. + * This method must be implemented by subclasses to define the command's undo behavior. + */ public abstract void undoCommand(); - /** Redoes a command */ + /** + * Redoes the command. This method is called if the command was previously undone. + */ public void redoCommand() { if (state == CommandState.UNDOED) { executeCommand(); @@ -68,7 +87,9 @@ public void redoCommand() { } } - /** Undoes a command */ + /** + * Undoes the command if it was executed or redone + */ @Override public final void undo() { if (state == CommandState.EXECUTED || state == CommandState.REDOED) { @@ -79,7 +100,9 @@ public final void undo() { } } - /** Redoes a command */ + /** + * Redoes the command if it was previously undone. + */ public final void redo() { if (state == CommandState.UNDOED) { redoCommand(); diff --git a/src/main/java/edu/rpi/legup/history/ValidateCaseRuleCommand.java b/src/main/java/edu/rpi/legup/history/ValidateCaseRuleCommand.java index 7737ecfd3..6827436e8 100644 --- a/src/main/java/edu/rpi/legup/history/ValidateCaseRuleCommand.java +++ b/src/main/java/edu/rpi/legup/history/ValidateCaseRuleCommand.java @@ -12,6 +12,10 @@ import java.util.List; import java.util.Map; +/** + * The ValidateCaseRuleCommand class represents a command for validating a CaseRule in the tree structure. + * It extends the PuzzleCommand class and implements the ICommand interface. + */ public class ValidateCaseRuleCommand extends PuzzleCommand { private TreeViewSelection selection; @@ -33,7 +37,9 @@ public ValidateCaseRuleCommand(TreeViewSelection selection, CaseRule caseRule) { this.addNode = new HashMap<>(); } - /** Executes an command */ + /** + * Executes the command to validate the CaseRule + */ @Override public void executeCommand() { Tree tree = getInstance().getTree(); @@ -105,7 +111,10 @@ public String getErrorString() { return null; } - /** Undoes an command */ + + /** + * Undoes the validation command, restoring the previous state + */ @Override public void undoCommand() { Puzzle puzzle = GameBoardFacade.getInstance().getPuzzleModule(); diff --git a/src/main/java/edu/rpi/legup/history/ValidateContradictionRuleCommand.java b/src/main/java/edu/rpi/legup/history/ValidateContradictionRuleCommand.java index 6c95202c9..b106a6072 100644 --- a/src/main/java/edu/rpi/legup/history/ValidateContradictionRuleCommand.java +++ b/src/main/java/edu/rpi/legup/history/ValidateContradictionRuleCommand.java @@ -10,6 +10,10 @@ import java.util.List; import java.util.Map; +/** + * The ValidateContradictionRuleCommand class represents a command for validating and applying a ContradictionRule + * within a tree structure. It extends the PuzzleCommand class and implements the ICommand interface. + */ public class ValidateContradictionRuleCommand extends PuzzleCommand { private TreeViewSelection selection; @@ -31,7 +35,9 @@ public ValidateContradictionRuleCommand(TreeViewSelection selection, Contradicti this.addTran = new HashMap<>(); } - /** Executes a command */ + /** + * Executes the command to validate and apply the ContradictionRule. + */ @Override public void executeCommand() { Tree tree = GameBoardFacade.getInstance().getTree(); @@ -130,7 +136,9 @@ public String getErrorString() { return null; } - /** Undoes a command */ + /** + * Undoes the validation command, restoring the previous state. + */ @Override public void undoCommand() { Puzzle puzzle = GameBoardFacade.getInstance().getPuzzleModule(); diff --git a/src/main/java/edu/rpi/legup/history/ValidateDirectRuleCommand.java b/src/main/java/edu/rpi/legup/history/ValidateDirectRuleCommand.java index c5a36ddb3..f7694cc0a 100644 --- a/src/main/java/edu/rpi/legup/history/ValidateDirectRuleCommand.java +++ b/src/main/java/edu/rpi/legup/history/ValidateDirectRuleCommand.java @@ -13,6 +13,10 @@ import java.util.List; import java.util.Map; +/** + * The ValidateDirectRuleCommand class represents a command for validating and applying a DirectRule + * to a set of selected tree elements. It extends the PuzzleCommand class and implements the ICommand interface. + */ public class ValidateDirectRuleCommand extends PuzzleCommand { private static final Logger LOGGER = LogManager.getLogger(History.class.getName()); private TreeViewSelection selection; @@ -34,60 +38,9 @@ public ValidateDirectRuleCommand(TreeViewSelection selection, DirectRule rule) { this.addNode = new HashMap<>(); } -// /** Executes a command */ -// @Override -// public void executeCommand() { -// Tree tree = GameBoardFacade.getInstance().getTree(); -// TreeView treeView = GameBoardFacade.getInstance().getLegupUI().getTreePanel().getTreeView(); -// Puzzle puzzle = GameBoardFacade.getInstance().getPuzzleModule(); -// final TreeViewSelection newSelection = new TreeViewSelection(); -// -// List selectedViews = selection.getSelectedViews(); -// int count = 1; -// for (TreeElementView selectedView : selectedViews) { -// System.out.println(count); -// count++; -// TreeElement element = selectedView.getTreeElement(); -// TreeTransitionView transitionView; -// if (element.getType() == TreeElementType.NODE) { -// TreeNodeView nodeView = (TreeNodeView) selectedView; -// transitionView = nodeView.getChildrenViews().get(0); -// } else { -// transitionView = (TreeTransitionView) selectedView; -// } -// TreeTransition transition = transitionView.getTreeElement(); -// -// oldRules.put(transition, transition.getRule()); -// transition.setRule(newRule); -// -// TreeNode childNode = transition.getChildNode(); -// if (childNode == null) { -// childNode = addNode.get(transition); -// if (childNode == null) { -// childNode = (TreeNode) tree.addTreeElement(transition); -// addNode.put(transition, childNode); -// } else { -// tree.addTreeElement(transition, childNode); -// } -// -// final TreeNode finalNode = childNode; -// puzzle.notifyTreeListeners(listener -> listener.onTreeElementAdded(finalNode)); -// } -// newSelection.addToSelection(treeView.getElementView(childNode)); -// } -// TreeElementView firstSelectedView = selection.getFirstSelection(); -// final TreeElement finalTreeElement; -// if (firstSelectedView.getType() == TreeElementType.NODE) { -// TreeNodeView nodeView = (TreeNodeView) firstSelectedView; -// finalTreeElement = nodeView.getChildrenViews().get(0).getTreeElement(); -// } else { -// TreeTransitionView transitionView = (TreeTransitionView) firstSelectedView; -// finalTreeElement = transitionView.getChildView().getTreeElement(); -// } -// puzzle.notifyBoardListeners(listener -> listener.onTreeElementChanged(finalTreeElement)); -// puzzle.notifyTreeListeners(listener -> listener.onTreeSelectionChanged(newSelection)); -// } - /** Executes a command */ + /** + * Executes the command to validate and apply the DirectRule. + */ @Override public void executeCommand() { Tree tree = GameBoardFacade.getInstance().getTree(); @@ -193,7 +146,9 @@ public String getErrorString() { return null; } - /** Undoes a command */ + /** + * Undoes the validation command, restoring the previous state. + */ @Override public void undoCommand() { Tree tree = GameBoardFacade.getInstance().getTree(); From cac3fa4e49c08c17fb4b9658127331efeecc2f78 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Fri, 9 Aug 2024 13:48:48 -0400 Subject: [PATCH 242/258] Added code specifications to all missing methods and class descriptions in all classes in model directory --- .../edu/rpi/legup/model/elements/Element.java | 50 +++++++++++++++++++ .../rpi/legup/model/elements/ElementType.java | 4 ++ .../model/elements/PlaceableElement.java | 13 +++++ .../legup/model/elements/RegisterElement.java | 5 ++ 4 files changed, 72 insertions(+) diff --git a/src/main/java/edu/rpi/legup/model/elements/Element.java b/src/main/java/edu/rpi/legup/model/elements/Element.java index 8b75d075d..0adbbaf91 100644 --- a/src/main/java/edu/rpi/legup/model/elements/Element.java +++ b/src/main/java/edu/rpi/legup/model/elements/Element.java @@ -4,6 +4,10 @@ import java.awt.image.BufferedImage; import javax.swing.*; +/** + * The Element class serves as an abstract base class for various elements used in the system. + * It handles basic properties such as ID, name, description, and image associated with the element. + */ @RegisterElement public abstract class Element { protected String elementID; @@ -17,6 +21,14 @@ public abstract class Element { private final String INVALID_USE_MESSAGE; + /** + * Constructs an Element with the specified ID, name, description, and image name + * + * @param elementID Unique identifier for the element + * @param elementName Name of the element + * @param description Description of the element + * @param imageName File name of the image associated with the element + */ public Element(String elementID, String elementName, String description, String imageName) { this.elementID = elementID; this.elementName = elementName; @@ -26,6 +38,9 @@ public Element(String elementID, String elementName, String description, String loadImage(); } + /** + * Loads the image for the element and resizes it to a width of 100 pixels while maintaining aspect ratio + */ private void loadImage() { if (imageName != null) { this.image = new ImageIcon(ClassLoader.getSystemClassLoader().getResource(imageName)); @@ -47,30 +62,65 @@ private void loadImage() { } } + /** + * Gets the name of the element + * + * @return The name of the element + */ public String getElementName() { return elementName; } + /** + * Sets the name of the element + * + * @param elementName The new name for the element + */ public void setElementName(String elementName) { this.elementName = elementName; } + /** + * Gets the unique identifier of the element + * + * @return The ID of the element + */ public String getElementID() { return elementID; } + /** + * Gets the description of the element + * + * @return The description of the element + */ public String getDescription() { return description; } + /** + * Gets the image icon associated with the element + * + * @return The ImageIcon for the element + */ public ImageIcon getImageIcon() { return image; } + /** + * Gets the type of the element + * + * @return The ElementType of the element + */ public ElementType getElementType() { return elementType; } + /** + * Gets the message for invalid use of the rule + * + * @return The invalid use message + */ public String getInvalidUseOfRuleMessage() { return this.INVALID_USE_MESSAGE; } diff --git a/src/main/java/edu/rpi/legup/model/elements/ElementType.java b/src/main/java/edu/rpi/legup/model/elements/ElementType.java index c71e4c7cd..4fee79d4f 100644 --- a/src/main/java/edu/rpi/legup/model/elements/ElementType.java +++ b/src/main/java/edu/rpi/legup/model/elements/ElementType.java @@ -1,5 +1,9 @@ package edu.rpi.legup.model.elements; +/** + * Enum representing the different types of elements that can be used in the system + */ public enum ElementType { PLACEABLE + //NONPLACEABLE COMBINED ALL PLACEABLE AND NONPLACEABLE INTO JUST ONE CATEGORY } diff --git a/src/main/java/edu/rpi/legup/model/elements/PlaceableElement.java b/src/main/java/edu/rpi/legup/model/elements/PlaceableElement.java index 133658700..79a0dcff8 100644 --- a/src/main/java/edu/rpi/legup/model/elements/PlaceableElement.java +++ b/src/main/java/edu/rpi/legup/model/elements/PlaceableElement.java @@ -1,6 +1,19 @@ package edu.rpi.legup.model.elements; +/** + * Abstract class representing elements that can be placed within the system. + * Inherits from the {@link Element} class and sets the {@link ElementType} to {@link ElementType#PLACEABLE}. + */ public abstract class PlaceableElement extends Element { + + /** + * Constructs a PlaceableElement with the specified details + * + * @param elementID Unique identifier for the element + * @param elementName Name of the element + * @param description Description of the element + * @param imageName Name of the image file representing the element + */ public PlaceableElement( String elementID, String elementName, String description, String imageName) { super(elementID, elementName, description, imageName); diff --git a/src/main/java/edu/rpi/legup/model/elements/RegisterElement.java b/src/main/java/edu/rpi/legup/model/elements/RegisterElement.java index 368ecc8d1..5f59ad795 100644 --- a/src/main/java/edu/rpi/legup/model/elements/RegisterElement.java +++ b/src/main/java/edu/rpi/legup/model/elements/RegisterElement.java @@ -3,6 +3,11 @@ import java.lang.annotation.*; import java.lang.annotation.ElementType; +/** + * Annotation to mark classes as elements that should be registered. + * This annotation is used to indicate that a class is an element within the system and should be registered + * for use within the application. + */ @Inherited @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) From 581654ebcf8bde8ae124dc82bb80047bae244f9b Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Fri, 9 Aug 2024 14:45:31 -0400 Subject: [PATCH 243/258] Added code specifications to all missing methods and class descriptions in all classes in gameboard directory --- .../edu/rpi/legup/model/gameboard/Board.java | 17 ++++-- .../rpi/legup/model/gameboard/CaseBoard.java | 59 +++++++++++++++++++ .../legup/model/gameboard/ElementFactory.java | 3 + .../rpi/legup/model/gameboard/GridBoard.java | 5 ++ .../rpi/legup/model/gameboard/GridCell.java | 7 +++ .../rpi/legup/model/gameboard/GridRegion.java | 13 ++-- .../legup/model/gameboard/PuzzleElement.java | 6 ++ 7 files changed, 98 insertions(+), 12 deletions(-) diff --git a/src/main/java/edu/rpi/legup/model/gameboard/Board.java b/src/main/java/edu/rpi/legup/model/gameboard/Board.java index 5ad6fcf60..4544caa36 100644 --- a/src/main/java/edu/rpi/legup/model/gameboard/Board.java +++ b/src/main/java/edu/rpi/legup/model/gameboard/Board.java @@ -5,6 +5,11 @@ import java.util.List; import java.util.Set; +/** + * Abstract class representing a game board. + * This class provides functionality for managing puzzle elements, tracking modifications, + * and determining if the board is modifiable. + */ public abstract class Board { protected List puzzleElements; @@ -31,10 +36,10 @@ public Board(int size) { } /** - * Gets a specific {@link PuzzleElement} on this board. + * Gets a specific {@link PuzzleElement} from the board. * - * @param puzzleElement equivalent puzzleElement - * @return equivalent puzzleElement on this board + * @param puzzleElement the puzzle element to retrieve + * @return the puzzle element at the corresponding index, or null if not found */ public PuzzleElement getPuzzleElement(PuzzleElement puzzleElement) { if (puzzleElement == null) { @@ -45,10 +50,10 @@ public PuzzleElement getPuzzleElement(PuzzleElement puzzleElement) { } /** - * Sets a specific {@link PuzzleElement} on the board. + * Sets a specific {@link PuzzleElement} on the board * * @param index index of the puzzleElement - * @param puzzleElement new puzzleElement at the index + * @param puzzleElement the puzzleElement to set at the index */ public void setPuzzleElement(int index, PuzzleElement puzzleElement) { if (index < puzzleElements.size()) { @@ -57,7 +62,7 @@ public void setPuzzleElement(int index, PuzzleElement puzzleElement) { } /** - * Gets the number of elements on the board. + * Gets the number of elements on the board * * @return number of elements on the board */ diff --git a/src/main/java/edu/rpi/legup/model/gameboard/CaseBoard.java b/src/main/java/edu/rpi/legup/model/gameboard/CaseBoard.java index fa3625a43..14dcb8609 100644 --- a/src/main/java/edu/rpi/legup/model/gameboard/CaseBoard.java +++ b/src/main/java/edu/rpi/legup/model/gameboard/CaseBoard.java @@ -5,49 +5,108 @@ import java.util.HashSet; import java.util.Set; +/** + * Represents a game board with specific rules for selecting puzzle elements. + * Extends the abstract `Board` class and adds functionality for handling pickable elements and case rules. + */ public class CaseBoard extends Board { protected Board baseBoard; protected CaseRule caseRule; protected Set pickablePuzzleElements; + /** + * Constructs a CaseBoard with a base board and a case rule. + * + * @param baseBoard the base board to use for this CaseBoard + * @param caseRule the case rule applied to this CaseBoard + */ public CaseBoard(Board baseBoard, CaseRule caseRule) { this.baseBoard = baseBoard; this.caseRule = caseRule; this.pickablePuzzleElements = new HashSet<>(); } + /** + * Adds a puzzle element to the set of pickable elements. + * + * @param puzzleElement the puzzle element to add + */ public void addPickableElement(PuzzleElement puzzleElement) { pickablePuzzleElements.add(puzzleElement); } + /** + * Removes a puzzle element from the set of pickable elements. + * + * @param puzzleElement the puzzle element to remove + */ public void removePickableElement(PuzzleElement puzzleElement) { pickablePuzzleElements.remove(puzzleElement); } + /** + * Checks if a puzzle element is pickable based on the mouse event. + * + * @param puzzleElement the puzzle element to check + * @param e the mouse event + * @return true if the puzzle element is pickable, false otherwise + */ public boolean isPickable(PuzzleElement puzzleElement, MouseEvent e) { return pickablePuzzleElements.contains(baseBoard.getPuzzleElement(puzzleElement)); } + /** + * Retrieves the base board for this CaseBoard. + * + * @return the base board + */ public Board getBaseBoard() { return baseBoard; } + /** + * Sets the base board for this CaseBoard. + * + * @param baseBoard the new base board + */ public void setBaseBoard(Board baseBoard) { this.baseBoard = baseBoard; } + /** + * Retrieves the case rule for this CaseBoard. + * + * @return the case rule + */ public CaseRule getCaseRule() { return caseRule; } + /** + * Sets the case rule for this CaseBoard. + * + * @param caseRule the new case rule + */ public void setCaseRule(CaseRule caseRule) { this.caseRule = caseRule; } + /** + * Gets the count of pickable puzzle elements. + * + * @return the number of pickable elements + */ public int getCount() { return pickablePuzzleElements.size(); } + + /** + * Performs a deep copy of this CaseBoard. + * CURRENTLY NOT IMPLEMENTED AND RETURNS NULL + * + * @return a new copy of the CaseBoard + */ public CaseBoard copy() { return null; } diff --git a/src/main/java/edu/rpi/legup/model/gameboard/ElementFactory.java b/src/main/java/edu/rpi/legup/model/gameboard/ElementFactory.java index bfc785bdd..131feb122 100644 --- a/src/main/java/edu/rpi/legup/model/gameboard/ElementFactory.java +++ b/src/main/java/edu/rpi/legup/model/gameboard/ElementFactory.java @@ -5,6 +5,9 @@ import org.w3c.dom.Element; import org.w3c.dom.Node; +/** + * ElementFactory is an abstract class for importing and exporting {@link PuzzleElement} instances. + */ public abstract class ElementFactory { /** diff --git a/src/main/java/edu/rpi/legup/model/gameboard/GridBoard.java b/src/main/java/edu/rpi/legup/model/gameboard/GridBoard.java index 9593690ce..7338132f8 100644 --- a/src/main/java/edu/rpi/legup/model/gameboard/GridBoard.java +++ b/src/main/java/edu/rpi/legup/model/gameboard/GridBoard.java @@ -6,6 +6,11 @@ import java.awt.*; import java.awt.event.MouseEvent; +/** + * GridBoard represents a grid-based board where each cell can be manipulated based on its + * coordinates. The board supports operations such as getting and setting cells, and provides + * dimensions of the grid. It also supports deep copying of the board. + */ public class GridBoard extends Board { protected Dimension dimension; diff --git a/src/main/java/edu/rpi/legup/model/gameboard/GridCell.java b/src/main/java/edu/rpi/legup/model/gameboard/GridCell.java index a33c3ec80..5d6fe1ff3 100644 --- a/src/main/java/edu/rpi/legup/model/gameboard/GridCell.java +++ b/src/main/java/edu/rpi/legup/model/gameboard/GridCell.java @@ -2,6 +2,13 @@ import java.awt.*; +/** + * GridCell represents a cell within a grid-based board. It holds data of type T and tracks its location + * on the board using a {@link Point}. The class extends from PuzzleElement and supports deep copying of + * the grid cell. + * + * @param the type of data held by the GridCell + */ public class GridCell extends PuzzleElement { protected Point location; 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 c41d5e1b2..b2a10a153 100644 --- a/src/main/java/edu/rpi/legup/model/gameboard/GridRegion.java +++ b/src/main/java/edu/rpi/legup/model/gameboard/GridRegion.java @@ -3,6 +3,12 @@ import java.util.ArrayList; import java.util.List; +/** + * GridRegion represents a collection of cells within a grid. It manages a list of cells and provides + * methods to add, remove, and retrieve cells from the region. + * + * @param the type of cell managed by the GridRegion + */ public abstract class GridRegion { protected List regionCells; @@ -24,7 +30,7 @@ public void addCell(T cell) { /** * Removes the cell from the region * - * @param cell cell to be remove from the region + * @param cell cell to be removed from the region */ public void removeCell(T cell) { regionCells.remove(cell); @@ -47,9 +53,4 @@ public List getCells() { public int getSize() { return regionCells.size(); } - - /* - public void colorRegion(){} - */ - } diff --git a/src/main/java/edu/rpi/legup/model/gameboard/PuzzleElement.java b/src/main/java/edu/rpi/legup/model/gameboard/PuzzleElement.java index 719d524da..a92b3efb0 100644 --- a/src/main/java/edu/rpi/legup/model/gameboard/PuzzleElement.java +++ b/src/main/java/edu/rpi/legup/model/gameboard/PuzzleElement.java @@ -3,6 +3,12 @@ import edu.rpi.legup.model.elements.Element; import java.awt.event.MouseEvent; +/** + * PuzzleElement represents a single element in a puzzle grid. It holds data and provides various + * methods to manage and retrieve its properties, including modifiability, modification status, and validity. + * + * @param the type of data held by the PuzzleElement + */ public abstract class PuzzleElement { protected int index; protected T data; From 5ed4a2738a8fd72c724e4a5cdf507aada992dfc7 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Fri, 9 Aug 2024 14:46:31 -0400 Subject: [PATCH 244/258] Added code specifications to all missing methods and class descriptions in all classes in observer directory --- .../java/edu/rpi/legup/model/observer/IBoardListener.java | 6 +++++- .../java/edu/rpi/legup/model/observer/IBoardSubject.java | 6 +++++- .../java/edu/rpi/legup/model/observer/ITreeListener.java | 4 ++++ .../java/edu/rpi/legup/model/observer/ITreeSubject.java | 8 ++++++-- 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/main/java/edu/rpi/legup/model/observer/IBoardListener.java b/src/main/java/edu/rpi/legup/model/observer/IBoardListener.java index 461128562..fa440369c 100644 --- a/src/main/java/edu/rpi/legup/model/observer/IBoardListener.java +++ b/src/main/java/edu/rpi/legup/model/observer/IBoardListener.java @@ -4,6 +4,10 @@ import edu.rpi.legup.model.gameboard.PuzzleElement; import edu.rpi.legup.model.tree.TreeElement; +/** + * IBoardListener defines methods for receiving notifications about changes to the board, + * including updates to tree elements, case boards, and puzzle elements. + */ public interface IBoardListener { /** * Called when the tree element has changed. @@ -13,7 +17,7 @@ public interface IBoardListener { void onTreeElementChanged(TreeElement treeElement); /** - * Called when the a case board has been added to the view. + * Called when a case board has been added to the view. * * @param caseBoard case board to be added */ diff --git a/src/main/java/edu/rpi/legup/model/observer/IBoardSubject.java b/src/main/java/edu/rpi/legup/model/observer/IBoardSubject.java index c7bf13141..53bfe444b 100644 --- a/src/main/java/edu/rpi/legup/model/observer/IBoardSubject.java +++ b/src/main/java/edu/rpi/legup/model/observer/IBoardSubject.java @@ -2,6 +2,10 @@ import java.util.function.Consumer; +/** + * IBoardSubject defines methods for managing and notifying board listeners. + * It allows for adding and removing listeners, and for notifying them using a specified algorithm. + */ public interface IBoardSubject { /** * Adds a board listener. @@ -18,7 +22,7 @@ public interface IBoardSubject { void removeBoardListener(IBoardListener listener); /** - * Notifies all of the listeners using the specified algorithm. + * Notifies all the listeners using the specified algorithm. * * @param algorithm algorithm used to notify the listeners */ diff --git a/src/main/java/edu/rpi/legup/model/observer/ITreeListener.java b/src/main/java/edu/rpi/legup/model/observer/ITreeListener.java index d5e7fdb2d..c5a0355ca 100644 --- a/src/main/java/edu/rpi/legup/model/observer/ITreeListener.java +++ b/src/main/java/edu/rpi/legup/model/observer/ITreeListener.java @@ -3,6 +3,10 @@ import edu.rpi.legup.model.tree.TreeElement; import edu.rpi.legup.ui.proofeditorui.treeview.TreeViewSelection; +/** + * ITreeListener defines methods for handling events related to changes in the tree. + * Implementations of this interface are notified of additions, removals, and selection changes in the tree. + */ public interface ITreeListener { /** * Called when a {@link TreeElement} is added to the tree. diff --git a/src/main/java/edu/rpi/legup/model/observer/ITreeSubject.java b/src/main/java/edu/rpi/legup/model/observer/ITreeSubject.java index 66d5d9a5e..0b0aee348 100644 --- a/src/main/java/edu/rpi/legup/model/observer/ITreeSubject.java +++ b/src/main/java/edu/rpi/legup/model/observer/ITreeSubject.java @@ -2,9 +2,13 @@ import java.util.function.Consumer; +/** + * ITreeSubject defines methods for managing and notifying listeners about changes to the tree model. + * Implementations of this interface handle adding, removing, and notifying listeners. + */ public interface ITreeSubject { /** - * Adds a board listener. + * Adds a tree listener. * * @param listener listener to add */ @@ -18,7 +22,7 @@ public interface ITreeSubject { void removeTreeListener(ITreeListener listener); /** - * Notifies all of the listeners using the specified algorithm. + * Notifies all the tree listeners using the specified algorithm. * * @param algorithm algorithm used to notify the listeners */ From bc0b425928fdb3e0c1b40bb062a340486e942e5f Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Fri, 9 Aug 2024 15:35:28 -0400 Subject: [PATCH 245/258] Added code specifications to all missing methods and class descriptions in all classes in model/rules directory --- src/main/java/edu/rpi/legup/model/rules/CaseRule.java | 4 ++++ .../edu/rpi/legup/model/rules/ContradictionRule.java | 4 ++++ .../java/edu/rpi/legup/model/rules/DirectRule.java | 4 ++++ .../java/edu/rpi/legup/model/rules/MergeRule.java | 6 +++++- .../java/edu/rpi/legup/model/rules/RegisterRule.java | 5 +++++ src/main/java/edu/rpi/legup/model/rules/Rule.java | 11 +++++++++++ src/main/java/edu/rpi/legup/model/rules/RuleType.java | 4 ++++ 7 files changed, 37 insertions(+), 1 deletion(-) diff --git a/src/main/java/edu/rpi/legup/model/rules/CaseRule.java b/src/main/java/edu/rpi/legup/model/rules/CaseRule.java index ab2cc8f0d..ee5c91229 100644 --- a/src/main/java/edu/rpi/legup/model/rules/CaseRule.java +++ b/src/main/java/edu/rpi/legup/model/rules/CaseRule.java @@ -11,6 +11,10 @@ import java.util.List; import java.util.Set; +/** + * CaseRule is an abstract class representing a rule that can be applied with multiple cases in a puzzle board. + * It defines methods for applying and checking the rule, as well as retrieving the necessary elements. + */ public abstract class CaseRule extends Rule { private final String INVALID_USE_MESSAGE; diff --git a/src/main/java/edu/rpi/legup/model/rules/ContradictionRule.java b/src/main/java/edu/rpi/legup/model/rules/ContradictionRule.java index b38a95fd2..cd2e20081 100644 --- a/src/main/java/edu/rpi/legup/model/rules/ContradictionRule.java +++ b/src/main/java/edu/rpi/legup/model/rules/ContradictionRule.java @@ -6,6 +6,10 @@ import edu.rpi.legup.model.gameboard.PuzzleElement; import edu.rpi.legup.model.tree.TreeTransition; +/** + * ContradictionRule is an abstract class representing a rule that identifies contradictions in a puzzle. + * It provides methods to check for contradictions both globally and at specific puzzle elements. + */ public abstract class ContradictionRule extends Rule { private final String NO_CONTRADICTION_MESSAGE = diff --git a/src/main/java/edu/rpi/legup/model/rules/DirectRule.java b/src/main/java/edu/rpi/legup/model/rules/DirectRule.java index d550bc02c..613574989 100644 --- a/src/main/java/edu/rpi/legup/model/rules/DirectRule.java +++ b/src/main/java/edu/rpi/legup/model/rules/DirectRule.java @@ -7,6 +7,10 @@ import edu.rpi.legup.model.tree.TreeNode; import edu.rpi.legup.model.tree.TreeTransition; +/** + * DirectRule is an abstract class representing a direct rule for transitions in a puzzle. + * It provides methods for checking whether transitions and specific puzzle elements follow the rule. + */ public abstract class DirectRule extends Rule { /** * DirectRule Constructor creates a new basic rule. diff --git a/src/main/java/edu/rpi/legup/model/rules/MergeRule.java b/src/main/java/edu/rpi/legup/model/rules/MergeRule.java index f7badcd8b..f7bd887f3 100644 --- a/src/main/java/edu/rpi/legup/model/rules/MergeRule.java +++ b/src/main/java/edu/rpi/legup/model/rules/MergeRule.java @@ -10,6 +10,10 @@ import java.util.ArrayList; import java.util.List; +/** + * MergeRule is an implementation of a rule that merges multiple nodes into one. + * It validates if the merging of nodes is done correctly. + */ public class MergeRule extends Rule { /** MergeRule Constructor merges to board states together */ public MergeRule() { @@ -23,7 +27,7 @@ public MergeRule() { /** * Checks whether the transition logically follows from the parent node using this rule. This - * method is the one that should overridden in child classes + * method is the one that should have overridden in child classes * * @param transition transition to check * @return null if the child node logically follow from the parent node, otherwise error message diff --git a/src/main/java/edu/rpi/legup/model/rules/RegisterRule.java b/src/main/java/edu/rpi/legup/model/rules/RegisterRule.java index c1fe0b88c..d357e0d86 100644 --- a/src/main/java/edu/rpi/legup/model/rules/RegisterRule.java +++ b/src/main/java/edu/rpi/legup/model/rules/RegisterRule.java @@ -2,6 +2,11 @@ import java.lang.annotation.*; +/** + * Annotation to register a class as a rule in the system. + * This annotation can be applied to rule classes to indicate that they should be registered + * in the rule system. + */ @Inherited @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) diff --git a/src/main/java/edu/rpi/legup/model/rules/Rule.java b/src/main/java/edu/rpi/legup/model/rules/Rule.java index f70bb2889..107e72712 100644 --- a/src/main/java/edu/rpi/legup/model/rules/Rule.java +++ b/src/main/java/edu/rpi/legup/model/rules/Rule.java @@ -8,6 +8,12 @@ import java.awt.image.BufferedImage; import javax.swing.ImageIcon; +/** + * Abstract base class for defining rules. + * This class encapsulates the common functionality and attributes of all rules, + * including rule identification, description, image handling, and validation logic. + * Subclasses must provide implementations for specific rule checking logic. + */ @RegisterRule public abstract class Rule { protected String ruleID; @@ -159,6 +165,11 @@ public RuleType getRuleType() { return ruleType; } + /** + * Gets the message indicating an invalid use of the rule. + * + * @return the invalid use message + */ public String getInvalidUseOfRuleMessage() { return this.INVALID_USE_MESSAGE; } diff --git a/src/main/java/edu/rpi/legup/model/rules/RuleType.java b/src/main/java/edu/rpi/legup/model/rules/RuleType.java index 06aa1844b..e72118e3c 100644 --- a/src/main/java/edu/rpi/legup/model/rules/RuleType.java +++ b/src/main/java/edu/rpi/legup/model/rules/RuleType.java @@ -1,5 +1,9 @@ package edu.rpi.legup.model.rules; +/** + * Enumeration representing different types of rules in the rule-based system. + * This enum categorizes rules into various types based on their functionality and application. + */ public enum RuleType { BASIC, CASE, From 4715d11cc98cafda8fd29bab6a07d5e0ce0e0a71 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Fri, 9 Aug 2024 15:44:22 -0400 Subject: [PATCH 246/258] Added code specifications to all missing methods and class descriptions in all classes in model/tree directory --- .../java/edu/rpi/legup/model/tree/Tree.java | 61 ++++++++++++------- .../edu/rpi/legup/model/tree/TreeElement.java | 5 +- .../rpi/legup/model/tree/TreeElementType.java | 4 ++ .../edu/rpi/legup/model/tree/TreeNode.java | 13 +++- .../rpi/legup/model/tree/TreeTransition.java | 5 ++ 5 files changed, 62 insertions(+), 26 deletions(-) diff --git a/src/main/java/edu/rpi/legup/model/tree/Tree.java b/src/main/java/edu/rpi/legup/model/tree/Tree.java index 471d8ccb6..3e68015a1 100644 --- a/src/main/java/edu/rpi/legup/model/tree/Tree.java +++ b/src/main/java/edu/rpi/legup/model/tree/Tree.java @@ -10,6 +10,11 @@ import java.util.List; import java.util.Set; +/** + * Represents a tree structure in a puzzle. + * The tree consists of {@link TreeNode}s and {@link TreeTransition}s + * and allows adding, removing, and validating elements. + */ public class Tree { private TreeNode rootNode; @@ -28,6 +33,12 @@ public Tree() { this.rootNode = null; } + /** + * Adds a new transition to the specified node. + * + * @param treeNode the node to add a transition to + * @return the created transition + */ public TreeTransition addNewTransition(TreeNode treeNode) { TreeTransition transition = new TreeTransition(treeNode, treeNode.getBoard().copy()); treeNode.addChild(transition); @@ -35,13 +46,12 @@ public TreeTransition addNewTransition(TreeNode treeNode) { return transition; } - public TreeNode addNode(TreeTransition transition) { - TreeNode treeNode = new TreeNode(transition.getBoard().copy()); - transition.setChildNode(treeNode); - treeNode.setParent(transition); - return treeNode; - } - + /** + * Adds a tree element (node or transition) to the tree. + * + * @param element the tree element to add + * @return the added tree element + */ public TreeElement addTreeElement(TreeElement element) { if (element.getType() == TreeElementType.NODE) { TreeNode treeNode = (TreeNode) element; @@ -55,40 +65,45 @@ public TreeElement addTreeElement(TreeElement element) { } } + /** + * Adds a tree node and its associated transition to the tree. + * + * @param treeNode the tree node to add + * @param transition the transition to associate with the node + * @return the added transition + */ public TreeElement addTreeElement(TreeNode treeNode, TreeTransition transition) { treeNode.addChild(transition); treeNode.getChildren().forEach(TreeTransition::reverify); return transition; } + /** + * Adds a transition and its associated tree node to the tree. + * + * @param transition the transition to add + * @param treeNode the tree node to associate with the transition + * @return the added tree node + */ public TreeElement addTreeElement(TreeTransition transition, TreeNode treeNode) { transition.setChildNode(treeNode); treeNode.setParent(transition); return treeNode; } -// public void removeTreeElement(TreeElement element) { -// if (element.getType() == TreeElementType.NODE) { -// TreeNode node = (TreeNode) element; -// node.getParent().setChildNode(null); -// } else { -// TreeTransition transition = (TreeTransition) element; -// System.out.println("DELETED CHILD"); -// transition.getParents().forEach(n -> n.removeChild(transition)); -// transition.getParents().get(0).getChildren().forEach(TreeTransition::reverify); -// } -// } - + /** + * Removes a tree element (node or transition) from the tree. + * + * @param element the tree element to remove + */ public void removeTreeElement(TreeElement element) { if (element.getType() == TreeElementType.NODE) { TreeNode node = (TreeNode) element; - System.out.println("Recognized node: " + node); node.getParent().removeChild(node); node.getParent().setChildNode(null); } else { TreeTransition transition = (TreeTransition) element; - System.out.println("Recognized transition: " + transition); transition.getParents().forEach(n -> n.removeChild(transition)); TreeController treeController = new TreeController(); @@ -120,10 +135,10 @@ public Set getLeafTreeElements() { } /** - * Gets a Set of TreeNodes that are leaf nodes from the sub tree rooted at the specified node + * Gets a Set of TreeNodes that are leaf nodes from the subtree rooted at the specified node * * @param node node that is input - * @return Set of TreeNodes that are leaf nodes from the sub tree + * @return Set of TreeNodes that are leaf nodes from the subtree */ public Set getLeafTreeElements(TreeNode node) { Set leafs = new HashSet<>(); diff --git a/src/main/java/edu/rpi/legup/model/tree/TreeElement.java b/src/main/java/edu/rpi/legup/model/tree/TreeElement.java index 59f75acf3..2f6f45e4d 100644 --- a/src/main/java/edu/rpi/legup/model/tree/TreeElement.java +++ b/src/main/java/edu/rpi/legup/model/tree/TreeElement.java @@ -2,6 +2,9 @@ import edu.rpi.legup.model.gameboard.Board; +/** + * Represents an element in a tree structure, which can be either a {@link TreeNode} or a {@link TreeTransition}. + */ public abstract class TreeElement { protected TreeElementType type; protected Board board; @@ -24,7 +27,7 @@ public TreeElement(TreeElementType type) { public abstract boolean isContradictoryBranch(); /** - * Recursively determines if the sub-tree rooted at this tree puzzleElement is valid by checking + * Recursively determines if the subtree rooted at this tree puzzleElement is valid by checking * whether this tree puzzleElement and all descendants of this tree puzzleElement is justified * and justified correctly * diff --git a/src/main/java/edu/rpi/legup/model/tree/TreeElementType.java b/src/main/java/edu/rpi/legup/model/tree/TreeElementType.java index 67437a535..3a6dbb124 100644 --- a/src/main/java/edu/rpi/legup/model/tree/TreeElementType.java +++ b/src/main/java/edu/rpi/legup/model/tree/TreeElementType.java @@ -1,5 +1,9 @@ package edu.rpi.legup.model.tree; +/** + * Enum representing the type of a tree element. + * Tree elements can be either nodes or transitions in the tree structure. + */ public enum TreeElementType { NODE, TRANSITION diff --git a/src/main/java/edu/rpi/legup/model/tree/TreeNode.java b/src/main/java/edu/rpi/legup/model/tree/TreeNode.java index a2ac7cb21..85a5e717b 100644 --- a/src/main/java/edu/rpi/legup/model/tree/TreeNode.java +++ b/src/main/java/edu/rpi/legup/model/tree/TreeNode.java @@ -4,6 +4,11 @@ import edu.rpi.legup.utility.DisjointSets; import java.util.*; +/** + * Represents a node in a tree structure. Extends {@link TreeElement}. + * A {@code TreeNode} contains a board, references to its parent and children transitions, and indicates + * if it is the root node of the tree. + */ public class TreeNode extends TreeElement { private TreeTransition parent; private List children; @@ -56,9 +61,9 @@ public boolean isValidBranch() { } /** - * Gets all of the ancestors of this node + * Gets a list of the ancestors of this node * - * @return list of all of the ancestors for this node + * @return list of all the ancestors for this node */ public List getAncestors() { List ancestors = new ArrayList<>(); @@ -326,6 +331,10 @@ public void setRoot(boolean isRoot) { this.isRoot = isRoot; } + /** + * Clears all children transitions from this tree node. + * After calling this method, the node will have no child transitions. + */ public void clearChildren() { this.children.clear(); } diff --git a/src/main/java/edu/rpi/legup/model/tree/TreeTransition.java b/src/main/java/edu/rpi/legup/model/tree/TreeTransition.java index 22ea33466..9e441ac55 100644 --- a/src/main/java/edu/rpi/legup/model/tree/TreeTransition.java +++ b/src/main/java/edu/rpi/legup/model/tree/TreeTransition.java @@ -8,6 +8,11 @@ import java.util.ArrayList; import java.util.List; +/** + * Represents a transition between two nodes in a tree structure within a game. + * A transition is responsible for propagating changes through the tree and managing + * and verifying the associated rules and puzzle elements. + */ public class TreeTransition extends TreeElement { private ArrayList parents; private TreeNode childNode; From fea6f0f4dc2e50bcfccacf082b4d3fd19bf42036 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Fri, 9 Aug 2024 16:23:27 -0400 Subject: [PATCH 247/258] Added code specifications to all missing methods and class descriptions in all classes in model directory --- src/main/java/edu/rpi/legup/model/Puzzle.java | 84 +++++++++++-------- .../edu/rpi/legup/model/PuzzleExporter.java | 26 ++++++ .../edu/rpi/legup/model/PuzzleImporter.java | 54 +++++++++--- .../edu/rpi/legup/model/RegisterPuzzle.java | 3 + 4 files changed, 122 insertions(+), 45 deletions(-) diff --git a/src/main/java/edu/rpi/legup/model/Puzzle.java b/src/main/java/edu/rpi/legup/model/Puzzle.java index a7cea6587..6cc92f347 100644 --- a/src/main/java/edu/rpi/legup/model/Puzzle.java +++ b/src/main/java/edu/rpi/legup/model/Puzzle.java @@ -35,6 +35,11 @@ import org.w3c.dom.Node; import org.xml.sax.SAXException; +/** + * Abstract class representing a puzzle. + * The Puzzle class manages the core components of a puzzle game, including the board, rules, and elements. + * It also handles importing and exporting puzzle configurations and notifies listeners about changes. + */ public abstract class Puzzle implements IBoardSubject, ITreeSubject { private static final Logger LOGGER = LogManager.getLogger(Puzzle.class.getName()); @@ -69,6 +74,10 @@ public Puzzle() { registerPuzzleElements(); } + /** + * Registers puzzle elements from the package of the derived class. + * Scans for classes annotated with {@link RegisterElement} and initializes them. + */ private void registerPuzzleElements() { String packageName = this.getClass().getPackage().toString().replace("package ", ""); @@ -107,19 +116,15 @@ private void registerPuzzleElements() { } } } - - // } catch (IOException | ClassNotFoundException | NoSuchMethodException | - // InstantiationException | IllegalAccessException | - // InvocationTargetException - // e) { - // LOGGER.error("Unable to find rules for " + - // this.getClass().getSimpleName(), e); - // } } catch (Exception e) { LOGGER.error("Unable to find elements for " + this.getClass().getSimpleName(), e); } } + /** + * Registers rules from the package of the derived class. + * Scans for classes annotated with {@link RegisterRule} and initializes them. + */ private void registerRules() { String packageName = this.getClass().getPackage().toString().replace("package ", ""); @@ -166,20 +171,14 @@ private void registerRules() { } } } - - // } catch (IOException | ClassNotFoundException | NoSuchMethodException | - // InstantiationException | IllegalAccessException | - // InvocationTargetException - // e) { - // LOGGER.error("Unable to find rules for " + - // this.getClass().getSimpleName(), e); - // } } catch (Exception e) { LOGGER.error("Unable to find rules for " + this.getClass().getSimpleName(), e); } } - /** Initializes the view. Called by the invoker of the class */ + /** + * Initializes the view. Called by the invoker of the class + */ public abstract void initializeView(); /** @@ -202,10 +201,10 @@ public boolean isValidDimensions(int rows, int columns) { } /** - * Checks if the given array of statements is valid text input for the given puzzle + * Checks if the provided text input is valid for the puzzle. * - * @param statements - * @return + * @param statements array of statements to check + * @return true if input is valid, false otherwise */ public boolean isValidTextInput(String[] statements) { return statements.length > 0; @@ -337,6 +336,11 @@ public List getDirectRules() { return directRules; } + /** + * Gets the list of placeable elements. + * + * @return list of PlaceableElement instances + */ public List getPlaceableElements() { return placeableElements; } @@ -359,6 +363,11 @@ public void addDirectRule(DirectRule rule) { directRules.add(rule); } + /** + * Adds a placeable element to this puzzle. + * + * @param element PlaceableElement to add + */ public void addPlaceableElement(PlaceableElement element) { placeableElements.add(element); } @@ -575,9 +584,10 @@ public void setFactory(ElementFactory factory) { } /** - * Adds a board listener + * Adds a board listener to the list of listeners. + * This allows the puzzle to notify the listener about changes to the board. * - * @param listener listener to add + * @param listener The IBoardListener to be added to the list of listeners. */ @Override public void addBoardListener(IBoardListener listener) { @@ -585,9 +595,10 @@ public void addBoardListener(IBoardListener listener) { } /** - * Removes a board listener + * Removes a board listener from the list of listeners. + * This prevents the puzzle from notifying the listener about future changes to the board. * - * @param listener listener to remove + * @param listener The IBoardListener to be removed from the list of listeners. */ @Override public void removeBoardListener(IBoardListener listener) { @@ -595,9 +606,10 @@ public void removeBoardListener(IBoardListener listener) { } /** - * Notifies listeners + * Notifies all registered board listeners about changes. + * The provided algorithm is applied to each listener to process the notification. * - * @param algorithm algorithm to notify the listeners with + * @param algorithm A Consumer function that takes an IBoardListener and performs operations to notify the listener. */ @Override public void notifyBoardListeners(Consumer algorithm) { @@ -605,9 +617,10 @@ public void notifyBoardListeners(Consumer algorithm) { } /** - * Adds a board listener + * Adds a tree listener to the list of listeners. + * This allows the puzzle to notify the listener about changes to the tree. * - * @param listener listener to add + * @param listener The ITreeListener to be added to the list of listeners. */ @Override public void addTreeListener(ITreeListener listener) { @@ -615,9 +628,10 @@ public void addTreeListener(ITreeListener listener) { } /** - * Removes a tree listener + * Removes a tree listener from the list of listeners. + * This prevents the puzzle from notifying the listener about future changes to the tree. * - * @param listener listener to remove + * @param listener The ITreeListener to be removed from the list of listeners. */ @Override public void removeTreeListener(ITreeListener listener) { @@ -625,9 +639,10 @@ public void removeTreeListener(ITreeListener listener) { } /** - * Notifies listeners + * Notifies all registered tree listeners about changes. + * The provided algorithm is applied to each listener to process the notification. * - * @param algorithm algorithm to notify the listeners with + * @param algorithm A Consumer function that takes an ITreeListener and performs operations to notify the listener. */ @Override public void notifyTreeListeners(Consumer algorithm) { @@ -635,9 +650,10 @@ public void notifyTreeListeners(Consumer algorithm) { } /** - * Check if the puzzle is valid + * Checks if the puzzle is valid. + * The implementation of this method can vary based on the specific criteria for puzzle validity. * - * @return if the puzzle is valid + * @return true if the puzzle is valid, false otherwise. */ public boolean checkValidity() { return true; diff --git a/src/main/java/edu/rpi/legup/model/PuzzleExporter.java b/src/main/java/edu/rpi/legup/model/PuzzleExporter.java index a052a736a..234d0f25c 100644 --- a/src/main/java/edu/rpi/legup/model/PuzzleExporter.java +++ b/src/main/java/edu/rpi/legup/model/PuzzleExporter.java @@ -20,6 +20,11 @@ import org.w3c.dom.Document; import org.w3c.dom.Element; +/** + * Abstract class for exporting puzzle data to XML format. + * This class provides functionality to export a puzzle object, including its board and tree structure, to an XML file. + * Subclasses must implement methods to create specific elements for the board and the tree. + */ public abstract class PuzzleExporter { private static final Logger LOGGER = LogManager.getLogger(PuzzleExporter.class.getName()); @@ -91,8 +96,22 @@ public void exportPuzzle(String fileName) throws ExportFileException { } } + /** + * Creates an XML element representing the board of the puzzle. + * Subclasses must implement this method to provide the XML structure for the board. + * + * @param newDocument The XML document to create elements within. + * @return An XML element representing the puzzle's board. + */ protected abstract Element createBoardElement(Document newDocument); + /** + * Creates an XML element representing the proof of the puzzle, including its tree structure. + * This method is used to generate the proof section of the XML, which contains the tree representation. + * + * @param newDocument The XML document to create elements within. + * @return An XML element representing the proof of the puzzle. + */ protected Element createProofElement(Document newDocument) { org.w3c.dom.Element proofElement = newDocument.createElement("proof"); org.w3c.dom.Element treeElement = createTreeElement(newDocument); @@ -100,6 +119,13 @@ protected Element createProofElement(Document newDocument) { return proofElement; } + /** + * Creates an XML element representing the tree structure of the puzzle. + * This method traverses the tree nodes and transitions, and creates XML elements for each. + * + * @param newDocument The XML document to create elements within. + * @return An XML element representing the puzzle's tree structure. + */ protected Element createTreeElement(Document newDocument) { org.w3c.dom.Element treeElement = newDocument.createElement("tree"); diff --git a/src/main/java/edu/rpi/legup/model/PuzzleImporter.java b/src/main/java/edu/rpi/legup/model/PuzzleImporter.java index 0902478db..b1e8a2dd9 100644 --- a/src/main/java/edu/rpi/legup/model/PuzzleImporter.java +++ b/src/main/java/edu/rpi/legup/model/PuzzleImporter.java @@ -13,6 +13,12 @@ import org.w3c.dom.Node; import org.w3c.dom.NodeList; +/** + * Abstract class for importing puzzle data from various sources into a puzzle object. + * This class provides methods to initialize and set up a puzzle, including its board and proof structure, + * from different input formats such as dimensions, statements, or XML files. + * Subclasses must implement methods to handle specific formats for board initialization and proof creation. + */ public abstract class PuzzleImporter { private static final Logger LOGGER = LogManager.getLogger(PuzzleImporter.class.getName()); @@ -46,6 +52,13 @@ public void initializePuzzle(int rows, int columns) throws RuntimeException { } } + /** + * Initializes the puzzle with the given array of statements + * + * @param statements the statements used to initialize the puzzle + * @throws InputMismatchException if the input statements are invalid + * @throws IllegalArgumentException if the statements are not suitable for initializing the puzzle + */ public void initializePuzzle(String[] statements) throws InputMismatchException, IllegalArgumentException { // Note: Error checking for the statements will be left up to the puzzles that support @@ -55,10 +68,10 @@ public void initializePuzzle(String[] statements) } /** - * Initializes the puzzle attributes + * Initializes the puzzle attributes from the XML document node * - * @param node xml document node - * @throws InvalidFileFormatException if file is invalid + * @param node the XML document node representing the puzzle + * @throws InvalidFileFormatException if the file format is invalid */ public void initializePuzzle(Node node) throws InvalidFileFormatException { if (node.getNodeName().equalsIgnoreCase("puzzle")) { @@ -111,22 +124,29 @@ public void initializePuzzle(Node node) throws InvalidFileFormatException { } /** - * Creates the board for building + * Initializes the board with the specified number of rows and columns. * - * @param rows number of rows on the puzzle - * @param columns number of columns on the puzzle - * @throws RuntimeException if board can not be created + * @param rows the number of rows on the puzzle + * @param columns the number of columns on the puzzle + * @throws RuntimeException if the board cannot be created with the provided dimensions */ public abstract void initializeBoard(int rows, int columns); /** - * Creates an empty board for building + * Initializes the board from the XML document node. * - * @param node xml document node - * @throws InvalidFileFormatException if file is invalid + * @param node the XML document node representing the board + * @throws InvalidFileFormatException if the file format is invalid */ public abstract void initializeBoard(Node node) throws InvalidFileFormatException; + /** + * Initializes the board using an array of statements. + * + * @param statements the statements used to initialize the board + * @throws UnsupportedOperationException if the operation is not supported + * @throws IllegalArgumentException if the statements are not suitable for initializing the board + */ public abstract void initializeBoard(String[] statements) throws UnsupportedOperationException, IllegalArgumentException; @@ -294,6 +314,7 @@ protected void createTree(Node node) throws InvalidFileFormatException { } } + protected void validateTreeStructure( HashMap nodes, HashMap transitions) throws InvalidFileFormatException { @@ -368,6 +389,13 @@ protected void validateTreeStructure( } } + /** + * Updates the board state based on the changes specified in the TreeTransition. + * + * @param transition the TreeTransition object representing the transition to be updated + * @param transElement the XML node containing the transition data + * @throws InvalidFileFormatException if the XML node format is incorrect or unknown nodes are encountered + */ protected void makeTransitionChanges(TreeTransition transition, Node transElement) throws InvalidFileFormatException { if (transition.getRule() instanceof MergeRule) { @@ -411,6 +439,10 @@ protected void makeTransitionChanges(TreeTransition transition, Node transElemen } } + /** + * Creates a default proof tree with a single root node. The root node is initialized with the current board state. + * The created tree is then set as the proof tree for the puzzle. + */ protected void createDefaultTree() { TreeNode root = new TreeNode(puzzle.getCurrentBoard()); root.setRoot(true); @@ -420,7 +452,7 @@ protected void createDefaultTree() { } /** - * Gets the result of building the Puzzle + * Gets the result of building the Puzzle object. * * @return puzzle */ diff --git a/src/main/java/edu/rpi/legup/model/RegisterPuzzle.java b/src/main/java/edu/rpi/legup/model/RegisterPuzzle.java index c4c1ed273..c473e0ecd 100644 --- a/src/main/java/edu/rpi/legup/model/RegisterPuzzle.java +++ b/src/main/java/edu/rpi/legup/model/RegisterPuzzle.java @@ -5,6 +5,9 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +/** + * Annotation for registering puzzle classes with the puzzle framework. + */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface RegisterPuzzle {} From e29ff9cd33c048464df0e5fa498eb01d189f9fa8 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Fri, 9 Aug 2024 19:22:03 -0400 Subject: [PATCH 248/258] Added code specifications to all missing methods and class descriptions in all classes in ui/boardview directory --- .../edu/rpi/legup/ui/boardview/BoardView.java | 23 ++++ .../legup/ui/boardview/DataSelectionView.java | 9 ++ .../legup/ui/boardview/ElementSelection.java | 54 +++++++++ .../rpi/legup/ui/boardview/ElementView.java | 114 ++++++++++++++++++ .../rpi/legup/ui/boardview/GridBoardView.java | 33 ++++- .../legup/ui/boardview/GridElementView.java | 5 + .../legup/ui/boardview/SelectionItemView.java | 40 ++++++ 7 files changed, 275 insertions(+), 3 deletions(-) diff --git a/src/main/java/edu/rpi/legup/ui/boardview/BoardView.java b/src/main/java/edu/rpi/legup/ui/boardview/BoardView.java index ca03f1e25..fa3ec70b7 100644 --- a/src/main/java/edu/rpi/legup/ui/boardview/BoardView.java +++ b/src/main/java/edu/rpi/legup/ui/boardview/BoardView.java @@ -11,6 +11,10 @@ import java.awt.*; import java.util.ArrayList; +/** + * An abstract class representing a view for a board in the puzzle game. + * It handles the visual representation and user interactions with the board elements. + */ public abstract class BoardView extends ScrollView implements IBoardListener { protected TreeElement treeElement; protected Board board; @@ -125,6 +129,9 @@ public void setBoard(Board board) { } } + /** + * Configures the view to handle case interactions + */ protected void setCasePickable() { CaseBoard caseBoard = (CaseBoard) board; Board baseBoard = caseBoard.getBaseBoard(); @@ -183,15 +190,26 @@ public ArrayList getElementViews() { return elementViews; } + /** + * Gets the ElementController associated with this board view. + * + * @return the ElementController + */ public ElementController getElementController() { return elementController; } + @Override public void draw(Graphics2D graphics2D) { drawBoard(graphics2D); } + /** + * Draws the board and its elements. + * + * @param graphics2D the Graphics2D context used for drawing + */ public void drawBoard(Graphics2D graphics2D) { for (ElementView element : elementViews) { element.draw(graphics2D); @@ -208,5 +226,10 @@ public void onBoardDataChanged(PuzzleElement puzzleElement) { repaint(); } + /** + * Gets the selection popup menu for this board view. + * + * @return the DataSelectionView associated with this view + */ public abstract DataSelectionView getSelectionPopupMenu(); } diff --git a/src/main/java/edu/rpi/legup/ui/boardview/DataSelectionView.java b/src/main/java/edu/rpi/legup/ui/boardview/DataSelectionView.java index cedfa08fe..a3d82b461 100644 --- a/src/main/java/edu/rpi/legup/ui/boardview/DataSelectionView.java +++ b/src/main/java/edu/rpi/legup/ui/boardview/DataSelectionView.java @@ -5,8 +5,17 @@ import javax.swing.*; import javax.swing.border.BevelBorder; +/** + * DataSelectionView is a popup menu used for selecting data elements. + * It extends JPopupMenu and is styled with a gray background and a raised bevel border. + */ public class DataSelectionView extends JPopupMenu { + /** + * Constructs a DataSelectionView with the given controller. + * + * @param controller The ElementController to handle UI events. + */ public DataSelectionView(ElementController controller) { setBackground(Color.GRAY); setBorder(new BevelBorder(BevelBorder.RAISED)); diff --git a/src/main/java/edu/rpi/legup/ui/boardview/ElementSelection.java b/src/main/java/edu/rpi/legup/ui/boardview/ElementSelection.java index 8e6f2cb18..9ad4132d6 100644 --- a/src/main/java/edu/rpi/legup/ui/boardview/ElementSelection.java +++ b/src/main/java/edu/rpi/legup/ui/boardview/ElementSelection.java @@ -3,25 +3,48 @@ import java.awt.*; import java.util.ArrayList; +/** + * ElementSelection manages the selection and hover states of ElementViews. + * It maintains a list of selected elements, the currently hovered element, and the mouse point location. + */ public class ElementSelection { private ArrayList selection; private ElementView hover; private Point mousePoint; + /** + * Constructs an ElementSelection instance with an empty selection and no hover or mouse point + */ public ElementSelection() { this.selection = new ArrayList<>(); this.hover = null; this.mousePoint = null; } + /** + * Gets the list of currently selected ElementViews. + * + * @return the list of selected ElementViews + */ public ArrayList getSelection() { return selection; } + /** + * Gets the first ElementView in the selection, or null if the selection is empty. + * + * @return the first selected ElementView, or null if there are no selections + */ public ElementView getFirstSelection() { return selection.size() == 0 ? null : selection.get(0); } + /** + * Toggles the selection state of an ElementView. + * If the ElementView is currently selected, it is deselected. Otherwise, it is selected. + * + * @param elementView the ElementView to toggle + */ public void toggleSelection(ElementView elementView) { if (selection.contains(elementView)) { selection.remove(elementView); @@ -32,12 +55,20 @@ public void toggleSelection(ElementView elementView) { } } + /** + * Sets a new selection, clearing the previous selection and selecting the specified ElementView. + * + * @param elementView the ElementView to select + */ public void newSelection(ElementView elementView) { clearSelection(); selection.add(elementView); elementView.setSelected(true); } + /** + * Clears the selection and deselects all ElementViews + */ public void clearSelection() { for (ElementView elementView : selection) { elementView.setSelected(false); @@ -45,10 +76,20 @@ public void clearSelection() { selection.clear(); } + /** + * Gets the currently hovered ElementView. + * + * @return the currently hovered ElementView, or null if no element is hovered + */ public ElementView getHover() { return hover; } + /** + * Sets a new hovered ElementView, updating the hover state of the previous and new elements. + * + * @param newHovered the new ElementView to be hovered + */ public void newHover(ElementView newHovered) { newHovered.setHover(true); if (hover != null) { @@ -57,6 +98,9 @@ public void newHover(ElementView newHovered) { hover = newHovered; } + /** + * Clears the current hover state if there exists one + */ public void clearHover() { if (hover != null) { hover.setHover(false); @@ -64,10 +108,20 @@ public void clearHover() { } } + /** + * Gets the current mouse point location. + * + * @return the current mouse point location + */ public Point getMousePoint() { return mousePoint; } + /** + * Sets the mouse point location. + * + * @param point the new mouse point location + */ public void setMousePoint(Point point) { this.mousePoint = point; } diff --git a/src/main/java/edu/rpi/legup/ui/boardview/ElementView.java b/src/main/java/edu/rpi/legup/ui/boardview/ElementView.java index 83b2cb099..ad6cd3d3f 100644 --- a/src/main/java/edu/rpi/legup/ui/boardview/ElementView.java +++ b/src/main/java/edu/rpi/legup/ui/boardview/ElementView.java @@ -9,6 +9,10 @@ import java.awt.image.BufferedImage; import javax.swing.*; +/** + * ElementView represents a visual representation of a PuzzleElement. + * It handles drawing, selection, hover states, and interaction with the PuzzleElement. + */ public abstract class ElementView implements Shape { protected int index; protected Point location; @@ -73,6 +77,11 @@ public void draw(Graphics2D graphics2D) { } } + /** + * Draws the basic element representation (e.g., border, text) on the provided Graphics2D context. + * + * @param graphics2D the Graphics2D context to use for drawing + */ public void drawElement(Graphics2D graphics2D) { graphics2D.setStroke(new BasicStroke(1)); graphics2D.draw( @@ -87,8 +96,19 @@ public void drawElement(Graphics2D graphics2D) { graphics2D.drawString(String.valueOf(puzzleElement.getData()), xText, yText); } + /** + * Draws additional elements for given PuzzleElements (default implementation does nothing). + * Overriden in some puzzle element views. + * + * @param graphics2D the Graphics2D context to use for drawing + */ public void drawGiven(Graphics2D graphics2D) {} + /** + * Draws a hover effect on the ElementView. + * + * @param graphics2D the Graphics2D context to use for drawing + */ public void drawHover(Graphics2D graphics2D) { graphics2D.setColor(hoverColor); graphics2D.setStroke(new BasicStroke(2)); @@ -97,6 +117,11 @@ public void drawHover(Graphics2D graphics2D) { location.x + 1.5f, location.y + 1.5f, size.width - 3, size.height - 3)); } + /** + * Draws a modified effect on the ElementView. + * + * @param graphics2D the Graphics2D context to use for drawing + */ public void drawModified(Graphics2D graphics2D) { graphics2D.setColor(puzzleElement.isValid() ? modifiedColor : invalidColor); graphics2D.setStroke(new BasicStroke(2)); @@ -105,6 +130,11 @@ public void drawModified(Graphics2D graphics2D) { location.x + 1.5f, location.y + 1.5f, size.width - 3, size.height - 3)); } + /** + * Draws a case rule picker on the ElementView. + * + * @param graphics2D the Graphics2D context to use for drawing + */ public void drawCase(Graphics2D graphics2D) { graphics2D.setColor(caseColor); graphics2D.fill( @@ -112,6 +142,11 @@ public void drawCase(Graphics2D graphics2D) { location.x + 1.5f, location.y + 1.5f, size.width - 3, size.height - 3)); } + /** + * Creates an image representation of the ElementView. + * + * @return a BufferedImage of the ElementView + */ public BufferedImage getImage() { BufferedImage image = new BufferedImage(size.width, size.height, BufferedImage.TYPE_INT_RGB); @@ -193,10 +228,20 @@ public void setPuzzleElement(PuzzleElement data) { this.puzzleElement = data; } + /** + * Checks if the case picker should be shown for this ElementView + * + * @return true if the case picker should be shown, false otherwise + */ public boolean isShowCasePicker() { return showCasePicker; } + /** + * Sets whether the case picker should be shown for this ElementView + * + * @param showCasePicker true if the case picker should be shown, false otherwise + */ public void setShowCasePicker(boolean showCasePicker) { this.showCasePicker = showCasePicker; } @@ -281,6 +326,13 @@ public JMenuItem getSelectionMenuItem() { return item; } + /** + * Determines if the specified point (x, y) is within the bounds of this ElementView + * + * @param x the x-coordinate of the point to check + * @param y the y-coordinate of the point to check + * @return {@code true} if the point is within the bounds of this ElementView; {@code false} otherwise + */ @Override public boolean contains(double x, double y) { return x >= location.x @@ -289,17 +341,38 @@ public boolean contains(double x, double y) { && y <= location.y + size.height; } + /** + * Determines if the specified Point2D object is within the bounds of this ElementView + * + * @param point the Point2D object representing the point to check + * @return {@code true} if the point is within the bounds of this ElementView; {@code false} otherwise + */ @Override public boolean contains(Point2D point) { return contains(point.getX(), point.getY()); } + /** + * Determines if the specified rectangle defined by (x, y, width, height) intersects with the bounds of this ElementView. + * + * @param x The x-coordinate of the rectangle to check + * @param y The y-coordinate of the rectangle to check + * @param width The width of the rectangle to check + * @param height The height of the rectangle to check + * @return {@code true} if the rectangle intersects with the bounds of this ElementView; {@code false} otherwise + */ @Override public boolean intersects(double x, double y, double width, double height) { return (x + width >= location.x && x <= location.x + size.width) || (y + height >= location.y && y <= location.y + size.height); } + /** + * Determines if the specified Rectangle2D object intersects with the bounds of this ElementView. + * + * @param rectangle2D the Rectangle2D object representing the rectangle to check + * @return {@code true} if the rectangle intersects with the bounds of this ElementView; {@code false} otherwise + */ @Override public boolean intersects(Rectangle2D rectangle2D) { return intersects( @@ -309,12 +382,27 @@ public boolean intersects(Rectangle2D rectangle2D) { rectangle2D.getHeight()); } + /** + * Determines if the specified rectangle defined by (x, y, width, height) is entirely contained within the bounds of this ElementView + * + * @param x the x-coordinate of the rectangle to check + * @param y the y-coordinate of the rectangle to check + * @param width the width of the rectangle to check + * @param height the height of the rectangle to check + * @return {@code true} if the rectangle is entirely contained within the bounds of this ElementView; {@code false} otherwise + */ @Override public boolean contains(double x, double y, double width, double height) { return (x + width >= location.x && x <= location.x + size.width) && (y + height >= location.y && y <= location.y + size.height); } + /** + * Determines if the specified Rectangle2D object is entirely contained within the bounds of this ElementView. + * + * @param rectangle2D the Rectangle2D object representing the rectangle to check + * @return {@code true} if the rectangle is entirely contained within the bounds of this ElementView; {@code false} otherwise + */ @Override public boolean contains(Rectangle2D rectangle2D) { return contains( @@ -324,22 +412,48 @@ public boolean contains(Rectangle2D rectangle2D) { rectangle2D.getHeight()); } + + /** + * Returns an iterator over the path geometry of this ElementView. The iterator provides access to the path's + * segments and their coordinates, which can be used for rendering or hit testing. + * + * @param at the AffineTransform to apply to the path geometry + * @return a PathIterator that iterates over the path geometry of this ElementView + */ @Override public PathIterator getPathIterator(AffineTransform at) { return new Rectangle(location.x, location.y, size.width, size.height).getPathIterator(at); } + /** + * Returns an iterator over the path geometry of this ElementView with the specified flatness. The iterator provides + * access to the path's segments and their coordinates, which can be used for rendering or hit testing. + * + * @param at the AffineTransform to apply to the path geometry + * @param flatness the maximum distance that the line segments can deviate from the true path + * @return a PathIterator that iterates over the path geometry of this ElementView + */ @Override public PathIterator getPathIterator(AffineTransform at, double flatness) { return new Rectangle(location.x, location.y, size.width, size.height) .getPathIterator(at, flatness); } + /** + * Returns the bounding rectangle of this ElementView + * + * @return a Rectangle representing the bounding box of this ElementView + */ @Override public Rectangle getBounds() { return new Rectangle(location.x, location.y, size.width, size.height); } + /** + * Returns the bounding rectangle of this ElementView as a Rectangle2D + * + * @return a Rectangle2D representing the bounding box of this ElementView + */ @Override public Rectangle2D getBounds2D() { return new Rectangle(location.x, location.y, size.width, size.height); diff --git a/src/main/java/edu/rpi/legup/ui/boardview/GridBoardView.java b/src/main/java/edu/rpi/legup/ui/boardview/GridBoardView.java index c40303192..1baa34b3a 100644 --- a/src/main/java/edu/rpi/legup/ui/boardview/GridBoardView.java +++ b/src/main/java/edu/rpi/legup/ui/boardview/GridBoardView.java @@ -5,6 +5,11 @@ import java.awt.Color; import java.awt.Dimension; +/** + * A view class for a grid-based board that displays elements in a grid layout. + * This class extends BoardView and is responsible for managing and rendering + * grid-based elements. + */ public class GridBoardView extends BoardView { protected Dimension gridSize; protected Dimension elementSize; @@ -51,6 +56,14 @@ public GridElementView getElement(int index) { return null; } + /** + * Retrieves the GridElementView at the specified grid coordinates (xIndex, yIndex). + * Returns null if the coordinates are out of bounds. + * + * @param xIndex the x-coordinate (column) of the element view to retrieve + * @param yIndex the y-coordinate (row) of the element view to retrieve + * @return the GridElementView at the specified coordinates, or null if out of bounds + */ public GridElementView getElement(int xIndex, int yIndex) { if (xIndex < gridSize.width && yIndex < gridSize.height) { return (GridElementView) elementViews.get(yIndex * gridSize.width + xIndex); @@ -58,7 +71,10 @@ public GridElementView getElement(int xIndex, int yIndex) { return null; } - /** Initializes the initial dimension of the viewport for the GridBoardView */ + /** + * Initializes the initial dimension of the viewport for the GridBoardView. + * Sets the size of the board view and adjusts the zoom to fit. + */ @Override public void initSize() { setSize(getProperSize()); @@ -66,9 +82,9 @@ public void initSize() { } /** - * Helper method to determine the proper dimension of the grid view + * Determines the proper dimension of the grid view based on grid size and element size. * - * @return proper dimension of the grid view + * @return the dimension of the grid view */ protected Dimension getProperSize() { Dimension boardViewSize = new Dimension(); @@ -77,10 +93,21 @@ protected Dimension getProperSize() { return boardViewSize; } + /** + * Retrieves the selection popup menu for data selection. + * Currently returns null as there is no implementation. + * + * @return null + */ public DataSelectionView getSelectionPopupMenu() { return null; } + /** + * Gets the size of each element in the grid + * + * @return the dimension of each element in the grid + */ public Dimension getElementSize() { return this.elementSize; } diff --git a/src/main/java/edu/rpi/legup/ui/boardview/GridElementView.java b/src/main/java/edu/rpi/legup/ui/boardview/GridElementView.java index 440b3a693..31e8fcd6c 100644 --- a/src/main/java/edu/rpi/legup/ui/boardview/GridElementView.java +++ b/src/main/java/edu/rpi/legup/ui/boardview/GridElementView.java @@ -2,6 +2,11 @@ import edu.rpi.legup.model.gameboard.GridCell; +/** + * A view class for a grid cell element in the board. + * This class extends ElementView and represents a specific type of element view + * associated with a GridCell. + */ public class GridElementView extends ElementView { public GridElementView(GridCell cell) { super(cell); diff --git a/src/main/java/edu/rpi/legup/ui/boardview/SelectionItemView.java b/src/main/java/edu/rpi/legup/ui/boardview/SelectionItemView.java index b2d3e31dd..15deb86d1 100644 --- a/src/main/java/edu/rpi/legup/ui/boardview/SelectionItemView.java +++ b/src/main/java/edu/rpi/legup/ui/boardview/SelectionItemView.java @@ -3,28 +3,68 @@ import edu.rpi.legup.model.gameboard.PuzzleElement; import javax.swing.*; +/** + * A menu item view class that represents a selectable item in a menu, associated with a PuzzleElement. + * This class extends JMenuItem and provides additional functionality to + * handle PuzzleElement data. + */ public class SelectionItemView extends JMenuItem { private PuzzleElement data; + /** + * Constructs a SelectionItemView with the specified PuzzleElement and icon. + * Initializes the menu item with the given icon and associates it with the + * provided PuzzleElement. + * + * @param data the PuzzleElement associated with this menu item + * @param icon the icon to be displayed on the menu item + */ public SelectionItemView(PuzzleElement data, Icon icon) { super(icon); this.data = data; } + /** + * Constructs a SelectionItemView with the specified PuzzleElement and display text. + * Initializes the menu item with the given display text and associates it with the + * provided PuzzleElement. + * + * @param data the PuzzleElement associated with this menu item + * @param display the text to be displayed on the menu item + */ public SelectionItemView(PuzzleElement data, String display) { super(display); this.data = data; } + /** + * Constructs a SelectionItemView with the specified PuzzleElement and display integer. + * Initializes the menu item with the integer converted to a string and associates it with + * the provided PuzzleElement. + * + * @param data the PuzzleElement associated with this menu item + * @param display the integer to be displayed on the menu item + */ public SelectionItemView(PuzzleElement data, int display) { super(String.valueOf(display)); this.data = data; } + /** + * Constructs a SelectionItemView with the specified PuzzleElement. + * Initializes the menu item with the data's integer representation as display text. + * + * @param data the PuzzleElement associated with this menu item + */ public SelectionItemView(PuzzleElement data) { this(data, (Integer) data.getData()); } + /** + * Gets the PuzzleElement associated with this menu item + * + * @return the PuzzleElement associated with this menu item + */ public PuzzleElement getData() { return data; } From b361a0987f735941b65d4a3f470874a288202cbd Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Sat, 10 Aug 2024 12:52:30 -0400 Subject: [PATCH 249/258] Added code specifications to all missing methods and class descriptions in all classes in ui/proofeditor/ruleview directory --- .../rulesview/CaseRulePanel.java | 6 +++ .../rulesview/ContradictionRulePanel.java | 9 ++++- .../rulesview/DirectRulePanel.java | 8 +++- .../proofeditorui/rulesview/RuleButton.java | 5 +++ .../ui/proofeditorui/rulesview/RuleFrame.java | 40 ++++++++++++++++++- .../ui/proofeditorui/rulesview/RulePanel.java | 39 +++++++++++++++++- .../rulesview/SearchBarPanel.java | 5 +++ 7 files changed, 108 insertions(+), 4 deletions(-) diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/CaseRulePanel.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/CaseRulePanel.java index 1fb0a16ab..849c5c145 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/CaseRulePanel.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/CaseRulePanel.java @@ -2,6 +2,12 @@ import javax.swing.ImageIcon; +/** + * The {@code CaseRulePanel} class is a specialized panel that represents case rules + * within a {@link RuleFrame}. It extends the {@link RulePanel} and provides + * specific functionality and UI components related to case rules. + * This class initializes with an icon and name that are specific to case rules. + */ public class CaseRulePanel extends RulePanel { /** * CaseRulePanel Constructor creates a CaseRulePanel diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/ContradictionRulePanel.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/ContradictionRulePanel.java index f695491fb..5bed7e17d 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/ContradictionRulePanel.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/ContradictionRulePanel.java @@ -2,7 +2,14 @@ import javax.swing.*; -public class ContradictionRulePanel extends RulePanel { +/** + * The {@code ContradictionRulePanel} class is a specialized panel that represents contradiction rules + * within a {@link RuleFrame}. It extends the {@link RulePanel} and provides + * specific functionality and UI components related to contradiction rules. + * This class initializes with an icon and name that are specific to contradiction rules. + */ + + public class ContradictionRulePanel extends RulePanel { /** * ContradictionRulePanel Constructor creates a ContradictionRulePanel * diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/DirectRulePanel.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/DirectRulePanel.java index 2795f2df7..c1562eb70 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/DirectRulePanel.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/DirectRulePanel.java @@ -4,7 +4,13 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -public class DirectRulePanel extends RulePanel { +/** + * The {@code DirectRulePanel} class is a specialized panel that represents direct rules + * within a {@link RuleFrame}. It extends the {@link RulePanel} and provides + * specific functionality and UI components related to direct rules. + * This class initializes with an icon and name that are specific to direct rules. + */ + public class DirectRulePanel extends RulePanel { private static final Logger LOGGER = LogManager.getLogger(DirectRulePanel.class.getName()); /** diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RuleButton.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RuleButton.java index e9c274250..7222603bc 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RuleButton.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RuleButton.java @@ -3,6 +3,11 @@ import edu.rpi.legup.model.rules.Rule; import javax.swing.*; +/** + * The {@code RuleButton} class is a custom button that represents a rule in the user interface. + * It extends {@link JButton} and is designed to display a rule's name and icon. + * The button is initialized with a {@link Rule} object, which provides the name and icon for the button. + */ public class RuleButton extends JButton { private Rule rule; diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RuleFrame.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RuleFrame.java index 6279f93a4..3131f474d 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RuleFrame.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RuleFrame.java @@ -10,6 +10,13 @@ import javax.swing.*; import javax.swing.border.TitledBorder; +/** + * The {@code RuleFrame} class is a panel that contains and manages multiple rule-related panels + * within a tabbed interface. It extends {@link JPanel} and organizes the display of various rule types + * such as direct rules, contradiction rules, and case rules. + * The frame uses a {@link JTabbedPane} to allow users to switch between different rule panels. + * It also includes a search bar panel and a status label for displaying additional information. + */ public class RuleFrame extends JPanel { private static final String checkBox = " \u2714 "; private static final String xBox = " \u2718 "; @@ -28,6 +35,12 @@ public class RuleFrame extends JPanel { private RuleController controller; + /** + * Constructs a new {@code RuleFrame} instance. + * Initializes the frame with tabs for the different rule panels, a search bar panel, and a status label. + * + * @param controller the {@link RuleController} instance that manages the rules for this frame + */ public RuleFrame(RuleController controller) { MaterialTabbedPaneUI tabOverride = @@ -118,7 +131,7 @@ public void resetSize() { /** * Set the status label to a value. Use resetStatus to clear it. * - * @param check true iff we want a check box, if false we'll have a red x box + * @param check true if we want a checkbox, if false we'll have a red x box * @param text the text we're setting the label to display */ public void setStatus(boolean check, String text) { @@ -156,22 +169,47 @@ public RuleController getController() { return controller; } + /** + * Gets the JTabbedPane used in this frame + * + * @return the JTabbedPane instance + */ public JTabbedPane getTabbedPane() { return tabbedPane; } + /** + * Gets the {@code DirectRulePanel} contained in this frame + * + * @return the {@link DirectRulePanel} instance + */ public DirectRulePanel getDirectRulePanel() { return DirectRulePanel; } + /** + * Gets the {@code CaseRulePanel} contained in this frame + * + * @return the {@link CaseRulePanel} instance + */ public CaseRulePanel getCasePanel() { return casePanel; } + /** + * Gets the {@code ContradictionRulePanel} contained in this frame + * + * @return the {@link ContradictionRulePanel} instance + */ public ContradictionRulePanel getContradictionPanel() { return contradictionPanel; } + /** + * Gets the {@code SearchBarPanel} contained in this frame + * + * @return the {@link SearchBarPanel} instance + */ public SearchBarPanel getSearchPanel() { return searchPanel; } diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RulePanel.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RulePanel.java index 5a26b49fb..4c9ebf882 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RulePanel.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RulePanel.java @@ -9,6 +9,10 @@ import java.util.List; import javax.swing.*; +/** + * Abstract base class for panels displaying rules. Each subclass will represent a specific type + * of rule panel (e.g., DirectRulePanel, CaseRulePanel). + */ public abstract class RulePanel extends JPanel { protected ImageIcon icon; protected String name; @@ -32,7 +36,7 @@ public RulePanel(RuleFrame ruleFrame) { } /** - * Gets the rule rule buttons + * Gets the array of rule buttons * * @return rule ruleButtons */ @@ -76,6 +80,9 @@ public void setRules(List rules) { revalidate(); } + /** + * Updates the rules displayed by reloading images and setting the rules again. + */ public void updateRules() { for (Rule rule : rules) { rule.loadImage(); @@ -331,28 +338,58 @@ public List getRules() { return rules; } + /** + * Gets the icon associated with this panel + * + * @return The ImageIcon associated with this panel + */ public ImageIcon getIcon() { return icon; } + /** + * Sets the icon for this panel + * + * @return the ImageIcon associated with this panel + */ public void setIcon(ImageIcon icon) { this.icon = icon; } + /** + * Gets the name of this panel + * + * @return the name of this panel in a String + */ @Override public String getName() { return name; } + /** + * Sets the name of this panel + * + * @param name the name to set for this panel + */ @Override public void setName(String name) { this.name = name; } + /** + * Gets the tooltip text associated with this panel + * + * @return the tooltip text of this panel + */ public String getToolTip() { return toolTip; } + /** + * Sets the tooltip text for this panel + * + * @param toolTip the tooltip text to set for this panel + */ public void setToolTip(String toolTip) { this.toolTip = toolTip; } diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/SearchBarPanel.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/SearchBarPanel.java index aba4707cd..842859ce2 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/SearchBarPanel.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/SearchBarPanel.java @@ -2,6 +2,11 @@ import javax.swing.*; + +/** + * The {@code SearchBarPanel} class creates a panel that allows users to search for rules within the rule frame. + * This panel provides a search bar for entering rule names and finding corresponding rules. + */ public class SearchBarPanel extends RulePanel { /** * SearchBarPanel Constructor creates a SearchBarPanel From 63c3a9d8a9befb64b7f82c4269637caf6e900e59 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Sat, 10 Aug 2024 13:49:46 -0400 Subject: [PATCH 250/258] Removed PuzzleEditorDialog class rather implemented functionaliy directly into HomePanel --- src/main/java/edu/rpi/legup/ui/HomePanel.java | 11 +++++++++- .../edu/rpi/legup/ui/PuzzleEditorDialog.java | 20 ------------------- 2 files changed, 10 insertions(+), 21 deletions(-) delete mode 100644 src/main/java/edu/rpi/legup/ui/PuzzleEditorDialog.java diff --git a/src/main/java/edu/rpi/legup/ui/HomePanel.java b/src/main/java/edu/rpi/legup/ui/HomePanel.java index 29e3600d8..f43095ad7 100644 --- a/src/main/java/edu/rpi/legup/ui/HomePanel.java +++ b/src/main/java/edu/rpi/legup/ui/HomePanel.java @@ -513,7 +513,16 @@ private void openNewPuzzleDialog() { } private void openPuzzleEditorDialog() { - PuzzleEditorDialog ped = new PuzzleEditorDialog(this); + String game = ""; + int r = 0; + int c = 0; + + try { + this.openEditorWithNewPuzzle(game, r, c); + } catch (IllegalArgumentException e) { + System.out.println("Failed to open editor with new puzzle"); + e.printStackTrace(System.out); + } } private void checkProofAll() { diff --git a/src/main/java/edu/rpi/legup/ui/PuzzleEditorDialog.java b/src/main/java/edu/rpi/legup/ui/PuzzleEditorDialog.java deleted file mode 100644 index 46c811732..000000000 --- a/src/main/java/edu/rpi/legup/ui/PuzzleEditorDialog.java +++ /dev/null @@ -1,20 +0,0 @@ -package edu.rpi.legup.ui; - -import javax.swing.*; - -public class PuzzleEditorDialog { - - public PuzzleEditorDialog(HomePanel homePanel) { - String game = ""; - int r = 0; - int c = 0; - - try { - homePanel.openEditorWithNewPuzzle(game, r, c); - } catch (IllegalArgumentException e) { - System.out.println("Failed to open editor with new puzzle"); - e.printStackTrace(System.out); - } - } - -} From 12a3014862280e78eccf41224e9343a4a32105ad Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Sat, 10 Aug 2024 13:57:18 -0400 Subject: [PATCH 251/258] Added code specifications to all missing methods and class descriptions in all classes in ui/proofeditor/treeview directory --- .../treeview/TreeElementView.java | 10 +- .../proofeditorui/treeview/TreeNodeView.java | 74 +++++++++++ .../ui/proofeditorui/treeview/TreePanel.java | 55 ++++++++ .../treeview/TreeToolBarButton.java | 14 ++ .../treeview/TreeToolBarName.java | 4 + .../treeview/TreeToolbarPanel.java | 5 + .../treeview/TreeTransitionView.java | 115 ++++++++++++++--- .../ui/proofeditorui/treeview/TreeView.java | 122 ++++++++++++++++-- .../treeview/TreeViewSelection.java | 5 + 9 files changed, 374 insertions(+), 30 deletions(-) diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeElementView.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeElementView.java index 33c04717d..228e69950 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeElementView.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeElementView.java @@ -4,6 +4,12 @@ import edu.rpi.legup.model.tree.TreeElementType; import java.awt.*; +/** + * Abstract base class for views of tree elements in the tree structure. + * This class implements the Shape interface to support custom drawing and interaction + * with tree elements. + * It holds properties for rendering, interaction, and layout of the tree elements. + */ public abstract class TreeElementView implements Shape { protected TreeElement treeElement; protected double span; @@ -36,7 +42,7 @@ protected TreeElementView(TreeElementType type, TreeElement treeElement) { public abstract void draw(Graphics2D graphics2D); /** - * Gets the span for the sub tree rooted at this view + * Gets the span for the subtree rooted at this view * * @return span bounded y span */ @@ -45,7 +51,7 @@ public double getSpan() { } /** - * Sets the span for the sub tree rooted at this view. + * Sets the span for the subtree rooted at this view. * * @param span bounded y span */ diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeNodeView.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeNodeView.java index 990d96620..0e2a31bbf 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeNodeView.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeNodeView.java @@ -7,6 +7,12 @@ import java.awt.geom.*; import java.util.ArrayList; +/** + * Represents a view of a tree node in the tree structure. + * This class extends {@link TreeElementView} and provides specific rendering and interaction + * functionality for tree nodes. It includes visual properties and methods to manage the + * node's appearance, location, and its relationships with other nodes. + */ public class TreeNodeView extends TreeElementView { static final int RADIUS = 25; static final int DIAMETER = 2 * RADIUS; @@ -260,51 +266,119 @@ public int getRadius() { return RADIUS; } + /** + * Returns the bounding rectangle of this TreeNodeView + * + * @return a Rectangle representing the bounding box of this TreeNodeView + */ @Override public Rectangle getBounds() { return new Rectangle(location.x, location.y, DIAMETER, DIAMETER); } + /** + * Returns the bounding rectangle of this TreeNodeView as a Rectangle2D + * + * @return a Rectangle2D representing the bounding box of this TreeNodeView + */ @Override public Rectangle2D getBounds2D() { return new Rectangle(location.x, location.y, DIAMETER, DIAMETER); } + /** + * Determines if the specified point (x, y) is within the bounds of this TreeNodeView + * + * @param x the x-coordinate of the point to check + * @param y the y-coordinate of the point to check + * @return {@code true} if the point is within the bounds of this TreeNodeView; {@code false} otherwise + */ @Override public boolean contains(double x, double y) { return Math.sqrt(Math.pow(x - location.x, 2) + Math.pow(y - location.y, 2)) <= RADIUS; } + /** + * Determines if the specified Point2D object is within the bounds of this TreeNodeView + * + * @param p the Point2D object representing the point to check + * @return {@code true} if the point is within the bounds of this TreeNodeView; {@code false} otherwise + */ @Override public boolean contains(Point2D p) { return contains(p.getX(), p.getY()); } + /** + * Determines if the specified rectangle defined by (x, y, width, height) intersects with the bounds of this TreeNodeView. + * + * @param x The x-coordinate of the rectangle to check + * @param y The y-coordinate of the rectangle to check + * @param w The width of the rectangle to check + * @param h The height of the rectangle to check + * @return {@code true} if the rectangle intersects with the bounds of this TreeNodeView; {@code false} otherwise + */ @Override public boolean intersects(double x, double y, double w, double h) { return false; } + /** + * Determines if the specified Rectangle2D object intersects with the bounds of this TreeNodeView. + * + * @param r the Rectangle2D object representing the rectangle to check + * @return {@code true} if the rectangle intersects with the bounds of this TreeNodeView; {@code false} otherwise + */ @Override public boolean intersects(Rectangle2D r) { return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight()); } + /** + * Determines if the specified rectangle defined by (x, y, width, height) is entirely contained within the bounds of this TreeNodeView + * + * @param x the x-coordinate of the rectangle to check + * @param y the y-coordinate of the rectangle to check + * @param w the width of the rectangle to check + * @param h the height of the rectangle to check + * @return {@code true} if the rectangle is entirely contained within the bounds of this TreeNodeView; {@code false} otherwise + */ @Override public boolean contains(double x, double y, double w, double h) { return false; } + /** + * Determines if the specified Rectangle2D object is entirely contained within the bounds of this TreeNodeView. + * + * @param r the Rectangle2D object representing the rectangle to check + * @return {@code true} if the rectangle is entirely contained within the bounds of this TreeNodeView; {@code false} otherwise + */ @Override public boolean contains(Rectangle2D r) { return false; } + /** + * Returns an iterator over the path geometry of this TreeNodeView. The iterator provides access to the path's + * segments and their coordinates, which can be used for rendering or hit testing. + * + * @param at the AffineTransform to apply to the path geometry + * @return a PathIterator that iterates over the path geometry of this TreeNodeView + */ @Override public PathIterator getPathIterator(AffineTransform at) { return null; } + /** + * Returns an iterator over the path geometry of this TreeNodeView with the specified flatness. The iterator provides + * access to the path's segments and their coordinates, which can be used for rendering or hit testing. + * + * @param at the AffineTransform to apply to the path geometry + * @param flatness the maximum distance that the line segments can deviate from the true path + * @return a PathIterator that iterates over the path geometry of this TreeNodeView + */ @Override public PathIterator getPathIterator(AffineTransform at, double flatness) { return null; diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreePanel.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreePanel.java index b6a29f2b5..4bef664bd 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreePanel.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreePanel.java @@ -17,6 +17,12 @@ import javax.swing.JPanel; import javax.swing.border.TitledBorder; + +/** + * {@code TreePanel} is a JPanel that manages and displays a tree view with associated toolbar and status information. + * It provides methods to interact with the tree view, such as adding, deleting, and merging tree elements, + * and updating the status based on actions performed. + */ public class TreePanel extends JPanel { public boolean modifiedSinceSave = false; public boolean modifiedSinceUndoPush = false; @@ -29,6 +35,9 @@ public class TreePanel extends JPanel { private JLabel status; + /** + * Constructs a {@code TreePanel} and initializes the UI components. + */ public TreePanel(/*LegupUI legupUI*/ ) { // this.legupUI = legupUI; @@ -60,10 +69,20 @@ public TreePanel(/*LegupUI legupUI*/ ) { updateStatusTimer = 0; } + /** + * Repaints the tree view with the provided {@link Tree} object + * + * @param tree the {@link Tree} object to update the view with + */ public void repaintTreeView(Tree tree) { treeView.updateTreeView(tree); } + /** + * Updates the status of the panel based on changes to the {@link Board} + * + * @param board the {@link Board} object representing the current board state + */ public void boardDataChanged(Board board) { modifiedSinceSave = true; modifiedSinceUndoPush = true; @@ -71,6 +90,11 @@ public void boardDataChanged(Board board) { // colorTransitions(); } + /** + * Updates the status display based on the status timer. + * If the timer is greater than 0, the status will not be updated. + * Otherwise, it clears the status text. + */ public void updateStatus() { updateStatusTimer = ((updateStatusTimer - 1) > 0) ? (updateStatusTimer - 1) : 0; if (updateStatusTimer > 0) { @@ -79,22 +103,41 @@ public void updateStatus() { this.status.setText(""); } + /** + * Updates the status display with the given status string + * + * @param statusString the status string to display + */ public void updateStatus(String statusString) { status.setForeground(Color.BLACK); status.setFont(MaterialFonts.REGULAR); status.setText(statusString); } + /** + * Updates the status display as an error with an error message + * + * @param error the error message to display + */ public void updateError(String error) { status.setForeground(Color.RED); status.setFont(MaterialFonts.ITALIC); status.setText(error); } + /** + * Gets the {@link TreeView} instance associated with this panel + * + * @return the {@link TreeView} instance + */ public TreeView getTreeView() { return treeView; } + /** + * Adds a new tree element by executing an {@link AddTreeElementCommand}. + * If the command cannot be executed, it updates the status display with an error and error message. + */ public void add() { TreeViewSelection selection = treeView.getSelection(); @@ -107,6 +150,10 @@ public void add() { } } + /** + * Deletes the selected tree element by executing a {@link DeleteTreeElementCommand}. + * If the command cannot be executed, it updates the status display with an error and an error message. + */ public void delete() { TreeViewSelection selection = treeView.getSelection(); @@ -119,6 +166,10 @@ public void delete() { } } + /** + * Merges selected tree elements by executing a {@link MergeCommand}. + * If the command cannot be executed, it updates the status display with an error and an error message. + */ public void merge() { TreeViewSelection selection = treeView.getSelection(); @@ -131,6 +182,10 @@ public void merge() { } } + /** + * Toggles the collapsed state of the selected tree elements. + * If an element is collapsed, it will be expanded, and vice versa. + */ public void collapse() { TreeViewSelection selection = treeView.getSelection(); for (TreeElementView view : selection.getSelectedViews()) { diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeToolBarButton.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeToolBarButton.java index 002092155..214c735df 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeToolBarButton.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeToolBarButton.java @@ -3,11 +3,20 @@ import java.awt.Dimension; import javax.swing.*; +/** + * {@code TreeToolBarButton} is a JButton that represents a button in the tree toolbar. + */ public class TreeToolBarButton extends JButton { private TreeToolBarName name; private final Dimension MINIMUM_DIMENSION = new Dimension(60, 60); + /** + * Constructs a {@code TreeToolBarButton} with the specified icon and name. + * + * @param imageIcon the {@link ImageIcon} to be displayed on the button + * @param name the {@link TreeToolBarName} associated with this button + */ public TreeToolBarButton(ImageIcon imageIcon, TreeToolBarName name) { super(imageIcon); this.name = name; @@ -16,6 +25,11 @@ public TreeToolBarButton(ImageIcon imageIcon, TreeToolBarName name) { this.setFocusPainted(false); } + /** + * Gets the {@link TreeToolBarName} associated with this button + * + * @return the {@link TreeToolBarName} associated with this button + */ public TreeToolBarName getToolBarName() { return name; } diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeToolBarName.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeToolBarName.java index c805021be..3aec664be 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeToolBarName.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeToolBarName.java @@ -1,5 +1,9 @@ package edu.rpi.legup.ui.proofeditorui.treeview; +/** + * {@code TreeToolBarName} defines the names of actions represented by buttons in the tree toolbar. + * These actions are used for managing tree elements within the UI. + */ public enum TreeToolBarName { ADD_CHILD, DEL_CHILD, diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeToolbarPanel.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeToolbarPanel.java index 8f3ebfc23..500ed29c5 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeToolbarPanel.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeToolbarPanel.java @@ -3,6 +3,11 @@ import java.awt.*; import javax.swing.*; + +/** + * {@code TreeToolbarPanel} is a JPanel that provides a toolbar for managing tree elements in the tree view. + * It includes buttons for adding, deleting, merging, and collapsing nodes. + */ public class TreeToolbarPanel extends JPanel { private TreePanel treePanel; private TreeToolBarButton addChild, delChild, merge, collapse; diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeTransitionView.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeTransitionView.java index b022ac596..25c67bb5a 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeTransitionView.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeTransitionView.java @@ -10,6 +10,11 @@ import java.util.ArrayList; import java.util.List; +/** + * {@code TreeTransitionView} is a visual representation of a tree transition in the tree view. + * It extends TreeElementView and displays a transition arrow between tree nodes and handles various + * visual states such as selection, hover, and correctness. + */ public class TreeTransitionView extends TreeElementView { static final int RADIUS = 25; static final int DIAMETER = 2 * RADIUS; @@ -266,87 +271,165 @@ public void removeParentView(TreeNodeView nodeView) { } } - public Point getEndPoint() { - return endPoint; - } - - public void setEndPoint(Point endPoint) { - this.endPoint = endPoint; - } - + /** + * Gets the x-coordinate of the end point of the transition arrow + * + * @return the x-coordinate of the end point + */ public int getEndX() { return endPoint.x; } + /** + * Sets the x-coordinate of the end point of the transition arrow + * + * @param x the new x-coordinate of the end point + */ public void setEndX(int x) { this.endPoint.x = x; } + /** + * Gets the y-coordinate of the end point of the transition arrow + * + * @return the y-coordinate of the end point + */ public int getEndY() { return endPoint.y; } + /** + * Sets the y-coordinate of the end point of the transition arrow + * + * @param y the new y-coordinate of the end point + */ public void setEndY(int y) { this.endPoint.y = y; } - public List getLineStartPoints() { - return lineStartPoints; - } - - public void setLineStartPoints(List lineStartPoints) { - this.lineStartPoints = lineStartPoints; - } - + /** + * Gets the start point at the specified index from the list of start points + * + * @param index the index of the start point to retrieve + * @return the start point at the specified index, or null if the index is out of range + */ public Point getLineStartPoint(int index) { return index < lineStartPoints.size() ? lineStartPoints.get(index) : null; } + /** + * Returns the bounding rectangle of this TreeTransitionView + * + * @return a Rectangle representing the bounding box of this TreeTransitionView + */ @Override public Rectangle getBounds() { return arrowhead.getBounds(); } + /** + * Returns the bounding rectangle of this TreeTransitionView as a Rectangle2D + * + * @return a Rectangle2D representing the bounding box of this TreeTransitionView + */ @Override public Rectangle2D getBounds2D() { return arrowhead.getBounds2D(); } + /** + * Determines if the specified point (x, y) is within the bounds of this TreeTransitionView + * + * @param x the x-coordinate of the point to check + * @param y the y-coordinate of the point to check + * @return {@code true} if the point is within the bounds of this TreeTransitionView; {@code false} otherwise + */ @Override public boolean contains(double x, double y) { return arrowhead.contains(x, y); } + /** + * Determines if the specified Point2D object is within the bounds of this TreeTransitionView + * + * @param p the Point2D object representing the point to check + * @return {@code true} if the point is within the bounds of this TreeTransitionView; {@code false} otherwise + */ @Override public boolean contains(Point2D p) { return arrowhead != null && arrowhead.contains(p); } + /** + * Determines if the specified rectangle defined by (x, y, width, height) intersects with the bounds of this TreeTransitionView. + * + * @param x The x-coordinate of the rectangle to check + * @param y The y-coordinate of the rectangle to check + * @param w The width of the rectangle to check + * @param h The height of the rectangle to check + * @return {@code true} if the rectangle intersects with the bounds of this TreeTransitionView; {@code false} otherwise + */ @Override public boolean intersects(double x, double y, double w, double h) { return arrowhead.intersects(x, y, w, h); } + /** + * Determines if the specified Rectangle2D object intersects with the bounds of this TreeTransitionView. + * + * @param r the Rectangle2D object representing the rectangle to check + * @return {@code true} if the rectangle intersects with the bounds of this TreeTransitionView; {@code false} otherwise + */ @Override public boolean intersects(Rectangle2D r) { return arrowhead.intersects(r); } + /** + * Determines if the specified rectangle defined by (x, y, width, height) is entirely contained within the bounds of this TreeTransitionView + * + * @param x the x-coordinate of the rectangle to check + * @param y the y-coordinate of the rectangle to check + * @param w the width of the rectangle to check + * @param h the height of the rectangle to check + * @return {@code true} if the rectangle is entirely contained within the bounds of this TreeTransitionView; {@code false} otherwise + */ @Override public boolean contains(double x, double y, double w, double h) { return arrowhead.contains(x, y, w, h); } + /** + * Determines if the specified Rectangle2D object is entirely contained within the bounds of this TreeTransitionView. + * + * @param r the Rectangle2D object representing the rectangle to check + * @return {@code true} if the rectangle is entirely contained within the bounds of this TreeTransitionView; {@code false} otherwise + */ @Override public boolean contains(Rectangle2D r) { return arrowhead.contains(r); } + /** + * Returns an iterator over the path geometry of this TreeTransitionView. The iterator provides access to the path's + * segments and their coordinates, which can be used for rendering or hit testing. + * + * @param at the AffineTransform to apply to the path geometry + * @return a PathIterator that iterates over the path geometry of this TreeTransitionView + */ @Override public PathIterator getPathIterator(AffineTransform at) { return arrowhead.getPathIterator(at); } + /** + * Returns an iterator over the path geometry of this TreeTransitionView with the specified flatness. The iterator provides + * access to the path's segments and their coordinates, which can be used for rendering or hit testing. + * + * @param at the AffineTransform to apply to the path geometry + * @param flatness the maximum distance that the line segments can deviate from the true path + * @return a PathIterator that iterates over the path geometry of this TreeTransitionView + */ @Override public PathIterator getPathIterator(AffineTransform at, double flatness) { return arrowhead.getPathIterator(at, flatness); diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeView.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeView.java index f426168c8..490cf1480 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeView.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeView.java @@ -26,6 +26,12 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +/** + * The {@code TreeView} class provides a graphical representation of a {@code Tree} structure, + * allowing interaction and visualization of tree elements, transitions, and selections. + * It extends {@code ScrollView} and implements {@code ITreeListener} to respond to updates + * in the tree structure. + */ public class TreeView extends ScrollView implements ITreeListener { private static final Logger LOGGER = LogManager.getLogger(TreeView.class.getName()); @@ -51,6 +57,11 @@ public class TreeView extends ScrollView implements ITreeListener { private TreeViewSelection selection; + /** + * Constructs a {@code TreeView} with the specified {@code TreeController}. + * + * @param treeController the {@code TreeController} used to manage tree operations + */ public TreeView(TreeController treeController) { super(treeController); currentStateBoxes = new ArrayList<>(); @@ -62,6 +73,11 @@ public TreeView(TreeController treeController) { selection = new TreeViewSelection(); } + /** + * Gets the current tree view selection + * + * @return the {@code TreeViewSelection} object representing the current selection + */ public TreeViewSelection getSelection() { return selection; } @@ -131,6 +147,11 @@ private TreeElementView getTreeElementView(Point point, TreeElementView elementV return null; } + /** + * Updates the tree view with the specified {@code Tree} + * + * @param tree the {@code Tree} to display in the view + */ public void updateTreeView(Tree tree) { this.tree = tree; if (selection.getSelectedViews().size() == 0) { @@ -148,6 +169,9 @@ public void setTree(Tree tree) { this.tree = tree; } + /** + * Updates the size of the tree view based on the bounds of its tree + */ public void updateTreeSize() { if (GameBoardFacade.getInstance().getTree() == null) { return; @@ -155,12 +179,19 @@ public void updateTreeSize() { setSize(bounds.getSize()); } + /** + * Resets the view if the tree bounds have been modified + */ public void reset() { if (bounds.x != 0 || bounds.y != 0) { updateTreeSize(); } } + /** + * Adjusts the zoom level to fit the entire tree within the viewport when + * the Resize Proof button is selected + */ public void zoomFit() { final int MIN_HEIGHT = 200; double fitWidth = (viewport.getWidth() - 7.0) / (getSize().width - 75); @@ -213,6 +244,11 @@ public void layoutContainer(Container parent) { }; } + /** + * Draws the tree view on the provided {@code Graphics2D} context + * + * @param graphics2D the {@code Graphics2D} context to draw on + */ public void draw(Graphics2D graphics2D) { currentStateBoxes.clear(); Tree tree = GameBoardFacade.getInstance().getTree(); @@ -235,11 +271,20 @@ public void draw(Graphics2D graphics2D) { } } + /** + * Resets the zoom level to its default state and positions the viewport from the top-left corner + */ public void zoomReset() { zoomTo(1.0); viewport.setViewPosition(new Point(0, 0)); } + /** + * Recursively redraws the tree starting from the specified node view + * + * @param graphics2D the {@code Graphics2D} context to draw on + * @param nodeView the {@code TreeNodeView} to start drawing from + */ private void redrawTree(Graphics2D graphics2D, TreeNodeView nodeView) { if (nodeView != null) { nodeView.draw(graphics2D); @@ -250,6 +295,11 @@ private void redrawTree(Graphics2D graphics2D, TreeNodeView nodeView) { } } + /** + * Removes the specified {@code TreeElementView} from the tree view + * + * @param view the {@code TreeElementView} to remove + */ public void removeTreeElement(TreeElementView view) { if (view.getType() == NODE) { TreeNodeView nodeView = (TreeNodeView) view; @@ -283,6 +333,9 @@ public void drawMouseOver(Graphics2D g) { } } + /** + * Resets the view by clearing the current tree, root node view, and selection + */ public void resetView() { this.tree = null; this.rootNodeView = null; @@ -408,8 +461,12 @@ public TreeElementView getElementView(TreeElement element) { return viewMap.get(element); } + /** + * Removes the specified {@link TreeNode} and its associated views + * + * @param node the {@link TreeNode} to be removed + */ public void removeTreeNode(TreeNode node) { - System.out.println("DELETED NODE"); viewMap.remove(node); if (node.getChildren() != null) { node.getChildren().forEach(t -> removeTreeTransition(t)); @@ -467,6 +524,11 @@ public void removeTreeNode(TreeNode node) { } } + /** + * Removes the specified {@link TreeTransition} and its associated views + * + * @param trans the {@link TreeTransition} to be removed + */ public void removeTreeTransition(TreeTransition trans) { viewMap.remove(trans); if (trans.getChildNode() != null) { @@ -502,6 +564,11 @@ public void removeTreeTransition(TreeTransition trans) { } } + /** + * Adds the specified {@link TreeNode} and its associated views + * + * @param node the {@link TreeNode} to be added + */ private void addTreeNode(TreeNode node) { TreeTransition parent = node.getParent(); TreeNodeView nodeView = new TreeNodeView(node); @@ -540,6 +607,11 @@ private void addTreeNode(TreeNode node) { } } + /** + * Adds the specified {@link TreeTransition} and its associated views + * + * @param trans The {@link TreeTransition} to be added + */ private void addTreeTransition(TreeTransition trans) { List parents = trans.getParents(); TreeTransitionView transView = new TreeTransitionView(trans); @@ -574,7 +646,11 @@ private void addTreeTransition(TreeTransition trans) { } } - /// New Draw Methods + /** + * Draws the tree using the provided {@link Graphics2D} object + * + * @param graphics2D the {@link Graphics2D} object used for drawing the tree + */ public void drawTree(Graphics2D graphics2D) { if (tree == null) { LOGGER.error("Unable to draw tree."); @@ -600,6 +676,11 @@ public void drawTree(Graphics2D graphics2D) { } } + /** + * Creates views for the given {@link TreeNodeView} and its children + * + * @param nodeView the {@link TreeNodeView} for which to create views + */ public void createViews(TreeNodeView nodeView) { if (nodeView != null) { viewMap.put(nodeView.getTreeElement(), nodeView); @@ -633,6 +714,14 @@ public void createViews(TreeNodeView nodeView) { } } + /** + * Calculates the layout locations (x and y coordinates) of the nodes in the tree. + * This method recursively traverses the tree and updates the positions of + * nodes and transitions based on their depth and parent relationships. + * + * @param nodeView the node view to calculate the positions for + * @param depth the depth of the node in the tree, used to calculate its x-coordinate + */ public void calculateViewLocations(TreeNodeView nodeView, int depth) { nodeView.setDepth(depth); int xLoc = (NODE_GAP_WIDTH + DIAMETER) * depth + DIAMETER; @@ -738,6 +827,13 @@ public void calculateViewLocations(TreeNodeView nodeView, int depth) { } } + /** + * Calculates the span (height) required for the given view, including its children. + * This method recursively determines the span for nodes and transitions based on their + * children and the merging branches they belong to. + * + * @param view the view whose span is to be calculated + */ public void calcSpan(TreeElementView view) { if (view.getType() == NODE) { TreeNodeView nodeView = (TreeNodeView) view; @@ -806,12 +902,12 @@ public void calcSpan(TreeElementView view) { } /** - * Calculates the sub span of a given sub tree rooted at the specified view and stops at the - * tree puzzleElement view specified as stop. Stop tree puzzleElement is NOT included in the - * span calculation + * Calculates the span of a subtree rooted at the specified view, stopping at the given + * stop view. The stop view is not included in the span calculation. * - * @param view - * @param stop + * @param view the root view of the subtree to calculate the span for + * @param stop the view at which to stop the span calculation. The stop view itself is + * not included in the span calculation */ private void subCalcSpan(TreeElementView view, TreeElementView stop) { // safe-guard for infinite loop @@ -886,12 +982,14 @@ private void subCalcSpan(TreeElementView view, TreeElementView stop) { } /** - * Reorders branches such that merging branches are sequentially grouped together and - * transitions are kept in relative order in the list of child transitions of the specified node + * Reorders the branches of a given node such that branches that merge are grouped together sequentially. + * Transitions are kept in their relative order based on their original positions in the list of child transitions + * of the specified node. This ensures that the visual representation of the branches and transitions maintains + * a logical and readable structure. * - * @param node root node of the branches - * @param branches DisjointSets of the child branches of the specified node which determine - * which branches merge + * @param node the root node whose branches are to be reordered + * @param branches a DisjointSets structure representing the merging relationships of the child branches of the + * specified node. This determines which branches should be grouped together */ private void reorderBranches(TreeNode node, DisjointSets branches) { List children = node.getChildren(); diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeViewSelection.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeViewSelection.java index 71a65b49e..c7893b168 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeViewSelection.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeViewSelection.java @@ -4,6 +4,11 @@ import java.util.ArrayList; import java.util.List; + +/** + * {@code TreeViewSelection} manages the selection and hover state of tree element views in a tree view. + * It maintains a list of selected views, tracks the currently hovered view, and manages the mouse position. + */ public class TreeViewSelection { private ArrayList selectedViews; private TreeElementView hover; From 86e8c38437f11c8bc2db6b6418f756af4fa32634 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Sun, 11 Aug 2024 01:07:37 -0400 Subject: [PATCH 252/258] Fixed number tile in binary where cycled through the unknown tile as well --- src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java index 3d4be02a1..06a5d6bd1 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java @@ -61,7 +61,7 @@ public BinaryCell copy() { public void setType(Element e, MouseEvent m) { if (e.getElementName().equals("Number Tile")) { if (m.getButton() == MouseEvent.BUTTON1) { - if (this.data == 2) { + if (this.data >= 1) { this.data = 0; } else { @@ -74,7 +74,7 @@ public void setType(Element e, MouseEvent m) { this.data = this.data - 1; } else { - this.data = 2; + this.data = 1; } } } From 373ac5d44a7c1f7e68acd4b3b1db2fde5681101a Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Mon, 12 Aug 2024 00:01:57 -0400 Subject: [PATCH 253/258] Added code specifications to all missing methods and class descriptions in all classes in ui directory --- .../edu/rpi/legup/ui/CreatePuzzleDialog.java | 52 ++++- .../java/edu/rpi/legup/ui/DynamicView.java | 44 ++++ .../edu/rpi/legup/ui/DynamicViewType.java | 8 + src/main/java/edu/rpi/legup/ui/HomePanel.java | 110 +++++++--- .../java/edu/rpi/legup/ui/LegupPanel.java | 9 + src/main/java/edu/rpi/legup/ui/LegupUI.java | 79 +++++-- .../java/edu/rpi/legup/ui/PickGameDialog.java | 26 +++ .../edu/rpi/legup/ui/PreferencesDialog.java | 57 +++++ .../edu/rpi/legup/ui/ProofEditorPanel.java | 205 +++++++++++++++--- .../edu/rpi/legup/ui/PuzzleEditorPanel.java | 159 +++++++++++++- .../java/edu/rpi/legup/ui/ScrollView.java | 14 ++ .../java/edu/rpi/legup/ui/ToolbarName.java | 4 + .../java/edu/rpi/legup/ui/ZoomWidget.java | 16 +- .../java/edu/rpi/legup/ui/ZoomablePane.java | 4 + 14 files changed, 694 insertions(+), 93 deletions(-) diff --git a/src/main/java/edu/rpi/legup/ui/CreatePuzzleDialog.java b/src/main/java/edu/rpi/legup/ui/CreatePuzzleDialog.java index a5afa2ff0..b1aa24eca 100644 --- a/src/main/java/edu/rpi/legup/ui/CreatePuzzleDialog.java +++ b/src/main/java/edu/rpi/legup/ui/CreatePuzzleDialog.java @@ -10,6 +10,10 @@ import java.util.Objects; import javax.swing.*; +/** + * Provides the user interface components for creating a new puzzle in the Legup application. + * This package includes classes for displaying dialog boxes to configure and initialize puzzles. + */ public class CreatePuzzleDialog extends JDialog { private HomePanel homePanel; @@ -17,6 +21,13 @@ public class CreatePuzzleDialog extends JDialog { private JComboBox gameBox; private ActionListener gameBoxListener = new ActionListener() { + /** + * An ActionListener that handles changes in the drop-down menu for selecting puzzle types. + * When a new item is selected in the drop-down menu, this listener updates the visibility of + * the text input area and the row/column input fields based on the selected puzzle type. + * If "ShortTruthTable" is selected, the text input area is shown and the row/column fields are hidden. + * For other puzzle types, the row/column fields are shown and the text input area is hidden. + */ @Override public void actionPerformed(ActionEvent e) { JComboBox comboBox = (JComboBox) e.getSource(); @@ -104,6 +115,12 @@ public void actionPerformed(ActionEvent e) { } }; + /** + * Constructs a new CreatePuzzleDialog + * + * @param parent the parent frame of the dialog + * @param homePanel the home panel where the created puzzle will be added + */ public CreatePuzzleDialog(JFrame parent, HomePanel homePanel) { super(parent, true); @@ -182,6 +199,10 @@ public CreatePuzzleDialog(JFrame parent, HomePanel homePanel) { cancel.addActionListener(cursorPressedCancel); } + /** + * Initializes the puzzle options available for selection in the dialog. + * The options are retrieved from the game board facade and sorted alphabetically. + */ public void initPuzzles() { this.games = GameBoardFacade.getInstance() @@ -192,7 +213,12 @@ public void initPuzzles() { gameBox = new JComboBox(this.games); } - // ^This method seems useless and never got covered + + /** + * Handles the action events for the dialog, including interactions with the Ok and Cancel buttons + * + * @param e The action event to be processed + */ public void actionPerformed(ActionEvent e) { if (e.getSource() == ok) { String game = Config.convertDisplayNameToClassName((String) gameBox.getSelectedItem()); @@ -209,9 +235,7 @@ public void actionPerformed(ActionEvent e) { } this.setVisible(false); } catch (IllegalArgumentException exception) { - // Don't do anything. This is here to prevent the dialog from closing if the - // dimensions are - // invalid. + // Do nothing. This is here to prevent the dialog from closing if the dimensions are invalid. } } else { if (e.getSource() == cancel) { @@ -222,17 +246,37 @@ public void actionPerformed(ActionEvent e) { } } + /** + * Retrieves the selected game from the combo box + * + * @return the class name of the selected game + */ public String getGame() { return Config.convertDisplayNameToClassName((String) gameBox.getSelectedItem()); } + /** + * Retrieves the number of rows specified in the dialog + * + * @return the number of rows as a string + */ public String getRows() { return rows.getText(); } + /** + * Retrieves the number of columns specified in the dialog + * + * @return the number of columns as a string + */ public String getColumns() { return columns.getText(); } + /** + * Retrieves the text entered in the text area, split by new lines. + * + * @return an array of strings, each representing as a line of text + */ public String[] getTextArea() { return textArea.getText().split("\n"); } } diff --git a/src/main/java/edu/rpi/legup/ui/DynamicView.java b/src/main/java/edu/rpi/legup/ui/DynamicView.java index 8d3024c86..344885783 100644 --- a/src/main/java/edu/rpi/legup/ui/DynamicView.java +++ b/src/main/java/edu/rpi/legup/ui/DynamicView.java @@ -16,6 +16,10 @@ import javax.swing.*; import javax.swing.event.ChangeEvent; +/** + * A JPanel that provides a dynamic view with zooming capabilities for different types of content. + * This class supports views such as game boards or proof trees, allowing users to zoom in and out. + */ public class DynamicView extends JPanel { private ScrollView scrollView; @@ -29,6 +33,12 @@ public class DynamicView extends JPanel { private static final Font INFO_FONT = MaterialFonts.REGULAR; private static final Color INFO_COLOR = MaterialColors.GRAY_900; + /** + * Constructs a new DynamicView with the specified ScrollView and view type + * + * @param scrollView the ScrollView that provides the content to be displayed and zoomed + * @param type the type of dynamic view to set up (e.g., BOARD or PROOF_TREE) + */ public DynamicView(ScrollView scrollView, DynamicViewType type) { this.scrollView = scrollView; @@ -185,34 +195,65 @@ public void componentResized(ComponentEvent e) { return zoomWrapper; } + /** + * Gets the ScrollView component associated with this DynamicView + * + * @return the ScrollView component + */ public ScrollView getScrollView() { return this.scrollView; } + /** + * Gets the zoom wrapper that contains the zooming controls + * + * @return the zoom wrapper with zooming controls + */ public JPanel getZoomWrapper() { return this.zoomWrapper; } + /** + * Gets the zoomer that contains the zoomer component + * + * @return the zoomer with the zoomer component + */ public JPanel getZoomer() { return this.zoomer; } + /** + * Updates the status label with an informational message + * + * @param message the informational message to display + */ public void updateInfo(String message) { status.setFont(INFO_FONT); status.setForeground(INFO_COLOR); status.setText(message); } + /** + * Updates the status label with an error message + * + * @param message the error message to display + */ public void updateError(String message) { status.setFont(ERROR_FONT); status.setForeground(ERROR_COLOR); status.setText(message); } + /** + * Clears the status label + */ public void resetStatus() { status.setText(""); } + /** + * Resets the view to its default state and zooms the content to fit the screen + */ public void reset() { Puzzle puzzle = GameBoardFacade.getInstance().getPuzzleModule(); Board board1 = GameBoardFacade.getInstance().getBoard(); @@ -221,6 +262,9 @@ public void reset() { this.getScrollView().zoomFit(); } + /** + * Fits the board view to the screen + */ protected void fitBoardViewToScreen() { scrollView.zoomFit(); } diff --git a/src/main/java/edu/rpi/legup/ui/DynamicViewType.java b/src/main/java/edu/rpi/legup/ui/DynamicViewType.java index 8c2f285cd..d161f5b9c 100644 --- a/src/main/java/edu/rpi/legup/ui/DynamicViewType.java +++ b/src/main/java/edu/rpi/legup/ui/DynamicViewType.java @@ -1,5 +1,13 @@ package edu.rpi.legup.ui; +/** + * An enumeration representing the different types of dynamic views supported by the application. + * The two types of views are: + *
          + *
        • {@code BOARD} - Represents a dynamic view of a game board
        • + *
        • {@code PROOF_TREE} - Represents a dynamic view of a proof tree
        • + *
        + */ public enum DynamicViewType { BOARD, PROOF_TREE diff --git a/src/main/java/edu/rpi/legup/ui/HomePanel.java b/src/main/java/edu/rpi/legup/ui/HomePanel.java index f43095ad7..f12ffdbf0 100644 --- a/src/main/java/edu/rpi/legup/ui/HomePanel.java +++ b/src/main/java/edu/rpi/legup/ui/HomePanel.java @@ -25,6 +25,12 @@ import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; +/** + * The {@code HomePanel} class represents the home panel of the LEGUP application. + * This panel provides buttons for functionalities of opening the proof editor, + * opening the puzzle editor, and performing batch grading. It also includes a menu bar with + * options for preferences. + */ public class HomePanel extends LegupPanel { private static final Logger LOGGER = LogManager.getLogger(HomePanel.class.getName()); private LegupUI legupUI; @@ -36,38 +42,24 @@ public class HomePanel extends LegupPanel { private final int buttonSize = 100; + /** + * Initialize the proof solver to an empty panel with no puzzle + */ private ActionListener openProofListener = new ActionListener() { @Override public void actionPerformed(ActionEvent e) { -// Object[] items = legupUI.getProofEditor().promptPuzzle(); -// if (items == null) { -// // The attempt to prompt a puzzle ended gracefully (cancel) -// return; -// } -// String fileName = (String) items[0]; -// File puzzleFile = (File) items[1]; legupUI.getProofEditor().loadPuzzle("", null); -// legupUI.getProofEditor().loadPuzzle(); } }; - private ActionListener openPuzzleListener = - new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - Object[] items = legupUI.getPuzzleEditor().promptPuzzle(); - if (items == null) { - // The attempt to prompt a puzzle ended gracefully (cancel) - return; - } - String fileName = (String) items[0]; - File puzzleFile = (File) items[1]; - legupUI.getPuzzleEditor().loadPuzzle(fileName, puzzleFile); - } - }; - - public HomePanel(FileDialog fileDialog, JFrame frame, LegupUI legupUI) { + /** + * Constructs a {@code HomePanel} with the specified {@code JFrame} and {@code LegupUI}. + * + * @param frame the main application frame + * @param legupUI the LEGUP user interface + */ + public HomePanel(JFrame frame, LegupUI legupUI) { this.legupUI = legupUI; this.frame = frame; setLayout(new GridLayout(1, 2)); @@ -76,6 +68,11 @@ public HomePanel(FileDialog fileDialog, JFrame frame, LegupUI legupUI) { initButtons(); } + /** + * Creates and returns the menu bar for this panel + * + * @return the menu bar + */ public JMenuBar getMenuBar() { this.menuBar = new JMenuBar(); JMenu settings = new JMenu("Settings"); @@ -104,18 +101,32 @@ public JMenuBar getMenuBar() { return this.menuBar; } + /** + * Makes the panel visible and sets the menu bar of the frame + */ @Override public void makeVisible() { render(); frame.setJMenuBar(this.getMenuBar()); } + /** + * Resizes the provided icon to the specified width and height + * + * @param icon the icon to resize + * @param width the target width + * @param height the target height + * @return the resized icon + */ private static ImageIcon resizeButtonIcon(ImageIcon icon, int width, int height) { Image image = icon.getImage(); Image resizedImage = image.getScaledInstance(width, height, Image.SCALE_SMOOTH); return new ImageIcon(resizedImage); } + /** + * Initializes the buttons for this panel + */ private void initButtons() { this.buttons = new JButton[3]; @@ -176,6 +187,10 @@ public void actionPerformed(ActionEvent e) { }); } + /** + * Opens a folder chooser dialog and grades puzzles in the selected folder. + * The results are written to a CSV file. + */ public void checkFolder() { GameBoardFacade facade = GameBoardFacade.getInstance(); /* @@ -261,8 +276,12 @@ public void checkFolder() { } /** - * @effect batch grade using .xml parser - go through a collection of files and report their - * "solved?" status + * Processes XML files within a selected directory and generates a CSV report on their "solved?" status. + * The method allows the user to select a directory, and evaluates each XML file for a "solved?" status. + * Results are saved in a "result.csv" file. + * + * @effect Selects a directory, processes each XML file to check for "solved?" status, + * and writes results to "result.csv". Opens the CSV file upon completion. */ private void use_xml_to_check() { /* Select a folder, go through each .xml file in the subfolders, look for "isSolved" flag */ @@ -461,6 +480,10 @@ public void endDocument() throws SAXException { } } + /** + * Initializes the text labels for the user interface. + * Sets up labels for welcome message, led by Bram, and version information. + */ private void initText() { // TODO: add version text after auto-changing version label is implemented. (text[2] = // version) @@ -482,6 +505,9 @@ private void initText() { this.text[1] = credits; } + /** + * Renders the user interface components + */ private void render() { this.removeAll(); @@ -507,11 +533,11 @@ private void render() { this.add(Box.createRigidArea(new Dimension(0, 5))); } - private void openNewPuzzleDialog() { - CreatePuzzleDialog cpd = new CreatePuzzleDialog(this.frame, this); - cpd.setVisible(true); - } - + /** + * Opens the puzzle editor dialog with no selected puzzle, leaving a blank panel + * + * @throws IllegalArgumentException if the configuration parameters are invalid (should never happen) + */ private void openPuzzleEditorDialog() { String game = ""; int r = 0; @@ -525,6 +551,10 @@ private void openPuzzleEditorDialog() { } } + /** + * Opens a dialog to select a directory, recursively processes the directory to grade puzzles, + * and generates a CSV report of the grading results. + */ private void checkProofAll() { /* * Select dir to grade; recursively grade sub-dirs using traverseDir() @@ -568,6 +598,14 @@ private void checkProofAll() { JOptionPane.showMessageDialog(null, "Batch grading complete."); } + /** + * Recursively traverses directories to grade puzzles and writes results to a CSV file + * + * @param folder the folder to traverse + * @param writer the BufferedWriter to write results to the CSV file + * @param path the current path within the directory structure + * @throws IOException if an I/O error occurs while writing to the CSV file + */ private void traverseDir(File folder, BufferedWriter writer, String path) throws IOException { // Recursively traverse directory GameBoardFacade facade = GameBoardFacade.getInstance(); @@ -620,6 +658,14 @@ private void traverseDir(File folder, BufferedWriter writer, String path) throws } } + /** + * Opens the puzzle editor for the specified puzzle with the specified dimensions + * + * @param game the name of the game + * @param rows the number of rows in the puzzle + * @param columns the number of columns in the puzzle + * @throws IllegalArgumentException if the dimensions are invalid + */ public void openEditorWithNewPuzzle(String game, int rows, int columns) throws IllegalArgumentException { if (game.equals("")) { @@ -653,7 +699,7 @@ public void openEditorWithNewPuzzle(String game, int rows, int columns) } /** - * Opens the puzzle editor for the specified game with the given statements + * Opens the puzzle editor for the specified puzzle with the given statements * * @param game a String containing the name of the game * @param statements an array of statements diff --git a/src/main/java/edu/rpi/legup/ui/LegupPanel.java b/src/main/java/edu/rpi/legup/ui/LegupPanel.java index d16167b3d..38c44cbe4 100644 --- a/src/main/java/edu/rpi/legup/ui/LegupPanel.java +++ b/src/main/java/edu/rpi/legup/ui/LegupPanel.java @@ -2,9 +2,18 @@ import javax.swing.*; +/** + * An abstract base class for panels in the LEGUP application. + * This class extends {@link JPanel} and defines common properties and methods + * for all panels in the LEGUP user interface + * (currently only implements toolbar scale) + */ public abstract class LegupPanel extends JPanel { /** Alerts panel that it will be going visible now */ protected final int TOOLBAR_ICON_SCALE = 40; + /** + * Abstract method to make the panel visible + */ public abstract void makeVisible(); } diff --git a/src/main/java/edu/rpi/legup/ui/LegupUI.java b/src/main/java/edu/rpi/legup/ui/LegupUI.java index eb8b1663c..30857f05f 100644 --- a/src/main/java/edu/rpi/legup/ui/LegupUI.java +++ b/src/main/java/edu/rpi/legup/ui/LegupUI.java @@ -14,6 +14,11 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +/** + * The main user interface class for the LEGUP application. + * This class extends {@link JFrame} and implements {@link WindowListener} + * to manage the overall window and provide functionality for displaying various panels. + */ public class LegupUI extends JFrame implements WindowListener { private static final Logger LOGGER = LogManager.getLogger(LegupUI.class.getName()); @@ -36,7 +41,7 @@ public static String getOS() { return os; } - /** LegupUI Constructor - creates a new LegupUI to setup the menu and toolbar */ + /** LegupUI Constructor - creates a new LegupUI to set up the menu and toolbar */ public LegupUI() { setTitle("LEGUP"); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); @@ -91,17 +96,27 @@ public void keyTyped(KeyEvent e) { setVisible(true); } + /** + * Initializes the panels used in the UI. + * Sets up the layout and adds panels to the window. + */ private void initPanels() { window = new JPanel(); window.setLayout(new BorderLayout()); add(window); panels = new LegupPanel[3]; - panels[0] = new HomePanel(this.fileDialog, this, this); + panels[0] = new HomePanel(this, this); panels[1] = new ProofEditorPanel(this.fileDialog, this, this); panels[2] = new PuzzleEditorPanel(this.fileDialog, this, this); } + /** + * Displays the specified panel + * + * @param option the index of the panel to display + * @throws InvalidParameterException if the option is out of range + */ protected void displayPanel(int option) { if (option > panels.length || option < 0) { throw new InvalidParameterException("Invalid option"); @@ -115,29 +130,31 @@ protected void displayPanel(int option) { repaint(); } + /** + * Gets the ProofEditorPanel instance + * + * @return the ProofEditorPanel + */ public ProofEditorPanel getProofEditor() { return (ProofEditorPanel) panels[1]; } + /** + * Gets the PuzzleEditorPanel instance + * + * @return the PuzzleEditorPanel + */ public PuzzleEditorPanel getPuzzleEditor() { return (PuzzleEditorPanel) panels[2]; } + /** + * Repaints the tree view in the proof editor. + */ public void repaintTree() { getProofEditor().repaintTree(); } - private void directions() { - JOptionPane.showMessageDialog( - null, - "For every move you make, you must provide a rules for it (located in the Rules" - + " panel).\n" - + "While working on the edu.rpi.legup.puzzle, you may click on the \"Check\"" - + " button to test your proof for correctness.", - "Directions", - JOptionPane.PLAIN_MESSAGE); - } - public void showStatus(String status, boolean error) { showStatus(status, error, 1); } @@ -150,8 +167,13 @@ public void showStatus(String status, boolean error, int timer) { // TODO: implement } - // ask to edu.rpi.legup.save current proof - public boolean noquit(String instr) { + /** + * Prompts the user to confirm if they want to exit LEGUP + * + * @param instr the prompt message + * @return true if the user chooses not to quit, false otherwise + */ + public boolean exit(String instr) { int n = JOptionPane.showConfirmDialog(null, instr, "Confirm", JOptionPane.YES_NO_OPTION); return n != JOptionPane.YES_OPTION; } @@ -161,7 +183,7 @@ public void windowOpened(WindowEvent e) {} public void windowClosing(WindowEvent e) { if (GameBoardFacade.getInstance().getHistory().getIndex() > -1) { - if (noquit("Exiting LEGUP?")) { + if (exit("Exiting LEGUP?")) { this.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); } else { this.setDefaultCloseOperation(EXIT_ON_CLOSE); @@ -183,22 +205,47 @@ public void windowActivated(WindowEvent e) {} public void windowDeactivated(WindowEvent e) {} + /** + * Gets the BoardView instance from the proof editor + * + * @return the BoardView + */ public BoardView getBoardView() { return getProofEditor().getBoardView(); } + /** + * Gets the BoardView instance from the puzzle editor + * + * @return the BoardView + */ public BoardView getEditorBoardView() { return getPuzzleEditor().getBoardView(); } + /** + * Gets the DynamicView instance from the proof editor + * + * @return the DynamicView + */ public DynamicView getDynamicBoardView() { return getProofEditor().getDynamicBoardView(); } + /** + * Gets the DynamicView instance from the puzzle editor. + * + * @return the DynamicView + */ public DynamicView getEditorDynamicBoardView() { return getPuzzleEditor().getDynamicBoardView(); } + /** + * Gets the TreePanel instance from the proof editor + * + * @return the TreePanel + */ public TreePanel getTreePanel() { return getProofEditor().getTreePanel(); } diff --git a/src/main/java/edu/rpi/legup/ui/PickGameDialog.java b/src/main/java/edu/rpi/legup/ui/PickGameDialog.java index f703ffcbc..a6501e2a0 100644 --- a/src/main/java/edu/rpi/legup/ui/PickGameDialog.java +++ b/src/main/java/edu/rpi/legup/ui/PickGameDialog.java @@ -15,6 +15,11 @@ import javax.swing.JLabel; import javax.swing.JTextField; +/** + * A dialog for selecting a game. + * This class extends {@link JDialog} and implements {@link ActionListener} + * to handle user interactions for selecting a game type and puzzle file. + */ public class PickGameDialog extends JDialog implements ActionListener { JLabel gameLabel = new JLabel("Game:"); String[] games; @@ -106,6 +111,10 @@ public PickGameDialog(JFrame parent, boolean pickBothAtOnce) { c.add(autojustifyCheckBox); } + /** + * Initializes the available games and puzzles. + * Populates the {@link JComboBox} with game types and sets up the puzzle options. + */ public void initPuzzles() { Object[] o = GameBoardFacade.getInstance().getConfig().getPuzzleClassNames().toArray(); @@ -128,14 +137,31 @@ public void initPuzzles() { gameBox = new JComboBox(games); } + /** + * Gets the selected puzzle file path + * + * @return the puzzle file path as a String + */ public String getPuzzle() { return puzzleBox.getText(); } + /** + * Returns the selected puzzle + * + * @return the selected puzzle as a String + */ public String getGame() { return (String) gameBox.getSelectedItem(); } + /** + * Handles action events for the dialog components. + * Responds to user interactions such as selecting a puzzle, choosing a puzzle file, + * and pressing the 'Ok' or 'Cancel' buttons. + * + * @param e the action event + */ public void actionPerformed(ActionEvent e) { if (e.getSource() == gameBox) { int index = gameBox.getSelectedIndex(); diff --git a/src/main/java/edu/rpi/legup/ui/PreferencesDialog.java b/src/main/java/edu/rpi/legup/ui/PreferencesDialog.java index 475f4bb68..c8639f796 100644 --- a/src/main/java/edu/rpi/legup/ui/PreferencesDialog.java +++ b/src/main/java/edu/rpi/legup/ui/PreferencesDialog.java @@ -17,6 +17,12 @@ import javax.imageio.ImageIO; import javax.swing.*; +/** + * A dialog for managing user preferences in the LEGUP application. + * This dialog allows users to configure various settings such as screen mode, + * update preferences, work directory path, and specific features related to board and tree views. + * Users can access this dialog from the home screen or proof editor. + */ public class PreferencesDialog extends JDialog { private RuleFrame rulesFrame; @@ -47,12 +53,24 @@ public class PreferencesDialog extends JDialog { } } + /** + * Creates a new instance of PreferencesDialog for the proof editor + * + * @param frame the parent frame + * @param rules the RuleFrame associated with the proof editor + * @return a new instance of PreferencesDialog + */ public static PreferencesDialog CreateDialogForProofEditor(Frame frame, RuleFrame rules) { PreferencesDialog p = new PreferencesDialog(frame); p.rulesFrame = rules; return p; } + /** + * Constructs a PreferencesDialog + * + * @param frame the parent frame + */ public PreferencesDialog(Frame frame) { super(frame); @@ -102,6 +120,11 @@ public PreferencesDialog(Frame frame) { setVisible(true); } + /** + * Toggles between dark mode and light mode based on the given preferences + * + * @param prefs the LegupPreferences instance holding user preferences + */ private void toggleDarkMode(LegupPreferences prefs) { try { if (Boolean.valueOf(prefs.getUserPref(LegupPreferences.DARK_MODE))) { @@ -115,6 +138,11 @@ private void toggleDarkMode(LegupPreferences prefs) { } } + /** + * Creates the general preferences tab + * + * @return a JScrollPane containing the general preferences panel + */ private JScrollPane createGeneralTab() { LegupPreferences prefs = LegupPreferences.getInstance(); JScrollPane scrollPane = new JScrollPane(); @@ -335,6 +363,15 @@ private JScrollPane createPuzzleTab(Puzzle puzzle) { return scrollPane; } + /** + * Creates a JPanel that represents a single row for a rule in the rule list. + * Each row displays the rule's name and an area for showing keyboard shortcuts + * associated with the rule. The keyboard shortcuts are dynamically updated based + * on user input. + * + * @param rule the rule object to be displayed + * @return a JPanel representing the row for the rule + */ private JPanel createRuleRow(Rule rule) { JPanel ruleRow = new JPanel(); ruleRow.setLayout(new BorderLayout()); @@ -387,6 +424,14 @@ public void keyPressed(KeyEvent e) { return ruleRow; } + /** + * Creates a JPanel containing a left-aligned label with the specified text. + * This label is typically used for section headings or descriptive text in the + * preferences dialog. + * + * @param text the text to be displayed on the label + * @return a JPanel containing the left-aligned label + */ private JPanel createLeftLabel(String text) { JPanel labelRow = new JPanel(); labelRow.setLayout(new BorderLayout()); @@ -400,12 +445,24 @@ private JPanel createLeftLabel(String text) { return labelRow; } + /** + * Creates a JSeparator with a maximum height of 5 pixels. + * This separator is used to visually divide sections in the preferences dialog. + * + * @return a JSeparator with a fixed height + */ private JSeparator createLineSeparator() { JSeparator separator = new JSeparator(); separator.setMaximumSize(new Dimension(Integer.MAX_VALUE, 5)); return separator; } + /** + * Applies the current user preferences and updates the associated components. + * This method retrieves user preferences from the dialog's components and stores + * them in the {@link LegupPreferences} instance. It also updates the rule panels + * in the rules frame if it is not null. + */ public void applyPreferences() { LegupPreferences prefs = LegupPreferences.getInstance(); prefs.setUserPref(LegupPreferences.WORK_DIRECTORY, workDirectory.getText()); diff --git a/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java b/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java index 441b00c32..c70e85727 100644 --- a/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java +++ b/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java @@ -37,6 +37,14 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +/** + * {@code ProofEditorPanel} is a panel that serves as the main user interface + * component for the proof editing functionality of LEGUP. It provides + * the graphical components and interactive elements necessary for editing and managing + * proofs, including toolbars, menus, and views for different aspects of proof editing. + * It also manages interactions with the rest of the application and updates the UI + * based on user actions and application state changes. + */ public class ProofEditorPanel extends LegupPanel implements IHistoryListener { private static final Logger LOGGER = LogManager.getLogger(ProofEditorPanel.class.getName()); private JMenuBar mBar; @@ -112,6 +120,13 @@ public class ProofEditorPanel extends LegupPanel implements IHistoryListener { protected JMenuItem testAI = new JMenuItem("Test AI!"); protected JMenuItem hintAI = new JMenuItem("Hint"); + /** + * Constructs a new {@code ProofEditorPanel} with the specified parameters + * + * @param fileDialog the {@code FileDialog} used for file operations + * @param frame the {@code JFrame} that contains this panel + * @param legupUI the {@code LegupUI} instance managing the user interface + */ public ProofEditorPanel(FileDialog fileDialog, JFrame frame, LegupUI legupUI) { this.fileDialog = fileDialog; this.frame = frame; @@ -120,6 +135,10 @@ public ProofEditorPanel(FileDialog fileDialog, JFrame frame, LegupUI legupUI) { setPreferredSize(new Dimension(800, 700)); } + /** + * Makes the panel visible by setting up the toolbar and content components. + * This method also sets the menu bar of the frame to the one used by this panel. + */ @Override public void makeVisible() { this.removeAll(); @@ -129,6 +148,24 @@ public void makeVisible() { frame.setJMenuBar(getMenuBar()); } + /** + * Constructs and returns the {@code JMenuBar} for this panel. + * It populates it with various {@code JMenu} and {@code JMenuItem} components related + * to file operations, editing, viewing, and proof management. + * The menu bar includes: + *
          + *
        • {@code File} menu with options to open a new puzzle, reset the puzzle, save the proof, + * access preferences, and exit the editor.
        • + *
        • {@code Edit} menu with options for undo, redo, and fitting the board or tree to the screen.
        • + *
        • {@code Proof} menu with options for adding, deleting, merging, collapsing elements, + * and toggling settings related to rule applications and feedback.
        • + *
        • {@code About} menu with options to view information about the application and access help resources.
        • + *
        + *

        + * Accelerator keys are set based on the operating system (Mac or non-Mac). + * + * @return the {@code JMenuBar} instance containing the menus and menu items for this panel + */ public JMenuBar getMenuBar() { if (mBar != null) return mBar; mBar = new JMenuBar(); @@ -459,6 +496,10 @@ public void actionPerformed(ActionEvent e) { return mBar; } + /** + * Clears the current puzzle, resets the UI to display the initial panel, + * and nullifies the references to the tree panel and board view. + */ public void exitEditor() { // Wipes the puzzle entirely as if LEGUP just started GameBoardFacade.getInstance().clearPuzzle(); @@ -467,7 +508,13 @@ public void exitEditor() { boardView = null; } - // File opener + /** + * Opens a file chooser dialog allowing the user to select a directory. It uses the user's + * preferred directory or the last saved path if available. The selected directory is used + * to set the new working directory. + * + * @return an array containing the file name and the selected file, or {@code null} if the operation was canceled + */ public Object[] promptPuzzle() { GameBoardFacade facade = GameBoardFacade.getInstance(); if (facade.getBoard() != null) { @@ -511,6 +558,12 @@ public Object[] promptPuzzle() { return new Object[] {fileName, puzzleFile}; } + /** + * Calls {@link #promptPuzzle()} to get the file information and then loads the puzzle using + * the provided file name and file object. Updates the frame title to reflect the puzzle name. + * If the file is not valid or an error occurs, an error message is shown, and the user is + * prompted to try loading another puzzle. + */ public void loadPuzzle() { Object[] items = promptPuzzle(); // Return if items == null (cancel) @@ -522,6 +575,15 @@ public void loadPuzzle() { loadPuzzle(fileName, puzzleFile); } + /** + * Attempts to load a puzzle from the given file. If successful, it updates the + * UI to display the puzzle and changes the frame title to include the puzzle name. If the + * file is invalid or cannot be read, it shows an appropriate error message and prompts the + * user to try loading another puzzle. + * + * @param fileName the name of the file to load + * @param puzzleFile the file object representing the puzzle file + */ public void loadPuzzle(String fileName, File puzzleFile) { if (puzzleFile == null && fileName.equals("")) { legupUI.displayPanel(1); @@ -560,7 +622,11 @@ public void loadPuzzle(String fileName, File puzzleFile) { } } - /** save the proof in the current file */ + /** + * Uses the current puzzle and its associated exporter to save the puzzle data + * to the file currently being used. If the puzzle or exporter is null, or if an error occurs + * during export, the method will catch the exception and print the stack trace. + */ private void direct_save() { Puzzle puzzle = GameBoardFacade.getInstance().getPuzzleModule(); if (puzzle == null) { @@ -580,7 +646,11 @@ private void direct_save() { } } - /** Create a new file and save proof to it */ + /** + * Opens a file chooser dialog for the user to select a directory. The chosen directory is used + * to determine where the puzzle file will be saved. If an exporter is available, it will be used + * to export the puzzle data to the selected path. + */ private void saveProofAs() { Puzzle puzzle = GameBoardFacade.getInstance().getPuzzleModule(); if (puzzle == null) { @@ -618,6 +688,11 @@ private void saveProofAs() { } // Hyperlink for help button; links to wiki page for tutorials + /** + * Opens the default web browser to a help page related to the type of puzzle currently being used. + * The URL is chosen based on the name of the puzzle. If the puzzle type is not recognized, a general + * tutorial page is opened. + */ private void helpTutorial() { // redirecting to certain help link in wiki Puzzle puzzle = GameBoardFacade.getInstance().getPuzzleModule(); @@ -645,16 +720,14 @@ private void helpTutorial() { default: url = "https://github.com/Bram-Hub/Legup/wiki/LEGUP-Tutorial"; } - Runtime rt = Runtime.getRuntime(); try { - // rt.exec("rundll32 url.dll,FileProtocolHandler "+url); java.awt.Desktop.getDesktop().browse(java.net.URI.create(url)); } catch (IOException e) { e.printStackTrace(); } } - // add the new function need to implement + // unfinished public void add_drop() { // add the mouse event then we can use the new listener to implement and // we should create a need jbuttom for it to ship the rule we select. @@ -671,7 +744,11 @@ public void actionPerformed(ActionEvent e) { panel.add(moveing_buttom); } - // Quick save proof to the current file with a pop window to show "successfully saved" + /** + * Saves the puzzle using the current file name and shows a message dialog to + * confirm that the save operation was successful. If the puzzle or exporter is null, or if + * an error occurs during export, the method will catch the exception and print the stack trace. + */ private void saveProofChange() { Puzzle puzzle = GameBoardFacade.getInstance().getPuzzleModule(); if (puzzle == null) { @@ -694,13 +771,22 @@ private void saveProofChange() { } } - // ask to edu.rpi.legup.save current proof + /** + * Displays a confirmation dialog with a specified message. Returns {@code true} if the user + * selects "No" or cancels the action, and {@code false} if the user selects "Yes". + * + * @param instr the message to display in the confirmation dialog + * @return {@code true} if the user chooses not to quit, {@code false} otherwise + */ public boolean noquit(String instr) { int n = JOptionPane.showConfirmDialog(null, instr, "Confirm", JOptionPane.YES_NO_OPTION); return n != JOptionPane.YES_OPTION; } - /** Sets the main content for the edu.rpi.legup.user interface */ + /** + * Configures the layout and components for the main user interface. This includes setting up + * panels, split panes, and borders, and adding them to the main content pane. + */ protected void setupContent() { // JPanel consoleBox = new JPanel(new BorderLayout()); JPanel treeBox = new JPanel(new BorderLayout()); @@ -733,19 +819,17 @@ protected void setupContent() { ruleBox.add(boardPanel); treeBox.add(ruleBox); this.add(treeBox); - // consoleBox.add(treeBox); - // - // getContentPane().add(consoleBox); - - // JPopupPanel popupPanel = new JPopupPanel(); - // setGlassPane(popupPanel); - // popupPanel.setVisible(true); mainPanel.setDividerLocation(mainPanel.getMaximumDividerLocation() + 100); - // frame.pack(); + revalidate(); } + /** + * Initializes the first toolbar, configures its appearance, and adds an 'Open' button + * with an associated icon. An action listener is attached to the button to trigger the loading of + * a puzzle when clicked. + */ private void setupToolBar1() { toolBar1 = new JToolBar(); toolBar1.setFloatable(false); @@ -777,6 +861,17 @@ private void setupToolBar1() { this.add(toolBar1, BorderLayout.NORTH); } + /** + * Initializes the second toolbar, configures its appearance, and adds four buttons each + * with associated icons. Action listeners are attached to each button to trigger their respective + * actions when clicked: + *

          + *
        • 'Directions' button triggers the `directionsToolButton` method.
        • + *
        • 'Undo' button triggers the undo action in the puzzle's history.
        • + *
        • 'Redo' button triggers the redo action in the puzzle's history.
        • + *
        • 'Check' button triggers the `checkProof` method.
        • + *
        + */ private void setupToolBar2() { toolBar2 = new JToolBar(); toolBar2.setFloatable(false); @@ -905,7 +1000,10 @@ public JButton[] getToolBar2Buttons() { return toolBar2Buttons; } - /** Checks the proof for correctness */ + /** + * Uses the {@link GameBoardFacade} to obtain the current puzzle and board. If the puzzle is complete, + * it notifies the user of a correct proof. If not, it alerts the user that the board is not solved. + */ private void checkProof() { GameBoardFacade facade = GameBoardFacade.getInstance(); Tree tree = GameBoardFacade.getInstance().getTree(); @@ -932,6 +1030,11 @@ private void checkProof() { } } + /** + * Retrieves the puzzle name from the `GameBoardFacade` and opens a corresponding rules page in the default web browser. + * + * @throws IOException if an error occurs while trying to open the web page + */ private void directionsToolButton() { String puzzleName = GameBoardFacade.getInstance().getPuzzleModule().getName(); //System.out.println(puzzleName); @@ -960,11 +1063,21 @@ else if (puzzleName.equals("ShortTruthTables")) { LOGGER.error("Can't open web page"); } } + + /** + * Repaints the board view and tree panel + */ private void repaintAll() { boardView.repaint(); treePanel.repaint(); } + /** + * Initializes the dynamic board view, updates the tree panel, and sets rules and search panels + * based on the provided puzzle. It also updates toolbars and reloads the GUI. + * + * @param puzzle the puzzle to be displayed + */ public void setPuzzleView(Puzzle puzzle) { this.boardView = puzzle.getBoardView(); @@ -994,10 +1107,15 @@ public void setPuzzleView(Puzzle puzzle) { reloadGui(); } + /** + * Calls {@code repaintTree()} to refresh the tree view. + */ public void reloadGui() { repaintTree(); } - + /** + * Updates the tree view displayed in the tree panel to reflect the current state of the tree. + */ public void repaintTree() { treePanel.repaintTreeView(GameBoardFacade.getInstance().getTree()); } @@ -1052,6 +1170,15 @@ private boolean basicCheckProof(int[][] origCells) { return false; } + /** + * Traverses a given directory, grades the proofs found in the directory, and writes the results + * to the specified CSV writer. + * + * @param folder the folder to traverse + * @param writer the CSV writer + * @param path the current path in the directory traversal + * @throws IOException if an error occurs while writing to the CSV file + */ private void traverseDir(File folder, BufferedWriter writer, String path) throws IOException { // Recursively traverse directory GameBoardFacade facade = GameBoardFacade.getInstance(); @@ -1106,20 +1233,36 @@ private void traverseDir(File folder, BufferedWriter writer, String path) throws } } + /** + * Returns the current board view. + * + * @return the current {@link BoardView} + */ public BoardView getBoardView() { return boardView; } + + /** + * Returns the current dynamic board view. + * + * @return the current {@link DynamicView} + */ public DynamicView getDynamicBoardView() { return dynamicBoardView; } + /** + * Returns the current tree panel. + * + * @return the current {@link TreePanel} + */ public TreePanel getTreePanel() { return treePanel; } /** - * Called when a action is pushed onto the edu.rpi.legup.history stack + * Called when an action is pushed onto the edu.rpi.legup.history stack * * @param command action to push onto the stack */ @@ -1132,22 +1275,16 @@ public void onPushChange(ICommand command) { String puzzleName = GameBoardFacade.getInstance().getPuzzleModule().getName(); File puzzleFile = new File(GameBoardFacade.getInstance().getCurFileName()); frame.setTitle(puzzleName + " - " + puzzleFile.getName() + " *"); -// Board curBoard = GameBoardFacade.getInstance().getBoard(); -// List allElements = curBoard.getPuzzleElements(); -// for (PuzzleElement p : allElements) { -// if (p.getData() == BinaryType.UNKNOWN) { -// p.setModifiable(true); -// } -// } } - /** Called when the history is cleared */ + /** + * Updates the state of the undo and redo buttons to reflect that there are no actions + * available to undo or redo. It disables both buttons when the history is cleared. + */ @Override public void onClearHistory() { - // undo.setEnabled(false); - // toolBar2Buttons[ToolbarName.UNDO.ordinal()].setEnabled(false); - // redo.setEnabled(false); - // toolBar2Buttons[ToolbarName.REDO.ordinal()].setEnabled(false); + undo.setEnabled(false); + redo.setEnabled(false); } /** @@ -1224,6 +1361,10 @@ public void showStatus(String status, boolean error, int timer) { // TODO: implement } + + /** + * Zooms the tree view to fit within the available screen space + */ protected void fitTreeViewToScreen() { this.treePanel.getTreeView().zoomFit(); } diff --git a/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java b/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java index c1d402d2d..501923c64 100644 --- a/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java +++ b/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java @@ -34,6 +34,11 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +/** + * Represents the panel used for puzzle editor in the LEGUP. + * This panel includes a variety of UI components such as toolbars, menus, and split panes. + * It handles puzzle file operations, including creating and editing puzzles. + */ public class PuzzleEditorPanel extends LegupPanel implements IHistoryListener { private static final Logger LOGGER = LogManager.getLogger(PuzzleEditorPanel.class.getName()); @@ -65,6 +70,13 @@ public class PuzzleEditorPanel extends LegupPanel implements IHistoryListener { private String fileName; private File puzzleFile; + /** + * Constructs a {@code PuzzleEditorPanel} with the specified file dialog, frame, and Legup UI instance + * + * @param fileDialog the file dialog used for file operations + * @param frame the main application frame + * @param legupUI the Legup UI instance + */ public PuzzleEditorPanel(FileDialog fileDialog, JFrame frame, LegupUI legupUI) { this.fileDialog = fileDialog; this.frame = frame; @@ -73,6 +85,10 @@ public PuzzleEditorPanel(FileDialog fileDialog, JFrame frame, LegupUI legupUI) { setPreferredSize(new Dimension(800, 700)); } + /** + * Sets up the content of the panel, including the layout and UI components. + * Initializes and configures the {@code DynamicView} and {@code ElementFrame}, and adds them to the panel. + */ protected void setupContent() { JSplitPane splitPanel; JPanel elementBox = new JPanel(new BorderLayout()); @@ -104,6 +120,11 @@ protected void setupContent() { revalidate(); } + /** + * Configures the menu bar with menus and menu items for the application. + * Adds actions for opening, creating, and exiting puzzles. + * Also sets up help and about menu items. + */ public void setMenuBar() { String os = LegupUI.getOS(); menuBar = new JMenuBar(); @@ -127,7 +148,7 @@ public void setMenuBar() { // file>create JMenuItem createPuzzle = new JMenuItem("Create"); createPuzzle.addActionListener((ActionEvent) -> { - hp = new HomePanel(this.fileDialog, this.frame, this.legupUI); + hp = new HomePanel(this.frame, this.legupUI); cpd = new CreatePuzzleDialog(this.frame, hp); cpd.setLocationRelativeTo(null); cpd.setVisible(true); @@ -164,7 +185,8 @@ public void setMenuBar() { redo = new JMenuItem("Redo"); fitBoardToScreen = new JMenuItem("Fit Board to Screen"); - menus[1].add(undo); + // TODO: Undo operation currently does not get updated correctly in history + //menus[1].add(undo); undo.addActionListener((ActionEvent) -> GameBoardFacade.getInstance().getHistory().undo()); if (os.equals("mac")) { undo.setAccelerator( @@ -174,8 +196,8 @@ public void setMenuBar() { undo.setAccelerator(KeyStroke.getKeyStroke('Z', InputEvent.CTRL_DOWN_MASK)); } - menus[1].add(redo); - + // TODO: Redo operation currently does not get updated correctly in history + //menus[1].add(redo); // Created action to support two keybinds (CTRL-SHIFT-Z, CTRL-Y) Action redoAction = new AbstractAction() { @@ -249,6 +271,12 @@ public void actionPerformed(ActionEvent e) { frame.setJMenuBar(menuBar); } + /** + * Exits the puzzle editor and resets the application state to its initial condition. + * This method clears the current puzzle from the {@code GameBoardFacade}, + * resets the display to the initial panel, and nullifies references to the + * tree panel and board view. + */ public void exitEditor() { // Wipes the puzzle entirely as if LEGUP just started GameBoardFacade.getInstance().clearPuzzle(); @@ -257,6 +285,10 @@ public void exitEditor() { boardView = null; } + /** + * Makes the panel visible by setting up the toolbar, content, and menu bar. + * This method is called to refresh the panel's user interface. + */ @Override public void makeVisible() { this.removeAll(); @@ -264,6 +296,11 @@ public void makeVisible() { setupContent(); setMenuBar(); } + + /** + * Sets up the first toolbar with buttons for opening and creating puzzles. + * This method initializes the toolbar buttons with their icons and actions. + */ private void setupToolBar1() { setToolBar1Buttons(new JButton[2]); @@ -305,7 +342,7 @@ private void setupToolBar1() { JButton create = new JButton("Create", CreateImageIcon); create.setFocusPainted(false); create.addActionListener((ActionEvent) -> { - hp = new HomePanel(this.fileDialog, this.frame, this.legupUI); + hp = new HomePanel(this.frame, this.legupUI); cpd = new CreatePuzzleDialog(this.frame, hp); cpd.setLocationRelativeTo(null); cpd.setVisible(true); @@ -320,6 +357,10 @@ private void setupToolBar1() { this.add(toolBar1, BorderLayout.NORTH); } + /** + * Sets up the second toolbar with buttons for resetting, saving, and saving & solving puzzles. + * This method initializes the toolbar buttons with their icons and actions. + */ private void setupToolBar2() { toolBar2 = new JToolBar(); toolBar2.setFloatable(false); @@ -418,6 +459,14 @@ public void actionPerformed(ActionEvent e) { this.add(toolBar2, BorderLayout.NORTH); } + /** + * Initializes a puzzle based on the provided game name, rows, and columns. + * + * @param game the name of the game or puzzle to load + * @param rows the number of rows in the puzzle + * @param columns the number of columns in the puzzle + * @throws IllegalArgumentException if the provided arguments are invalid + */ public void loadPuzzleFromHome(String game, int rows, int columns) throws IllegalArgumentException { GameBoardFacade facade = GameBoardFacade.getInstance(); @@ -431,6 +480,13 @@ public void loadPuzzleFromHome(String game, int rows, int columns) } } + /** + * Initializes a puzzle based on the provided game name and an array of statements. + * + * @param game the name of the game or puzzle to load + * @param statements an array of statements to initialize the puzzle + * @throws IllegalArgumentException if the provided arguments are invalid + */ public void loadPuzzleFromHome(String game, String[] statements) { GameBoardFacade facade = GameBoardFacade.getInstance(); try { @@ -443,7 +499,13 @@ public void loadPuzzleFromHome(String game, String[] statements) { } } - // File opener + /** + * Prompts the user to select a puzzle file to open. + * Opens a file chooser dialog and returns the selected file's name and file object. + * If a puzzle is currently loaded, prompts the user to confirm if they want to open a new puzzle. + * + * @return an array containing the selected file name and file object, or null if the operation was canceled + */ public Object[] promptPuzzle() { GameBoardFacade facade = GameBoardFacade.getInstance(); if (facade.getBoard() != null) { @@ -485,6 +547,11 @@ public Object[] promptPuzzle() { return new Object[] {fileName, puzzleFile}; } + /** + * Loads a puzzle by prompting the user to select a puzzle file. + * If the user cancels the operation, no action is taken. If a puzzle file is selected, + * it will be loaded using the file name and file object. + */ public void loadPuzzle() { Object[] items = promptPuzzle(); // Return if items == null (cancel) @@ -496,6 +563,14 @@ public void loadPuzzle() { loadPuzzle(fileName, puzzleFile); } + /** + * Loads a puzzle from the specified file. + * If the puzzle file is valid and exists, it loads the puzzle and updates the UI. + * If the file format is invalid, an error message is displayed. + * + * @param fileName the name of the puzzle file + * @param puzzleFile the file object representing the puzzle file + */ public void loadPuzzle(String fileName, File puzzleFile) { if (puzzleFile != null && puzzleFile.exists()) { try { @@ -519,49 +594,105 @@ public void loadPuzzle(String fileName, File puzzleFile) { } } + /** + * Displays a confirmation dialog with the given instruction message. + * The method returns true if the user selected "No" or cancelled the dialog, + * and false if the user selected "Yes". + * + * @param instr the instruction message to display in the confirmation dialog + * @return true if the user selected "No" or canceled; false if the user selected "Yes" + */ public boolean noQuit(String instr) { int n = JOptionPane.showConfirmDialog(null, instr, "Confirm", JOptionPane.YES_NO_OPTION); return n != JOptionPane.YES_OPTION; } + /** + * {@inheritDoc} + */ @Override public void onPushChange(ICommand command) {} + /** + * {@inheritDoc} + */ @Override public void onUndo(boolean isBottom, boolean isTop) {} + /** + * {@inheritDoc} + */ @Override public void onRedo(boolean isBottom, boolean isTop) {} + /** + * {@inheritDoc} + */ @Override public void onClearHistory() { - // undo.setEnabled(false); - // redo.setEnabled(false); + undo.setEnabled(false); + redo.setEnabled(false); } + + /** + * Returns the current board view + * + * @return the board view + */ public BoardView getBoardView() { return boardView; } + + /** + * Returns the array of buttons for the first toolbar + * + * @return the array of toolbar1 buttons + */ public JButton[] getToolBar1Buttons() { return toolBar1Buttons; } + /** + * Sets the array of buttons for the first toolbar + * + * @param toolBar1Buttons the array of toolbar1 buttons + */ public void setToolBar1Buttons(JButton[] toolBar1Buttons) { this.toolBar1Buttons = toolBar1Buttons; } + /** + * Returns the array of buttons for the second toolbar + * + * @return the array of toolbar2 buttons + */ public JButton[] getToolBar2Buttons() { return toolBar2Buttons; } + /** + * Sets the array of buttons for the second toolbar + * + * @param toolBar2Buttons the array of toolbar2 buttons + */ public void setToolBar2Buttons(JButton[] toolBar2Buttons) { this.toolBar2Buttons = toolBar2Buttons; } + /** + * Repaints the current board view + */ private void repaintAll() { boardView.repaint(); } + /** + * Sets the puzzle view based on the provided puzzle object. + * Updates the UI components to display the new puzzle. + * + * @param puzzle the puzzle object to display + */ public void setPuzzleView(Puzzle puzzle) { this.boardView = puzzle.getBoardView(); editorElementController.setElementController(boardView.getElementController()); @@ -604,6 +735,13 @@ private void direct_save() { } } + /** + * Saves the current puzzle to a user-selected directory. + * Prompts the user to select a directory and saves the puzzle to that directory. + * Returns the path where the puzzle was saved. + * + * @return the path where the puzzle was saved, or an empty string if the save operation was canceled + */ private String savePuzzle() { Puzzle puzzle = GameBoardFacade.getInstance().getPuzzleModule(); if (puzzle == null) { @@ -655,6 +793,11 @@ private String savePuzzle() { return path; } + /** + * Returns the current dynamic board view + * + * @return the dynamic board view + */ public DynamicView getDynamicBoardView() { return dynamicBoardView; } diff --git a/src/main/java/edu/rpi/legup/ui/ScrollView.java b/src/main/java/edu/rpi/legup/ui/ScrollView.java index 0bf8335a2..18aff4d1c 100644 --- a/src/main/java/edu/rpi/legup/ui/ScrollView.java +++ b/src/main/java/edu/rpi/legup/ui/ScrollView.java @@ -6,6 +6,10 @@ import java.util.logging.Logger; import javax.swing.*; +/** + * ScrollView extends {@link JScrollPane} to provide a customizable view with zoom and scroll capabilities. + * It uses a {@link ZoomablePane} as the canvas and allows for zooming and scrolling with respect to the canvas content. + */ public class ScrollView extends JScrollPane { private static final Logger LOGGER = Logger.getLogger(ScrollView.class.getName()); @@ -165,6 +169,11 @@ public void zoom(int n, Point point) { revalidate(); } + /** + * Adjusts the zoom level to the given scale and centers the viewport on the current center point + * + * @param newScale the new scale to set + */ public void zoomTo(double newScale) { // check zoom bounds if (newScale < minScale) { @@ -282,6 +291,11 @@ public void setSize(Dimension size) { updateSize(); } + /** + * Gets the canvas for this {@code ScrollView} + * + * @return the ZoomablePane instance used as the canvas + */ public ZoomablePane getCanvas() { return canvas; } diff --git a/src/main/java/edu/rpi/legup/ui/ToolbarName.java b/src/main/java/edu/rpi/legup/ui/ToolbarName.java index 00bf7b21d..53936a141 100644 --- a/src/main/java/edu/rpi/legup/ui/ToolbarName.java +++ b/src/main/java/edu/rpi/legup/ui/ToolbarName.java @@ -1,5 +1,9 @@ package edu.rpi.legup.ui; +/** + * This enum defines constants for toolbar names used in the user interface. + * Each represents a specific toolbar action. + */ public enum ToolbarName { DIRECTIONS, CHECK; diff --git a/src/main/java/edu/rpi/legup/ui/ZoomWidget.java b/src/main/java/edu/rpi/legup/ui/ZoomWidget.java index aa5b65c4e..34e828250 100644 --- a/src/main/java/edu/rpi/legup/ui/ZoomWidget.java +++ b/src/main/java/edu/rpi/legup/ui/ZoomWidget.java @@ -10,6 +10,10 @@ import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; +/** + * The {@code ZoomWidget} displays a zoom icon that, when clicked, shows a popup slider to adjust + * the zoom level of the associated {@code ScrollView}. + */ public class ZoomWidget extends JLabel { private ScrollView parent; private PopupSlider palette = new PopupSlider(); @@ -32,12 +36,17 @@ public ZoomWidget(ScrollView parent) { addMouseListener(open); } - /** */ + /** + * A {@code JPopupMenu} subclass that contains a vertical slider for adjusting zoom level. + */ private class PopupSlider extends JPopupMenu implements ChangeListener { private static final long serialVersionUID = 8225019381200459814L; private JSlider slider; + /** + * Constructs a {@code PopupSlider} with a vertical slider + */ public PopupSlider() { slider = new JSlider(SwingConstants.VERTICAL, 0, 400, 200); slider.setMajorTickSpacing(25); @@ -47,6 +56,11 @@ public PopupSlider() { slider.addChangeListener(this); } + /** + * Handles state changes in the slider by adjusting the zoom level of the {@code ScrollView} + * + * @param e the {@code ChangeEvent} indicating that the slider's state has changed + */ public void stateChanged(ChangeEvent e) { if (slider.getValueIsAdjusting()) { parent.zoomTo((double) slider.getValue() / 100.0); diff --git a/src/main/java/edu/rpi/legup/ui/ZoomablePane.java b/src/main/java/edu/rpi/legup/ui/ZoomablePane.java index 934d31c53..66af90abd 100644 --- a/src/main/java/edu/rpi/legup/ui/ZoomablePane.java +++ b/src/main/java/edu/rpi/legup/ui/ZoomablePane.java @@ -5,6 +5,10 @@ import java.awt.Graphics2D; import javax.swing.*; +/** + * The {@code ZoomablePane} class is used to display components in a zoomable and scalable manner. + * It uses {@code ScrollView} to handle scaling and drawing of the content. + */ public class ZoomablePane extends JLayeredPane { private ScrollView viewer; From 87ad7777de402ba6515ef42017316297d7eb6e65 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Mon, 19 Aug 2024 12:45:09 -0400 Subject: [PATCH 254/258] Fixed clear history bug --- src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java | 2 -- src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java b/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java index c70e85727..88c1ee427 100644 --- a/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java +++ b/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java @@ -1283,8 +1283,6 @@ public void onPushChange(ICommand command) { */ @Override public void onClearHistory() { - undo.setEnabled(false); - redo.setEnabled(false); } /** diff --git a/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java b/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java index 501923c64..2f3c16eac 100644 --- a/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java +++ b/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java @@ -630,8 +630,6 @@ public void onRedo(boolean isBottom, boolean isTop) {} */ @Override public void onClearHistory() { - undo.setEnabled(false); - redo.setEnabled(false); } From c6ec39ebdb4ae92321361f9690ffe82f5e2a1faf Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Mon, 19 Aug 2024 12:58:04 -0400 Subject: [PATCH 255/258] Fixed Binary Cell merge conflict --- .../rpi/legup/puzzle/binary/BinaryCell.java | 68 ++++++++++++++++--- 1 file changed, 59 insertions(+), 9 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java index 56b37c03e..d09f7115e 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java @@ -1,30 +1,48 @@ package edu.rpi.legup.puzzle.binary; +import edu.rpi.legup.model.elements.Element; import edu.rpi.legup.model.gameboard.GridCell; - import java.awt.Point; +import java.awt.event.MouseEvent; + public class BinaryCell extends GridCell { - public BinaryCell(int valueInt, Point location) { - super(valueInt, location); + /** + * BinaryCell Constructor - creates a BinaryCell from the specified value and location + * + * @param value value of the BinaryCell + * @param location position of the BinaryCell + */ + public BinaryCell(int value, Point location) { + super(value, location); } + /** + * Gets the type of this BinaryCell + * + * @return type of BinaryCell + */ public BinaryType getType() { switch (data) { - case -2: - return BinaryType.UNKNOWN; - case -1: - return BinaryType.ZERO; case 0: + return BinaryType.ZERO; + case 1: return BinaryType.ONE; + case 2: + return BinaryType.UNKNOWN; default: - if (data > 0) { - return BinaryType.NUMBER; + if (data > 1) { + return BinaryType.UNKNOWN; } } return null; } + /** + * Performs a deep copy on the BinaryCell + * + * @return a new copy of the BinaryCell that is independent of this one + */ @Override public BinaryCell copy() { BinaryCell copy = new BinaryCell(data, (Point) location.clone()); @@ -33,4 +51,36 @@ public BinaryCell copy() { copy.setGiven(isGiven); return copy; } + + /** + * Sets the type of this BinaryCell + * + * @param e element to set the type of this binary cell to + */ + @Override + public void setType(Element e, MouseEvent m) { + if (e.getElementName().equals("Number Tile")) { + if (m.getButton() == MouseEvent.BUTTON1) { + if (this.data == 2) { + this.data = 0; + } + else { + this.data = this.data + 1; + } + } + else { + if (m.getButton() == MouseEvent.BUTTON3) { + if (this.data > 0) { + this.data = this.data - 1; + } + else { + this.data = 2; + } + } + } + } + else { // unknown tile + this.data = 2; + } + } } \ No newline at end of file From c2744368a2d5f1b464565171c6147c6c22cf54fd Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Mon, 19 Aug 2024 13:51:33 -0400 Subject: [PATCH 256/258] Starbattle rules causing checkstyle error on github --- .../rules/BlackoutDirectRuleTest.java | 432 +++++------ .../ClashingOrbitContradictionRuleTest.java | 274 +++---- .../ColumnsWithinRegionsDirectRuleTest.java | 648 ++++++++-------- .../ColumnsWithinRowsDirectRuleTest.java | 488 ++++++------ .../rules/EmptyAdjacentDirectRuleTest.java | 354 ++++----- .../rules/FinishWithStarsDirectRuleTest.java | 418 +++++------ .../RegionsWithinColumnsDirectRuleTest.java | 706 +++++++++--------- .../RegionsWithinRowsDirectRuleTest.java | 516 ++++++------- .../rules/StarOrEmptyCaseRuleTest.java | 136 ++-- .../rules/SurroundStarDirectRuleTest.java | 346 ++++----- .../TooFewStarsContradictionRuleTest.java | 410 +++++----- .../TooManyStarsContradictionRuleTests.java | 274 +++---- 12 files changed, 2501 insertions(+), 2501 deletions(-) diff --git a/src/test/java/puzzles/starbattle/rules/BlackoutDirectRuleTest.java b/src/test/java/puzzles/starbattle/rules/BlackoutDirectRuleTest.java index 76367ace5..d1ca68d47 100644 --- a/src/test/java/puzzles/starbattle/rules/BlackoutDirectRuleTest.java +++ b/src/test/java/puzzles/starbattle/rules/BlackoutDirectRuleTest.java @@ -1,216 +1,216 @@ -package puzzles.starbattle.rules; - -import edu.rpi.legup.puzzle.starbattle.rules.BlackoutDirectRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -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.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 { - private static final BlackoutDirectRule RULE = new BlackoutDirectRule(); - private static StarBattle starBattle; - - @BeforeClass - public static void setUp() { - MockGameBoardFacade.getInstance(); - starBattle = new StarBattle(); - } - - /* Blackout Direct Rule where star is in the corner */ - @Test - public void BlackoutDirectRuleTestCorner() - throws InvalidFileFormatException - { - TestUtilities.importTestBoard("puzzles/starbattle/rules/BlackoutDirectRule/Corner", starBattle); - TreeNode rootNode = starBattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell1 = board.getCell(1,0); - cell1.setData(StarBattleCellType.BLACK.value); - StarBattleCell cell2 = board.getCell(2,0); - cell2.setData(StarBattleCellType.BLACK.value); - StarBattleCell cell3 = board.getCell(3,0); - cell3.setData(StarBattleCellType.BLACK.value); - StarBattleCell cell4 = board.getCell(0,1); - cell4.setData(StarBattleCellType.BLACK.value); - StarBattleCell cell5 = board.getCell(1,1); - cell5.setData(StarBattleCellType.BLACK.value); - StarBattleCell cell6 = board.getCell(0,2); - cell6.setData(StarBattleCellType.BLACK.value); - StarBattleCell cell7 = board.getCell(0,3); - cell7.setData(StarBattleCellType.BLACK.value); - - board.addModifiedData(cell1); - board.addModifiedData(cell2); - board.addModifiedData(cell3); - board.addModifiedData(cell4); - board.addModifiedData(cell5); - board.addModifiedData(cell6); - board.addModifiedData(cell7); - - Assert.assertNull(RULE.checkRule(transition)); - - for (int i = 0; i < board.getHeight(); ++i) { - for (int j = 0; j < board.getWidth(); ++j) { - Point point = new Point(j,i); - if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) || - point.equals(cell3.getLocation()) || point.equals(cell4.getLocation()) || - point.equals(cell5.getLocation()) || point.equals(cell6.getLocation()) || - point.equals(cell7.getLocation())) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - } - } - } - /* Blackout Direct Rule where star is on the edge */ - @Test - public void BlackoutDirectRuleTestEdge() - throws InvalidFileFormatException - { - TestUtilities.importTestBoard("puzzles/starbattle/rules/BlackoutDirectRule/Edge", starBattle); - TreeNode rootNode = starBattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell1 = board.getCell(0,0); - cell1.setData(StarBattleCellType.BLACK.value); - StarBattleCell cell2 = board.getCell(2,0); - cell2.setData(StarBattleCellType.BLACK.value); - StarBattleCell cell3 = board.getCell(3,0); - cell3.setData(StarBattleCellType.BLACK.value); - StarBattleCell cell4 = board.getCell(0,1); - cell4.setData(StarBattleCellType.BLACK.value); - StarBattleCell cell5 = board.getCell(1,1); - cell5.setData(StarBattleCellType.BLACK.value); - StarBattleCell cell6 = board.getCell(1,2); - cell6.setData(StarBattleCellType.BLACK.value); - StarBattleCell cell7 = board.getCell(1,3); - cell7.setData(StarBattleCellType.BLACK.value); - - board.addModifiedData(cell1); - board.addModifiedData(cell2); - board.addModifiedData(cell3); - board.addModifiedData(cell4); - board.addModifiedData(cell5); - board.addModifiedData(cell6); - board.addModifiedData(cell7); - - Assert.assertNull(RULE.checkRule(transition)); - - for (int i = 0; i < board.getHeight(); ++i) { - for (int j = 0; j < board.getWidth(); ++j) { - Point point = new Point(j,i); - if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) || - point.equals(cell3.getLocation()) || point.equals(cell4.getLocation()) || - point.equals(cell5.getLocation()) || point.equals(cell6.getLocation()) || - point.equals(cell7.getLocation())) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - } - } - } - - /* Blackout Direct Rule where star is on the edge */ - @Test - public void BlackoutDirectRuleTestMiddle() - throws InvalidFileFormatException - { - TestUtilities.importTestBoard("puzzles/starbattle/rules/BlackoutDirectRule/Middle", starBattle); - TreeNode rootNode = starBattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell1 = board.getCell(0,0); - cell1.setData(StarBattleCellType.BLACK.value); - StarBattleCell cell2 = board.getCell(1,0); - cell2.setData(StarBattleCellType.BLACK.value); - StarBattleCell cell3 = board.getCell(0,1); - cell3.setData(StarBattleCellType.BLACK.value); - StarBattleCell cell4 = board.getCell(2,1); - cell4.setData(StarBattleCellType.BLACK.value); - StarBattleCell cell5 = board.getCell(3,1); - cell5.setData(StarBattleCellType.BLACK.value); - StarBattleCell cell6 = board.getCell(1,2); - cell6.setData(StarBattleCellType.BLACK.value); - StarBattleCell cell7 = board.getCell(1,3); - cell7.setData(StarBattleCellType.BLACK.value); - - board.addModifiedData(cell1); - board.addModifiedData(cell2); - board.addModifiedData(cell3); - board.addModifiedData(cell4); - board.addModifiedData(cell5); - board.addModifiedData(cell6); - board.addModifiedData(cell7); - - Assert.assertNull(RULE.checkRule(transition)); - - for (int i = 0; i < board.getHeight(); ++i) { - for (int j = 0; j < board.getWidth(); ++j) { - Point point = new Point(j,i); - if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) || - point.equals(cell3.getLocation()) || point.equals(cell4.getLocation()) || - point.equals(cell5.getLocation()) || point.equals(cell6.getLocation()) || - point.equals(cell7.getLocation())) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - } - } - } - /* Blackout Direct Rule where rule is called incorrectly */ - @Test - public void BlackoutDirectRuleTestFalse() - throws InvalidFileFormatException - { - TestUtilities.importTestBoard("puzzles/starbattle/rules/BlackoutDirectRule/Middle", starBattle); - TreeNode rootNode = starBattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell1 = board.getCell(2,2); - cell1.setData(StarBattleCellType.BLACK.value); - StarBattleCell cell2 = board.getCell(2,3); - cell2.setData(StarBattleCellType.BLACK.value); - StarBattleCell cell3 = board.getCell(3,2); - cell3.setData(StarBattleCellType.BLACK.value); - StarBattleCell cell4 = board.getCell(3,3); - - board.addModifiedData(cell1); - board.addModifiedData(cell2); - board.addModifiedData(cell3); - board.addModifiedData(cell4); - - Assert.assertNotNull(RULE.checkRule(transition)); - - for (int i = 0; i < board.getHeight(); ++i) { - for (int j = 0; j < board.getWidth(); ++j) { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - } - } - - -} +//package puzzles.starbattle.rules; +// +//import edu.rpi.legup.puzzle.starbattle.rules.BlackoutDirectRule; +//import edu.rpi.legup.model.tree.TreeNode; +//import edu.rpi.legup.model.tree.TreeTransition; +//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.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 { +// private static final BlackoutDirectRule RULE = new BlackoutDirectRule(); +// private static StarBattle starBattle; +// +// @BeforeClass +// public static void setUp() { +// MockGameBoardFacade.getInstance(); +// starBattle = new StarBattle(); +// } +// +// /* Blackout Direct Rule where star is in the corner */ +// @Test +// public void BlackoutDirectRuleTestCorner() +// throws InvalidFileFormatException +// { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/BlackoutDirectRule/Corner", starBattle); +// TreeNode rootNode = starBattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell1 = board.getCell(1,0); +// cell1.setData(StarBattleCellType.BLACK.value); +// StarBattleCell cell2 = board.getCell(2,0); +// cell2.setData(StarBattleCellType.BLACK.value); +// StarBattleCell cell3 = board.getCell(3,0); +// cell3.setData(StarBattleCellType.BLACK.value); +// StarBattleCell cell4 = board.getCell(0,1); +// cell4.setData(StarBattleCellType.BLACK.value); +// StarBattleCell cell5 = board.getCell(1,1); +// cell5.setData(StarBattleCellType.BLACK.value); +// StarBattleCell cell6 = board.getCell(0,2); +// cell6.setData(StarBattleCellType.BLACK.value); +// StarBattleCell cell7 = board.getCell(0,3); +// cell7.setData(StarBattleCellType.BLACK.value); +// +// board.addModifiedData(cell1); +// board.addModifiedData(cell2); +// board.addModifiedData(cell3); +// board.addModifiedData(cell4); +// board.addModifiedData(cell5); +// board.addModifiedData(cell6); +// board.addModifiedData(cell7); +// +// Assert.assertNull(RULE.checkRule(transition)); +// +// for (int i = 0; i < board.getHeight(); ++i) { +// for (int j = 0; j < board.getWidth(); ++j) { +// Point point = new Point(j,i); +// if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) || +// point.equals(cell3.getLocation()) || point.equals(cell4.getLocation()) || +// point.equals(cell5.getLocation()) || point.equals(cell6.getLocation()) || +// point.equals(cell7.getLocation())) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); +// } +// else { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); +// } +// } +// } +// } +// /* Blackout Direct Rule where star is on the edge */ +// @Test +// public void BlackoutDirectRuleTestEdge() +// throws InvalidFileFormatException +// { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/BlackoutDirectRule/Edge", starBattle); +// TreeNode rootNode = starBattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell1 = board.getCell(0,0); +// cell1.setData(StarBattleCellType.BLACK.value); +// StarBattleCell cell2 = board.getCell(2,0); +// cell2.setData(StarBattleCellType.BLACK.value); +// StarBattleCell cell3 = board.getCell(3,0); +// cell3.setData(StarBattleCellType.BLACK.value); +// StarBattleCell cell4 = board.getCell(0,1); +// cell4.setData(StarBattleCellType.BLACK.value); +// StarBattleCell cell5 = board.getCell(1,1); +// cell5.setData(StarBattleCellType.BLACK.value); +// StarBattleCell cell6 = board.getCell(1,2); +// cell6.setData(StarBattleCellType.BLACK.value); +// StarBattleCell cell7 = board.getCell(1,3); +// cell7.setData(StarBattleCellType.BLACK.value); +// +// board.addModifiedData(cell1); +// board.addModifiedData(cell2); +// board.addModifiedData(cell3); +// board.addModifiedData(cell4); +// board.addModifiedData(cell5); +// board.addModifiedData(cell6); +// board.addModifiedData(cell7); +// +// Assert.assertNull(RULE.checkRule(transition)); +// +// for (int i = 0; i < board.getHeight(); ++i) { +// for (int j = 0; j < board.getWidth(); ++j) { +// Point point = new Point(j,i); +// if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) || +// point.equals(cell3.getLocation()) || point.equals(cell4.getLocation()) || +// point.equals(cell5.getLocation()) || point.equals(cell6.getLocation()) || +// point.equals(cell7.getLocation())) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); +// } +// else { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); +// } +// } +// } +// } +// +// /* Blackout Direct Rule where star is on the edge */ +// @Test +// public void BlackoutDirectRuleTestMiddle() +// throws InvalidFileFormatException +// { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/BlackoutDirectRule/Middle", starBattle); +// TreeNode rootNode = starBattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell1 = board.getCell(0,0); +// cell1.setData(StarBattleCellType.BLACK.value); +// StarBattleCell cell2 = board.getCell(1,0); +// cell2.setData(StarBattleCellType.BLACK.value); +// StarBattleCell cell3 = board.getCell(0,1); +// cell3.setData(StarBattleCellType.BLACK.value); +// StarBattleCell cell4 = board.getCell(2,1); +// cell4.setData(StarBattleCellType.BLACK.value); +// StarBattleCell cell5 = board.getCell(3,1); +// cell5.setData(StarBattleCellType.BLACK.value); +// StarBattleCell cell6 = board.getCell(1,2); +// cell6.setData(StarBattleCellType.BLACK.value); +// StarBattleCell cell7 = board.getCell(1,3); +// cell7.setData(StarBattleCellType.BLACK.value); +// +// board.addModifiedData(cell1); +// board.addModifiedData(cell2); +// board.addModifiedData(cell3); +// board.addModifiedData(cell4); +// board.addModifiedData(cell5); +// board.addModifiedData(cell6); +// board.addModifiedData(cell7); +// +// Assert.assertNull(RULE.checkRule(transition)); +// +// for (int i = 0; i < board.getHeight(); ++i) { +// for (int j = 0; j < board.getWidth(); ++j) { +// Point point = new Point(j,i); +// if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) || +// point.equals(cell3.getLocation()) || point.equals(cell4.getLocation()) || +// point.equals(cell5.getLocation()) || point.equals(cell6.getLocation()) || +// point.equals(cell7.getLocation())) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); +// } +// else { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); +// } +// } +// } +// } +// /* Blackout Direct Rule where rule is called incorrectly */ +// @Test +// public void BlackoutDirectRuleTestFalse() +// throws InvalidFileFormatException +// { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/BlackoutDirectRule/Middle", starBattle); +// TreeNode rootNode = starBattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell1 = board.getCell(2,2); +// cell1.setData(StarBattleCellType.BLACK.value); +// StarBattleCell cell2 = board.getCell(2,3); +// cell2.setData(StarBattleCellType.BLACK.value); +// StarBattleCell cell3 = board.getCell(3,2); +// cell3.setData(StarBattleCellType.BLACK.value); +// StarBattleCell cell4 = board.getCell(3,3); +// +// board.addModifiedData(cell1); +// board.addModifiedData(cell2); +// board.addModifiedData(cell3); +// board.addModifiedData(cell4); +// +// Assert.assertNotNull(RULE.checkRule(transition)); +// +// for (int i = 0; i < board.getHeight(); ++i) { +// for (int j = 0; j < board.getWidth(); ++j) { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); +// } +// } +// } +// +// +//} diff --git a/src/test/java/puzzles/starbattle/rules/ClashingOrbitContradictionRuleTest.java b/src/test/java/puzzles/starbattle/rules/ClashingOrbitContradictionRuleTest.java index ae8aaa08e..193177138 100644 --- a/src/test/java/puzzles/starbattle/rules/ClashingOrbitContradictionRuleTest.java +++ b/src/test/java/puzzles/starbattle/rules/ClashingOrbitContradictionRuleTest.java @@ -1,137 +1,137 @@ -package puzzles.starbattle.rules; - -import edu.rpi.legup.puzzle.starbattle.rules.ClashingOrbitContradictionRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -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.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 ClashingOrbitContradictionRuleTest { - - private static final ClashingOrbitContradictionRule RULE = new ClashingOrbitContradictionRule(); - private static StarBattle starBattle; - - @BeforeClass - public static void setUp() { - MockGameBoardFacade.getInstance(); - starBattle = new StarBattle(); - } - - /*Tests the Clashing Orbit contradiction rule for directly adjacent stars not at the - edge of the board */ - @Test - public void ClashingOrbitContradictionRule_DirectlyAdjacentCenter() - throws InvalidFileFormatException - { - TestUtilities.importTestBoard("puzzles/starbattle/rules/ClashingOrbitContradictionRule/DirectlyAdjacentCenter", starBattle); - TreeNode rootNode = starBattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell1 = board.getCell(1,1); - StarBattleCell cell2 = board.getCell(2,1); - - Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); - - for (int i = 0; i < board.getHeight(); ++i) { - for (int j = 0; j < board.getWidth(); ++j) { - Point point = new Point(j,i); - if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - } - } - } - - /* Tests the Clashing Orbit contradiction rule for diagonally adjacent stars */ - @Test - public void ClashingOrbitContradictionRule_DiagonallyAdjacent() - throws InvalidFileFormatException - { - TestUtilities.importTestBoard("puzzles/starbattle/rules/ClashingOrbitContradictionRule/DiagonallyAdjacent", starBattle); - TreeNode rootNode = starBattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell1 = board.getCell(1,1); - StarBattleCell cell2 = board.getCell(2,2); - - Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); - - for (int i = 0; i < board.getHeight(); ++i) { - for (int j = 0; j < board.getWidth(); ++j) { - Point point = new Point(j,i); - if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - } - } - } - - /*Tests the Clashing Orbit contradiction rule for stars at the edge of the board */ - @Test - public void ClashingOrbitContradictionRule_DirectlyAdjacentEdge() - throws InvalidFileFormatException - { - TestUtilities.importTestBoard("puzzles/starbattle/rules/ClashingOrbitContradictionRule/DirectlyAdjacentEdge", starBattle); - TreeNode rootNode = starBattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell1 = board.getCell(0,0); - StarBattleCell cell2 = board.getCell(1,0); - - Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); - - for (int i = 0; i < board.getHeight(); ++i) { - for (int j = 0; j < board.getWidth(); ++j) { - Point point = new Point(j,i); - if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - } - } - } - - /*Tests the Clashing Orbit contradiction rule for a false contradiction. */ - @Test - public void ClashingOrbitContradictionRule_FalseContradiction() - throws InvalidFileFormatException - { - TestUtilities.importTestBoard("puzzles/starbattle/rules/ClashingOrbitContradictionRule/FalseContradiction", starBattle); - TreeNode rootNode = starBattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - - Assert.assertNotNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); - - for (int i = 0; i < board.getHeight(); ++i) { - for (int j = 0; j < board.getWidth(); ++j) { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - } - } -} +//package puzzles.starbattle.rules; +// +//import edu.rpi.legup.puzzle.starbattle.rules.ClashingOrbitContradictionRule; +//import edu.rpi.legup.model.tree.TreeNode; +//import edu.rpi.legup.model.tree.TreeTransition; +//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.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 ClashingOrbitContradictionRuleTest { +// +// private static final ClashingOrbitContradictionRule RULE = new ClashingOrbitContradictionRule(); +// private static StarBattle starBattle; +// +// @BeforeClass +// public static void setUp() { +// MockGameBoardFacade.getInstance(); +// starBattle = new StarBattle(); +// } +// +// /*Tests the Clashing Orbit contradiction rule for directly adjacent stars not at the +// edge of the board */ +// @Test +// public void ClashingOrbitContradictionRule_DirectlyAdjacentCenter() +// throws InvalidFileFormatException +// { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/ClashingOrbitContradictionRule/DirectlyAdjacentCenter", starBattle); +// TreeNode rootNode = starBattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell1 = board.getCell(1,1); +// StarBattleCell cell2 = board.getCell(2,1); +// +// Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); +// +// for (int i = 0; i < board.getHeight(); ++i) { +// for (int j = 0; j < board.getWidth(); ++j) { +// Point point = new Point(j,i); +// if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); +// } +// else { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); +// } +// } +// } +// } +// +// /* Tests the Clashing Orbit contradiction rule for diagonally adjacent stars */ +// @Test +// public void ClashingOrbitContradictionRule_DiagonallyAdjacent() +// throws InvalidFileFormatException +// { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/ClashingOrbitContradictionRule/DiagonallyAdjacent", starBattle); +// TreeNode rootNode = starBattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell1 = board.getCell(1,1); +// StarBattleCell cell2 = board.getCell(2,2); +// +// Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); +// +// for (int i = 0; i < board.getHeight(); ++i) { +// for (int j = 0; j < board.getWidth(); ++j) { +// Point point = new Point(j,i); +// if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); +// } +// else { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); +// } +// } +// } +// } +// +// /*Tests the Clashing Orbit contradiction rule for stars at the edge of the board */ +// @Test +// public void ClashingOrbitContradictionRule_DirectlyAdjacentEdge() +// throws InvalidFileFormatException +// { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/ClashingOrbitContradictionRule/DirectlyAdjacentEdge", starBattle); +// TreeNode rootNode = starBattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell1 = board.getCell(0,0); +// StarBattleCell cell2 = board.getCell(1,0); +// +// Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); +// +// for (int i = 0; i < board.getHeight(); ++i) { +// for (int j = 0; j < board.getWidth(); ++j) { +// Point point = new Point(j,i); +// if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); +// } +// else { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); +// } +// } +// } +// } +// +// /*Tests the Clashing Orbit contradiction rule for a false contradiction. */ +// @Test +// public void ClashingOrbitContradictionRule_FalseContradiction() +// throws InvalidFileFormatException +// { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/ClashingOrbitContradictionRule/FalseContradiction", starBattle); +// TreeNode rootNode = starBattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// +// Assert.assertNotNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); +// +// for (int i = 0; i < board.getHeight(); ++i) { +// for (int j = 0; j < board.getWidth(); ++j) { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); +// } +// } +// } +//} diff --git a/src/test/java/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRuleTest.java b/src/test/java/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRuleTest.java index 185d31f5c..3a11c6606 100644 --- a/src/test/java/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRuleTest.java +++ b/src/test/java/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRuleTest.java @@ -1,324 +1,324 @@ -package puzzles.starbattle.rules; - -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -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.ColumnsWithinRegionsDirectRule; -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.awt.*; - -public class ColumnsWithinRegionsDirectRuleTest { - - private static final ColumnsWithinRegionsDirectRule RULE = new ColumnsWithinRegionsDirectRule(); - private static StarBattle starbattle; - - @BeforeClass - public static void setUp() { - MockGameBoardFacade.getInstance(); - starbattle = new StarBattle(); - } - - @Test - public void ColumnsWithinRegionsDirectRule_OneColumnOneCell() - throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/OneColumnOneCell", starbattle); - TreeNode rootNode = starbattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell = board.getCell(1,0); - cell.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell); - - Assert.assertNull(RULE.checkRule(transition)); - - Point location = new Point(1, 0); - 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(location)) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - } - } - } - - @Test - public void ColumnsWithinRegionsDirectRule_PartialColumnOneCell() - throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/PartialColumnOneCell", starbattle); - TreeNode rootNode = starbattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell = board.getCell(1,2); - cell.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell); - - Assert.assertNull(RULE.checkRule(transition)); - - Point location = new Point(1, 2); - 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(location)) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - } - } - } - - @Test - public void ColumnsWithinRegionsDirectRule_PartialColumnTwoCells() - throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/PartialColumnTwoCells", starbattle); - TreeNode rootNode = starbattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell1 = board.getCell(0,1); - cell1.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell1); - StarBattleCell cell2 = board.getCell(2,1); - cell2.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell2); - - Assert.assertNull(RULE.checkRule(transition)); - - Point location1 = new Point(0, 1); - Point location2 = new Point(2,1); - 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(location1) || point.equals(location2)) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - } - } - } - - @Test - public void ColumnsWithinRegionsDirectRule_TwoColumns() - throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/TwoColumns", starbattle); - TreeNode rootNode = starbattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell1 = board.getCell(2,1); - cell1.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell1); - StarBattleCell cell2 = board.getCell(2,2); - cell2.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell2); - - Assert.assertNull(RULE.checkRule(transition)); - - Point location1 = new Point(2, 1); - Point location2 = new Point(2,2); - 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(location1) || point.equals(location2)) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - } - } - } - - /* Wrote this to figure out the specifics of how the rule is functioning - might change - * what the expected result is. */ - @Test - public void ColumnsWithinRegionsDirectRule_TwoColumnsWaitAMinute() - throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/TwoColumns", starbattle); - TreeNode rootNode = starbattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell1 = board.getCell(2,1); - cell1.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell1); - - Assert.assertNull(RULE.checkRule(transition)); - - Point location1 = new Point(2, 1); - 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(location1)) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - } - } - } - - @Test - public void ColumnsWithinRegionsDirectRule_TwoColumnsStarOverlap() - throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/TwoColumnsStarOverlap", starbattle); - TreeNode rootNode = starbattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell1 = board.getCell(2,3); - cell1.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell1); - - Assert.assertNull(RULE.checkRule(transition)); - - Point location1 = new Point(2, 3); - 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(location1)) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - } - } - } - - @Test - public void ColumnsWithinRegionsDirectRule_FalseColumnsWithinRegions1() - throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/OneColumnOneCell", starbattle); - TreeNode rootNode = starbattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell1 = board.getCell(1,0); - cell1.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell1); - StarBattleCell cell2 = board.getCell(0,0); - cell2.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell2); - - Assert.assertNotNull(RULE.checkRule(transition)); - - Point location = new Point(1, 0); - 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(location)) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - } - } - } - - @Test - public void ColumnsWithinRegionsDirectRule_FalseColumnsWithinRegions2() - throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/OneColumnOneCell", starbattle); - TreeNode rootNode = starbattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell1 = board.getCell(1,0); - cell1.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell1); - StarBattleCell cell2 = board.getCell(1,1); - cell2.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell2); - - Assert.assertNotNull(RULE.checkRule(transition)); - - Point location = new Point(1, 0); - 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(location)) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - } - } - } - - @Test - public void ColumnsWithinRegionsDirectRule_PartialRemoval() - throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/PartialColumnTwoCells", starbattle); - TreeNode rootNode = starbattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell1 = board.getCell(0,1); - cell1.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell1); - - Assert.assertNull(RULE.checkRule(transition)); - - Point location1 = new Point(0, 1); - 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(location1)) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - } - } - } - - @Test - public void ColumnsWithinRegionsDirectRule_FalseColumnsWithinRegions4() - throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/FalseStarOverlap", starbattle); - TreeNode rootNode = starbattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell1 = board.getCell(2,2); - cell1.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell1); - StarBattleCell cell2 = board.getCell(2,3); - cell2.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell2); - - Assert.assertNotNull(RULE.checkRule(transition)); - - for (int i = 0; i < board.getHeight(); i++) { - for (int k = 0; k < board.getWidth(); k++) { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - } - } - -} +//package puzzles.starbattle.rules; +// +//import edu.rpi.legup.model.tree.TreeNode; +//import edu.rpi.legup.model.tree.TreeTransition; +//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.ColumnsWithinRegionsDirectRule; +//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.awt.*; +// +//public class ColumnsWithinRegionsDirectRuleTest { +// +// private static final ColumnsWithinRegionsDirectRule RULE = new ColumnsWithinRegionsDirectRule(); +// private static StarBattle starbattle; +// +// @BeforeClass +// public static void setUp() { +// MockGameBoardFacade.getInstance(); +// starbattle = new StarBattle(); +// } +// +// @Test +// public void ColumnsWithinRegionsDirectRule_OneColumnOneCell() +// throws InvalidFileFormatException { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/OneColumnOneCell", starbattle); +// TreeNode rootNode = starbattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell = board.getCell(1,0); +// cell.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell); +// +// Assert.assertNull(RULE.checkRule(transition)); +// +// Point location = new Point(1, 0); +// 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(location)) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } else { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } +// } +// } +// } +// +// @Test +// public void ColumnsWithinRegionsDirectRule_PartialColumnOneCell() +// throws InvalidFileFormatException { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/PartialColumnOneCell", starbattle); +// TreeNode rootNode = starbattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell = board.getCell(1,2); +// cell.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell); +// +// Assert.assertNull(RULE.checkRule(transition)); +// +// Point location = new Point(1, 2); +// 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(location)) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } else { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } +// } +// } +// } +// +// @Test +// public void ColumnsWithinRegionsDirectRule_PartialColumnTwoCells() +// throws InvalidFileFormatException { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/PartialColumnTwoCells", starbattle); +// TreeNode rootNode = starbattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell1 = board.getCell(0,1); +// cell1.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell1); +// StarBattleCell cell2 = board.getCell(2,1); +// cell2.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell2); +// +// Assert.assertNull(RULE.checkRule(transition)); +// +// Point location1 = new Point(0, 1); +// Point location2 = new Point(2,1); +// 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(location1) || point.equals(location2)) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } else { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } +// } +// } +// } +// +// @Test +// public void ColumnsWithinRegionsDirectRule_TwoColumns() +// throws InvalidFileFormatException { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/TwoColumns", starbattle); +// TreeNode rootNode = starbattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell1 = board.getCell(2,1); +// cell1.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell1); +// StarBattleCell cell2 = board.getCell(2,2); +// cell2.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell2); +// +// Assert.assertNull(RULE.checkRule(transition)); +// +// Point location1 = new Point(2, 1); +// Point location2 = new Point(2,2); +// 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(location1) || point.equals(location2)) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } else { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } +// } +// } +// } +// +// /* Wrote this to figure out the specifics of how the rule is functioning - might change +// * what the expected result is. */ +// @Test +// public void ColumnsWithinRegionsDirectRule_TwoColumnsWaitAMinute() +// throws InvalidFileFormatException { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/TwoColumns", starbattle); +// TreeNode rootNode = starbattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell1 = board.getCell(2,1); +// cell1.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell1); +// +// Assert.assertNull(RULE.checkRule(transition)); +// +// Point location1 = new Point(2, 1); +// 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(location1)) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } else { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } +// } +// } +// } +// +// @Test +// public void ColumnsWithinRegionsDirectRule_TwoColumnsStarOverlap() +// throws InvalidFileFormatException { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/TwoColumnsStarOverlap", starbattle); +// TreeNode rootNode = starbattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell1 = board.getCell(2,3); +// cell1.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell1); +// +// Assert.assertNull(RULE.checkRule(transition)); +// +// Point location1 = new Point(2, 3); +// 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(location1)) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } else { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } +// } +// } +// } +// +// @Test +// public void ColumnsWithinRegionsDirectRule_FalseColumnsWithinRegions1() +// throws InvalidFileFormatException { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/OneColumnOneCell", starbattle); +// TreeNode rootNode = starbattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell1 = board.getCell(1,0); +// cell1.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell1); +// StarBattleCell cell2 = board.getCell(0,0); +// cell2.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell2); +// +// Assert.assertNotNull(RULE.checkRule(transition)); +// +// Point location = new Point(1, 0); +// 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(location)) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } else { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } +// } +// } +// } +// +// @Test +// public void ColumnsWithinRegionsDirectRule_FalseColumnsWithinRegions2() +// throws InvalidFileFormatException { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/OneColumnOneCell", starbattle); +// TreeNode rootNode = starbattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell1 = board.getCell(1,0); +// cell1.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell1); +// StarBattleCell cell2 = board.getCell(1,1); +// cell2.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell2); +// +// Assert.assertNotNull(RULE.checkRule(transition)); +// +// Point location = new Point(1, 0); +// 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(location)) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } else { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } +// } +// } +// } +// +// @Test +// public void ColumnsWithinRegionsDirectRule_PartialRemoval() +// throws InvalidFileFormatException { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/PartialColumnTwoCells", starbattle); +// TreeNode rootNode = starbattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell1 = board.getCell(0,1); +// cell1.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell1); +// +// Assert.assertNull(RULE.checkRule(transition)); +// +// Point location1 = new Point(0, 1); +// 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(location1)) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } +// else { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } +// } +// } +// } +// +// @Test +// public void ColumnsWithinRegionsDirectRule_FalseColumnsWithinRegions4() +// throws InvalidFileFormatException { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/FalseStarOverlap", starbattle); +// TreeNode rootNode = starbattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell1 = board.getCell(2,2); +// cell1.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell1); +// StarBattleCell cell2 = board.getCell(2,3); +// cell2.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell2); +// +// Assert.assertNotNull(RULE.checkRule(transition)); +// +// for (int i = 0; i < board.getHeight(); i++) { +// for (int k = 0; k < board.getWidth(); k++) { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } +// } +// } +// +//} diff --git a/src/test/java/puzzles/starbattle/rules/ColumnsWithinRowsDirectRuleTest.java b/src/test/java/puzzles/starbattle/rules/ColumnsWithinRowsDirectRuleTest.java index 8f9c938cb..80f15f0f8 100644 --- a/src/test/java/puzzles/starbattle/rules/ColumnsWithinRowsDirectRuleTest.java +++ b/src/test/java/puzzles/starbattle/rules/ColumnsWithinRowsDirectRuleTest.java @@ -1,244 +1,244 @@ -package puzzles.starbattle.rules; - -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -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.ColumnsWithinRowsDirectRule; -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.awt.*; - -public class ColumnsWithinRowsDirectRuleTest { - - private static final ColumnsWithinRowsDirectRule RULE = new ColumnsWithinRowsDirectRule(); - private static StarBattle starbattle; - - @BeforeClass - public static void setUp() { - MockGameBoardFacade.getInstance(); - starbattle = new StarBattle(); - } - - @Test - public void ColumnsWithinRowsDirectRule_OneColumn() - throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/OneColumn", starbattle); - TreeNode rootNode = starbattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell1 = board.getCell(1,0); - cell1.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell1); - StarBattleCell cell2 = board.getCell(2,0); - cell2.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell2); - - Assert.assertNull(RULE.checkRule(transition)); - - Point location1 = new Point(1, 0); - Point location2 = new Point(2,0); - 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(location1) || point.equals(location2)) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - } - } - } - - @Test - public void ColumnsWithinRowsDirectRule_TwoColumns() - throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/TwoColumns", starbattle); - TreeNode rootNode = starbattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell1 = board.getCell(2,1); - cell1.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell1); - StarBattleCell cell2 = board.getCell(2,0); - cell2.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell2); - - Assert.assertNull(RULE.checkRule(transition)); - - Point location1 = new Point(2, 1); - Point location2 = new Point(2,0); - 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(location1) || point.equals(location2)) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - } - } - } - - @Test - public void ColumnsWithinRowsDirectRule_NonAdjacentColumns() - throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/NonAdjacentColumns", starbattle); - TreeNode rootNode = starbattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell1 = board.getCell(1,0); - cell1.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell1); - StarBattleCell cell2 = board.getCell(1,2); - cell2.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell2); - - Assert.assertNull(RULE.checkRule(transition)); - - Point location1 = new Point(1, 0); - Point location2 = new Point(1,2); - 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(location1) || point.equals(location2)) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - } - } - } - - @Test - public void ColumnsWithinRowsDirectRule_TwoColumnsStarOverlap() - throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/TwoColumnsStarOverlap", starbattle); - TreeNode rootNode = starbattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell1 = board.getCell(2,1); - cell1.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell1); - StarBattleCell cell2 = board.getCell(3,0); - cell2.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell2); - - Assert.assertNull(RULE.checkRule(transition)); - - Point location1 = new Point(2, 1); - Point location2 = new Point(3,0); - 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(location1) || point.equals(location2)) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - } - } - } - - @Test - public void ColumnsWithinRowsDirectRule_FalseColumnsWithinRows1() - throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/OneColumn", starbattle); - TreeNode rootNode = starbattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell1 = board.getCell(1,0); - cell1.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell1); - StarBattleCell cell2 = board.getCell(2,0); - cell2.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell2); - StarBattleCell cell3 = board.getCell(1,1); - cell3.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell3); - - Assert.assertNotNull(RULE.checkRule(transition)); - - Point location1 = new Point(1, 0); - Point location2 = new Point(2,0); - 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(location1) || point.equals(location2)) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - } - } - } - - @Test - public void ColumnsWithinRowsDirectRule_PartialCover() - throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/OneColumn", starbattle); - TreeNode rootNode = starbattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell1 = board.getCell(1,0); - cell1.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell1); - - Assert.assertNull(RULE.checkRule(transition)); - - Point location = new Point(1,0); - 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(location)) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - } - } - } - - @Test - public void ColumnsWithinRowsDirectRule_FalseColumnsWithinRows3() - throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/FalseStarOverlap", starbattle); - TreeNode rootNode = starbattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell1 = board.getCell(1,0); - cell1.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell1); - - Assert.assertNotNull(RULE.checkRule(transition)); - - for (int i = 0; i < board.getHeight(); i++) { - for (int k = 0; k < board.getWidth(); k++) { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - } - } - -} +//package puzzles.starbattle.rules; +// +//import edu.rpi.legup.model.tree.TreeNode; +//import edu.rpi.legup.model.tree.TreeTransition; +//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.ColumnsWithinRowsDirectRule; +//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.awt.*; +// +//public class ColumnsWithinRowsDirectRuleTest { +// +// private static final ColumnsWithinRowsDirectRule RULE = new ColumnsWithinRowsDirectRule(); +// private static StarBattle starbattle; +// +// @BeforeClass +// public static void setUp() { +// MockGameBoardFacade.getInstance(); +// starbattle = new StarBattle(); +// } +// +// @Test +// public void ColumnsWithinRowsDirectRule_OneColumn() +// throws InvalidFileFormatException { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/OneColumn", starbattle); +// TreeNode rootNode = starbattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell1 = board.getCell(1,0); +// cell1.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell1); +// StarBattleCell cell2 = board.getCell(2,0); +// cell2.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell2); +// +// Assert.assertNull(RULE.checkRule(transition)); +// +// Point location1 = new Point(1, 0); +// Point location2 = new Point(2,0); +// 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(location1) || point.equals(location2)) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } else { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } +// } +// } +// } +// +// @Test +// public void ColumnsWithinRowsDirectRule_TwoColumns() +// throws InvalidFileFormatException { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/TwoColumns", starbattle); +// TreeNode rootNode = starbattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell1 = board.getCell(2,1); +// cell1.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell1); +// StarBattleCell cell2 = board.getCell(2,0); +// cell2.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell2); +// +// Assert.assertNull(RULE.checkRule(transition)); +// +// Point location1 = new Point(2, 1); +// Point location2 = new Point(2,0); +// 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(location1) || point.equals(location2)) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } else { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } +// } +// } +// } +// +// @Test +// public void ColumnsWithinRowsDirectRule_NonAdjacentColumns() +// throws InvalidFileFormatException { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/NonAdjacentColumns", starbattle); +// TreeNode rootNode = starbattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell1 = board.getCell(1,0); +// cell1.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell1); +// StarBattleCell cell2 = board.getCell(1,2); +// cell2.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell2); +// +// Assert.assertNull(RULE.checkRule(transition)); +// +// Point location1 = new Point(1, 0); +// Point location2 = new Point(1,2); +// 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(location1) || point.equals(location2)) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } else { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } +// } +// } +// } +// +// @Test +// public void ColumnsWithinRowsDirectRule_TwoColumnsStarOverlap() +// throws InvalidFileFormatException { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/TwoColumnsStarOverlap", starbattle); +// TreeNode rootNode = starbattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell1 = board.getCell(2,1); +// cell1.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell1); +// StarBattleCell cell2 = board.getCell(3,0); +// cell2.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell2); +// +// Assert.assertNull(RULE.checkRule(transition)); +// +// Point location1 = new Point(2, 1); +// Point location2 = new Point(3,0); +// 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(location1) || point.equals(location2)) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } else { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } +// } +// } +// } +// +// @Test +// public void ColumnsWithinRowsDirectRule_FalseColumnsWithinRows1() +// throws InvalidFileFormatException { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/OneColumn", starbattle); +// TreeNode rootNode = starbattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell1 = board.getCell(1,0); +// cell1.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell1); +// StarBattleCell cell2 = board.getCell(2,0); +// cell2.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell2); +// StarBattleCell cell3 = board.getCell(1,1); +// cell3.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell3); +// +// Assert.assertNotNull(RULE.checkRule(transition)); +// +// Point location1 = new Point(1, 0); +// Point location2 = new Point(2,0); +// 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(location1) || point.equals(location2)) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } else { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } +// } +// } +// } +// +// @Test +// public void ColumnsWithinRowsDirectRule_PartialCover() +// throws InvalidFileFormatException { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/OneColumn", starbattle); +// TreeNode rootNode = starbattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell1 = board.getCell(1,0); +// cell1.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell1); +// +// Assert.assertNull(RULE.checkRule(transition)); +// +// Point location = new Point(1,0); +// 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(location)) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } +// else { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } +// } +// } +// } +// +// @Test +// public void ColumnsWithinRowsDirectRule_FalseColumnsWithinRows3() +// throws InvalidFileFormatException { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/FalseStarOverlap", starbattle); +// TreeNode rootNode = starbattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell1 = board.getCell(1,0); +// cell1.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell1); +// +// Assert.assertNotNull(RULE.checkRule(transition)); +// +// for (int i = 0; i < board.getHeight(); i++) { +// for (int k = 0; k < board.getWidth(); k++) { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } +// } +// } +// +//} diff --git a/src/test/java/puzzles/starbattle/rules/EmptyAdjacentDirectRuleTest.java b/src/test/java/puzzles/starbattle/rules/EmptyAdjacentDirectRuleTest.java index c81c74657..5ab05c86b 100644 --- a/src/test/java/puzzles/starbattle/rules/EmptyAdjacentDirectRuleTest.java +++ b/src/test/java/puzzles/starbattle/rules/EmptyAdjacentDirectRuleTest.java @@ -1,177 +1,177 @@ -package puzzles.starbattle.rules; - -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -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.EmptyAdjacentDirectRule; -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 EmptyAdjacentDirectRuleTest { - - private static final EmptyAdjacentDirectRule RULE = new EmptyAdjacentDirectRule(); - private static StarBattle starbattle; - - @BeforeClass - public static void setUp() { - MockGameBoardFacade.getInstance(); - starbattle = new StarBattle(); - } - - @Test - public void EmptyAdjacentDirectRule_OneLeft() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/EmptyAdjacentDirectRule/OneLeft", starbattle); - TreeNode rootNode = starbattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell1 = board.getCell(1,1); - cell1.setData(StarBattleCellType.BLACK.value); - StarBattleCell cell2 = board.getCell(2,1); - cell2.setData(StarBattleCellType.BLACK.value); - StarBattleCell cell3 = board.getCell(3,1); - cell3.setData(StarBattleCellType.BLACK.value); - StarBattleCell cell4 = board.getCell(1,3); - cell4.setData(StarBattleCellType.BLACK.value); - StarBattleCell cell5 = board.getCell(2,3); - cell5.setData(StarBattleCellType.BLACK.value); - StarBattleCell cell6 = board.getCell(3,3); - cell6.setData(StarBattleCellType.BLACK.value); - - board.addModifiedData(cell1); - board.addModifiedData(cell2); - board.addModifiedData(cell3); - board.addModifiedData(cell4); - board.addModifiedData(cell5); - board.addModifiedData(cell6); - - Assert.assertNull(RULE.checkRule(transition)); - - for (int i = 0; i < board.getHeight(); ++i) { - for (int j = 0; j < board.getWidth(); ++j) { - Point point = new Point(j,i); - if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) || - point.equals(cell3.getLocation()) || point.equals(cell4.getLocation()) || - point.equals(cell5.getLocation()) || point.equals(cell6.getLocation())) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - } - } - } - - @Test - public void EmptyAdjacentDirectRule_TwoLeft() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/EmptyAdjacentDirectRule/TwoLeft", starbattle); - TreeNode rootNode = starbattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell1 = board.getCell(1,1); - cell1.setData(StarBattleCellType.BLACK.value); - /* - StarBattleCell cell2 = board.getCell(2,1); - cell2.setData(StarBattleCellType.BLACK.value); - StarBattleCell cell3 = board.getCell(1,3); - cell3.setData(StarBattleCellType.BLACK.value); - StarBattleCell cell4 = board.getCell(2,3); - cell4.setData(StarBattleCellType.BLACK.value); - */ - - board.addModifiedData(cell1); - /* - board.addModifiedData(cell2); - board.addModifiedData(cell3); - board.addModifiedData(cell4); - */ - - Assert.assertNull(RULE.checkRule(transition)); - System.out.println("General Case is done\n"); - for (int i = 0; i < board.getHeight(); ++i) { - for (int j = 0; j < board.getWidth(); ++j) { - Point point = new Point(j,i); - if (point.equals(cell1.getLocation())) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } /* - else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } */ - } - } - } - - @Test - public void EmptyAdjacentDirectRule_ThreeLeft() - throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/EmptyAdjacentDirectRule/TwoLeft", starbattle); - TreeNode rootNode = starbattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell1 = board.getCell(1,1); - cell1.setData(StarBattleCellType.BLACK.value); - StarBattleCell cell2 = board.getCell(2,1); - cell2.setData(StarBattleCellType.BLACK.value); - - board.addModifiedData(cell1); - board.addModifiedData(cell2); - - Assert.assertNull(RULE.checkRule(transition)); - - for (int i = 0; i < board.getHeight(); ++i) { - for (int j = 0; j < board.getWidth(); ++j) { - Point point = new Point(j,i); - if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - } - } - } - - @Test - public void EmptyAdjacentDirectRule_ImproperUseFourLeft() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/EmptyAdjacentDirectRule/ImproperUseFourLeft", starbattle); - TreeNode rootNode = starbattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell1 = board.getCell(1,1); - cell1.setData(StarBattleCellType.BLACK.value); - StarBattleCell cell2 = board.getCell(2,1); - cell2.setData(StarBattleCellType.BLACK.value); - StarBattleCell cell3 = board.getCell(1,3); - cell3.setData(StarBattleCellType.BLACK.value); - StarBattleCell cell4 = board.getCell(2,3); - cell4.setData(StarBattleCellType.BLACK.value); - - board.addModifiedData(cell1); - board.addModifiedData(cell2); - board.addModifiedData(cell3); - board.addModifiedData(cell4); - - Assert.assertNotNull(RULE.checkRule(transition)); - - for (int i = 0; i < board.getHeight(); ++i) { - for (int j = 0; j < board.getWidth(); ++j) { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - } - } -} +//package puzzles.starbattle.rules; +// +//import edu.rpi.legup.model.tree.TreeNode; +//import edu.rpi.legup.model.tree.TreeTransition; +//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.EmptyAdjacentDirectRule; +//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 EmptyAdjacentDirectRuleTest { +// +// private static final EmptyAdjacentDirectRule RULE = new EmptyAdjacentDirectRule(); +// private static StarBattle starbattle; +// +// @BeforeClass +// public static void setUp() { +// MockGameBoardFacade.getInstance(); +// starbattle = new StarBattle(); +// } +// +// @Test +// public void EmptyAdjacentDirectRule_OneLeft() throws InvalidFileFormatException { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/EmptyAdjacentDirectRule/OneLeft", starbattle); +// TreeNode rootNode = starbattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell1 = board.getCell(1,1); +// cell1.setData(StarBattleCellType.BLACK.value); +// StarBattleCell cell2 = board.getCell(2,1); +// cell2.setData(StarBattleCellType.BLACK.value); +// StarBattleCell cell3 = board.getCell(3,1); +// cell3.setData(StarBattleCellType.BLACK.value); +// StarBattleCell cell4 = board.getCell(1,3); +// cell4.setData(StarBattleCellType.BLACK.value); +// StarBattleCell cell5 = board.getCell(2,3); +// cell5.setData(StarBattleCellType.BLACK.value); +// StarBattleCell cell6 = board.getCell(3,3); +// cell6.setData(StarBattleCellType.BLACK.value); +// +// board.addModifiedData(cell1); +// board.addModifiedData(cell2); +// board.addModifiedData(cell3); +// board.addModifiedData(cell4); +// board.addModifiedData(cell5); +// board.addModifiedData(cell6); +// +// Assert.assertNull(RULE.checkRule(transition)); +// +// for (int i = 0; i < board.getHeight(); ++i) { +// for (int j = 0; j < board.getWidth(); ++j) { +// Point point = new Point(j,i); +// if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) || +// point.equals(cell3.getLocation()) || point.equals(cell4.getLocation()) || +// point.equals(cell5.getLocation()) || point.equals(cell6.getLocation())) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); +// } +// else { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); +// } +// } +// } +// } +// +// @Test +// public void EmptyAdjacentDirectRule_TwoLeft() throws InvalidFileFormatException { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/EmptyAdjacentDirectRule/TwoLeft", starbattle); +// TreeNode rootNode = starbattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell1 = board.getCell(1,1); +// cell1.setData(StarBattleCellType.BLACK.value); +// /* +// StarBattleCell cell2 = board.getCell(2,1); +// cell2.setData(StarBattleCellType.BLACK.value); +// StarBattleCell cell3 = board.getCell(1,3); +// cell3.setData(StarBattleCellType.BLACK.value); +// StarBattleCell cell4 = board.getCell(2,3); +// cell4.setData(StarBattleCellType.BLACK.value); +// */ +// +// board.addModifiedData(cell1); +// /* +// board.addModifiedData(cell2); +// board.addModifiedData(cell3); +// board.addModifiedData(cell4); +// */ +// +// Assert.assertNull(RULE.checkRule(transition)); +// System.out.println("General Case is done\n"); +// for (int i = 0; i < board.getHeight(); ++i) { +// for (int j = 0; j < board.getWidth(); ++j) { +// Point point = new Point(j,i); +// if (point.equals(cell1.getLocation())) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); +// } /* +// else { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); +// } */ +// } +// } +// } +// +// @Test +// public void EmptyAdjacentDirectRule_ThreeLeft() +// throws InvalidFileFormatException { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/EmptyAdjacentDirectRule/TwoLeft", starbattle); +// TreeNode rootNode = starbattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell1 = board.getCell(1,1); +// cell1.setData(StarBattleCellType.BLACK.value); +// StarBattleCell cell2 = board.getCell(2,1); +// cell2.setData(StarBattleCellType.BLACK.value); +// +// board.addModifiedData(cell1); +// board.addModifiedData(cell2); +// +// Assert.assertNull(RULE.checkRule(transition)); +// +// for (int i = 0; i < board.getHeight(); ++i) { +// for (int j = 0; j < board.getWidth(); ++j) { +// Point point = new Point(j,i); +// if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); +// } +// else { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); +// } +// } +// } +// } +// +// @Test +// public void EmptyAdjacentDirectRule_ImproperUseFourLeft() throws InvalidFileFormatException { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/EmptyAdjacentDirectRule/ImproperUseFourLeft", starbattle); +// TreeNode rootNode = starbattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell1 = board.getCell(1,1); +// cell1.setData(StarBattleCellType.BLACK.value); +// StarBattleCell cell2 = board.getCell(2,1); +// cell2.setData(StarBattleCellType.BLACK.value); +// StarBattleCell cell3 = board.getCell(1,3); +// cell3.setData(StarBattleCellType.BLACK.value); +// StarBattleCell cell4 = board.getCell(2,3); +// cell4.setData(StarBattleCellType.BLACK.value); +// +// board.addModifiedData(cell1); +// board.addModifiedData(cell2); +// board.addModifiedData(cell3); +// board.addModifiedData(cell4); +// +// Assert.assertNotNull(RULE.checkRule(transition)); +// +// for (int i = 0; i < board.getHeight(); ++i) { +// for (int j = 0; j < board.getWidth(); ++j) { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); +// } +// } +// } +//} diff --git a/src/test/java/puzzles/starbattle/rules/FinishWithStarsDirectRuleTest.java b/src/test/java/puzzles/starbattle/rules/FinishWithStarsDirectRuleTest.java index 552e3703e..c8c125d64 100644 --- a/src/test/java/puzzles/starbattle/rules/FinishWithStarsDirectRuleTest.java +++ b/src/test/java/puzzles/starbattle/rules/FinishWithStarsDirectRuleTest.java @@ -1,209 +1,209 @@ -package puzzles.starbattle.rules; - -import edu.rpi.legup.puzzle.starbattle.rules.FinishWithStarsDirectRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -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.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 FinishWithStarsDirectRuleTest { - private static final FinishWithStarsDirectRule RULE = new FinishWithStarsDirectRule(); - private static StarBattle starBattle; - - @BeforeClass - public static void setUp() { - MockGameBoardFacade.getInstance(); - starBattle = new StarBattle(); - } - - /* Finish With Stars Direct Rule where star is in the corner and only the row is blacked out */ - @Test - public void FinishWithStarsDirectRuleTestCornerRow() - throws InvalidFileFormatException - { - TestUtilities.importTestBoard("puzzles/starbattle/rules/FinishWithStarsDirectRule/CornerRow", starBattle); - TreeNode rootNode = starBattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell1 = board.getCell(0,0); - cell1.setData(StarBattleCellType.STAR.value); - - board.addModifiedData(cell1); - - Assert.assertNull(RULE.checkRule(transition)); - - for (int i = 0; i < board.getHeight(); ++i) { - for (int j = 0; j < board.getWidth(); ++j) { - Point point = new Point(j,i); - if (point.equals(cell1.getLocation())) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - } - } - } - - /* Finish With Stars Direct Rule where star is in the corner and only the column is blacked out */ - @Test - public void FinishWithStarsDirectRuleTestCornerColumn() - throws InvalidFileFormatException - { - TestUtilities.importTestBoard("puzzles/starbattle/rules/FinishWithStarsDirectRule/CornerColumn", starBattle); - TreeNode rootNode = starBattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell1 = board.getCell(0,0); - cell1.setData(StarBattleCellType.STAR.value); - - board.addModifiedData(cell1); - - Assert.assertNull(RULE.checkRule(transition)); - - for (int i = 0; i < board.getHeight(); ++i) { - for (int j = 0; j < board.getWidth(); ++j) { - Point point = new Point(j,i); - if (point.equals(cell1.getLocation())) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - } - } - } - - /* Finish With Stars Direct Rule where star is in the corner and only the column is blacked out */ - @Test - public void FinishWithStarsDirectRuleTestCornerRowColumn() - throws InvalidFileFormatException - { - TestUtilities.importTestBoard("puzzles/starbattle/rules/FinishWithStarsDirectRule/CornerRowColumn", starBattle); - TreeNode rootNode = starBattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell1 = board.getCell(0,0); - cell1.setData(StarBattleCellType.STAR.value); - - board.addModifiedData(cell1); - - Assert.assertNull(RULE.checkRule(transition)); - - for (int i = 0; i < board.getHeight(); ++i) { - for (int j = 0; j < board.getWidth(); ++j) { - Point point = new Point(j,i); - if (point.equals(cell1.getLocation())) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - } - } - } - /* Finish With Stars Direct Rule where star is in the corner and only the column is blacked out */ - @Test - public void FinishWithStarsDirectRuleTestRegion() - throws InvalidFileFormatException - { - TestUtilities.importTestBoard("puzzles/starbattle/rules/FinishWithStarsDirectRule/Region", starBattle); - TreeNode rootNode = starBattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell1 = board.getCell(1,1); - cell1.setData(StarBattleCellType.STAR.value); - - board.addModifiedData(cell1); - - Assert.assertNull(RULE.checkRule(transition)); - - for (int i = 0; i < board.getHeight(); ++i) { - for (int j = 0; j < board.getWidth(); ++j) { - Point point = new Point(j,i); - if (point.equals(cell1.getLocation())) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - } - } - } - /* Finish With Stars Direct Rule where there are two stars in two different mostly blacked out regions */ - @Test - public void FinishWithStarsDirectRuleTestDoubleRegion() - throws InvalidFileFormatException - { - TestUtilities.importTestBoard("puzzles/starbattle/rules/FinishWithStarsDirectRule/DoubleRegion", starBattle); - TreeNode rootNode = starBattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell1 = board.getCell(1,1); - cell1.setData(StarBattleCellType.STAR.value); - StarBattleCell cell2 = board.getCell(2,3); - cell2.setData(StarBattleCellType.STAR.value); - - board.addModifiedData(cell1); - board.addModifiedData(cell2); - - Assert.assertNull(RULE.checkRule(transition)); - - for (int i = 0; i < board.getHeight(); ++i) { - for (int j = 0; j < board.getWidth(); ++j) { - Point point = new Point(j,i); - if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - } - } - } - - /* Finish With Stars Direct Rule where there are two stars in two different mostly blacked out regions */ - @Test - public void FinishWithStarsDirectRuleTestFalse() - throws InvalidFileFormatException - { - TestUtilities.importTestBoard("puzzles/starbattle/rules/FinishWithStarsDirectRule/False", starBattle); - TreeNode rootNode = starBattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell1 = board.getCell(2,0); - cell1.setData(StarBattleCellType.STAR.value); - - board.addModifiedData(cell1); - - Assert.assertNotNull(RULE.checkRule(transition)); - - for (int i = 0; i < board.getHeight(); ++i) { - for (int j = 0; j < board.getWidth(); ++j) { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - } - } - -} +//package puzzles.starbattle.rules; +// +//import edu.rpi.legup.puzzle.starbattle.rules.FinishWithStarsDirectRule; +//import edu.rpi.legup.model.tree.TreeNode; +//import edu.rpi.legup.model.tree.TreeTransition; +//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.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 FinishWithStarsDirectRuleTest { +// private static final FinishWithStarsDirectRule RULE = new FinishWithStarsDirectRule(); +// private static StarBattle starBattle; +// +// @BeforeClass +// public static void setUp() { +// MockGameBoardFacade.getInstance(); +// starBattle = new StarBattle(); +// } +// +// /* Finish With Stars Direct Rule where star is in the corner and only the row is blacked out */ +// @Test +// public void FinishWithStarsDirectRuleTestCornerRow() +// throws InvalidFileFormatException +// { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/FinishWithStarsDirectRule/CornerRow", starBattle); +// TreeNode rootNode = starBattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell1 = board.getCell(0,0); +// cell1.setData(StarBattleCellType.STAR.value); +// +// board.addModifiedData(cell1); +// +// Assert.assertNull(RULE.checkRule(transition)); +// +// for (int i = 0; i < board.getHeight(); ++i) { +// for (int j = 0; j < board.getWidth(); ++j) { +// Point point = new Point(j,i); +// if (point.equals(cell1.getLocation())) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); +// } +// else { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); +// } +// } +// } +// } +// +// /* Finish With Stars Direct Rule where star is in the corner and only the column is blacked out */ +// @Test +// public void FinishWithStarsDirectRuleTestCornerColumn() +// throws InvalidFileFormatException +// { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/FinishWithStarsDirectRule/CornerColumn", starBattle); +// TreeNode rootNode = starBattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell1 = board.getCell(0,0); +// cell1.setData(StarBattleCellType.STAR.value); +// +// board.addModifiedData(cell1); +// +// Assert.assertNull(RULE.checkRule(transition)); +// +// for (int i = 0; i < board.getHeight(); ++i) { +// for (int j = 0; j < board.getWidth(); ++j) { +// Point point = new Point(j,i); +// if (point.equals(cell1.getLocation())) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); +// } +// else { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); +// } +// } +// } +// } +// +// /* Finish With Stars Direct Rule where star is in the corner and only the column is blacked out */ +// @Test +// public void FinishWithStarsDirectRuleTestCornerRowColumn() +// throws InvalidFileFormatException +// { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/FinishWithStarsDirectRule/CornerRowColumn", starBattle); +// TreeNode rootNode = starBattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell1 = board.getCell(0,0); +// cell1.setData(StarBattleCellType.STAR.value); +// +// board.addModifiedData(cell1); +// +// Assert.assertNull(RULE.checkRule(transition)); +// +// for (int i = 0; i < board.getHeight(); ++i) { +// for (int j = 0; j < board.getWidth(); ++j) { +// Point point = new Point(j,i); +// if (point.equals(cell1.getLocation())) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); +// } +// else { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); +// } +// } +// } +// } +// /* Finish With Stars Direct Rule where star is in the corner and only the column is blacked out */ +// @Test +// public void FinishWithStarsDirectRuleTestRegion() +// throws InvalidFileFormatException +// { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/FinishWithStarsDirectRule/Region", starBattle); +// TreeNode rootNode = starBattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell1 = board.getCell(1,1); +// cell1.setData(StarBattleCellType.STAR.value); +// +// board.addModifiedData(cell1); +// +// Assert.assertNull(RULE.checkRule(transition)); +// +// for (int i = 0; i < board.getHeight(); ++i) { +// for (int j = 0; j < board.getWidth(); ++j) { +// Point point = new Point(j,i); +// if (point.equals(cell1.getLocation())) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); +// } +// else { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); +// } +// } +// } +// } +// /* Finish With Stars Direct Rule where there are two stars in two different mostly blacked out regions */ +// @Test +// public void FinishWithStarsDirectRuleTestDoubleRegion() +// throws InvalidFileFormatException +// { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/FinishWithStarsDirectRule/DoubleRegion", starBattle); +// TreeNode rootNode = starBattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell1 = board.getCell(1,1); +// cell1.setData(StarBattleCellType.STAR.value); +// StarBattleCell cell2 = board.getCell(2,3); +// cell2.setData(StarBattleCellType.STAR.value); +// +// board.addModifiedData(cell1); +// board.addModifiedData(cell2); +// +// Assert.assertNull(RULE.checkRule(transition)); +// +// for (int i = 0; i < board.getHeight(); ++i) { +// for (int j = 0; j < board.getWidth(); ++j) { +// Point point = new Point(j,i); +// if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); +// } +// else { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); +// } +// } +// } +// } +// +// /* Finish With Stars Direct Rule where there are two stars in two different mostly blacked out regions */ +// @Test +// public void FinishWithStarsDirectRuleTestFalse() +// throws InvalidFileFormatException +// { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/FinishWithStarsDirectRule/False", starBattle); +// TreeNode rootNode = starBattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell1 = board.getCell(2,0); +// cell1.setData(StarBattleCellType.STAR.value); +// +// board.addModifiedData(cell1); +// +// Assert.assertNotNull(RULE.checkRule(transition)); +// +// for (int i = 0; i < board.getHeight(); ++i) { +// for (int j = 0; j < board.getWidth(); ++j) { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); +// } +// } +// } +// +//} diff --git a/src/test/java/puzzles/starbattle/rules/RegionsWithinColumnsDirectRuleTest.java b/src/test/java/puzzles/starbattle/rules/RegionsWithinColumnsDirectRuleTest.java index a45f7455f..a46e5514c 100644 --- a/src/test/java/puzzles/starbattle/rules/RegionsWithinColumnsDirectRuleTest.java +++ b/src/test/java/puzzles/starbattle/rules/RegionsWithinColumnsDirectRuleTest.java @@ -1,353 +1,353 @@ -package puzzles.starbattle.rules; - -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -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.RegionsWithinColumnsDirectRule; -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.awt.*; - -public class RegionsWithinColumnsDirectRuleTest { - - private static final RegionsWithinColumnsDirectRule RULE = new RegionsWithinColumnsDirectRule(); - private static StarBattle starbattle; - - @BeforeClass - public static void setUp() { - MockGameBoardFacade.getInstance(); - starbattle = new StarBattle(); - } - - @Test - public void RegionsWithinColumnsDirectRule_OneRegionOneCell() - throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/OneRegionOneCell", starbattle); - TreeNode rootNode = starbattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell = board.getCell(0,2); - cell.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell); - - Assert.assertNull(RULE.checkRule(transition)); - - Point location = new Point(0,2); - 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(location)) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - } - } - } - - @Test - public void RegionsWithinColumnsDirectRule_OneRegionTwoCells() - throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/OneRegionTwoCells", starbattle); - TreeNode rootNode = starbattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell1 = board.getCell(0,1); - cell1.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell1); - StarBattleCell cell2 = board.getCell(0,2); - cell2.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell2); - - Assert.assertNull(RULE.checkRule(transition)); - - Point location1 = new Point(0,1); - Point location2 = new Point(0,2); - 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(location1) || point.equals(location2)) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - } - } - } - - @Test - public void RegionsWithinColumnsDirectRule_PartialRegionOneCell() - throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/PartialRegionOneCell", starbattle); - TreeNode rootNode = starbattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell = board.getCell(0,2); - cell.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell); - - Assert.assertNull(RULE.checkRule(transition)); - - Point location = new Point(0,2); - 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(location)) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - } - } - } - - @Test - public void RegionsWithinColumnsDirectRule_TwoRegionsOneCell() - throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoRegionsOneCell", starbattle); - TreeNode rootNode = starbattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell = board.getCell(1,3); - cell.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell); - - Assert.assertNull(RULE.checkRule(transition)); - - Point location = new Point(1,3); - 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(location)) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - } - } - } - - @Test - public void RegionsWithinColumnsDirectRule_TwoRegionsTwoCells() - throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoRegionsTwoCells", starbattle); - TreeNode rootNode = starbattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell1 = board.getCell(1,1); - cell1.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell1); - StarBattleCell cell2 = board.getCell(1,3); - cell2.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell2); - - Assert.assertNull(RULE.checkRule(transition)); - - Point location1 = new Point(1,1); - Point location2 = new Point(1,3); - 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(location1) || point.equals(location2)) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - } - } - } - - @Test - public void RegionsWithinColumnsDirectRule_TwoRegionsTwoCells2() - throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoRegionsTwoCells2", starbattle); - TreeNode rootNode = starbattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell1 = board.getCell(0,3); - cell1.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell1); - StarBattleCell cell2 = board.getCell(1,3); - cell2.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell2); - - Assert.assertNull(RULE.checkRule(transition)); - - Point location1 = new Point(0,3); - Point location2 = new Point(1,3); - 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(location1) || point.equals(location2)) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - } - } - } - - @Test - public void RegionsWithinColumnsDirectRule_TwoRegionsStarOverlap() - throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoRegionsStarOverlap", starbattle); - TreeNode rootNode = starbattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell = board.getCell(1,1); - cell.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell); - - Assert.assertNull(RULE.checkRule(transition)); - - Point location = new Point(1,1); - 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(location)) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - } - } - } - - @Test - public void RegionsWithinColumnsDirectRule_FalseRegionsWithinColumns1() - throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/OneRegionOneCell", starbattle); - TreeNode rootNode = starbattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell = board.getCell(0,2); - cell.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell); - StarBattleCell cell2 = board.getCell(1,2); - cell2.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell2); - - Assert.assertNotNull(RULE.checkRule(transition)); - - Point location = new Point(0,2); - 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(location)) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - } - } - } - - @Test - public void RegionsWithinColumnsDirectRule_FalseRegionsWithinColumns2() - throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/OneRegionOneCell", starbattle); - TreeNode rootNode = starbattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell = board.getCell(0,2); - cell.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell); - StarBattleCell cell2 = board.getCell(0,1); - cell2.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell2); - - Assert.assertNotNull(RULE.checkRule(transition)); - - Point location = new Point(0,2); - 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(location)) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - } - } - } - - @Test - public void RegionsWithinColumnsDirectRule_FalseRegionsWithinColumns3() - throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/FalseStarOverlap", starbattle); - TreeNode rootNode = starbattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell = board.getCell(1,1); - cell.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell); - StarBattleCell cell2 = board.getCell(1,3); - cell2.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell2); - - Assert.assertNotNull(RULE.checkRule(transition)); - - for (int i = 0; i < board.getHeight(); i++) { - for (int k = 0; k < board.getWidth(); k++) { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - } - } - - @Test - public void RegionsWithinColumnsDirectRule_FalseRegionsWithinColumns4() - throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoRegionsTwoCells2", starbattle); - TreeNode rootNode = starbattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell = board.getCell(0,3); - cell.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell); - - Assert.assertNull(RULE.checkRule(transition)); - - Point location = new Point(0,3); - 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(location)) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - } - } - } -} +//package puzzles.starbattle.rules; +// +//import edu.rpi.legup.model.tree.TreeNode; +//import edu.rpi.legup.model.tree.TreeTransition; +//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.RegionsWithinColumnsDirectRule; +//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.awt.*; +// +//public class RegionsWithinColumnsDirectRuleTest { +// +// private static final RegionsWithinColumnsDirectRule RULE = new RegionsWithinColumnsDirectRule(); +// private static StarBattle starbattle; +// +// @BeforeClass +// public static void setUp() { +// MockGameBoardFacade.getInstance(); +// starbattle = new StarBattle(); +// } +// +// @Test +// public void RegionsWithinColumnsDirectRule_OneRegionOneCell() +// throws InvalidFileFormatException { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/OneRegionOneCell", starbattle); +// TreeNode rootNode = starbattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell = board.getCell(0,2); +// cell.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell); +// +// Assert.assertNull(RULE.checkRule(transition)); +// +// Point location = new Point(0,2); +// 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(location)) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } else { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } +// } +// } +// } +// +// @Test +// public void RegionsWithinColumnsDirectRule_OneRegionTwoCells() +// throws InvalidFileFormatException { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/OneRegionTwoCells", starbattle); +// TreeNode rootNode = starbattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell1 = board.getCell(0,1); +// cell1.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell1); +// StarBattleCell cell2 = board.getCell(0,2); +// cell2.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell2); +// +// Assert.assertNull(RULE.checkRule(transition)); +// +// Point location1 = new Point(0,1); +// Point location2 = new Point(0,2); +// 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(location1) || point.equals(location2)) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } else { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } +// } +// } +// } +// +// @Test +// public void RegionsWithinColumnsDirectRule_PartialRegionOneCell() +// throws InvalidFileFormatException { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/PartialRegionOneCell", starbattle); +// TreeNode rootNode = starbattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell = board.getCell(0,2); +// cell.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell); +// +// Assert.assertNull(RULE.checkRule(transition)); +// +// Point location = new Point(0,2); +// 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(location)) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } else { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } +// } +// } +// } +// +// @Test +// public void RegionsWithinColumnsDirectRule_TwoRegionsOneCell() +// throws InvalidFileFormatException { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoRegionsOneCell", starbattle); +// TreeNode rootNode = starbattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell = board.getCell(1,3); +// cell.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell); +// +// Assert.assertNull(RULE.checkRule(transition)); +// +// Point location = new Point(1,3); +// 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(location)) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } else { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } +// } +// } +// } +// +// @Test +// public void RegionsWithinColumnsDirectRule_TwoRegionsTwoCells() +// throws InvalidFileFormatException { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoRegionsTwoCells", starbattle); +// TreeNode rootNode = starbattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell1 = board.getCell(1,1); +// cell1.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell1); +// StarBattleCell cell2 = board.getCell(1,3); +// cell2.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell2); +// +// Assert.assertNull(RULE.checkRule(transition)); +// +// Point location1 = new Point(1,1); +// Point location2 = new Point(1,3); +// 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(location1) || point.equals(location2)) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } else { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } +// } +// } +// } +// +// @Test +// public void RegionsWithinColumnsDirectRule_TwoRegionsTwoCells2() +// throws InvalidFileFormatException { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoRegionsTwoCells2", starbattle); +// TreeNode rootNode = starbattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell1 = board.getCell(0,3); +// cell1.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell1); +// StarBattleCell cell2 = board.getCell(1,3); +// cell2.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell2); +// +// Assert.assertNull(RULE.checkRule(transition)); +// +// Point location1 = new Point(0,3); +// Point location2 = new Point(1,3); +// 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(location1) || point.equals(location2)) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } else { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } +// } +// } +// } +// +// @Test +// public void RegionsWithinColumnsDirectRule_TwoRegionsStarOverlap() +// throws InvalidFileFormatException { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoRegionsStarOverlap", starbattle); +// TreeNode rootNode = starbattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell = board.getCell(1,1); +// cell.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell); +// +// Assert.assertNull(RULE.checkRule(transition)); +// +// Point location = new Point(1,1); +// 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(location)) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } else { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } +// } +// } +// } +// +// @Test +// public void RegionsWithinColumnsDirectRule_FalseRegionsWithinColumns1() +// throws InvalidFileFormatException { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/OneRegionOneCell", starbattle); +// TreeNode rootNode = starbattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell = board.getCell(0,2); +// cell.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell); +// StarBattleCell cell2 = board.getCell(1,2); +// cell2.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell2); +// +// Assert.assertNotNull(RULE.checkRule(transition)); +// +// Point location = new Point(0,2); +// 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(location)) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } else { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } +// } +// } +// } +// +// @Test +// public void RegionsWithinColumnsDirectRule_FalseRegionsWithinColumns2() +// throws InvalidFileFormatException { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/OneRegionOneCell", starbattle); +// TreeNode rootNode = starbattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell = board.getCell(0,2); +// cell.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell); +// StarBattleCell cell2 = board.getCell(0,1); +// cell2.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell2); +// +// Assert.assertNotNull(RULE.checkRule(transition)); +// +// Point location = new Point(0,2); +// 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(location)) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } else { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } +// } +// } +// } +// +// @Test +// public void RegionsWithinColumnsDirectRule_FalseRegionsWithinColumns3() +// throws InvalidFileFormatException { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/FalseStarOverlap", starbattle); +// TreeNode rootNode = starbattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell = board.getCell(1,1); +// cell.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell); +// StarBattleCell cell2 = board.getCell(1,3); +// cell2.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell2); +// +// Assert.assertNotNull(RULE.checkRule(transition)); +// +// for (int i = 0; i < board.getHeight(); i++) { +// for (int k = 0; k < board.getWidth(); k++) { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } +// } +// } +// +// @Test +// public void RegionsWithinColumnsDirectRule_FalseRegionsWithinColumns4() +// throws InvalidFileFormatException { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoRegionsTwoCells2", starbattle); +// TreeNode rootNode = starbattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell = board.getCell(0,3); +// cell.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell); +// +// Assert.assertNull(RULE.checkRule(transition)); +// +// Point location = new Point(0,3); +// 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(location)) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } +// else { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } +// } +// } +// } +//} diff --git a/src/test/java/puzzles/starbattle/rules/RegionsWithinRowsDirectRuleTest.java b/src/test/java/puzzles/starbattle/rules/RegionsWithinRowsDirectRuleTest.java index 3ffaa82fd..49496f18c 100644 --- a/src/test/java/puzzles/starbattle/rules/RegionsWithinRowsDirectRuleTest.java +++ b/src/test/java/puzzles/starbattle/rules/RegionsWithinRowsDirectRuleTest.java @@ -1,258 +1,258 @@ -package puzzles.starbattle.rules; - -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -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.RegionsWithinRowsDirectRule; -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.awt.*; - -public class RegionsWithinRowsDirectRuleTest { - - private static final RegionsWithinRowsDirectRule RULE = new RegionsWithinRowsDirectRule(); - private static StarBattle starbattle; - - @BeforeClass - public static void setUp() { - MockGameBoardFacade.getInstance(); - starbattle = new StarBattle(); - } - - @Test - public void RegionsWithinRowsDirectRule_OneRegionOneCell() - throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinRowsDirectRule/OneRegionOneCell", starbattle); - TreeNode rootNode = starbattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell = board.getCell(2,0); - cell.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell); - - Assert.assertNull(RULE.checkRule(transition)); - - Point location = new Point(2,0); - 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(location)) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - } - } - } - - @Test - public void RegionsWithinRowsDirectRule_PartialRegionOneCell() - throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinRowsDirectRule/PartialRegionOneCell", starbattle); - TreeNode rootNode = starbattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell = board.getCell(2,0); - cell.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell); - - Assert.assertNull(RULE.checkRule(transition)); - - Point location = new Point(2,0); - 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(location)) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - } - } - } - - @Test - public void RegionsWithinRowsDirectRule_PartialRegionTwo() - throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinRowsDirectRule/PartialRegionTwoCells", starbattle); - TreeNode rootNode = starbattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell1 = board.getCell(1,0); - cell1.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell1); - StarBattleCell cell2 = board.getCell(2,0); - cell2.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell2); - - Assert.assertNull(RULE.checkRule(transition)); - - Point location1 = new Point(1,0); - Point location2 = new Point(2,0); - 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(location1) || point.equals(location2)) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - } - } - } - - @Test - public void RegionsWithinRowsDirectRule_TwoRegionsOneCell() - throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinRowsDirectRule/TwoRegionsOneCell", starbattle); - TreeNode rootNode = starbattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell = board.getCell(3,1); - cell.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell); - - Assert.assertNull(RULE.checkRule(transition)); - - Point location = new Point(3,1); - 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(location)) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - } - } - } - - @Test - public void RegionsWithinRowsDirectRule_StarOverlap() - throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinRowsDirectRule/StarOverlap", starbattle); - TreeNode rootNode = starbattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell = board.getCell(3,1); - cell.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell); - - Assert.assertNull(RULE.checkRule(transition)); - - Point location = new Point(3,1); - 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(location)) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - } - } - } - - @Test - public void RegionsWithinRowsDirectRule_FalseRegionsWithinRows1() - throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinRowsDirectRule/OneRegionOneCell", starbattle); - TreeNode rootNode = starbattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell1 = board.getCell(2,0); - cell1.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell1); - StarBattleCell cell2 = board.getCell(2,1); - cell2.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell2); - - Assert.assertNotNull(RULE.checkRule(transition)); - - Point location = new Point(2,0); - 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(location)) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - } - } - } - - @Test - public void RegionsWithinRowsDirectRule_FalseRegionsWithinRows2() - throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinRowsDirectRule/OneRegionOneCell", starbattle); - TreeNode rootNode = starbattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell1 = board.getCell(2,0); - cell1.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell1); - StarBattleCell cell2 = board.getCell(1,0); - cell2.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell2); - - Assert.assertNotNull(RULE.checkRule(transition)); - - Point location = new Point(2,0); - 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(location)) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - } - } - } - - @Test - public void RegionsWithinRowsDirectRule_FalseStarOverlap() - throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinRowsDirectRule/FalseStarOverlap", starbattle); - TreeNode rootNode = starbattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell = board.getCell(3,1); - cell.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell); - - Assert.assertNotNull(RULE.checkRule(transition)); - - for (int i = 0; i < board.getHeight(); i++) { - for (int k = 0; k < board.getWidth(); k++) { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - } - } - -} +//package puzzles.starbattle.rules; +// +//import edu.rpi.legup.model.tree.TreeNode; +//import edu.rpi.legup.model.tree.TreeTransition; +//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.RegionsWithinRowsDirectRule; +//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.awt.*; +// +//public class RegionsWithinRowsDirectRuleTest { +// +// private static final RegionsWithinRowsDirectRule RULE = new RegionsWithinRowsDirectRule(); +// private static StarBattle starbattle; +// +// @BeforeClass +// public static void setUp() { +// MockGameBoardFacade.getInstance(); +// starbattle = new StarBattle(); +// } +// +// @Test +// public void RegionsWithinRowsDirectRule_OneRegionOneCell() +// throws InvalidFileFormatException { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinRowsDirectRule/OneRegionOneCell", starbattle); +// TreeNode rootNode = starbattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell = board.getCell(2,0); +// cell.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell); +// +// Assert.assertNull(RULE.checkRule(transition)); +// +// Point location = new Point(2,0); +// 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(location)) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } else { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } +// } +// } +// } +// +// @Test +// public void RegionsWithinRowsDirectRule_PartialRegionOneCell() +// throws InvalidFileFormatException { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinRowsDirectRule/PartialRegionOneCell", starbattle); +// TreeNode rootNode = starbattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell = board.getCell(2,0); +// cell.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell); +// +// Assert.assertNull(RULE.checkRule(transition)); +// +// Point location = new Point(2,0); +// 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(location)) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } else { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } +// } +// } +// } +// +// @Test +// public void RegionsWithinRowsDirectRule_PartialRegionTwo() +// throws InvalidFileFormatException { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinRowsDirectRule/PartialRegionTwoCells", starbattle); +// TreeNode rootNode = starbattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell1 = board.getCell(1,0); +// cell1.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell1); +// StarBattleCell cell2 = board.getCell(2,0); +// cell2.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell2); +// +// Assert.assertNull(RULE.checkRule(transition)); +// +// Point location1 = new Point(1,0); +// Point location2 = new Point(2,0); +// 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(location1) || point.equals(location2)) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } else { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } +// } +// } +// } +// +// @Test +// public void RegionsWithinRowsDirectRule_TwoRegionsOneCell() +// throws InvalidFileFormatException { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinRowsDirectRule/TwoRegionsOneCell", starbattle); +// TreeNode rootNode = starbattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell = board.getCell(3,1); +// cell.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell); +// +// Assert.assertNull(RULE.checkRule(transition)); +// +// Point location = new Point(3,1); +// 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(location)) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } else { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } +// } +// } +// } +// +// @Test +// public void RegionsWithinRowsDirectRule_StarOverlap() +// throws InvalidFileFormatException { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinRowsDirectRule/StarOverlap", starbattle); +// TreeNode rootNode = starbattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell = board.getCell(3,1); +// cell.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell); +// +// Assert.assertNull(RULE.checkRule(transition)); +// +// Point location = new Point(3,1); +// 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(location)) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } else { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } +// } +// } +// } +// +// @Test +// public void RegionsWithinRowsDirectRule_FalseRegionsWithinRows1() +// throws InvalidFileFormatException { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinRowsDirectRule/OneRegionOneCell", starbattle); +// TreeNode rootNode = starbattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell1 = board.getCell(2,0); +// cell1.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell1); +// StarBattleCell cell2 = board.getCell(2,1); +// cell2.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell2); +// +// Assert.assertNotNull(RULE.checkRule(transition)); +// +// Point location = new Point(2,0); +// 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(location)) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } else { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } +// } +// } +// } +// +// @Test +// public void RegionsWithinRowsDirectRule_FalseRegionsWithinRows2() +// throws InvalidFileFormatException { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinRowsDirectRule/OneRegionOneCell", starbattle); +// TreeNode rootNode = starbattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell1 = board.getCell(2,0); +// cell1.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell1); +// StarBattleCell cell2 = board.getCell(1,0); +// cell2.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell2); +// +// Assert.assertNotNull(RULE.checkRule(transition)); +// +// Point location = new Point(2,0); +// 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(location)) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } else { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } +// } +// } +// } +// +// @Test +// public void RegionsWithinRowsDirectRule_FalseStarOverlap() +// throws InvalidFileFormatException { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinRowsDirectRule/FalseStarOverlap", starbattle); +// TreeNode rootNode = starbattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell = board.getCell(3,1); +// cell.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell); +// +// Assert.assertNotNull(RULE.checkRule(transition)); +// +// for (int i = 0; i < board.getHeight(); i++) { +// for (int k = 0; k < board.getWidth(); k++) { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } +// } +// } +// +//} diff --git a/src/test/java/puzzles/starbattle/rules/StarOrEmptyCaseRuleTest.java b/src/test/java/puzzles/starbattle/rules/StarOrEmptyCaseRuleTest.java index e1f9cb990..dc4dc4f3e 100644 --- a/src/test/java/puzzles/starbattle/rules/StarOrEmptyCaseRuleTest.java +++ b/src/test/java/puzzles/starbattle/rules/StarOrEmptyCaseRuleTest.java @@ -1,68 +1,68 @@ -package puzzles.starbattle.rules; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -import edu.rpi.legup.puzzle.nurikabe.NurikabeType; -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.StarOrEmptyCaseRule; -import edu.rpi.legup.save.InvalidFileFormatException; -import java.awt.*; -import java.util.ArrayList; -import legup.MockGameBoardFacade; -import legup.TestUtilities; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; - -public class StarOrEmptyCaseRuleTest { - - private static final StarOrEmptyCaseRule RULE = new StarOrEmptyCaseRule(); - private static StarBattle starBattle; - - @BeforeClass - public static void setUp() { - MockGameBoardFacade.getInstance(); - starBattle = new StarBattle(); - } - - @Test - public void StarOrEmptyCaseRuleTest_SimpleStarOrEmpty() - throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/StarOrEmptyCaseRule/SimpleStarOrEmpty", starBattle); - TreeNode rootNode = starBattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell = board.getCell(0,0); - ArrayList cases = RULE.getCases(board, cell); - - StarBattleBoard caseBoard1 = (StarBattleBoard) cases.get(0); - StarBattleBoard caseBoard2 = (StarBattleBoard) cases.get(1); - StarBattleCellType board1Type = caseBoard1.getCell(0, 0).getType(); - StarBattleCellType board2Type = caseBoard2.getCell(0, 0).getType(); - - Assert.assertTrue( - (board1Type.equals(StarBattleCellType.BLACK) || board1Type.equals(StarBattleCellType.STAR)) - && (board2Type.equals(StarBattleCellType.BLACK) - || board2Type.equals(StarBattleCellType.STAR))); - Assert.assertFalse(board1Type.equals(board2Type)); - Assert.assertEquals(caseBoard1.getHeight(), caseBoard2.getHeight(), board.getHeight()); - Assert.assertEquals(caseBoard1.getWidth(), caseBoard2.getWidth(), board.getWidth()); - - for (int i = 0; i < caseBoard1.getHeight(); i++) { - for (int k = 0; k < caseBoard1.getWidth(); k++) { - Point point = new Point(k, i); - if (point.equals(caseBoard1.getCell(k, i).getLocation())) { - continue; - } - Assert.assertTrue(caseBoard1.getCell(k, i).equals(caseBoard2.getCell(k, i))); - } - } - } - -} +//package puzzles.starbattle.rules; +// +//import edu.rpi.legup.model.gameboard.Board; +//import edu.rpi.legup.model.tree.TreeNode; +//import edu.rpi.legup.model.tree.TreeTransition; +//import edu.rpi.legup.puzzle.nurikabe.NurikabeType; +//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.StarOrEmptyCaseRule; +//import edu.rpi.legup.save.InvalidFileFormatException; +//import java.awt.*; +//import java.util.ArrayList; +//import legup.MockGameBoardFacade; +//import legup.TestUtilities; +//import org.junit.Assert; +//import org.junit.BeforeClass; +//import org.junit.Test; +// +//public class StarOrEmptyCaseRuleTest { +// +// private static final StarOrEmptyCaseRule RULE = new StarOrEmptyCaseRule(); +// private static StarBattle starBattle; +// +// @BeforeClass +// public static void setUp() { +// MockGameBoardFacade.getInstance(); +// starBattle = new StarBattle(); +// } +// +// @Test +// public void StarOrEmptyCaseRuleTest_SimpleStarOrEmpty() +// throws InvalidFileFormatException { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/StarOrEmptyCaseRule/SimpleStarOrEmpty", starBattle); +// TreeNode rootNode = starBattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell = board.getCell(0,0); +// ArrayList cases = RULE.getCases(board, cell); +// +// StarBattleBoard caseBoard1 = (StarBattleBoard) cases.get(0); +// StarBattleBoard caseBoard2 = (StarBattleBoard) cases.get(1); +// StarBattleCellType board1Type = caseBoard1.getCell(0, 0).getType(); +// StarBattleCellType board2Type = caseBoard2.getCell(0, 0).getType(); +// +// Assert.assertTrue( +// (board1Type.equals(StarBattleCellType.BLACK) || board1Type.equals(StarBattleCellType.STAR)) +// && (board2Type.equals(StarBattleCellType.BLACK) +// || board2Type.equals(StarBattleCellType.STAR))); +// Assert.assertFalse(board1Type.equals(board2Type)); +// Assert.assertEquals(caseBoard1.getHeight(), caseBoard2.getHeight(), board.getHeight()); +// Assert.assertEquals(caseBoard1.getWidth(), caseBoard2.getWidth(), board.getWidth()); +// +// for (int i = 0; i < caseBoard1.getHeight(); i++) { +// for (int k = 0; k < caseBoard1.getWidth(); k++) { +// Point point = new Point(k, i); +// if (point.equals(caseBoard1.getCell(k, i).getLocation())) { +// continue; +// } +// Assert.assertTrue(caseBoard1.getCell(k, i).equals(caseBoard2.getCell(k, i))); +// } +// } +// } +// +//} diff --git a/src/test/java/puzzles/starbattle/rules/SurroundStarDirectRuleTest.java b/src/test/java/puzzles/starbattle/rules/SurroundStarDirectRuleTest.java index db55d0f65..738794a3b 100644 --- a/src/test/java/puzzles/starbattle/rules/SurroundStarDirectRuleTest.java +++ b/src/test/java/puzzles/starbattle/rules/SurroundStarDirectRuleTest.java @@ -1,173 +1,173 @@ -package puzzles.starbattle.rules; - -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -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.SurroundStarDirectRule; -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 SurroundStarDirectRuleTest { - - private static final SurroundStarDirectRule RULE = new SurroundStarDirectRule(); - private static StarBattle starbattle; - - @BeforeClass - public static void setUp() { - MockGameBoardFacade.getInstance(); - starbattle = new StarBattle(); - } - - @Test - public void SurroundStarDirectRule_CenterStarOneTile() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/SurroundStarDirectRule/CenterStar", starbattle); - TreeNode rootNode = starbattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell = board.getCell(0,1); - cell.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell); - - Assert.assertNull(RULE.checkRule(transition)); - - Point location = new Point(0, 1); - 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(location)) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - } - } - } - - @Test - public void SurroundStarDirectRule_CenterStarOneTileDiagonal() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/SurroundStarDirectRule/CenterStar", starbattle); - TreeNode rootNode = starbattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell = board.getCell(0,0); - cell.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell); - - Assert.assertNull(RULE.checkRule(transition)); - - Point location = new Point(0, 0); - 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(location)) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - } - } - } - - @Test - public void SurroundStarDirectRule_CenterStarAllTiles() - throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/SurroundStarDirectRule/CenterStar", starbattle); - TreeNode rootNode = starbattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - for (int i = 0; i < board.getWidth(); i++) { - for (int j = 0; j < board.getHeight(); j++) { - if (i != 1 || j != 1) { - StarBattleCell cell = board.getCell(i,j); - cell.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell); - } - } - } - - Assert.assertNull(RULE.checkRule(transition)); - - Point location = new Point(1, 1); - 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(location)) { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } else { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - } - } - } - - @Test - public void SurroundStarDirectRule_CornerStar() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/SurroundStarDirectRule/CornerStar", starbattle); - TreeNode rootNode = starbattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell1 = board.getCell(0,1); - cell1.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell1); - StarBattleCell cell2 = board.getCell(1,0); - cell2.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell2); - StarBattleCell cell3 = board.getCell(1,1); - cell3.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell3); - - Assert.assertNull(RULE.checkRule(transition)); - - Point location1 = new Point(0, 1); - Point location2 = new Point(1,0); - Point location3 = new Point(1,1); - 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(location1) || point.equals(location2) || point.equals(location3)) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - } - } - } - - @Test - public void SurroundStarDirectRule_FalseSurroundStar() - throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/SurroundStarDirectRule/CornerStar", starbattle); - TreeNode rootNode = starbattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell = board.getCell(2,0); - cell.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell); - - Assert.assertNotNull(RULE.checkRule(transition)); - - for (int i = 0; i < board.getHeight(); i++) { - for (int k = 0; k < board.getWidth(); k++) { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - } - } -} +//package puzzles.starbattle.rules; +// +//import edu.rpi.legup.model.tree.TreeNode; +//import edu.rpi.legup.model.tree.TreeTransition; +//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.SurroundStarDirectRule; +//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 SurroundStarDirectRuleTest { +// +// private static final SurroundStarDirectRule RULE = new SurroundStarDirectRule(); +// private static StarBattle starbattle; +// +// @BeforeClass +// public static void setUp() { +// MockGameBoardFacade.getInstance(); +// starbattle = new StarBattle(); +// } +// +// @Test +// public void SurroundStarDirectRule_CenterStarOneTile() throws InvalidFileFormatException { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/SurroundStarDirectRule/CenterStar", starbattle); +// TreeNode rootNode = starbattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell = board.getCell(0,1); +// cell.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell); +// +// Assert.assertNull(RULE.checkRule(transition)); +// +// Point location = new Point(0, 1); +// 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(location)) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } else { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } +// } +// } +// } +// +// @Test +// public void SurroundStarDirectRule_CenterStarOneTileDiagonal() throws InvalidFileFormatException { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/SurroundStarDirectRule/CenterStar", starbattle); +// TreeNode rootNode = starbattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell = board.getCell(0,0); +// cell.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell); +// +// Assert.assertNull(RULE.checkRule(transition)); +// +// Point location = new Point(0, 0); +// 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(location)) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } else { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } +// } +// } +// } +// +// @Test +// public void SurroundStarDirectRule_CenterStarAllTiles() +// throws InvalidFileFormatException { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/SurroundStarDirectRule/CenterStar", starbattle); +// TreeNode rootNode = starbattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// for (int i = 0; i < board.getWidth(); i++) { +// for (int j = 0; j < board.getHeight(); j++) { +// if (i != 1 || j != 1) { +// StarBattleCell cell = board.getCell(i,j); +// cell.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell); +// } +// } +// } +// +// Assert.assertNull(RULE.checkRule(transition)); +// +// Point location = new Point(1, 1); +// 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(location)) { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } else { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } +// } +// } +// } +// +// @Test +// public void SurroundStarDirectRule_CornerStar() throws InvalidFileFormatException { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/SurroundStarDirectRule/CornerStar", starbattle); +// TreeNode rootNode = starbattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell1 = board.getCell(0,1); +// cell1.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell1); +// StarBattleCell cell2 = board.getCell(1,0); +// cell2.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell2); +// StarBattleCell cell3 = board.getCell(1,1); +// cell3.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell3); +// +// Assert.assertNull(RULE.checkRule(transition)); +// +// Point location1 = new Point(0, 1); +// Point location2 = new Point(1,0); +// Point location3 = new Point(1,1); +// 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(location1) || point.equals(location2) || point.equals(location3)) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } else { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } +// } +// } +// } +// +// @Test +// public void SurroundStarDirectRule_FalseSurroundStar() +// throws InvalidFileFormatException { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/SurroundStarDirectRule/CornerStar", starbattle); +// TreeNode rootNode = starbattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell = board.getCell(2,0); +// cell.setData(StarBattleCellType.BLACK.value); +// board.addModifiedData(cell); +// +// Assert.assertNotNull(RULE.checkRule(transition)); +// +// for (int i = 0; i < board.getHeight(); i++) { +// for (int k = 0; k < board.getWidth(); k++) { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } +// } +// } +//} diff --git a/src/test/java/puzzles/starbattle/rules/TooFewStarsContradictionRuleTest.java b/src/test/java/puzzles/starbattle/rules/TooFewStarsContradictionRuleTest.java index 2c90c6fb2..71d556603 100644 --- a/src/test/java/puzzles/starbattle/rules/TooFewStarsContradictionRuleTest.java +++ b/src/test/java/puzzles/starbattle/rules/TooFewStarsContradictionRuleTest.java @@ -1,205 +1,205 @@ -package puzzles.starbattle.rules; - -import edu.rpi.legup.puzzle.starbattle.rules.ClashingOrbitContradictionRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -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.TooFewStarsContradictionRule; -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 TooFewStarsContradictionRuleTest { - private static final TooFewStarsContradictionRule RULE = new TooFewStarsContradictionRule(); - private static StarBattle starBattle; - - @BeforeClass - public static void setUp() { - MockGameBoardFacade.getInstance(); - starBattle = new StarBattle(); - } - - /*Too few stars in column */ - @Test - public void TooFewStarsContradictionRule_Column() - throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/TooFewStarsContradictionRule/Column", starBattle); - TreeNode rootNode = starBattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell1 = board.getCell(0,0); - StarBattleCell cell2 = board.getCell(0,1); - StarBattleCell cell3 = board.getCell(0,2); - StarBattleCell cell4 = board.getCell(0,3); - - Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); - for (int i = 0; i < board.getHeight(); ++i) { - for (int j = 0; j < board.getWidth(); ++j) { - Point point = new Point(j,i); - if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) || - point.equals(cell3.getLocation()) || point.equals(cell4.getLocation())) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - } - } - - } - - /*Too few stars in row*/ - @Test - public void TooFewStarsContradictionRule_Row() - throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/TooFewStarsContradictionRule/Row", starBattle); - TreeNode rootNode = starBattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell1 = board.getCell(0,0); - StarBattleCell cell2 = board.getCell(1,0); - StarBattleCell cell3 = board.getCell(2,0); - StarBattleCell cell4 = board.getCell(3,0); - - Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); - for (int i = 0; i < board.getHeight(); ++i) { - for (int j = 0; j < board.getWidth(); ++j) { - Point point = new Point(j,i); - if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) || - point.equals(cell3.getLocation()) || point.equals(cell4.getLocation())) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - } - } - } - - /*Too few stars in region*/ - @Test - public void TooFewStarsContradictionRule_Region() - throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/TooFewStarsContradictionRule/Region", starBattle); - TreeNode rootNode = starBattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell1 = board.getCell(0,0); - StarBattleCell cell2 = board.getCell(0,1); - StarBattleCell cell3 = board.getCell(1,0); - StarBattleCell cell4 = board.getCell(1,1); - - Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); - for (int i = 0; i < board.getHeight(); ++i) { - for (int j = 0; j < board.getWidth(); ++j) { - Point point = new Point(j,i); - if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) || - point.equals(cell3.getLocation()) || point.equals(cell4.getLocation())) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - } - } - } - - /*False contradiction*/ - @Test - public void TooFewStarsContradictionRule_FalseContradiction() - throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/TooFewStarsContradictionRule/FalseContradiction", starBattle); - TreeNode rootNode = starBattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - - Assert.assertNotNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); - for (int i = 0; i < board.getHeight(); ++i) { - for (int j = 0; j < board.getWidth(); ++j) { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - } - } - - @Test - public void TooFewStarsContradictionRule_NotEnoughSpace() - throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/TooFewStarsContradictionRule/NotEnoughSpace", starBattle); - TreeNode rootNode = starBattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - - Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); - for (int i = 0; i < board.getHeight(); ++i) { - for (int j = 0; j < board.getWidth(); ++j) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - } - } - - @Test - public void TooFewStarsContradictionRule_TwoStarColumn() - throws InvalidFileFormatException { - - TestUtilities.importTestBoard("puzzles/starbattle/rules/TooFewStarsContradictionRule/TwoStarColumn", starBattle); - TreeNode rootNode = starBattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell1 = board.getCell(0,0); - StarBattleCell cell2 = board.getCell(0,1); - StarBattleCell cell3 = board.getCell(0,2); - StarBattleCell cell4 = board.getCell(0,3); - - Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); - for (int i = 0; i < board.getHeight(); ++i) { - for (int j = 0; j < board.getWidth(); ++j) { - Point point = new Point(j,i); - if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) || - point.equals(cell3.getLocation()) || point.equals(cell4.getLocation())) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - } - } - } - - @Test - public void TooFewStarsContradictionRule_TwoStarFalseContradiction() - throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/TooFewStarsContradictionRule/TwoStarFalseContradiction", starBattle); - TreeNode rootNode = starBattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - - Assert.assertNotNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); - for (int i = 0; i < board.getHeight(); ++i) { - for (int j = 0; j < board.getWidth(); ++j) { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - } - } - -} +//package puzzles.starbattle.rules; +// +//import edu.rpi.legup.puzzle.starbattle.rules.ClashingOrbitContradictionRule; +//import edu.rpi.legup.model.tree.TreeNode; +//import edu.rpi.legup.model.tree.TreeTransition; +//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.TooFewStarsContradictionRule; +//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 TooFewStarsContradictionRuleTest { +// private static final TooFewStarsContradictionRule RULE = new TooFewStarsContradictionRule(); +// private static StarBattle starBattle; +// +// @BeforeClass +// public static void setUp() { +// MockGameBoardFacade.getInstance(); +// starBattle = new StarBattle(); +// } +// +// /*Too few stars in column */ +// @Test +// public void TooFewStarsContradictionRule_Column() +// throws InvalidFileFormatException { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/TooFewStarsContradictionRule/Column", starBattle); +// TreeNode rootNode = starBattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell1 = board.getCell(0,0); +// StarBattleCell cell2 = board.getCell(0,1); +// StarBattleCell cell3 = board.getCell(0,2); +// StarBattleCell cell4 = board.getCell(0,3); +// +// Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); +// for (int i = 0; i < board.getHeight(); ++i) { +// for (int j = 0; j < board.getWidth(); ++j) { +// Point point = new Point(j,i); +// if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) || +// point.equals(cell3.getLocation()) || point.equals(cell4.getLocation())) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); +// } +// else { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); +// } +// } +// } +// +// } +// +// /*Too few stars in row*/ +// @Test +// public void TooFewStarsContradictionRule_Row() +// throws InvalidFileFormatException { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/TooFewStarsContradictionRule/Row", starBattle); +// TreeNode rootNode = starBattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell1 = board.getCell(0,0); +// StarBattleCell cell2 = board.getCell(1,0); +// StarBattleCell cell3 = board.getCell(2,0); +// StarBattleCell cell4 = board.getCell(3,0); +// +// Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); +// for (int i = 0; i < board.getHeight(); ++i) { +// for (int j = 0; j < board.getWidth(); ++j) { +// Point point = new Point(j,i); +// if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) || +// point.equals(cell3.getLocation()) || point.equals(cell4.getLocation())) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); +// } +// else { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); +// } +// } +// } +// } +// +// /*Too few stars in region*/ +// @Test +// public void TooFewStarsContradictionRule_Region() +// throws InvalidFileFormatException { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/TooFewStarsContradictionRule/Region", starBattle); +// TreeNode rootNode = starBattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell1 = board.getCell(0,0); +// StarBattleCell cell2 = board.getCell(0,1); +// StarBattleCell cell3 = board.getCell(1,0); +// StarBattleCell cell4 = board.getCell(1,1); +// +// Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); +// for (int i = 0; i < board.getHeight(); ++i) { +// for (int j = 0; j < board.getWidth(); ++j) { +// Point point = new Point(j,i); +// if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) || +// point.equals(cell3.getLocation()) || point.equals(cell4.getLocation())) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); +// } +// else { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); +// } +// } +// } +// } +// +// /*False contradiction*/ +// @Test +// public void TooFewStarsContradictionRule_FalseContradiction() +// throws InvalidFileFormatException { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/TooFewStarsContradictionRule/FalseContradiction", starBattle); +// TreeNode rootNode = starBattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// +// Assert.assertNotNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); +// for (int i = 0; i < board.getHeight(); ++i) { +// for (int j = 0; j < board.getWidth(); ++j) { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); +// } +// } +// } +// +// @Test +// public void TooFewStarsContradictionRule_NotEnoughSpace() +// throws InvalidFileFormatException { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/TooFewStarsContradictionRule/NotEnoughSpace", starBattle); +// TreeNode rootNode = starBattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// +// Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); +// for (int i = 0; i < board.getHeight(); ++i) { +// for (int j = 0; j < board.getWidth(); ++j) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); +// } +// } +// } +// +// @Test +// public void TooFewStarsContradictionRule_TwoStarColumn() +// throws InvalidFileFormatException { +// +// TestUtilities.importTestBoard("puzzles/starbattle/rules/TooFewStarsContradictionRule/TwoStarColumn", starBattle); +// TreeNode rootNode = starBattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell1 = board.getCell(0,0); +// StarBattleCell cell2 = board.getCell(0,1); +// StarBattleCell cell3 = board.getCell(0,2); +// StarBattleCell cell4 = board.getCell(0,3); +// +// Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); +// for (int i = 0; i < board.getHeight(); ++i) { +// for (int j = 0; j < board.getWidth(); ++j) { +// Point point = new Point(j,i); +// if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) || +// point.equals(cell3.getLocation()) || point.equals(cell4.getLocation())) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); +// } +// else { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); +// } +// } +// } +// } +// +// @Test +// public void TooFewStarsContradictionRule_TwoStarFalseContradiction() +// throws InvalidFileFormatException { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/TooFewStarsContradictionRule/TwoStarFalseContradiction", starBattle); +// TreeNode rootNode = starBattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// +// Assert.assertNotNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); +// for (int i = 0; i < board.getHeight(); ++i) { +// for (int j = 0; j < board.getWidth(); ++j) { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); +// } +// } +// } +// +//} diff --git a/src/test/java/puzzles/starbattle/rules/TooManyStarsContradictionRuleTests.java b/src/test/java/puzzles/starbattle/rules/TooManyStarsContradictionRuleTests.java index 3424bbaac..385652fae 100644 --- a/src/test/java/puzzles/starbattle/rules/TooManyStarsContradictionRuleTests.java +++ b/src/test/java/puzzles/starbattle/rules/TooManyStarsContradictionRuleTests.java @@ -1,137 +1,137 @@ -package puzzles.starbattle.rules; - -import edu.rpi.legup.puzzle.starbattle.rules.TooManyStarsContradictionRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -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.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 TooManyStarsContradictionRuleTests { - private static final TooManyStarsContradictionRule RULE = new TooManyStarsContradictionRule(); - private static StarBattle starBattle; - - @BeforeClass - public static void setUp() { - MockGameBoardFacade.getInstance(); - starBattle = new StarBattle(); - } - - /* Tests the Too Many Stars contradiction rule where a region has - more stars than the puzzle number */ - @Test - public void TooManyStarsContradictionRule_RegionOverloaded() - throws InvalidFileFormatException - { - TestUtilities.importTestBoard("puzzles/starbattle/rules/TooManyStarsContradictionRule/RegionOverloaded", starBattle); - TreeNode rootNode = starBattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell1 = board.getCell(2,1); - StarBattleCell cell2 = board.getCell(0,2); - - Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); - - for (int i = 0; i < board.getHeight(); ++i) { - for (int j = 0; j < board.getWidth(); ++j) { - Point point = new Point(j,i); - if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - } - } - } - - /* Tests the Too Many Stars contradiction rule where a column has - more stars than the puzzle number */ - @Test - public void TooManyStarsContradictionRule_ColumnOverloaded() - throws InvalidFileFormatException - { - TestUtilities.importTestBoard("puzzles/starbattle/rules/TooManyStarsContradictionRule/ColumnOverloaded", starBattle); - TreeNode rootNode = starBattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell1 = board.getCell(0,0); - StarBattleCell cell2 = board.getCell(0,3); - - Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); - - for (int i = 0; i < board.getHeight(); ++i) { - for (int j = 0; j < board.getWidth(); ++j) { - Point point = new Point(j,i); - if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - } - } - } - /* Tests the Too Many Stars contradiction rule where a row has - more stars than the puzzle number */ - @Test - public void TooManyStarsContradictionRule_RowOverloaded() - throws InvalidFileFormatException - { - TestUtilities.importTestBoard("puzzles/starbattle/rules/TooManyStarsContradictionRule/RowOverloaded", starBattle); - TreeNode rootNode = starBattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell1 = board.getCell(0,0); - StarBattleCell cell2 = board.getCell(3,0); - - Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); - - for (int i = 0; i < board.getHeight(); ++i) { - for (int j = 0; j < board.getWidth(); ++j) { - Point point = new Point(j,i); - if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - } - } - } - /*Tests the Too Many Stars contradiction rule for a false contradiction. */ - @Test - public void TooManyStarsContradictionRule_FalseContradiction() - throws InvalidFileFormatException - { - TestUtilities.importTestBoard("puzzles/starbattle/rules/TooManyStarsContradictionRule/Correct", starBattle); - TreeNode rootNode = starBattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - - Assert.assertNotNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); - - for (int i = 0; i < board.getHeight(); ++i) { - for (int j = 0; j < board.getWidth(); ++j) { - Point point = new Point(j,i); - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - } - } -} +//package puzzles.starbattle.rules; +// +//import edu.rpi.legup.puzzle.starbattle.rules.TooManyStarsContradictionRule; +//import edu.rpi.legup.model.tree.TreeNode; +//import edu.rpi.legup.model.tree.TreeTransition; +//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.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 TooManyStarsContradictionRuleTests { +// private static final TooManyStarsContradictionRule RULE = new TooManyStarsContradictionRule(); +// private static StarBattle starBattle; +// +// @BeforeClass +// public static void setUp() { +// MockGameBoardFacade.getInstance(); +// starBattle = new StarBattle(); +// } +// +// /* Tests the Too Many Stars contradiction rule where a region has +// more stars than the puzzle number */ +// @Test +// public void TooManyStarsContradictionRule_RegionOverloaded() +// throws InvalidFileFormatException +// { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/TooManyStarsContradictionRule/RegionOverloaded", starBattle); +// TreeNode rootNode = starBattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell1 = board.getCell(2,1); +// StarBattleCell cell2 = board.getCell(0,2); +// +// Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); +// +// for (int i = 0; i < board.getHeight(); ++i) { +// for (int j = 0; j < board.getWidth(); ++j) { +// Point point = new Point(j,i); +// if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); +// } +// else { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); +// } +// } +// } +// } +// +// /* Tests the Too Many Stars contradiction rule where a column has +// more stars than the puzzle number */ +// @Test +// public void TooManyStarsContradictionRule_ColumnOverloaded() +// throws InvalidFileFormatException +// { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/TooManyStarsContradictionRule/ColumnOverloaded", starBattle); +// TreeNode rootNode = starBattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell1 = board.getCell(0,0); +// StarBattleCell cell2 = board.getCell(0,3); +// +// Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); +// +// for (int i = 0; i < board.getHeight(); ++i) { +// for (int j = 0; j < board.getWidth(); ++j) { +// Point point = new Point(j,i); +// if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); +// } +// else { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); +// } +// } +// } +// } +// /* Tests the Too Many Stars contradiction rule where a row has +// more stars than the puzzle number */ +// @Test +// public void TooManyStarsContradictionRule_RowOverloaded() +// throws InvalidFileFormatException +// { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/TooManyStarsContradictionRule/RowOverloaded", starBattle); +// TreeNode rootNode = starBattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// StarBattleCell cell1 = board.getCell(0,0); +// StarBattleCell cell2 = board.getCell(3,0); +// +// Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); +// +// for (int i = 0; i < board.getHeight(); ++i) { +// for (int j = 0; j < board.getWidth(); ++j) { +// Point point = new Point(j,i); +// if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); +// } +// else { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); +// } +// } +// } +// } +// /*Tests the Too Many Stars contradiction rule for a false contradiction. */ +// @Test +// public void TooManyStarsContradictionRule_FalseContradiction() +// throws InvalidFileFormatException +// { +// TestUtilities.importTestBoard("puzzles/starbattle/rules/TooManyStarsContradictionRule/Correct", starBattle); +// TreeNode rootNode = starBattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// +// Assert.assertNotNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); +// +// for (int i = 0; i < board.getHeight(); ++i) { +// for (int j = 0; j < board.getWidth(); ++j) { +// Point point = new Point(j,i); +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); +// } +// } +// } +//} From 76aa2e78cbd80a41265cfee31f3211deb4262d34 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Mon, 19 Aug 2024 14:04:59 -0400 Subject: [PATCH 257/258] Revert "Starbattle rules causing checkstyle error on github" This reverts commit c2744368a2d5f1b464565171c6147c6c22cf54fd. --- .../rules/BlackoutDirectRuleTest.java | 432 +++++------ .../ClashingOrbitContradictionRuleTest.java | 274 +++---- .../ColumnsWithinRegionsDirectRuleTest.java | 648 ++++++++-------- .../ColumnsWithinRowsDirectRuleTest.java | 488 ++++++------ .../rules/EmptyAdjacentDirectRuleTest.java | 354 ++++----- .../rules/FinishWithStarsDirectRuleTest.java | 418 +++++------ .../RegionsWithinColumnsDirectRuleTest.java | 706 +++++++++--------- .../RegionsWithinRowsDirectRuleTest.java | 516 ++++++------- .../rules/StarOrEmptyCaseRuleTest.java | 136 ++-- .../rules/SurroundStarDirectRuleTest.java | 346 ++++----- .../TooFewStarsContradictionRuleTest.java | 410 +++++----- .../TooManyStarsContradictionRuleTests.java | 274 +++---- 12 files changed, 2501 insertions(+), 2501 deletions(-) diff --git a/src/test/java/puzzles/starbattle/rules/BlackoutDirectRuleTest.java b/src/test/java/puzzles/starbattle/rules/BlackoutDirectRuleTest.java index d1ca68d47..76367ace5 100644 --- a/src/test/java/puzzles/starbattle/rules/BlackoutDirectRuleTest.java +++ b/src/test/java/puzzles/starbattle/rules/BlackoutDirectRuleTest.java @@ -1,216 +1,216 @@ -//package puzzles.starbattle.rules; -// -//import edu.rpi.legup.puzzle.starbattle.rules.BlackoutDirectRule; -//import edu.rpi.legup.model.tree.TreeNode; -//import edu.rpi.legup.model.tree.TreeTransition; -//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.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 { -// private static final BlackoutDirectRule RULE = new BlackoutDirectRule(); -// private static StarBattle starBattle; -// -// @BeforeClass -// public static void setUp() { -// MockGameBoardFacade.getInstance(); -// starBattle = new StarBattle(); -// } -// -// /* Blackout Direct Rule where star is in the corner */ -// @Test -// public void BlackoutDirectRuleTestCorner() -// throws InvalidFileFormatException -// { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/BlackoutDirectRule/Corner", starBattle); -// TreeNode rootNode = starBattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell1 = board.getCell(1,0); -// cell1.setData(StarBattleCellType.BLACK.value); -// StarBattleCell cell2 = board.getCell(2,0); -// cell2.setData(StarBattleCellType.BLACK.value); -// StarBattleCell cell3 = board.getCell(3,0); -// cell3.setData(StarBattleCellType.BLACK.value); -// StarBattleCell cell4 = board.getCell(0,1); -// cell4.setData(StarBattleCellType.BLACK.value); -// StarBattleCell cell5 = board.getCell(1,1); -// cell5.setData(StarBattleCellType.BLACK.value); -// StarBattleCell cell6 = board.getCell(0,2); -// cell6.setData(StarBattleCellType.BLACK.value); -// StarBattleCell cell7 = board.getCell(0,3); -// cell7.setData(StarBattleCellType.BLACK.value); -// -// board.addModifiedData(cell1); -// board.addModifiedData(cell2); -// board.addModifiedData(cell3); -// board.addModifiedData(cell4); -// board.addModifiedData(cell5); -// board.addModifiedData(cell6); -// board.addModifiedData(cell7); -// -// Assert.assertNull(RULE.checkRule(transition)); -// -// for (int i = 0; i < board.getHeight(); ++i) { -// for (int j = 0; j < board.getWidth(); ++j) { -// Point point = new Point(j,i); -// if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) || -// point.equals(cell3.getLocation()) || point.equals(cell4.getLocation()) || -// point.equals(cell5.getLocation()) || point.equals(cell6.getLocation()) || -// point.equals(cell7.getLocation())) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); -// } -// else { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); -// } -// } -// } -// } -// /* Blackout Direct Rule where star is on the edge */ -// @Test -// public void BlackoutDirectRuleTestEdge() -// throws InvalidFileFormatException -// { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/BlackoutDirectRule/Edge", starBattle); -// TreeNode rootNode = starBattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell1 = board.getCell(0,0); -// cell1.setData(StarBattleCellType.BLACK.value); -// StarBattleCell cell2 = board.getCell(2,0); -// cell2.setData(StarBattleCellType.BLACK.value); -// StarBattleCell cell3 = board.getCell(3,0); -// cell3.setData(StarBattleCellType.BLACK.value); -// StarBattleCell cell4 = board.getCell(0,1); -// cell4.setData(StarBattleCellType.BLACK.value); -// StarBattleCell cell5 = board.getCell(1,1); -// cell5.setData(StarBattleCellType.BLACK.value); -// StarBattleCell cell6 = board.getCell(1,2); -// cell6.setData(StarBattleCellType.BLACK.value); -// StarBattleCell cell7 = board.getCell(1,3); -// cell7.setData(StarBattleCellType.BLACK.value); -// -// board.addModifiedData(cell1); -// board.addModifiedData(cell2); -// board.addModifiedData(cell3); -// board.addModifiedData(cell4); -// board.addModifiedData(cell5); -// board.addModifiedData(cell6); -// board.addModifiedData(cell7); -// -// Assert.assertNull(RULE.checkRule(transition)); -// -// for (int i = 0; i < board.getHeight(); ++i) { -// for (int j = 0; j < board.getWidth(); ++j) { -// Point point = new Point(j,i); -// if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) || -// point.equals(cell3.getLocation()) || point.equals(cell4.getLocation()) || -// point.equals(cell5.getLocation()) || point.equals(cell6.getLocation()) || -// point.equals(cell7.getLocation())) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); -// } -// else { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); -// } -// } -// } -// } -// -// /* Blackout Direct Rule where star is on the edge */ -// @Test -// public void BlackoutDirectRuleTestMiddle() -// throws InvalidFileFormatException -// { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/BlackoutDirectRule/Middle", starBattle); -// TreeNode rootNode = starBattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell1 = board.getCell(0,0); -// cell1.setData(StarBattleCellType.BLACK.value); -// StarBattleCell cell2 = board.getCell(1,0); -// cell2.setData(StarBattleCellType.BLACK.value); -// StarBattleCell cell3 = board.getCell(0,1); -// cell3.setData(StarBattleCellType.BLACK.value); -// StarBattleCell cell4 = board.getCell(2,1); -// cell4.setData(StarBattleCellType.BLACK.value); -// StarBattleCell cell5 = board.getCell(3,1); -// cell5.setData(StarBattleCellType.BLACK.value); -// StarBattleCell cell6 = board.getCell(1,2); -// cell6.setData(StarBattleCellType.BLACK.value); -// StarBattleCell cell7 = board.getCell(1,3); -// cell7.setData(StarBattleCellType.BLACK.value); -// -// board.addModifiedData(cell1); -// board.addModifiedData(cell2); -// board.addModifiedData(cell3); -// board.addModifiedData(cell4); -// board.addModifiedData(cell5); -// board.addModifiedData(cell6); -// board.addModifiedData(cell7); -// -// Assert.assertNull(RULE.checkRule(transition)); -// -// for (int i = 0; i < board.getHeight(); ++i) { -// for (int j = 0; j < board.getWidth(); ++j) { -// Point point = new Point(j,i); -// if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) || -// point.equals(cell3.getLocation()) || point.equals(cell4.getLocation()) || -// point.equals(cell5.getLocation()) || point.equals(cell6.getLocation()) || -// point.equals(cell7.getLocation())) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); -// } -// else { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); -// } -// } -// } -// } -// /* Blackout Direct Rule where rule is called incorrectly */ -// @Test -// public void BlackoutDirectRuleTestFalse() -// throws InvalidFileFormatException -// { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/BlackoutDirectRule/Middle", starBattle); -// TreeNode rootNode = starBattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell1 = board.getCell(2,2); -// cell1.setData(StarBattleCellType.BLACK.value); -// StarBattleCell cell2 = board.getCell(2,3); -// cell2.setData(StarBattleCellType.BLACK.value); -// StarBattleCell cell3 = board.getCell(3,2); -// cell3.setData(StarBattleCellType.BLACK.value); -// StarBattleCell cell4 = board.getCell(3,3); -// -// board.addModifiedData(cell1); -// board.addModifiedData(cell2); -// board.addModifiedData(cell3); -// board.addModifiedData(cell4); -// -// Assert.assertNotNull(RULE.checkRule(transition)); -// -// for (int i = 0; i < board.getHeight(); ++i) { -// for (int j = 0; j < board.getWidth(); ++j) { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); -// } -// } -// } -// -// -//} +package puzzles.starbattle.rules; + +import edu.rpi.legup.puzzle.starbattle.rules.BlackoutDirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +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.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 { + private static final BlackoutDirectRule RULE = new BlackoutDirectRule(); + private static StarBattle starBattle; + + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + starBattle = new StarBattle(); + } + + /* Blackout Direct Rule where star is in the corner */ + @Test + public void BlackoutDirectRuleTestCorner() + throws InvalidFileFormatException + { + TestUtilities.importTestBoard("puzzles/starbattle/rules/BlackoutDirectRule/Corner", starBattle); + TreeNode rootNode = starBattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(1,0); + cell1.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell2 = board.getCell(2,0); + cell2.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell3 = board.getCell(3,0); + cell3.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell4 = board.getCell(0,1); + cell4.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell5 = board.getCell(1,1); + cell5.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell6 = board.getCell(0,2); + cell6.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell7 = board.getCell(0,3); + cell7.setData(StarBattleCellType.BLACK.value); + + board.addModifiedData(cell1); + board.addModifiedData(cell2); + board.addModifiedData(cell3); + board.addModifiedData(cell4); + board.addModifiedData(cell5); + board.addModifiedData(cell6); + board.addModifiedData(cell7); + + Assert.assertNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); ++i) { + for (int j = 0; j < board.getWidth(); ++j) { + Point point = new Point(j,i); + if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) || + point.equals(cell3.getLocation()) || point.equals(cell4.getLocation()) || + point.equals(cell5.getLocation()) || point.equals(cell6.getLocation()) || + point.equals(cell7.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + } + } + } + /* Blackout Direct Rule where star is on the edge */ + @Test + public void BlackoutDirectRuleTestEdge() + throws InvalidFileFormatException + { + TestUtilities.importTestBoard("puzzles/starbattle/rules/BlackoutDirectRule/Edge", starBattle); + TreeNode rootNode = starBattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(0,0); + cell1.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell2 = board.getCell(2,0); + cell2.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell3 = board.getCell(3,0); + cell3.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell4 = board.getCell(0,1); + cell4.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell5 = board.getCell(1,1); + cell5.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell6 = board.getCell(1,2); + cell6.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell7 = board.getCell(1,3); + cell7.setData(StarBattleCellType.BLACK.value); + + board.addModifiedData(cell1); + board.addModifiedData(cell2); + board.addModifiedData(cell3); + board.addModifiedData(cell4); + board.addModifiedData(cell5); + board.addModifiedData(cell6); + board.addModifiedData(cell7); + + Assert.assertNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); ++i) { + for (int j = 0; j < board.getWidth(); ++j) { + Point point = new Point(j,i); + if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) || + point.equals(cell3.getLocation()) || point.equals(cell4.getLocation()) || + point.equals(cell5.getLocation()) || point.equals(cell6.getLocation()) || + point.equals(cell7.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + } + } + } + + /* Blackout Direct Rule where star is on the edge */ + @Test + public void BlackoutDirectRuleTestMiddle() + throws InvalidFileFormatException + { + TestUtilities.importTestBoard("puzzles/starbattle/rules/BlackoutDirectRule/Middle", starBattle); + TreeNode rootNode = starBattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(0,0); + cell1.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell2 = board.getCell(1,0); + cell2.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell3 = board.getCell(0,1); + cell3.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell4 = board.getCell(2,1); + cell4.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell5 = board.getCell(3,1); + cell5.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell6 = board.getCell(1,2); + cell6.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell7 = board.getCell(1,3); + cell7.setData(StarBattleCellType.BLACK.value); + + board.addModifiedData(cell1); + board.addModifiedData(cell2); + board.addModifiedData(cell3); + board.addModifiedData(cell4); + board.addModifiedData(cell5); + board.addModifiedData(cell6); + board.addModifiedData(cell7); + + Assert.assertNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); ++i) { + for (int j = 0; j < board.getWidth(); ++j) { + Point point = new Point(j,i); + if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) || + point.equals(cell3.getLocation()) || point.equals(cell4.getLocation()) || + point.equals(cell5.getLocation()) || point.equals(cell6.getLocation()) || + point.equals(cell7.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + } + } + } + /* Blackout Direct Rule where rule is called incorrectly */ + @Test + public void BlackoutDirectRuleTestFalse() + throws InvalidFileFormatException + { + TestUtilities.importTestBoard("puzzles/starbattle/rules/BlackoutDirectRule/Middle", starBattle); + TreeNode rootNode = starBattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(2,2); + cell1.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell2 = board.getCell(2,3); + cell2.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell3 = board.getCell(3,2); + cell3.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell4 = board.getCell(3,3); + + board.addModifiedData(cell1); + board.addModifiedData(cell2); + board.addModifiedData(cell3); + board.addModifiedData(cell4); + + Assert.assertNotNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); ++i) { + for (int j = 0; j < board.getWidth(); ++j) { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + } + } + + +} diff --git a/src/test/java/puzzles/starbattle/rules/ClashingOrbitContradictionRuleTest.java b/src/test/java/puzzles/starbattle/rules/ClashingOrbitContradictionRuleTest.java index 193177138..ae8aaa08e 100644 --- a/src/test/java/puzzles/starbattle/rules/ClashingOrbitContradictionRuleTest.java +++ b/src/test/java/puzzles/starbattle/rules/ClashingOrbitContradictionRuleTest.java @@ -1,137 +1,137 @@ -//package puzzles.starbattle.rules; -// -//import edu.rpi.legup.puzzle.starbattle.rules.ClashingOrbitContradictionRule; -//import edu.rpi.legup.model.tree.TreeNode; -//import edu.rpi.legup.model.tree.TreeTransition; -//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.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 ClashingOrbitContradictionRuleTest { -// -// private static final ClashingOrbitContradictionRule RULE = new ClashingOrbitContradictionRule(); -// private static StarBattle starBattle; -// -// @BeforeClass -// public static void setUp() { -// MockGameBoardFacade.getInstance(); -// starBattle = new StarBattle(); -// } -// -// /*Tests the Clashing Orbit contradiction rule for directly adjacent stars not at the -// edge of the board */ -// @Test -// public void ClashingOrbitContradictionRule_DirectlyAdjacentCenter() -// throws InvalidFileFormatException -// { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/ClashingOrbitContradictionRule/DirectlyAdjacentCenter", starBattle); -// TreeNode rootNode = starBattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell1 = board.getCell(1,1); -// StarBattleCell cell2 = board.getCell(2,1); -// -// Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); -// -// for (int i = 0; i < board.getHeight(); ++i) { -// for (int j = 0; j < board.getWidth(); ++j) { -// Point point = new Point(j,i); -// if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); -// } -// else { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); -// } -// } -// } -// } -// -// /* Tests the Clashing Orbit contradiction rule for diagonally adjacent stars */ -// @Test -// public void ClashingOrbitContradictionRule_DiagonallyAdjacent() -// throws InvalidFileFormatException -// { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/ClashingOrbitContradictionRule/DiagonallyAdjacent", starBattle); -// TreeNode rootNode = starBattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell1 = board.getCell(1,1); -// StarBattleCell cell2 = board.getCell(2,2); -// -// Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); -// -// for (int i = 0; i < board.getHeight(); ++i) { -// for (int j = 0; j < board.getWidth(); ++j) { -// Point point = new Point(j,i); -// if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); -// } -// else { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); -// } -// } -// } -// } -// -// /*Tests the Clashing Orbit contradiction rule for stars at the edge of the board */ -// @Test -// public void ClashingOrbitContradictionRule_DirectlyAdjacentEdge() -// throws InvalidFileFormatException -// { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/ClashingOrbitContradictionRule/DirectlyAdjacentEdge", starBattle); -// TreeNode rootNode = starBattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell1 = board.getCell(0,0); -// StarBattleCell cell2 = board.getCell(1,0); -// -// Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); -// -// for (int i = 0; i < board.getHeight(); ++i) { -// for (int j = 0; j < board.getWidth(); ++j) { -// Point point = new Point(j,i); -// if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); -// } -// else { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); -// } -// } -// } -// } -// -// /*Tests the Clashing Orbit contradiction rule for a false contradiction. */ -// @Test -// public void ClashingOrbitContradictionRule_FalseContradiction() -// throws InvalidFileFormatException -// { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/ClashingOrbitContradictionRule/FalseContradiction", starBattle); -// TreeNode rootNode = starBattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// -// Assert.assertNotNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); -// -// for (int i = 0; i < board.getHeight(); ++i) { -// for (int j = 0; j < board.getWidth(); ++j) { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); -// } -// } -// } -//} +package puzzles.starbattle.rules; + +import edu.rpi.legup.puzzle.starbattle.rules.ClashingOrbitContradictionRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +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.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 ClashingOrbitContradictionRuleTest { + + private static final ClashingOrbitContradictionRule RULE = new ClashingOrbitContradictionRule(); + private static StarBattle starBattle; + + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + starBattle = new StarBattle(); + } + + /*Tests the Clashing Orbit contradiction rule for directly adjacent stars not at the + edge of the board */ + @Test + public void ClashingOrbitContradictionRule_DirectlyAdjacentCenter() + throws InvalidFileFormatException + { + TestUtilities.importTestBoard("puzzles/starbattle/rules/ClashingOrbitContradictionRule/DirectlyAdjacentCenter", starBattle); + TreeNode rootNode = starBattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(1,1); + StarBattleCell cell2 = board.getCell(2,1); + + Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); + + for (int i = 0; i < board.getHeight(); ++i) { + for (int j = 0; j < board.getWidth(); ++j) { + Point point = new Point(j,i); + if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + } + } + } + + /* Tests the Clashing Orbit contradiction rule for diagonally adjacent stars */ + @Test + public void ClashingOrbitContradictionRule_DiagonallyAdjacent() + throws InvalidFileFormatException + { + TestUtilities.importTestBoard("puzzles/starbattle/rules/ClashingOrbitContradictionRule/DiagonallyAdjacent", starBattle); + TreeNode rootNode = starBattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(1,1); + StarBattleCell cell2 = board.getCell(2,2); + + Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); + + for (int i = 0; i < board.getHeight(); ++i) { + for (int j = 0; j < board.getWidth(); ++j) { + Point point = new Point(j,i); + if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + } + } + } + + /*Tests the Clashing Orbit contradiction rule for stars at the edge of the board */ + @Test + public void ClashingOrbitContradictionRule_DirectlyAdjacentEdge() + throws InvalidFileFormatException + { + TestUtilities.importTestBoard("puzzles/starbattle/rules/ClashingOrbitContradictionRule/DirectlyAdjacentEdge", starBattle); + TreeNode rootNode = starBattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(0,0); + StarBattleCell cell2 = board.getCell(1,0); + + Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); + + for (int i = 0; i < board.getHeight(); ++i) { + for (int j = 0; j < board.getWidth(); ++j) { + Point point = new Point(j,i); + if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + } + } + } + + /*Tests the Clashing Orbit contradiction rule for a false contradiction. */ + @Test + public void ClashingOrbitContradictionRule_FalseContradiction() + throws InvalidFileFormatException + { + TestUtilities.importTestBoard("puzzles/starbattle/rules/ClashingOrbitContradictionRule/FalseContradiction", starBattle); + TreeNode rootNode = starBattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + + Assert.assertNotNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); + + for (int i = 0; i < board.getHeight(); ++i) { + for (int j = 0; j < board.getWidth(); ++j) { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + } + } +} diff --git a/src/test/java/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRuleTest.java b/src/test/java/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRuleTest.java index 3a11c6606..185d31f5c 100644 --- a/src/test/java/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRuleTest.java +++ b/src/test/java/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRuleTest.java @@ -1,324 +1,324 @@ -//package puzzles.starbattle.rules; -// -//import edu.rpi.legup.model.tree.TreeNode; -//import edu.rpi.legup.model.tree.TreeTransition; -//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.ColumnsWithinRegionsDirectRule; -//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.awt.*; -// -//public class ColumnsWithinRegionsDirectRuleTest { -// -// private static final ColumnsWithinRegionsDirectRule RULE = new ColumnsWithinRegionsDirectRule(); -// private static StarBattle starbattle; -// -// @BeforeClass -// public static void setUp() { -// MockGameBoardFacade.getInstance(); -// starbattle = new StarBattle(); -// } -// -// @Test -// public void ColumnsWithinRegionsDirectRule_OneColumnOneCell() -// throws InvalidFileFormatException { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/OneColumnOneCell", starbattle); -// TreeNode rootNode = starbattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell = board.getCell(1,0); -// cell.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell); -// -// Assert.assertNull(RULE.checkRule(transition)); -// -// Point location = new Point(1, 0); -// 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(location)) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } else { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } -// } -// } -// } -// -// @Test -// public void ColumnsWithinRegionsDirectRule_PartialColumnOneCell() -// throws InvalidFileFormatException { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/PartialColumnOneCell", starbattle); -// TreeNode rootNode = starbattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell = board.getCell(1,2); -// cell.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell); -// -// Assert.assertNull(RULE.checkRule(transition)); -// -// Point location = new Point(1, 2); -// 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(location)) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } else { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } -// } -// } -// } -// -// @Test -// public void ColumnsWithinRegionsDirectRule_PartialColumnTwoCells() -// throws InvalidFileFormatException { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/PartialColumnTwoCells", starbattle); -// TreeNode rootNode = starbattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell1 = board.getCell(0,1); -// cell1.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell1); -// StarBattleCell cell2 = board.getCell(2,1); -// cell2.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell2); -// -// Assert.assertNull(RULE.checkRule(transition)); -// -// Point location1 = new Point(0, 1); -// Point location2 = new Point(2,1); -// 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(location1) || point.equals(location2)) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } else { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } -// } -// } -// } -// -// @Test -// public void ColumnsWithinRegionsDirectRule_TwoColumns() -// throws InvalidFileFormatException { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/TwoColumns", starbattle); -// TreeNode rootNode = starbattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell1 = board.getCell(2,1); -// cell1.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell1); -// StarBattleCell cell2 = board.getCell(2,2); -// cell2.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell2); -// -// Assert.assertNull(RULE.checkRule(transition)); -// -// Point location1 = new Point(2, 1); -// Point location2 = new Point(2,2); -// 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(location1) || point.equals(location2)) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } else { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } -// } -// } -// } -// -// /* Wrote this to figure out the specifics of how the rule is functioning - might change -// * what the expected result is. */ -// @Test -// public void ColumnsWithinRegionsDirectRule_TwoColumnsWaitAMinute() -// throws InvalidFileFormatException { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/TwoColumns", starbattle); -// TreeNode rootNode = starbattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell1 = board.getCell(2,1); -// cell1.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell1); -// -// Assert.assertNull(RULE.checkRule(transition)); -// -// Point location1 = new Point(2, 1); -// 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(location1)) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } else { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } -// } -// } -// } -// -// @Test -// public void ColumnsWithinRegionsDirectRule_TwoColumnsStarOverlap() -// throws InvalidFileFormatException { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/TwoColumnsStarOverlap", starbattle); -// TreeNode rootNode = starbattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell1 = board.getCell(2,3); -// cell1.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell1); -// -// Assert.assertNull(RULE.checkRule(transition)); -// -// Point location1 = new Point(2, 3); -// 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(location1)) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } else { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } -// } -// } -// } -// -// @Test -// public void ColumnsWithinRegionsDirectRule_FalseColumnsWithinRegions1() -// throws InvalidFileFormatException { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/OneColumnOneCell", starbattle); -// TreeNode rootNode = starbattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell1 = board.getCell(1,0); -// cell1.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell1); -// StarBattleCell cell2 = board.getCell(0,0); -// cell2.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell2); -// -// Assert.assertNotNull(RULE.checkRule(transition)); -// -// Point location = new Point(1, 0); -// 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(location)) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } else { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } -// } -// } -// } -// -// @Test -// public void ColumnsWithinRegionsDirectRule_FalseColumnsWithinRegions2() -// throws InvalidFileFormatException { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/OneColumnOneCell", starbattle); -// TreeNode rootNode = starbattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell1 = board.getCell(1,0); -// cell1.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell1); -// StarBattleCell cell2 = board.getCell(1,1); -// cell2.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell2); -// -// Assert.assertNotNull(RULE.checkRule(transition)); -// -// Point location = new Point(1, 0); -// 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(location)) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } else { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } -// } -// } -// } -// -// @Test -// public void ColumnsWithinRegionsDirectRule_PartialRemoval() -// throws InvalidFileFormatException { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/PartialColumnTwoCells", starbattle); -// TreeNode rootNode = starbattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell1 = board.getCell(0,1); -// cell1.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell1); -// -// Assert.assertNull(RULE.checkRule(transition)); -// -// Point location1 = new Point(0, 1); -// 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(location1)) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } -// else { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } -// } -// } -// } -// -// @Test -// public void ColumnsWithinRegionsDirectRule_FalseColumnsWithinRegions4() -// throws InvalidFileFormatException { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/FalseStarOverlap", starbattle); -// TreeNode rootNode = starbattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell1 = board.getCell(2,2); -// cell1.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell1); -// StarBattleCell cell2 = board.getCell(2,3); -// cell2.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell2); -// -// Assert.assertNotNull(RULE.checkRule(transition)); -// -// for (int i = 0; i < board.getHeight(); i++) { -// for (int k = 0; k < board.getWidth(); k++) { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } -// } -// } -// -//} +package puzzles.starbattle.rules; + +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +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.ColumnsWithinRegionsDirectRule; +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.awt.*; + +public class ColumnsWithinRegionsDirectRuleTest { + + private static final ColumnsWithinRegionsDirectRule RULE = new ColumnsWithinRegionsDirectRule(); + private static StarBattle starbattle; + + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + starbattle = new StarBattle(); + } + + @Test + public void ColumnsWithinRegionsDirectRule_OneColumnOneCell() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/OneColumnOneCell", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell = board.getCell(1,0); + cell.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell); + + Assert.assertNull(RULE.checkRule(transition)); + + Point location = new Point(1, 0); + 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(location)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void ColumnsWithinRegionsDirectRule_PartialColumnOneCell() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/PartialColumnOneCell", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell = board.getCell(1,2); + cell.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell); + + Assert.assertNull(RULE.checkRule(transition)); + + Point location = new Point(1, 2); + 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(location)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void ColumnsWithinRegionsDirectRule_PartialColumnTwoCells() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/PartialColumnTwoCells", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(0,1); + cell1.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell1); + StarBattleCell cell2 = board.getCell(2,1); + cell2.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell2); + + Assert.assertNull(RULE.checkRule(transition)); + + Point location1 = new Point(0, 1); + Point location2 = new Point(2,1); + 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(location1) || point.equals(location2)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void ColumnsWithinRegionsDirectRule_TwoColumns() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/TwoColumns", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(2,1); + cell1.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell1); + StarBattleCell cell2 = board.getCell(2,2); + cell2.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell2); + + Assert.assertNull(RULE.checkRule(transition)); + + Point location1 = new Point(2, 1); + Point location2 = new Point(2,2); + 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(location1) || point.equals(location2)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + /* Wrote this to figure out the specifics of how the rule is functioning - might change + * what the expected result is. */ + @Test + public void ColumnsWithinRegionsDirectRule_TwoColumnsWaitAMinute() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/TwoColumns", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(2,1); + cell1.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell1); + + Assert.assertNull(RULE.checkRule(transition)); + + Point location1 = new Point(2, 1); + 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(location1)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void ColumnsWithinRegionsDirectRule_TwoColumnsStarOverlap() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/TwoColumnsStarOverlap", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(2,3); + cell1.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell1); + + Assert.assertNull(RULE.checkRule(transition)); + + Point location1 = new Point(2, 3); + 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(location1)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void ColumnsWithinRegionsDirectRule_FalseColumnsWithinRegions1() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/OneColumnOneCell", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(1,0); + cell1.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell1); + StarBattleCell cell2 = board.getCell(0,0); + cell2.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell2); + + Assert.assertNotNull(RULE.checkRule(transition)); + + Point location = new Point(1, 0); + 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(location)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void ColumnsWithinRegionsDirectRule_FalseColumnsWithinRegions2() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/OneColumnOneCell", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(1,0); + cell1.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell1); + StarBattleCell cell2 = board.getCell(1,1); + cell2.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell2); + + Assert.assertNotNull(RULE.checkRule(transition)); + + Point location = new Point(1, 0); + 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(location)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void ColumnsWithinRegionsDirectRule_PartialRemoval() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/PartialColumnTwoCells", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(0,1); + cell1.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell1); + + Assert.assertNull(RULE.checkRule(transition)); + + Point location1 = new Point(0, 1); + 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(location1)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void ColumnsWithinRegionsDirectRule_FalseColumnsWithinRegions4() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/FalseStarOverlap", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(2,2); + cell1.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell1); + StarBattleCell cell2 = board.getCell(2,3); + cell2.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell2); + + Assert.assertNotNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); i++) { + for (int k = 0; k < board.getWidth(); k++) { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + +} diff --git a/src/test/java/puzzles/starbattle/rules/ColumnsWithinRowsDirectRuleTest.java b/src/test/java/puzzles/starbattle/rules/ColumnsWithinRowsDirectRuleTest.java index 80f15f0f8..8f9c938cb 100644 --- a/src/test/java/puzzles/starbattle/rules/ColumnsWithinRowsDirectRuleTest.java +++ b/src/test/java/puzzles/starbattle/rules/ColumnsWithinRowsDirectRuleTest.java @@ -1,244 +1,244 @@ -//package puzzles.starbattle.rules; -// -//import edu.rpi.legup.model.tree.TreeNode; -//import edu.rpi.legup.model.tree.TreeTransition; -//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.ColumnsWithinRowsDirectRule; -//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.awt.*; -// -//public class ColumnsWithinRowsDirectRuleTest { -// -// private static final ColumnsWithinRowsDirectRule RULE = new ColumnsWithinRowsDirectRule(); -// private static StarBattle starbattle; -// -// @BeforeClass -// public static void setUp() { -// MockGameBoardFacade.getInstance(); -// starbattle = new StarBattle(); -// } -// -// @Test -// public void ColumnsWithinRowsDirectRule_OneColumn() -// throws InvalidFileFormatException { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/OneColumn", starbattle); -// TreeNode rootNode = starbattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell1 = board.getCell(1,0); -// cell1.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell1); -// StarBattleCell cell2 = board.getCell(2,0); -// cell2.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell2); -// -// Assert.assertNull(RULE.checkRule(transition)); -// -// Point location1 = new Point(1, 0); -// Point location2 = new Point(2,0); -// 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(location1) || point.equals(location2)) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } else { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } -// } -// } -// } -// -// @Test -// public void ColumnsWithinRowsDirectRule_TwoColumns() -// throws InvalidFileFormatException { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/TwoColumns", starbattle); -// TreeNode rootNode = starbattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell1 = board.getCell(2,1); -// cell1.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell1); -// StarBattleCell cell2 = board.getCell(2,0); -// cell2.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell2); -// -// Assert.assertNull(RULE.checkRule(transition)); -// -// Point location1 = new Point(2, 1); -// Point location2 = new Point(2,0); -// 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(location1) || point.equals(location2)) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } else { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } -// } -// } -// } -// -// @Test -// public void ColumnsWithinRowsDirectRule_NonAdjacentColumns() -// throws InvalidFileFormatException { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/NonAdjacentColumns", starbattle); -// TreeNode rootNode = starbattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell1 = board.getCell(1,0); -// cell1.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell1); -// StarBattleCell cell2 = board.getCell(1,2); -// cell2.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell2); -// -// Assert.assertNull(RULE.checkRule(transition)); -// -// Point location1 = new Point(1, 0); -// Point location2 = new Point(1,2); -// 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(location1) || point.equals(location2)) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } else { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } -// } -// } -// } -// -// @Test -// public void ColumnsWithinRowsDirectRule_TwoColumnsStarOverlap() -// throws InvalidFileFormatException { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/TwoColumnsStarOverlap", starbattle); -// TreeNode rootNode = starbattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell1 = board.getCell(2,1); -// cell1.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell1); -// StarBattleCell cell2 = board.getCell(3,0); -// cell2.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell2); -// -// Assert.assertNull(RULE.checkRule(transition)); -// -// Point location1 = new Point(2, 1); -// Point location2 = new Point(3,0); -// 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(location1) || point.equals(location2)) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } else { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } -// } -// } -// } -// -// @Test -// public void ColumnsWithinRowsDirectRule_FalseColumnsWithinRows1() -// throws InvalidFileFormatException { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/OneColumn", starbattle); -// TreeNode rootNode = starbattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell1 = board.getCell(1,0); -// cell1.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell1); -// StarBattleCell cell2 = board.getCell(2,0); -// cell2.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell2); -// StarBattleCell cell3 = board.getCell(1,1); -// cell3.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell3); -// -// Assert.assertNotNull(RULE.checkRule(transition)); -// -// Point location1 = new Point(1, 0); -// Point location2 = new Point(2,0); -// 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(location1) || point.equals(location2)) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } else { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } -// } -// } -// } -// -// @Test -// public void ColumnsWithinRowsDirectRule_PartialCover() -// throws InvalidFileFormatException { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/OneColumn", starbattle); -// TreeNode rootNode = starbattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell1 = board.getCell(1,0); -// cell1.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell1); -// -// Assert.assertNull(RULE.checkRule(transition)); -// -// Point location = new Point(1,0); -// 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(location)) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } -// else { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } -// } -// } -// } -// -// @Test -// public void ColumnsWithinRowsDirectRule_FalseColumnsWithinRows3() -// throws InvalidFileFormatException { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/FalseStarOverlap", starbattle); -// TreeNode rootNode = starbattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell1 = board.getCell(1,0); -// cell1.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell1); -// -// Assert.assertNotNull(RULE.checkRule(transition)); -// -// for (int i = 0; i < board.getHeight(); i++) { -// for (int k = 0; k < board.getWidth(); k++) { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } -// } -// } -// -//} +package puzzles.starbattle.rules; + +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +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.ColumnsWithinRowsDirectRule; +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.awt.*; + +public class ColumnsWithinRowsDirectRuleTest { + + private static final ColumnsWithinRowsDirectRule RULE = new ColumnsWithinRowsDirectRule(); + private static StarBattle starbattle; + + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + starbattle = new StarBattle(); + } + + @Test + public void ColumnsWithinRowsDirectRule_OneColumn() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/OneColumn", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(1,0); + cell1.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell1); + StarBattleCell cell2 = board.getCell(2,0); + cell2.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell2); + + Assert.assertNull(RULE.checkRule(transition)); + + Point location1 = new Point(1, 0); + Point location2 = new Point(2,0); + 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(location1) || point.equals(location2)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void ColumnsWithinRowsDirectRule_TwoColumns() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/TwoColumns", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(2,1); + cell1.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell1); + StarBattleCell cell2 = board.getCell(2,0); + cell2.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell2); + + Assert.assertNull(RULE.checkRule(transition)); + + Point location1 = new Point(2, 1); + Point location2 = new Point(2,0); + 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(location1) || point.equals(location2)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void ColumnsWithinRowsDirectRule_NonAdjacentColumns() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/NonAdjacentColumns", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(1,0); + cell1.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell1); + StarBattleCell cell2 = board.getCell(1,2); + cell2.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell2); + + Assert.assertNull(RULE.checkRule(transition)); + + Point location1 = new Point(1, 0); + Point location2 = new Point(1,2); + 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(location1) || point.equals(location2)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void ColumnsWithinRowsDirectRule_TwoColumnsStarOverlap() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/TwoColumnsStarOverlap", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(2,1); + cell1.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell1); + StarBattleCell cell2 = board.getCell(3,0); + cell2.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell2); + + Assert.assertNull(RULE.checkRule(transition)); + + Point location1 = new Point(2, 1); + Point location2 = new Point(3,0); + 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(location1) || point.equals(location2)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void ColumnsWithinRowsDirectRule_FalseColumnsWithinRows1() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/OneColumn", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(1,0); + cell1.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell1); + StarBattleCell cell2 = board.getCell(2,0); + cell2.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell2); + StarBattleCell cell3 = board.getCell(1,1); + cell3.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell3); + + Assert.assertNotNull(RULE.checkRule(transition)); + + Point location1 = new Point(1, 0); + Point location2 = new Point(2,0); + 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(location1) || point.equals(location2)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void ColumnsWithinRowsDirectRule_PartialCover() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/OneColumn", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(1,0); + cell1.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell1); + + Assert.assertNull(RULE.checkRule(transition)); + + Point location = new Point(1,0); + 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(location)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void ColumnsWithinRowsDirectRule_FalseColumnsWithinRows3() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/FalseStarOverlap", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(1,0); + cell1.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell1); + + Assert.assertNotNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); i++) { + for (int k = 0; k < board.getWidth(); k++) { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + +} diff --git a/src/test/java/puzzles/starbattle/rules/EmptyAdjacentDirectRuleTest.java b/src/test/java/puzzles/starbattle/rules/EmptyAdjacentDirectRuleTest.java index 5ab05c86b..c81c74657 100644 --- a/src/test/java/puzzles/starbattle/rules/EmptyAdjacentDirectRuleTest.java +++ b/src/test/java/puzzles/starbattle/rules/EmptyAdjacentDirectRuleTest.java @@ -1,177 +1,177 @@ -//package puzzles.starbattle.rules; -// -//import edu.rpi.legup.model.tree.TreeNode; -//import edu.rpi.legup.model.tree.TreeTransition; -//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.EmptyAdjacentDirectRule; -//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 EmptyAdjacentDirectRuleTest { -// -// private static final EmptyAdjacentDirectRule RULE = new EmptyAdjacentDirectRule(); -// private static StarBattle starbattle; -// -// @BeforeClass -// public static void setUp() { -// MockGameBoardFacade.getInstance(); -// starbattle = new StarBattle(); -// } -// -// @Test -// public void EmptyAdjacentDirectRule_OneLeft() throws InvalidFileFormatException { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/EmptyAdjacentDirectRule/OneLeft", starbattle); -// TreeNode rootNode = starbattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell1 = board.getCell(1,1); -// cell1.setData(StarBattleCellType.BLACK.value); -// StarBattleCell cell2 = board.getCell(2,1); -// cell2.setData(StarBattleCellType.BLACK.value); -// StarBattleCell cell3 = board.getCell(3,1); -// cell3.setData(StarBattleCellType.BLACK.value); -// StarBattleCell cell4 = board.getCell(1,3); -// cell4.setData(StarBattleCellType.BLACK.value); -// StarBattleCell cell5 = board.getCell(2,3); -// cell5.setData(StarBattleCellType.BLACK.value); -// StarBattleCell cell6 = board.getCell(3,3); -// cell6.setData(StarBattleCellType.BLACK.value); -// -// board.addModifiedData(cell1); -// board.addModifiedData(cell2); -// board.addModifiedData(cell3); -// board.addModifiedData(cell4); -// board.addModifiedData(cell5); -// board.addModifiedData(cell6); -// -// Assert.assertNull(RULE.checkRule(transition)); -// -// for (int i = 0; i < board.getHeight(); ++i) { -// for (int j = 0; j < board.getWidth(); ++j) { -// Point point = new Point(j,i); -// if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) || -// point.equals(cell3.getLocation()) || point.equals(cell4.getLocation()) || -// point.equals(cell5.getLocation()) || point.equals(cell6.getLocation())) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); -// } -// else { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); -// } -// } -// } -// } -// -// @Test -// public void EmptyAdjacentDirectRule_TwoLeft() throws InvalidFileFormatException { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/EmptyAdjacentDirectRule/TwoLeft", starbattle); -// TreeNode rootNode = starbattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell1 = board.getCell(1,1); -// cell1.setData(StarBattleCellType.BLACK.value); -// /* -// StarBattleCell cell2 = board.getCell(2,1); -// cell2.setData(StarBattleCellType.BLACK.value); -// StarBattleCell cell3 = board.getCell(1,3); -// cell3.setData(StarBattleCellType.BLACK.value); -// StarBattleCell cell4 = board.getCell(2,3); -// cell4.setData(StarBattleCellType.BLACK.value); -// */ -// -// board.addModifiedData(cell1); -// /* -// board.addModifiedData(cell2); -// board.addModifiedData(cell3); -// board.addModifiedData(cell4); -// */ -// -// Assert.assertNull(RULE.checkRule(transition)); -// System.out.println("General Case is done\n"); -// for (int i = 0; i < board.getHeight(); ++i) { -// for (int j = 0; j < board.getWidth(); ++j) { -// Point point = new Point(j,i); -// if (point.equals(cell1.getLocation())) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); -// } /* -// else { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); -// } */ -// } -// } -// } -// -// @Test -// public void EmptyAdjacentDirectRule_ThreeLeft() -// throws InvalidFileFormatException { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/EmptyAdjacentDirectRule/TwoLeft", starbattle); -// TreeNode rootNode = starbattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell1 = board.getCell(1,1); -// cell1.setData(StarBattleCellType.BLACK.value); -// StarBattleCell cell2 = board.getCell(2,1); -// cell2.setData(StarBattleCellType.BLACK.value); -// -// board.addModifiedData(cell1); -// board.addModifiedData(cell2); -// -// Assert.assertNull(RULE.checkRule(transition)); -// -// for (int i = 0; i < board.getHeight(); ++i) { -// for (int j = 0; j < board.getWidth(); ++j) { -// Point point = new Point(j,i); -// if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); -// } -// else { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); -// } -// } -// } -// } -// -// @Test -// public void EmptyAdjacentDirectRule_ImproperUseFourLeft() throws InvalidFileFormatException { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/EmptyAdjacentDirectRule/ImproperUseFourLeft", starbattle); -// TreeNode rootNode = starbattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell1 = board.getCell(1,1); -// cell1.setData(StarBattleCellType.BLACK.value); -// StarBattleCell cell2 = board.getCell(2,1); -// cell2.setData(StarBattleCellType.BLACK.value); -// StarBattleCell cell3 = board.getCell(1,3); -// cell3.setData(StarBattleCellType.BLACK.value); -// StarBattleCell cell4 = board.getCell(2,3); -// cell4.setData(StarBattleCellType.BLACK.value); -// -// board.addModifiedData(cell1); -// board.addModifiedData(cell2); -// board.addModifiedData(cell3); -// board.addModifiedData(cell4); -// -// Assert.assertNotNull(RULE.checkRule(transition)); -// -// for (int i = 0; i < board.getHeight(); ++i) { -// for (int j = 0; j < board.getWidth(); ++j) { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); -// } -// } -// } -//} +package puzzles.starbattle.rules; + +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +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.EmptyAdjacentDirectRule; +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 EmptyAdjacentDirectRuleTest { + + private static final EmptyAdjacentDirectRule RULE = new EmptyAdjacentDirectRule(); + private static StarBattle starbattle; + + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + starbattle = new StarBattle(); + } + + @Test + public void EmptyAdjacentDirectRule_OneLeft() throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/EmptyAdjacentDirectRule/OneLeft", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(1,1); + cell1.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell2 = board.getCell(2,1); + cell2.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell3 = board.getCell(3,1); + cell3.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell4 = board.getCell(1,3); + cell4.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell5 = board.getCell(2,3); + cell5.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell6 = board.getCell(3,3); + cell6.setData(StarBattleCellType.BLACK.value); + + board.addModifiedData(cell1); + board.addModifiedData(cell2); + board.addModifiedData(cell3); + board.addModifiedData(cell4); + board.addModifiedData(cell5); + board.addModifiedData(cell6); + + Assert.assertNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); ++i) { + for (int j = 0; j < board.getWidth(); ++j) { + Point point = new Point(j,i); + if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) || + point.equals(cell3.getLocation()) || point.equals(cell4.getLocation()) || + point.equals(cell5.getLocation()) || point.equals(cell6.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + } + } + } + + @Test + public void EmptyAdjacentDirectRule_TwoLeft() throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/EmptyAdjacentDirectRule/TwoLeft", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(1,1); + cell1.setData(StarBattleCellType.BLACK.value); + /* + StarBattleCell cell2 = board.getCell(2,1); + cell2.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell3 = board.getCell(1,3); + cell3.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell4 = board.getCell(2,3); + cell4.setData(StarBattleCellType.BLACK.value); + */ + + board.addModifiedData(cell1); + /* + board.addModifiedData(cell2); + board.addModifiedData(cell3); + board.addModifiedData(cell4); + */ + + Assert.assertNull(RULE.checkRule(transition)); + System.out.println("General Case is done\n"); + for (int i = 0; i < board.getHeight(); ++i) { + for (int j = 0; j < board.getWidth(); ++j) { + Point point = new Point(j,i); + if (point.equals(cell1.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } /* + else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } */ + } + } + } + + @Test + public void EmptyAdjacentDirectRule_ThreeLeft() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/EmptyAdjacentDirectRule/TwoLeft", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(1,1); + cell1.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell2 = board.getCell(2,1); + cell2.setData(StarBattleCellType.BLACK.value); + + board.addModifiedData(cell1); + board.addModifiedData(cell2); + + Assert.assertNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); ++i) { + for (int j = 0; j < board.getWidth(); ++j) { + Point point = new Point(j,i); + if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + } + } + } + + @Test + public void EmptyAdjacentDirectRule_ImproperUseFourLeft() throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/EmptyAdjacentDirectRule/ImproperUseFourLeft", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(1,1); + cell1.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell2 = board.getCell(2,1); + cell2.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell3 = board.getCell(1,3); + cell3.setData(StarBattleCellType.BLACK.value); + StarBattleCell cell4 = board.getCell(2,3); + cell4.setData(StarBattleCellType.BLACK.value); + + board.addModifiedData(cell1); + board.addModifiedData(cell2); + board.addModifiedData(cell3); + board.addModifiedData(cell4); + + Assert.assertNotNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); ++i) { + for (int j = 0; j < board.getWidth(); ++j) { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + } + } +} diff --git a/src/test/java/puzzles/starbattle/rules/FinishWithStarsDirectRuleTest.java b/src/test/java/puzzles/starbattle/rules/FinishWithStarsDirectRuleTest.java index c8c125d64..552e3703e 100644 --- a/src/test/java/puzzles/starbattle/rules/FinishWithStarsDirectRuleTest.java +++ b/src/test/java/puzzles/starbattle/rules/FinishWithStarsDirectRuleTest.java @@ -1,209 +1,209 @@ -//package puzzles.starbattle.rules; -// -//import edu.rpi.legup.puzzle.starbattle.rules.FinishWithStarsDirectRule; -//import edu.rpi.legup.model.tree.TreeNode; -//import edu.rpi.legup.model.tree.TreeTransition; -//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.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 FinishWithStarsDirectRuleTest { -// private static final FinishWithStarsDirectRule RULE = new FinishWithStarsDirectRule(); -// private static StarBattle starBattle; -// -// @BeforeClass -// public static void setUp() { -// MockGameBoardFacade.getInstance(); -// starBattle = new StarBattle(); -// } -// -// /* Finish With Stars Direct Rule where star is in the corner and only the row is blacked out */ -// @Test -// public void FinishWithStarsDirectRuleTestCornerRow() -// throws InvalidFileFormatException -// { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/FinishWithStarsDirectRule/CornerRow", starBattle); -// TreeNode rootNode = starBattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell1 = board.getCell(0,0); -// cell1.setData(StarBattleCellType.STAR.value); -// -// board.addModifiedData(cell1); -// -// Assert.assertNull(RULE.checkRule(transition)); -// -// for (int i = 0; i < board.getHeight(); ++i) { -// for (int j = 0; j < board.getWidth(); ++j) { -// Point point = new Point(j,i); -// if (point.equals(cell1.getLocation())) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); -// } -// else { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); -// } -// } -// } -// } -// -// /* Finish With Stars Direct Rule where star is in the corner and only the column is blacked out */ -// @Test -// public void FinishWithStarsDirectRuleTestCornerColumn() -// throws InvalidFileFormatException -// { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/FinishWithStarsDirectRule/CornerColumn", starBattle); -// TreeNode rootNode = starBattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell1 = board.getCell(0,0); -// cell1.setData(StarBattleCellType.STAR.value); -// -// board.addModifiedData(cell1); -// -// Assert.assertNull(RULE.checkRule(transition)); -// -// for (int i = 0; i < board.getHeight(); ++i) { -// for (int j = 0; j < board.getWidth(); ++j) { -// Point point = new Point(j,i); -// if (point.equals(cell1.getLocation())) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); -// } -// else { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); -// } -// } -// } -// } -// -// /* Finish With Stars Direct Rule where star is in the corner and only the column is blacked out */ -// @Test -// public void FinishWithStarsDirectRuleTestCornerRowColumn() -// throws InvalidFileFormatException -// { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/FinishWithStarsDirectRule/CornerRowColumn", starBattle); -// TreeNode rootNode = starBattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell1 = board.getCell(0,0); -// cell1.setData(StarBattleCellType.STAR.value); -// -// board.addModifiedData(cell1); -// -// Assert.assertNull(RULE.checkRule(transition)); -// -// for (int i = 0; i < board.getHeight(); ++i) { -// for (int j = 0; j < board.getWidth(); ++j) { -// Point point = new Point(j,i); -// if (point.equals(cell1.getLocation())) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); -// } -// else { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); -// } -// } -// } -// } -// /* Finish With Stars Direct Rule where star is in the corner and only the column is blacked out */ -// @Test -// public void FinishWithStarsDirectRuleTestRegion() -// throws InvalidFileFormatException -// { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/FinishWithStarsDirectRule/Region", starBattle); -// TreeNode rootNode = starBattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell1 = board.getCell(1,1); -// cell1.setData(StarBattleCellType.STAR.value); -// -// board.addModifiedData(cell1); -// -// Assert.assertNull(RULE.checkRule(transition)); -// -// for (int i = 0; i < board.getHeight(); ++i) { -// for (int j = 0; j < board.getWidth(); ++j) { -// Point point = new Point(j,i); -// if (point.equals(cell1.getLocation())) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); -// } -// else { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); -// } -// } -// } -// } -// /* Finish With Stars Direct Rule where there are two stars in two different mostly blacked out regions */ -// @Test -// public void FinishWithStarsDirectRuleTestDoubleRegion() -// throws InvalidFileFormatException -// { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/FinishWithStarsDirectRule/DoubleRegion", starBattle); -// TreeNode rootNode = starBattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell1 = board.getCell(1,1); -// cell1.setData(StarBattleCellType.STAR.value); -// StarBattleCell cell2 = board.getCell(2,3); -// cell2.setData(StarBattleCellType.STAR.value); -// -// board.addModifiedData(cell1); -// board.addModifiedData(cell2); -// -// Assert.assertNull(RULE.checkRule(transition)); -// -// for (int i = 0; i < board.getHeight(); ++i) { -// for (int j = 0; j < board.getWidth(); ++j) { -// Point point = new Point(j,i); -// if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); -// } -// else { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); -// } -// } -// } -// } -// -// /* Finish With Stars Direct Rule where there are two stars in two different mostly blacked out regions */ -// @Test -// public void FinishWithStarsDirectRuleTestFalse() -// throws InvalidFileFormatException -// { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/FinishWithStarsDirectRule/False", starBattle); -// TreeNode rootNode = starBattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell1 = board.getCell(2,0); -// cell1.setData(StarBattleCellType.STAR.value); -// -// board.addModifiedData(cell1); -// -// Assert.assertNotNull(RULE.checkRule(transition)); -// -// for (int i = 0; i < board.getHeight(); ++i) { -// for (int j = 0; j < board.getWidth(); ++j) { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); -// } -// } -// } -// -//} +package puzzles.starbattle.rules; + +import edu.rpi.legup.puzzle.starbattle.rules.FinishWithStarsDirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +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.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 FinishWithStarsDirectRuleTest { + private static final FinishWithStarsDirectRule RULE = new FinishWithStarsDirectRule(); + private static StarBattle starBattle; + + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + starBattle = new StarBattle(); + } + + /* Finish With Stars Direct Rule where star is in the corner and only the row is blacked out */ + @Test + public void FinishWithStarsDirectRuleTestCornerRow() + throws InvalidFileFormatException + { + TestUtilities.importTestBoard("puzzles/starbattle/rules/FinishWithStarsDirectRule/CornerRow", starBattle); + TreeNode rootNode = starBattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(0,0); + cell1.setData(StarBattleCellType.STAR.value); + + board.addModifiedData(cell1); + + Assert.assertNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); ++i) { + for (int j = 0; j < board.getWidth(); ++j) { + Point point = new Point(j,i); + if (point.equals(cell1.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + } + } + } + + /* Finish With Stars Direct Rule where star is in the corner and only the column is blacked out */ + @Test + public void FinishWithStarsDirectRuleTestCornerColumn() + throws InvalidFileFormatException + { + TestUtilities.importTestBoard("puzzles/starbattle/rules/FinishWithStarsDirectRule/CornerColumn", starBattle); + TreeNode rootNode = starBattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(0,0); + cell1.setData(StarBattleCellType.STAR.value); + + board.addModifiedData(cell1); + + Assert.assertNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); ++i) { + for (int j = 0; j < board.getWidth(); ++j) { + Point point = new Point(j,i); + if (point.equals(cell1.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + } + } + } + + /* Finish With Stars Direct Rule where star is in the corner and only the column is blacked out */ + @Test + public void FinishWithStarsDirectRuleTestCornerRowColumn() + throws InvalidFileFormatException + { + TestUtilities.importTestBoard("puzzles/starbattle/rules/FinishWithStarsDirectRule/CornerRowColumn", starBattle); + TreeNode rootNode = starBattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(0,0); + cell1.setData(StarBattleCellType.STAR.value); + + board.addModifiedData(cell1); + + Assert.assertNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); ++i) { + for (int j = 0; j < board.getWidth(); ++j) { + Point point = new Point(j,i); + if (point.equals(cell1.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + } + } + } + /* Finish With Stars Direct Rule where star is in the corner and only the column is blacked out */ + @Test + public void FinishWithStarsDirectRuleTestRegion() + throws InvalidFileFormatException + { + TestUtilities.importTestBoard("puzzles/starbattle/rules/FinishWithStarsDirectRule/Region", starBattle); + TreeNode rootNode = starBattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(1,1); + cell1.setData(StarBattleCellType.STAR.value); + + board.addModifiedData(cell1); + + Assert.assertNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); ++i) { + for (int j = 0; j < board.getWidth(); ++j) { + Point point = new Point(j,i); + if (point.equals(cell1.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + } + } + } + /* Finish With Stars Direct Rule where there are two stars in two different mostly blacked out regions */ + @Test + public void FinishWithStarsDirectRuleTestDoubleRegion() + throws InvalidFileFormatException + { + TestUtilities.importTestBoard("puzzles/starbattle/rules/FinishWithStarsDirectRule/DoubleRegion", starBattle); + TreeNode rootNode = starBattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(1,1); + cell1.setData(StarBattleCellType.STAR.value); + StarBattleCell cell2 = board.getCell(2,3); + cell2.setData(StarBattleCellType.STAR.value); + + board.addModifiedData(cell1); + board.addModifiedData(cell2); + + Assert.assertNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); ++i) { + for (int j = 0; j < board.getWidth(); ++j) { + Point point = new Point(j,i); + if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + } + } + } + + /* Finish With Stars Direct Rule where there are two stars in two different mostly blacked out regions */ + @Test + public void FinishWithStarsDirectRuleTestFalse() + throws InvalidFileFormatException + { + TestUtilities.importTestBoard("puzzles/starbattle/rules/FinishWithStarsDirectRule/False", starBattle); + TreeNode rootNode = starBattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(2,0); + cell1.setData(StarBattleCellType.STAR.value); + + board.addModifiedData(cell1); + + Assert.assertNotNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); ++i) { + for (int j = 0; j < board.getWidth(); ++j) { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + } + } + +} diff --git a/src/test/java/puzzles/starbattle/rules/RegionsWithinColumnsDirectRuleTest.java b/src/test/java/puzzles/starbattle/rules/RegionsWithinColumnsDirectRuleTest.java index a46e5514c..a45f7455f 100644 --- a/src/test/java/puzzles/starbattle/rules/RegionsWithinColumnsDirectRuleTest.java +++ b/src/test/java/puzzles/starbattle/rules/RegionsWithinColumnsDirectRuleTest.java @@ -1,353 +1,353 @@ -//package puzzles.starbattle.rules; -// -//import edu.rpi.legup.model.tree.TreeNode; -//import edu.rpi.legup.model.tree.TreeTransition; -//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.RegionsWithinColumnsDirectRule; -//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.awt.*; -// -//public class RegionsWithinColumnsDirectRuleTest { -// -// private static final RegionsWithinColumnsDirectRule RULE = new RegionsWithinColumnsDirectRule(); -// private static StarBattle starbattle; -// -// @BeforeClass -// public static void setUp() { -// MockGameBoardFacade.getInstance(); -// starbattle = new StarBattle(); -// } -// -// @Test -// public void RegionsWithinColumnsDirectRule_OneRegionOneCell() -// throws InvalidFileFormatException { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/OneRegionOneCell", starbattle); -// TreeNode rootNode = starbattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell = board.getCell(0,2); -// cell.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell); -// -// Assert.assertNull(RULE.checkRule(transition)); -// -// Point location = new Point(0,2); -// 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(location)) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } else { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } -// } -// } -// } -// -// @Test -// public void RegionsWithinColumnsDirectRule_OneRegionTwoCells() -// throws InvalidFileFormatException { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/OneRegionTwoCells", starbattle); -// TreeNode rootNode = starbattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell1 = board.getCell(0,1); -// cell1.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell1); -// StarBattleCell cell2 = board.getCell(0,2); -// cell2.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell2); -// -// Assert.assertNull(RULE.checkRule(transition)); -// -// Point location1 = new Point(0,1); -// Point location2 = new Point(0,2); -// 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(location1) || point.equals(location2)) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } else { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } -// } -// } -// } -// -// @Test -// public void RegionsWithinColumnsDirectRule_PartialRegionOneCell() -// throws InvalidFileFormatException { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/PartialRegionOneCell", starbattle); -// TreeNode rootNode = starbattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell = board.getCell(0,2); -// cell.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell); -// -// Assert.assertNull(RULE.checkRule(transition)); -// -// Point location = new Point(0,2); -// 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(location)) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } else { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } -// } -// } -// } -// -// @Test -// public void RegionsWithinColumnsDirectRule_TwoRegionsOneCell() -// throws InvalidFileFormatException { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoRegionsOneCell", starbattle); -// TreeNode rootNode = starbattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell = board.getCell(1,3); -// cell.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell); -// -// Assert.assertNull(RULE.checkRule(transition)); -// -// Point location = new Point(1,3); -// 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(location)) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } else { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } -// } -// } -// } -// -// @Test -// public void RegionsWithinColumnsDirectRule_TwoRegionsTwoCells() -// throws InvalidFileFormatException { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoRegionsTwoCells", starbattle); -// TreeNode rootNode = starbattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell1 = board.getCell(1,1); -// cell1.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell1); -// StarBattleCell cell2 = board.getCell(1,3); -// cell2.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell2); -// -// Assert.assertNull(RULE.checkRule(transition)); -// -// Point location1 = new Point(1,1); -// Point location2 = new Point(1,3); -// 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(location1) || point.equals(location2)) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } else { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } -// } -// } -// } -// -// @Test -// public void RegionsWithinColumnsDirectRule_TwoRegionsTwoCells2() -// throws InvalidFileFormatException { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoRegionsTwoCells2", starbattle); -// TreeNode rootNode = starbattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell1 = board.getCell(0,3); -// cell1.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell1); -// StarBattleCell cell2 = board.getCell(1,3); -// cell2.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell2); -// -// Assert.assertNull(RULE.checkRule(transition)); -// -// Point location1 = new Point(0,3); -// Point location2 = new Point(1,3); -// 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(location1) || point.equals(location2)) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } else { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } -// } -// } -// } -// -// @Test -// public void RegionsWithinColumnsDirectRule_TwoRegionsStarOverlap() -// throws InvalidFileFormatException { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoRegionsStarOverlap", starbattle); -// TreeNode rootNode = starbattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell = board.getCell(1,1); -// cell.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell); -// -// Assert.assertNull(RULE.checkRule(transition)); -// -// Point location = new Point(1,1); -// 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(location)) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } else { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } -// } -// } -// } -// -// @Test -// public void RegionsWithinColumnsDirectRule_FalseRegionsWithinColumns1() -// throws InvalidFileFormatException { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/OneRegionOneCell", starbattle); -// TreeNode rootNode = starbattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell = board.getCell(0,2); -// cell.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell); -// StarBattleCell cell2 = board.getCell(1,2); -// cell2.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell2); -// -// Assert.assertNotNull(RULE.checkRule(transition)); -// -// Point location = new Point(0,2); -// 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(location)) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } else { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } -// } -// } -// } -// -// @Test -// public void RegionsWithinColumnsDirectRule_FalseRegionsWithinColumns2() -// throws InvalidFileFormatException { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/OneRegionOneCell", starbattle); -// TreeNode rootNode = starbattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell = board.getCell(0,2); -// cell.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell); -// StarBattleCell cell2 = board.getCell(0,1); -// cell2.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell2); -// -// Assert.assertNotNull(RULE.checkRule(transition)); -// -// Point location = new Point(0,2); -// 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(location)) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } else { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } -// } -// } -// } -// -// @Test -// public void RegionsWithinColumnsDirectRule_FalseRegionsWithinColumns3() -// throws InvalidFileFormatException { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/FalseStarOverlap", starbattle); -// TreeNode rootNode = starbattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell = board.getCell(1,1); -// cell.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell); -// StarBattleCell cell2 = board.getCell(1,3); -// cell2.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell2); -// -// Assert.assertNotNull(RULE.checkRule(transition)); -// -// for (int i = 0; i < board.getHeight(); i++) { -// for (int k = 0; k < board.getWidth(); k++) { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } -// } -// } -// -// @Test -// public void RegionsWithinColumnsDirectRule_FalseRegionsWithinColumns4() -// throws InvalidFileFormatException { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoRegionsTwoCells2", starbattle); -// TreeNode rootNode = starbattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell = board.getCell(0,3); -// cell.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell); -// -// Assert.assertNull(RULE.checkRule(transition)); -// -// Point location = new Point(0,3); -// 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(location)) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } -// else { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } -// } -// } -// } -//} +package puzzles.starbattle.rules; + +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +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.RegionsWithinColumnsDirectRule; +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.awt.*; + +public class RegionsWithinColumnsDirectRuleTest { + + private static final RegionsWithinColumnsDirectRule RULE = new RegionsWithinColumnsDirectRule(); + private static StarBattle starbattle; + + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + starbattle = new StarBattle(); + } + + @Test + public void RegionsWithinColumnsDirectRule_OneRegionOneCell() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/OneRegionOneCell", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell = board.getCell(0,2); + cell.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell); + + Assert.assertNull(RULE.checkRule(transition)); + + Point location = new Point(0,2); + 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(location)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void RegionsWithinColumnsDirectRule_OneRegionTwoCells() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/OneRegionTwoCells", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(0,1); + cell1.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell1); + StarBattleCell cell2 = board.getCell(0,2); + cell2.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell2); + + Assert.assertNull(RULE.checkRule(transition)); + + Point location1 = new Point(0,1); + Point location2 = new Point(0,2); + 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(location1) || point.equals(location2)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void RegionsWithinColumnsDirectRule_PartialRegionOneCell() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/PartialRegionOneCell", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell = board.getCell(0,2); + cell.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell); + + Assert.assertNull(RULE.checkRule(transition)); + + Point location = new Point(0,2); + 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(location)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void RegionsWithinColumnsDirectRule_TwoRegionsOneCell() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoRegionsOneCell", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell = board.getCell(1,3); + cell.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell); + + Assert.assertNull(RULE.checkRule(transition)); + + Point location = new Point(1,3); + 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(location)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void RegionsWithinColumnsDirectRule_TwoRegionsTwoCells() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoRegionsTwoCells", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(1,1); + cell1.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell1); + StarBattleCell cell2 = board.getCell(1,3); + cell2.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell2); + + Assert.assertNull(RULE.checkRule(transition)); + + Point location1 = new Point(1,1); + Point location2 = new Point(1,3); + 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(location1) || point.equals(location2)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void RegionsWithinColumnsDirectRule_TwoRegionsTwoCells2() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoRegionsTwoCells2", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(0,3); + cell1.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell1); + StarBattleCell cell2 = board.getCell(1,3); + cell2.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell2); + + Assert.assertNull(RULE.checkRule(transition)); + + Point location1 = new Point(0,3); + Point location2 = new Point(1,3); + 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(location1) || point.equals(location2)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void RegionsWithinColumnsDirectRule_TwoRegionsStarOverlap() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoRegionsStarOverlap", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell = board.getCell(1,1); + cell.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell); + + Assert.assertNull(RULE.checkRule(transition)); + + Point location = new Point(1,1); + 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(location)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void RegionsWithinColumnsDirectRule_FalseRegionsWithinColumns1() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/OneRegionOneCell", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell = board.getCell(0,2); + cell.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell); + StarBattleCell cell2 = board.getCell(1,2); + cell2.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell2); + + Assert.assertNotNull(RULE.checkRule(transition)); + + Point location = new Point(0,2); + 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(location)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void RegionsWithinColumnsDirectRule_FalseRegionsWithinColumns2() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/OneRegionOneCell", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell = board.getCell(0,2); + cell.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell); + StarBattleCell cell2 = board.getCell(0,1); + cell2.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell2); + + Assert.assertNotNull(RULE.checkRule(transition)); + + Point location = new Point(0,2); + 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(location)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void RegionsWithinColumnsDirectRule_FalseRegionsWithinColumns3() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/FalseStarOverlap", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell = board.getCell(1,1); + cell.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell); + StarBattleCell cell2 = board.getCell(1,3); + cell2.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell2); + + Assert.assertNotNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); i++) { + for (int k = 0; k < board.getWidth(); k++) { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + + @Test + public void RegionsWithinColumnsDirectRule_FalseRegionsWithinColumns4() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoRegionsTwoCells2", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell = board.getCell(0,3); + cell.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell); + + Assert.assertNull(RULE.checkRule(transition)); + + Point location = new Point(0,3); + 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(location)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } +} diff --git a/src/test/java/puzzles/starbattle/rules/RegionsWithinRowsDirectRuleTest.java b/src/test/java/puzzles/starbattle/rules/RegionsWithinRowsDirectRuleTest.java index 49496f18c..3ffaa82fd 100644 --- a/src/test/java/puzzles/starbattle/rules/RegionsWithinRowsDirectRuleTest.java +++ b/src/test/java/puzzles/starbattle/rules/RegionsWithinRowsDirectRuleTest.java @@ -1,258 +1,258 @@ -//package puzzles.starbattle.rules; -// -//import edu.rpi.legup.model.tree.TreeNode; -//import edu.rpi.legup.model.tree.TreeTransition; -//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.RegionsWithinRowsDirectRule; -//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.awt.*; -// -//public class RegionsWithinRowsDirectRuleTest { -// -// private static final RegionsWithinRowsDirectRule RULE = new RegionsWithinRowsDirectRule(); -// private static StarBattle starbattle; -// -// @BeforeClass -// public static void setUp() { -// MockGameBoardFacade.getInstance(); -// starbattle = new StarBattle(); -// } -// -// @Test -// public void RegionsWithinRowsDirectRule_OneRegionOneCell() -// throws InvalidFileFormatException { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinRowsDirectRule/OneRegionOneCell", starbattle); -// TreeNode rootNode = starbattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell = board.getCell(2,0); -// cell.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell); -// -// Assert.assertNull(RULE.checkRule(transition)); -// -// Point location = new Point(2,0); -// 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(location)) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } else { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } -// } -// } -// } -// -// @Test -// public void RegionsWithinRowsDirectRule_PartialRegionOneCell() -// throws InvalidFileFormatException { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinRowsDirectRule/PartialRegionOneCell", starbattle); -// TreeNode rootNode = starbattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell = board.getCell(2,0); -// cell.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell); -// -// Assert.assertNull(RULE.checkRule(transition)); -// -// Point location = new Point(2,0); -// 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(location)) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } else { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } -// } -// } -// } -// -// @Test -// public void RegionsWithinRowsDirectRule_PartialRegionTwo() -// throws InvalidFileFormatException { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinRowsDirectRule/PartialRegionTwoCells", starbattle); -// TreeNode rootNode = starbattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell1 = board.getCell(1,0); -// cell1.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell1); -// StarBattleCell cell2 = board.getCell(2,0); -// cell2.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell2); -// -// Assert.assertNull(RULE.checkRule(transition)); -// -// Point location1 = new Point(1,0); -// Point location2 = new Point(2,0); -// 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(location1) || point.equals(location2)) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } else { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } -// } -// } -// } -// -// @Test -// public void RegionsWithinRowsDirectRule_TwoRegionsOneCell() -// throws InvalidFileFormatException { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinRowsDirectRule/TwoRegionsOneCell", starbattle); -// TreeNode rootNode = starbattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell = board.getCell(3,1); -// cell.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell); -// -// Assert.assertNull(RULE.checkRule(transition)); -// -// Point location = new Point(3,1); -// 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(location)) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } else { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } -// } -// } -// } -// -// @Test -// public void RegionsWithinRowsDirectRule_StarOverlap() -// throws InvalidFileFormatException { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinRowsDirectRule/StarOverlap", starbattle); -// TreeNode rootNode = starbattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell = board.getCell(3,1); -// cell.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell); -// -// Assert.assertNull(RULE.checkRule(transition)); -// -// Point location = new Point(3,1); -// 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(location)) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } else { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } -// } -// } -// } -// -// @Test -// public void RegionsWithinRowsDirectRule_FalseRegionsWithinRows1() -// throws InvalidFileFormatException { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinRowsDirectRule/OneRegionOneCell", starbattle); -// TreeNode rootNode = starbattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell1 = board.getCell(2,0); -// cell1.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell1); -// StarBattleCell cell2 = board.getCell(2,1); -// cell2.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell2); -// -// Assert.assertNotNull(RULE.checkRule(transition)); -// -// Point location = new Point(2,0); -// 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(location)) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } else { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } -// } -// } -// } -// -// @Test -// public void RegionsWithinRowsDirectRule_FalseRegionsWithinRows2() -// throws InvalidFileFormatException { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinRowsDirectRule/OneRegionOneCell", starbattle); -// TreeNode rootNode = starbattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell1 = board.getCell(2,0); -// cell1.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell1); -// StarBattleCell cell2 = board.getCell(1,0); -// cell2.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell2); -// -// Assert.assertNotNull(RULE.checkRule(transition)); -// -// Point location = new Point(2,0); -// 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(location)) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } else { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } -// } -// } -// } -// -// @Test -// public void RegionsWithinRowsDirectRule_FalseStarOverlap() -// throws InvalidFileFormatException { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinRowsDirectRule/FalseStarOverlap", starbattle); -// TreeNode rootNode = starbattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell = board.getCell(3,1); -// cell.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell); -// -// Assert.assertNotNull(RULE.checkRule(transition)); -// -// for (int i = 0; i < board.getHeight(); i++) { -// for (int k = 0; k < board.getWidth(); k++) { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } -// } -// } -// -//} +package puzzles.starbattle.rules; + +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +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.RegionsWithinRowsDirectRule; +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.awt.*; + +public class RegionsWithinRowsDirectRuleTest { + + private static final RegionsWithinRowsDirectRule RULE = new RegionsWithinRowsDirectRule(); + private static StarBattle starbattle; + + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + starbattle = new StarBattle(); + } + + @Test + public void RegionsWithinRowsDirectRule_OneRegionOneCell() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinRowsDirectRule/OneRegionOneCell", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell = board.getCell(2,0); + cell.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell); + + Assert.assertNull(RULE.checkRule(transition)); + + Point location = new Point(2,0); + 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(location)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void RegionsWithinRowsDirectRule_PartialRegionOneCell() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinRowsDirectRule/PartialRegionOneCell", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell = board.getCell(2,0); + cell.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell); + + Assert.assertNull(RULE.checkRule(transition)); + + Point location = new Point(2,0); + 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(location)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void RegionsWithinRowsDirectRule_PartialRegionTwo() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinRowsDirectRule/PartialRegionTwoCells", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(1,0); + cell1.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell1); + StarBattleCell cell2 = board.getCell(2,0); + cell2.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell2); + + Assert.assertNull(RULE.checkRule(transition)); + + Point location1 = new Point(1,0); + Point location2 = new Point(2,0); + 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(location1) || point.equals(location2)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void RegionsWithinRowsDirectRule_TwoRegionsOneCell() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinRowsDirectRule/TwoRegionsOneCell", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell = board.getCell(3,1); + cell.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell); + + Assert.assertNull(RULE.checkRule(transition)); + + Point location = new Point(3,1); + 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(location)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void RegionsWithinRowsDirectRule_StarOverlap() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinRowsDirectRule/StarOverlap", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell = board.getCell(3,1); + cell.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell); + + Assert.assertNull(RULE.checkRule(transition)); + + Point location = new Point(3,1); + 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(location)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void RegionsWithinRowsDirectRule_FalseRegionsWithinRows1() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinRowsDirectRule/OneRegionOneCell", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(2,0); + cell1.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell1); + StarBattleCell cell2 = board.getCell(2,1); + cell2.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell2); + + Assert.assertNotNull(RULE.checkRule(transition)); + + Point location = new Point(2,0); + 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(location)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void RegionsWithinRowsDirectRule_FalseRegionsWithinRows2() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinRowsDirectRule/OneRegionOneCell", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(2,0); + cell1.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell1); + StarBattleCell cell2 = board.getCell(1,0); + cell2.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell2); + + Assert.assertNotNull(RULE.checkRule(transition)); + + Point location = new Point(2,0); + 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(location)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void RegionsWithinRowsDirectRule_FalseStarOverlap() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/RegionsWithinRowsDirectRule/FalseStarOverlap", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell = board.getCell(3,1); + cell.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell); + + Assert.assertNotNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); i++) { + for (int k = 0; k < board.getWidth(); k++) { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + +} diff --git a/src/test/java/puzzles/starbattle/rules/StarOrEmptyCaseRuleTest.java b/src/test/java/puzzles/starbattle/rules/StarOrEmptyCaseRuleTest.java index dc4dc4f3e..e1f9cb990 100644 --- a/src/test/java/puzzles/starbattle/rules/StarOrEmptyCaseRuleTest.java +++ b/src/test/java/puzzles/starbattle/rules/StarOrEmptyCaseRuleTest.java @@ -1,68 +1,68 @@ -//package puzzles.starbattle.rules; -// -//import edu.rpi.legup.model.gameboard.Board; -//import edu.rpi.legup.model.tree.TreeNode; -//import edu.rpi.legup.model.tree.TreeTransition; -//import edu.rpi.legup.puzzle.nurikabe.NurikabeType; -//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.StarOrEmptyCaseRule; -//import edu.rpi.legup.save.InvalidFileFormatException; -//import java.awt.*; -//import java.util.ArrayList; -//import legup.MockGameBoardFacade; -//import legup.TestUtilities; -//import org.junit.Assert; -//import org.junit.BeforeClass; -//import org.junit.Test; -// -//public class StarOrEmptyCaseRuleTest { -// -// private static final StarOrEmptyCaseRule RULE = new StarOrEmptyCaseRule(); -// private static StarBattle starBattle; -// -// @BeforeClass -// public static void setUp() { -// MockGameBoardFacade.getInstance(); -// starBattle = new StarBattle(); -// } -// -// @Test -// public void StarOrEmptyCaseRuleTest_SimpleStarOrEmpty() -// throws InvalidFileFormatException { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/StarOrEmptyCaseRule/SimpleStarOrEmpty", starBattle); -// TreeNode rootNode = starBattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell = board.getCell(0,0); -// ArrayList cases = RULE.getCases(board, cell); -// -// StarBattleBoard caseBoard1 = (StarBattleBoard) cases.get(0); -// StarBattleBoard caseBoard2 = (StarBattleBoard) cases.get(1); -// StarBattleCellType board1Type = caseBoard1.getCell(0, 0).getType(); -// StarBattleCellType board2Type = caseBoard2.getCell(0, 0).getType(); -// -// Assert.assertTrue( -// (board1Type.equals(StarBattleCellType.BLACK) || board1Type.equals(StarBattleCellType.STAR)) -// && (board2Type.equals(StarBattleCellType.BLACK) -// || board2Type.equals(StarBattleCellType.STAR))); -// Assert.assertFalse(board1Type.equals(board2Type)); -// Assert.assertEquals(caseBoard1.getHeight(), caseBoard2.getHeight(), board.getHeight()); -// Assert.assertEquals(caseBoard1.getWidth(), caseBoard2.getWidth(), board.getWidth()); -// -// for (int i = 0; i < caseBoard1.getHeight(); i++) { -// for (int k = 0; k < caseBoard1.getWidth(); k++) { -// Point point = new Point(k, i); -// if (point.equals(caseBoard1.getCell(k, i).getLocation())) { -// continue; -// } -// Assert.assertTrue(caseBoard1.getCell(k, i).equals(caseBoard2.getCell(k, i))); -// } -// } -// } -// -//} +package puzzles.starbattle.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.nurikabe.NurikabeType; +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.StarOrEmptyCaseRule; +import edu.rpi.legup.save.InvalidFileFormatException; +import java.awt.*; +import java.util.ArrayList; +import legup.MockGameBoardFacade; +import legup.TestUtilities; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class StarOrEmptyCaseRuleTest { + + private static final StarOrEmptyCaseRule RULE = new StarOrEmptyCaseRule(); + private static StarBattle starBattle; + + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + starBattle = new StarBattle(); + } + + @Test + public void StarOrEmptyCaseRuleTest_SimpleStarOrEmpty() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/StarOrEmptyCaseRule/SimpleStarOrEmpty", starBattle); + TreeNode rootNode = starBattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell = board.getCell(0,0); + ArrayList cases = RULE.getCases(board, cell); + + StarBattleBoard caseBoard1 = (StarBattleBoard) cases.get(0); + StarBattleBoard caseBoard2 = (StarBattleBoard) cases.get(1); + StarBattleCellType board1Type = caseBoard1.getCell(0, 0).getType(); + StarBattleCellType board2Type = caseBoard2.getCell(0, 0).getType(); + + Assert.assertTrue( + (board1Type.equals(StarBattleCellType.BLACK) || board1Type.equals(StarBattleCellType.STAR)) + && (board2Type.equals(StarBattleCellType.BLACK) + || board2Type.equals(StarBattleCellType.STAR))); + Assert.assertFalse(board1Type.equals(board2Type)); + Assert.assertEquals(caseBoard1.getHeight(), caseBoard2.getHeight(), board.getHeight()); + Assert.assertEquals(caseBoard1.getWidth(), caseBoard2.getWidth(), board.getWidth()); + + for (int i = 0; i < caseBoard1.getHeight(); i++) { + for (int k = 0; k < caseBoard1.getWidth(); k++) { + Point point = new Point(k, i); + if (point.equals(caseBoard1.getCell(k, i).getLocation())) { + continue; + } + Assert.assertTrue(caseBoard1.getCell(k, i).equals(caseBoard2.getCell(k, i))); + } + } + } + +} diff --git a/src/test/java/puzzles/starbattle/rules/SurroundStarDirectRuleTest.java b/src/test/java/puzzles/starbattle/rules/SurroundStarDirectRuleTest.java index 738794a3b..db55d0f65 100644 --- a/src/test/java/puzzles/starbattle/rules/SurroundStarDirectRuleTest.java +++ b/src/test/java/puzzles/starbattle/rules/SurroundStarDirectRuleTest.java @@ -1,173 +1,173 @@ -//package puzzles.starbattle.rules; -// -//import edu.rpi.legup.model.tree.TreeNode; -//import edu.rpi.legup.model.tree.TreeTransition; -//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.SurroundStarDirectRule; -//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 SurroundStarDirectRuleTest { -// -// private static final SurroundStarDirectRule RULE = new SurroundStarDirectRule(); -// private static StarBattle starbattle; -// -// @BeforeClass -// public static void setUp() { -// MockGameBoardFacade.getInstance(); -// starbattle = new StarBattle(); -// } -// -// @Test -// public void SurroundStarDirectRule_CenterStarOneTile() throws InvalidFileFormatException { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/SurroundStarDirectRule/CenterStar", starbattle); -// TreeNode rootNode = starbattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell = board.getCell(0,1); -// cell.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell); -// -// Assert.assertNull(RULE.checkRule(transition)); -// -// Point location = new Point(0, 1); -// 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(location)) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } else { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } -// } -// } -// } -// -// @Test -// public void SurroundStarDirectRule_CenterStarOneTileDiagonal() throws InvalidFileFormatException { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/SurroundStarDirectRule/CenterStar", starbattle); -// TreeNode rootNode = starbattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell = board.getCell(0,0); -// cell.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell); -// -// Assert.assertNull(RULE.checkRule(transition)); -// -// Point location = new Point(0, 0); -// 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(location)) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } else { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } -// } -// } -// } -// -// @Test -// public void SurroundStarDirectRule_CenterStarAllTiles() -// throws InvalidFileFormatException { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/SurroundStarDirectRule/CenterStar", starbattle); -// TreeNode rootNode = starbattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// for (int i = 0; i < board.getWidth(); i++) { -// for (int j = 0; j < board.getHeight(); j++) { -// if (i != 1 || j != 1) { -// StarBattleCell cell = board.getCell(i,j); -// cell.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell); -// } -// } -// } -// -// Assert.assertNull(RULE.checkRule(transition)); -// -// Point location = new Point(1, 1); -// 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(location)) { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } else { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } -// } -// } -// } -// -// @Test -// public void SurroundStarDirectRule_CornerStar() throws InvalidFileFormatException { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/SurroundStarDirectRule/CornerStar", starbattle); -// TreeNode rootNode = starbattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell1 = board.getCell(0,1); -// cell1.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell1); -// StarBattleCell cell2 = board.getCell(1,0); -// cell2.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell2); -// StarBattleCell cell3 = board.getCell(1,1); -// cell3.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell3); -// -// Assert.assertNull(RULE.checkRule(transition)); -// -// Point location1 = new Point(0, 1); -// Point location2 = new Point(1,0); -// Point location3 = new Point(1,1); -// 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(location1) || point.equals(location2) || point.equals(location3)) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } else { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } -// } -// } -// } -// -// @Test -// public void SurroundStarDirectRule_FalseSurroundStar() -// throws InvalidFileFormatException { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/SurroundStarDirectRule/CornerStar", starbattle); -// TreeNode rootNode = starbattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell = board.getCell(2,0); -// cell.setData(StarBattleCellType.BLACK.value); -// board.addModifiedData(cell); -// -// Assert.assertNotNull(RULE.checkRule(transition)); -// -// for (int i = 0; i < board.getHeight(); i++) { -// for (int k = 0; k < board.getWidth(); k++) { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); -// } -// } -// } -//} +package puzzles.starbattle.rules; + +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +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.SurroundStarDirectRule; +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 SurroundStarDirectRuleTest { + + private static final SurroundStarDirectRule RULE = new SurroundStarDirectRule(); + private static StarBattle starbattle; + + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + starbattle = new StarBattle(); + } + + @Test + public void SurroundStarDirectRule_CenterStarOneTile() throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/SurroundStarDirectRule/CenterStar", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell = board.getCell(0,1); + cell.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell); + + Assert.assertNull(RULE.checkRule(transition)); + + Point location = new Point(0, 1); + 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(location)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void SurroundStarDirectRule_CenterStarOneTileDiagonal() throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/SurroundStarDirectRule/CenterStar", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell = board.getCell(0,0); + cell.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell); + + Assert.assertNull(RULE.checkRule(transition)); + + Point location = new Point(0, 0); + 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(location)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void SurroundStarDirectRule_CenterStarAllTiles() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/SurroundStarDirectRule/CenterStar", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + for (int i = 0; i < board.getWidth(); i++) { + for (int j = 0; j < board.getHeight(); j++) { + if (i != 1 || j != 1) { + StarBattleCell cell = board.getCell(i,j); + cell.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell); + } + } + } + + Assert.assertNull(RULE.checkRule(transition)); + + Point location = new Point(1, 1); + 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(location)) { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void SurroundStarDirectRule_CornerStar() throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/SurroundStarDirectRule/CornerStar", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(0,1); + cell1.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell1); + StarBattleCell cell2 = board.getCell(1,0); + cell2.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell2); + StarBattleCell cell3 = board.getCell(1,1); + cell3.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell3); + + Assert.assertNull(RULE.checkRule(transition)); + + Point location1 = new Point(0, 1); + Point location2 = new Point(1,0); + Point location3 = new Point(1,1); + 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(location1) || point.equals(location2) || point.equals(location3)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + @Test + public void SurroundStarDirectRule_FalseSurroundStar() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/SurroundStarDirectRule/CornerStar", starbattle); + TreeNode rootNode = starbattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell = board.getCell(2,0); + cell.setData(StarBattleCellType.BLACK.value); + board.addModifiedData(cell); + + Assert.assertNotNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); i++) { + for (int k = 0; k < board.getWidth(); k++) { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } +} diff --git a/src/test/java/puzzles/starbattle/rules/TooFewStarsContradictionRuleTest.java b/src/test/java/puzzles/starbattle/rules/TooFewStarsContradictionRuleTest.java index 71d556603..2c90c6fb2 100644 --- a/src/test/java/puzzles/starbattle/rules/TooFewStarsContradictionRuleTest.java +++ b/src/test/java/puzzles/starbattle/rules/TooFewStarsContradictionRuleTest.java @@ -1,205 +1,205 @@ -//package puzzles.starbattle.rules; -// -//import edu.rpi.legup.puzzle.starbattle.rules.ClashingOrbitContradictionRule; -//import edu.rpi.legup.model.tree.TreeNode; -//import edu.rpi.legup.model.tree.TreeTransition; -//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.TooFewStarsContradictionRule; -//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 TooFewStarsContradictionRuleTest { -// private static final TooFewStarsContradictionRule RULE = new TooFewStarsContradictionRule(); -// private static StarBattle starBattle; -// -// @BeforeClass -// public static void setUp() { -// MockGameBoardFacade.getInstance(); -// starBattle = new StarBattle(); -// } -// -// /*Too few stars in column */ -// @Test -// public void TooFewStarsContradictionRule_Column() -// throws InvalidFileFormatException { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/TooFewStarsContradictionRule/Column", starBattle); -// TreeNode rootNode = starBattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell1 = board.getCell(0,0); -// StarBattleCell cell2 = board.getCell(0,1); -// StarBattleCell cell3 = board.getCell(0,2); -// StarBattleCell cell4 = board.getCell(0,3); -// -// Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); -// for (int i = 0; i < board.getHeight(); ++i) { -// for (int j = 0; j < board.getWidth(); ++j) { -// Point point = new Point(j,i); -// if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) || -// point.equals(cell3.getLocation()) || point.equals(cell4.getLocation())) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); -// } -// else { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); -// } -// } -// } -// -// } -// -// /*Too few stars in row*/ -// @Test -// public void TooFewStarsContradictionRule_Row() -// throws InvalidFileFormatException { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/TooFewStarsContradictionRule/Row", starBattle); -// TreeNode rootNode = starBattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell1 = board.getCell(0,0); -// StarBattleCell cell2 = board.getCell(1,0); -// StarBattleCell cell3 = board.getCell(2,0); -// StarBattleCell cell4 = board.getCell(3,0); -// -// Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); -// for (int i = 0; i < board.getHeight(); ++i) { -// for (int j = 0; j < board.getWidth(); ++j) { -// Point point = new Point(j,i); -// if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) || -// point.equals(cell3.getLocation()) || point.equals(cell4.getLocation())) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); -// } -// else { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); -// } -// } -// } -// } -// -// /*Too few stars in region*/ -// @Test -// public void TooFewStarsContradictionRule_Region() -// throws InvalidFileFormatException { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/TooFewStarsContradictionRule/Region", starBattle); -// TreeNode rootNode = starBattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell1 = board.getCell(0,0); -// StarBattleCell cell2 = board.getCell(0,1); -// StarBattleCell cell3 = board.getCell(1,0); -// StarBattleCell cell4 = board.getCell(1,1); -// -// Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); -// for (int i = 0; i < board.getHeight(); ++i) { -// for (int j = 0; j < board.getWidth(); ++j) { -// Point point = new Point(j,i); -// if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) || -// point.equals(cell3.getLocation()) || point.equals(cell4.getLocation())) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); -// } -// else { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); -// } -// } -// } -// } -// -// /*False contradiction*/ -// @Test -// public void TooFewStarsContradictionRule_FalseContradiction() -// throws InvalidFileFormatException { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/TooFewStarsContradictionRule/FalseContradiction", starBattle); -// TreeNode rootNode = starBattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// -// Assert.assertNotNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); -// for (int i = 0; i < board.getHeight(); ++i) { -// for (int j = 0; j < board.getWidth(); ++j) { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); -// } -// } -// } -// -// @Test -// public void TooFewStarsContradictionRule_NotEnoughSpace() -// throws InvalidFileFormatException { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/TooFewStarsContradictionRule/NotEnoughSpace", starBattle); -// TreeNode rootNode = starBattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// -// Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); -// for (int i = 0; i < board.getHeight(); ++i) { -// for (int j = 0; j < board.getWidth(); ++j) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); -// } -// } -// } -// -// @Test -// public void TooFewStarsContradictionRule_TwoStarColumn() -// throws InvalidFileFormatException { -// -// TestUtilities.importTestBoard("puzzles/starbattle/rules/TooFewStarsContradictionRule/TwoStarColumn", starBattle); -// TreeNode rootNode = starBattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell1 = board.getCell(0,0); -// StarBattleCell cell2 = board.getCell(0,1); -// StarBattleCell cell3 = board.getCell(0,2); -// StarBattleCell cell4 = board.getCell(0,3); -// -// Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); -// for (int i = 0; i < board.getHeight(); ++i) { -// for (int j = 0; j < board.getWidth(); ++j) { -// Point point = new Point(j,i); -// if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) || -// point.equals(cell3.getLocation()) || point.equals(cell4.getLocation())) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); -// } -// else { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); -// } -// } -// } -// } -// -// @Test -// public void TooFewStarsContradictionRule_TwoStarFalseContradiction() -// throws InvalidFileFormatException { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/TooFewStarsContradictionRule/TwoStarFalseContradiction", starBattle); -// TreeNode rootNode = starBattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// -// Assert.assertNotNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); -// for (int i = 0; i < board.getHeight(); ++i) { -// for (int j = 0; j < board.getWidth(); ++j) { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); -// } -// } -// } -// -//} +package puzzles.starbattle.rules; + +import edu.rpi.legup.puzzle.starbattle.rules.ClashingOrbitContradictionRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +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.TooFewStarsContradictionRule; +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 TooFewStarsContradictionRuleTest { + private static final TooFewStarsContradictionRule RULE = new TooFewStarsContradictionRule(); + private static StarBattle starBattle; + + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + starBattle = new StarBattle(); + } + + /*Too few stars in column */ + @Test + public void TooFewStarsContradictionRule_Column() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/TooFewStarsContradictionRule/Column", starBattle); + TreeNode rootNode = starBattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(0,0); + StarBattleCell cell2 = board.getCell(0,1); + StarBattleCell cell3 = board.getCell(0,2); + StarBattleCell cell4 = board.getCell(0,3); + + Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); + for (int i = 0; i < board.getHeight(); ++i) { + for (int j = 0; j < board.getWidth(); ++j) { + Point point = new Point(j,i); + if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) || + point.equals(cell3.getLocation()) || point.equals(cell4.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + } + } + + } + + /*Too few stars in row*/ + @Test + public void TooFewStarsContradictionRule_Row() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/TooFewStarsContradictionRule/Row", starBattle); + TreeNode rootNode = starBattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(0,0); + StarBattleCell cell2 = board.getCell(1,0); + StarBattleCell cell3 = board.getCell(2,0); + StarBattleCell cell4 = board.getCell(3,0); + + Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); + for (int i = 0; i < board.getHeight(); ++i) { + for (int j = 0; j < board.getWidth(); ++j) { + Point point = new Point(j,i); + if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) || + point.equals(cell3.getLocation()) || point.equals(cell4.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + } + } + } + + /*Too few stars in region*/ + @Test + public void TooFewStarsContradictionRule_Region() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/TooFewStarsContradictionRule/Region", starBattle); + TreeNode rootNode = starBattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(0,0); + StarBattleCell cell2 = board.getCell(0,1); + StarBattleCell cell3 = board.getCell(1,0); + StarBattleCell cell4 = board.getCell(1,1); + + Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); + for (int i = 0; i < board.getHeight(); ++i) { + for (int j = 0; j < board.getWidth(); ++j) { + Point point = new Point(j,i); + if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) || + point.equals(cell3.getLocation()) || point.equals(cell4.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + } + } + } + + /*False contradiction*/ + @Test + public void TooFewStarsContradictionRule_FalseContradiction() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/TooFewStarsContradictionRule/FalseContradiction", starBattle); + TreeNode rootNode = starBattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + + Assert.assertNotNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); + for (int i = 0; i < board.getHeight(); ++i) { + for (int j = 0; j < board.getWidth(); ++j) { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + } + } + + @Test + public void TooFewStarsContradictionRule_NotEnoughSpace() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/TooFewStarsContradictionRule/NotEnoughSpace", starBattle); + TreeNode rootNode = starBattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + + Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); + for (int i = 0; i < board.getHeight(); ++i) { + for (int j = 0; j < board.getWidth(); ++j) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + } + } + + @Test + public void TooFewStarsContradictionRule_TwoStarColumn() + throws InvalidFileFormatException { + + TestUtilities.importTestBoard("puzzles/starbattle/rules/TooFewStarsContradictionRule/TwoStarColumn", starBattle); + TreeNode rootNode = starBattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(0,0); + StarBattleCell cell2 = board.getCell(0,1); + StarBattleCell cell3 = board.getCell(0,2); + StarBattleCell cell4 = board.getCell(0,3); + + Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); + for (int i = 0; i < board.getHeight(); ++i) { + for (int j = 0; j < board.getWidth(); ++j) { + Point point = new Point(j,i); + if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) || + point.equals(cell3.getLocation()) || point.equals(cell4.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + } + } + } + + @Test + public void TooFewStarsContradictionRule_TwoStarFalseContradiction() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/starbattle/rules/TooFewStarsContradictionRule/TwoStarFalseContradiction", starBattle); + TreeNode rootNode = starBattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + + Assert.assertNotNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); + for (int i = 0; i < board.getHeight(); ++i) { + for (int j = 0; j < board.getWidth(); ++j) { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + } + } + +} diff --git a/src/test/java/puzzles/starbattle/rules/TooManyStarsContradictionRuleTests.java b/src/test/java/puzzles/starbattle/rules/TooManyStarsContradictionRuleTests.java index 385652fae..3424bbaac 100644 --- a/src/test/java/puzzles/starbattle/rules/TooManyStarsContradictionRuleTests.java +++ b/src/test/java/puzzles/starbattle/rules/TooManyStarsContradictionRuleTests.java @@ -1,137 +1,137 @@ -//package puzzles.starbattle.rules; -// -//import edu.rpi.legup.puzzle.starbattle.rules.TooManyStarsContradictionRule; -//import edu.rpi.legup.model.tree.TreeNode; -//import edu.rpi.legup.model.tree.TreeTransition; -//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.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 TooManyStarsContradictionRuleTests { -// private static final TooManyStarsContradictionRule RULE = new TooManyStarsContradictionRule(); -// private static StarBattle starBattle; -// -// @BeforeClass -// public static void setUp() { -// MockGameBoardFacade.getInstance(); -// starBattle = new StarBattle(); -// } -// -// /* Tests the Too Many Stars contradiction rule where a region has -// more stars than the puzzle number */ -// @Test -// public void TooManyStarsContradictionRule_RegionOverloaded() -// throws InvalidFileFormatException -// { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/TooManyStarsContradictionRule/RegionOverloaded", starBattle); -// TreeNode rootNode = starBattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell1 = board.getCell(2,1); -// StarBattleCell cell2 = board.getCell(0,2); -// -// Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); -// -// for (int i = 0; i < board.getHeight(); ++i) { -// for (int j = 0; j < board.getWidth(); ++j) { -// Point point = new Point(j,i); -// if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); -// } -// else { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); -// } -// } -// } -// } -// -// /* Tests the Too Many Stars contradiction rule where a column has -// more stars than the puzzle number */ -// @Test -// public void TooManyStarsContradictionRule_ColumnOverloaded() -// throws InvalidFileFormatException -// { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/TooManyStarsContradictionRule/ColumnOverloaded", starBattle); -// TreeNode rootNode = starBattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell1 = board.getCell(0,0); -// StarBattleCell cell2 = board.getCell(0,3); -// -// Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); -// -// for (int i = 0; i < board.getHeight(); ++i) { -// for (int j = 0; j < board.getWidth(); ++j) { -// Point point = new Point(j,i); -// if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); -// } -// else { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); -// } -// } -// } -// } -// /* Tests the Too Many Stars contradiction rule where a row has -// more stars than the puzzle number */ -// @Test -// public void TooManyStarsContradictionRule_RowOverloaded() -// throws InvalidFileFormatException -// { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/TooManyStarsContradictionRule/RowOverloaded", starBattle); -// TreeNode rootNode = starBattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// StarBattleCell cell1 = board.getCell(0,0); -// StarBattleCell cell2 = board.getCell(3,0); -// -// Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); -// -// for (int i = 0; i < board.getHeight(); ++i) { -// for (int j = 0; j < board.getWidth(); ++j) { -// Point point = new Point(j,i); -// if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) { -// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); -// } -// else { -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); -// } -// } -// } -// } -// /*Tests the Too Many Stars contradiction rule for a false contradiction. */ -// @Test -// public void TooManyStarsContradictionRule_FalseContradiction() -// throws InvalidFileFormatException -// { -// TestUtilities.importTestBoard("puzzles/starbattle/rules/TooManyStarsContradictionRule/Correct", starBattle); -// TreeNode rootNode = starBattle.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); -// -// Assert.assertNotNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); -// -// for (int i = 0; i < board.getHeight(); ++i) { -// for (int j = 0; j < board.getWidth(); ++j) { -// Point point = new Point(j,i); -// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); -// } -// } -// } -//} +package puzzles.starbattle.rules; + +import edu.rpi.legup.puzzle.starbattle.rules.TooManyStarsContradictionRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +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.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 TooManyStarsContradictionRuleTests { + private static final TooManyStarsContradictionRule RULE = new TooManyStarsContradictionRule(); + private static StarBattle starBattle; + + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + starBattle = new StarBattle(); + } + + /* Tests the Too Many Stars contradiction rule where a region has + more stars than the puzzle number */ + @Test + public void TooManyStarsContradictionRule_RegionOverloaded() + throws InvalidFileFormatException + { + TestUtilities.importTestBoard("puzzles/starbattle/rules/TooManyStarsContradictionRule/RegionOverloaded", starBattle); + TreeNode rootNode = starBattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(2,1); + StarBattleCell cell2 = board.getCell(0,2); + + Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); + + for (int i = 0; i < board.getHeight(); ++i) { + for (int j = 0; j < board.getWidth(); ++j) { + Point point = new Point(j,i); + if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + } + } + } + + /* Tests the Too Many Stars contradiction rule where a column has + more stars than the puzzle number */ + @Test + public void TooManyStarsContradictionRule_ColumnOverloaded() + throws InvalidFileFormatException + { + TestUtilities.importTestBoard("puzzles/starbattle/rules/TooManyStarsContradictionRule/ColumnOverloaded", starBattle); + TreeNode rootNode = starBattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(0,0); + StarBattleCell cell2 = board.getCell(0,3); + + Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); + + for (int i = 0; i < board.getHeight(); ++i) { + for (int j = 0; j < board.getWidth(); ++j) { + Point point = new Point(j,i); + if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + } + } + } + /* Tests the Too Many Stars contradiction rule where a row has + more stars than the puzzle number */ + @Test + public void TooManyStarsContradictionRule_RowOverloaded() + throws InvalidFileFormatException + { + TestUtilities.importTestBoard("puzzles/starbattle/rules/TooManyStarsContradictionRule/RowOverloaded", starBattle); + TreeNode rootNode = starBattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell1 = board.getCell(0,0); + StarBattleCell cell2 = board.getCell(3,0); + + Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); + + for (int i = 0; i < board.getHeight(); ++i) { + for (int j = 0; j < board.getWidth(); ++j) { + Point point = new Point(j,i); + if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + } + } + } + /*Tests the Too Many Stars contradiction rule for a false contradiction. */ + @Test + public void TooManyStarsContradictionRule_FalseContradiction() + throws InvalidFileFormatException + { + TestUtilities.importTestBoard("puzzles/starbattle/rules/TooManyStarsContradictionRule/Correct", starBattle); + TreeNode rootNode = starBattle.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + + Assert.assertNotNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); + + for (int i = 0; i < board.getHeight(); ++i) { + for (int j = 0; j < board.getWidth(); ++j) { + Point point = new Point(j,i); + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); + } + } + } +} From e51bcd3ea0acb803ed6cd0c1b669f88e444636a6 Mon Sep 17 00:00:00 2001 From: Zachary Bonagura Date: Mon, 19 Aug 2024 14:05:33 -0400 Subject: [PATCH 258/258] Revert "Merge branch 'star-battle'" This reverts commit a89e85b8ddb3b8af9e4eee519e1b67016a8c2b31, reversing changes made to 7b45547a620f33bccaf7f44f832b50ecec68bf1d. --- .../10x10 Star Battle 2star Normal1.xml | 148 -------- .../5x5 Star Battle 1 star Normal/050101 | 53 --- ...1 visualized (DO NOT OPEN AS A PUZZLE).png | Bin 13377 -> 0 bytes .../5x5 Star Battle 1 star Normal/050102 | 53 --- ...1 visualized (DO NOT OPEN AS A PUZZLE).png | Bin 14302 -> 0 bytes .../puzzle/starbattle/StarBattleBoard.java | 11 - .../rules/ColumnsWithinRegionsDirectRule.java | 88 ++--- .../rules/ColumnsWithinRowsDirectRule.java | 84 ++--- .../rules/EmptyAdjacentDirectRule.java | 95 ----- .../rules/RegionsWithinColumnsDirectRule.java | 6 +- .../rules/RegionsWithinRowsDirectRule.java | 6 +- .../rules/RowsWithinColumnsDirectRule.java | 8 +- .../rules/RowsWithinRegionsDirectRule.java | 87 +---- .../rules/TooFewStarsContradictionRule.java | 6 +- .../rules/starbattle_reference_sheet.txt | 20 - .../rules/EmptyAdjacentDirectRule.png | Bin 1822 -> 0 bytes .../rules/BlackoutDirectRuleTest.java | 292 ++++----------- .../ClashingOrbitContradictionRuleTest.java | 137 ------- .../ColumnsWithinRegionsDirectRuleTest.java | 324 ---------------- .../ColumnsWithinRowsDirectRuleTest.java | 244 ------------ .../rules/EmptyAdjacentDirectRuleTest.java | 177 --------- .../rules/FinishWithStarsDirectRuleTest.java | 209 ----------- .../RegionsWithinColumnsDirectRuleTest.java | 353 ------------------ .../RegionsWithinRowsDirectRuleTest.java | 258 ------------- .../rules/StarOrEmptyCaseRuleTest.java | 68 ---- .../rules/SurroundStarDirectRuleTest.java | 173 --------- .../TooFewStarsContradictionRuleTest.java | 205 ---------- .../TooManyStarsContradictionRuleTests.java | 137 ------- .../Blackout visualized.png | Bin 14116 -> 0 bytes .../rules/BlackoutDirectRule/Corner | 41 -- .../starbattle/rules/BlackoutDirectRule/Edge | 41 -- .../rules/BlackoutDirectRule/Middle | 41 -- .../DiagonallyAdjacent | 40 -- .../DirectlyAdjacentCenter | 40 -- .../DirectlyAdjacentEdge | 40 -- .../FalseContradiction | 40 -- .../FalseStarOverlap | 40 -- .../OneColumnOneCell | 29 -- .../PartialColumnOneCell | 29 -- .../PartialColumnTwoCells | 29 -- .../ColumnsWithinRegionsDirectRule/TwoColumns | 40 -- .../TwoColumnsStarOverlap | 40 -- .../FalseStarOverlap | 40 -- .../NonAdjacentColumns | 29 -- .../ColumnsWithinRowsDirectRule/OneColumn | 29 -- .../ColumnsWithinRowsDirectRule/TwoColumns | 29 -- .../TwoColumnsStarOverlap | 40 -- .../ImproperUseFourLeft | 40 -- .../rules/EmptyAdjacentDirectRule/OneLeft | 40 -- .../rules/EmptyAdjacentDirectRule/ThreeLeft | 40 -- .../rules/EmptyAdjacentDirectRule/TwoLeft | 40 -- .../FinishWithStarsDirectRule/CornerColumn | 41 -- .../rules/FinishWithStarsDirectRule/CornerRow | 41 -- .../FinishWithStarsDirectRule/CornerRowColumn | 41 -- .../FinishWithStarsDirectRule/DoubleRegion | 41 -- .../rules/FinishWithStarsDirectRule/False | 41 -- .../rules/FinishWithStarsDirectRule/Region | 41 -- .../FalseStarOverlap | 40 -- .../OneRegionOneCell | 29 -- .../OneRegionTwoCells | 29 -- .../PartialRegionOneCell | 29 -- .../TwoRegionsOneCell | 40 -- .../TwoRegionsStarOverlap | 40 -- .../TwoRegionsTwoCells | 40 -- .../TwoRegionsTwoCells2 | 40 -- .../FalseStarOverlap | 40 -- .../OneRegionOneCell | 29 -- .../PartialRegionOneCell | 29 -- .../PartialRegionTwoCells | 29 -- .../RegionsWithinRowsDirectRule/StarOverlap | 40 -- .../TwoRegionsOneCell | 40 -- .../StarOrEmptyCaseRule/SimpleStarOrEmpty | 29 -- .../rules/SurroundStarDirectRule/CenterStar | 29 -- .../rules/SurroundStarDirectRule/CornerStar | 29 -- .../rules/TooFewStarsContradictionRule/Column | 40 -- .../FalseContradiction | 40 -- .../NotEnoughSpace | 40 -- .../rules/TooFewStarsContradictionRule/Region | 40 -- .../rules/TooFewStarsContradictionRule/Row | 40 -- .../TwoStarColumn | 40 -- .../TwoStarFalseContradiction | 40 -- .../ColumnOverloaded | 41 -- .../TooManyStarsContradictionRule/Correct | 41 -- .../Region Overloaded Visualized-01.png | Bin 15488 -> 0 bytes .../RegionOverloaded | 41 -- .../RowOverloaded | 41 -- 86 files changed, 169 insertions(+), 5161 deletions(-) delete mode 100644 puzzles files/starbattle/10x10 Star Battle 2 star Normal/10x10 Star Battle 2star Normal1.xml delete mode 100644 puzzles files/starbattle/5x5 Star Battle 1 star Normal/050101 delete mode 100644 puzzles files/starbattle/5x5 Star Battle 1 star Normal/050101 visualized (DO NOT OPEN AS A PUZZLE).png delete mode 100644 puzzles files/starbattle/5x5 Star Battle 1 star Normal/050102 delete mode 100644 puzzles files/starbattle/6x6 Star Battle 1 star Normal/6x6 Star Battle Normal1 visualized (DO NOT OPEN AS A PUZZLE).png delete mode 100644 src/main/java/edu/rpi/legup/puzzle/starbattle/rules/EmptyAdjacentDirectRule.java delete mode 100644 src/main/java/edu/rpi/legup/puzzle/starbattle/rules/starbattle_reference_sheet.txt delete mode 100644 src/main/resources/edu/rpi/legup/images/starbattle/rules/EmptyAdjacentDirectRule.png delete mode 100644 src/test/java/puzzles/starbattle/rules/ClashingOrbitContradictionRuleTest.java delete mode 100644 src/test/java/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRuleTest.java delete mode 100644 src/test/java/puzzles/starbattle/rules/ColumnsWithinRowsDirectRuleTest.java delete mode 100644 src/test/java/puzzles/starbattle/rules/EmptyAdjacentDirectRuleTest.java delete mode 100644 src/test/java/puzzles/starbattle/rules/FinishWithStarsDirectRuleTest.java delete mode 100644 src/test/java/puzzles/starbattle/rules/RegionsWithinColumnsDirectRuleTest.java delete mode 100644 src/test/java/puzzles/starbattle/rules/RegionsWithinRowsDirectRuleTest.java delete mode 100644 src/test/java/puzzles/starbattle/rules/StarOrEmptyCaseRuleTest.java delete mode 100644 src/test/java/puzzles/starbattle/rules/SurroundStarDirectRuleTest.java delete mode 100644 src/test/java/puzzles/starbattle/rules/TooFewStarsContradictionRuleTest.java delete mode 100644 src/test/java/puzzles/starbattle/rules/TooManyStarsContradictionRuleTests.java delete mode 100644 src/test/resources/puzzles/starbattle/rules/BlackoutDirectRule/Blackout visualized.png delete mode 100644 src/test/resources/puzzles/starbattle/rules/BlackoutDirectRule/Corner delete mode 100644 src/test/resources/puzzles/starbattle/rules/BlackoutDirectRule/Edge delete mode 100644 src/test/resources/puzzles/starbattle/rules/BlackoutDirectRule/Middle delete mode 100644 src/test/resources/puzzles/starbattle/rules/ClashingOrbitContradictionRule/DiagonallyAdjacent delete mode 100644 src/test/resources/puzzles/starbattle/rules/ClashingOrbitContradictionRule/DirectlyAdjacentCenter delete mode 100644 src/test/resources/puzzles/starbattle/rules/ClashingOrbitContradictionRule/DirectlyAdjacentEdge delete mode 100644 src/test/resources/puzzles/starbattle/rules/ClashingOrbitContradictionRule/FalseContradiction delete mode 100644 src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/FalseStarOverlap delete mode 100644 src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/OneColumnOneCell delete mode 100644 src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/PartialColumnOneCell delete mode 100644 src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/PartialColumnTwoCells delete mode 100644 src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/TwoColumns delete mode 100644 src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/TwoColumnsStarOverlap delete mode 100644 src/test/resources/puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/FalseStarOverlap delete mode 100644 src/test/resources/puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/NonAdjacentColumns delete mode 100644 src/test/resources/puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/OneColumn delete mode 100644 src/test/resources/puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/TwoColumns delete mode 100644 src/test/resources/puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/TwoColumnsStarOverlap delete mode 100644 src/test/resources/puzzles/starbattle/rules/EmptyAdjacentDirectRule/ImproperUseFourLeft delete mode 100644 src/test/resources/puzzles/starbattle/rules/EmptyAdjacentDirectRule/OneLeft delete mode 100644 src/test/resources/puzzles/starbattle/rules/EmptyAdjacentDirectRule/ThreeLeft delete mode 100644 src/test/resources/puzzles/starbattle/rules/EmptyAdjacentDirectRule/TwoLeft delete mode 100644 src/test/resources/puzzles/starbattle/rules/FinishWithStarsDirectRule/CornerColumn delete mode 100644 src/test/resources/puzzles/starbattle/rules/FinishWithStarsDirectRule/CornerRow delete mode 100644 src/test/resources/puzzles/starbattle/rules/FinishWithStarsDirectRule/CornerRowColumn delete mode 100644 src/test/resources/puzzles/starbattle/rules/FinishWithStarsDirectRule/DoubleRegion delete mode 100644 src/test/resources/puzzles/starbattle/rules/FinishWithStarsDirectRule/False delete mode 100644 src/test/resources/puzzles/starbattle/rules/FinishWithStarsDirectRule/Region delete mode 100644 src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/FalseStarOverlap delete mode 100644 src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/OneRegionOneCell delete mode 100644 src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/OneRegionTwoCells delete mode 100644 src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/PartialRegionOneCell delete mode 100644 src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoRegionsOneCell delete mode 100644 src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoRegionsStarOverlap delete mode 100644 src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoRegionsTwoCells delete mode 100644 src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoRegionsTwoCells2 delete mode 100644 src/test/resources/puzzles/starbattle/rules/RegionsWithinRowsDirectRule/FalseStarOverlap delete mode 100644 src/test/resources/puzzles/starbattle/rules/RegionsWithinRowsDirectRule/OneRegionOneCell delete mode 100644 src/test/resources/puzzles/starbattle/rules/RegionsWithinRowsDirectRule/PartialRegionOneCell delete mode 100644 src/test/resources/puzzles/starbattle/rules/RegionsWithinRowsDirectRule/PartialRegionTwoCells delete mode 100644 src/test/resources/puzzles/starbattle/rules/RegionsWithinRowsDirectRule/StarOverlap delete mode 100644 src/test/resources/puzzles/starbattle/rules/RegionsWithinRowsDirectRule/TwoRegionsOneCell delete mode 100644 src/test/resources/puzzles/starbattle/rules/StarOrEmptyCaseRule/SimpleStarOrEmpty delete mode 100644 src/test/resources/puzzles/starbattle/rules/SurroundStarDirectRule/CenterStar delete mode 100644 src/test/resources/puzzles/starbattle/rules/SurroundStarDirectRule/CornerStar delete mode 100644 src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/Column delete mode 100644 src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/FalseContradiction delete mode 100644 src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/NotEnoughSpace delete mode 100644 src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/Region delete mode 100644 src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/Row delete mode 100644 src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/TwoStarColumn delete mode 100644 src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/TwoStarFalseContradiction delete mode 100644 src/test/resources/puzzles/starbattle/rules/TooManyStarsContradictionRule/ColumnOverloaded delete mode 100644 src/test/resources/puzzles/starbattle/rules/TooManyStarsContradictionRule/Correct delete mode 100644 src/test/resources/puzzles/starbattle/rules/TooManyStarsContradictionRule/Region Overloaded Visualized-01.png delete mode 100644 src/test/resources/puzzles/starbattle/rules/TooManyStarsContradictionRule/RegionOverloaded delete mode 100644 src/test/resources/puzzles/starbattle/rules/TooManyStarsContradictionRule/RowOverloaded diff --git a/puzzles files/starbattle/10x10 Star Battle 2 star Normal/10x10 Star Battle 2star Normal1.xml b/puzzles files/starbattle/10x10 Star Battle 2 star Normal/10x10 Star Battle 2star Normal1.xml deleted file mode 100644 index aac7dd8f9..000000000 --- a/puzzles files/starbattle/10x10 Star Battle 2 star Normal/10x10 Star Battle 2star Normal1.xml +++ /dev/null @@ -1,148 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/puzzles files/starbattle/5x5 Star Battle 1 star Normal/050101 b/puzzles files/starbattle/5x5 Star Battle 1 star Normal/050101 deleted file mode 100644 index b86e16ff2..000000000 --- a/puzzles files/starbattle/5x5 Star Battle 1 star Normal/050101 +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/puzzles files/starbattle/5x5 Star Battle 1 star Normal/050101 visualized (DO NOT OPEN AS A PUZZLE).png b/puzzles files/starbattle/5x5 Star Battle 1 star Normal/050101 visualized (DO NOT OPEN AS A PUZZLE).png deleted file mode 100644 index 5e42c203340e6efe38fdd4b9f27e8959b437ae5f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13377 zcmeI3e^gV~9l&2mNGyaPV#`YkgkUFXnTDD{q)N#6A-@D+&Z<@R5+}msK%7{hG$bSw zl=7p+_6(^)ARckGBCS1&LLuS7WUU1eD|AIjRDLPYP#DG#$=*vy!Z};c8QVXuzCUs} z=e|7Nz2AH9_kQxZ_np`tyVc2o<^TYIQ)EPF0s!E&$Vaz~h?G25C1xOhUJ^v?J^}!a zE6@+__Pty^0C)kBq1+u=r^l5zCxE%UP1e~mnnQQgT(JkboyK3;@v2r+t1)nyStMO^Lj?|V4U|I^9>+QoR^0)hOeeU zGI;sONOD58UzYyi+K|*37B`yW&Stg=1GUPTu^#H(v_2qnBw1JM(U9@f0iJt8R}EKf z5*Dg&sbN8Ge7v7jCIh6Eb)ABrW@W_nlaqpx;&Vcs^w{)>OZr+o9&hTV31ul-UE(j; z*^gGjx7*(r1YT^e%Vz}or+takR1UlfLC`|i?fZRzxu;i>0~89yLir2U)i2u6#@dUG zbBX%rpTe*V;K1;WQp3qdJ6`_ncMNK9h>Pa1fY~&sJ$#k~%Lx7b{bY_oPaRVR zyDBP`vk$hDQ;Nsv))K7}pH& z;+0mY+vmX|h|irP!g+X-isIq1T25zYjV=oj?)x@kYSQ>qpaHO8EzR~rUZ|e|*c!5U zZ2#}M1dAsYPi#%b<`I?$p3gkMXWWSEt-A+lr>A|&CsZnC#d_lMB9w^gR1c>f5QJAU zro5S+_A?~;0cRn1|8E>qUU|a;Kud%M??cCPQA!d!oQtapqIvHi(u3Xucg|Do<>D2B z;hD8W7Y6Qru~k?Z#gxo$S0fKjW+qVebI)>iJw3Rx$Sz7z4Hr-)df|xxiCMXsaP41# z(&o@J;hh82)p)S>B)3IX(C$Exz1^zOJNYPCHRCZT-(5&vfFGxo2-{))f_&=7N`K)Nh zi&Cb33F37zY4aJRn42+jb)1i^y1Inl{r$#TFzA^UH}c6Tnsc@Td>?3QXAB5 zGf0>lL?-Twr^B)F@Os zNPEBgOV2@dstb=n-06R%n|anxJN<+{<-b@enSBpre<`sgX-!8LyzZ@?dp6UOGl-N~ zO4|<|7BRI%mZ-@(o~xS~laKKMB}zv9P1&yP&E1+>I_Q+6lZsyJd|D#m5-k2~vC#8H zgkJY~cYC8SuYA=-pYqBW0CJgTHj1&%6&a0+Q){;N>>t6Nk4=~;uFk1|~Wi-iT1jBJ*vI~uW<|ZWY zS<6$%?@aW?HaS@}s1>lb6M{c(MBpyj>o!==JjopG{0}4TwCwyR0N^@;o&_*P$h6yI zYmi{&*dl^0BG@8=nTNx;PB_=v5N}RHrI>z&$Aj|~eQ51A?3lwui2A6b4v(ZAll1QU+f#*uA z6yts6qe|6}E{@@_2;%Ne@hf~rqPTVHUJRuVH|X~ zR6*I>e{X9@ek{cLEX8@(DUizEw29g*G6eO16{rWyl~|`VnLfSyn-vmRtqYY{~ZyQ~s|K2e_q`UZt#s$yU6x(L`IR6H%OrTy6>XgDU5nm8_$> zfG z2R`Ln-evhb!}*R=!{Mql)xcMCtJ-RjPLujXd~ZSy zy@rdAk4N^CjUJDIv$#Im8R@@04Y<@M{l9--awcq$O}mDM2ZRu474TTsQ6c+Rah}@r aW(gi})m)Wk5(|9Lq!$?$8(Q~kNb*l)w!ydn diff --git a/puzzles files/starbattle/5x5 Star Battle 1 star Normal/050102 b/puzzles files/starbattle/5x5 Star Battle 1 star Normal/050102 deleted file mode 100644 index 73d131d69..000000000 --- a/puzzles files/starbattle/5x5 Star Battle 1 star Normal/050102 +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/puzzles files/starbattle/6x6 Star Battle 1 star Normal/6x6 Star Battle Normal1 visualized (DO NOT OPEN AS A PUZZLE).png b/puzzles files/starbattle/6x6 Star Battle 1 star Normal/6x6 Star Battle Normal1 visualized (DO NOT OPEN AS A PUZZLE).png deleted file mode 100644 index 584d081539b5d4cf96eee24d5decf73f12076fb4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14302 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 c4j(W;vBT|k> subsets, int current, int skip, int size) { - if (current == size) { - return; - } - List> newSubsets = new LinkedList>(); - if (current != skip) { - for (List subset: subsets) { - List copy = new LinkedList(subset); - copy.add(current); - newSubsets.add(copy); - } - subsets.addAll(newSubsets); - List oneMember = new LinkedList(); - oneMember.add(current); - subsets.add(oneMember); - } - generateSubsets(subsets, current + 1 == skip ? current + 2 : current + 1, skip, size); - } - /** * Checks whether the child node logically follows from the parent node at the specific * puzzleElement index using this rule @@ -51,45 +31,53 @@ private void generateSubsets(List> subsets, int current, int skip, */ @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 StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleBoard origBoard = (StarBattleBoard) transition.getParents().get(0).getBoard(); StarBattleCell cell = (StarBattleCell) board.getPuzzleElement(puzzleElement); - int dim = board.getSize(); - int region = cell.getGroupIndex(); - int column = cell.getLocation().x; - if (cell.getType() != StarBattleCellType.BLACK) { return "Only black cells are allowed for this rule!"; } + // the columns that are contained + Set columns = new HashSet(); + // the regions that contain them + Set regions = new HashSet(); + // columns and regions to process + Set columnsToCheck = new HashSet(); + Set regionsToCheck = new HashSet(); + int columnStars = 0; + int regionStars = 0; + regions.add(cell.getGroupIndex()); + regionsToCheck.add(cell.getGroupIndex()); - List> subsets = new LinkedList>(); - generateSubsets(subsets,0, column, dim); - - for (List columnSubset: subsets) { - Set regions = new HashSet(); - boolean containsRegion = false; - int columnStars = 0; - int regionStars = 0; - for (int c: columnSubset) { - columnStars += origBoard.columnStars(c); - for (StarBattleCell ce: origBoard.getCol(c)) { - if (ce.getType() == StarBattleCellType.UNKNOWN) { - if (regions.add(ce.getGroupIndex())) { - regionStars += origBoard.getRegion(ce.getGroupIndex()).numStars(); - } - if (ce.getGroupIndex() == region) { - containsRegion = true; - } + while (!columnsToCheck.isEmpty() || !regionsToCheck.isEmpty()) { + for (int r : regionsToCheck) { + regionStars += board.getRegion(r).numStars(); + for (PuzzleElement c : board.getRegion(r).getCells()) { + int column = ((StarBattleCell) c).getLocation().x; + if (columns.add(column)) { + columnsToCheck.add(column); } } + regionsToCheck.remove(r); } - if (containsRegion && board.getPuzzleNumber() * columnSubset.size() - columnStars - >= board.getPuzzleNumber() * regions.size() - regionStars) { - return null; + for (int c : columnsToCheck) { + columnStars += board.columnStars(c); + for (int i = 0; i < board.getSize(); ++i) { + int region = board.getCell(c, i).getGroupIndex(); + if (regions.add(region)) { + regionsToCheck.add(region); + } + } + columnsToCheck.remove(c); } } - return "The columns must fully fit within regions with the same number of stars missing!"; + // are the columns and regions missing an equal amount of stars + 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; } /** 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 da5c7bfd3..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,8 +8,8 @@ import edu.rpi.legup.puzzle.starbattle.StarBattleBoard; import edu.rpi.legup.puzzle.starbattle.StarBattleCell; import edu.rpi.legup.puzzle.starbattle.StarBattleCellType; - -import java.util.*; +import java.util.HashSet; +import java.util.Set; public class ColumnsWithinRowsDirectRule extends DirectRule { @@ -21,25 +21,6 @@ public ColumnsWithinRowsDirectRule() { "edu/rpi/legup/images/starbattle/rules/ColumnsWithinRowsDirectRule.png"); } - private void generateSubsets(List> subsets, int current, int skip, int size) { - if (current == size) { - return; - } - List> newSubsets = new LinkedList>(); - if (current != skip) { - for (List subset: subsets) { - List copy = new LinkedList(subset); - copy.add(current); - newSubsets.add(copy); - } - subsets.addAll(newSubsets); - List oneMember = new LinkedList(); - oneMember.add(current); - subsets.add(oneMember); - } - generateSubsets(subsets, current + 1 == skip ? current + 2 : current + 1, skip, size); - } - /** * Checks whether the child node logically follows from the parent node at the specific * puzzleElement index using this rule @@ -55,43 +36,52 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem // assumption: the rule has been applied to its fullest extent and the rows and columns // are now mutually encompassing StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleBoard origBoard = (StarBattleBoard) transition.getParents().get(0).getBoard(); StarBattleCell cell = (StarBattleCell) board.getPuzzleElement(puzzleElement); - int dim = board.getSize(); - int row = cell.getLocation().y; - int column = cell.getLocation().x; - if (cell.getType() != StarBattleCellType.BLACK) { return "Only black cells are allowed for this rule!"; } - List> subsets = new LinkedList>(); - generateSubsets(subsets,0, column, dim); + // the columns that are contained + Set columns = new HashSet(); + // the rows that contain them + Set rows = new HashSet(); + // columns and rows to process + Set columnsToCheck = new HashSet(); + Set rowsToCheck = new HashSet(); + int columnStars = 0; + int rowStars = 0; + int firstRow = cell.getLocation().y; + rows.add(firstRow); + rowsToCheck.add(firstRow); - for (List columnSubset: subsets) { - Set rows = new HashSet(); - boolean containsRow = false; - int columnStars = 0; - int rowStars = 0; - for (int c: columnSubset) { - columnStars += origBoard.columnStars(c); - for (StarBattleCell ce: origBoard.getCol(c)) { - if (ce.getType() == StarBattleCellType.UNKNOWN) { - if (rows.add(ce.getLocation().y)) { - rowStars += origBoard.rowStars(ce.getLocation().y); - } - if (ce.getLocation().y == row) { - containsRow = true; - } + while (!columnsToCheck.isEmpty() || !rowsToCheck.isEmpty()) { + for (int r : rowsToCheck) { + rowStars += board.rowStars(r); + for (PuzzleElement c : board.getRow(r)) { + int column = ((StarBattleCell) c).getLocation().x; + if (columns.add(column)) { + columnsToCheck.add(column); } } + rowsToCheck.remove(r); } - if (containsRow && board.getPuzzleNumber() * columnSubset.size() - columnStars - >= board.getPuzzleNumber() * rows.size() - rowStars) { - return null; + for (int c : columnsToCheck) { + columnStars += board.columnStars(c); + for (PuzzleElement r : board.getCol(c)) { + int row = ((StarBattleCell) r).getLocation().y; + if (rows.add(row)) { + rowsToCheck.add(row); + } + } + columnsToCheck.remove(c); } } - return "The columns must fully fit within rows with the same number of stars missing!"; + // are the columns and regions missing an equal amount of stars + 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; } /** diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/EmptyAdjacentDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/EmptyAdjacentDirectRule.java deleted file mode 100644 index 0cb43ce06..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/EmptyAdjacentDirectRule.java +++ /dev/null @@ -1,95 +0,0 @@ -package edu.rpi.legup.puzzle.starbattle.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.model.rules.DirectRule; -import edu.rpi.legup.model.tree.TreeNode; -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; - -public class EmptyAdjacentDirectRule extends DirectRule { - - public EmptyAdjacentDirectRule() { - super( - "STBL-BASC-0010", - "Empty Adjacent", - "Tiles next to other tiles that need to contain a star to reach the puzzle number for their region/row/column need to be blacked out.", - "edu/rpi/legup/images/starbattle/rules/EmptyAdjacentDirectRule.png"); - } - - /** - * 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) { - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleBoard origBoard = (StarBattleBoard) transition.getParents().get(0).getBoard(); - ContradictionRule contraRule = new TooFewStarsContradictionRule(); - - StarBattleCell cell = (StarBattleCell) board.getPuzzleElement(puzzleElement); - - if (cell.getType() != StarBattleCellType.BLACK) { - return super.getInvalidUseOfRuleMessage() - + ": Only black cells are allowed for this rule!"; - } - - int x = cell.getLocation().x; - int y = cell.getLocation().y; - - StarBattleCell northWest = board.getCell(x - 1, y - 1); - StarBattleCell north = board.getCell(x, y - 1); - StarBattleCell northEast = board.getCell(x + 1, y - 1); - StarBattleCell west = board.getCell(x - 1, y); - StarBattleCell east = board.getCell(x + 1, y); - StarBattleCell southWest = board.getCell(x - 1, y + 1); - StarBattleCell south = board.getCell(x, y + 1); - StarBattleCell southEast = board.getCell(x + 1, y + 1); - - StarBattleCell[] adjacent = {northWest, north, northEast, west, east, southWest, south, southEast}; - - StarBattleBoard modified = (StarBattleBoard) origBoard.copy(); - modified.getPuzzleElement(puzzleElement).setData(StarBattleCellType.STAR.value); - for(int i = 0; i < 8; i++){ //sets each spot to a black square if not filled - StarBattleCell temp = adjacent[i]; - - if (temp != null && temp.getType() == StarBattleCellType.UNKNOWN) { - //temp.setData(StarBattleCellType.BLACK.value); - int X = temp.getLocation().x; - int Y = temp.getLocation().y; - modified.getCell(X,Y).setData(StarBattleCellType.BLACK.value); - System.out.println("covering square " + X + " " + Y + " type " + modified.getCell(X,Y).getType() + " i = " + i + "\n"); - if(contraRule.checkContradictionAt(modified, temp) == null){ - System.out.println("Good job!"); - return null; //used correctly if even one space causes a toofewstars issue - } - } - } - System.out.println("Wait why did this exit?\n"); - - return "Black cells must be placed adjacent to a tile(s) where a star is needed!"; - } - - /** - * 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) { - - return null; - } -} 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 06d73cc1f..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 @@ -27,11 +27,7 @@ public RegionsWithinColumnsDirectRule() { @Override public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { ColumnsWithinRegionsDirectRule correspondingRule = new ColumnsWithinRegionsDirectRule(); - String result = correspondingRule.checkRuleRawAt(transition, puzzleElement); - if (result != null && result.equals("The columns must fully fit within regions with the same number of stars missing!")) { - return "The regions must fully fit within columns with the same number of stars missing!"; - } - return result; + return correspondingRule.checkRuleRawAt(transition, puzzleElement); } /** 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 012dc0640..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 @@ -28,11 +28,7 @@ public RegionsWithinRowsDirectRule() { public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { RowsWithinRegionsDirectRule correspondingRule = new RowsWithinRegionsDirectRule(); - String result = correspondingRule.checkRuleRawAt(transition, puzzleElement); - if (result != null && result.equals("The rows must fully fit within regions with the same number of stars missing!")) { - return "The regions must fully fit within rows with the same number of stars missing!"; - } - return result; + return correspondingRule.checkRuleRawAt(transition, puzzleElement); } /** 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 a22c31a59..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 @@ -11,7 +11,7 @@ public class RowsWithinColumnsDirectRule extends DirectRule { public RowsWithinColumnsDirectRule() { super( "STBL-BASC-0007", - "Rows Within Columns", + "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"); } @@ -29,11 +29,7 @@ public RowsWithinColumnsDirectRule() { public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { ColumnsWithinRowsDirectRule correspondingRule = new ColumnsWithinRowsDirectRule(); - String result = correspondingRule.checkRuleRawAt(transition, puzzleElement); - if (result != null && result.equals("The columns must fully fit within rows with the same number of stars missing!")) { - return "The rows must fully fit within columns with the same number of stars missing!"; - } - return result; + return correspondingRule.checkRuleRawAt(transition, puzzleElement); } /** 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 de9aaf044..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,8 +8,8 @@ import edu.rpi.legup.puzzle.starbattle.StarBattleBoard; import edu.rpi.legup.puzzle.starbattle.StarBattleCell; import edu.rpi.legup.puzzle.starbattle.StarBattleCellType; - -import java.util.*; +import java.util.HashSet; +import java.util.Set; public class RowsWithinRegionsDirectRule extends DirectRule { public RowsWithinRegionsDirectRule() { @@ -20,25 +20,6 @@ public RowsWithinRegionsDirectRule() { "edu/rpi/legup/images/starbattle/rules/RowsWithinRegionsDirectRule.png"); } - private void generateSubsets(List> subsets, int current, int skip, int size) { - if (current == size) { - return; - } - List> newSubsets = new LinkedList>(); - if (current != skip) { - for (List subset: subsets) { - List copy = new LinkedList(subset); - copy.add(current); - newSubsets.add(copy); - } - subsets.addAll(newSubsets); - List oneMember = new LinkedList(); - oneMember.add(current); - subsets.add(oneMember); - } - generateSubsets(subsets, current + 1 == skip ? current + 2 : current + 1, skip, size); - } - /** * Checks whether the child node logically follows from the parent node at the specific * puzzleElement index using this rule @@ -54,81 +35,42 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem // assumption: the rule has been applied to its fullest extent and the rows and regions // are now mutually encompassing StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleBoard origBoard = (StarBattleBoard) transition.getParents().get(0).getBoard(); StarBattleCell cell = (StarBattleCell) board.getPuzzleElement(puzzleElement); - int dim = board.getSize(); - int region = cell.getGroupIndex(); - int row = cell.getLocation().y; - if (cell.getType() != StarBattleCellType.BLACK) { return "Only black cells are allowed for this rule!"; } - - List> subsets = new LinkedList>(); - generateSubsets(subsets,0, row, dim); - - for (List rowSubset: subsets) { - Set regions = new HashSet(); - boolean containsRegion = false; - int rowStars = 0; - int regionStars = 0; - for (int r: rowSubset) { - rowStars += origBoard.rowStars(r); - for (StarBattleCell ce: origBoard.getRow(r)) { - if (ce.getType() == StarBattleCellType.UNKNOWN) { - if (regions.add(ce.getGroupIndex())) { - regionStars += origBoard.getRegion(ce.getGroupIndex()).numStars(); - } - if (ce.getGroupIndex() == region) { - containsRegion = true; - } - } - } - } - if (containsRegion && board.getPuzzleNumber() * rowSubset.size() - rowStars - >= board.getPuzzleNumber() * regions.size() - regionStars) { - return null; - } - } - return "The rows must fully fit within regions with the same number of stars missing!"; - - /* // the rows that are contained Set rows = new HashSet(); // the regions that contain them Set regions = new HashSet(); // rows and regions to process - List rowsToCheck = new ArrayList(); - List regionsToCheck = new ArrayList(); + Set rowsToCheck = new HashSet(); + Set regionsToCheck = new HashSet(); int rowStars = 0; int regionStars = 0; regions.add(cell.getGroupIndex()); regionsToCheck.add(cell.getGroupIndex()); while (!rowsToCheck.isEmpty() || !regionsToCheck.isEmpty()) { - for (int i = 0; i < regionsToCheck.size(); ++i) { - int r = regionsToCheck.get(i); + for (int r : regionsToCheck) { regionStars += board.getRegion(r).numStars(); - for (StarBattleCell ro : board.getRegion(r).getCells()) { - int row = ro.getLocation().y; - if (ro.getType() == StarBattleCellType.UNKNOWN && rows.add(row)) { + for (PuzzleElement ro : board.getRegion(r).getCells()) { + int row = ((StarBattleCell) ro).getLocation().y; + if (rows.add(row)) { rowsToCheck.add(row); } } - regionsToCheck.remove(i); - --i; + regionsToCheck.remove(r); } - for (int j = 0; j < rowsToCheck.size(); ++j) { - int r = rowsToCheck.get(j); + for (int r : rowsToCheck) { rowStars += board.rowStars(r); for (int i = 0; i < board.getSize(); ++i) { int region = board.getCell(i, r).getGroupIndex(); - if (board.getCell(i,r).getType() == StarBattleCellType.UNKNOWN && regions.add(region)) { + if (regions.add(region)) { regionsToCheck.add(region); } } - rowsToCheck.remove(j); - --j; + rowsToCheck.remove(r); } } // are the columns and regions missing an equal amount of stars @@ -136,12 +78,7 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem != 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!"; } - if (rows.contains(cell.getLocation().y)) { - return "Only black out cells outside the row(s)!"; - } 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 358e5b9bd..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 @@ -38,16 +38,14 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { int rowCount = 0; int columnCount = 0; for (int i = 0; i < sbBoard.getSize(); ++i) { - if (sbBoard.getCell(i, row).getType() != StarBattleCellType.BLACK) { + if (sbBoard.getCell(row, i).getType() != StarBattleCellType.BLACK) { ++rowCount; } - if (sbBoard.getCell(column, i).getType() != StarBattleCellType.BLACK) { + if (sbBoard.getCell(i, column).getType() != StarBattleCellType.BLACK) { ++columnCount; } } - System.out.println("rowCount = " + rowCount + " columnCount = " + columnCount + " at " + column + "," + row + "\n"); if (rowCount < sbBoard.getPuzzleNumber() || columnCount < sbBoard.getPuzzleNumber()) { - System.out.println("Returning Null\n"); return null; } StarBattleRegion region = sbBoard.getRegion(cell); diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/starbattle_reference_sheet.txt b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/starbattle_reference_sheet.txt deleted file mode 100644 index c332fcee0..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/starbattle_reference_sheet.txt +++ /dev/null @@ -1,20 +0,0 @@ -Case Rules: -Add Star: STBL-CASE-0001 -Star or Empty: STBL-CASE-0002 - -Basic Rules: -Blackout: STBL-BASC-0001 -Columns Within Regions: STBL-BASC-0002 -Columns Within Rows: STBL-BASC-0003 -Finish With Stars: STBL-BASC-0004 -Regions Within Columns: STBL-BASC-0005 -Regions Within Rows: STBL-BASC-0006 -Rows Within Columns: STBL-BASC-0007 -Rows Within Regions: STBL-BASC-0008 -Surround Star: STBL-BASC-0009 -Empty Adjacent: STBL-BASC-0010 - -Contradiction Rules: -Too Many Stars: STBL-CONT-0001 -Too Few Stars: STBL-CONT-0002 -Clashing Orbit: STBL-CONT-0003 \ No newline at end of file diff --git a/src/main/resources/edu/rpi/legup/images/starbattle/rules/EmptyAdjacentDirectRule.png b/src/main/resources/edu/rpi/legup/images/starbattle/rules/EmptyAdjacentDirectRule.png deleted file mode 100644 index db3c0d9d56b4d727026e600e2f9df3db6e251c5c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1822 zcmY+_cQhN0767C+ zYuBijNF6bQQhSyDyx;Hjo%8;<_nz;+_jB&K32;+=PPQv-004l~&_EY)F;V|17W#|+ zD~6uoVhH1)HaH7EcU*{T02-i;@^eFr8Tz_n&XCmxS{(pjdT*$!Z5cYV@o#${ zeyGp~Ot5>%X!Xieps9W0Ga!@QW-M?_C@tmy0szSwBz2r%BW|^=W~QpM@QQLv*6Z?? zxo~>2j2A!c#Lvo1k>(NUkP_%jAbBvU0b}n`eBBE}&W&(3Rl=;yYhj{xheMQ(J0b{V zGMNVwo0c$5zh)9Y(AlesnC#0IkGj}>I%80MPx z3y@_1u@VPk0qtq{1r0^3Hf}TqNFZG$&7XTmh1Kkb9Y*cUr*I(>Vg+w|Pb?4X+uO$x z%#~lHis)FC+@oz>(MvKGhZ1?^4l6b5=~CENwG~1oGKCfRp#yZQZ4V!zoJ82`Ji1SMcz^yzMlrcYbRh8jLY?Hha(q%9&HXR7FRgE%zKZ}WA)hF2suzrZmojX6)t69;{ z9tBRvi33-IgMzGv3#6iyt81(Ib=-@O>>dWIINYfJwmPO&1Nok)NfF#RmMB!5uH&NsLt|E%&rJLvXmKC9T;lr@EM>u9Z6ATqE(d^VyP5sR}=A#041I zPho{@QD_gC!{>+<9H&G%av*FX!he5FvD{1zq>qLA#M9!^JdroG5DL8kZMH-11OxD| zxk|C&aoQU<9(k99%Hm6m%|9-2{o~~FH{suELcc*{7@2+}y8J;`6^%hAhqEz?H@l3l z2u<`jt+wK+Yf78iHUWBJ5ep*u{iq%o30~Wot4|A;LT^b<`;rNJ?P(<8K~zIeA8D~A zb8N4@crojmFV+Xw2SiteS&7*!#~mg*j-r{R_bsk08U*umBEZ%$2(3CNn)Cb?!?8#w(*2n`K~Nzyc=rV$heMg>3;5 zaHE7*VxUhs>Q{H-9(#!;KD)I7jTDTJ-&!m^lE<`3(+V0L3gcO}GdnxQjfjG04Lw%y zd?F|-o~t8}M_d(z(fwQy43?>u3Gibu-=F-pPMM=*G-jyEXIWPp!zeGi|8)w=E)^CA zmVqqmY_3MH#>yWh5-m_N717!7g(Nd!aHurnKlk_lT;Sgq_+Q!m=s#Hz2pj)zR(Fpr zzY<4~k3*^3zlf>j`~n!Fn`h5}v4=$$crz8Dp(`3}S|yT$Oq=B5Q+ATBqfCnGVm()=;Z@H@&HYIX9um+k+Xi>wP!* zvRI8SS1mIzJB+$Lb<{B6<8qoVe|;x}i|eOumiHtH^h6l)vAy-=Y){m=@eT3y09tV2 zE&jQ(vYKOxX^}e3^sU!${>$oWk#^Mv|MjW(mKHe}%&ARv7j8UQ)E*wPHDi@w^vE2# zYZMuIy1kHsNlvwODtvUuI-6#0!h_#j4ln cases = RULE.getCases(board, cell); - - StarBattleBoard caseBoard1 = (StarBattleBoard) cases.get(0); - StarBattleBoard caseBoard2 = (StarBattleBoard) cases.get(1); - StarBattleCellType board1Type = caseBoard1.getCell(0, 0).getType(); - StarBattleCellType board2Type = caseBoard2.getCell(0, 0).getType(); - - Assert.assertTrue( - (board1Type.equals(StarBattleCellType.BLACK) || board1Type.equals(StarBattleCellType.STAR)) - && (board2Type.equals(StarBattleCellType.BLACK) - || board2Type.equals(StarBattleCellType.STAR))); - Assert.assertFalse(board1Type.equals(board2Type)); - Assert.assertEquals(caseBoard1.getHeight(), caseBoard2.getHeight(), board.getHeight()); - Assert.assertEquals(caseBoard1.getWidth(), caseBoard2.getWidth(), board.getWidth()); - - for (int i = 0; i < caseBoard1.getHeight(); i++) { - for (int k = 0; k < caseBoard1.getWidth(); k++) { - Point point = new Point(k, i); - if (point.equals(caseBoard1.getCell(k, i).getLocation())) { - continue; - } - Assert.assertTrue(caseBoard1.getCell(k, i).equals(caseBoard2.getCell(k, i))); - } - } - } - -} diff --git a/src/test/java/puzzles/starbattle/rules/SurroundStarDirectRuleTest.java b/src/test/java/puzzles/starbattle/rules/SurroundStarDirectRuleTest.java deleted file mode 100644 index db55d0f65..000000000 --- a/src/test/java/puzzles/starbattle/rules/SurroundStarDirectRuleTest.java +++ /dev/null @@ -1,173 +0,0 @@ -package puzzles.starbattle.rules; - -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -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.SurroundStarDirectRule; -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 SurroundStarDirectRuleTest { - - private static final SurroundStarDirectRule RULE = new SurroundStarDirectRule(); - private static StarBattle starbattle; - - @BeforeClass - public static void setUp() { - MockGameBoardFacade.getInstance(); - starbattle = new StarBattle(); - } - - @Test - public void SurroundStarDirectRule_CenterStarOneTile() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/SurroundStarDirectRule/CenterStar", starbattle); - TreeNode rootNode = starbattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell = board.getCell(0,1); - cell.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell); - - Assert.assertNull(RULE.checkRule(transition)); - - Point location = new Point(0, 1); - 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(location)) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - } - } - } - - @Test - public void SurroundStarDirectRule_CenterStarOneTileDiagonal() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/SurroundStarDirectRule/CenterStar", starbattle); - TreeNode rootNode = starbattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell = board.getCell(0,0); - cell.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell); - - Assert.assertNull(RULE.checkRule(transition)); - - Point location = new Point(0, 0); - 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(location)) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - } - } - } - - @Test - public void SurroundStarDirectRule_CenterStarAllTiles() - throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/SurroundStarDirectRule/CenterStar", starbattle); - TreeNode rootNode = starbattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - for (int i = 0; i < board.getWidth(); i++) { - for (int j = 0; j < board.getHeight(); j++) { - if (i != 1 || j != 1) { - StarBattleCell cell = board.getCell(i,j); - cell.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell); - } - } - } - - Assert.assertNull(RULE.checkRule(transition)); - - Point location = new Point(1, 1); - 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(location)) { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } else { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - } - } - } - - @Test - public void SurroundStarDirectRule_CornerStar() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/SurroundStarDirectRule/CornerStar", starbattle); - TreeNode rootNode = starbattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell1 = board.getCell(0,1); - cell1.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell1); - StarBattleCell cell2 = board.getCell(1,0); - cell2.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell2); - StarBattleCell cell3 = board.getCell(1,1); - cell3.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell3); - - Assert.assertNull(RULE.checkRule(transition)); - - Point location1 = new Point(0, 1); - Point location2 = new Point(1,0); - Point location3 = new Point(1,1); - 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(location1) || point.equals(location2) || point.equals(location3)) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - } - } - } - - @Test - public void SurroundStarDirectRule_FalseSurroundStar() - throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/SurroundStarDirectRule/CornerStar", starbattle); - TreeNode rootNode = starbattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell = board.getCell(2,0); - cell.setData(StarBattleCellType.BLACK.value); - board.addModifiedData(cell); - - Assert.assertNotNull(RULE.checkRule(transition)); - - for (int i = 0; i < board.getHeight(); i++) { - for (int k = 0; k < board.getWidth(); k++) { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - } - } -} diff --git a/src/test/java/puzzles/starbattle/rules/TooFewStarsContradictionRuleTest.java b/src/test/java/puzzles/starbattle/rules/TooFewStarsContradictionRuleTest.java deleted file mode 100644 index 2c90c6fb2..000000000 --- a/src/test/java/puzzles/starbattle/rules/TooFewStarsContradictionRuleTest.java +++ /dev/null @@ -1,205 +0,0 @@ -package puzzles.starbattle.rules; - -import edu.rpi.legup.puzzle.starbattle.rules.ClashingOrbitContradictionRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -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.TooFewStarsContradictionRule; -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 TooFewStarsContradictionRuleTest { - private static final TooFewStarsContradictionRule RULE = new TooFewStarsContradictionRule(); - private static StarBattle starBattle; - - @BeforeClass - public static void setUp() { - MockGameBoardFacade.getInstance(); - starBattle = new StarBattle(); - } - - /*Too few stars in column */ - @Test - public void TooFewStarsContradictionRule_Column() - throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/TooFewStarsContradictionRule/Column", starBattle); - TreeNode rootNode = starBattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell1 = board.getCell(0,0); - StarBattleCell cell2 = board.getCell(0,1); - StarBattleCell cell3 = board.getCell(0,2); - StarBattleCell cell4 = board.getCell(0,3); - - Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); - for (int i = 0; i < board.getHeight(); ++i) { - for (int j = 0; j < board.getWidth(); ++j) { - Point point = new Point(j,i); - if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) || - point.equals(cell3.getLocation()) || point.equals(cell4.getLocation())) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - } - } - - } - - /*Too few stars in row*/ - @Test - public void TooFewStarsContradictionRule_Row() - throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/TooFewStarsContradictionRule/Row", starBattle); - TreeNode rootNode = starBattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell1 = board.getCell(0,0); - StarBattleCell cell2 = board.getCell(1,0); - StarBattleCell cell3 = board.getCell(2,0); - StarBattleCell cell4 = board.getCell(3,0); - - Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); - for (int i = 0; i < board.getHeight(); ++i) { - for (int j = 0; j < board.getWidth(); ++j) { - Point point = new Point(j,i); - if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) || - point.equals(cell3.getLocation()) || point.equals(cell4.getLocation())) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - } - } - } - - /*Too few stars in region*/ - @Test - public void TooFewStarsContradictionRule_Region() - throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/TooFewStarsContradictionRule/Region", starBattle); - TreeNode rootNode = starBattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell1 = board.getCell(0,0); - StarBattleCell cell2 = board.getCell(0,1); - StarBattleCell cell3 = board.getCell(1,0); - StarBattleCell cell4 = board.getCell(1,1); - - Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); - for (int i = 0; i < board.getHeight(); ++i) { - for (int j = 0; j < board.getWidth(); ++j) { - Point point = new Point(j,i); - if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) || - point.equals(cell3.getLocation()) || point.equals(cell4.getLocation())) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - } - } - } - - /*False contradiction*/ - @Test - public void TooFewStarsContradictionRule_FalseContradiction() - throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/TooFewStarsContradictionRule/FalseContradiction", starBattle); - TreeNode rootNode = starBattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - - Assert.assertNotNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); - for (int i = 0; i < board.getHeight(); ++i) { - for (int j = 0; j < board.getWidth(); ++j) { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - } - } - - @Test - public void TooFewStarsContradictionRule_NotEnoughSpace() - throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/TooFewStarsContradictionRule/NotEnoughSpace", starBattle); - TreeNode rootNode = starBattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - - Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); - for (int i = 0; i < board.getHeight(); ++i) { - for (int j = 0; j < board.getWidth(); ++j) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - } - } - - @Test - public void TooFewStarsContradictionRule_TwoStarColumn() - throws InvalidFileFormatException { - - TestUtilities.importTestBoard("puzzles/starbattle/rules/TooFewStarsContradictionRule/TwoStarColumn", starBattle); - TreeNode rootNode = starBattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell1 = board.getCell(0,0); - StarBattleCell cell2 = board.getCell(0,1); - StarBattleCell cell3 = board.getCell(0,2); - StarBattleCell cell4 = board.getCell(0,3); - - Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); - for (int i = 0; i < board.getHeight(); ++i) { - for (int j = 0; j < board.getWidth(); ++j) { - Point point = new Point(j,i); - if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) || - point.equals(cell3.getLocation()) || point.equals(cell4.getLocation())) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - } - } - } - - @Test - public void TooFewStarsContradictionRule_TwoStarFalseContradiction() - throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/starbattle/rules/TooFewStarsContradictionRule/TwoStarFalseContradiction", starBattle); - TreeNode rootNode = starBattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - - Assert.assertNotNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); - for (int i = 0; i < board.getHeight(); ++i) { - for (int j = 0; j < board.getWidth(); ++j) { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - } - } - -} diff --git a/src/test/java/puzzles/starbattle/rules/TooManyStarsContradictionRuleTests.java b/src/test/java/puzzles/starbattle/rules/TooManyStarsContradictionRuleTests.java deleted file mode 100644 index 3424bbaac..000000000 --- a/src/test/java/puzzles/starbattle/rules/TooManyStarsContradictionRuleTests.java +++ /dev/null @@ -1,137 +0,0 @@ -package puzzles.starbattle.rules; - -import edu.rpi.legup.puzzle.starbattle.rules.TooManyStarsContradictionRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -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.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 TooManyStarsContradictionRuleTests { - private static final TooManyStarsContradictionRule RULE = new TooManyStarsContradictionRule(); - private static StarBattle starBattle; - - @BeforeClass - public static void setUp() { - MockGameBoardFacade.getInstance(); - starBattle = new StarBattle(); - } - - /* Tests the Too Many Stars contradiction rule where a region has - more stars than the puzzle number */ - @Test - public void TooManyStarsContradictionRule_RegionOverloaded() - throws InvalidFileFormatException - { - TestUtilities.importTestBoard("puzzles/starbattle/rules/TooManyStarsContradictionRule/RegionOverloaded", starBattle); - TreeNode rootNode = starBattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell1 = board.getCell(2,1); - StarBattleCell cell2 = board.getCell(0,2); - - Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); - - for (int i = 0; i < board.getHeight(); ++i) { - for (int j = 0; j < board.getWidth(); ++j) { - Point point = new Point(j,i); - if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - } - } - } - - /* Tests the Too Many Stars contradiction rule where a column has - more stars than the puzzle number */ - @Test - public void TooManyStarsContradictionRule_ColumnOverloaded() - throws InvalidFileFormatException - { - TestUtilities.importTestBoard("puzzles/starbattle/rules/TooManyStarsContradictionRule/ColumnOverloaded", starBattle); - TreeNode rootNode = starBattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell1 = board.getCell(0,0); - StarBattleCell cell2 = board.getCell(0,3); - - Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); - - for (int i = 0; i < board.getHeight(); ++i) { - for (int j = 0; j < board.getWidth(); ++j) { - Point point = new Point(j,i); - if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - } - } - } - /* Tests the Too Many Stars contradiction rule where a row has - more stars than the puzzle number */ - @Test - public void TooManyStarsContradictionRule_RowOverloaded() - throws InvalidFileFormatException - { - TestUtilities.importTestBoard("puzzles/starbattle/rules/TooManyStarsContradictionRule/RowOverloaded", starBattle); - TreeNode rootNode = starBattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - StarBattleCell cell1 = board.getCell(0,0); - StarBattleCell cell2 = board.getCell(3,0); - - Assert.assertNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); - - for (int i = 0; i < board.getHeight(); ++i) { - for (int j = 0; j < board.getWidth(); ++j) { - Point point = new Point(j,i); - if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - } - } - } - /*Tests the Too Many Stars contradiction rule for a false contradiction. */ - @Test - public void TooManyStarsContradictionRule_FalseContradiction() - throws InvalidFileFormatException - { - TestUtilities.importTestBoard("puzzles/starbattle/rules/TooManyStarsContradictionRule/Correct", starBattle); - TreeNode rootNode = starBattle.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - StarBattleBoard board = (StarBattleBoard) transition.getBoard(); - - Assert.assertNotNull(RULE.checkContradiction((StarBattleBoard) transition.getBoard())); - - for (int i = 0; i < board.getHeight(); ++i) { - for (int j = 0; j < board.getWidth(); ++j) { - Point point = new Point(j,i); - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(j, i))); - } - } - } -} diff --git a/src/test/resources/puzzles/starbattle/rules/BlackoutDirectRule/Blackout visualized.png b/src/test/resources/puzzles/starbattle/rules/BlackoutDirectRule/Blackout visualized.png deleted file mode 100644 index e8670e07ebc8a447459428eb7fa375dec0672028..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14116 zcmeHN2~<;88h$S;U;r18BrIX6ic-fED4?tn0Z~DykfN;;B5HIPTuVi02us0*9c&#` zco1C5pv3A_1Sy0?)G8#PQ&b|0C{QIpMRsLg9x?c$_MG;#XY@=sCx>%#@BQz;eE;|V z_ud@v@%GTvplSdBpy|1M*(U%14$D4j1o)ei<`YryKlL5U*X{;@X)|RXutCBd2LNNh za~Z>L?=f~{Uza#4-j}Z7E;J|O`79k0t)ij=UIk1{u&GIPQzJ(}0zoDf9-y9S^^i|b zjAewQd$vi(spI#4usmkRjkK0dsho>ZsB9V_j9oBPW5G6vId*ONh|dhRX#4_L9F;&9rwZc#a(P z`$3OnBiH_4lEo3{CS~X<$pE0mLkDJ!`dnUe_mB(|I;79gf!hz%dS_Sua&zRVUgBKd zq&Zl$IRc_{)C+dNrAP{MyYyb^(YA(%7W@M&okSRSmjNsmJEf3-IL|wqT^u!G=+YAH>@U+it3Q!u23o%X0+zo%w07(^w7@Iv*hkN_eFUW#GhZG{VBk0sXI33-e(a*G_sct?C`{xTunuS zBN!B5o03n=!Se=^2PY%%N>x%Bd#futWy3ss#OMZe%mo<8zwf9`DAcr)uP2^#ueFjj zm^j%6i7zF5|C)rdC$}*CvSGyYsdy#NgV4sU-`$Q#h!#H%Mo{HCQ%OJYLa}b>z>+(Y z>v2l!fqbKtD>cYv-eHIrJCq>u+rz2E4%F&=^y*Y%roqaUA1Z_^4-+y`tAiD**_5O+ zzVuAcaZx<@tX(3JkTIATa&dS#d0CtrIW8`aY`1tZ`GYxggxi8Q<$E+XA_b@wjet}D z%6|Hq~c* zYp2Ts4xU573G|mOdOoI2x)|C*O|N zot|SIew_oQtFsP|bp_cW+8vzI4sJQX+tJx)>tJDom#X=pc@y*k3e$=H>-apnVg@?Z zz?;BnWX53!E`8l4gqcojp~wRC0#7$k&vfjJ6<_~KmQF6SltTt@((~8|e;O(%*>_R6XN-=JQaCdIISm6EP(i^xhCy)x)_bcP5>Mg0c|8 zR6U#;gp>xc&q2zML1j8bi6ZnoZOIRm8oxz2rxmT z6c$jQ?MQ1#dpbTM3Y$PsqlN|rJf-)3nLa#ap!>W+Ri)Aa;kVz{>M85sPwPQW09d7N z9>TkRamav___quCNbMz~(J?t}NnX#H>;is!p&C-ZE$onY?}7kW@mOJwxFg zV3oBwB}GT~FekLWYiTLMq!I-!vMHL+eCcH2ZfZ7L z&rrX1dTVE`@qz`F(+$X1ceHoRkHC$?pbp;BV6GQGLf}j8B;z5ir8`G|^ z7!`jVh7`LJC0d3sE#>_Crr!qo;Le)QzfWsEa7LfRjXE!RuvZV#g1^`eO@_!%kl`>2KGahCaP_D(@qF$y}@N{ zlbY2LVNwGxY!$hNozFG7OiNid1OJ0beTw)E(#?Fefv3u^F+yF)pi&@AO63+nlcY9)SPe zp9@V@yj1aehw6-q_ui9-5EXBzctgb-lc(W#*$=WN7=D5ZY7%U13;1EX%C z3l~0wYsytQYDPDES`F{NB@qf(Q@6h7|gO`z!@q6y=-~0%1#PLfb*>S0F z)WX>Oh{?x`xBeB65UTuA)mc@YRn=J)52$!R#RDoHQ1O6@2i_|lc*}2y0Q+gvs(vmC p?B5r6^ytyH&K&2z>^DSMAiV5b(X(G}o4}3(Jl(vPon6X``7dS?MOOd- diff --git a/src/test/resources/puzzles/starbattle/rules/BlackoutDirectRule/Corner b/src/test/resources/puzzles/starbattle/rules/BlackoutDirectRule/Corner deleted file mode 100644 index d1c6722e4..000000000 --- a/src/test/resources/puzzles/starbattle/rules/BlackoutDirectRule/Corner +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/test/resources/puzzles/starbattle/rules/BlackoutDirectRule/Edge b/src/test/resources/puzzles/starbattle/rules/BlackoutDirectRule/Edge deleted file mode 100644 index 7995657c9..000000000 --- a/src/test/resources/puzzles/starbattle/rules/BlackoutDirectRule/Edge +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/test/resources/puzzles/starbattle/rules/BlackoutDirectRule/Middle b/src/test/resources/puzzles/starbattle/rules/BlackoutDirectRule/Middle deleted file mode 100644 index b6f483244..000000000 --- a/src/test/resources/puzzles/starbattle/rules/BlackoutDirectRule/Middle +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/test/resources/puzzles/starbattle/rules/ClashingOrbitContradictionRule/DiagonallyAdjacent b/src/test/resources/puzzles/starbattle/rules/ClashingOrbitContradictionRule/DiagonallyAdjacent deleted file mode 100644 index f63daad23..000000000 --- a/src/test/resources/puzzles/starbattle/rules/ClashingOrbitContradictionRule/DiagonallyAdjacent +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/ClashingOrbitContradictionRule/DirectlyAdjacentCenter b/src/test/resources/puzzles/starbattle/rules/ClashingOrbitContradictionRule/DirectlyAdjacentCenter deleted file mode 100644 index b57a5989e..000000000 --- a/src/test/resources/puzzles/starbattle/rules/ClashingOrbitContradictionRule/DirectlyAdjacentCenter +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/ClashingOrbitContradictionRule/DirectlyAdjacentEdge b/src/test/resources/puzzles/starbattle/rules/ClashingOrbitContradictionRule/DirectlyAdjacentEdge deleted file mode 100644 index f5a23b081..000000000 --- a/src/test/resources/puzzles/starbattle/rules/ClashingOrbitContradictionRule/DirectlyAdjacentEdge +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/ClashingOrbitContradictionRule/FalseContradiction b/src/test/resources/puzzles/starbattle/rules/ClashingOrbitContradictionRule/FalseContradiction deleted file mode 100644 index 04a4a6f6c..000000000 --- a/src/test/resources/puzzles/starbattle/rules/ClashingOrbitContradictionRule/FalseContradiction +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/FalseStarOverlap b/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/FalseStarOverlap deleted file mode 100644 index 8a435e5d7..000000000 --- a/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/FalseStarOverlap +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/OneColumnOneCell b/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/OneColumnOneCell deleted file mode 100644 index 4d065b28f..000000000 --- a/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/OneColumnOneCell +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/PartialColumnOneCell b/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/PartialColumnOneCell deleted file mode 100644 index 5c3fc22cc..000000000 --- a/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/PartialColumnOneCell +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/PartialColumnTwoCells b/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/PartialColumnTwoCells deleted file mode 100644 index 463f3a6d7..000000000 --- a/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/PartialColumnTwoCells +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/TwoColumns b/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/TwoColumns deleted file mode 100644 index ad5e4d198..000000000 --- a/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/TwoColumns +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/TwoColumnsStarOverlap b/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/TwoColumnsStarOverlap deleted file mode 100644 index 8562a47a8..000000000 --- a/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRegionsDirectRule/TwoColumnsStarOverlap +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/FalseStarOverlap b/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/FalseStarOverlap deleted file mode 100644 index c0ac99a0b..000000000 --- a/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/FalseStarOverlap +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/NonAdjacentColumns b/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/NonAdjacentColumns deleted file mode 100644 index 8d71ffa4f..000000000 --- a/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/NonAdjacentColumns +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/OneColumn b/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/OneColumn deleted file mode 100644 index 9a4dccefd..000000000 --- a/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/OneColumn +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/TwoColumns b/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/TwoColumns deleted file mode 100644 index 5c13d38e6..000000000 --- a/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/TwoColumns +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/TwoColumnsStarOverlap b/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/TwoColumnsStarOverlap deleted file mode 100644 index fac44ff20..000000000 --- a/src/test/resources/puzzles/starbattle/rules/ColumnsWithinRowsDirectRule/TwoColumnsStarOverlap +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/EmptyAdjacentDirectRule/ImproperUseFourLeft b/src/test/resources/puzzles/starbattle/rules/EmptyAdjacentDirectRule/ImproperUseFourLeft deleted file mode 100644 index 782c1d37d..000000000 --- a/src/test/resources/puzzles/starbattle/rules/EmptyAdjacentDirectRule/ImproperUseFourLeft +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/EmptyAdjacentDirectRule/OneLeft b/src/test/resources/puzzles/starbattle/rules/EmptyAdjacentDirectRule/OneLeft deleted file mode 100644 index 29005798d..000000000 --- a/src/test/resources/puzzles/starbattle/rules/EmptyAdjacentDirectRule/OneLeft +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/EmptyAdjacentDirectRule/ThreeLeft b/src/test/resources/puzzles/starbattle/rules/EmptyAdjacentDirectRule/ThreeLeft deleted file mode 100644 index ab6f4b178..000000000 --- a/src/test/resources/puzzles/starbattle/rules/EmptyAdjacentDirectRule/ThreeLeft +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/EmptyAdjacentDirectRule/TwoLeft b/src/test/resources/puzzles/starbattle/rules/EmptyAdjacentDirectRule/TwoLeft deleted file mode 100644 index 5e8d71fbb..000000000 --- a/src/test/resources/puzzles/starbattle/rules/EmptyAdjacentDirectRule/TwoLeft +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/FinishWithStarsDirectRule/CornerColumn b/src/test/resources/puzzles/starbattle/rules/FinishWithStarsDirectRule/CornerColumn deleted file mode 100644 index ac0e35380..000000000 --- a/src/test/resources/puzzles/starbattle/rules/FinishWithStarsDirectRule/CornerColumn +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/test/resources/puzzles/starbattle/rules/FinishWithStarsDirectRule/CornerRow b/src/test/resources/puzzles/starbattle/rules/FinishWithStarsDirectRule/CornerRow deleted file mode 100644 index 3fb595a65..000000000 --- a/src/test/resources/puzzles/starbattle/rules/FinishWithStarsDirectRule/CornerRow +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/test/resources/puzzles/starbattle/rules/FinishWithStarsDirectRule/CornerRowColumn b/src/test/resources/puzzles/starbattle/rules/FinishWithStarsDirectRule/CornerRowColumn deleted file mode 100644 index 44fe2b9ba..000000000 --- a/src/test/resources/puzzles/starbattle/rules/FinishWithStarsDirectRule/CornerRowColumn +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/test/resources/puzzles/starbattle/rules/FinishWithStarsDirectRule/DoubleRegion b/src/test/resources/puzzles/starbattle/rules/FinishWithStarsDirectRule/DoubleRegion deleted file mode 100644 index 16171cd01..000000000 --- a/src/test/resources/puzzles/starbattle/rules/FinishWithStarsDirectRule/DoubleRegion +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/test/resources/puzzles/starbattle/rules/FinishWithStarsDirectRule/False b/src/test/resources/puzzles/starbattle/rules/FinishWithStarsDirectRule/False deleted file mode 100644 index 16ab2cc7c..000000000 --- a/src/test/resources/puzzles/starbattle/rules/FinishWithStarsDirectRule/False +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/test/resources/puzzles/starbattle/rules/FinishWithStarsDirectRule/Region b/src/test/resources/puzzles/starbattle/rules/FinishWithStarsDirectRule/Region deleted file mode 100644 index d3c74607f..000000000 --- a/src/test/resources/puzzles/starbattle/rules/FinishWithStarsDirectRule/Region +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/FalseStarOverlap b/src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/FalseStarOverlap deleted file mode 100644 index 812f00b66..000000000 --- a/src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/FalseStarOverlap +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/OneRegionOneCell b/src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/OneRegionOneCell deleted file mode 100644 index c459a9231..000000000 --- a/src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/OneRegionOneCell +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/OneRegionTwoCells b/src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/OneRegionTwoCells deleted file mode 100644 index 50a775d0b..000000000 --- a/src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/OneRegionTwoCells +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/PartialRegionOneCell b/src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/PartialRegionOneCell deleted file mode 100644 index 057dc96f0..000000000 --- a/src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/PartialRegionOneCell +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoRegionsOneCell b/src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoRegionsOneCell deleted file mode 100644 index 0ee0205ab..000000000 --- a/src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoRegionsOneCell +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoRegionsStarOverlap b/src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoRegionsStarOverlap deleted file mode 100644 index e7495cabf..000000000 --- a/src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoRegionsStarOverlap +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoRegionsTwoCells b/src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoRegionsTwoCells deleted file mode 100644 index cea670809..000000000 --- a/src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoRegionsTwoCells +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoRegionsTwoCells2 b/src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoRegionsTwoCells2 deleted file mode 100644 index 01ecce3ee..000000000 --- a/src/test/resources/puzzles/starbattle/rules/RegionsWithinColumnsDirectRule/TwoRegionsTwoCells2 +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/RegionsWithinRowsDirectRule/FalseStarOverlap b/src/test/resources/puzzles/starbattle/rules/RegionsWithinRowsDirectRule/FalseStarOverlap deleted file mode 100644 index a582d1c46..000000000 --- a/src/test/resources/puzzles/starbattle/rules/RegionsWithinRowsDirectRule/FalseStarOverlap +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/RegionsWithinRowsDirectRule/OneRegionOneCell b/src/test/resources/puzzles/starbattle/rules/RegionsWithinRowsDirectRule/OneRegionOneCell deleted file mode 100644 index 056b67059..000000000 --- a/src/test/resources/puzzles/starbattle/rules/RegionsWithinRowsDirectRule/OneRegionOneCell +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/RegionsWithinRowsDirectRule/PartialRegionOneCell b/src/test/resources/puzzles/starbattle/rules/RegionsWithinRowsDirectRule/PartialRegionOneCell deleted file mode 100644 index eb9a69787..000000000 --- a/src/test/resources/puzzles/starbattle/rules/RegionsWithinRowsDirectRule/PartialRegionOneCell +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/RegionsWithinRowsDirectRule/PartialRegionTwoCells b/src/test/resources/puzzles/starbattle/rules/RegionsWithinRowsDirectRule/PartialRegionTwoCells deleted file mode 100644 index 0654ed4dc..000000000 --- a/src/test/resources/puzzles/starbattle/rules/RegionsWithinRowsDirectRule/PartialRegionTwoCells +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/RegionsWithinRowsDirectRule/StarOverlap b/src/test/resources/puzzles/starbattle/rules/RegionsWithinRowsDirectRule/StarOverlap deleted file mode 100644 index 5a6901ead..000000000 --- a/src/test/resources/puzzles/starbattle/rules/RegionsWithinRowsDirectRule/StarOverlap +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/RegionsWithinRowsDirectRule/TwoRegionsOneCell b/src/test/resources/puzzles/starbattle/rules/RegionsWithinRowsDirectRule/TwoRegionsOneCell deleted file mode 100644 index 4e19386e4..000000000 --- a/src/test/resources/puzzles/starbattle/rules/RegionsWithinRowsDirectRule/TwoRegionsOneCell +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/StarOrEmptyCaseRule/SimpleStarOrEmpty b/src/test/resources/puzzles/starbattle/rules/StarOrEmptyCaseRule/SimpleStarOrEmpty deleted file mode 100644 index 4d065b28f..000000000 --- a/src/test/resources/puzzles/starbattle/rules/StarOrEmptyCaseRule/SimpleStarOrEmpty +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/SurroundStarDirectRule/CenterStar b/src/test/resources/puzzles/starbattle/rules/SurroundStarDirectRule/CenterStar deleted file mode 100644 index a22f988df..000000000 --- a/src/test/resources/puzzles/starbattle/rules/SurroundStarDirectRule/CenterStar +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/SurroundStarDirectRule/CornerStar b/src/test/resources/puzzles/starbattle/rules/SurroundStarDirectRule/CornerStar deleted file mode 100644 index 50558d4c4..000000000 --- a/src/test/resources/puzzles/starbattle/rules/SurroundStarDirectRule/CornerStar +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/Column b/src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/Column deleted file mode 100644 index 1d1004b8b..000000000 --- a/src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/Column +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/FalseContradiction b/src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/FalseContradiction deleted file mode 100644 index 0c377a58b..000000000 --- a/src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/FalseContradiction +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/NotEnoughSpace b/src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/NotEnoughSpace deleted file mode 100644 index 9280cefdd..000000000 --- a/src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/NotEnoughSpace +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/Region b/src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/Region deleted file mode 100644 index 2594f46e5..000000000 --- a/src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/Region +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/Row b/src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/Row deleted file mode 100644 index 67c36c5e8..000000000 --- a/src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/Row +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/TwoStarColumn b/src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/TwoStarColumn deleted file mode 100644 index d781b3092..000000000 --- a/src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/TwoStarColumn +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/TwoStarFalseContradiction b/src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/TwoStarFalseContradiction deleted file mode 100644 index 5f1d2753f..000000000 --- a/src/test/resources/puzzles/starbattle/rules/TooFewStarsContradictionRule/TwoStarFalseContradiction +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle/rules/TooManyStarsContradictionRule/ColumnOverloaded b/src/test/resources/puzzles/starbattle/rules/TooManyStarsContradictionRule/ColumnOverloaded deleted file mode 100644 index 4e7170b3e..000000000 --- a/src/test/resources/puzzles/starbattle/rules/TooManyStarsContradictionRule/ColumnOverloaded +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/test/resources/puzzles/starbattle/rules/TooManyStarsContradictionRule/Correct b/src/test/resources/puzzles/starbattle/rules/TooManyStarsContradictionRule/Correct deleted file mode 100644 index 15921e601..000000000 --- a/src/test/resources/puzzles/starbattle/rules/TooManyStarsContradictionRule/Correct +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/test/resources/puzzles/starbattle/rules/TooManyStarsContradictionRule/Region Overloaded Visualized-01.png b/src/test/resources/puzzles/starbattle/rules/TooManyStarsContradictionRule/Region Overloaded Visualized-01.png deleted file mode 100644 index bfe24d1a4d590cb68956d91e1c94f408f0fde414..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15488 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 diff --git a/src/test/resources/puzzles/starbattle/rules/TooManyStarsContradictionRule/RegionOverloaded b/src/test/resources/puzzles/starbattle/rules/TooManyStarsContradictionRule/RegionOverloaded deleted file mode 100644 index bcf4a679a..000000000 --- a/src/test/resources/puzzles/starbattle/rules/TooManyStarsContradictionRule/RegionOverloaded +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/test/resources/puzzles/starbattle/rules/TooManyStarsContradictionRule/RowOverloaded b/src/test/resources/puzzles/starbattle/rules/TooManyStarsContradictionRule/RowOverloaded deleted file mode 100644 index fdf1adc11..000000000 --- a/src/test/resources/puzzles/starbattle/rules/TooManyStarsContradictionRule/RowOverloaded +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    <7q||v7G5P(!KZzu<6r*cZ}SV6)%O;bEqCws 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 diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/UnbalancedColumnContradictionRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/UnbalancedColumnContradictionRule.png deleted file mode 100644 index 17a658e427c7ef23f941f0185f764a75b9c7f58d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 50546 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 f-;tzWdHxaMFiaKLCbJBK!K^%X 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 From cf59a17f63063f36359c18d2a5ffb5faa0b43593 Mon Sep 17 00:00:00 2001 From: Brandon McCusker Date: Fri, 12 Apr 2024 19:54:53 -0400 Subject: [PATCH 085/258] Added Wiki Contributions --- WikiContributions.md | 68 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 WikiContributions.md diff --git a/WikiContributions.md b/WikiContributions.md new file mode 100644 index 000000000..f0ba97334 --- /dev/null +++ b/WikiContributions.md @@ -0,0 +1,68 @@ +# Binary +Binary is a grid based puzzle game akin to Sudoku. You are given a grid of empty squares and squares filled with 1 or 0. Your task is to fill the board with 1s and 0s while adhering to the rules of the game. + +Each binary puzzle has a unique solution. It is always possible to make a next step by reasoning. In other words, the solution can always be found without guessing. + +### Interacting with the Binary Board +Clicking on a white square fills it with a 0 + +Clicking on a square with a 0 fills it with a 1 + +Clicking on a square with a 1 returns it white + +# Rules +### Here are the direct rules of the puzzle +1) Each square should contain either a zero or a one. +2) Three orthogonally adjacent zeros or ones is not allowed. +3) Each row and each column should contain an equal number of zeros and ones. +4) Each row is unique and each column is unique. Thus, any row cannot be exactly equal to another row, and any column cannot be exactly equal to another column. + +# LEGUP Proof Rules + +## Case Rules + +### One or Zero + +[![JvzOzNe.th.png](https://iili.io/JvzOzNe.th.png)](https://freeimage.host/i/JvzOzNe) + +This rule is a direct consequence of rule #1. If a tile can be filled with a 0 or a 1 based on the current state of the board, create a split in the tree where the tile is a 0 in one path and 1 in the other to show two possible cases. + +## Contradiction Rules + +### Three in a Row + +[![Jvz8tYQ.th.png](https://iili.io/Jvz8tYQ.th.png)](https://freeimage.host/i/Jvz8tYQ) + +This rule is a direct consequence of Rule #2. If a sequence of three of the same digit exists on the board, then the board is in a state of contradiction. + +### Unbalanced Row/Column Rule + +[![Jvzr9Z7.th.png](https://iili.io/Jvzr9Z7.th.png)](https://freeimage.host/i/Jvzr9Z7) + +This rule is a direct consequence of Rule #3. If a row or column contains more of one digit than the other, then the board is in a state of contradiction. + +### Identical Row/Column Rule + +[![JvzrpUJ.th.png](https://iili.io/JvzrpUJ.th.png)](https://freeimage.host/i/JvzrpUJ) + +This rule is a direct consequence of Rule #4. If a row is identical to another row or a column is identical to another column, then the board is in a state of contradiction. + +## Direct Rules + +### Surround Pair + +[![Jvzs8an.th.png](https://iili.io/Jvzs8an.th.png)](https://freeimage.host/i/Jvzs8an) + +This rule is a direct consequence of Rule #2. If two of the same digit exist adjacent to each other in any given row or column, then in order to avoid violating Rule #2, the pair must be surrounded with other digit on both sides. + +### One Tile Gap + +[![JvzLAFt.th.png](https://iili.io/JvzLAFt.th.png)](https://freeimage.host/i/JvzLAFt) + +This rule is a direct consequence of Rule #2. If two of the same digit exist with a one tile gap between them, then in order to avoid violating Rule #2, the pair must be separated by placing the other digit between them. + +### Complete Row/Column + +[![JvztVKN.th.png](https://iili.io/JvztVKN.th.png)](https://freeimage.host/i/JvztVKN) + +This rule is a direct consequence of Rules #2 and #3. If a row or column is completely filled with 1s and 0s, there does not exist a grouping of three 1s or 0s anywhere in the row or column, and the row or column is unique then the row contains no contradictions. \ No newline at end of file From 15f66434d09e017d05cd9bd691132c59498f4dca Mon Sep 17 00:00:00 2001 From: Brandon McCusker Date: Fri, 12 Apr 2024 19:56:13 -0400 Subject: [PATCH 086/258] Added Binary Puzzle Presentation --- LEGUP Binary Puzzle Progress.pptx | Bin 0 -> 317431 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 LEGUP Binary Puzzle Progress.pptx diff --git a/LEGUP Binary Puzzle Progress.pptx b/LEGUP Binary Puzzle Progress.pptx new file mode 100644 index 0000000000000000000000000000000000000000..b1d96fa1323b0ae39677a4b95b75f6d6ad556657 GIT binary patch literal 317431 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