();
+ Point cellLoc = cell.getLocation();
+ for (int i=-1; i <= 1; i++) {
+ for (int j=-1; j <= 1; j++) {
+ if (cellLoc.getX() + i < 0 || cellLoc.y + j < 0 || cellLoc.x + i >= board.getWidth() || cellLoc.y + j >= board.getHeight()) {
+ continue;
+ }
+ FillapixCell adjCell = board.getCell(cellLoc.x + i, cellLoc.y + j);
+ if (adjCell == null) {
+ continue;
+ }
+ adjCells.add(adjCell);
+ }
+ }
+ return adjCells;
+ }
+
+ /**
+ * Gets all cells that are contained in the square defined as having 'distance'
+ * cells between the center and the outer wall. For example, distance = 1:
+ * |X|X|X|X|X|
+ * |X| | | |X|
+ * |X| |O| |X|
+ * |X| | | |X|
+ * |X|X|X|X|X|
+ * O is 'cell', and all 'X' will be returned in the ArrayList
+ */
+ public static ArrayList getCellsAtDistance(FillapixBoard board, FillapixCell cell, int distance) {
+ ArrayList adjCells = new ArrayList();
+ Point cellLoc = cell.getLocation();
+ int i = 0, j = 0;
+ // top line
+ for (i = cellLoc.x - (distance), j = cellLoc.y - (distance+1); i <= cellLoc.x + (distance+1); i++) {
+ if (cellLoc.getX() + i < 0 || cellLoc.y + j < 0 || cellLoc.x + i >= board.getWidth() || cellLoc.y + j >= board.getHeight()) {
+ continue;
+ }
+ FillapixCell adjCell = board.getCell(cellLoc.x + i, cellLoc.y + j);
+ if (adjCell == null) {
+ continue;
+ }
+ adjCells.add(adjCell);
+ }
+ // right line
+ for (i = cellLoc.x + (distance+1), j = cellLoc.y - (distance); j <= cellLoc.y + (distance+1); j++) {
+ if (cellLoc.getX() + i < 0 || cellLoc.y + j < 0 || cellLoc.x + i >= board.getWidth() || cellLoc.y + j >= board.getHeight()) {
+ continue;
+ }
+ FillapixCell adjCell = board.getCell(cellLoc.x + i, cellLoc.y + j);
+ if (adjCell == null) {
+ continue;
+ }
+ adjCells.add(adjCell);
+ }
+ // bottom line
+ for (i = cellLoc.x + (distance), j = cellLoc.y + (distance+1); i <= cellLoc.x - (distance+1); i--) {
+ if (cellLoc.getX() + i < 0 || cellLoc.y + j < 0 || cellLoc.x + i >= board.getWidth() || cellLoc.y + j >= board.getHeight()) {
+ continue;
+ }
+ FillapixCell adjCell = board.getCell(cellLoc.x + i, cellLoc.y + j);
+ if (adjCell == null) {
+ continue;
+ }
+ adjCells.add(adjCell);
+ }
+ // left line
+ for (i = cellLoc.x - (distance+1), j = cellLoc.y + (distance); j <= cellLoc.y - (distance+1); j--) {
+ if (cellLoc.getX() + i < 0 || cellLoc.y + j < 0 || cellLoc.x + i >= board.getWidth() || cellLoc.y + j >= board.getHeight()) {
+ continue;
+ }
+ FillapixCell adjCell = board.getCell(cellLoc.x + i, cellLoc.y + j);
+ if (adjCell == null) {
+ continue;
+ }
+ adjCells.add(adjCell);
+ }
+
+ return adjCells;
+ }
+
+ /**
+ * Finds all possible combinations of chosenNumObj
items can be
+ * chosen from totalNumObj
total items.
+ * For example, if 1 item is chosen from 2 possible items, the combinations
+ * are:
+ * [ [true,false], [false,true] ]
+ *
+ * @param totalNumItems the total number of items that can possibly be chosen
+ * @param chosenNumItems the number of items to be chosen
+ *
+ * @return an ArrayList of Boolean arrays. Each index in the ArrayList represents
+ * a distinct combination. Each Boolean array will be totalNumItems
+ * long and each index will be true
if the corresponding item is
+ * included in that combination, and false
otherwise.
+ */
+ public static ArrayList getCombinations(int chosenNumItems, int totalNumItems) {
+ ArrayList combinations = new ArrayList();
+
+ // calculate all combinations
+ boolean[] array = new boolean[totalNumItems];
+ recurseCombinations(combinations, 0, chosenNumItems, 0, totalNumItems, array);
+
+ return combinations;
+ }
+
+ private static void recurseCombinations(ArrayList result, int curIndex, int maxBlack, int numBlack, int len, boolean[] workingArray) {
+ if (curIndex == len) {
+ // complete, but not valid solution
+ if (numBlack != maxBlack) {
+ return;
+ }
+ // complete and valid solution
+ result.add(workingArray.clone());
+ return;
+ }
+ // there is no chance of completing the required number of solutions, so quit
+ if (len - curIndex < maxBlack - numBlack) {
+ return;
+ }
+
+ if (numBlack < maxBlack) {
+ workingArray[curIndex] = true;
+ recurseCombinations(result, curIndex+1, maxBlack, numBlack+1, len, workingArray);
+ }
+ workingArray[curIndex] = false;
+ recurseCombinations(result, curIndex+1, maxBlack, numBlack, len, workingArray);
+ }
+
+ public static boolean checkBoardForContradiction(FillapixBoard board) {
+ ContradictionRule tooManyBlack = new TooManyBlackCellsContradictionRule();
+ ContradictionRule tooManyWhite = new TooFewBlackCellsContradictionRule();
+ for (int i= 0; i < board.getWidth(); i++) {
+ for (int j=0; j < board.getHeight(); j++) {
+ if (tooManyBlack.checkContradictionAt(board, board.getCell(i, j)) == null ||
+ tooManyWhite.checkContradictionAt(board, board.getCell(i, j)) == null) {
+ return true;
+ }
+ }
+ }
+ return false;
}
}
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
new file mode 100644
index 000000000..7e43fc6b4
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/BlackTile.java
@@ -0,0 +1,9 @@
+package edu.rpi.legup.puzzle.fillapix.elements;
+
+import edu.rpi.legup.model.elements.PlaceableElement;
+
+public class BlackTile extends PlaceableElement {
+ public BlackTile() {
+ super("FPIX-PLAC-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
new file mode 100644
index 000000000..beee70e21
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/NumberTile.java
@@ -0,0 +1,27 @@
+package edu.rpi.legup.puzzle.fillapix.elements;
+
+import edu.rpi.legup.model.elements.NonPlaceableElement;
+
+public class NumberTile extends NonPlaceableElement {
+ private int object_num;
+
+ public NumberTile() {
+ super("FPIX-UNPL-0001", "Number Tile", "A numbered tile", "edu/rpi/legup/images/fillapix/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;
+ }
+
+}
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
new file mode 100644
index 000000000..ef754782f
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/UnknownTile.java
@@ -0,0 +1,9 @@
+package edu.rpi.legup.puzzle.fillapix.elements;
+
+import edu.rpi.legup.model.elements.NonPlaceableElement;
+
+public class UnknownTile extends NonPlaceableElement {
+ public UnknownTile() {
+ super("FPIX-UNPL-0002", "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
new file mode 100644
index 000000000..dd27d2834
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/WhiteTile.java
@@ -0,0 +1,9 @@
+package edu.rpi.legup.puzzle.fillapix.elements;
+
+import edu.rpi.legup.model.elements.PlaceableElement;
+
+public class WhiteTile extends PlaceableElement {
+ public WhiteTile() {
+ super("FPIX-PLAC-0002", "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
new file mode 100644
index 000000000..0409fa800
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/fillapix_elements_reference_sheet.txt
@@ -0,0 +1,5 @@
+FPIX-PLAC-0001 : BlackTile
+FPIX-PLAC-0002 : WhiteTile
+
+FPIX-UNPL-0001 : NumberTile
+FPIX-UNPL-0002 : UnknownTile
\ No newline at end of file
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 fd6b7c022..1e5151c48 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
@@ -40,13 +40,13 @@ public ArrayList getCases(Board board, PuzzleElement puzzleElement) {
Board case1 = board.copy();
FillapixCell cell1 = (FillapixCell) case1.getPuzzleElement(puzzleElement);
- cell1.setType(FillapixCellType.BLACK);
+ cell1.setCellType(FillapixCellType.BLACK);
case1.addModifiedData(cell1);
cases.add(case1);
Board case2 = board.copy();
FillapixCell cell2 = (FillapixCell) case2.getPuzzleElement(puzzleElement);
- cell2.setType(FillapixCellType.WHITE);
+ cell2.setCellType(FillapixCellType.WHITE);
case2.addModifiedData(cell2);
cases.add(case2);
diff --git a/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/FinishWithBlackDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/FinishWithBlackDirectRule.java
index afd226693..06a8045ed 100644
--- a/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/FinishWithBlackDirectRule.java
+++ b/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/FinishWithBlackDirectRule.java
@@ -8,6 +8,7 @@
import edu.rpi.legup.puzzle.fillapix.FillapixBoard;
import edu.rpi.legup.puzzle.fillapix.FillapixCell;
import edu.rpi.legup.puzzle.fillapix.FillapixCellType;
+import edu.rpi.legup.puzzle.fillapix.FillapixUtilities;
public class FinishWithBlackDirectRule extends DirectRule {
public FinishWithBlackDirectRule() {
@@ -28,7 +29,7 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem
return super.getInvalidUseOfRuleMessage() + ": This cell must be black to be applicable with this rule.";
}
- if (isForcedBlack(parentBoard, cell)) {
+ if (FillapixUtilities.isForcedBlack(parentBoard, cell)) {
return null;
}
else {
@@ -36,14 +37,6 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem
}
}
- private boolean isForcedBlack(FillapixBoard board, FillapixCell cell) {
- TooFewBlackCellsContradictionRule tooManyBlackCells = new TooFewBlackCellsContradictionRule();
- FillapixBoard whiteCaseBoard = board.copy();
- FillapixCell whiteCell = (FillapixCell) whiteCaseBoard.getPuzzleElement(cell);
- whiteCell.setType(FillapixCellType.WHITE);
- return tooManyBlackCells.checkContradictionAt(whiteCaseBoard, cell) == null;
- }
-
/**
* Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}.
*
@@ -55,8 +48,8 @@ public Board getDefaultBoard(TreeNode node) {
FillapixBoard fillapixBoard = (FillapixBoard) node.getBoard().copy();
for (PuzzleElement element : fillapixBoard.getPuzzleElements()) {
FillapixCell cell = (FillapixCell) element;
- if (cell.getType() == FillapixCellType.UNKNOWN && isForcedBlack((FillapixBoard) node.getBoard(), cell)) {
- cell.setType(FillapixCellType.BLACK);
+ if (cell.getType() == FillapixCellType.UNKNOWN && FillapixUtilities.isForcedBlack((FillapixBoard) node.getBoard(), cell)) {
+ cell.setCellType(FillapixCellType.BLACK);
fillapixBoard.addModifiedData(cell);
}
}
diff --git a/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/FinishWithWhiteDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/FinishWithWhiteDirectRule.java
index ec482d5f7..7e213a59c 100644
--- a/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/FinishWithWhiteDirectRule.java
+++ b/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/FinishWithWhiteDirectRule.java
@@ -8,10 +8,11 @@
import edu.rpi.legup.puzzle.fillapix.FillapixBoard;
import edu.rpi.legup.puzzle.fillapix.FillapixCell;
import edu.rpi.legup.puzzle.fillapix.FillapixCellType;
+import edu.rpi.legup.puzzle.fillapix.FillapixUtilities;
public class FinishWithWhiteDirectRule extends DirectRule {
public FinishWithWhiteDirectRule() {
- super("FFIX-BASC-0002",
+ super("FPIX-BASC-0002",
"Finish with White",
"The remaining unknowns around and on a cell must be white to satisfy the number",
"edu/rpi/legup/images/fillapix/rules/FinishWithWhite.png");
@@ -28,7 +29,7 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem
return super.getInvalidUseOfRuleMessage() + ": This cell must be white to be applicable with this rule";
}
- if (isForcedWhite(parentBoard, cell)) {
+ if (FillapixUtilities.isForcedWhite(parentBoard, cell)) {
return null;
}
else {
@@ -36,14 +37,6 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem
}
}
- private boolean isForcedWhite(FillapixBoard board, FillapixCell cell) {
- TooManyBlackCellsContradictionRule tooManyBlackCells = new TooManyBlackCellsContradictionRule();
- FillapixBoard blackCaseBoard = board.copy();
- FillapixCell blackCell = (FillapixCell) blackCaseBoard.getPuzzleElement(cell);
- blackCell.setType(FillapixCellType.BLACK);
- return tooManyBlackCells.checkContradictionAt(blackCaseBoard, cell) == null;
- }
-
/**
* Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}.
*
@@ -55,8 +48,8 @@ public Board getDefaultBoard(TreeNode node) {
FillapixBoard fillapixBoard = (FillapixBoard) node.getBoard().copy();
for (PuzzleElement element : fillapixBoard.getPuzzleElements()) {
FillapixCell cell = (FillapixCell) element;
- if (cell.getType() == FillapixCellType.UNKNOWN && isForcedWhite((FillapixBoard) node.getBoard(), cell)) {
- cell.setType(FillapixCellType.WHITE);
+ if (cell.getType() == FillapixCellType.UNKNOWN && FillapixUtilities.isForcedWhite((FillapixBoard) node.getBoard(), cell)) {
+ cell.setCellType(FillapixCellType.WHITE);
fillapixBoard.addModifiedData(cell);
}
}
diff --git a/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/MirrorDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/MirrorDirectRule.java
new file mode 100644
index 000000000..656cedb3f
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/MirrorDirectRule.java
@@ -0,0 +1,103 @@
+package edu.rpi.legup.puzzle.fillapix.rules;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import edu.rpi.legup.model.gameboard.Board;
+import edu.rpi.legup.model.gameboard.PuzzleElement;
+import edu.rpi.legup.model.rules.CaseRule;
+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.fillapix.FillapixBoard;
+import edu.rpi.legup.puzzle.fillapix.FillapixCell;
+import edu.rpi.legup.puzzle.fillapix.FillapixCellType;
+import edu.rpi.legup.puzzle.fillapix.FillapixUtilities;
+
+public class MirrorDirectRule extends DirectRule {
+ public MirrorDirectRule() {
+ super("FPIX-BASC-0003",
+ "Mirror",
+ "Two adjacent clues with the same value must have the same number of black squares in their unshared regions",
+ "edu/rpi/legup/images/fillapix/rules/Mirror.png");
+ }
+
+ @Override
+ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) {
+ FillapixBoard board = (FillapixBoard) transition.getBoard();
+ FillapixBoard parentBoard = (FillapixBoard) transition.getParents().get(0).getBoard().copy();
+ FillapixCell cell = (FillapixCell) board.getPuzzleElement(puzzleElement);
+ FillapixCell parentCell = (FillapixCell) parentBoard.getPuzzleElement(puzzleElement);
+
+ // cell has to have been empty before
+ if (parentCell.getType() != FillapixCellType.UNKNOWN) {
+ return super.getInvalidUseOfRuleMessage();
+ }
+
+ // parentBoard cannot have any contradictions
+ if (FillapixUtilities.checkBoardForContradiction(parentBoard)) {
+ return super.getInvalidUseOfRuleMessage();
+ }
+
+ // find all cells adjacent to cell that are numbered
+ ArrayList adjCells = FillapixUtilities.getAdjacentCells(parentBoard, parentCell);
+ ArrayList adjNums = new ArrayList();
+ for (int i=0; i < adjCells.size(); i++) {
+ if ((adjCells.get(i)).getNumber() >= 0 && adjCells.get(i).getNumber() < 10) {
+ adjNums.add(adjCells.get(i));
+ }
+ }
+ // the numbered cells must be next to another numbered cell of the same value
+ Iterator itr = adjNums.iterator();
+ while (itr.hasNext()) {
+ FillapixCell adjNum = itr.next();
+ adjCells = FillapixUtilities.getAdjacentCells(parentBoard, adjNum);
+ boolean found = false;
+ for (FillapixCell adjCell : adjCells) {
+ if (adjCell.getNumber() == adjNum.getNumber() && adjCell.getIndex() != adjNum.getIndex()) {
+ found = true;
+ }
+ }
+ if (!found) {
+ itr.remove();
+ }
+ }
+
+ // change the color of the parentCell, and check if there exists a valid board
+ if (cell.getType() == FillapixCellType.BLACK) {
+ parentCell.setCellType(FillapixCellType.WHITE);
+ }
+ else {
+ parentCell.setCellType(FillapixCellType.BLACK);
+ }
+ parentBoard.addModifiedData(parentCell);
+ CaseRule completeClue = new SatisfyClueCaseRule();
+ List caseBoards;
+ for (FillapixCell adjNum : adjNums) {
+ caseBoards = completeClue.getCases(parentBoard, adjNum);
+ boolean found = true;
+ for (Board b : caseBoards) {
+ if (!FillapixUtilities.checkBoardForContradiction((FillapixBoard) b)) {
+ found = false;
+ }
+ }
+ if (found) {
+ return null;
+ }
+ }
+
+ return super.getInvalidUseOfRuleMessage();
+ }
+
+ /**
+ * 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
diff --git a/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/NonTouchingSharedDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/NonTouchingSharedDirectRule.java
new file mode 100644
index 000000000..fe94dbcb4
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/NonTouchingSharedDirectRule.java
@@ -0,0 +1,99 @@
+package edu.rpi.legup.puzzle.fillapix.rules;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import edu.rpi.legup.model.gameboard.Board;
+import edu.rpi.legup.model.gameboard.PuzzleElement;
+import edu.rpi.legup.model.rules.CaseRule;
+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.fillapix.FillapixBoard;
+import edu.rpi.legup.puzzle.fillapix.FillapixCell;
+import edu.rpi.legup.puzzle.fillapix.FillapixCellType;
+import edu.rpi.legup.puzzle.fillapix.FillapixUtilities;
+
+public class NonTouchingSharedDirectRule extends DirectRule {
+ public NonTouchingSharedDirectRule() {
+ super("FPIX-BASC-0005",
+ "NonTouching Shared",
+ "Clues with shared cells have the same difference in black cells in their unshared regions as the difference in their numbers",
+ "edu/rpi/legup/images/fillapix/rules/TouchingSides.png");
+ }
+
+ @Override
+ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) {
+ FillapixBoard board = (FillapixBoard) transition.getBoard();
+ FillapixBoard parentBoard = (FillapixBoard) transition.getParents().get(0).getBoard().copy();
+ FillapixCell cell = (FillapixCell) board.getPuzzleElement(puzzleElement);
+ FillapixCell parentCell = (FillapixCell) parentBoard.getPuzzleElement(puzzleElement);
+
+ // cell has to have been empty before
+ if (parentCell.getType() != FillapixCellType.UNKNOWN) {
+ return super.getInvalidUseOfRuleMessage();
+ }
+
+ // parentBoard cannot have any contradictions
+ if (FillapixUtilities.checkBoardForContradiction(parentBoard)) {
+ return super.getInvalidUseOfRuleMessage();
+ }
+
+ // get all adjCells that have a number
+ ArrayList adjCells = FillapixUtilities.getAdjacentCells(parentBoard, parentCell);
+ adjCells.removeIf(x -> x.getNumber() < 0 || x.getNumber() >= 10);
+ /* remove any number cell that does not have another number cell not
+ * touching, but sharing cells */
+ Iterator itr = adjCells.iterator();
+ while (itr.hasNext()) {
+ ArrayList sharingCells = FillapixUtilities.getCellsAtDistance(parentBoard, parentCell, 1);
+ boolean found = false;
+ for (FillapixCell sharingCell : sharingCells) {
+ if (sharingCell.getNumber() >= 0 && sharingCell.getNumber() < 10) {
+ found = true;
+ }
+ }
+ if (!found) {
+ itr.remove();
+ }
+ }
+
+ // change the cell to the opposite color
+ if (cell.getType() == FillapixCellType.BLACK) {
+ parentCell.setCellType(FillapixCellType.WHITE);
+ }
+ else {
+ parentCell.setCellType(FillapixCellType.BLACK);
+ }
+ // check for some contradiction in all cases
+ parentBoard.addModifiedData(parentCell);
+ CaseRule completeClue = new SatisfyClueCaseRule();
+ List caseBoards;
+ for (FillapixCell adjCell : adjCells) {
+ caseBoards = completeClue.getCases(parentBoard, adjCell);
+ boolean found = true;
+ for (Board b : caseBoards) {
+ if (!FillapixUtilities.checkBoardForContradiction((FillapixBoard) b)) {
+ found = false;
+ }
+ }
+ if (found) {
+ return null;
+ }
+ }
+
+ return super.getInvalidUseOfRuleMessage();
+ }
+
+ /**
+ * 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
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
new file mode 100644
index 000000000..4520add31
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/SatisfyClueCaseRule.java
@@ -0,0 +1,234 @@
+package edu.rpi.legup.puzzle.fillapix.rules;
+
+import java.awt.Point;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+
+import edu.rpi.legup.model.gameboard.Board;
+import edu.rpi.legup.model.gameboard.CaseBoard;
+import edu.rpi.legup.model.gameboard.PuzzleElement;
+import edu.rpi.legup.model.rules.CaseRule;
+import edu.rpi.legup.model.tree.TreeNode;
+import edu.rpi.legup.model.tree.TreeTransition;
+import edu.rpi.legup.puzzle.fillapix.FillapixBoard;
+import edu.rpi.legup.puzzle.fillapix.FillapixCell;
+import edu.rpi.legup.puzzle.fillapix.FillapixCellType;
+import edu.rpi.legup.puzzle.fillapix.FillapixUtilities;
+
+public class SatisfyClueCaseRule extends CaseRule {
+ public SatisfyClueCaseRule() {
+ super("FPIX-CASE-0002",
+ "Satisfy Clue",
+ "Each clue must touch that number of squares.",
+ "edu/rpi/legup/images/fillapix/cases/SatisfyClue.png");
+ }
+
+ @Override
+ public CaseBoard getCaseBoard(Board board) {
+ FillapixBoard fillapixBoard = (FillapixBoard) board.copy();
+ CaseBoard caseBoard = new CaseBoard(fillapixBoard, this);
+ fillapixBoard.setModifiable(false);
+ for (PuzzleElement data : fillapixBoard.getPuzzleElements()) {
+ FillapixCell cell = (FillapixCell) data;
+ if (cell.getNumber() >= 0 && cell.getNumber() <= 9 && FillapixUtilities.hasEmptyAdjacent(fillapixBoard, cell)) {
+ caseBoard.addPickableElement(data);
+ }
+ }
+ return caseBoard;
+ }
+
+ @Override
+ public ArrayList getCases(Board board, PuzzleElement puzzleElement) {
+ ArrayList cases = new ArrayList();
+
+ // get value of cell
+ FillapixBoard fillapixBoard = (FillapixBoard) board.copy();
+ FillapixCell cell = (FillapixCell) fillapixBoard.getPuzzleElement(puzzleElement);
+ int cellMaxBlack = cell.getNumber();
+ if (cellMaxBlack < 0 || cellMaxBlack > 9) { // cell is not valid cell
+ return null;
+ }
+
+ // find number of black & empty squares
+ int cellNumBlack = 0;
+ int cellNumEmpty = 0;
+ ArrayList emptyCells = new ArrayList();
+ ArrayList adjCells = FillapixUtilities.getAdjacentCells(fillapixBoard, cell);
+ for (FillapixCell adjCell : adjCells) {
+ if (adjCell.getType() == FillapixCellType.BLACK) {
+ cellNumBlack++;
+ }
+ if (adjCell.getType() == FillapixCellType.UNKNOWN) {
+ cellNumEmpty++;
+ emptyCells.add(adjCell);
+ }
+ }
+ // no cases if no empty or if too many black already
+ if (cellNumBlack > cellMaxBlack || cellNumEmpty == 0) {
+ return cases;
+ }
+
+ // generate all cases as boolean expressions
+ ArrayList combinations;
+ combinations = FillapixUtilities.getCombinations(cellMaxBlack - cellNumBlack, cellNumEmpty);
+
+ for (int i=0; i < combinations.size(); i++) {
+ Board case_ = board.copy();
+ for (int j=0; j < combinations.get(i).length; j++) {
+ cell = (FillapixCell) case_.getPuzzleElement(emptyCells.get(j));
+ if (combinations.get(i)[j]) {
+ cell.setCellType(FillapixCellType.BLACK);
+ }
+ else {
+ cell.setCellType(FillapixCellType.WHITE);
+ }
+ case_.addModifiedData(cell);
+ }
+ cases.add(case_);
+ }
+
+ return cases;
+ }
+
+ @Override
+ public String checkRuleRaw(TreeTransition transition) {
+ TreeNode parent = transition.getParents().get(0);
+ List childTransitions = parent.getChildren();
+
+ /*
+ * In order for the transition to be valid, it can only be applied to
+ * one cell, thus:
+ * * there must be modified cells
+ * * all modified cells must share at least one common adjacent
+ * cell
+ * * all modified cells must fit within a 3X3 square
+ * * the center of one of the possible squaress must be a cell
+ * with a number
+ * * that cells possible combinations must match the transitions
+ * If all the above is verified, then the transition is valid
+ */
+
+
+ /* ensure there are modified cells */
+ Set modCells = transition.getBoard().getModifiedData();
+ if (modCells.size() <= 0) {
+ return super.getInvalidUseOfRuleMessage();
+ }
+
+
+ /* ensure modified cells occur within a 3X3 square */
+ int minVertLoc = Integer.MAX_VALUE, maxVertLoc = Integer.MIN_VALUE;
+ int minHorzLoc = Integer.MAX_VALUE, maxHorzLoc = Integer.MIN_VALUE;
+ for (PuzzleElement modCell : modCells) {
+ Point loc = ((FillapixCell) modCell).getLocation();
+ if (loc.x < minHorzLoc) {
+ minHorzLoc = loc.x;
+ }
+ if (loc.x > maxHorzLoc) {
+ maxHorzLoc = loc.x;
+ }
+ if (loc.y < minVertLoc) {
+ minVertLoc = loc.y;
+ }
+ if (loc.y > maxVertLoc) {
+ maxVertLoc = loc.y;
+ }
+ }
+ if (maxVertLoc - minVertLoc > 3 || maxHorzLoc - minHorzLoc > 3) {
+ return super.getInvalidUseOfRuleMessage();
+ }
+
+
+ /* get the center of all possible 3X3 squares,
+ * and collect all that have numbers */
+ FillapixBoard board = (FillapixBoard) transition.getParents().get(0).getBoard();
+ Set possibleCenters = new TreeSet();
+ possibleCenters.addAll(FillapixUtilities.getAdjacentCells(board, (FillapixCell) modCells.iterator().next()));
+ for (PuzzleElement modCell : modCells) {
+ possibleCenters.retainAll((FillapixUtilities.getAdjacentCells(board, (FillapixCell) modCell)));
+ }
+ // removing all elements without a valid number
+ possibleCenters.removeIf(x -> x.getNumber() < 0 || x.getNumber() >= 10);
+ if (possibleCenters.isEmpty()) {
+ return super.getInvalidUseOfRuleMessage();
+ }
+
+
+ /* Now go through the remaining centers, and check if their combinations
+ * match the transitions */
+ for (FillapixCell possibleCenter : possibleCenters) {
+ int numBlack = 0;
+ int numEmpty = 0;
+ int maxBlack = possibleCenter.getNumber();
+ for (FillapixCell adjCell : FillapixUtilities.getAdjacentCells(board, possibleCenter)) {
+ if (adjCell.getType() == FillapixCellType.BLACK) {
+ numBlack++;
+ }
+ if (adjCell.getType() == FillapixCellType.UNKNOWN) {
+ numEmpty++;
+ }
+ }
+ if (numEmpty <= 0 || numBlack > maxBlack) {
+ // this cell has no cases (no empty) or is already broken (too many black)
+ continue;
+ }
+
+ ArrayList combinations = FillapixUtilities.getCombinations(maxBlack - numBlack, numEmpty);
+ if (combinations.size() != childTransitions.size()) {
+ // not this center because combinations do not match transitions
+ continue;
+ }
+ boolean quitEarly = false;
+ for (TreeTransition trans : childTransitions) {
+ /* convert the transition board into boolean format, so that it
+ * can be compared to the combinations */
+ FillapixBoard transBoard = (FillapixBoard) trans.getBoard();
+ ArrayList transModCells = new ArrayList();
+ for (PuzzleElement modCell : modCells) {
+ transModCells.add((FillapixCell) transBoard.getPuzzleElement(modCell));
+ }
+
+ boolean[] translatedModCells = new boolean[transModCells.size()];
+ for (int i=0; i < transModCells.size(); i++) {
+ if (transModCells.get(i).getType() == FillapixCellType.BLACK) {
+ translatedModCells[i] = true;
+ }
+ else {
+ translatedModCells[i] = false;
+ }
+ }
+
+ // try to find the above state in the combinations, remove if found
+ boolean removed = false;
+ for (boolean[] combination : combinations) {
+ if (Arrays.equals(combination, translatedModCells)) {
+ combinations.remove(combination);
+ removed = true;
+ break;
+ }
+ }
+ // if combination not found, no need to check further, just quit
+ if (!removed) {
+ quitEarly = true;
+ break;
+ }
+ }
+
+ /* we found a center that is valid */
+ if (combinations.isEmpty() && !quitEarly) {
+ return null;
+ }
+ }
+
+ return super.getInvalidUseOfRuleMessage();
+ }
+
+
+ @Override
+ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) {
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/TooFewBlackCellsContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/TooFewBlackCellsContradictionRule.java
index e8dd32860..c37050978 100644
--- a/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/TooFewBlackCellsContradictionRule.java
+++ b/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/TooFewBlackCellsContradictionRule.java
@@ -6,8 +6,9 @@
import edu.rpi.legup.puzzle.fillapix.FillapixBoard;
import edu.rpi.legup.puzzle.fillapix.FillapixCell;
import edu.rpi.legup.puzzle.fillapix.FillapixCellType;
+import edu.rpi.legup.puzzle.fillapix.FillapixUtilities;
-import java.awt.*;
+import java.util.ArrayList;
public class TooFewBlackCellsContradictionRule extends ContradictionRule {
@@ -31,22 +32,24 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) {
FillapixBoard fillapixBoard = (FillapixBoard) board;
FillapixCell cell = (FillapixCell) fillapixBoard.getPuzzleElement(puzzleElement);
- Point loc = cell.getLocation();
- for (int i = -1; i < 2; i++) {
- for (int j = -1; j < 2; j++) {
- FillapixCell adjCell = fillapixBoard.getCell(loc.x + i, loc.y + j);
- if (adjCell != null) {
- int cellNum = adjCell.getNumber();
- if (cellNum >= 0) {
- int numBlackCells = fillapixBoard.getNumCells(adjCell, FillapixCellType.BLACK);
- int numUnknownCells = fillapixBoard.getNumCells(adjCell, FillapixCellType.UNKNOWN);
- if (numBlackCells + numUnknownCells < cellNum) {
- return null;
- }
- }
- }
+ int cellNum = cell.getNumber();
+ if (cellNum < 0 || cellNum >= 10) {
+ return super.getNoContradictionMessage();
+ }
+ int numBlack = 0, numEmpty = 0;
+ ArrayList adjCells = FillapixUtilities.getAdjacentCells(fillapixBoard, cell);
+ for (FillapixCell adjCell : adjCells) {
+ if (adjCell.getType() == FillapixCellType.BLACK) {
+ numBlack++;
+ }
+ if (adjCell.getType() == FillapixCellType.UNKNOWN) {
+ numEmpty++;
}
}
+ if (numBlack + numEmpty < cellNum) {
+ return null;
+ }
+
return super.getNoContradictionMessage();
}
}
diff --git a/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/TooManyBlackCellsContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/TooManyBlackCellsContradictionRule.java
index 5a1192cc9..68395ce7f 100644
--- a/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/TooManyBlackCellsContradictionRule.java
+++ b/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/TooManyBlackCellsContradictionRule.java
@@ -6,8 +6,9 @@
import edu.rpi.legup.puzzle.fillapix.FillapixBoard;
import edu.rpi.legup.puzzle.fillapix.FillapixCell;
import edu.rpi.legup.puzzle.fillapix.FillapixCellType;
+import edu.rpi.legup.puzzle.fillapix.FillapixUtilities;
-import java.awt.*;
+import java.util.ArrayList;
public class TooManyBlackCellsContradictionRule extends ContradictionRule {
@@ -31,21 +32,21 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) {
FillapixBoard fillapixBoard = (FillapixBoard) board;
FillapixCell cell = (FillapixCell) fillapixBoard.getPuzzleElement(puzzleElement);
- Point loc = cell.getLocation();
- for (int i = -1; i < 2; i++) {
- for (int j = -1; j < 2; j++) {
- FillapixCell adjCell = fillapixBoard.getCell(loc.x + i, loc.y + j);
- if (adjCell != null) {
- int cellNum = adjCell.getNumber();
- if (cellNum >= 0) {
- int numBlackCells = fillapixBoard.getNumCells(adjCell, FillapixCellType.BLACK);
- if (numBlackCells > cellNum) {
- return null;
- }
- }
- }
+ int cellNum = cell.getNumber();
+ if (cellNum < 0 || cellNum >= 10) {
+ return super.getNoContradictionMessage();
+ }
+ int numBlack = 0;
+ ArrayList adjCells = FillapixUtilities.getAdjacentCells(fillapixBoard, cell);
+ for (FillapixCell adjCell : adjCells) {
+ if (adjCell.getType() == FillapixCellType.BLACK) {
+ numBlack++;
}
}
+ if (numBlack > cellNum) {
+ return null;
+ }
+
return super.getNoContradictionMessage();
}
}
diff --git a/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/TouchingCornersDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/TouchingCornersDirectRule.java
new file mode 100644
index 000000000..6f4be7842
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/TouchingCornersDirectRule.java
@@ -0,0 +1,108 @@
+package edu.rpi.legup.puzzle.fillapix.rules;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import edu.rpi.legup.model.gameboard.Board;
+import edu.rpi.legup.model.gameboard.PuzzleElement;
+import edu.rpi.legup.model.rules.CaseRule;
+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.fillapix.FillapixBoard;
+import edu.rpi.legup.puzzle.fillapix.FillapixCell;
+import edu.rpi.legup.puzzle.fillapix.FillapixCellType;
+import edu.rpi.legup.puzzle.fillapix.FillapixUtilities;
+
+public class TouchingCornersDirectRule extends DirectRule {
+ public TouchingCornersDirectRule() {
+ super("FPIX-BASC-0005",
+ "Touching Corners",
+ "Clues with touching corners have the same difference in black cells in their unshared regions as the difference in their numbers",
+ "edu/rpi/legup/images/fillapix/rules/TouchingCorners.png");
+ }
+
+ @Override
+ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) {
+ FillapixBoard board = (FillapixBoard) transition.getBoard();
+ FillapixBoard parentBoard = (FillapixBoard) transition.getParents().get(0).getBoard().copy();
+ FillapixCell cell = (FillapixCell) board.getPuzzleElement(puzzleElement);
+ FillapixCell parentCell = (FillapixCell) parentBoard.getPuzzleElement(puzzleElement);
+
+ // cell has to have been empty before
+ if (parentCell.getType() != FillapixCellType.UNKNOWN) {
+ return super.getInvalidUseOfRuleMessage();
+ }
+
+ // parentBoard cannot have any contradictions
+ if (FillapixUtilities.checkBoardForContradiction(parentBoard)) {
+ return super.getInvalidUseOfRuleMessage();
+ }
+
+ // get all adjCells that have a number
+ ArrayList adjCells = FillapixUtilities.getAdjacentCells(parentBoard, parentCell);
+ adjCells.removeIf(x -> x.getNumber() < 0 || x.getNumber() >= 10);
+ /* remove any number cell that does not have another number cell diagonally
+ * adjacent to it on the opposite side of the modified cell */
+ Iterator itr = adjCells.iterator();
+ while (itr.hasNext()) {
+ FillapixCell adjCell = itr.next();
+
+ boolean found = false;
+ ArrayList adjAdjCells = FillapixUtilities.getAdjacentCells(parentBoard, adjCell);
+ for (FillapixCell adjAdjCell : adjAdjCells) {
+ if (adjAdjCell.getLocation().x != adjCell.getLocation().x &&
+ adjAdjCell.getLocation().y != adjCell.getLocation().y &&
+ adjAdjCell.getNumber() >= 0 && adjAdjCell.getNumber() < 10 &&
+ adjAdjCell.getIndex() != parentCell.getIndex()) {
+ // adjAdjCell is diagonally adjacent to adjCell && it has a
+ // number && it is not parentCell
+ found = true;
+ }
+ }
+
+ // does not qualify for this rule
+ if (!found) {
+ itr.remove();
+ }
+ }
+
+ // change the cell to the opposite color
+ if (cell.getType() == FillapixCellType.BLACK) {
+ parentCell.setCellType(FillapixCellType.WHITE);
+ }
+ else {
+ parentCell.setCellType(FillapixCellType.BLACK);
+ }
+ // check for some contradiction in all cases
+ parentBoard.addModifiedData(parentCell);
+ CaseRule completeClue = new SatisfyClueCaseRule();
+ List caseBoards;
+ for (FillapixCell adjCell : adjCells) {
+ caseBoards = completeClue.getCases(parentBoard, adjCell);
+ boolean found = true;
+ for (Board b : caseBoards) {
+ if (!FillapixUtilities.checkBoardForContradiction((FillapixBoard) b)) {
+ found = false;
+ }
+ }
+ if (found) {
+ return null;
+ }
+ }
+
+ return super.getInvalidUseOfRuleMessage();
+ }
+
+ /**
+ * 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
diff --git a/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/TouchingSidesDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/TouchingSidesDirectRule.java
new file mode 100644
index 000000000..bd6dd0169
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/TouchingSidesDirectRule.java
@@ -0,0 +1,115 @@
+package edu.rpi.legup.puzzle.fillapix.rules;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import edu.rpi.legup.model.gameboard.Board;
+import edu.rpi.legup.model.gameboard.PuzzleElement;
+import edu.rpi.legup.model.rules.CaseRule;
+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.fillapix.FillapixBoard;
+import edu.rpi.legup.puzzle.fillapix.FillapixCell;
+import edu.rpi.legup.puzzle.fillapix.FillapixCellType;
+import edu.rpi.legup.puzzle.fillapix.FillapixUtilities;
+
+public class TouchingSidesDirectRule extends DirectRule {
+ public TouchingSidesDirectRule() {
+ super("FPIX-BASC-0004",
+ "Touching Sides",
+ "Clues with touching sides have the same difference in black cells in their unshared regions as the difference in their numbers",
+ "edu/rpi/legup/images/fillapix/rules/TouchingSides.png");
+ }
+
+ @Override
+ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) {
+ FillapixBoard board = (FillapixBoard) transition.getBoard();
+ FillapixBoard parentBoard = (FillapixBoard) transition.getParents().get(0).getBoard().copy();
+ FillapixCell cell = (FillapixCell) board.getPuzzleElement(puzzleElement);
+ FillapixCell parentCell = (FillapixCell) parentBoard.getPuzzleElement(puzzleElement);
+
+ // cell has to have been empty before
+ if (parentCell.getType() != FillapixCellType.UNKNOWN) {
+ return super.getInvalidUseOfRuleMessage();
+ }
+
+ // parentBoard cannot have any contradictions
+ if (FillapixUtilities.checkBoardForContradiction(parentBoard)) {
+ return super.getInvalidUseOfRuleMessage();
+ }
+
+ // get all adjCells that have a number
+ ArrayList adjCells = FillapixUtilities.getAdjacentCells(parentBoard, parentCell);
+ adjCells.removeIf(x -> x.getNumber() < 0 || x.getNumber() >= 10);
+ /* remove any number cell that does not have another number cell adjacent
+ * to it on the opposite side of the modified cell */
+ Iterator itr = adjCells.iterator();
+ while (itr.hasNext()) {
+ // calculate x and y offset of adjCell from cell
+ FillapixCell adjCell = itr.next();
+ int xOffset = adjCell.getLocation().x - cell.getLocation().x;
+ int yOffset = adjCell.getLocation().y - cell.getLocation().y;
+
+ boolean found = false;
+ // check vertically for numbered cell in opposite direction of cell
+ if (adjCell.getLocation().x + xOffset >= 0 && adjCell.getLocation().x < parentBoard.getWidth()) {
+ int adjNum = parentBoard.getCell(adjCell.getLocation().x + xOffset, adjCell.getLocation().y).getNumber();
+ if (adjNum >= 0 && adjNum < 10) {
+ found = true;
+ }
+ }
+ // check horizontally for numbered cell in opposite direction of cell
+ if (adjCell.getLocation().y + yOffset >= 0 && adjCell.getLocation().y < parentBoard.getHeight()) {
+ int adjNum = parentBoard.getCell(adjCell.getLocation().x, adjCell.getLocation().y + yOffset).getNumber();
+ if (adjNum >= 0 && adjNum < 10) {
+ found = true;
+ }
+ }
+
+ // if no horizontally or vertically adjacent cell on opposite side of 'cell' has number,
+ // then adjCell is not valid, so should be removed
+ if (!found) {
+ itr.remove();
+ }
+ }
+
+ // change the cell to the opposite color
+ if (cell.getType() == FillapixCellType.BLACK) {
+ parentCell.setCellType(FillapixCellType.WHITE);
+ }
+ else {
+ parentCell.setCellType(FillapixCellType.BLACK);
+ }
+ // check for some contradiction in all cases
+ parentBoard.addModifiedData(parentCell);
+ CaseRule completeClue = new SatisfyClueCaseRule();
+ List caseBoards;
+ for (FillapixCell adjCell : adjCells) {
+ caseBoards = completeClue.getCases(parentBoard, adjCell);
+ boolean found = true;
+ for (Board b : caseBoards) {
+ if (!FillapixUtilities.checkBoardForContradiction((FillapixBoard) b)) {
+ found = false;
+ }
+ }
+ if (found) {
+ return null;
+ }
+ }
+
+ return super.getInvalidUseOfRuleMessage();
+ }
+
+ /**
+ * 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
diff --git a/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/fillapix_reference_sheet.txt b/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/fillapix_reference_sheet.txt
index b6172e7fb..2e3c96a86 100644
--- a/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/fillapix_reference_sheet.txt
+++ b/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/fillapix_reference_sheet.txt
@@ -1,7 +1,11 @@
FPIX-BASC-0001 : FinishWithBlackDirectRule
FPIX-BASC-0002 : FinishWithWhiteDirectRule
+FPIX-BASC-0003 : MirrorDirectRule
+FPIX-BASC-0004 : TouchingSidesDirectRule
+FPIX-BASC-0005 : TouchingCornersDirectRule
FPIX-CONT-0001 : TooFewBlackCellsContradictionRule
FPIX-CONT-0002 : TooManyBlackCellsContradictionRule
-FPIX-CASE-0001 : BlackOrWhiteCaseRule
\ No newline at end of file
+FPIX-CASE-0001 : BlackOrWhiteCaseRule
+FPIX-CASE-0002 : CompleteClueCaseRule
\ No newline at end of file
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 1f166685b..cf7b70ccd 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
@@ -287,4 +287,67 @@ private List getAdjacentCells(LightUpBoard board, LightUpCell cell)
}
return cells;
}
+
+ /**
+ * Returns the elements necessary for the cases returned by getCases(board,puzzleElement) to be valid
+ * Overridden by case rules dependent on more than just the modified data
+ *
+ * @param board board state at application
+ * @param puzzleElement selected puzzleElement
+ * @return List of puzzle elements (typically cells) this application of the case rule depends upon.
+ * Defaults to any element modified by any case
+ */
+ @Override
+ public List dependentElements(Board board, PuzzleElement puzzleElement) {
+ List elements = new ArrayList<>();
+
+ LightUpBoard puzzleBoard = (LightUpBoard) board;
+ LightUpCell point = (LightUpCell)puzzleBoard.getPuzzleElement(puzzleElement);
+
+ List cells = getAdjacentCells(puzzleBoard,point);
+
+ for (LightUpCell cell : cells) {
+ //add cells that can light adjacents from any direction
+ Point location = cell.getLocation();
+ for (int i = location.x; i < puzzleBoard.getWidth(); i++) {
+ System.out.println(i);
+ LightUpCell c = puzzleBoard.getCell(i, location.y);
+ if (c.getType() == LightUpCellType.BLACK || c.getType() == LightUpCellType.NUMBER) {
+ break;
+ }
+ else if (!elements.contains(board.getPuzzleElement(c))) {
+ elements.add(board.getPuzzleElement(c));
+ }
+ }
+ for (int i = location.x; i >= 0; i--) {
+ LightUpCell c = puzzleBoard.getCell(i, location.y);
+ if (c.getType() == LightUpCellType.BLACK || c.getType() == LightUpCellType.NUMBER) {
+ break;
+ }
+ else if (!elements.contains(board.getPuzzleElement(c))) {
+ elements.add(board.getPuzzleElement(c));
+ }
+ }
+ for (int i = location.y; i < puzzleBoard.getHeight(); i++) {
+ LightUpCell c = puzzleBoard.getCell(location.x, i);
+ if (c.getType() == LightUpCellType.BLACK || c.getType() == LightUpCellType.NUMBER) {
+ break;
+ }
+ else if (!elements.contains(board.getPuzzleElement(c))) {
+ elements.add(board.getPuzzleElement(c));
+ }
+ }
+ for (int i = location.y; i >= 0; i--) {
+ LightUpCell c = puzzleBoard.getCell(location.x, i);
+ if (c.getType() == LightUpCellType.BLACK || c.getType() == LightUpCellType.NUMBER) {
+ break;
+ }
+ else if (!elements.contains(board.getPuzzleElement(c))) {
+ elements.add(board.getPuzzleElement(c));
+ }
+ }
+ }
+
+ return elements;
+ }
}
diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/SurroundRegionDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/SurroundRegionDirectRule.java
index b77f8a79f..d992fd22c 100644
--- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/SurroundRegionDirectRule.java
+++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/SurroundRegionDirectRule.java
@@ -3,12 +3,20 @@
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.tree.TreeNode;
import edu.rpi.legup.model.tree.TreeTransition;
import edu.rpi.legup.puzzle.nurikabe.NurikabeBoard;
import edu.rpi.legup.puzzle.nurikabe.NurikabeCell;
import edu.rpi.legup.puzzle.nurikabe.NurikabeType;
+import edu.rpi.legup.puzzle.nurikabe.NurikabeUtilities;
+import edu.rpi.legup.utility.DisjointSets;
+
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.HashSet;
+import java.util.Set;
+import java.awt.*;
public class SurroundRegionDirectRule extends DirectRule {
@@ -29,7 +37,6 @@ public SurroundRegionDirectRule() {
*/
@Override
public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) {
- ContradictionRule contraRule = new TooManySpacesContradictionRule();
NurikabeBoard destBoardState = (NurikabeBoard) transition.getBoard();
NurikabeBoard origBoardState = (NurikabeBoard) transition.getParents().get(0).getBoard();
@@ -44,12 +51,35 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem
NurikabeCell modCell = (NurikabeCell) modified.getPuzzleElement(puzzleElement);
modCell.setData(NurikabeType.WHITE.toValue());
- if (contraRule.checkContradiction(modified) == null) {
- return null;
- }
- else {
- return "Does not follow from this rule at this index";
+ if(cell.getType() == NurikabeType.BLACK) {
+ DisjointSets regions = NurikabeUtilities.getNurikabeRegions(destBoardState);
+ Set adj = new HashSet<>(); //set to hold adjacent cells
+ Point loc = cell.getLocation(); //position of placed cell
+ List directions = Arrays.asList(new Point(-1, 0), new Point(1, 0), new Point(0, -1), new Point(0, 1));
+ for(Point direction : directions) {
+ NurikabeCell curr = destBoardState.getCell(loc.x + direction.x, loc.y + direction.y);
+ if(curr != null) {
+ if(curr.getType() == NurikabeType.WHITE || curr.getType() == NurikabeType.NUMBER) {
+ adj.add(curr); //adds cells to adj only if they are white or number blocks
+ }
+ }
+ }
+ List numberedCells = new ArrayList<>(); //number value of number cells
+ for (NurikabeCell c : adj) { //loops through adjacent cells
+ Set disRow = regions.getSet(c); //set of white spaces
+ for (NurikabeCell d : disRow) { //loops through white spaces
+ if (d.getType() == NurikabeType.NUMBER) { //if the white space is a number
+ numberedCells.add(d); //add that number to numberedCells
+ }
+ }
+ }
+ for (NurikabeCell number : numberedCells) { //loops through numberedCells
+ if (regions.getSet(number).size() == number.getData()) { //if that cells white area is the exact
+ return null; //size of the number of one of the number cells within that set
+ }
+ }
}
+ return "Does not follow from this rule at this index";
}
/**
diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/ShortTruthTableOperation.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/ShortTruthTableOperation.java
index 380afb4cd..bc713d407 100644
--- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/ShortTruthTableOperation.java
+++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/ShortTruthTableOperation.java
@@ -1,61 +1,57 @@
-package edu.rpi.legup.puzzle.shorttruthtable;
-
-import java.util.Collections;
-import java.util.Map;
-import java.util.TreeMap;
-
-public class ShortTruthTableOperation {
-
- public static final char AND = '^';
- public static final char OR = '|';
- public static final char NOT = '~';
- public static final char CONDITIONAL = '>';
- public static final char BICONDITIONAL = '-';
-
- private ShortTruthTableOperation() {
- }
-
-
- public static String getLogicSymbol(char c) {
- switch (c) {
- case AND:
- return "\u2227";
- case OR:
- return "\u2228";
- case NOT:
- return "\u00AC";
- case CONDITIONAL:
- return "\u2192";
- case BICONDITIONAL:
- return "\u2194";
- }
- return "" + c;
- }
-
- public static String getRuleName(char operation) {
- switch (operation) {
- case AND:
- return "And";
- case OR:
- return "Or";
- case NOT:
- return "Not";
- case CONDITIONAL:
- return "Conditional";
- case BICONDITIONAL:
- return "Biconditional";
- }
- return null;
- }
-
-
- public static boolean isOperation(char c) {
- return c == AND ||
- c == OR ||
- c == NOT ||
- c == CONDITIONAL ||
- c == BICONDITIONAL;
- }
-
-
-}
+package edu.rpi.legup.puzzle.shorttruthtable;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.TreeMap;
+
+public class ShortTruthTableOperation {
+
+ public static final char AND = '^';
+ public static final char OR = '|';
+ public static final char NOT = '~';
+ public static final char CONDITIONAL = '>';
+ public static final char BICONDITIONAL = '-';
+
+ private ShortTruthTableOperation() {
+ }
+
+ public static String getLogicSymbol(char c) {
+ switch (c) {
+ case AND:
+ return "\u2227";
+ case OR:
+ return "\u2228";
+ case NOT:
+ return "\u00AC";
+ case CONDITIONAL:
+ return "\u2192";
+ case BICONDITIONAL:
+ return "\u2194";
+ }
+ return "" + c;
+ }
+
+ public static String getRuleName(char operation) {
+ switch (operation) {
+ case AND:
+ return "And";
+ case OR:
+ return "Or";
+ case NOT:
+ return "Not";
+ case CONDITIONAL:
+ return "Conditional";
+ case BICONDITIONAL:
+ return "Biconditional";
+ }
+ return null;
+ }
+
+ public static boolean isOperation(char c) {
+ return c == AND ||
+ c == OR ||
+ c == NOT ||
+ c == CONDITIONAL ||
+ c == BICONDITIONAL;
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/DirectRule_Generic.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/DirectRule_Generic.java
index a9b9ab651..e1ac78b8c 100644
--- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/DirectRule_Generic.java
+++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/DirectRule_Generic.java
@@ -22,6 +22,8 @@ public DirectRule_Generic(String ruleID, String ruleName, String description, St
}
public String checkRuleRawAt(TreeTransition transition, PuzzleElement element) {
+ // Rule must have cell to evaluate on
+ if (element == null) return super.getInvalidUseOfRuleMessage() + ": Must have painted cell";
// Check that the puzzle element is not unknown
ShortTruthTableBoard parentBoard = (ShortTruthTableBoard) transition.getParents().get(0).getBoard();
diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRuleAnd.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRuleAnd.java
index ddc84df16..12fac9c4c 100644
--- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRuleAnd.java
+++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRuleAnd.java
@@ -1,23 +1,23 @@
-package edu.rpi.legup.puzzle.shorttruthtable.rules.caserule;
-
-import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableOperation;
-import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCellType;
-
-public class CaseRuleAnd extends CaseRule_GenericStatement {
-
- public CaseRuleAnd() {
- super("STTT-CASE-0001", ShortTruthTableOperation.AND,
- "And",
- trueCases,
- falseCases);
- }
-
- private static final ShortTruthTableCellType[][] trueCases = {
- {T, T}
- };
- private static final ShortTruthTableCellType[][] falseCases = {
- {F, N},
- {N, F}
- };
-
-}
+package edu.rpi.legup.puzzle.shorttruthtable.rules.caserule;
+
+import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableOperation;
+import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCellType;
+
+public class CaseRuleAnd extends CaseRule_GenericStatement {
+
+ public CaseRuleAnd() {
+ super("STTT-CASE-0001", ShortTruthTableOperation.AND,
+ "And",
+ trueCases,
+ falseCases);
+ }
+
+ private static final ShortTruthTableCellType[][] trueCases = {
+ {T, T}
+ };
+ private static final ShortTruthTableCellType[][] falseCases = {
+ {F, U},
+ {U, F}
+ };
+
+}
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 9b2ef7fea..f168499cc 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
@@ -20,7 +20,6 @@ public CaseRuleAtomic() {
super("STTT-CASE-0002", "Atomic",
"True or False",
"Each unknown cell must either be true or false");
- System.out.println("Case Rule T/F constructor");
}
// Adds all elements that can be selected for this case rule
diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRuleConditional.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRuleConditional.java
index 867708729..a9fee2b4e 100644
--- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRuleConditional.java
+++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRuleConditional.java
@@ -1,23 +1,23 @@
-package edu.rpi.legup.puzzle.shorttruthtable.rules.caserule;
-
-import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableOperation;
-import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCellType;
-
-public class CaseRuleConditional extends CaseRule_GenericStatement {
-
- public CaseRuleConditional() {
- super("STTT-CASE-0004", ShortTruthTableOperation.CONDITIONAL,
- "Conditional",
- trueCases,
- falseCases);
- }
-
- private static final ShortTruthTableCellType[][] trueCases = {
- {N, T},
- {F, N}
- };
- private static final ShortTruthTableCellType[][] falseCases = {
- {T, F},
- };
-
-}
+package edu.rpi.legup.puzzle.shorttruthtable.rules.caserule;
+
+import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableOperation;
+import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCellType;
+
+public class CaseRuleConditional extends CaseRule_GenericStatement {
+
+ public CaseRuleConditional() {
+ super("STTT-CASE-0004", ShortTruthTableOperation.CONDITIONAL,
+ "Conditional",
+ trueCases,
+ falseCases);
+ }
+
+ private static final ShortTruthTableCellType[][] trueCases = {
+ {U, T},
+ {F, U}
+ };
+ private static final ShortTruthTableCellType[][] falseCases = {
+ {T, F},
+ };
+
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRuleOr.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRuleOr.java
index e0bc9774c..82f814cc8 100644
--- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRuleOr.java
+++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRuleOr.java
@@ -1,23 +1,23 @@
-package edu.rpi.legup.puzzle.shorttruthtable.rules.caserule;
-
-import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableOperation;
-import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCellType;
-
-public class CaseRuleOr extends CaseRule_GenericStatement {
-
- public CaseRuleOr() {
- super("STTT-CASE-0005", ShortTruthTableOperation.OR,
- "Or",
- trueCases,
- falseCases);
- }
-
- private static final ShortTruthTableCellType[][] trueCases = {
- {T, N},
- {N, T}
- };
- private static final ShortTruthTableCellType[][] falseCases = {
- {F, F},
- };
-
-}
+package edu.rpi.legup.puzzle.shorttruthtable.rules.caserule;
+
+import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableOperation;
+import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCellType;
+
+public class CaseRuleOr extends CaseRule_GenericStatement {
+
+ public CaseRuleOr() {
+ super("STTT-CASE-0005", ShortTruthTableOperation.OR,
+ "Or",
+ trueCases,
+ falseCases);
+ }
+
+ private static final ShortTruthTableCellType[][] trueCases = {
+ {T, U},
+ {U, T}
+ };
+ private static final ShortTruthTableCellType[][] falseCases = {
+ {F, F},
+ };
+
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRule_Generic.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRule_Generic.java
index 047ea5d33..1409f4baa 100644
--- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRule_Generic.java
+++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRule_Generic.java
@@ -1,73 +1,71 @@
-package edu.rpi.legup.puzzle.shorttruthtable.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.shorttruthtable.ShortTruthTableBoard;
-import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCell;
-import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCellType;
-
-
-import java.util.ArrayList;
-import java.util.List;
-
-public abstract class CaseRule_Generic extends CaseRule {
-
- public CaseRule_Generic(String ruleID, String ruleName, String title, String description) {
- super(ruleID, title, description, "edu/rpi/legup/images/shorttruthtable/ruleimages/case/" + ruleName + ".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) {
- List childTransitions = transition.getParents().get(0).getChildren();
- if (childTransitions.size() != 2) {
- return "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 "This case rule must have 1 modified cell for each case.";
- }
-
- ShortTruthTableCell mod1 = (ShortTruthTableCell) case1.getBoard().getModifiedData().iterator().next();
- ShortTruthTableCell mod2 = (ShortTruthTableCell) case2.getBoard().getModifiedData().iterator().next();
- if (!mod1.getLocation().equals(mod2.getLocation())) {
- return "This case rule must modify the same cell for each case.";
- }
-
- boolean firstPossibility = mod1.getType() == ShortTruthTableCellType.TRUE && mod2.getType() == ShortTruthTableCellType.FALSE;
- boolean secondPossibility = mod1.getType() == ShortTruthTableCellType.FALSE && mod2.getType() == ShortTruthTableCellType.TRUE;
- if (!firstPossibility && !secondPossibility) {
- return "This case rule must an empty true or false cell.";
- }
-
- 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 checkRuleRaw(transition);
- }
-}
+package edu.rpi.legup.puzzle.shorttruthtable.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.shorttruthtable.ShortTruthTableBoard;
+import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCell;
+import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCellType;
+
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.swing.JOptionPane;
+
+import com.google.firebase.database.core.utilities.Tree;
+
+public abstract class CaseRule_Generic extends CaseRule {
+
+ public CaseRule_Generic(String ruleID, String ruleName, String title, String description) {
+ super(ruleID, title, description, "edu/rpi/legup/images/shorttruthtable/ruleimages/case/" + ruleName + ".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) {
+ // Validate that two children are generated
+ List childTransitions = transition.getParents().get(0).getChildren();
+ if (childTransitions.size() >= 1) {
+ return "ERROR: This case rule must spawn at least 1 child.";
+ }
+
+ // Validate that the modified cells are of type UNKNOWN, TRUE, or FALSE
+ List cases = Arrays.asList(childTransitions.get(0), childTransitions.get(1));
+ for (TreeTransition c : cases) {
+ ShortTruthTableCell mod1 = (ShortTruthTableCell)c.getBoard().getModifiedData().iterator().next();
+ ShortTruthTableCell mod2 = (ShortTruthTableCell)c.getBoard().getModifiedData().iterator().next();
+ if (!(mod1.getType() == ShortTruthTableCellType.TRUE || mod1.getType() == ShortTruthTableCellType.FALSE || mod1.getType() == ShortTruthTableCellType.UNKNOWN) &&
+ (mod2.getType() == ShortTruthTableCellType.TRUE || mod2.getType() == ShortTruthTableCellType.FALSE || mod2.getType() == ShortTruthTableCellType.UNKNOWN)) {
+ return "ERROR: This case rule must be an unknown, true, or false cell.";
+ }
+ }
+ 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 checkRuleRaw(transition);
+ }
+}
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 375a60292..0e25586a8 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
@@ -10,7 +10,7 @@
import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableStatement;
import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableOperation;
-
+import java.util.List;
import java.util.ArrayList;
public abstract class CaseRule_GenericStatement extends CaseRule_Generic {
@@ -35,9 +35,9 @@ public CaseRule_GenericStatement(String ruleID, char operation, String title,
protected static final ShortTruthTableCellType T = ShortTruthTableCellType.TRUE;
protected static final ShortTruthTableCellType F = ShortTruthTableCellType.FALSE;
- protected static final ShortTruthTableCellType N = null;
+ protected static final ShortTruthTableCellType U = ShortTruthTableCellType.UNKNOWN;
- //Adds all elements that can be selected for this caserule
+ // Adds all elements that can be selected for this caserule
@Override
public CaseBoard getCaseBoard(Board board) {
//copy the board and add all elements that can be selected
@@ -47,31 +47,19 @@ public CaseBoard getCaseBoard(Board board) {
//add all elements that can be selected for the case rule statement
for (PuzzleElement element : sttBoard.getPuzzleElements()) {
-
- System.out.println("GetCaseBoard Testing: " + element);
-
//get the cell object
ShortTruthTableCell cell = sttBoard.getCellFromElement(element);
//the cell must match the symbol
if (cell.getSymbol() != this.operation) continue;
-
- System.out.println(" Selectable... checking logic");
-
//the statement must be assigned with unassigned sub-statements
if (!cell.getType().isTrueOrFalse()) continue;
- System.out.println(" Operation is known");
if (cell.getStatementReference().getRightStatement().getCell().getType().isTrueOrFalse()) continue;
- System.out.println(" right side is unknown");
if (this.operation != ShortTruthTableOperation.NOT &&
cell.getStatementReference().getRightStatement().getCell().getType().isTrueOrFalse()) {
continue;
}
- System.out.println(" left side is unknown");
-
- System.out.println(" Valid choice");
//if the element has passed all the checks, it can be selected
caseBoard.addPickableElement(element);
-
}
return caseBoard;
}
@@ -86,57 +74,64 @@ public CaseBoard getCaseBoard(Board board) {
@SuppressWarnings("unchecked")
@Override
public ArrayList getCases(Board board, PuzzleElement puzzleElement) {
-
ShortTruthTableBoard sttBoard = ((ShortTruthTableBoard) board);
-
ShortTruthTableCell cell = sttBoard.getCellFromElement(puzzleElement);
- //if the statement is set to true
+ // If the statement is set to true, collect true cases. Otherwise, collect the false cases
if (cell.getType() == ShortTruthTableCellType.TRUE) {
return getCasesFromCell(sttBoard, puzzleElement, trueCases);
}
-
- //if the statement is set to false
return getCasesFromCell(sttBoard, puzzleElement, falseCases);
-
}
+ /**
+ * Collects a list of boards for each possible outcome of case-rule application
+ * @param board current board state
+ * @param puzzleElement case rule operator
+ * @param possibilities list of possibilities for operator state
+ * @return ArrayList of Boards
+ */
private ArrayList getCasesFromCell(ShortTruthTableBoard board, PuzzleElement puzzleElement, ShortTruthTableCellType[][] possibilities) {
-
- //store all possible boards
+ // Create branch case for each possibility
ArrayList cases = new ArrayList<>();
-
- //go through all the possibilities
for (int i = 0; i < possibilities.length; i++) {
- //create a new board
+ // Create a new board to modify and get statement of selected square
ShortTruthTableBoard b = board.copy();
-
- //get the statement of the square that was selected
ShortTruthTableCell cell = b.getCellFromElement(puzzleElement);
ShortTruthTableStatement statement = cell.getStatementReference();
- //modify its children
- //avoid error if it is a NOT statement
- if (possibilities[i][0] != null) {
+ // Modify neighboring cells of case-rule application by the provided logical cases
+ if (possibilities[i][0] != ShortTruthTableCellType.UNKNOWN) {
ShortTruthTableCell leftCell = statement.getLeftStatement().getCell();
leftCell.setData(possibilities[i][0]);
b.addModifiedData(leftCell);
}
-
- //always modify the right side of the statement
- if (possibilities[i][1] != null) {
+ if (possibilities[i][1] != ShortTruthTableCellType.UNKNOWN) {
ShortTruthTableCell rightCell = statement.getRightStatement().getCell();
rightCell.setData(possibilities[i][1]);
b.addModifiedData(rightCell);
}
- //add the board possibility to the list
cases.add(b);
}
-
- //return all possibilities
return cases;
-
}
+
+ /**
+ * Returns the elements necessary for the cases returned by getCases(board,puzzleElement) to be valid
+ * Overridden by case rules dependent on more than just the modified data
+ *
+ * @param board board state at application
+ * @param puzzleElement selected puzzleElement
+ * @return List of puzzle elements (typically cells) this application of the case rule depends upon.
+ * Defaults to any element modified by any case
+ */
+ @Override
+ public List dependentElements(Board board, PuzzleElement puzzleElement) {
+ List elements = super.dependentElements(board,puzzleElement);
+
+ elements.add(board.getPuzzleElement(puzzleElement));
+ return elements;
+ }
}
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 ca6bcbe02..52e8a6400 100644
--- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersBoard.java
+++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersBoard.java
@@ -25,9 +25,6 @@ public class SkyscrapersBoard extends GridBoard {
private boolean viewFlag = false;
private boolean dupeFlag = false;
- private SkyscrapersClue modClue = null;
- //helper variable for case rule verification, tracks recently modified row/col
-
public SkyscrapersBoard(int size) {
super(size, size);
@@ -94,14 +91,6 @@ public void setViewFlag(boolean newFlag) {
viewFlag = newFlag;
}
- public SkyscrapersClue getmodClue() {
- return modClue;
- }
-
- public void setModClue(SkyscrapersClue newClue) {
- modClue = newClue;
- }
-
@Override
public SkyscrapersCell getCell(int x, int y) {
return (SkyscrapersCell) super.getCell(x, y);
diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersClue.java b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersClue.java
index dc68f45c7..1e7b1b45e 100644
--- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersClue.java
+++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersClue.java
@@ -47,6 +47,9 @@ public void setType(SkyscrapersType type) {
}
public SkyscrapersClue copy() {
- return null;
+ SkyscrapersClue copy = new SkyscrapersClue(data, clueIndex, type);
+ copy.setIndex(index);
+ copy.setModifiable(isModifiable);
+ return copy;
}
}
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 683b742bf..01527294a 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
@@ -69,7 +69,6 @@ public ArrayList getCasesFor(Board board, PuzzleElement puzzleElement, In
PuzzleElement newCell = newCase.getPuzzleElement(cell);
newCell.setData(number);
newCase.addModifiedData(newCell);
- newCase.setModClue((SkyscrapersClue) newCase.getPuzzleElement(clue));
//if flags
boolean passed = true;
@@ -103,12 +102,7 @@ public String checkRuleRaw(TreeTransition transition) {
return "This case rule must have at least one child.";
}
- //find changed row/col
- SkyscrapersClue modClue = ((SkyscrapersBoard) childTransitions.get(0).getBoard()).getmodClue();
-
- //System.out.println(modClue.getType());
- //System.out.println(modClue.getClueIndex());
- if (childTransitions.size() != getCasesFor(oldBoard, modClue, (Integer) childTransitions.get(0).getBoard().getModifiedData().iterator().next().getData()).size()) {
+ if (childTransitions.size() != getCasesFor(oldBoard, oldBoard.getPuzzleElement(transition.getSelection()), (Integer) childTransitions.get(0).getBoard().getModifiedData().iterator().next().getData()).size()) {
//System.out.println("Wrong number of cases.");
return "Wrong number of cases.";
}
@@ -132,4 +126,49 @@ public String checkRuleRaw(TreeTransition transition) {
public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) {
return checkRuleRaw(transition);
}
+
+ /**
+ * Returns the elements necessary for the cases returned by getCases(board,puzzleElement) to be valid
+ * Overridden by case rules dependent on more than just the modified data
+ *
+ * @param board board state at application
+ * @param puzzleElement selected puzzleElement
+ * @return List of puzzle elements (typically cells) this application of the case rule depends upon.
+ * Defaults to any element modified by any case
+ */
+ @Override
+ public List dependentElements(Board board, PuzzleElement puzzleElement) {
+ List elements = new ArrayList<>();
+
+ SkyscrapersBoard puzzleBoard = (SkyscrapersBoard) board;
+ SkyscrapersClue clue = (SkyscrapersClue)puzzleBoard.getPuzzleElement(puzzleElement);
+
+ // check each point in modified row/col
+ List data = puzzleBoard.getRowCol(clue.getClueIndex(),SkyscrapersType.ANY,clue.getType() == SkyscrapersType.CLUE_WEST);
+ for (SkyscrapersCell point : data) {
+ List cells = new ArrayList<>(List.of(point));
+
+ // if dependent on row/col
+ if ((puzzleBoard.getDupeFlag() || puzzleBoard.getViewFlag()) && point.getType() == SkyscrapersType.UNKNOWN) {
+ // get perpendicular row/col intersecting this point
+ int index;
+ if (clue.getType() == SkyscrapersType.CLUE_WEST) {
+ index = point.getLocation().x;
+ }
+ else {
+ index = point.getLocation().y;
+ }
+ cells.addAll(puzzleBoard.getRowCol(index,SkyscrapersType.ANY,clue.getType() != SkyscrapersType.CLUE_WEST));
+ }
+
+ // add all to result
+ for (SkyscrapersCell cell : cells) {
+ if (!elements.contains(board.getPuzzleElement(cell))) {
+ elements.add(board.getPuzzleElement(cell));
+ }
+ }
+ }
+
+ return elements;
+ }
}
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 a061c62a3..3bf0de70a 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
@@ -7,6 +7,7 @@
import edu.rpi.legup.model.tree.TreeTransition;
import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersBoard;
import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersCell;
+import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersClue;
import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersType;
import java.awt.*;
@@ -134,4 +135,38 @@ public String checkRuleRaw(TreeTransition transition) {
public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) {
return checkRuleRaw(transition);
}
+
+ /**
+ * Returns the elements necessary for the cases returned by getCases(board,puzzleElement) to be valid
+ * Overridden by case rules dependent on more than just the modified data
+ *
+ * @param board board state at application
+ * @param puzzleElement selected puzzleElement
+ * @return List of puzzle elements (typically cells) this application of the case rule depends upon.
+ * Defaults to any element modified by any case
+ */
+ @Override
+ public List dependentElements(Board board, PuzzleElement puzzleElement) {
+ List elements = new ArrayList<>();
+
+ SkyscrapersBoard puzzleBoard = (SkyscrapersBoard) board;
+ SkyscrapersCell point = (SkyscrapersCell)puzzleBoard.getPuzzleElement(puzzleElement);
+
+ List cells = new ArrayList<>(List.of(point));
+
+ // if dependent on row/col
+ if (puzzleBoard.getDupeFlag() || puzzleBoard.getViewFlag()) {
+ // add all cells in row/col intersecting given point
+ cells.addAll(puzzleBoard.getRowCol(point.getLocation().x,SkyscrapersType.ANY,false));
+ cells.addAll(puzzleBoard.getRowCol(point.getLocation().y,SkyscrapersType.ANY,true));
+ }
+
+ for (SkyscrapersCell cell : cells) {
+ if (!elements.contains(board.getPuzzleElement(cell))) {
+ elements.add(board.getPuzzleElement(cell));
+ }
+ }
+
+ return elements;
+ }
}
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 2542ea335..dc809f34d 100644
--- a/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentBoard.java
+++ b/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentBoard.java
@@ -124,21 +124,11 @@ public void notifyDeletion(PuzzleElement puzzleElement) {
public List getAdjacent(TreeTentCell cell, TreeTentType type) {
List adj = new ArrayList<>();
Point loc = cell.getLocation();
- TreeTentCell up = getCell(loc.x, loc.y - 1);
- TreeTentCell right = getCell(loc.x + 1, loc.y);
- TreeTentCell down = getCell(loc.x, loc.y + 1);
- TreeTentCell left = getCell(loc.x - 1, loc.y);
- if (up != null && up.getType() == type) {
- adj.add(up);
- }
- if (right != null && right.getType() == type) {
- adj.add(right);
- }
- if (down != null && down.getType() == type) {
- adj.add(down);
- }
- if (left != null && left.getType() == type) {
- adj.add(left);
+ for (int i = -2; i < 2; i++) {
+ TreeTentCell adjCell = getCell(loc.x + (i % 2), loc.y + ((i + 1) % 2));
+ if (adjCell != null && adjCell.getType() == type) {
+ adj.add(adjCell);
+ }
}
return adj;
}
diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentCell.java b/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentCell.java
index 290e0858d..b6411a5cf 100644
--- a/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentCell.java
+++ b/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentCell.java
@@ -16,15 +16,31 @@ public TreeTentType getType() {
return data;
}
+ public int getValue() {
+ switch (data) {
+ case TREE:
+ return 1;
+ case GRASS:
+ return 2;
+ case TENT:
+ return 3;
+ default:
+ return 0;
+ }
+ }
+
@Override
public void setType(Element e, MouseEvent m) {
switch (e.getElementName()) {
case "Unknown Tile":
this.data = TreeTentType.UNKNOWN;
+ break;
case "Tree Tile":
this.data = TreeTentType.TREE;
+ break;
case "Grass Tile":
this.data = TreeTentType.GRASS;
+ break;
case "Tent Tile":
this.data = TreeTentType.TENT;
}
diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentCellFactory.java b/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentCellFactory.java
index 969ffdf0f..20b8066a4 100644
--- a/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentCellFactory.java
+++ b/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentCellFactory.java
@@ -83,7 +83,7 @@ public org.w3c.dom.Element exportCell(Document document, PuzzleElement puzzleEle
TreeTentCell cell = (TreeTentCell) puzzleElement;
Point loc = cell.getLocation();
- cellElement.setAttribute("value", String.valueOf(cell.getData()));
+ cellElement.setAttribute("value", String.valueOf(cell.getValue()));
cellElement.setAttribute("x", String.valueOf(loc.x));
cellElement.setAttribute("y", String.valueOf(loc.y));
diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentController.java b/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentController.java
index 2b969b4bb..1f431594c 100644
--- a/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentController.java
+++ b/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentController.java
@@ -29,83 +29,83 @@ public TreeTentController() {
this.lastCellPressed = null;
}
-// @Override
-// public void mousePressed(MouseEvent e) {
-// if (e.getButton() != MouseEvent.BUTTON2) {
-// BoardView boardView = getInstance().getLegupUI().getBoardView();
-// dragStart = boardView.getElement(e.getPoint());
-// lastCellPressed = boardView.getElement(e.getPoint());
-// }
-// }
+ @Override
+ public void mousePressed(MouseEvent e) {
+ if (e.getButton() != MouseEvent.BUTTON2) {
+ BoardView boardView = getInstance().getLegupUI().getBoardView();
+ dragStart = boardView.getElement(e.getPoint());
+ lastCellPressed = boardView.getElement(e.getPoint());
+ }
+ }
+
+ @Override
+ public void mouseReleased(MouseEvent e) {
+ if (GameBoardFacade.getInstance().getLegupUI().getTreePanel() != null && e.getButton() != MouseEvent.BUTTON2) {
+ TreePanel treePanel = GameBoardFacade.getInstance().getLegupUI().getTreePanel();
+ TreeView treeView = GameBoardFacade.getInstance().getLegupUI().getTreePanel().getTreeView();
+ BoardView boardView = getInstance().getLegupUI().getBoardView();
+ lastCellPressed = boardView.getElement(e.getPoint());
+ Board board = boardView.getBoard();
+ TreeViewSelection selection = treeView.getSelection();
-// @Override
-// public void mouseReleased(MouseEvent e) {
-// if (GameBoardFacade.getInstance().getLegupUI().getTreePanel() != null && e.getButton() != MouseEvent.BUTTON2) {
-// TreePanel treePanel = GameBoardFacade.getInstance().getLegupUI().getTreePanel();
-// TreeView treeView = GameBoardFacade.getInstance().getLegupUI().getTreePanel().getTreeView();
-// BoardView boardView = getInstance().getLegupUI().getBoardView();
-// lastCellPressed = boardView.getElement(e.getPoint());
-// Board board = boardView.getBoard();
-// TreeViewSelection selection = treeView.getSelection();
-//
-// if (dragStart != null) {
-// if (board instanceof CaseBoard) {
-// CaseBoard caseBoard = (CaseBoard) board;
-// AutoCaseRuleCommand autoCaseRuleCommand = new AutoCaseRuleCommand(dragStart, selection, caseBoard.getCaseRule(), caseBoard, e);
-// if (autoCaseRuleCommand.canExecute()) {
-// autoCaseRuleCommand.execute();
-// getInstance().getHistory().pushChange(autoCaseRuleCommand);
-// treePanel.updateError("");
-// }
-// else {
-// treePanel.updateError(autoCaseRuleCommand.getError());
-// }
-// }
-// else {
-// if (dragStart == lastCellPressed) {
-// if (dragStart.getPuzzleElement().getIndex() >= 0) {
-// ICommand edit = new EditDataCommand(lastCellPressed, selection, e);
-// if (edit.canExecute()) {
-// edit.execute();
-// getInstance().getHistory().pushChange(edit);
-// treePanel.updateError("");
-// }
-// else {
-// treePanel.updateError(edit.getError());
-// }
-// }
-// else {
-// ClueCommand edit = new ClueCommand(selection, (TreeTentClueView) dragStart);
-// if (edit.canExecute()) {
-// edit.execute();
-// getInstance().getHistory().pushChange(edit);
-// treePanel.updateError("");
-// }
-// else {
-// treePanel.updateError(edit.getError());
-// }
-// }
-// }
-// else {
-// if (lastCellPressed != null) {
-// if (dragStart instanceof TreeTentElementView) {
-// ICommand editLine = new EditLineCommand(selection, (TreeTentElementView) dragStart, lastCellPressed);
-// if (editLine.canExecute()) {
-// editLine.execute();
-// getInstance().getHistory().pushChange(editLine);
-// }
-// else {
-// treePanel.updateError(editLine.getError());
-// }
-// }
-// }
-// }
-// }
-// }
-// dragStart = null;
-// lastCellPressed = null;
-// }
-// }
+ if (dragStart != null) {
+ if (board instanceof CaseBoard) {
+ CaseBoard caseBoard = (CaseBoard) board;
+ AutoCaseRuleCommand autoCaseRuleCommand = new AutoCaseRuleCommand(dragStart, selection, caseBoard.getCaseRule(), caseBoard, e);
+ if (autoCaseRuleCommand.canExecute()) {
+ autoCaseRuleCommand.execute();
+ getInstance().getHistory().pushChange(autoCaseRuleCommand);
+ treePanel.updateError("");
+ }
+ else {
+ treePanel.updateError(autoCaseRuleCommand.getError());
+ }
+ }
+ else {
+ if (dragStart == lastCellPressed) {
+ if (dragStart.getPuzzleElement().getIndex() >= 0) {
+ ICommand edit = new EditDataCommand(lastCellPressed, selection, e);
+ if (edit.canExecute()) {
+ edit.execute();
+ getInstance().getHistory().pushChange(edit);
+ treePanel.updateError("");
+ }
+ else {
+ treePanel.updateError(edit.getError());
+ }
+ }
+ else {
+ ClueCommand edit = new ClueCommand(selection, (TreeTentClueView) dragStart);
+ if (edit.canExecute()) {
+ edit.execute();
+ getInstance().getHistory().pushChange(edit);
+ treePanel.updateError("");
+ }
+ else {
+ treePanel.updateError(edit.getError());
+ }
+ }
+ }
+ else {
+ if (lastCellPressed != null) {
+ if (dragStart instanceof TreeTentElementView) {
+ ICommand editLine = new EditLineCommand(selection, (TreeTentElementView) dragStart, lastCellPressed);
+ if (editLine.canExecute()) {
+ editLine.execute();
+ getInstance().getHistory().pushChange(editLine);
+ }
+ else {
+ treePanel.updateError(editLine.getError());
+ }
+ }
+ }
+ }
+ }
+ }
+ dragStart = null;
+ lastCellPressed = null;
+ }
+ }
@Override
public void changeCell(MouseEvent e, PuzzleElement element) {
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 538772b74..698b3aa5e 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
@@ -160,4 +160,29 @@ public String checkRuleRaw(TreeTransition transition) {
public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) {
return null;
}
+
+ /**
+ * Returns the elements necessary for the cases returned by getCases(board,puzzleElement) to be valid
+ * Overridden by case rules dependent on more than just the modified data
+ *
+ * @param board board state at application
+ * @param puzzleElement selected puzzleElement
+ * @return List of puzzle elements (typically cells) this application of the case rule depends upon.
+ * Defaults to any element modified by any case
+ */
+ @Override
+ public List dependentElements(Board board, PuzzleElement puzzleElement) {
+ List elements = new ArrayList<>();
+
+ TreeTentBoard treeTentBoard = (TreeTentBoard) board;
+ TreeTentClue clue = (TreeTentClue) puzzleElement;
+
+ // add all elements of filled row
+ for (int i = 0; i < treeTentBoard.getWidth(); i++) {
+ TreeTentCell cell = treeTentBoard.getCell(i, clue.getClueIndex()-1);
+ elements.add(board.getPuzzleElement((cell)));
+ }
+
+ return elements;
+ }
}
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 36f466f87..39b1d0251 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
@@ -5,7 +5,6 @@
import edu.rpi.legup.model.gameboard.PuzzleElement;
import edu.rpi.legup.model.rules.CaseRule;
import edu.rpi.legup.model.tree.TreeTransition;
-import edu.rpi.legup.puzzle.treetent.TreeTent;
import edu.rpi.legup.puzzle.treetent.TreeTentBoard;
import edu.rpi.legup.puzzle.treetent.TreeTentType;
import edu.rpi.legup.puzzle.treetent.TreeTentCell;
@@ -151,4 +150,18 @@ public String checkRuleRaw(TreeTransition transition) {
public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) {
return checkRuleRaw(transition);
}
+
+ /**
+ * Returns the elements necessary for the cases returned by getCases(board,puzzleElement) to be valid
+ * Overridden by case rules dependent on more than just the modified data
+ *
+ * @param board board state at application
+ * @param puzzleElement selected puzzleElement
+ * @return List of puzzle elements (typically cells) this application of the case rule depends upon.
+ * Defaults to any element modified by any case
+ */
+ @Override
+ public List dependentElements(Board board, PuzzleElement puzzleElement) {
+ return List.of(board.getPuzzleElement(puzzleElement));
+ }
}
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 249547301..72ffd62eb 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
@@ -10,6 +10,7 @@
import edu.rpi.legup.puzzle.treetent.TreeTentLine;
import edu.rpi.legup.puzzle.treetent.TreeTentType;
+import java.awt.Point;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@@ -152,4 +153,32 @@ public String checkRuleRaw(TreeTransition transition) {
public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) {
return checkRuleRaw(transition);
}
+
+ /**
+ * Returns the elements necessary for the cases returned by getCases(board,puzzleElement) to be valid
+ * Overridden by case rules dependent on more than just the modified data
+ *
+ * @param board board state at application
+ * @param puzzleElement selected puzzleElement
+ * @return List of puzzle elements (typically cells) this application of the case rule depends upon.
+ * Defaults to any element modified by any case
+ */
+ @Override
+ public List dependentElements(Board board, PuzzleElement puzzleElement) {
+ List elements = new ArrayList<>(List.of(board.getPuzzleElement(puzzleElement)));
+
+ TreeTentBoard treeTentBoard = (TreeTentBoard) board;
+ TreeTentCell point = (TreeTentCell) puzzleElement;
+
+ // get all adjacent cells
+ Point loc = point.getLocation();
+ for (int i = -2; i < 2; i++) {
+ TreeTentCell cell = treeTentBoard.getCell(loc.x + (i % 2), loc.y + ((i + 1) % 2));
+ if (cell != null) {
+ elements.add(board.getPuzzleElement(cell));
+ }
+ }
+
+ return elements;
+ }
}
diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/rules/SurroundTentWithGrassDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/treetent/rules/SurroundTentWithGrassDirectRule.java
index 829c1c1e9..44e9dfcc4 100644
--- a/src/main/java/edu/rpi/legup/puzzle/treetent/rules/SurroundTentWithGrassDirectRule.java
+++ b/src/main/java/edu/rpi/legup/puzzle/treetent/rules/SurroundTentWithGrassDirectRule.java
@@ -31,6 +31,9 @@ public SurroundTentWithGrassDirectRule() {
*/
@Override
public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) {
+ if (puzzleElement == null) {
+ return null;
+ }
if (puzzleElement instanceof TreeTentLine) {
return super.getInvalidUseOfRuleMessage() + ": Line is not valid for this rule.";
}
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 fa08972ed..9bfffe60a 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
@@ -2,7 +2,12 @@
import edu.rpi.legup.app.GameBoardFacade;
import edu.rpi.legup.controller.TreeController;
+import edu.rpi.legup.model.gameboard.Board;
+import edu.rpi.legup.model.gameboard.GridCell;
+import edu.rpi.legup.model.gameboard.PuzzleElement;
import edu.rpi.legup.model.observer.ITreeListener;
+import edu.rpi.legup.model.rules.CaseRule;
+import edu.rpi.legup.model.rules.Rule;
import edu.rpi.legup.model.tree.Tree;
import edu.rpi.legup.model.tree.TreeElement;
import edu.rpi.legup.model.tree.TreeNode;
@@ -316,6 +321,50 @@ public void onTreeElementRemoved(TreeElement element) {
TreeTransition trans = (TreeTransition) element;
TreeTransitionView transView = (TreeTransitionView) viewMap.get(trans);
+ // unlock ancestor elements if case rule deleted
+ Rule rule = trans.getRule();
+ for (TreeNode node : trans.getParents()) {
+
+ // only if the last case of a case rule will be deleted
+ if (!(rule instanceof CaseRule && node.getChildren().isEmpty())) {
+ continue;
+ }
+
+ CaseRule caseRule = (CaseRule)rule;
+ // set dependent elements to be modifiable by ancestors (if not dependent on others)
+ List ancestors = node.getAncestors();
+ for (TreeNode ancestor : ancestors) {
+ // for all ancestors but root
+ if (ancestor.getParent() == null) {
+ continue;
+ }
+
+ for (PuzzleElement pelement : caseRule.dependentElements(node.getBoard(), trans.getSelection())) {
+ // decrement, unlock if 0 cases depended
+ PuzzleElement oldElement = ancestor.getParent().getBoard().getPuzzleElement(pelement);
+ oldElement.setCasesDepended(oldElement.getCasesDepended() - 1);
+ if (oldElement.getCasesDepended() != 0) {
+ continue;
+ }
+
+ // set modifiable if started modifiable
+ boolean modifiable = tree.getRootNode().getBoard().getPuzzleElement(oldElement).isModifiable();
+
+ // unmodifiable if already modified
+ TreeNode modNode = ancestor.getParent().getParents().get(0);
+ while (modNode.getParent()!=null) {
+ Board modBoard = modNode.getParent().getBoard();
+ if (modBoard.getModifiedData().contains(modBoard.getPuzzleElement(oldElement))) {
+ modifiable = false;
+ break;
+ }
+ modNode = modNode.getParent().getParents().get(0);
+ }
+ oldElement.setModifiable(modifiable);
+ }
+ }
+ }
+
transView.getParentViews().forEach(n -> n.removeChildrenView(transView));
removeTreeTransition(trans);
}
@@ -331,35 +380,7 @@ public void onTreeElementRemoved(TreeElement element) {
public void onTreeSelectionChanged(TreeViewSelection selection) {
this.selection.getSelectedViews().forEach(v -> v.setSelected(false));
selection.getSelectedViews().forEach(v -> v.setSelected(true));
-
this.selection = selection;
-
-// List selectedViews = selection.getSelectedViews();
-// Point avg = new Point();
-// for(TreeElementView elementView : selectedViews) {
-// if(elementView.getType() == NODE) {
-// TreeNodeView nodeView = (TreeNodeView)elementView;
-// avg.x += nodeView.getX();
-// avg.y += nodeView.getY();
-// } else {
-// TreeTransitionView transitionView = (TreeTransitionView) elementView;
-// avg.x += transitionView.getEndX();
-// avg.y += transitionView.getEndY();
-// }
-// }
-// avg.x /= selectedViews.size();
-// avg.y /= selectedViews.size();
-//
-// Point pos = viewport.getViewPosition();
-// if(pos.x < avg.x) {
-// pos.x = avg.x - pos.x;
-// }
-// if(pos.y < avg.y) {
-// pos.y = avg.y - pos.y;
-// }
-//
-// viewport.setViewPosition(pos);
-
repaint();
}
@@ -383,6 +404,46 @@ public TreeElementView getElementView(TreeElement element) {
private void removeTreeNode(TreeNode node) {
viewMap.remove(node);
+ List children = node.getChildren();
+
+ // if child is a case rule, unlock ancestor elements
+ if (!children.isEmpty()) {
+ Rule rule = children.get(0).getRule();
+ if (rule instanceof CaseRule) {
+ CaseRule caseRule = (CaseRule)rule;
+ // set dependent elements to be modifiable by ancestors (if not dependent on others)
+ List ancestors = node.getAncestors();
+ for (TreeNode ancestor : ancestors) {
+ // for all ancestors but root
+ if (ancestor.getParent() == null) {
+ continue;
+ }
+ for (PuzzleElement pelement : caseRule.dependentElements(node.getBoard(), children.get(0).getSelection())) {
+ // decrement, unlock if 0 cases depended
+ PuzzleElement oldElement = ancestor.getParent().getBoard().getPuzzleElement(pelement);
+ oldElement.setCasesDepended(oldElement.getCasesDepended() - 1);
+ if (oldElement.getCasesDepended() == 0) {
+ continue;
+ }
+
+ // set modifiable if started modifiable
+ boolean modifiable = tree.getRootNode().getBoard().getPuzzleElement(oldElement).isModifiable();
+
+ // unmodifiable if already modified
+ TreeNode modNode = ancestor.getParent().getParents().get(0);
+ while (modNode.getParent() != null) {
+ Board modBoard = modNode.getParent().getBoard();
+ if (modBoard.getModifiedData().contains(modBoard.getPuzzleElement(oldElement))) {
+ modifiable = false;
+ break;
+ }
+ modNode = modNode.getParent().getParents().get(0);
+ }
+ oldElement.setModifiable(modifiable);
+ }
+ }
+ }
+ }
node.getChildren().forEach(t -> removeTreeTransition(t));
}
@@ -405,6 +466,27 @@ private void addTreeNode(TreeNode node) {
viewMap.put(node, nodeView);
if (!node.getChildren().isEmpty()) {
+
+ // if adding a case rule, lock dependent ancestor elements
+ Rule rule = node.getChildren().get(0).getRule();
+ if (rule instanceof CaseRule) {
+ CaseRule caseRule = (CaseRule)rule;
+
+ List ancestors = node.getAncestors();
+ for (TreeNode ancestor : ancestors) {
+ // for all ancestors but root
+ if (ancestor.getParent() == null) {
+ continue;
+ }
+ for (PuzzleElement element : caseRule.dependentElements(node.getBoard(), node.getChildren().get(0).getSelection())) {
+ // increment and lock
+ PuzzleElement oldElement = ancestor.getParent().getBoard().getPuzzleElement(element);
+ oldElement.setCasesDepended(oldElement.getCasesDepended()+1);
+ oldElement.setModifiable(false);
+ }
+ }
+ }
+
node.getChildren().forEach(t -> addTreeTransition(t));
}
}
@@ -417,6 +499,26 @@ private void addTreeTransition(TreeTransition trans) {
TreeNodeView parentNodeView = (TreeNodeView) viewMap.get(parent);
transView.addParentView(parentNodeView);
parentNodeView.addChildrenView(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
+ 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);
+ oldElement.setModifiable(false);
+ }
+ }
+ }
}
viewMap.put(trans, transView);
diff --git a/src/main/resources/edu/rpi/legup/images/fillapix/cases/BlackOrWhite.png b/src/main/resources/edu/rpi/legup/images/fillapix/cases/BlackOrWhite.png
index ff234c17f..17df92f1a 100644
Binary files a/src/main/resources/edu/rpi/legup/images/fillapix/cases/BlackOrWhite.png and b/src/main/resources/edu/rpi/legup/images/fillapix/cases/BlackOrWhite.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/fillapix/cases/SatisfyClue.png b/src/main/resources/edu/rpi/legup/images/fillapix/cases/SatisfyClue.png
new file mode 100644
index 000000000..8d84efed9
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/fillapix/cases/SatisfyClue.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/fillapix/contradictions/TooFewBlackCells.png b/src/main/resources/edu/rpi/legup/images/fillapix/contradictions/TooFewBlackCells.png
index b017078a2..b93d81e67 100644
Binary files a/src/main/resources/edu/rpi/legup/images/fillapix/contradictions/TooFewBlackCells.png and b/src/main/resources/edu/rpi/legup/images/fillapix/contradictions/TooFewBlackCells.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/fillapix/contradictions/TooManyBlackCells.png b/src/main/resources/edu/rpi/legup/images/fillapix/contradictions/TooManyBlackCells.png
index a0b27424d..393a8c544 100644
Binary files a/src/main/resources/edu/rpi/legup/images/fillapix/contradictions/TooManyBlackCells.png and b/src/main/resources/edu/rpi/legup/images/fillapix/contradictions/TooManyBlackCells.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/fillapix/rules/FinishWithBlack.png b/src/main/resources/edu/rpi/legup/images/fillapix/rules/FinishWithBlack.png
index 41e540ad1..d098bce41 100644
Binary files a/src/main/resources/edu/rpi/legup/images/fillapix/rules/FinishWithBlack.png and b/src/main/resources/edu/rpi/legup/images/fillapix/rules/FinishWithBlack.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/fillapix/rules/FinishWithWhite.png b/src/main/resources/edu/rpi/legup/images/fillapix/rules/FinishWithWhite.png
index 330f705f1..758ca7591 100644
Binary files a/src/main/resources/edu/rpi/legup/images/fillapix/rules/FinishWithWhite.png and b/src/main/resources/edu/rpi/legup/images/fillapix/rules/FinishWithWhite.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/fillapix/rules/Mirror.png b/src/main/resources/edu/rpi/legup/images/fillapix/rules/Mirror.png
new file mode 100644
index 000000000..991408d9c
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/fillapix/rules/Mirror.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/fillapix/rules/NontouchingShared.png b/src/main/resources/edu/rpi/legup/images/fillapix/rules/NontouchingShared.png
new file mode 100644
index 000000000..1be04f3ce
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/fillapix/rules/NontouchingShared.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/fillapix/rules/TouchingCorners.png b/src/main/resources/edu/rpi/legup/images/fillapix/rules/TouchingCorners.png
new file mode 100644
index 000000000..f3eba46b6
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/fillapix/rules/TouchingCorners.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/fillapix/rules/TouchingSides.png b/src/main/resources/edu/rpi/legup/images/fillapix/rules/TouchingSides.png
new file mode 100644
index 000000000..6d3b12dfd
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/fillapix/rules/TouchingSides.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/fillapix/tiles/BlackTile.png b/src/main/resources/edu/rpi/legup/images/fillapix/tiles/BlackTile.png
new file mode 100644
index 000000000..93e169df8
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/fillapix/tiles/BlackTile.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/fillapix/tiles/NumberTile.png b/src/main/resources/edu/rpi/legup/images/fillapix/tiles/NumberTile.png
new file mode 100644
index 000000000..5a8540d02
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/fillapix/tiles/NumberTile.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/fillapix/tiles/UnknownTile.png b/src/main/resources/edu/rpi/legup/images/fillapix/tiles/UnknownTile.png
new file mode 100644
index 000000000..850fbf127
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/fillapix/tiles/UnknownTile.png differ
diff --git a/src/main/resources/edu/rpi/legup/images/fillapix/tiles/WhiteTile.png b/src/main/resources/edu/rpi/legup/images/fillapix/tiles/WhiteTile.png
new file mode 100644
index 000000000..fc2c683eb
Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/fillapix/tiles/WhiteTile.png differ
diff --git a/src/main/resources/edu/rpi/legup/legup/config b/src/main/resources/edu/rpi/legup/legup/config
index 24fdcf365..19e63a2a3 100644
--- a/src/main/resources/edu/rpi/legup/legup/config
+++ b/src/main/resources/edu/rpi/legup/legup/config
@@ -7,7 +7,7 @@
+ fileCreationDisabled="false"/>
-
\ No newline at end of file
+
diff --git a/src/test/java/legup/TestRunner.java b/src/test/java/legup/TestRunner.java
index 9d79c590e..3a74c4c61 100644
--- a/src/test/java/legup/TestRunner.java
+++ b/src/test/java/legup/TestRunner.java
@@ -42,8 +42,6 @@ public static void main(String[] args) {
Result result12 = JUnitCore.runClasses(TooManyBulbsContradictionRuleTest.class);
printTestResults(result12);
-
-
//nurikabe tests
Result result13 = JUnitCore.runClasses(BlackBetweenRegionsDirectRuleTest.class);
printTestResults(result13);
@@ -76,7 +74,6 @@ public static void main(String[] args) {
Result result27 = JUnitCore.runClasses(WhiteBottleNeckDirectRuleTest.class);
printTestResults(result27);
-
// Treetent
Result result28 = JUnitCore.runClasses(EmptyFieldDirectRuleTest.class);
printTestResults(result28);
@@ -94,6 +91,8 @@ public static void main(String[] args) {
printTestResults(result34);
Result result35 = JUnitCore.runClasses(TreeForTentDirectRuleTest.class);
printTestResults(result35);
+ Result result36 = JUnitCore.runClasses(TentOrGrassCaseRuleTest.class);
+ printTestResults(result36);
}
private static void printTestResults(Result result) {
diff --git a/src/test/java/puzzles/lightup/rules/BulbsInPathContradictionRuleTest.java b/src/test/java/puzzles/lightup/rules/BulbsInPathContradictionRuleTest.java
index b595fec15..0e7930751 100644
--- a/src/test/java/puzzles/lightup/rules/BulbsInPathContradictionRuleTest.java
+++ b/src/test/java/puzzles/lightup/rules/BulbsInPathContradictionRuleTest.java
@@ -34,6 +34,7 @@ public void BulbsInPathContradictionRule_LightInHorizontalPath() throws InvalidF
Assert.assertNull(RULE.checkContradictionAt(board, board.getCell(0, 0)));
Assert.assertNull(RULE.checkContradictionAt(board, board.getCell(2, 0)));
+
Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(0, 1)));
}
@@ -67,4 +68,19 @@ public void BulbsInPathContradictionRule_BlockInVerticalPath() throws InvalidFil
Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(1, 1)));
}
+
+ @Test
+ public void BulbsInPathContradictionRule_BlockInHorizontalPath() throws InvalidFileFormatException{
+ TestUtilities.importTestBoard("puzzles/lightup/rules/BulbsInPathContradictionRule/BlockInHorizontalPath", lightUp);
+ TreeNode rootNode = lightUp.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ LightUpBoard board = (LightUpBoard) transition.getBoard();
+ Assert.assertNotNull(RULE.checkContradiction(board));
+ Assert.assertNotNull(RULE.checkContradictionAt(board,board.getCell(0,0)));
+ Assert.assertNotNull(RULE.checkContradictionAt(board,board.getCell(2,0)));
+ Assert.assertNotNull(RULE.checkContradictionAt(board,board.getCell(1,1)));
+
+ }
}
diff --git a/src/test/java/puzzles/lightup/rules/CannotLightACellContradictionRuleTest.java b/src/test/java/puzzles/lightup/rules/CannotLightACellContradictionRuleTest.java
index 447476dbb..7b3ffd2b9 100644
--- a/src/test/java/puzzles/lightup/rules/CannotLightACellContradictionRuleTest.java
+++ b/src/test/java/puzzles/lightup/rules/CannotLightACellContradictionRuleTest.java
@@ -21,13 +21,13 @@ public static void setUp() {
lightUp = new LightUp();
}
- @Test
+ @Test
//extensive full testing of null and non-null in a 5x5 board
public void FullLightTest() throws InvalidFileFormatException {
TestUtilities.importTestBoard("puzzles/lightup/rules/CannotLightACellContradictionRule/FullLightTest", lightUp);
TreeNode rootNode = lightUp.getTree().getRootNode();
TreeTransition transition = rootNode.getChildren().get(0);
- transition.setRule(RULE);
+ transition.setRule(RULE);
LightUpBoard board = (LightUpBoard) transition.getBoard();
//confirm there is a contradiction somewhere on the board
@@ -36,7 +36,7 @@ public void FullLightTest() throws InvalidFileFormatException {
//confirm it is impossible to light up these squares
Assert.assertNull(RULE.checkContradictionAt(board, board.getCell(1, 3)));
Assert.assertNull(RULE.checkContradictionAt(board, board.getCell(3, 3)));
-
+
//confirm these are not required to be lit because they are already lit or unable to be
Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(0, 0)));
Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(1, 1)));
@@ -44,13 +44,13 @@ public void FullLightTest() throws InvalidFileFormatException {
Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(3, 2)));
}
- @Test
+ @Test
//simple contradiction testing for null and non-null in a 3x3 board
public void CannotLightMiddleTest() throws InvalidFileFormatException {
TestUtilities.importTestBoard("puzzles/lightup/rules/CannotLightACellContradictionRule/CannotLight", lightUp);
TreeNode rootNode = lightUp.getTree().getRootNode();
TreeTransition transition = rootNode.getChildren().get(0);
- transition.setRule(RULE);
+ transition.setRule(RULE);
LightUpBoard board = (LightUpBoard) transition.getBoard();
//confirm there is a contradiction somewhere on the board
@@ -68,4 +68,24 @@ public void CannotLightMiddleTest() throws InvalidFileFormatException {
Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(1, 2)));
Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(2, 1)));
}
+
+ @Test
+ public void CanLightTest() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/lightup/rules/CannotLightACellContradictionRule/CanLightTest", lightUp);
+ TreeNode rootNode = lightUp.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ LightUpBoard board = (LightUpBoard) transition.getBoard();
+ //confirm there is not a contradiction somewhere on the board
+ Assert.assertNotNull(RULE.checkContradiction(board));
+
+ //confirm that these cells can be lit, are already lit, or that they are just black blocks
+ Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(1, 3)));
+ Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(3, 3)));
+ Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(0, 0)));
+ Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(1, 1)));
+ Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(1, 0)));
+ Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(3, 2)));
+ }
}
diff --git a/src/test/java/puzzles/lightup/rules/EmptyCellinLightDirectRuleTest.java b/src/test/java/puzzles/lightup/rules/EmptyCellinLightDirectRuleTest.java
index 637804892..b0a2d10ed 100644
--- a/src/test/java/puzzles/lightup/rules/EmptyCellinLightDirectRuleTest.java
+++ b/src/test/java/puzzles/lightup/rules/EmptyCellinLightDirectRuleTest.java
@@ -59,16 +59,33 @@ public void EmptyCellinLightDirectRule() throws InvalidFileFormatException{
cell7.setData(LightUpCellType.EMPTY.value);
board.addModifiedData(cell7);
+ LightUpCell cell8 = board.getCell(3,0);
+ cell8.setData(LightUpCellType.EMPTY.value);
+ board.addModifiedData(cell8);
+
+ LightUpCell cell9 = board.getCell(3,2);
+ cell9.setData(LightUpCellType.EMPTY.value);
+ board.addModifiedData(cell9);
+
+ LightUpCell cell10 = board.getCell(2,3);
+ cell10.setData(LightUpCellType.EMPTY.value);
+ board.addModifiedData(cell10);
+
+ LightUpCell cell11 = board.getCell(0,3);
+ cell11.setData(LightUpCellType.EMPTY.value);
+ board.addModifiedData(cell11);
+
//confirm there is a logical following of the EmptyCellinLight rule
Assert.assertNull(RULE.checkRule(transition));
- //cells (0,0) and (2,2) are not empty because they have lightbulbs, and (1,1)
- //because it is a black tile. Confirm the rest are empty
+ //cells (0,0) and (2,2) are not empty because they have lightbulbs, (1,1)
+ //because it is a black tile, and (1,3),(3,1),(3,3) because they are not lit. Confirm the rest are empty
LightUpCell c;
for (int i = 0; i < board.getHeight(); i++) {
for (int j = 0; j < board.getWidth(); j++) {
c = board.getCell(j, i);
- if ((i == 0 && j == 0) || (i == 2 && j == 2) || (i == 1 && j == 1)){
+ if ((i == 0 && j == 0) || (i == 2 && j == 2) || (i == 1 && j == 1) || (i == 1 && j == 3) || (i == 3 && j == 1)
+ || (i==3 && j==3)){
Assert.assertNotNull(RULE.checkRuleAt(transition, c));
}
else {
diff --git a/src/test/java/puzzles/nurikabe/rules/BlackBetweenRegionsDirectRuleTest.java b/src/test/java/puzzles/nurikabe/rules/BlackBetweenRegionsDirectRuleTest.java
index b32ce23ce..7e8b5eb83 100644
--- a/src/test/java/puzzles/nurikabe/rules/BlackBetweenRegionsDirectRuleTest.java
+++ b/src/test/java/puzzles/nurikabe/rules/BlackBetweenRegionsDirectRuleTest.java
@@ -30,6 +30,9 @@ public static void setUp() {
nurikabe = new Nurikabe();
}
+ /**
+ * Tests the Black Between Regions direct rule for regions that are diagonal to each other (diagonal going from top left to bottom right)
+ */
@Test
public void BlackBetweenRegionsDirectRule_DiagonalBlackBetweenRegions1Test() throws InvalidFileFormatException {
TestUtilities.importTestBoard("puzzles/nurikabe/rules/BlackBetweenRegionsDirectRule/DiagonalBlackBetweenRegions1", nurikabe);
@@ -62,6 +65,9 @@ public void BlackBetweenRegionsDirectRule_DiagonalBlackBetweenRegions1Test() thr
}
}
+ /**
+ * Tests the Black Between Regions direct rule for regions that are diagonal to each other (diagonal going from bottom left to top right)
+ */
@Test
public void BlackBetweenRegionsDirectRule_DiagonalBlackBetweenRegions2Test() throws InvalidFileFormatException {
TestUtilities.importTestBoard("puzzles/nurikabe/rules/BlackBetweenRegionsDirectRule/DiagonalBlackBetweenRegions2", nurikabe);
@@ -94,6 +100,9 @@ public void BlackBetweenRegionsDirectRule_DiagonalBlackBetweenRegions2Test() thr
}
}
+ /**
+ * Tests the Black Between Regions direct rule for regions that are horizontally opposite each other
+ */
@Test
public void BlackBetweenRegionsDirectRule_HorizontalBlackBetweenRegionsTest() throws InvalidFileFormatException {
TestUtilities.importTestBoard("puzzles/nurikabe/rules/BlackBetweenRegionsDirectRule/HorizontalBlackBetweenRegions", nurikabe);
@@ -123,6 +132,9 @@ public void BlackBetweenRegionsDirectRule_HorizontalBlackBetweenRegionsTest() th
}
}
+ /**
+ * Tests the Black Between Regions direct rule for regions that are vertically opposite each other
+ */
@Test
public void BlackBetweenRegionsDirectRule_VerticalBlackBetweenRegionsTest() throws InvalidFileFormatException {
TestUtilities.importTestBoard("puzzles/nurikabe/rules/BlackBetweenRegionsDirectRule/VerticalBlackBetweenRegions", nurikabe);
@@ -151,4 +163,28 @@ public void BlackBetweenRegionsDirectRule_VerticalBlackBetweenRegionsTest() thro
}
}
}
+
+ /**
+ * Tests the Black Between Regions direct rule for a false application of the rule, where a black tile is enclosed by one region
+ */
+ @Test
+ public void BlackBetweenRegionsDirectRule_FalseBlackBetweenRegionsTest() throws InvalidFileFormatException{
+ TestUtilities.importTestBoard("puzzles/nurikabe/rules/BlackBetweenRegionsDirectRule/FalseBlackBetweenRegions",nurikabe);
+ TreeNode rootNode = nurikabe.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ NurikabeBoard board = (NurikabeBoard) transition.getBoard();
+ NurikabeCell cell = board.getCell(1,1);
+ cell.setData(NurikabeType.BLACK.toValue());
+ board.addModifiedData(cell);
+
+ Assert.assertNotNull(RULE.checkRule(transition));
+
+ for(int i=0; i cases = RULE.getCases(board,cell);
+
+ Assert.assertEquals(2,cases.size());
+
+ NurikabeBoard caseBoard = (NurikabeBoard) cases.get(0);
+ NurikabeBoard caseBoard2 = (NurikabeBoard) cases.get(1);
+
+ NurikabeType board1Type = caseBoard.getCell(0,0).getType();
+ NurikabeType board2Type = caseBoard2.getCell(0,0).getType();
+
+ Assert.assertTrue((board1Type.equals(NurikabeType.BLACK) || board1Type.equals(NurikabeType.WHITE)) &&
+ (board2Type.equals(NurikabeType.BLACK) || board2Type.equals(NurikabeType.WHITE)));
+ Assert.assertFalse(board1Type.equals(board2Type));
+
+ Assert.assertEquals(caseBoard.getHeight(),caseBoard2.getHeight(), board.getHeight());
+ Assert.assertEquals(caseBoard.getWidth(),caseBoard2.getWidth(), board.getWidth());
+
+ for(int i=0; i cases = RULE.getCases(board, cell);
+
+ // Make sure that the rule checks out
+ Assert.assertNotNull(RULE.checkRule(transition));
+
+ // Make sure there are two branches
+ Assert.assertEquals(2, cases.size());
+
+ ShortTruthTableBoard caseBoard1 = (ShortTruthTableBoard) cases.get(0);
+ ShortTruthTableCellType board1A = caseBoard1.getCell(aX, aY).getType();
+ ShortTruthTableCellType board1B = caseBoard1.getCell(bX, bY).getType();
+
+ ShortTruthTableBoard caseBoard2 = (ShortTruthTableBoard) cases.get(1);
+ ShortTruthTableCellType board2A = caseBoard2.getCell(aX, aY).getType();
+ ShortTruthTableCellType board2B = caseBoard2.getCell(bX, bY).getType();
+
+ // Assert that the corresponding cells for the different case rules do not
+ // match with each other
+ Assert.assertNotEquals(board1A, board2A);
+ Assert.assertNotEquals(board1B, board2B);
+
+ // First assert the two cells are not equal, then verify that they are either
+ // unknown or false.
+ Assert.assertNotEquals(board1A, board1B);
+ Assert.assertTrue(board1A.equals(ShortTruthTableCellType.UNKNOWN) || board1A.equals(ShortTruthTableCellType.FALSE));
+ Assert.assertTrue(board1B.equals(ShortTruthTableCellType.UNKNOWN) || board1B.equals(ShortTruthTableCellType.FALSE));
+
+ Assert.assertNotEquals(board2A, board2B);
+ Assert.assertTrue(board2A.equals(ShortTruthTableCellType.UNKNOWN) || board1A.equals(ShortTruthTableCellType.FALSE));
+ Assert.assertTrue(board2B.equals(ShortTruthTableCellType.UNKNOWN) || board2B.equals(ShortTruthTableCellType.FALSE));
+
+ // Verify the board dimensions are unchanged
+ Assert.assertEquals(caseBoard1.getHeight(), caseBoard2.getHeight(), board.getHeight());
+ Assert.assertEquals(caseBoard1.getWidth(), caseBoard2.getWidth(), board.getWidth());
+
+ // Verify that everywhere else on the board is unchanged
+ for (int i = 0; i< caseBoard1.getWidth(); i++) {
+ for (int j = 0; j < caseBoard1.getHeight(); j++) {
+ // Make sure not to check the two cells that should be different
+ if (!((i == aX && j == aY) || (i == bX && j == bY))) {
+ Assert.assertEquals(caseBoard1.getCell(i, j).getType(), caseBoard2.getCell(i, j).getType());
+ }
+ }
+ }
+ }
+
+ /**
+ * Given a statement A ^ B where ^ is false, tests this case rule by ensuring that
+ * two branches are created: one where A is false and one where B is false.
+ */
+ @Test
+ public void SimpleStatement1FalseTest() throws InvalidFileFormatException {
+ falseAndTest("SimpleStatement1_False", 1, 0, 0, 0,
+ 2, 0);
+ }
+
+ /**
+ * Given a statement ~(A|B)^(C^D) where the first ^ is false, tests this case rule
+ * by ensuring that two branches are created: one where ~ is false and one where
+ * the second ^ is false.
+ */
+ @Test
+ public void ComplexStatement1FalseTest() throws InvalidFileFormatException {
+ falseAndTest("ComplexStatement1_False", 6, 0, 0, 0,
+ 9, 0);
+ }
+
+ private void trueAndTest(String fileName,
+ int andX, int andY,
+ int aX, int aY,
+ int bX, int bY) throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/AndCaseRule/" + fileName, stt);
+ TreeNode rootNode = stt.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard();
+ ShortTruthTableCell cell = board.getCell(andX,andY);
+ ArrayList cases = RULE.getCases(board, cell);
+
+ // Make sure that the rule checks out
+ Assert.assertNotNull(RULE.checkRule(transition));
+
+ // There should only be 1 branch
+ Assert.assertEquals(1, cases.size());
+
+ ShortTruthTableBoard caseBoard = (ShortTruthTableBoard) cases.get(0);
+ ShortTruthTableCellType caseBoardAType = caseBoard.getCell(aX, aY).getType();
+ ShortTruthTableCellType caseBoardBType = caseBoard.getCell(bX, bY).getType();
+
+ // Both cells should be true
+ Assert.assertEquals(caseBoardAType, ShortTruthTableCellType.TRUE);
+ Assert.assertEquals(caseBoardBType, ShortTruthTableCellType.TRUE);
+ Assert.assertEquals(caseBoardAType, caseBoardBType);
+
+ // Verify the board dimensions are unchanged
+ Assert.assertEquals(caseBoard.getHeight(), caseBoard.getHeight(), board.getHeight());
+ }
+
+ /**
+ * Given a statement A ^ B where ^ is false, tests this case rule by ensuring that
+ * one branch is created where A and B are both true.
+ */
+ @Test
+ public void SimpleStatement1AndTest() throws InvalidFileFormatException {
+ trueAndTest("SimpleStatement1_True", 1, 0, 0, 0,
+ 2, 0);
+ }
+
+ /**
+ * Given a statement ~(A|B)^(C^D) where the first ^ is true, tests this case rule
+ * by ensuring that one branch is created where both ~ and the second ^ are true.
+ */
+ @Test
+ public void ComplexStatement1TrueTest() throws InvalidFileFormatException {
+ trueAndTest("ComplexStatement1_True", 6, 0, 0, 0,
+ 9, 0);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/puzzles/shorttruthtable/rules/AndEliminationDirectRuleTest.java b/src/test/java/puzzles/shorttruthtable/rules/AndEliminationDirectRuleTest.java
new file mode 100644
index 000000000..0d94eb672
--- /dev/null
+++ b/src/test/java/puzzles/shorttruthtable/rules/AndEliminationDirectRuleTest.java
@@ -0,0 +1,204 @@
+package puzzles.shorttruthtable.rules;
+
+import edu.rpi.legup.model.tree.TreeNode;
+import edu.rpi.legup.model.tree.TreeTransition;
+import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTable;
+import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableBoard;
+import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCell;
+import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCellType;
+import edu.rpi.legup.puzzle.shorttruthtable.rules.basic.elimination.DirectRuleAndElimination;
+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 AndEliminationDirectRuleTest {
+ private static final DirectRuleAndElimination RULE = new DirectRuleAndElimination();
+ private static ShortTruthTable stt;
+
+ @BeforeClass
+ public static void setup() {
+ MockGameBoardFacade.getInstance();
+ stt = new ShortTruthTable();
+ }
+
+ /**
+ * Given one statement: B^C where ^ is true
+ *
+ * Checks all possible combinations of true, false, and unknown for B and C
+ * except for where both B and C are true and asserts that each one of them
+ * is not a valid application of the rule.
+ *
+ * @throws InvalidFileFormatException
+ */
+ @Test
+ public void trueAndTest1() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/AndEliminationDirectRule/TrueAnd", stt);
+ TreeNode rootNode = stt.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ ShortTruthTableCellType[] cellTypes = {ShortTruthTableCellType.TRUE, ShortTruthTableCellType.FALSE, ShortTruthTableCellType.UNKNOWN};
+
+ for (ShortTruthTableCellType cellType1 : cellTypes) {
+ for (ShortTruthTableCellType cellType2 : cellTypes) {
+ if (cellType1 == cellType2 && cellType1 == ShortTruthTableCellType.TRUE) {
+ continue;
+ }
+
+ ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard();
+ ShortTruthTableCell bonnie = board.getCell(0, 0);
+ ShortTruthTableCell clyde = board.getCell(2, 0);
+
+ if (cellType1 != ShortTruthTableCellType.UNKNOWN) {
+ bonnie.setData(cellType1);
+ board.addModifiedData(bonnie);
+ }
+
+ if (cellType2 != ShortTruthTableCellType.UNKNOWN) {
+ clyde.setData(cellType2);
+ board.addModifiedData(clyde);
+ }
+
+ Assert.assertNotNull(RULE.checkRule(transition));
+ }
+ }
+ }
+
+ /**
+ * Given one statement: B^C where ^ is true
+ *
+ * Checks all possible combinations of true and unknown for B and C
+ * except for where both B and C are unknown and asserts that each one
+ * of them is a valid application of the rule.
+ *
+ * @throws InvalidFileFormatException
+ */
+ @Test
+ public void trueAndTest2() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/AndEliminationDirectRule/TrueAnd", stt);
+ TreeNode rootNode = stt.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ ShortTruthTableCellType[] cellTypes = {ShortTruthTableCellType.TRUE, ShortTruthTableCellType.UNKNOWN};
+
+ for (ShortTruthTableCellType cellType1 : cellTypes) {
+ for (ShortTruthTableCellType cellType2 : cellTypes) {
+ if (cellType1 == cellType2 && cellType1 == ShortTruthTableCellType.UNKNOWN) {
+ continue;
+ }
+
+ ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard();
+ ShortTruthTableCell bonnie = board.getCell(0, 0);
+ ShortTruthTableCell clyde = board.getCell(2, 0);
+
+ if (cellType1 != ShortTruthTableCellType.UNKNOWN) {
+ bonnie.setData(cellType1);
+ board.addModifiedData(bonnie);
+ }
+
+ if (cellType2 != ShortTruthTableCellType.UNKNOWN) {
+ clyde.setData(cellType2);
+ board.addModifiedData(clyde);
+ }
+
+ Assert.assertNull(RULE.checkRule(transition));
+ }
+ }
+ }
+
+ /**
+ * Given one statement: B^C where ^ is false
+ *
+ * Checks all possible combinations of true, false, and unknown for B and C
+ * and asserts that each one of them is not a valid application of the rule.
+ *
+ * @throws InvalidFileFormatException
+ */
+ @Test
+ public void falseAndWithUnknownsTest() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/AndEliminationDirectRule/FalseAnd", stt);
+ TreeNode rootNode = stt.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ ShortTruthTableCellType[] cellTypes = {ShortTruthTableCellType.TRUE, ShortTruthTableCellType.FALSE, ShortTruthTableCellType.UNKNOWN};
+
+ for (ShortTruthTableCellType cellType1 : cellTypes) {
+ for (ShortTruthTableCellType cellType2 : cellTypes) {
+ ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard();
+ ShortTruthTableCell bonnie = board.getCell(0, 0);
+ ShortTruthTableCell clyde = board.getCell(2, 0);
+
+ if (cellType1 != ShortTruthTableCellType.UNKNOWN) {
+ bonnie.setData(cellType1);
+ board.addModifiedData(bonnie);
+ }
+
+ if (cellType2 != ShortTruthTableCellType.UNKNOWN) {
+ clyde.setData(cellType2);
+ board.addModifiedData(clyde);
+ }
+
+ Assert.assertNotNull(RULE.checkRule(transition));
+ }
+ }
+ }
+
+ /**
+ * Given one statement: B^C where both B and ^ are false
+ *
+ * Asserts that this is not a valid application of the rule if C is set to
+ * either true or false.
+ *
+ * @throws InvalidFileFormatException
+ */
+ @Test
+ public void falseAndWithKnownFalseTest() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/AndEliminationDirectRule/FalseAndWithKnownFalse", stt);
+ TreeNode rootNode = stt.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard();
+
+ ShortTruthTableCell clyde = board.getCell(2, 0);
+ clyde.setData(ShortTruthTableCellType.TRUE);
+ board.addModifiedData(clyde);
+ Assert.assertNotNull(RULE.checkRule(transition));
+
+ clyde.setData(ShortTruthTableCellType.FALSE);
+ board.addModifiedData(clyde);
+ Assert.assertNotNull(RULE.checkRule(transition));
+ }
+
+ /**
+ * Given one statement: B^C where B is true and ^ is false
+ *
+ * Asserts that this is a valid application of the rule if and only if C is
+ * set to false.
+ *
+ * @throws InvalidFileFormatException
+ */
+ @Test
+ public void falseAndWithKnownTrueTest() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/AndEliminationDirectRule/FalseAndWithKnownTrue", stt);
+ TreeNode rootNode = stt.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard();
+
+ ShortTruthTableCell clyde = board.getCell(2, 0);
+ clyde.setData(ShortTruthTableCellType.TRUE);
+ board.addModifiedData(clyde);
+ Assert.assertNotNull(RULE.checkRule(transition));
+
+ clyde.setData(ShortTruthTableCellType.FALSE);
+ board.addModifiedData(clyde);
+ Assert.assertNull(RULE.checkRule(transition));
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/puzzles/shorttruthtable/rules/AndIntroductionDirectRuleTest.java b/src/test/java/puzzles/shorttruthtable/rules/AndIntroductionDirectRuleTest.java
new file mode 100644
index 000000000..4d4e009b2
--- /dev/null
+++ b/src/test/java/puzzles/shorttruthtable/rules/AndIntroductionDirectRuleTest.java
@@ -0,0 +1,105 @@
+package puzzles.shorttruthtable.rules;
+
+import edu.rpi.legup.model.tree.TreeNode;
+import edu.rpi.legup.model.tree.TreeTransition;
+import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTable;
+import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableBoard;
+import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCell;
+import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCellType;
+import edu.rpi.legup.puzzle.shorttruthtable.rules.basic.introduction.DirectRuleAndIntroduction;
+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 AndIntroductionDirectRuleTest {
+ private static final DirectRuleAndIntroduction RULE = new DirectRuleAndIntroduction();
+ private static ShortTruthTable stt;
+
+ @BeforeClass
+ public static void setup() {
+ MockGameBoardFacade.getInstance();
+ stt = new ShortTruthTable();
+ }
+
+ /**
+ * Given a statement: A ^ B
+ *
+ * Asserts that if at least 1 of A or B is false, then this is a valid application
+ * of the rule if and only if ^ is false.
+ *
+ * @param filePath The file path for test board setup.
+ * @throws InvalidFileFormatException
+ */
+ @Test
+ public void FalseAndTest() throws InvalidFileFormatException {
+ String path = "puzzles/shorttruthtable/rules/AndIntroductionDirectRule/";
+ falseAndTestHelper(path + "FUF");
+ falseAndTestHelper(path + "FUU");
+ falseAndTestHelper(path + "UUF");
+ falseAndTestHelper(path + "FUT");
+ falseAndTestHelper(path + "TUF");
+ }
+
+ private void falseAndTestHelper(String filePath) throws InvalidFileFormatException {
+ TestUtilities.importTestBoard(filePath, stt);
+ TreeNode rootNode = stt.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard();
+ ShortTruthTableCell and = board.getCell(1, 0);
+
+ and.setData(ShortTruthTableCellType.TRUE);
+ board.addModifiedData(and);
+ Assert.assertNotNull(RULE.checkRule(transition));
+
+ and.setData(ShortTruthTableCellType.FALSE);
+ board.addModifiedData(and);
+ Assert.assertNull(RULE.checkRule(transition));
+ }
+
+ /**
+ * Given a statement: A ^ B
+ *
+ * Asserts that setting ^ to true is a valid application of the rule if
+ * and only if both A and B are true.
+ *
+ * @param filePath The file path for test board setup.
+ * @throws InvalidFileFormatException
+ */
+ @Test
+ public void FalseOrTest() throws InvalidFileFormatException {
+ String path = "puzzles/shorttruthtable/rules/AndIntroductionDirectRule/";
+ String[] letters = {"T", "F", "U"};
+ for (String first : letters) {
+ for (String second : letters) {
+ trueAndTestHelper(path + first + "U" + second);
+ }
+ }
+ }
+
+ private void trueAndTestHelper(String filePath) throws InvalidFileFormatException {
+ TestUtilities.importTestBoard(filePath, stt);
+ TreeNode rootNode = stt.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard();
+ ShortTruthTableCell a = board.getCell(0, 0);
+ ShortTruthTableCell b = board.getCell(2, 0);
+ ShortTruthTableCell and = board.getCell(1, 0);
+
+ and.setData(ShortTruthTableCellType.TRUE);
+ board.addModifiedData(and);
+
+ if (a.getType() == ShortTruthTableCellType.TRUE && b.getType() == ShortTruthTableCellType.TRUE) {
+ Assert.assertNull(RULE.checkRule(transition));
+ }
+ else {
+ Assert.assertNotNull(RULE.checkRule(transition));
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/puzzles/shorttruthtable/rules/AtomicDirectRuleTest.java b/src/test/java/puzzles/shorttruthtable/rules/AtomicDirectRuleTest.java
new file mode 100644
index 000000000..51aa213c6
--- /dev/null
+++ b/src/test/java/puzzles/shorttruthtable/rules/AtomicDirectRuleTest.java
@@ -0,0 +1,188 @@
+package puzzles.shorttruthtable.rules;
+
+import edu.rpi.legup.model.tree.TreeNode;
+import edu.rpi.legup.model.tree.TreeTransition;
+import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTable;
+import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableBoard;
+import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCell;
+import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCellType;
+import edu.rpi.legup.puzzle.shorttruthtable.rules.basic.DirectRuleAtomic;
+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 AtomicDirectRuleTest {
+ private static final DirectRuleAtomic RULE = new DirectRuleAtomic();
+ private static ShortTruthTable stt;
+
+ @BeforeClass
+ public static void setup() {
+ MockGameBoardFacade.getInstance();
+ stt = new ShortTruthTable();
+ }
+
+ /**
+ * Given two statements:
+ * A
+ * A
+ * where the first A is set to false.
+ *
+ * This test sets the second A to false and then asserts that this
+ * is a valid application of the rule.
+ *
+ * @throws InvalidFileFormatException
+ */
+ @Test
+ public void MatchingFalseTest() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/AtomicDirectRule/FalseA", stt);
+ TreeNode rootNode = stt.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard();
+
+ ShortTruthTableCell cell = board.getCell(0, 2);
+ cell.setData(ShortTruthTableCellType.FALSE);
+ board.addModifiedData(cell);
+
+ Assert.assertNull(RULE.checkRule(transition));
+ }
+
+ /**
+ * Given two statements:
+ * A
+ * A
+ * where the first A is set to false.
+ *
+ * This test sets the second A to true and then asserts that this
+ * is not a valid application of the rule.
+ *
+ * @throws InvalidFileFormatException
+ */
+ @Test
+ public void MismatchingFalseTest() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/AtomicDirectRule/FalseA", stt);
+ TreeNode rootNode = stt.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard();
+
+ ShortTruthTableCell cell = board.getCell(0, 2);
+ cell.setData(ShortTruthTableCellType.TRUE);
+ board.addModifiedData(cell);
+
+ Assert.assertNotNull(RULE.checkRule(transition));
+ }
+
+ /**
+ * Given two statements:
+ * B
+ * B
+ * where the first B is set to true.
+ *
+ * This test sets the second B to true and then asserts that this
+ * is a valid application of the rule.
+ *
+ * @throws InvalidFileFormatException
+ */
+ @Test
+ public void MatchingTrueTest() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/AtomicDirectRule/TrueB", stt);
+ TreeNode rootNode = stt.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard();
+
+ ShortTruthTableCell cell = board.getCell(0, 2);
+ cell.setData(ShortTruthTableCellType.TRUE);
+ board.addModifiedData(cell);
+
+ Assert.assertNull(RULE.checkRule(transition));
+ }
+
+ /**
+ * Given two statements:
+ * B
+ * B
+ * where the first B is set to true.
+ *
+ * This test sets the second B to false and then asserts that this
+ * is not a valid application of the rule.
+ *
+ * @throws InvalidFileFormatException
+ */
+ @Test
+ public void MismatchingTrueTest() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/AtomicDirectRule/TrueB", stt);
+ TreeNode rootNode = stt.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard();
+
+ ShortTruthTableCell cell = board.getCell(0, 2);
+ cell.setData(ShortTruthTableCellType.FALSE);
+ board.addModifiedData(cell);
+
+ Assert.assertNotNull(RULE.checkRule(transition));
+ }
+
+ /**
+ * Given two statements:
+ * C
+ * C
+ * where neither statement is set to anything.
+ *
+ * This test sets the second C to false and then asserts that this
+ * is not a valid application of the rule.
+ *
+ * @throws InvalidFileFormatException
+ */
+ @Test
+ public void NothingPreviouslyMarkedTest() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/AtomicDirectRule/Empty", stt);
+ TreeNode rootNode = stt.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard();
+
+ ShortTruthTableCell cell = board.getCell(0, 2);
+ cell.setData(ShortTruthTableCellType.FALSE);
+ board.addModifiedData(cell);
+
+ Assert.assertNotNull(RULE.checkRule(transition));
+ }
+
+ /**
+ * Given two statements:
+ * C
+ * C
+ * where neither statement is set to anything.
+ *
+ * This test sets the second C to true and then asserts that this
+ * is not a valid application of the rule.
+ *
+ * @throws InvalidFileFormatException
+ */
+ @Test
+ public void NothingPreviouslyMarkedTest2() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/AtomicDirectRule/Empty", stt);
+ TreeNode rootNode = stt.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard();
+
+ ShortTruthTableCell cell = board.getCell(0, 2);
+ cell.setData(ShortTruthTableCellType.TRUE);
+ board.addModifiedData(cell);
+
+ Assert.assertNotNull(RULE.checkRule(transition));
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/puzzles/shorttruthtable/rules/BiconditionalEliminationTest.java b/src/test/java/puzzles/shorttruthtable/rules/BiconditionalEliminationTest.java
new file mode 100644
index 000000000..05faf87bb
--- /dev/null
+++ b/src/test/java/puzzles/shorttruthtable/rules/BiconditionalEliminationTest.java
@@ -0,0 +1,373 @@
+package puzzles.shorttruthtable.rules;
+
+import edu.rpi.legup.model.tree.TreeNode;
+import edu.rpi.legup.model.tree.TreeTransition;
+import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTable;
+import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableBoard;
+import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCell;
+import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCellType;
+import edu.rpi.legup.puzzle.shorttruthtable.rules.basic.elimination.DirectRuleBiconditionalElimination;
+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 BiconditionalEliminationTest {
+ private static final DirectRuleBiconditionalElimination RULE = new DirectRuleBiconditionalElimination();
+ private static ShortTruthTable stt;
+
+ @BeforeClass
+ public static void setup() {
+ MockGameBoardFacade.getInstance();
+ stt = new ShortTruthTable();
+ }
+
+ /**
+ * Given one statement: A <-> B where both A and <-> are true
+ *
+ * Asserts that this is a valid application of the rule if and only if B is true.
+ *
+ * @throws InvalidFileFormatException
+ */
+ @Test
+ public void TrueBiconditionalWithTrueATest() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/BiconditionalEliminationDirectRule/TrueBiconditionalWithTrueA", stt);
+ TreeNode rootNode = stt.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard();
+ ShortTruthTableCell morty = board.getCell(2, 0);
+
+ // Asserts that this is not a valid application of the rule when B is unknown
+ morty.setData(ShortTruthTableCellType.UNKNOWN);
+ board.addModifiedData(morty);
+ Assert.assertNotNull(RULE.checkRule(transition));
+
+ // Asserts that this is a valid application of the rule when B is true
+ morty.setData(ShortTruthTableCellType.TRUE);
+ board.addModifiedData(morty);
+ Assert.assertNull(RULE.checkRule(transition));
+
+ // Asserts that this is not a valid application of the rule when B is false
+ morty.setData(ShortTruthTableCellType.FALSE);
+ board.addModifiedData(morty);
+ Assert.assertNotNull(RULE.checkRule(transition));
+ }
+
+ /**
+ * Given one statement: A <-> B where both B and <-> are true
+ *
+ * Asserts that this is a valid application of the rule if and only if A is true.
+ *
+ * @throws InvalidFileFormatException
+ */
+ @Test
+ public void TrueBiconditionalWithTrueBTest() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/BiconditionalEliminationDirectRule/TrueBiconditionalWithTrueB", stt);
+ TreeNode rootNode = stt.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard();
+ ShortTruthTableCell rick = board.getCell(0, 0);
+
+ // Asserts that this is a valid application of the rule when A is true
+ rick.setData(ShortTruthTableCellType.TRUE);
+ board.addModifiedData(rick);
+ Assert.assertNull(RULE.checkRule(transition));
+
+ // Asserts that this is not a valid application of the rule when A is unknown
+ rick.setData(ShortTruthTableCellType.UNKNOWN);
+ board.addModifiedData(rick);
+ Assert.assertNotNull(RULE.checkRule(transition));
+
+ // Asserts that this is not a valid application of the rule when A is false
+ rick.setData(ShortTruthTableCellType.FALSE);
+ board.addModifiedData(rick);
+ Assert.assertNotNull(RULE.checkRule(transition));
+ }
+
+
+ /**
+ * Given one statement: A <-> B where A is false and <-> is true
+ *
+ * Asserts that this is a valid application of the rule if and only if B is false.
+ *
+ * @throws InvalidFileFormatException
+ */
+ @Test
+ public void TrueBiconditionalWithFalseATest() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/BiconditionalEliminationDirectRule/TrueBiconditionalWithFalseA", stt);
+ TreeNode rootNode = stt.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard();
+ ShortTruthTableCell morty = board.getCell(2, 0);
+
+ // Asserts that this is not a valid application of the rule when B is unknown
+ morty.setData(ShortTruthTableCellType.UNKNOWN);
+ board.addModifiedData(morty);
+ Assert.assertNotNull(RULE.checkRule(transition));
+
+ // Asserts that this is not a valid application of the rule when B is true
+ morty.setData(ShortTruthTableCellType.TRUE);
+ board.addModifiedData(morty);
+ Assert.assertNotNull(RULE.checkRule(transition));
+
+ // Asserts that this is a valid application of the rule when B is false
+ morty.setData(ShortTruthTableCellType.FALSE);
+ board.addModifiedData(morty);
+ Assert.assertNull(RULE.checkRule(transition));
+ }
+
+ /**
+ * Given one statement: A <-> B where B is false and <-> is true
+ *
+ * Asserts that this is a valid application of the rule if and only if A is false.
+ *
+ * @throws InvalidFileFormatException
+ */
+ @Test
+ public void TrueBiconditionalWithFalseBTest() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/BiconditionalEliminationDirectRule/TrueBiconditionalWithFalseB", stt);
+ TreeNode rootNode = stt.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard();
+ ShortTruthTableCell rick = board.getCell(0, 0);
+
+ // Asserts that this is not a valid application of the rule when A is unknown
+ rick.setData(ShortTruthTableCellType.UNKNOWN);
+ board.addModifiedData(rick);
+ Assert.assertNotNull(RULE.checkRule(transition));
+
+ // Asserts that this is not a valid application of the rule when A is true
+ rick.setData(ShortTruthTableCellType.TRUE);
+ board.addModifiedData(rick);
+ Assert.assertNotNull(RULE.checkRule(transition));
+
+ // Asserts that this is a valid application of the rule when A is false
+ rick.setData(ShortTruthTableCellType.FALSE);
+ board.addModifiedData(rick);
+ Assert.assertNull(RULE.checkRule(transition));
+ }
+
+ /**
+ * Given one statement: A <-> B where A is true and <-> is false
+ *
+ * Asserts that this is a valid application of the rule if and only if B is false.
+ *
+ * @throws InvalidFileFormatException
+ */
+ @Test
+ public void FalseBiconditionalWithTrueATest() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/BiconditionalEliminationDirectRule/FalseBiconditionalWithTrueA", stt);
+ TreeNode rootNode = stt.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard();
+ ShortTruthTableCell morty = board.getCell(2, 0);
+
+ // Asserts that this is not a valid application of the rule when B is unknown
+ morty.setData(ShortTruthTableCellType.UNKNOWN);
+ board.addModifiedData(morty);
+ Assert.assertNotNull(RULE.checkRule(transition));
+
+ // Asserts that this is not a valid application of the rule when B is true
+ morty.setData(ShortTruthTableCellType.TRUE);
+ board.addModifiedData(morty);
+ Assert.assertNotNull(RULE.checkRule(transition));
+
+ // Asserts that this is a valid application of the rule when B is false
+ morty.setData(ShortTruthTableCellType.FALSE);
+ board.addModifiedData(morty);
+ Assert.assertNull(RULE.checkRule(transition));
+ }
+
+ /**
+ * Given one statement: A <-> B where B is true and <-> is false
+ *
+ * Asserts that this is a valid application of the rule if and only if A is false.
+ *
+ * @throws InvalidFileFormatException
+ */
+ @Test
+ public void FalseBiconditionalWithTrueBTest() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/BiconditionalEliminationDirectRule/FalseBiconditionalWithTrueB", stt);
+ TreeNode rootNode = stt.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard();
+ ShortTruthTableCell rick = board.getCell(0, 0);
+
+ // Asserts that this is not a valid application of the rule when A is unknown
+ rick.setData(ShortTruthTableCellType.UNKNOWN);
+ board.addModifiedData(rick);
+ Assert.assertNotNull(RULE.checkRule(transition));
+
+ // Asserts that this is not a valid application of the rule when A is true
+ rick.setData(ShortTruthTableCellType.TRUE);
+ board.addModifiedData(rick);
+ Assert.assertNotNull(RULE.checkRule(transition));
+
+ // Asserts that this is a valid application of the rule when A is false
+ rick.setData(ShortTruthTableCellType.FALSE);
+ board.addModifiedData(rick);
+ Assert.assertNull(RULE.checkRule(transition));
+ }
+
+ /**
+ * Given one statement: A <-> B where A and <-> are false
+ *
+ * Asserts that this is a valid application of the rule if and only if B is true.
+ *
+ * @throws InvalidFileFormatException
+ */
+ @Test
+ public void FalseBiconditionalWithFalseATest() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/BiconditionalEliminationDirectRule/FalseBiconditionalWithFalseA", stt);
+ TreeNode rootNode = stt.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard();
+ ShortTruthTableCell morty = board.getCell(2, 0);
+
+ // Asserts that this is not a valid application of the rule when B is unknown
+ morty.setData(ShortTruthTableCellType.UNKNOWN);
+ board.addModifiedData(morty);
+ Assert.assertNotNull(RULE.checkRule(transition));
+
+ // Asserts that this is a valid application of the rule when B is true
+ morty.setData(ShortTruthTableCellType.TRUE);
+ board.addModifiedData(morty);
+ Assert.assertNull(RULE.checkRule(transition));
+
+ // Asserts that this is not a valid application of the rule when B is false
+ morty.setData(ShortTruthTableCellType.FALSE);
+ board.addModifiedData(morty);
+ Assert.assertNotNull(RULE.checkRule(transition));
+ }
+
+ /**
+ * Given one statement: A <-> B where B and <-> are false
+ *
+ * Asserts that this is a valid application of the rule if and only if A is true.
+ *
+ * @throws InvalidFileFormatException
+ */
+ @Test
+ public void FalseBiconditionalWithFalseBTest() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/BiconditionalEliminationDirectRule/FalseBiconditionalWithFalseB", stt);
+ TreeNode rootNode = stt.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard();
+ ShortTruthTableCell rick = board.getCell(0, 0);
+
+ // Asserts that this is not a valid application of the rule when A is unknown
+ rick.setData(ShortTruthTableCellType.UNKNOWN);
+ board.addModifiedData(rick);
+ Assert.assertNotNull(RULE.checkRule(transition));
+
+ // Asserts that this is not a valid application of the rule when A is false
+ rick.setData(ShortTruthTableCellType.FALSE);
+ board.addModifiedData(rick);
+ Assert.assertNotNull(RULE.checkRule(transition));
+
+ // Asserts that this is a valid application of the rule when A is true
+ rick.setData(ShortTruthTableCellType.TRUE);
+ board.addModifiedData(rick);
+ Assert.assertNull(RULE.checkRule(transition));
+ }
+
+ /**
+ * Given one statement: A <-> B where <-> is true
+ *
+ * Asserts that setting any combination of A and B at the same time is not a valid
+ * application of this rule
+ *
+ * @throws InvalidFileFormatException
+ */
+ @Test
+ public void TrueBiconditionalSetBothAtOnceTest() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/BiconditionalEliminationDirectRule/TrueBiconditional", stt);
+ TreeNode rootNode = stt.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ ShortTruthTableCellType[] cellTypes = {ShortTruthTableCellType.TRUE, ShortTruthTableCellType.FALSE, ShortTruthTableCellType.UNKNOWN};
+
+ for (ShortTruthTableCellType cellType1 : cellTypes) {
+ for (ShortTruthTableCellType cellType2 : cellTypes) {
+ ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard();
+ ShortTruthTableCell rick = board.getCell(0, 0);
+ ShortTruthTableCell morty = board.getCell(2, 0);
+
+ rick.setData(cellType1);
+ morty.setData(cellType2);
+
+ board.addModifiedData(rick);
+ board.addModifiedData(morty);
+
+ Assert.assertNotNull(RULE.checkRule(transition));
+ }
+ }
+ }
+
+ /**
+ * Asserts that setting any combination of A and B at the same time is not a valid
+ * application of this rule. This is tested on multiple files.
+ *
+ * @throws InvalidFileFormatException
+ */
+ @Test
+ public void CannotSetBothAandBAtOnceTest() throws InvalidFileFormatException {
+ String directory = "puzzles/shorttruthtable/rules/BiconditionalEliminationDirectRule/";
+ setAandBBothAtOnceTest(directory + "FalseBiconditional");
+ setAandBBothAtOnceTest(directory + "TrueBiconditional");
+ setAandBBothAtOnceTest(directory + "FalseBiconditionalWithFalseA");
+ setAandBBothAtOnceTest(directory + "TrueBiconditionalWithFalseA");
+ setAandBBothAtOnceTest(directory + "FalseBiconditionalWithTrueA");
+ setAandBBothAtOnceTest(directory + "TrueBiconditionalWithTrueA");
+ }
+
+ /**
+ * Helper function to test biconditional elimination rule with given file path.
+ *
+ * @param filePath The file path for test board setup.
+ * @throws InvalidFileFormatException
+ */
+ private void setAandBBothAtOnceTest(String filePath) throws InvalidFileFormatException {
+ TestUtilities.importTestBoard(filePath, stt);
+ TreeNode rootNode = stt.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ ShortTruthTableCellType[] cellTypes = {ShortTruthTableCellType.TRUE, ShortTruthTableCellType.FALSE, ShortTruthTableCellType.UNKNOWN};
+
+ for (ShortTruthTableCellType cellType1 : cellTypes) {
+ for (ShortTruthTableCellType cellType2 : cellTypes) {
+ ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard();
+ ShortTruthTableCell rick = board.getCell(0, 0);
+ ShortTruthTableCell morty = board.getCell(2, 0);
+
+ rick.setData(cellType1);
+ morty.setData(cellType2);
+
+ board.addModifiedData(rick);
+ board.addModifiedData(morty);
+
+ Assert.assertNotNull(RULE.checkRule(transition));
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/puzzles/shorttruthtable/rules/BiconditionalIntroductionTest.java b/src/test/java/puzzles/shorttruthtable/rules/BiconditionalIntroductionTest.java
new file mode 100644
index 000000000..fe2574b5e
--- /dev/null
+++ b/src/test/java/puzzles/shorttruthtable/rules/BiconditionalIntroductionTest.java
@@ -0,0 +1,118 @@
+package puzzles.shorttruthtable.rules;
+
+import edu.rpi.legup.model.tree.TreeNode;
+import edu.rpi.legup.model.tree.TreeTransition;
+import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTable;
+import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableBoard;
+import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCell;
+import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCellType;
+import edu.rpi.legup.puzzle.shorttruthtable.rules.basic.introduction.DirectRuleBiconditionalIntroduction;
+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 BiconditionalIntroductionTest {
+ private static final DirectRuleBiconditionalIntroduction RULE = new DirectRuleBiconditionalIntroduction();
+ private static ShortTruthTable stt;
+
+ @BeforeClass
+ public static void setup() {
+ MockGameBoardFacade.getInstance();
+ stt = new ShortTruthTable();
+ }
+
+ /**
+ * Given a statement: A <-> B
+ *
+ * Asserts that if setting <-> to false is a valid application of this rule if and
+ * only if A and B do not match.
+ *
+ * @throws InvalidFileFormatException
+ */
+ @Test
+ public void FalseConditionalTest() throws InvalidFileFormatException {
+ String path = "puzzles/shorttruthtable/rules/BiconditionalIntroductionDirectRule/";
+
+ String[] letters = {"T", "F", "U"};
+ for (String a : letters) {
+ for (String b : letters) {
+ System.out.println(a + b);
+ falseConditionalHelper(path + a + "U" + b);
+ }
+ }
+ }
+
+ private void falseConditionalHelper(String filePath) throws InvalidFileFormatException {
+ TestUtilities.importTestBoard(filePath, stt);
+ TreeNode rootNode = stt.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard();
+ ShortTruthTableCell conditional = board.getCell(1, 0);
+
+ conditional.setData(ShortTruthTableCellType.FALSE);
+ board.addModifiedData(conditional);
+
+ ShortTruthTableCell a = board.getCell(0, 0);
+ ShortTruthTableCell b = board.getCell(2, 0);
+ if (a.getType() != b.getType()) {
+ // Not valid if they don't match but at least one of the values of A or B is unknown
+ if (a.getType() == ShortTruthTableCellType.UNKNOWN || b.getType() == ShortTruthTableCellType.UNKNOWN) {
+ Assert.assertNotNull(RULE.checkRule(transition));
+ }
+ else {
+ Assert.assertNull(RULE.checkRule(transition));
+ }
+ }
+ else {
+ Assert.assertNotNull(RULE.checkRule(transition));
+ }
+ }
+
+ /**
+ * Given a statement: A <-> B
+ *
+ * Asserts that if setting <-> to true is a valid application of this rule if and
+ * only if A and B match.
+ *
+ * @throws InvalidFileFormatException
+ */
+ @Test
+ public void TrueConditionalTest() throws InvalidFileFormatException {
+ String path = "puzzles/shorttruthtable/rules/BiconditionalIntroductionDirectRule/";
+
+ String[] letters = {"T", "F", "U"};
+ for (String a : letters) {
+ for (String b : letters) {
+ System.out.println(a + b);
+ trueConditionalHelper(path + a + "U" + b);
+ }
+ }
+ }
+
+ private void trueConditionalHelper(String filePath) throws InvalidFileFormatException {
+ TestUtilities.importTestBoard(filePath, stt);
+ TreeNode rootNode = stt.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard();
+ ShortTruthTableCell conditional = board.getCell(1, 0);
+
+ conditional.setData(ShortTruthTableCellType.TRUE);
+ board.addModifiedData(conditional);
+
+ ShortTruthTableCell a = board.getCell(0, 0);
+ ShortTruthTableCell b = board.getCell(2, 0);
+ if (a.getType() == b.getType() && a.getType() != ShortTruthTableCellType.UNKNOWN) {
+ Assert.assertNull(RULE.checkRule(transition));
+ }
+ else {
+ Assert.assertNotNull(RULE.checkRule(transition));
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/puzzles/shorttruthtable/rules/ConditionalEliminationTest.java b/src/test/java/puzzles/shorttruthtable/rules/ConditionalEliminationTest.java
new file mode 100644
index 000000000..8d0bb4e1a
--- /dev/null
+++ b/src/test/java/puzzles/shorttruthtable/rules/ConditionalEliminationTest.java
@@ -0,0 +1,233 @@
+package puzzles.shorttruthtable.rules;
+
+import edu.rpi.legup.model.tree.TreeNode;
+import edu.rpi.legup.model.tree.TreeTransition;
+import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTable;
+import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableBoard;
+import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCell;
+import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCellType;
+import edu.rpi.legup.puzzle.shorttruthtable.rules.basic.elimination.DirectRuleConditionalElimination;
+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 ConditionalEliminationTest {
+ private static final DirectRuleConditionalElimination RULE = new DirectRuleConditionalElimination();
+ private static ShortTruthTable stt;
+
+ @BeforeClass
+ public static void setup() {
+ MockGameBoardFacade.getInstance();
+ stt = new ShortTruthTable();
+ }
+
+ /**
+ * Given one statement: A -> B where -> is false
+ *
+ * Asserts that the only valid combination of A and B that is a valid application
+ * of this rule is when A is true and B is false
+ *
+ * @throws InvalidFileFormatException
+ */
+ @Test
+ public void FalseConditionalTest() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/ConditionalEliminationDirectRule/FalseConditional", stt);
+ TreeNode rootNode = stt.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ ShortTruthTableCellType[] cellTypes = {ShortTruthTableCellType.TRUE, ShortTruthTableCellType.FALSE, ShortTruthTableCellType.UNKNOWN};
+
+ for (ShortTruthTableCellType cellType1 : cellTypes) {
+ for (ShortTruthTableCellType cellType2 : cellTypes) {
+ ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard();
+ ShortTruthTableCell aubergine = board.getCell(0, 0);
+ ShortTruthTableCell boniato = board.getCell(2, 0);
+
+ aubergine.setData(cellType1);
+ boniato.setData(cellType2);
+
+ board.addModifiedData(aubergine);
+ board.addModifiedData(boniato);
+
+ if (cellType1 == ShortTruthTableCellType.TRUE && cellType2 == ShortTruthTableCellType.FALSE) {
+ Assert.assertNull(RULE.checkRule(transition));
+ }
+ else {
+ Assert.assertNotNull(RULE.checkRule(transition));
+ }
+ }
+ }
+ }
+
+ /**
+ * Given one statement: A -> B where -> is false
+ *
+ * Asserts that this is a valid application of the rule if and only if A
+ * is set to true.
+ *
+ * @throws InvalidFileFormatException
+ */
+ @Test
+ public void FalseConditionalTrueATest() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/ConditionalEliminationDirectRule/FalseConditional", stt);
+ TreeNode rootNode = stt.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard();
+ ShortTruthTableCell aubergine = board.getCell(0, 0);
+
+ aubergine.setData(ShortTruthTableCellType.TRUE);
+ board.addModifiedData(aubergine);
+ Assert.assertNull(RULE.checkRule(transition));
+
+ aubergine.setData(ShortTruthTableCellType.FALSE);
+ board.addModifiedData(aubergine);
+ Assert.assertNotNull(RULE.checkRule(transition));
+ }
+
+ /**
+ * Given one statement: A -> B where -> is false
+ *
+ * Asserts that this is a valid application of the rule if and only if B is
+ * set to false.
+ *
+ * @throws InvalidFileFormatException
+ */
+ @Test
+ public void FalseConditionalFalseBTest() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/ConditionalEliminationDirectRule/FalseConditional", stt);
+ TreeNode rootNode = stt.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard();
+ ShortTruthTableCell boniato = board.getCell(2, 0);
+
+ boniato.setData(ShortTruthTableCellType.FALSE);
+ board.addModifiedData(boniato);
+ Assert.assertNull(RULE.checkRule(transition));
+
+ boniato.setData(ShortTruthTableCellType.TRUE);
+ board.addModifiedData(boniato);
+ Assert.assertNotNull(RULE.checkRule(transition));
+ }
+
+ /**
+ * Given one statement: A -> B where -> is true
+ *
+ * Asserts that you cannot set any combination of both A and B at the same time.
+ *
+ * @throws InvalidFileFormatException
+ */
+ @Test
+ public void CannotSetBothAandBTrueConditionalTest() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/ConditionalEliminationDirectRule/TrueConditional", stt);
+ TreeNode rootNode = stt.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ ShortTruthTableCellType[] cellTypes = {ShortTruthTableCellType.TRUE, ShortTruthTableCellType.FALSE, ShortTruthTableCellType.UNKNOWN};
+
+ for (ShortTruthTableCellType cellType1 : cellTypes) {
+ for (ShortTruthTableCellType cellType2 : cellTypes) {
+ ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard();
+ ShortTruthTableCell aubergine = board.getCell(0, 0);
+ ShortTruthTableCell boniato = board.getCell(2, 0);
+
+ aubergine.setData(cellType1);
+ boniato.setData(cellType2);
+
+ board.addModifiedData(aubergine);
+ board.addModifiedData(boniato);
+
+ Assert.assertNotNull(RULE.checkRule(transition));
+ }
+ }
+ }
+
+ /**
+ * Given one statement: A -> B where A and -> are true
+ *
+ * Asserts that this is a valid application of this rule if and only if B
+ * is set to true.
+ *
+ * @throws InvalidFileFormatException
+ */
+ @Test
+ public void TrueAMeansTrueBTest() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/ConditionalEliminationDirectRule/TrueConditionalWithTrueA", stt);
+ TreeNode rootNode = stt.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard();
+ ShortTruthTableCell boniato = board.getCell(2, 0);
+
+ boniato.setData(ShortTruthTableCellType.TRUE);
+ board.addModifiedData(boniato);
+ Assert.assertNull(RULE.checkRule(transition));
+
+ boniato.setData(ShortTruthTableCellType.FALSE);
+ board.addModifiedData(boniato);
+ Assert.assertNotNull(RULE.checkRule(transition));
+ }
+
+ /**
+ * Given one statement: A -> B where B is false and -> is true
+ *
+ * Asserts that this is a valid application of this rule if and only if A
+ * is set to false.
+ *
+ * @throws InvalidFileFormatException
+ */
+ @Test
+ public void FalseBMeansFalseATest() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/ConditionalEliminationDirectRule/TrueConditionalWithFalseB", stt);
+ TreeNode rootNode = stt.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard();
+ ShortTruthTableCell aubergine = board.getCell(0, 0);
+
+ aubergine.setData(ShortTruthTableCellType.FALSE);
+ board.addModifiedData(aubergine);
+ Assert.assertNull(RULE.checkRule(transition));
+
+ aubergine.setData(ShortTruthTableCellType.TRUE);
+ board.addModifiedData(aubergine);
+ Assert.assertNotNull(RULE.checkRule(transition));
+ }
+
+ /**
+ * Given one statement: A -> B where B and -> are true
+ *
+ * Asserts that this is not a valid application of this rule no matter what
+ * A is set to.
+ *
+ * @throws InvalidFileFormatException
+ */
+ @Test
+ public void TrueBCannotDetermineA() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/ConditionalEliminationDirectRule/TrueConditionalWithTrueB", stt);
+ TreeNode rootNode = stt.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard();
+ ShortTruthTableCell boniato = board.getCell(2, 0);
+
+ boniato.setData(ShortTruthTableCellType.TRUE);
+ board.addModifiedData(boniato);
+ Assert.assertNotNull(RULE.checkRule(transition));
+
+ boniato.setData(ShortTruthTableCellType.FALSE);
+ board.addModifiedData(boniato);
+ Assert.assertNotNull(RULE.checkRule(transition));
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/puzzles/shorttruthtable/rules/ConditionalIntroductionTest.java b/src/test/java/puzzles/shorttruthtable/rules/ConditionalIntroductionTest.java
new file mode 100644
index 000000000..c1507eab1
--- /dev/null
+++ b/src/test/java/puzzles/shorttruthtable/rules/ConditionalIntroductionTest.java
@@ -0,0 +1,110 @@
+package puzzles.shorttruthtable.rules;
+
+import edu.rpi.legup.model.tree.TreeNode;
+import edu.rpi.legup.model.tree.TreeTransition;
+import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTable;
+import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableBoard;
+import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCell;
+import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCellType;
+import edu.rpi.legup.puzzle.shorttruthtable.rules.basic.introduction.DirectRuleConditionalIntroduction;
+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 ConditionalIntroductionTest {
+ private static final DirectRuleConditionalIntroduction RULE = new DirectRuleConditionalIntroduction();
+ private static ShortTruthTable stt;
+
+ @BeforeClass
+ public static void setup() {
+ MockGameBoardFacade.getInstance();
+ stt = new ShortTruthTable();
+ }
+
+ /**
+ * Given a statement: A -> B
+ *
+ * Asserts that if setting -> to false is a valid application of this rule if and
+ * only if A is true and B is false.
+ *
+ * @throws InvalidFileFormatException
+ */
+ @Test
+ public void FalseConditionalTest() throws InvalidFileFormatException {
+ String path = "puzzles/shorttruthtable/rules/ConditionalIntroductionDirectRule/";
+
+ String[] letters = {"T", "F", "U"};
+ for (String a : letters) {
+ for (String b : letters) {
+ falseConditionalHelper(path + a + "U" + b);
+ }
+ }
+ }
+
+ private void falseConditionalHelper(String filePath) throws InvalidFileFormatException {
+ TestUtilities.importTestBoard(filePath, stt);
+ TreeNode rootNode = stt.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard();
+ ShortTruthTableCell conditional = board.getCell(1, 0);
+
+ conditional.setData(ShortTruthTableCellType.FALSE);
+ board.addModifiedData(conditional);
+
+ ShortTruthTableCell a = board.getCell(0, 0);
+ ShortTruthTableCell b = board.getCell(2, 0);
+ if (a.getType() == ShortTruthTableCellType.TRUE && b.getType() == ShortTruthTableCellType.FALSE) {
+ Assert.assertNull(RULE.checkRule(transition));
+ }
+ else {
+ Assert.assertNotNull(RULE.checkRule(transition));
+ }
+ }
+
+ /**
+ * Given a statement: A -> B
+ *
+ * Asserts that if setting -> to true is a valid application of this rule if and
+ * only if A is false or B is true.
+ *
+ * @throws InvalidFileFormatException
+ */
+ @Test
+ public void TrueConditionalTest() throws InvalidFileFormatException {
+ String path = "puzzles/shorttruthtable/rules/ConditionalIntroductionDirectRule/";
+
+ String[] letters = {"T", "F", "U"};
+ for (String a : letters) {
+ for (String b : letters) {
+ trueConditionalTestHelper(path + a + "U" + b);
+ }
+ }
+ }
+
+ private void trueConditionalTestHelper(String filePath) throws InvalidFileFormatException {
+ TestUtilities.importTestBoard(filePath, stt);
+ TreeNode rootNode = stt.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard();
+ ShortTruthTableCell conditional = board.getCell(1, 0);
+
+ conditional.setData(ShortTruthTableCellType.TRUE);
+ board.addModifiedData(conditional);
+
+ ShortTruthTableCell a = board.getCell(0, 0);
+ ShortTruthTableCell b = board.getCell(2, 0);
+ if (a.getType() == ShortTruthTableCellType.FALSE || b.getType() == ShortTruthTableCellType.TRUE) {
+ Assert.assertNull(RULE.checkRule(transition));
+ }
+ else {
+ Assert.assertNotNull(RULE.checkRule(transition));
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/puzzles/shorttruthtable/rules/DirectRuleAtomicTest.java b/src/test/java/puzzles/shorttruthtable/rules/DirectRuleAtomicTest.java
deleted file mode 100644
index 81991fa46..000000000
--- a/src/test/java/puzzles/shorttruthtable/rules/DirectRuleAtomicTest.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package puzzles.shorttruthtable.rules;
-
-class DirectRuleAtomicTest {
-
-
-}
\ No newline at end of file
diff --git a/src/test/java/puzzles/shorttruthtable/rules/NotEliminationTest.java b/src/test/java/puzzles/shorttruthtable/rules/NotEliminationTest.java
new file mode 100644
index 000000000..6dbbf141c
--- /dev/null
+++ b/src/test/java/puzzles/shorttruthtable/rules/NotEliminationTest.java
@@ -0,0 +1,124 @@
+package puzzles.shorttruthtable.rules;
+
+import edu.rpi.legup.model.tree.TreeNode;
+import edu.rpi.legup.model.tree.TreeTransition;
+import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTable;
+import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableBoard;
+import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCell;
+import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCellType;
+import edu.rpi.legup.puzzle.shorttruthtable.rules.basic.elimination.DirectRuleNotElimination;
+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 NotEliminationTest {
+ private static final DirectRuleNotElimination RULE = new DirectRuleNotElimination();
+ private static ShortTruthTable stt;
+
+ @BeforeClass
+ public static void setup() {
+ MockGameBoardFacade.getInstance();
+ stt = new ShortTruthTable();
+ }
+
+ /**
+ * Given one statement: ¬A where ¬ is false
+ *
+ * Asserts that this is a valid application of this rule if and only if A is true
+ *
+ * @throws InvalidFileFormatException
+ */
+ @Test
+ public void FalseNot() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/NotEliminationDirectRule/FalseNot", stt);
+ TreeNode rootNode = stt.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ ShortTruthTableCellType[] cellTypes = {ShortTruthTableCellType.TRUE, ShortTruthTableCellType.FALSE, ShortTruthTableCellType.UNKNOWN};
+
+ for (ShortTruthTableCellType cellType : cellTypes) {
+ ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard();
+ ShortTruthTableCell a = board.getCell(1, 0);
+ a.setData(cellType);
+ board.addModifiedData(a);
+
+ if (cellType == ShortTruthTableCellType.TRUE) {
+ Assert.assertNull(RULE.checkRule(transition));
+ }
+ else {
+ Assert.assertNotNull(RULE.checkRule(transition));
+ }
+ }
+ }
+
+ /**
+ * Given one statement: ¬A where ¬ is true
+ *
+ * Asserts that this is a valid application of this rule if and only if A is false
+ *
+ * @throws InvalidFileFormatException
+ */
+ @Test
+ public void TrueNot() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/NotEliminationDirectRule/TrueNot", stt);
+ TreeNode rootNode = stt.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ ShortTruthTableCellType[] cellTypes = {ShortTruthTableCellType.TRUE, ShortTruthTableCellType.FALSE, ShortTruthTableCellType.UNKNOWN};
+
+ for (ShortTruthTableCellType cellType : cellTypes) {
+ ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard();
+ ShortTruthTableCell a = board.getCell(1, 0);
+ a.setData(cellType);
+ board.addModifiedData(a);
+
+ if (cellType == ShortTruthTableCellType.FALSE) {
+ Assert.assertNull(RULE.checkRule(transition));
+ }
+ else {
+ Assert.assertNotNull(RULE.checkRule(transition));
+ }
+ }
+ }
+
+// /**
+// * Given one statement: ¬A
+// *
+// * Asserts that setting both ¬ and A to any values would not be a valid
+// * application of this rule
+// *
+// * @throws InvalidFileFormatException
+// */
+// @Test
+// public void CannotSetBothAtOnceTest() throws InvalidFileFormatException {
+// TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/NotEliminationDirectRule/BlankNot", stt);
+// TreeNode rootNode = stt.getTree().getRootNode();
+// TreeTransition transition = rootNode.getChildren().get(0);
+// transition.setRule(RULE);
+//
+// ShortTruthTableCellType[] cellTypes = {ShortTruthTableCellType.TRUE, ShortTruthTableCellType.FALSE, ShortTruthTableCellType.UNKNOWN};
+//
+// for (ShortTruthTableCellType cellType1 : cellTypes) {
+// for (ShortTruthTableCellType cellType2 : cellTypes) {
+// ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard();
+// ShortTruthTableCell not = board.getCell(0, 0);
+// ShortTruthTableCell a = board.getCell(1, 0);
+//
+// not.setData(cellType1);
+// a.setData(cellType2);
+//
+// board.addModifiedData(not);
+// board.addModifiedData(a);
+//
+// System.out.println("TYPE1:" + cellType1);
+// System.out.println("TYPE2:" + cellType2);
+// Assert.assertNotNull(RULE.checkRule(transition));
+// }
+// }
+// }
+}
\ No newline at end of file
diff --git a/src/test/java/puzzles/shorttruthtable/rules/NotIntroductionTest.java b/src/test/java/puzzles/shorttruthtable/rules/NotIntroductionTest.java
new file mode 100644
index 000000000..a0a062ab3
--- /dev/null
+++ b/src/test/java/puzzles/shorttruthtable/rules/NotIntroductionTest.java
@@ -0,0 +1,122 @@
+package puzzles.shorttruthtable.rules;
+
+import edu.rpi.legup.model.tree.TreeNode;
+import edu.rpi.legup.model.tree.TreeTransition;
+import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTable;
+import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableBoard;
+import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCell;
+import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCellType;
+import edu.rpi.legup.puzzle.shorttruthtable.rules.basic.introduction.DirectRuleNotIntroduction;
+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 NotIntroductionTest {
+ private static final DirectRuleNotIntroduction RULE = new DirectRuleNotIntroduction();
+ private static ShortTruthTable stt;
+
+ @BeforeClass
+ public static void setup() {
+ MockGameBoardFacade.getInstance();
+ stt = new ShortTruthTable();
+ }
+
+ /**
+ * Given one statement: ¬A where A is false
+ *
+ * Asserts that this is a valid application of this rule if and only if ¬ is true
+ *
+ * @throws InvalidFileFormatException
+ */
+ @Test
+ public void FalseNot() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/NotIntroductionDirectRule/FalseA", stt);
+ TreeNode rootNode = stt.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ ShortTruthTableCellType[] cellTypes = {ShortTruthTableCellType.TRUE, ShortTruthTableCellType.FALSE, ShortTruthTableCellType.UNKNOWN};
+
+ for (ShortTruthTableCellType cellType : cellTypes) {
+ ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard();
+ ShortTruthTableCell not = board.getCell(0, 0);
+ not.setData(cellType);
+ board.addModifiedData(not);
+
+ if (cellType == ShortTruthTableCellType.TRUE) {
+ Assert.assertNull(RULE.checkRule(transition));
+ }
+ else {
+ Assert.assertNotNull(RULE.checkRule(transition));
+ }
+ }
+ }
+
+ /**
+ * Given one statement: ¬A where A is true
+ *
+ * Asserts that this is a valid application of this rule if and only if ¬ is false
+ *
+ * @throws InvalidFileFormatException
+ */
+ @Test
+ public void TrueNot() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/NotIntroductionDirectRule/TrueA", stt);
+ TreeNode rootNode = stt.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ ShortTruthTableCellType[] cellTypes = {ShortTruthTableCellType.TRUE, ShortTruthTableCellType.FALSE, ShortTruthTableCellType.UNKNOWN};
+
+ for (ShortTruthTableCellType cellType : cellTypes) {
+ ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard();
+ ShortTruthTableCell not = board.getCell(0, 0);
+ not.setData(cellType);
+ board.addModifiedData(not);
+
+ if (cellType == ShortTruthTableCellType.FALSE) {
+ Assert.assertNull(RULE.checkRule(transition));
+ }
+ else {
+ Assert.assertNotNull(RULE.checkRule(transition));
+ }
+ }
+ }
+
+ /**
+ * Given one statement: ¬A
+ *
+ * Asserts that setting both ¬ and A to any values would not be a valid
+ * application of this rule
+ *
+ * @throws InvalidFileFormatException
+ */
+ @Test
+ public void CannotSetBothAtOnceTest() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/NotIntroductionDirectRule/BlankA", stt);
+ TreeNode rootNode = stt.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ ShortTruthTableCellType[] cellTypes = {ShortTruthTableCellType.TRUE, ShortTruthTableCellType.FALSE, ShortTruthTableCellType.UNKNOWN};
+
+ for (ShortTruthTableCellType cellType1 : cellTypes) {
+ for (ShortTruthTableCellType cellType2 : cellTypes) {
+ ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard();
+ ShortTruthTableCell not = board.getCell(0, 0);
+ ShortTruthTableCell a = board.getCell(1, 0);
+
+ not.setData(cellType1);
+ a.setData(cellType2);
+
+ board.addModifiedData(not);
+ board.addModifiedData(a);
+
+ Assert.assertNotNull(RULE.checkRule(transition));
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/puzzles/shorttruthtable/rules/OrCaseRuleTest.java b/src/test/java/puzzles/shorttruthtable/rules/OrCaseRuleTest.java
new file mode 100644
index 000000000..276e822cf
--- /dev/null
+++ b/src/test/java/puzzles/shorttruthtable/rules/OrCaseRuleTest.java
@@ -0,0 +1,161 @@
+package puzzles.shorttruthtable.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.shorttruthtable.ShortTruthTable;
+import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableBoard;
+import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCell;
+import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCellType;
+import edu.rpi.legup.puzzle.shorttruthtable.rules.caserule.CaseRuleAnd;
+import edu.rpi.legup.puzzle.shorttruthtable.rules.caserule.CaseRuleOr;
+import edu.rpi.legup.save.InvalidFileFormatException;
+import legup.MockGameBoardFacade;
+import legup.TestUtilities;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.util.ArrayList;
+
+public class OrCaseRuleTest {
+
+ private static final CaseRuleOr RULE = new CaseRuleOr();
+ private static ShortTruthTable stt;
+
+ @BeforeClass
+ public static void setUp() {
+ MockGameBoardFacade.getInstance();
+ stt = new ShortTruthTable();
+ }
+
+ private void trueOrTest(String fileName,
+ int andX, int andY,
+ int aX, int aY,
+ int bX, int bY) throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/OrCaseRule/" + fileName, stt);
+ TreeNode rootNode = stt.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard();
+ ShortTruthTableCell cell = board.getCell(andX,andY);
+ ArrayList cases = RULE.getCases(board, cell);
+
+ // Make sure that the rule checks out
+ Assert.assertNotNull(RULE.checkRule(transition));
+
+ // Make sure there are two branches
+ Assert.assertEquals(2, cases.size());
+
+ ShortTruthTableBoard caseBoard1 = (ShortTruthTableBoard) cases.get(0);
+ ShortTruthTableCellType board1A = caseBoard1.getCell(aX, aY).getType();
+ ShortTruthTableCellType board1B = caseBoard1.getCell(bX, bY).getType();
+
+ ShortTruthTableBoard caseBoard2 = (ShortTruthTableBoard) cases.get(1);
+ ShortTruthTableCellType board2A = caseBoard2.getCell(aX, aY).getType();
+ ShortTruthTableCellType board2B = caseBoard2.getCell(bX, bY).getType();
+
+ // Assert that the corresponding cells for the different case rules do not
+ // match with each other
+ Assert.assertNotEquals(board1A, board2A);
+ Assert.assertNotEquals(board1B, board2B);
+
+ // First assert the two cells are not equal, then verify that they are either
+ // unknown or false.
+ Assert.assertNotEquals(board1A, board1B);
+ Assert.assertTrue(board1A.equals(ShortTruthTableCellType.UNKNOWN) || board1A.equals(ShortTruthTableCellType.TRUE));
+ Assert.assertTrue(board1B.equals(ShortTruthTableCellType.UNKNOWN) || board1B.equals(ShortTruthTableCellType.TRUE));
+
+ Assert.assertNotEquals(board2A, board2B);
+ Assert.assertTrue(board2A.equals(ShortTruthTableCellType.UNKNOWN) || board1A.equals(ShortTruthTableCellType.TRUE));
+ Assert.assertTrue(board2B.equals(ShortTruthTableCellType.UNKNOWN) || board2B.equals(ShortTruthTableCellType.TRUE));
+
+ // Verify the board dimensions are unchanged
+ Assert.assertEquals(caseBoard1.getHeight(), caseBoard2.getHeight(), board.getHeight());
+ Assert.assertEquals(caseBoard1.getWidth(), caseBoard2.getWidth(), board.getWidth());
+
+ // Verify that everywhere else on the board is unchanged
+ for (int i = 0; i< caseBoard1.getWidth(); i++) {
+ for (int j = 0; j < caseBoard1.getHeight(); j++) {
+ // Make sure not to check the two cells that should be different
+ if (!((i == aX && j == aY) || (i == bX && j == bY))) {
+ Assert.assertEquals(caseBoard1.getCell(i, j).getType(), caseBoard2.getCell(i, j).getType());
+ }
+ }
+ }
+ }
+
+ /**
+ * Given a statement A ^ B where ^ is false, tests this case rule by ensuring that
+ * two branches are created: one where A is false and one where B is false.
+ */
+ @Test
+ public void SimpleStatement1TrueTest() throws InvalidFileFormatException {
+ trueOrTest("SimpleStatement1_True", 1, 0, 0, 0,
+ 2, 0);
+ }
+
+ /**
+ * Given a statement ~(A|B)^(C^D) where the first ^ is false, tests this case rule
+ * by ensuring that two branches are created: one where ~ is false and one where
+ * the second ^ is false.
+ */
+ @Test
+ public void ComplexStatement1TrueTest() throws InvalidFileFormatException {
+ trueOrTest("ComplexStatement1_True", 6, 0, 0, 0,
+ 9, 0);
+ }
+
+ private void falseOrTest(String fileName,
+ int andX, int andY,
+ int aX, int aY,
+ int bX, int bY) throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/OrCaseRule/" + fileName, stt);
+ TreeNode rootNode = stt.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard();
+ ShortTruthTableCell cell = board.getCell(andX,andY);
+ ArrayList cases = RULE.getCases(board, cell);
+
+ // Make sure that the rule checks out
+ Assert.assertNotNull(RULE.checkRule(transition));
+
+ // There should only be 1 branch
+ Assert.assertEquals(1, cases.size());
+
+ ShortTruthTableBoard caseBoard = (ShortTruthTableBoard) cases.get(0);
+ ShortTruthTableCellType caseBoardAType = caseBoard.getCell(aX, aY).getType();
+ ShortTruthTableCellType caseBoardBType = caseBoard.getCell(bX, bY).getType();
+
+ // Both cells should be true
+ Assert.assertEquals(caseBoardAType, ShortTruthTableCellType.FALSE);
+ Assert.assertEquals(caseBoardBType, ShortTruthTableCellType.FALSE);
+ Assert.assertEquals(caseBoardAType, caseBoardBType);
+
+ // Verify the board dimensions are unchanged
+ Assert.assertEquals(caseBoard.getHeight(), caseBoard.getHeight(), board.getHeight());
+ }
+
+ /**
+ * Given a statement A ^ B where ^ is false, tests this case rule by ensuring that
+ * one branch is created where A and B are both true.
+ */
+ @Test
+ public void SimpleStatement1FalseTest() throws InvalidFileFormatException {
+ falseOrTest("SimpleStatement1_False", 1, 0, 0, 0,
+ 2, 0);
+ }
+
+ /**
+ * Given a statement ~(A|B)^(C^D) where the first ^ is true, tests this case rule
+ * by ensuring that one branch is created where both ~ and the second ^ are true.
+ */
+ @Test
+ public void ComplexStatement1FalseTest() throws InvalidFileFormatException {
+ falseOrTest("ComplexStatement1_False", 6, 0, 0, 0,
+ 9, 0);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/puzzles/shorttruthtable/rules/OrEliminationTest.java b/src/test/java/puzzles/shorttruthtable/rules/OrEliminationTest.java
new file mode 100644
index 000000000..6cdd0d639
--- /dev/null
+++ b/src/test/java/puzzles/shorttruthtable/rules/OrEliminationTest.java
@@ -0,0 +1,150 @@
+package puzzles.shorttruthtable.rules;
+
+import edu.rpi.legup.model.tree.TreeNode;
+import edu.rpi.legup.model.tree.TreeTransition;
+import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTable;
+import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableBoard;
+import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCell;
+import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCellType;
+import edu.rpi.legup.puzzle.shorttruthtable.rules.basic.elimination.DirectRuleOrElimination;
+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 OrEliminationTest {
+ private static final DirectRuleOrElimination RULE = new DirectRuleOrElimination();
+ private static ShortTruthTable stt;
+
+ @BeforeClass
+ public static void setup() {
+ MockGameBoardFacade.getInstance();
+ stt = new ShortTruthTable();
+ }
+
+ /**
+ * Given a statement: A V B, where A is false and V is true
+ *
+ * Asserts that this is a valid application of the rule if and only if B is true.
+ *
+ * @throws InvalidFileFormatException
+ */
+ @Test
+ public void FTUTest() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/OrEliminationDirectRule/FTU", stt);
+ TreeNode rootNode = stt.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard();
+ ShortTruthTableCell cell = board.getCell(2, 0);
+
+ cell.setData(ShortTruthTableCellType.TRUE);
+ board.addModifiedData(cell);
+ Assert.assertNull(RULE.checkRule(transition));
+
+ cell.setData(ShortTruthTableCellType.FALSE);
+ board.addModifiedData(cell);
+ Assert.assertNotNull(RULE.checkRule(transition));
+ }
+
+ /**
+ * Given a statement: A V B, where B is false and V is true
+ *
+ * Asserts that this is a valid application of the rule if and only if B is true.
+ *
+ * @throws InvalidFileFormatException
+ */
+ @Test
+ public void UTFTest() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/OrEliminationDirectRule/UTF", stt);
+ TreeNode rootNode = stt.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard();
+ ShortTruthTableCell cell = board.getCell(0, 0);
+
+ cell.setData(ShortTruthTableCellType.TRUE);
+ board.addModifiedData(cell);
+ Assert.assertNull(RULE.checkRule(transition));
+
+ cell.setData(ShortTruthTableCellType.FALSE);
+ board.addModifiedData(cell);
+ Assert.assertNotNull(RULE.checkRule(transition));
+ }
+
+ /**
+ * Given a statement: A V B, where V is false
+ *
+ * Asserts that this is a valid application of the rule if and only if both A
+ * and B are false.
+ *
+ * @throws InvalidFileFormatException
+ */
+ @Test
+ public void UFUTest() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/OrEliminationDirectRule/UFU", stt);
+ TreeNode rootNode = stt.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ ShortTruthTableCellType[] cellTypes = {ShortTruthTableCellType.TRUE, ShortTruthTableCellType.FALSE, ShortTruthTableCellType.UNKNOWN};
+
+ for (ShortTruthTableCellType cellType1 : cellTypes) {
+ for (ShortTruthTableCellType cellType2 : cellTypes) {
+ ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard();
+ ShortTruthTableCell a = board.getCell(0, 0);
+ ShortTruthTableCell b = board.getCell(2, 0);
+
+ a.setData(cellType1);
+ b.setData(cellType2);
+
+ board.addModifiedData(a);
+ board.addModifiedData(b);
+
+ if (cellType1 == ShortTruthTableCellType.FALSE && cellType2 == ShortTruthTableCellType.FALSE) {
+ Assert.assertNull(RULE.checkRule(transition));
+ }
+ else {
+ Assert.assertNotNull(RULE.checkRule(transition));
+ }
+ }
+ }
+ }
+
+ /**
+ * Given a statement: A V B, where V is true
+ *
+ * Asserts that setting both A and B is not a valid application of this rule.
+ *
+ * @throws InvalidFileFormatException
+ */
+ @Test
+ public void UTUTest() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/OrEliminationDirectRule/UTU", stt);
+ TreeNode rootNode = stt.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ ShortTruthTableCellType[] cellTypes = {ShortTruthTableCellType.TRUE, ShortTruthTableCellType.FALSE, ShortTruthTableCellType.UNKNOWN};
+
+ for (ShortTruthTableCellType cellType1 : cellTypes) {
+ for (ShortTruthTableCellType cellType2 : cellTypes) {
+ ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard();
+ ShortTruthTableCell a = board.getCell(0, 0);
+ ShortTruthTableCell b = board.getCell(2, 0);
+
+ a.setData(cellType1);
+ b.setData(cellType2);
+
+ board.addModifiedData(a);
+ board.addModifiedData(b);
+
+ Assert.assertNotNull(RULE.checkRule(transition));
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/puzzles/shorttruthtable/rules/OrIntroductionTest.java b/src/test/java/puzzles/shorttruthtable/rules/OrIntroductionTest.java
new file mode 100644
index 000000000..13cb10d55
--- /dev/null
+++ b/src/test/java/puzzles/shorttruthtable/rules/OrIntroductionTest.java
@@ -0,0 +1,105 @@
+package puzzles.shorttruthtable.rules;
+
+import edu.rpi.legup.model.tree.TreeNode;
+import edu.rpi.legup.model.tree.TreeTransition;
+import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTable;
+import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableBoard;
+import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCell;
+import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCellType;
+import edu.rpi.legup.puzzle.shorttruthtable.rules.basic.introduction.DirectRuleOrIntroduction;
+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 OrIntroductionTest {
+ private static final DirectRuleOrIntroduction RULE = new DirectRuleOrIntroduction();
+ private static ShortTruthTable stt;
+
+ @BeforeClass
+ public static void setup() {
+ MockGameBoardFacade.getInstance();
+ stt = new ShortTruthTable();
+ }
+
+ /**
+ * Given a statement: A V B
+ *
+ * Asserts that if at least 1 of A or B is true, then this is a valid application
+ * of the rule if and only if V is true.
+ *
+ * @param filePath The file path for test board setup.
+ * @throws InvalidFileFormatException
+ */
+ @Test
+ public void TrueOrTest() throws InvalidFileFormatException {
+ String path = "puzzles/shorttruthtable/rules/OrIntroductionDirectRule/";
+ trueOrTestHelper(path + "TUT");
+ trueOrTestHelper(path + "TUU");
+ trueOrTestHelper(path + "UUT");
+ trueOrTestHelper(path + "TUF");
+ trueOrTestHelper(path + "FUT");
+ }
+
+ private void trueOrTestHelper(String filePath) throws InvalidFileFormatException {
+ TestUtilities.importTestBoard(filePath, stt);
+ TreeNode rootNode = stt.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard();
+ ShortTruthTableCell or = board.getCell(1, 0);
+
+ or.setData(ShortTruthTableCellType.TRUE);
+ board.addModifiedData(or);
+ Assert.assertNull(RULE.checkRule(transition));
+
+ or.setData(ShortTruthTableCellType.FALSE);
+ board.addModifiedData(or);
+ Assert.assertNotNull(RULE.checkRule(transition));
+ }
+
+ /**
+ * Given a statement: A V B
+ *
+ * Asserts that setting V to false is a valid application of the rule if
+ * and only if both A and B are false.
+ *
+ * @param filePath The file path for test board setup.
+ * @throws InvalidFileFormatException
+ */
+ @Test
+ public void FalseOrTest() throws InvalidFileFormatException {
+ String path = "puzzles/shorttruthtable/rules/OrIntroductionDirectRule/";
+ String[] letters = {"T", "F", "U"};
+ for (String first : letters) {
+ for (String second : letters) {
+ falseOrTestHelper(path + first + "U" + second);
+ }
+ }
+ }
+
+ private void falseOrTestHelper(String filePath) throws InvalidFileFormatException {
+ TestUtilities.importTestBoard(filePath, stt);
+ TreeNode rootNode = stt.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard();
+ ShortTruthTableCell a = board.getCell(0, 0);
+ ShortTruthTableCell b = board.getCell(2, 0);
+ ShortTruthTableCell or = board.getCell(1, 0);
+
+ or.setData(ShortTruthTableCellType.FALSE);
+ board.addModifiedData(or);
+
+ if (a.getType() == ShortTruthTableCellType.FALSE && b.getType() == ShortTruthTableCellType.FALSE) {
+ Assert.assertNull(RULE.checkRule(transition));
+ }
+ else {
+ Assert.assertNotNull(RULE.checkRule(transition));
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/puzzles/shorttruthtable/rules/TrueOrFalseCaseRuleTest.java b/src/test/java/puzzles/shorttruthtable/rules/TrueOrFalseCaseRuleTest.java
new file mode 100644
index 000000000..849e9f15c
--- /dev/null
+++ b/src/test/java/puzzles/shorttruthtable/rules/TrueOrFalseCaseRuleTest.java
@@ -0,0 +1,78 @@
+package puzzles.shorttruthtable.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.shorttruthtable.ShortTruthTable;
+import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableBoard;
+import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCell;
+import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCellType;
+import edu.rpi.legup.puzzle.shorttruthtable.rules.caserule.CaseRuleAtomic;
+import edu.rpi.legup.save.InvalidFileFormatException;
+import legup.MockGameBoardFacade;
+import legup.TestUtilities;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.util.ArrayList;
+
+public class TrueOrFalseCaseRuleTest {
+
+ private static final CaseRuleAtomic RULE = new CaseRuleAtomic();
+ private static ShortTruthTable stt;
+
+ @BeforeClass
+ public static void setUp() {
+ MockGameBoardFacade.getInstance();
+ stt = new ShortTruthTable();
+ }
+
+ /**
+ * Tests the True or False case rule by ensuring that it results in two children,
+ * one that contains Statement as true and one that contains Statement as false.
+ */
+ @Test
+ public void TwoBranchesTest() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/TrueOrFalseCaseRule/Statement", stt);
+ TreeNode rootNode = stt.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard();
+ ShortTruthTableCell cell = board.getCell(0,0);
+ ArrayList cases = RULE.getCases(board, cell);
+
+ // Make sure that the rule checks out
+ Assert.assertNotNull(RULE.checkRule(transition));
+
+ // Make sure there are two branches
+ Assert.assertEquals(2, cases.size());
+
+ ShortTruthTableBoard caseBoard1 = (ShortTruthTableBoard) cases.get(0);
+ ShortTruthTableBoard caseBoard2 = (ShortTruthTableBoard) cases.get(1);
+
+ ShortTruthTableCellType cellType1 = caseBoard1.getCell(0,0).getType();
+ ShortTruthTableCellType cellType2 = caseBoard2.getCell(0,0).getType();
+
+ // First assert the two cells are not equal, then verify that they are true
+ // or false.
+ Assert.assertNotEquals(cellType1, cellType2);
+ Assert.assertTrue(cellType1.equals(ShortTruthTableCellType.TRUE) || cellType1.equals(ShortTruthTableCellType.FALSE));
+ Assert.assertTrue(cellType2.equals(ShortTruthTableCellType.TRUE) || cellType2.equals(ShortTruthTableCellType.FALSE));
+
+ // Verify the board dimensions are unchanged
+ Assert.assertEquals(caseBoard1.getHeight(), caseBoard2.getHeight(), board.getHeight());
+ Assert.assertEquals(caseBoard1.getWidth(), caseBoard2.getWidth(), board.getWidth());
+
+ // Verify that everywhere else on the board is unchanged
+ for (int i = 0; i< caseBoard1.getWidth(); i++) {
+ for (int j = 0; j < caseBoard1.getHeight(); j++) {
+ // Make sure not to check the one cell that should be different
+ if (i != 0 && j != 0) {
+ Assert.assertEquals(caseBoard1.getCell(i, j).getType(), caseBoard2.getCell(i, j).getType());
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/puzzles/treetent/rules/EmptyFieldDirectRuleTest.java b/src/test/java/puzzles/treetent/rules/EmptyFieldDirectRuleTest.java
index 50e2bb970..b7ec8eb02 100644
--- a/src/test/java/puzzles/treetent/rules/EmptyFieldDirectRuleTest.java
+++ b/src/test/java/puzzles/treetent/rules/EmptyFieldDirectRuleTest.java
@@ -27,6 +27,9 @@ public static void setUp() {
treetent = new TreeTent();
}
+ // creates a 3x3 puzzle with no trees
+ // make the (1,1) tile GRASS
+ // checks if tiles logically follow the EmptyFieldDirectRule
@Test
public void EmptyFieldTest() throws InvalidFileFormatException {
TestUtilities.importTestBoard("puzzles/treetent/rules/EmptyFieldDirectRule/EmptyField", treetent);
@@ -34,28 +37,38 @@ public void EmptyFieldTest() throws InvalidFileFormatException {
TreeTransition transition = rootNode.getChildren().get(0);
transition.setRule(RULE);
+ // get board state
TreeTentBoard board = (TreeTentBoard) transition.getBoard();
+ // change the board's cells considering the EmptyField rule
TreeTentCell cell1 = board.getCell(1, 1);
cell1.setData(TreeTentType.GRASS);
-
board.addModifiedData(cell1);
+ // confirm there is a logical following of the EmptyField rule
Assert.assertNull(RULE.checkRule(transition));
+ // only the cell above should change following the rule
+ TreeTentCell c;
for (int i = 0; i < board.getHeight(); i++) {
for (int k = 0; k < board.getWidth(); k++) {
- Point point = new Point(k, i);
- if (point.equals(cell1.getLocation())) {
- Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ c = board.getCell(k, i);
+ if (c.getLocation().equals(cell1.getLocation())) {
+ // logically follows
+ Assert.assertNull(RULE.checkRuleAt(transition, c));
}
else {
- Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ // does not use the rule to logically follow
+ Assert.assertNotNull(RULE.checkRuleAt(transition, c));
}
}
}
}
+ // creates a 3x3 puzzle with 4 trees
+ // trees are at (0,0), (2,0), (0,2), and (2,2)
+ // make the (1,1) tile GRASS.
+ // checks if tiles logically follow the EmptyFieldDirectRule
@Test
public void DiagonalTreeTest() throws InvalidFileFormatException {
TestUtilities.importTestBoard("puzzles/treetent/rules/EmptyFieldDirectRule/DiagonalTree", treetent);
@@ -63,26 +76,197 @@ public void DiagonalTreeTest() throws InvalidFileFormatException {
TreeTransition transition = rootNode.getChildren().get(0);
transition.setRule(RULE);
+ // get board state
TreeTentBoard board = (TreeTentBoard) transition.getBoard();
+ //change the board's cells considering the EmptyField rule
TreeTentCell cell1 = board.getCell(1, 1);
cell1.setData(TreeTentType.GRASS);
-
board.addModifiedData(cell1);
+ // confirm there is a logical following of the EmptyField rule
Assert.assertNull(RULE.checkRule(transition));
+ // only the cell above should change following the rule
+ TreeTentCell c;
for (int i = 0; i < board.getHeight(); i++) {
for (int k = 0; k < board.getWidth(); k++) {
- Point point = new Point(k, i);
- if (point.equals(cell1.getLocation())) {
- Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ c = board.getCell(k, i);
+ if (c.getLocation().equals(cell1.getLocation())) {
+ // logically follows
+ Assert.assertNull(RULE.checkRuleAt(transition, c));
}
else {
- Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ // does not use the rule to logically follow
+ Assert.assertNotNull(RULE.checkRuleAt(transition, c));
}
}
}
}
+
+ // creates a 3x3 puzzle with 4 trees
+ // trees are at (0,1), (1,0), (1,2), and (2,1)
+ // make the (1,1) tile GRASS.
+ // checks if tiles don't logically follow the EmptyFieldDirectRule
+ @Test
+ public void EmptyFieldTestFail() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/treetent/rules/EmptyFieldDirectRule/EmptyFieldFail", treetent);
+ TreeNode rootNode = treetent.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ // get board state
+ TreeTentBoard board = (TreeTentBoard) transition.getBoard();
+
+ //change the board's cells considering breaking the EmptyField rule
+ TreeTentCell cell1 = board.getCell(1, 1);
+ cell1.setData(TreeTentType.GRASS);
+ board.addModifiedData(cell1);
+
+ // confirm there is not a logical following of the EmptyField rule
+ Assert.assertNotNull(RULE.checkRule(transition));
+
+ // the cells should not follow the rule
+ TreeTentCell c;
+ for (int i = 0; i < board.getWidth(); i++) {
+ for (int j = 0; j < board.getHeight(); j++) {
+ c = board.getCell(j, i);
+ // does not use the rule to logically follow
+ Assert.assertNotNull(RULE.checkRuleAt(transition, c));
+ }
+ }
+ }
+
+ // creates a 3x3 puzzle with 1 tree
+ // tree is at (1,0)
+ // make the (1,1) tile GRASS.
+ // checks if tiles don't logically follow the EmptyFieldDirectRule
+ @Test
+ public void EmptyFieldTestFailTop() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/treetent/rules/EmptyFieldDirectRule/EmptyFieldFailTop", treetent);
+ TreeNode rootNode = treetent.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ // get board state
+ TreeTentBoard board = (TreeTentBoard) transition.getBoard();
+
+ //change the board's cells considering breaking the EmptyField rule
+ TreeTentCell cell1 = board.getCell(1, 1);
+ cell1.setData(TreeTentType.GRASS);
+ board.addModifiedData(cell1);
+
+ // confirm there is not a logical following of the EmptyField rule
+ Assert.assertNotNull(RULE.checkRule(transition));
+
+ // the cells should not follow the rule
+ TreeTentCell c;
+ for (int i = 0; i < board.getWidth(); i++) {
+ for (int j = 0; j < board.getHeight(); j++) {
+ c = board.getCell(j, i);
+ // does not use the rule to logically follow
+ Assert.assertNotNull(RULE.checkRuleAt(transition, c));
+ }
+ }
+ }
+
+ // creates a 3x3 puzzle with 1 tree
+ // tree is at (1,2)
+ // make the (1,1) tile GRASS.
+ // checks if tiles don't logically follow the EmptyFieldDirectRule
+ @Test
+ public void EmptyFieldTestFailTopBottom() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/treetent/rules/EmptyFieldDirectRule/EmptyFieldFailBottom", treetent);
+ TreeNode rootNode = treetent.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ // get board state
+ TreeTentBoard board = (TreeTentBoard) transition.getBoard();
+
+ //change the board's cells considering breaking the EmptyField rule
+ TreeTentCell cell1 = board.getCell(1, 1);
+ cell1.setData(TreeTentType.GRASS);
+ board.addModifiedData(cell1);
+
+ // confirm there is not a logical following of the EmptyField rule
+ Assert.assertNotNull(RULE.checkRule(transition));
+
+ // the cells should not follow the rule
+ TreeTentCell c;
+ for (int i = 0; i < board.getWidth(); i++) {
+ for (int j = 0; j < board.getHeight(); j++) {
+ c = board.getCell(j, i);
+ // does not use the rule to logically follow
+ Assert.assertNotNull(RULE.checkRuleAt(transition, c));
+ }
+ }
+ }
+
+ // creates a 3x3 puzzle with 1 tree
+ // tree is at (0,1)
+ // make the (1,1) tile GRASS.
+ // checks if tiles don't logically follow the EmptyFieldDirectRule
+ @Test
+ public void EmptyFieldTestFailLeft() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/treetent/rules/EmptyFieldDirectRule/EmptyFieldFailLeft", treetent);
+ TreeNode rootNode = treetent.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ // get board state
+ TreeTentBoard board = (TreeTentBoard) transition.getBoard();
+
+ //change the board's cells considering breaking the EmptyField rule
+ TreeTentCell cell1 = board.getCell(1, 1);
+ cell1.setData(TreeTentType.GRASS);
+ board.addModifiedData(cell1);
+
+ // confirm there is not a logical following of the EmptyField rule
+ Assert.assertNotNull(RULE.checkRule(transition));
+
+ // the cells should not follow the rule
+ TreeTentCell c;
+ for (int i = 0; i < board.getWidth(); i++) {
+ for (int j = 0; j < board.getHeight(); j++) {
+ c = board.getCell(j, i);
+ // does not use the rule to logically follow
+ Assert.assertNotNull(RULE.checkRuleAt(transition, c));
+ }
+ }
+ }
+
+ // creates a 3x3 puzzle with 1 tree
+ // tree is at (2,1)
+ // make the (1,1) tile GRASS.
+ // checks if tiles don't logically follow the EmptyFieldDirectRule
+ @Test
+ public void EmptyFieldTestFailRight() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/treetent/rules/EmptyFieldDirectRule/EmptyFieldFailRight", treetent);
+ TreeNode rootNode = treetent.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ // get board state
+ TreeTentBoard board = (TreeTentBoard) transition.getBoard();
+
+ //change the board's cells considering breaking the EmptyField rule
+ TreeTentCell cell1 = board.getCell(1, 1);
+ cell1.setData(TreeTentType.GRASS);
+ board.addModifiedData(cell1);
+
+ // confirm there is not a logical following of the EmptyField rule
+ Assert.assertNotNull(RULE.checkRule(transition));
+
+ // the cells should not follow the rule
+ TreeTentCell c;
+ for (int i = 0; i < board.getWidth(); i++) {
+ for (int j = 0; j < board.getHeight(); j++) {
+ c = board.getCell(j, i);
+ // does not use the rule to logically follow
+ Assert.assertNotNull(RULE.checkRuleAt(transition, c));
+ }
+ }
+ }
}
diff --git a/src/test/java/puzzles/treetent/rules/FinishWithGrassDirectRuleTest.java b/src/test/java/puzzles/treetent/rules/FinishWithGrassDirectRuleTest.java
index 8dbec657a..2517df563 100644
--- a/src/test/java/puzzles/treetent/rules/FinishWithGrassDirectRuleTest.java
+++ b/src/test/java/puzzles/treetent/rules/FinishWithGrassDirectRuleTest.java
@@ -15,6 +15,8 @@
import org.junit.Test;
import java.awt.*;
+import java.util.List;
+import java.util.ArrayList;
public class FinishWithGrassDirectRuleTest {
@@ -27,15 +29,24 @@ public static void setUp() {
treetent = new TreeTent();
}
+ /**
+ * 3x3 TreeTent puzzle with a tent at (0,0)
+ * Tests FinishWithGrassDirectRule on GRASS tiles horizontal of the tent
+ * at (1,0) and (2,0)
+ *
+ * @throws InvalidFileFormatException
+ */
@Test
- public void EmptyFieldTest() throws InvalidFileFormatException {
- TestUtilities.importTestBoard("puzzles/treetent/rules/FinishWithGrassDirectRule/FinishWithGrass", treetent);
+ public void FinishWithGrassHorizontalTest() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/treetent/rules/FinishWithGrassDirectRule/CornerTent", treetent);
TreeNode rootNode = treetent.getTree().getRootNode();
TreeTransition transition = rootNode.getChildren().get(0);
transition.setRule(RULE);
+ // get board state
TreeTentBoard board = (TreeTentBoard) transition.getBoard();
+ // change the board's cells considering the FinishWithGrass rule
TreeTentCell cell1 = board.getCell(1, 0);
cell1.setData(TreeTentType.GRASS);
TreeTentCell cell2 = board.getCell(2, 0);
@@ -44,21 +55,316 @@ public void EmptyFieldTest() throws InvalidFileFormatException {
board.addModifiedData(cell1);
board.addModifiedData(cell2);
+ // confirm there is a logical following of the EmptyField rule
Assert.assertNull(RULE.checkRule(transition));
+ // only the cell above should change following the rule
+ TreeTentCell c;
for (int i = 0; i < board.getHeight(); i++) {
for (int k = 0; k < board.getWidth(); k++) {
- Point point = new Point(k, i);
- if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) {
- Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ c = board.getCell(k, i);
+ if (c.getLocation().equals(cell1.getLocation()) || c.getLocation().equals(cell2.getLocation())) {
+ // logically follows
+ Assert.assertNull(RULE.checkRuleAt(transition, c));
}
else {
- Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ // does not use the rule to logically follow
+ Assert.assertNotNull(RULE.checkRuleAt(transition, c));
}
}
}
}
-}
+ /**
+ * 3x3 TreeTent puzzle with a tent at (0,0)
+ * Tests FinishWithGrassDirectRule on GRASS tiles vertical of the tent
+ * at (0,1) and (0,2)
+ *
+ * @throws InvalidFileFormatException
+ */
+ @Test
+ public void FinishWithGrassVerticalTest() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/treetent/rules/FinishWithGrassDirectRule/CornerTent", treetent);
+ TreeNode rootNode = treetent.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+ // get board state
+ TreeTentBoard board = (TreeTentBoard) transition.getBoard();
+ // change the board's cells considering the FinishWithGrass rule
+ TreeTentCell cell1 = board.getCell(0, 1);
+ cell1.setData(TreeTentType.GRASS);
+ TreeTentCell cell2 = board.getCell(0, 2);
+ cell2.setData(TreeTentType.GRASS);
+
+ board.addModifiedData(cell1);
+ board.addModifiedData(cell2);
+
+ // confirm there is a logical following of the EmptyField rule
+ Assert.assertNull(RULE.checkRule(transition));
+
+ // only the cell above should change following the rule
+ TreeTentCell c;
+ for (int i = 0; i < board.getHeight(); i++) {
+ for (int k = 0; k < board.getWidth(); k++) {
+ c = board.getCell(k, i);
+ if (c.getLocation().equals(cell1.getLocation()) || c.getLocation().equals(cell2.getLocation())) {
+ // logically follows
+ Assert.assertNull(RULE.checkRuleAt(transition, c));
+ }
+ else {
+ // does not use the rule to logically follow
+ Assert.assertNotNull(RULE.checkRuleAt(transition, c));
+ }
+ }
+ }
+ }
+
+ /**
+ * 3x3 TreeTent puzzle with a tent at (0,0)
+ * Tests FinishWithGrassDirectRule on GRASS tiles
+ * at (1,0), (2,0), (0,1), and (0,2)
+ *
+ * @throws InvalidFileFormatException
+ */
+ @Test
+ public void FinishWithGrassTest() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/treetent/rules/FinishWithGrassDirectRule/CornerTent", treetent);
+ TreeNode rootNode = treetent.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ // get board state
+ TreeTentBoard board = (TreeTentBoard) transition.getBoard();
+
+ // change the board's cells considering the FinishWithGrass rule
+ TreeTentCell cell1 = board.getCell(1, 0);
+ cell1.setData(TreeTentType.GRASS);
+ TreeTentCell cell2 = board.getCell(2, 0);
+ cell2.setData(TreeTentType.GRASS);
+ TreeTentCell cell3 = board.getCell(0, 1);
+ cell3.setData(TreeTentType.GRASS);
+ TreeTentCell cell4 = board.getCell(0, 2);
+ cell4.setData(TreeTentType.GRASS);
+
+ board.addModifiedData(cell1);
+ board.addModifiedData(cell2);
+ board.addModifiedData(cell3);
+ board.addModifiedData(cell4);
+
+ // confirm there is a logical following of the EmptyField rule
+ Assert.assertNull(RULE.checkRule(transition));
+
+ // only the cell above should change following the rule
+ TreeTentCell c;
+ for (int i = 0; i < board.getHeight(); i++) {
+ for (int k = 0; k < board.getWidth(); k++) {
+ c = board.getCell(k, i);
+ if (c.getLocation().equals(cell1.getLocation()) ||
+ c.getLocation().equals(cell2.getLocation()) ||
+ c.getLocation().equals(cell3.getLocation()) ||
+ c.getLocation().equals(cell4.getLocation())) {
+ // logically follows
+ Assert.assertNull(RULE.checkRuleAt(transition, c));
+ }
+ else {
+ // does not use the rule to logically follow
+ Assert.assertNotNull(RULE.checkRuleAt(transition, c));
+ }
+ }
+ }
+ }
+
+ /**
+ * 3x3 TreeTent puzzle with no tents
+ * Tests FinishWithGrassDirectRule on GRASS tiles
+ * GRASS tiles fill entire board
+ *
+ * @throws InvalidFileFormatException
+ */
+ @Test
+ public void NoTentTest() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/treetent/rules/FinishWithGrassDirectRule/NoTent", treetent);
+ TreeNode rootNode = treetent.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ // get board state
+ TreeTentBoard board = (TreeTentBoard) transition.getBoard();
+
+ // change the board's cells considering the FinishWithGrass rule
+ List cells = new ArrayList();
+ for (int i = 0; i < board.getWidth(); i++) {
+ for (int k = 0; k < board.getHeight(); k++) {
+ TreeTentCell c = board.getCell(i, k);
+ c.setData(TreeTentType.GRASS);
+ cells.add(c);
+ }
+ }
+
+ for (TreeTentCell c : cells) {
+ board.addModifiedData(c);
+ }
+
+ // confirm there is a logical following of the EmptyField rule
+ Assert.assertNull(RULE.checkRule(transition));
+
+ // all cells should change following the rule
+ for (TreeTentCell c : cells) {
+ // logically follows
+ Assert.assertNull(RULE.checkRuleAt(transition, c));
+ }
+ }
+ /**
+ * 3x3 TreeTent puzzle with a tent at (1,1)
+ * Tests FinishWithGrassDirectRule on GRASS tiles surrounding the tent
+ * at (1,0), (0,1), (2,1), and (1,2)
+ *
+ * @throws InvalidFileFormatException
+ */
+ @Test
+ public void MiddleTentTest() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/treetent/rules/FinishWithGrassDirectRule/MiddleTent", treetent);
+ TreeNode rootNode = treetent.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ // get board state
+ TreeTentBoard board = (TreeTentBoard) transition.getBoard();
+
+ // change the board's cells considering the FinishWithGrass rule
+ TreeTentCell cell1 = board.getCell(1, 0);
+ TreeTentCell cell2 = board.getCell(0, 1);
+ TreeTentCell cell3 = board.getCell(2, 1);
+ TreeTentCell cell4 = board.getCell(1, 2);
+
+ cell1.setData(TreeTentType.GRASS);
+ cell2.setData(TreeTentType.GRASS);
+ cell3.setData(TreeTentType.GRASS);
+ cell4.setData(TreeTentType.GRASS);
+
+ board.addModifiedData(cell1);
+ board.addModifiedData(cell2);
+ board.addModifiedData(cell3);
+ board.addModifiedData(cell4);
+
+ // confirm there is a logical following of the EmptyField rule
+ Assert.assertNull(RULE.checkRule(transition));
+
+ // only the cell above should change following the rule
+ TreeTentCell c;
+ for (int i = 0; i < board.getHeight(); i++) {
+ for (int k = 0; k < board.getWidth(); k++) {
+ c = board.getCell(k, i);
+ if (c.getLocation().equals(cell1.getLocation()) ||
+ c.getLocation().equals(cell2.getLocation()) ||
+ c.getLocation().equals(cell3.getLocation()) ||
+ c.getLocation().equals(cell4.getLocation())) {
+ // logically follows
+ Assert.assertNull(RULE.checkRuleAt(transition, c));
+ }
+ else {
+ // does not use the rule to logically follow
+ Assert.assertNotNull(RULE.checkRuleAt(transition, c));
+ }
+ }
+ }
+ }
+
+ /**
+ * 3x3 TreeTent puzzle with missing tents
+ * Tests FinishWithGrassDirectRule on GRASS tiles filling the puzzle
+ * all GRASS tiles should fail the FinishWithGrassDirectRule
+ *
+ * @throws InvalidFileFormatException
+ */
+ @Test
+ public void FailTentTest() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/treetent/rules/FinishWithGrassDirectRule/FailTent", treetent);
+ TreeNode rootNode = treetent.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ // get board state
+ TreeTentBoard board = (TreeTentBoard) transition.getBoard();
+
+ // change the board's cells not following the FinishWithGrass rule
+ List cells = new ArrayList();
+ for (int i = 0; i < board.getWidth(); i++) {
+ for (int k = 0; k < board.getHeight(); k++) {
+ TreeTentCell c = board.getCell(i, k);
+ c.setData(TreeTentType.GRASS);
+ cells.add(c);
+ }
+ }
+
+ for (TreeTentCell c : cells) {
+ board.addModifiedData(c);
+ }
+
+ // confirm there is a logical following of the EmptyField rule
+ Assert.assertNotNull(RULE.checkRule(transition));
+
+ // all cells should fail the rule test
+ for (TreeTentCell c : cells) {
+ // does not use the rule to logically follow
+ Assert.assertNotNull(RULE.checkRuleAt(transition, c));
+ }
+ }
+ /**
+ * 7x7 TreeTent puzzle with multiple tents spaced out
+ * Tests FinishWithGrassDirectRule on GRASS tiles between the tents
+ * at (0,3), (2,3), (4,3), and (6,3)
+ *
+ * @throws InvalidFileFormatException
+ */
+ @Test
+ public void SpacedOutTentTest() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/treetent/rules/FinishWithGrassDirectRule/SpacedOutTent", treetent);
+ TreeNode rootNode = treetent.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ // get board state
+ TreeTentBoard board = (TreeTentBoard) transition.getBoard();
+
+ // change the board's cells considering the FinishWithGrass rule
+ TreeTentCell cell1 = board.getCell(0, 3);
+ TreeTentCell cell2 = board.getCell(2, 3);
+ TreeTentCell cell3 = board.getCell(4, 3);
+ TreeTentCell cell4 = board.getCell(6, 3);
+
+ cell1.setData(TreeTentType.GRASS);
+ cell2.setData(TreeTentType.GRASS);
+ cell3.setData(TreeTentType.GRASS);
+ cell4.setData(TreeTentType.GRASS);
+
+ board.addModifiedData(cell1);
+ board.addModifiedData(cell2);
+ board.addModifiedData(cell3);
+ board.addModifiedData(cell4);
+
+ // confirm there is a logical following of the EmptyField rule
+ Assert.assertNull(RULE.checkRule(transition));
+
+ // only the cell above should change following the rule
+ TreeTentCell c;
+ for (int i = 0; i < board.getHeight(); i++) {
+ for (int k = 0; k < board.getWidth(); k++) {
+ c = board.getCell(k, i);
+ if (c.getLocation().equals(cell1.getLocation()) ||
+ c.getLocation().equals(cell2.getLocation()) ||
+ c.getLocation().equals(cell3.getLocation()) ||
+ c.getLocation().equals(cell4.getLocation())) {
+ // logically follows
+ Assert.assertNull(RULE.checkRuleAt(transition, c));
+ }
+ else {
+ // does not use the rule to logically follow
+ Assert.assertNotNull(RULE.checkRuleAt(transition, c));
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/puzzles/treetent/rules/FinishWithTentsDirectRuleTest.java b/src/test/java/puzzles/treetent/rules/FinishWithTentsDirectRuleTest.java
index 6c1468c50..725c3c9de 100644
--- a/src/test/java/puzzles/treetent/rules/FinishWithTentsDirectRuleTest.java
+++ b/src/test/java/puzzles/treetent/rules/FinishWithTentsDirectRuleTest.java
@@ -15,6 +15,7 @@
import org.junit.Test;
import java.awt.*;
+import java.util.*;
public class FinishWithTentsDirectRuleTest {
@@ -26,9 +27,94 @@ public static void setUp() {
MockGameBoardFacade.getInstance();
treetent = new TreeTent();
}
+
+ /**
+ * 3x3 TreeTent puzzle with a GRASS tile at (0,0)
+ * Tests FinishWithTentsDirectRule on TENT tiles horizontal of the GRASS tile
+ * at (1,0) and (2,0)
+ *
+ * @throws InvalidFileFormatException
+ */
+ @Test
+ public void FinishWithHorizontalTentsTest() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/treetent/rules/FinishWithTentsDirectRule/FinishWithHorizontalTents", 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);
+ cell1.setData(TreeTentType.TENT);
+ TreeTentCell cell2 = board.getCell(2, 0);
+ cell2.setData(TreeTentType.TENT);
+
+ board.addModifiedData(cell1);
+ board.addModifiedData(cell2);
+
+ Assert.assertNull(RULE.checkRule(transition));
+
+ for (int i = 0; i < board.getHeight(); i++) {
+ for (int k = 0; k < board.getWidth(); k++) {
+ TreeTentCell c = board.getCell(k, i);
+ if ((c.getLocation()).equals(cell1.getLocation()) || (c.getLocation()).equals(cell2.getLocation())) {
+ Assert.assertNull(RULE.checkRuleAt(transition, c));
+ }
+ else {
+ Assert.assertNotNull(RULE.checkRuleAt(transition, c));
+ }
+ }
+ }
+ }
+ /**
+ * 3x3 TreeTent puzzle with a GRASS tile at (0,0)
+ * Tests FinishWithTentsDirectRule on TENT tiles vertical of the GRASS tile
+ * at (0,1) and (0,2)
+ *
+ * @throws InvalidFileFormatException
+ */
@Test
- public void EmptyFieldTest() throws InvalidFileFormatException {
+ public void FinishWithVerticalTentsTest() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/treetent/rules/FinishWithTentsDirectRule/FinishWithVerticalTents", treetent);
+ TreeNode rootNode = treetent.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ TreeTentBoard board = (TreeTentBoard) transition.getBoard();
+
+ TreeTentCell cell1 = board.getCell(0, 1);
+ cell1.setData(TreeTentType.TENT);
+ TreeTentCell cell2 = board.getCell(0, 2);
+ cell2.setData(TreeTentType.TENT);
+
+ board.addModifiedData(cell1);
+ board.addModifiedData(cell2);
+
+ Assert.assertNull(RULE.checkRule(transition));
+
+ for (int i = 0; i < board.getHeight(); i++) {
+ for (int k = 0; k < board.getWidth(); k++) {
+ TreeTentCell c = board.getCell(k, i);
+ if ((c.getLocation()).equals(cell1.getLocation()) || (c.getLocation()).equals(cell2.getLocation())) {
+ Assert.assertNull(RULE.checkRuleAt(transition, c));
+ }
+ else {
+ Assert.assertNotNull(RULE.checkRuleAt(transition, c));
+ }
+ }
+ }
+ }
+
+ /**
+ * 3x3 TreeTent puzzle with a GRASS tile at (1,1)
+ * Tests FinishWithTentsDirectRule on TENT tiles around the GRASS tile
+ * at (1,0), (1,2), (0,1), and (2,1)
+ *
+ * @throws InvalidFileFormatException
+ */
+ @Test
+ public void FinishWithTentsTest() throws InvalidFileFormatException {
TestUtilities.importTestBoard("puzzles/treetent/rules/FinishWithTentsDirectRule/FinishWithTents", treetent);
TreeNode rootNode = treetent.getTree().getRootNode();
TreeTransition transition = rootNode.getChildren().get(0);
@@ -37,24 +123,235 @@ public void EmptyFieldTest() throws InvalidFileFormatException {
TreeTentBoard board = (TreeTentBoard) transition.getBoard();
TreeTentCell cell1 = board.getCell(1, 0);
+ TreeTentCell cell2 = board.getCell(1, 2);
+ TreeTentCell cell3 = board.getCell(0, 1);
+ TreeTentCell cell4 = board.getCell(2, 1);
+
cell1.setData(TreeTentType.TENT);
- TreeTentCell cell2 = board.getCell(2, 0);
cell2.setData(TreeTentType.TENT);
+ cell3.setData(TreeTentType.TENT);
+ cell4.setData(TreeTentType.TENT);
board.addModifiedData(cell1);
board.addModifiedData(cell2);
+ board.addModifiedData(cell3);
+ board.addModifiedData(cell4);
Assert.assertNull(RULE.checkRule(transition));
for (int i = 0; i < board.getHeight(); i++) {
for (int k = 0; k < board.getWidth(); k++) {
- Point point = new Point(k, i);
- if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) {
- Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ TreeTentCell c = board.getCell(k, i);
+ if ((c.getLocation()).equals(cell1.getLocation()) ||
+ (c.getLocation()).equals(cell2.getLocation()) ||
+ (c.getLocation()).equals(cell3.getLocation()) ||
+ (c.getLocation()).equals(cell4.getLocation())) {
+ Assert.assertNull(RULE.checkRuleAt(transition, c));
}
else {
- Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, c));
+ }
+ }
+ }
+ }
+
+ /**
+ * 3x3 TreeTent puzzle with a TENT tile at (1,1)
+ * Tests FinishWithTentsDirectRule on TENT tiles around the TENT tile
+ * at (1,0), (1,2), (0,1), and (2,1)
+ *
+ * @throws InvalidFileFormatException
+ */
+ @Test
+ public void AdditionalTentsTest() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/treetent/rules/FinishWithTentsDirectRule/AdditionalTents", 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, 2);
+ TreeTentCell cell3 = board.getCell(0, 1);
+ TreeTentCell cell4 = board.getCell(2, 1);
+
+ cell1.setData(TreeTentType.TENT);
+ cell2.setData(TreeTentType.TENT);
+ cell3.setData(TreeTentType.TENT);
+ cell4.setData(TreeTentType.TENT);
+
+ board.addModifiedData(cell1);
+ board.addModifiedData(cell2);
+ board.addModifiedData(cell3);
+ board.addModifiedData(cell4);
+
+ Assert.assertNull(RULE.checkRule(transition));
+
+ for (int i = 0; i < board.getHeight(); i++) {
+ for (int k = 0; k < board.getWidth(); k++) {
+ TreeTentCell c = board.getCell(k, i);
+ if ((c.getLocation()).equals(cell1.getLocation()) ||
+ (c.getLocation()).equals(cell2.getLocation()) ||
+ (c.getLocation()).equals(cell3.getLocation()) ||
+ (c.getLocation()).equals(cell4.getLocation())) {
+ Assert.assertNull(RULE.checkRuleAt(transition, c));
+ }
+ else {
+ Assert.assertNotNull(RULE.checkRuleAt(transition, c));
+ }
+ }
+ }
+ }
+
+ /**
+ * Empty 3x3 TreeTent puzzle
+ * Tests FinishWithTentsDirectRule on TENT tiles of entire puzzle
+ * all TENT tiles should fail FinishWithTentsDirectRule
+ * as no TENT tiles should be there
+ *
+ * @throws InvalidFileFormatException
+ */
+ @Test
+ public void FinishWithTentsFailTest() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/treetent/rules/FinishWithTentsDirectRule/FinishWithTentsFail", treetent);
+ TreeNode rootNode = treetent.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ TreeTentBoard board = (TreeTentBoard) transition.getBoard();
+
+ ArrayList cells = new ArrayList();
+
+ for (int i = 0; i < board.getHeight(); i++) {
+ for (int k = 0; k < board.getWidth(); k++) {
+ TreeTentCell c = board.getCell(k, i);
+ c.setData(TreeTentType.TENT);
+ board.addModifiedData(c);
+ cells.add(c);
+ }
+ }
+
+ 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)));
+ }
+ }
+ }
+
+ /**
+ * 3x3 TreeTent puzzle with a TENT tile at (1,1)
+ * Tests FinishWithTentsDirectRule on TENT tiles around the TENT tile
+ * at (1,0), (1,2), (0,1), and (2,1)
+ * all TENT tiles should fail FinishWithTentsDirectRule
+ * as there were already sufficient number of TENT tiles
+ *
+ * @throws InvalidFileFormatException
+ */
+ @Test
+ public void TooManyTentsTest() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/treetent/rules/FinishWithTentsDirectRule/TooManyTents", treetent);
+ TreeNode rootNode = treetent.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ TreeTentBoard board = (TreeTentBoard) transition.getBoard();
+
+ ArrayList cells = new ArrayList();
+
+ for (int i = 0; i < board.getHeight(); i++) {
+ for (int k = 0; k < board.getWidth(); k++) {
+ if((k == 1)&&(i == 1)) {
+ continue;
}
+ TreeTentCell c = board.getCell(k, i);
+ c.setData(TreeTentType.TENT);
+ board.addModifiedData(c);
+ cells.add(c);
+ }
+ }
+
+ 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)));
+ }
+ }
+ }
+
+ /**
+ * 3x3 TreeTent puzzle with a TENT tile at (1,1)
+ * Tests FinishWithTentsDirectRule on TENT tiles around the TENT tile
+ * at (1,0), (1,2), (0,1), and (2,1)
+ * all TENT tiles should fail FinishWithTentsDirectRule
+ * as there are multiple configurations of the placement
+ * of the TENT tiles
+ *
+ * @throws InvalidFileFormatException
+ */
+ @Test
+ public void AmbiguousTentsTest () throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/treetent/rules/FinishWithTentsDirectRule/AmbiguousTents", treetent);
+ TreeNode rootNode = treetent.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ TreeTentBoard board = (TreeTentBoard) transition.getBoard();
+
+ TreeTentCell cell = board.getCell(0, 1);
+ cell.setData(TreeTentType.TENT);
+ 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)));
+ }
+ }
+
+ cell.setData(TreeTentType.UNKNOWN);
+ board.addModifiedData(cell);
+ cell = board.getCell(1, 0);
+ cell.setData(TreeTentType.TENT);
+ 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)));
+ }
+ }
+
+ cell.setData(TreeTentType.UNKNOWN);
+ board.addModifiedData(cell);
+ cell = board.getCell(2, 1);
+ cell.setData(TreeTentType.TENT);
+ 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)));
+ }
+ }
+
+ cell.setData(TreeTentType.UNKNOWN);
+ board.addModifiedData(cell);
+ cell = board.getCell(1, 2);
+ cell.setData(TreeTentType.TENT);
+ 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/treetent/rules/LastCampingSpotDirectRuleTest.java b/src/test/java/puzzles/treetent/rules/LastCampingSpotDirectRuleTest.java
index 415b4f4b9..3e1b390fb 100644
--- a/src/test/java/puzzles/treetent/rules/LastCampingSpotDirectRuleTest.java
+++ b/src/test/java/puzzles/treetent/rules/LastCampingSpotDirectRuleTest.java
@@ -27,9 +27,14 @@ public static void setUp() {
treetent = new TreeTent();
}
+ /**
+ * @throws InvalidFileFormatException
+ *
+ * Checks if a test works for an empty square above a tree which is surrounded on all other sides.
+ */
@Test
- public void EmptyFieldTest() throws InvalidFileFormatException {
- TestUtilities.importTestBoard("puzzles/treetent/rules/LastCampingSpotDirectRule/LastCampingSpot", treetent);
+ public void EmptyFieldTest_Up() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/treetent/rules/LastCampingSpotDirectRule/LastCampingSpotUp", treetent);
TreeNode rootNode = treetent.getTree().getRootNode();
TreeTransition transition = rootNode.getChildren().get(0);
transition.setRule(RULE);
@@ -55,6 +60,108 @@ public void EmptyFieldTest() throws InvalidFileFormatException {
}
}
}
+
+ /**
+ * @throws InvalidFileFormatException
+ *
+ * Checks if a test works for an empty square below a tree which is surrounded on all other sides.
+ */
+ @Test
+ public void EmptyFieldTest_Down() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/treetent/rules/LastCampingSpotDirectRule/LastCampingSpotDown", 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, 2);
+ cell1.setData(TreeTentType.TENT);
+
+ board.addModifiedData(cell1);
+
+ Assert.assertNull(RULE.checkRule(transition));
+
+ for (int i = 0; i < board.getHeight(); i++) {
+ for (int k = 0; k < board.getWidth(); k++) {
+ Point point = new Point(k, i);
+ if (point.equals(cell1.getLocation())) {
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ }
+ else {
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ }
+ }
+ }
+ }
+
+ /**
+ * @throws InvalidFileFormatException
+ *
+ * Checks if a test works for an empty square to the left of a tree which is surrounded on all other sides.
+ */
+ @Test
+ public void EmptyFieldTest_Left() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/treetent/rules/LastCampingSpotDirectRule/LastCampingSpotLeft", treetent);
+ TreeNode rootNode = treetent.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ TreeTentBoard board = (TreeTentBoard) transition.getBoard();
+
+ TreeTentCell cell1 = board.getCell(0, 1);
+ cell1.setData(TreeTentType.TENT);
+
+ board.addModifiedData(cell1);
+
+ Assert.assertNull(RULE.checkRule(transition));
+
+ for (int i = 0; i < board.getHeight(); i++) {
+ for (int k = 0; k < board.getWidth(); k++) {
+ Point point = new Point(k, i);
+ if (point.equals(cell1.getLocation())) {
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ }
+ else {
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ }
+ }
+ }
+ }
+
+ /**
+ * @throws InvalidFileFormatException
+ *
+ * Checks if a test works for an empty square to the right of a tree which is surrounded on all other sides.
+ */
+ @Test
+ public void EmptyFieldTest_Right() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/treetent/rules/LastCampingSpotDirectRule/LastCampingSpotRight", treetent);
+ TreeNode rootNode = treetent.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ TreeTentBoard board = (TreeTentBoard) transition.getBoard();
+
+ TreeTentCell cell1 = board.getCell(2, 1);
+ cell1.setData(TreeTentType.TENT);
+
+ board.addModifiedData(cell1);
+
+ Assert.assertNull(RULE.checkRule(transition));
+
+ for (int i = 0; i < board.getHeight(); i++) {
+ for (int k = 0; k < board.getWidth(); k++) {
+ Point point = new Point(k, i);
+ if (point.equals(cell1.getLocation())) {
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ }
+ else {
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ }
+ }
+ }
+ }
}
diff --git a/src/test/java/puzzles/treetent/rules/NoTentForTreeContradictionRuleTest.java b/src/test/java/puzzles/treetent/rules/NoTentForTreeContradictionRuleTest.java
index b2d47e222..52aea28c0 100644
--- a/src/test/java/puzzles/treetent/rules/NoTentForTreeContradictionRuleTest.java
+++ b/src/test/java/puzzles/treetent/rules/NoTentForTreeContradictionRuleTest.java
@@ -28,8 +28,12 @@ public static void setUp() {
treetent = new TreeTent();
}
+ /**
+ * @throws InvalidFileFormatException
+ * Tests if a tree is next to only grass in a 2x2 grid triggers the contradiction
+ */
@Test
- public void NoTentForTreeContradictionRule_() throws InvalidFileFormatException {
+ public void NoTentForTreeContradictionRule_Basic() throws InvalidFileFormatException {
TestUtilities.importTestBoard("puzzles/treetent/rules/NoTentForTreeContradictionRule/NoTentForTree", treetent);
TreeNode rootNode = treetent.getTree().getRootNode();
TreeTransition transition = rootNode.getChildren().get(0);
@@ -43,5 +47,65 @@ public void NoTentForTreeContradictionRule_() throws InvalidFileFormatException
Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(1, 0)));
Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(1, 1)));
}
+
+ /**
+ * @throws InvalidFileFormatException
+ * Tests similarly to above, but now with a tent diagonally next to the tree, which should still contradict
+ */
+ @Test
+ public void NoTentForTreeContradictionRule_Diagonal() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/treetent/rules/NoTentForTreeContradictionRule/NoTentForTreeDiagonal", treetent);
+ TreeNode rootNode = treetent.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ TreeTentBoard board = (TreeTentBoard) transition.getBoard();
+
+ Assert.assertNull(RULE.checkContradiction(board));
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(0, 0)));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(0, 1)));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(1, 0)));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(1, 1)));
+ }
+
+ /**
+ * @throws InvalidFileFormatException
+ * Tests that adjacent trees do not allow a pass
+ */
+ @Test
+ public void NoTentForTreeContradictionRule_TwoTrees() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/treetent/rules/NoTentForTreeContradictionRule/NoTentForTreeTwoTrees", treetent);
+ TreeNode rootNode = treetent.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ TreeTentBoard board = (TreeTentBoard) transition.getBoard();
+
+ Assert.assertNull(RULE.checkContradiction(board));
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(0, 0)));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(0, 1)));
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(1, 0)));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(1, 1)));
+ }
+
+ /**
+ * @throws InvalidFileFormatException
+ * Tests similarly to above, but now with a tent diagonally next to two trees, which should still contradict on one.
+ */
+ @Test
+ public void NoTentForTreeContradictionRule_TwoTreesDiagonal() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/treetent/rules/NoTentForTreeContradictionRule/NoTentForTreeTwoTreesDiagonal", treetent);
+ TreeNode rootNode = treetent.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ TreeTentBoard board = (TreeTentBoard) transition.getBoard();
+
+ Assert.assertNull(RULE.checkContradiction(board));
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(0, 0)));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(0, 1)));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(1, 0)));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(1, 1)));
+ }
}
diff --git a/src/test/java/puzzles/treetent/rules/NoTreeForTentContradictionRuleTest.java b/src/test/java/puzzles/treetent/rules/NoTreeForTentContradictionRuleTest.java
index c3003cef1..2ad2ac90e 100644
--- a/src/test/java/puzzles/treetent/rules/NoTreeForTentContradictionRuleTest.java
+++ b/src/test/java/puzzles/treetent/rules/NoTreeForTentContradictionRuleTest.java
@@ -10,13 +10,9 @@
import edu.rpi.legup.puzzle.treetent.TreeTent;
import edu.rpi.legup.puzzle.treetent.TreeTentBoard;
-import edu.rpi.legup.puzzle.treetent.TreeTentCell;
-import edu.rpi.legup.puzzle.treetent.TreeTentType;
import edu.rpi.legup.puzzle.treetent.rules.NoTreeForTentContradictionRule;
import edu.rpi.legup.save.InvalidFileFormatException;
-import java.awt.*;
-
public class NoTreeForTentContradictionRuleTest {
private static final NoTreeForTentContradictionRule RULE = new NoTreeForTentContradictionRule();
@@ -28,9 +24,13 @@ public static void setUp() {
treetent = new TreeTent();
}
+ /**
+ * @throws InvalidFileFormatException
+ * Tests if, in a 2x2 Grid, a Tent in the NW corner has no adjacent trees
+ */
@Test
- public void NoTreeForTentContradictionRule_() throws InvalidFileFormatException {
- TestUtilities.importTestBoard("puzzles/treetent/rules/NoTreeForTentContradictionRule/NoTreeForTent", treetent);
+ public void NoTreeForTentContradictionRule_NW() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/treetent/rules/NoTreeForTentContradictionRule/NoTreeForTentNW", treetent);
TreeNode rootNode = treetent.getTree().getRootNode();
TreeTransition transition = rootNode.getChildren().get(0);
transition.setRule(RULE);
@@ -43,5 +43,165 @@ public void NoTreeForTentContradictionRule_() throws InvalidFileFormatException
Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(1, 0)));
Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(1, 1)));
}
+
+ /**
+ * @throws InvalidFileFormatException
+ * Tests if, in a 2x2 Grid, a Tent in the NE corner has no adjacent trees
+ */
+ @Test
+ public void NoTreeForTentContradictionRule_NE() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/treetent/rules/NoTreeForTentContradictionRule/NoTreeForTentNE", treetent);
+ TreeNode rootNode = treetent.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ TreeTentBoard board = (TreeTentBoard) transition.getBoard();
+
+ Assert.assertNull(RULE.checkContradiction(board));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(0, 0)));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(0, 1)));
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(1, 0)));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(1, 1)));
+ }
+
+ /**
+ * @throws InvalidFileFormatException
+ * Tests if, in a 2x2 Grid, a Tent in the NW corner has no adjacent trees
+ */
+ @Test
+ public void NoTreeForTentContradictionRule_SW() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/treetent/rules/NoTreeForTentContradictionRule/NoTreeForTentSW", treetent);
+ TreeNode rootNode = treetent.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ TreeTentBoard board = (TreeTentBoard) transition.getBoard();
+
+ Assert.assertNull(RULE.checkContradiction(board));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(0, 0)));
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(0, 1)));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(1, 0)));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(1, 1)));
+ }
+
+ /**
+ * @throws InvalidFileFormatException
+ * Tests if, in a 2x2 Grid, a Tent in the SE corner has no adjacent trees
+ */
+ @Test
+ public void NoTreeForTentContradictionRule_SE() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/treetent/rules/NoTreeForTentContradictionRule/NoTreeForTentSE", treetent);
+ TreeNode rootNode = treetent.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ TreeTentBoard board = (TreeTentBoard) transition.getBoard();
+
+ Assert.assertNull(RULE.checkContradiction(board));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(0, 0)));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(0, 1)));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(1, 0)));
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(1, 1)));
+ }
+
+ /**
+ * @throws InvalidFileFormatException
+ * Tests if, in a 3x3 Grid with no trees, a Tent in the center cell has no adjacent trees
+ */
+ @Test
+ public void NoTreeForTentContradictionRule_3x3() throws InvalidFileFormatException{
+ TestUtilities.importTestBoard("puzzles/treetent/rules/NoTreeForTentContradictionRule/NoTreeForTent3x3", treetent);
+ TreeNode rootNode = treetent.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ TreeTentBoard board = (TreeTentBoard) transition.getBoard();
+
+ Assert.assertNull(RULE.checkContradiction(board));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(0, 0)));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(1, 0)));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(2, 0)));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(0, 1)));
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(1, 1)));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(2, 1)));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(0, 2)));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(1, 2)));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(2, 2)));
+ }
+
+ /**
+ * @throws InvalidFileFormatException
+ * Tests if, in a 3x3 Grid with diagonal trees, a Tent in the center cell has no adjacent trees
+ */
+ @Test
+ public void NoTreeForTentContradictionRule_3x3WithDiagonalTrees() throws InvalidFileFormatException{
+ TestUtilities.importTestBoard("puzzles/treetent/rules/NoTreeForTentContradictionRule/NoTreeForTentDiagonals", treetent);
+ TreeNode rootNode = treetent.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ TreeTentBoard board = (TreeTentBoard) transition.getBoard();
+
+ Assert.assertNull(RULE.checkContradiction(board));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(0, 0)));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(1, 0)));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(2, 0)));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(0, 1)));
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(1, 1)));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(2, 1)));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(0, 2)));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(1, 2)));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(2, 2)));
+ }
+
+ /**
+ * @throws InvalidFileFormatException
+ * Tests if, in a 3x3 Grid with an adjacent tree, test does not assert null.
+ */
+ @Test
+ public void NoTreeForTentContradictionRule_YesTree() throws InvalidFileFormatException{
+ TestUtilities.importTestBoard("puzzles/treetent/rules/NoTreeForTentContradictionRule/NoTreeForTentYesTree", treetent);
+ TreeNode rootNode = treetent.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ TreeTentBoard board = (TreeTentBoard) transition.getBoard();
+
+ Assert.assertNotNull(RULE.checkContradiction(board));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(0, 0)));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(1, 0)));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(2, 0)));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(0, 1)));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(1, 1)));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(2, 1)));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(0, 2)));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(1, 2)));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(2, 2)));
+ }
+
+ /**
+ * @throws InvalidFileFormatException
+ * Tests if, in a 3x3 Grid with touching tents, a Tent in the center cell has no adjacent trees
+ */
+ @Test
+ public void NoTreeForTentContradictionRule_JustTent() throws InvalidFileFormatException{
+ TestUtilities.importTestBoard("puzzles/treetent/rules/NoTreeForTentContradictionRule/NoTreeForTentJustTent", treetent);
+ TreeNode rootNode = treetent.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ TreeTentBoard board = (TreeTentBoard) transition.getBoard();
+
+ Assert.assertNull(RULE.checkContradiction(board));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(0, 0)));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(1, 0)));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(2, 0)));
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(0, 1)));
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(1, 1)));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(2, 1)));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(0, 2)));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(1, 2)));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(2, 2)));
+ }
}
diff --git a/src/test/java/puzzles/treetent/rules/SurroundTentWithGrassDirectRuleTest.java b/src/test/java/puzzles/treetent/rules/SurroundTentWithGrassDirectRuleTest.java
index 14afb4dc0..999405747 100644
--- a/src/test/java/puzzles/treetent/rules/SurroundTentWithGrassDirectRuleTest.java
+++ b/src/test/java/puzzles/treetent/rules/SurroundTentWithGrassDirectRuleTest.java
@@ -27,6 +27,10 @@ public static void setUp() {
treetent = new TreeTent();
}
+ /**
+ * @throws InvalidFileFormatException
+ * Test to check if all adjacent and diagonals not filled with a tree are filled with grass
+ */
@Test
public void SurroundTentWithGrassBasicRuleTest() throws InvalidFileFormatException {
TestUtilities.importTestBoard("puzzles/treetent/rules/SurroundTentWithGrassDirectRule/SurroundTentWithGrass", treetent);
@@ -58,6 +62,90 @@ public void SurroundTentWithGrassBasicRuleTest() throws InvalidFileFormatExcepti
}
}
}
+
+ /**
+ * @throws InvalidFileFormatException
+ *
+ * Test with a 3x3 board with an absolutely empty area aside from a tent in the middle
+ * While such a situation is an illegal treetent setup, this direct rule doesn't consider that aspect, so its ok in this context
+ */
+ @Test
+ public void SurroundTentWithGrassBasicRuleTest_BadBoard() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/treetent/rules/SurroundTentWithGrassDirectRule/SurroundTentWithGrassBad", treetent);
+ TreeNode rootNode = treetent.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ TreeTentBoard board = (TreeTentBoard) transition.getBoard();
+
+ TreeTentCell cell1 = board.getCell(0, 0);
+ cell1.setData(TreeTentType.GRASS);
+ TreeTentCell cell2 = board.getCell(1, 0);
+ cell2.setData(TreeTentType.GRASS);
+ TreeTentCell cell3 = board.getCell(2, 0);
+ cell3.setData(TreeTentType.GRASS);
+ TreeTentCell cell4 = board.getCell(0, 1);
+ cell4.setData(TreeTentType.GRASS);
+ //Skip (1,1) due to being the Tent
+ TreeTentCell cell5 = board.getCell(2, 1);
+ cell5.setData(TreeTentType.GRASS);
+ TreeTentCell cell6 = board.getCell(0, 2);
+ cell6.setData(TreeTentType.GRASS);
+ TreeTentCell cell7 = board.getCell(1, 2);
+ cell7.setData(TreeTentType.GRASS);
+ TreeTentCell cell8 = board.getCell(2, 2);
+ cell8.setData(TreeTentType.GRASS);
+
+ board.addModifiedData(cell1);
+ board.addModifiedData(cell2);
+ board.addModifiedData(cell3);
+ //board.addModifiedData(cell4);
+ board.addModifiedData(cell5);
+ board.addModifiedData(cell6);
+ board.addModifiedData(cell7);
+ board.addModifiedData(cell8);
+
+ Assert.assertNull(RULE.checkRule(transition));
+
+ for (int i = 0; i < board.getHeight(); i++) {
+ for (int k = 0; k < board.getWidth(); k++) {
+ Point point = new Point(k, i);
+ if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) ||
+ point.equals(cell3.getLocation()) || //point.equals(cell4.getLocation()) ||
+ point.equals(cell5.getLocation()) || point.equals(cell6.getLocation()) ||
+ point.equals(cell7.getLocation()) || point.equals(cell8.getLocation())
+ ) {
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ }
+ else {
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ }
+ }
+ }
+ }
+
+ /**
+ * @throws InvalidFileFormatException
+ *
+ * Test to see if the rule passes even if no grass was able to be placed due to the presence of trees.
+ */
+ @Test
+ public void SurroundTentWithGrassBasicRuleTest_FullBoard() throws InvalidFileFormatException{
+ TestUtilities.importTestBoard("puzzles/treetent/rules/SurroundTentWithGrassDirectRule/SurroundTentWithGrassTrees", treetent);
+ TreeNode rootNode = treetent.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ TreeTentBoard board = (TreeTentBoard) transition.getBoard();
+
+ Assert.assertNull(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/treetent/rules/TentOrGrassCaseRuleTest.java b/src/test/java/puzzles/treetent/rules/TentOrGrassCaseRuleTest.java
new file mode 100644
index 000000000..4ec8b4e36
--- /dev/null
+++ b/src/test/java/puzzles/treetent/rules/TentOrGrassCaseRuleTest.java
@@ -0,0 +1,83 @@
+package puzzles.treetent.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.treetent.TreeTent;
+import edu.rpi.legup.puzzle.treetent.TreeTentBoard;
+import edu.rpi.legup.puzzle.treetent.TreeTentCell;
+import edu.rpi.legup.puzzle.treetent.TreeTentType;
+import edu.rpi.legup.puzzle.treetent.rules.TentOrGrassCaseRule;
+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.*;
+import java.util.ArrayList;
+
+public class TentOrGrassCaseRuleTest {
+ private static final TentOrGrassCaseRule RULE = new TentOrGrassCaseRule();
+ private static TreeTent treetent;
+
+ @BeforeClass
+ public static void setUp() {
+ MockGameBoardFacade.getInstance();
+ treetent = new TreeTent();
+ }
+
+ /**
+ * empty 3x3 TreeTent puzzle
+ * Tests TentOrGrassCaseRule on UNKOWN tile
+ * at (0,0)
+ *
+ * checks 2 cases are created
+ * checks first case is TENT tile
+ * checks second case is GRASS tile
+ * checks other cells have not been modified
+ *
+ * @throws InvalidFileFormatException
+ */
+ @Test
+ public void TentOrTreeTest() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/treetent/rules/TentOrGrassCaseRule/TestPuzzle", treetent);
+ TreeNode rootNode = treetent.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ TreeTentBoard board = (TreeTentBoard) transition.getBoard();
+ TreeTentCell testing_cell = board.getCell(0, 0);
+ ArrayList cases = RULE.getCases(board, testing_cell);
+
+ // assert correct number of cases created
+ Assert.assertEquals(2, cases.size());
+
+ // TENT case
+ TreeTentBoard tentCase = (TreeTentBoard) cases.get(0);
+ Assert.assertEquals(tentCase.getCell(0, 0).getType(), TreeTentType.TENT);
+
+ // GRASS case
+ TreeTentBoard grassCase = (TreeTentBoard) cases.get(1);
+ Assert.assertEquals(grassCase.getCell(0, 0).getType(), TreeTentType.GRASS);
+
+ // checks other cells have not been modified
+ TreeTentCell original_cell;
+ TreeTentCell case_cell;
+
+ for (int w =0; w < board.getWidth(); w++) {
+ for (int h = 0; h < board.getHeight(); h++) {
+ if (w == 0 && h ==0) {
+ continue;
+ }
+ original_cell = board.getCell(w, h);
+ case_cell = tentCase.getCell(w, h);
+ Assert.assertEquals(original_cell.getType(), case_cell.getType());
+
+ case_cell = grassCase.getCell(w, h);
+ Assert.assertEquals(original_cell.getType(), case_cell.getType());
+ }
+ }
+ }
+}
diff --git a/src/test/java/puzzles/treetent/rules/TooFewTentsContradictionRuleTest.java b/src/test/java/puzzles/treetent/rules/TooFewTentsContradictionRuleTest.java
index bfcb80a23..a5999dc6e 100644
--- a/src/test/java/puzzles/treetent/rules/TooFewTentsContradictionRuleTest.java
+++ b/src/test/java/puzzles/treetent/rules/TooFewTentsContradictionRuleTest.java
@@ -1,5 +1,6 @@
package puzzles.treetent.rules;
+import edu.rpi.legup.puzzle.treetent.TreeTentCell;
import legup.MockGameBoardFacade;
import legup.TestUtilities;
import edu.rpi.legup.model.tree.TreeNode;
@@ -10,8 +11,6 @@
import edu.rpi.legup.puzzle.treetent.TreeTent;
import edu.rpi.legup.puzzle.treetent.TreeTentBoard;
-import edu.rpi.legup.puzzle.treetent.TreeTentCell;
-import edu.rpi.legup.puzzle.treetent.TreeTentType;
import edu.rpi.legup.puzzle.treetent.rules.TooFewTentsContradictionRule;
import edu.rpi.legup.save.InvalidFileFormatException;
@@ -28,9 +27,46 @@ public static void setUp() {
treetent = new TreeTent();
}
+ /**
+ * @throws InvalidFileFormatException
+ * Using a 1x1 Puzzle Grid, which is just grass, checks if the fact it expects a tent on the y-axis is caught.
+ */
+ @Test
+ public void TooFewTentsContradictionRule_JustY() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/treetent/rules/TooFewTentsContradictionRule/TooFewTentsJustY", treetent);
+ TreeNode rootNode = treetent.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ TreeTentBoard board = (TreeTentBoard) transition.getBoard();
+ Assert.assertNull(RULE.checkContradiction(board));
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(0, 0)));
+ }
+
+ /**
+ * @throws InvalidFileFormatException
+ * Using a 1x1 Puzzle Grid, which is just a tent, checks if the fact it expects 2 tents on the y-axis is caught.
+ * (This is an impossible situation given the constraints, but for the purposes of the test it is fine)
+ */
+ @Test
+ public void TooFewTentsContradictionRule_WithTent() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/treetent/rules/TooFewTentsContradictionRule/TooFewTentsWithTent", treetent);
+ TreeNode rootNode = treetent.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ TreeTentBoard board = (TreeTentBoard) transition.getBoard();
+ Assert.assertNull(RULE.checkContradiction(board));
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(0, 0)));
+ }
+
+ /**
+ * @throws InvalidFileFormatException
+ * Using a 1x1 Puzzle Grid, which is just grass, checks if the fact it expects a tent on both x and y is caught.
+ */
@Test
- public void TooFewTentsContradictionRule_() throws InvalidFileFormatException {
- TestUtilities.importTestBoard("puzzles/treetent/rules/TooFewTentsContradictionRule/TooFewTents", treetent);
+ public void TooFewTentsContradictionRule_DoubleBad() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/treetent/rules/TooFewTentsContradictionRule/TooFewTentsDoubleBad", treetent);
TreeNode rootNode = treetent.getTree().getRootNode();
TreeTransition transition = rootNode.getChildren().get(0);
transition.setRule(RULE);
@@ -39,5 +75,177 @@ public void TooFewTentsContradictionRule_() throws InvalidFileFormatException {
Assert.assertNull(RULE.checkContradiction(board));
Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(0, 0)));
}
+
+ /**
+ * @throws InvalidFileFormatException
+ * Looks at a 2x2 Board in the format:
+ * [] Tr
+ * [] Gr
+ * Column 2 is checked to have 1 Tent (which is not present, thus producing a contradiction)
+ */
+ @Test
+ public void TooFewTentsContradictionRule_2x2ColumnOnly() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/treetent/rules/TooFewTentsContradictionRule/TooFewTents2x2Column",treetent);
+ TreeNode rootNode = treetent.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ TreeTentBoard board = (TreeTentBoard) transition.getBoard();
+
+ Assert.assertNull(RULE.checkContradiction(board));
+
+ TreeTentCell cell1 = board.getCell(1,0);
+ TreeTentCell cell2 = board.getCell(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(cell1.getLocation()) || point.equals(cell2.getLocation())) {
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ }
+ else {
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ }
+ }
+ }
+ }
+
+ /**
+ * @throws InvalidFileFormatException
+ * Looks at a 2x2 Board in the format:
+ * Tr Gr
+ * [] []
+ * Row 1 is checked to have 1 Tent (which is not present, thus producing a contradiction)
+ */
+ @Test
+ public void TooFewTentsContradictionRule_2x2RowOnly() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/treetent/rules/TooFewTentsContradictionRule/TooFewTents2x2Row",treetent);
+ TreeNode rootNode = treetent.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ TreeTentBoard board = (TreeTentBoard) transition.getBoard();
+
+ Assert.assertNull(RULE.checkContradiction(board));
+
+ TreeTentCell cell1 = board.getCell(0,0);
+ TreeTentCell cell2 = board.getCell(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(cell1.getLocation()) || point.equals(cell2.getLocation())) {
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ }
+ else {
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ }
+ }
+ }
+ }
+
+ /**
+ * @throws InvalidFileFormatException
+ * Looks at a 3x3 Board in the format:
+ * [] Tr []
+ * [] Gr []
+ * [] Gr []
+ * Column 2 is checked to have 1 Tent (which is not present, thus producing a contradiction)
+ */
+ @Test
+ public void TooFewTentsContradictionRule_3x3OneColumn() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/treetent/rules/TooFewTentsContradictionRule/TooFewTents3x3Column",treetent);
+ TreeNode rootNode = treetent.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ TreeTentBoard board = (TreeTentBoard) transition.getBoard();
+
+ Assert.assertNull(RULE.checkContradiction(board));
+
+ TreeTentCell cell1 = board.getCell(1,0);
+ TreeTentCell cell2 = board.getCell(1,1);
+ TreeTentCell cell3 = board.getCell(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(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)));
+ }
+ }
+ }
+ }
+
+ /**
+ * @throws InvalidFileFormatException
+ * Looks at a 3x3 Board in the format:
+ * Gr Tr Gr
+ * Gr [] Gr
+ * Gr Tr Gr
+ * Column 1 and 3 are checked to have 1 Tent (which is not present, thus producing a contradiction)
+ */
+ @Test
+ public void TooFewTentsContradictionRule_3x3TwoColumn() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/treetent/rules/TooFewTentsContradictionRule/TooFewTents3x3DoubleColumn",treetent);
+ TreeNode rootNode = treetent.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ TreeTentBoard board = (TreeTentBoard) transition.getBoard();
+
+ Assert.assertNull(RULE.checkContradiction(board));
+
+ TreeTentCell cell1 = board.getCell(0,0);
+ TreeTentCell cell2 = board.getCell(0,1);
+ TreeTentCell cell3 = board.getCell(0,2);
+ TreeTentCell cell4 = board.getCell(2,0);
+ TreeTentCell cell5 = board.getCell(2,1);
+ TreeTentCell cell6 = board.getCell(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(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(k, i)));
+ }
+ else {
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ }
+ }
+ }
+ }
+
+ /**
+ * @throws InvalidFileFormatException
+ * Looks at a 2x2 Board in the format:
+ * Tn []
+ * Tr []
+ * This should fail the contradiction as it is a legal board.
+ */
+ @Test
+ public void TooFewTentsContradictionRule_NoContradiction() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/treetent/rules/TooFewTentsContradictionRule/TooFewTentsNoContradiction",treetent);
+ TreeNode rootNode = treetent.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ TreeTentBoard board = (TreeTentBoard) transition.getBoard();
+
+ Assert.assertNotNull(RULE.checkContradiction(board));
+
+ 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/treetent/rules/TooManyTentsContradictionRuleTest.java b/src/test/java/puzzles/treetent/rules/TooManyTentsContradictionRuleTest.java
index 2845c7b25..2a351556b 100644
--- a/src/test/java/puzzles/treetent/rules/TooManyTentsContradictionRuleTest.java
+++ b/src/test/java/puzzles/treetent/rules/TooManyTentsContradictionRuleTest.java
@@ -28,17 +28,162 @@ public static void setUp() {
treetent = new TreeTent();
}
+ /*
+ TESTING BASIS:
+ All test in this Rule use a 3x3 table.
+ There is a Tree at (1,1)
+ There are tents at (0,1) and (2,2)
+ All Tent Counts are listed left to right or top to bottom
+ */
+
+ /**
+ * @throws InvalidFileFormatException
+ * Tests for TooManyTents if:
+ * Row Tent Counts: 0,0,0
+ * Column Tent Counts: 0,0,0
+ */
+ @Test
+ public void TooManyTentsContradictionRule_TotalFail() throws InvalidFileFormatException{
+ TestUtilities.importTestBoard("puzzles/treetent/rules/TooManyTentsContradictionRule/TooManyTentsTotalFail",treetent);
+ TreeNode rootNode = treetent.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ TreeTentBoard board = (TreeTentBoard) transition.getBoard();
+
+ TreeTentCell cell1 = board.getCell(0,1);
+
+ Assert.assertNull(RULE.checkContradiction(board));
+
+ for (int i = 0; i < board.getHeight(); i++) {
+ for (int k = 0; k < board.getWidth(); k++) {
+ Point point = new Point(k, i);
+ if (point.equals(cell1.getLocation())) {
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ }
+ else {
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ }
+ }
+ }
+ }
+
+ /**
+ * @throws InvalidFileFormatException
+ * Tests for TooManyTents if:
+ * Row Tent Counts: 1,0,0
+ * Column Tent Counts: 0,0,0
+ */
+ @Test
+ public void TooManyTentsContradictionRule_TopRight() throws InvalidFileFormatException{
+ TestUtilities.importTestBoard("puzzles/treetent/rules/TooManyTentsContradictionRule/TooManyTentsTopRight",treetent);
+ TreeNode rootNode = treetent.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ TreeTentBoard board = (TreeTentBoard) transition.getBoard();
+
+ TreeTentCell cell1 = board.getCell(0,0);
+ TreeTentCell cell2 = board.getCell(0,1);
+
+ Assert.assertNull(RULE.checkContradiction(board));
+
+ for (int i = 0; i < board.getHeight(); i++) {
+ for (int k = 0; k < board.getWidth(); k++) {
+ Point point = new Point(k, i);
+ if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) {
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ }
+ else {
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ }
+ }
+ }
+ }
+
+ /**
+ * @throws InvalidFileFormatException
+ * Tests for TooManyTests if:
+ * Row Tent Counts: 0,0,1
+ * Column Tent Counts: 0,0,0
+ */
+ @Test
+ public void TooManyTentsContradictionRule_BottomRight() throws InvalidFileFormatException{
+ TestUtilities.importTestBoard("puzzles/treetent/rules/TooManyTentsContradictionRule/TooManyTentsBottomRight",treetent);
+ TreeNode rootNode = treetent.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ TreeTentBoard board = (TreeTentBoard) transition.getBoard();
+
+ TreeTentCell cell1 = board.getCell(0,1);
+ TreeTentCell cell2 = board.getCell(0,2);
+
+ Assert.assertNull(RULE.checkContradiction(board));
+
+ for (int i = 0; i < board.getHeight(); i++) {
+ for (int k = 0; k < board.getWidth(); k++) {
+ Point point = new Point(k, i);
+ if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) {
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ }
+ else {
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ }
+ }
+ }
+ }
+
+ /**
+ * @throws InvalidFileFormatException
+ * Tests for TooManyTents if:
+ * Row Tent Counts: 0,0,0
+ * Column Tent Counts: 0,1,0
+ */
+ @Test
+ public void TooManyTentsContradictionRule_TopDown() throws InvalidFileFormatException{
+ TestUtilities.importTestBoard("puzzles/treetent/rules/TooManyTentsContradictionRule/TooManyTentsTopDown",treetent);
+ TreeNode rootNode = treetent.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ TreeTentBoard board = (TreeTentBoard) transition.getBoard();
+
+ TreeTentCell cell1 = board.getCell(0,1);
+ TreeTentCell cell2 = board.getCell(1,1);
+
+ Assert.assertNull(RULE.checkContradiction(board));
+
+ for (int i = 0; i < board.getHeight(); i++) {
+ for (int k = 0; k < board.getWidth(); k++) {
+ Point point = new Point(k, i);
+ if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) {
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ }
+ else {
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ }
+ }
+ }
+ }
+
+ /**
+ * @throws InvalidFileFormatException
+ * Tests for TooManyTents if:
+ * Row Tent Counts: 0,0,0
+ * Column Tent Counts: 0,0,1
+ */
@Test
- public void TooManyTentsContradictionRule_Column_Row() throws InvalidFileFormatException {
- TestUtilities.importTestBoard("puzzles/treetent/rules/TooManyTentsContradictionRule/TooManyTentsContradictionRuleColumn_Row", treetent);
+ public void TooManyTentsContradictionRule_BottomDown() throws InvalidFileFormatException{
+ TestUtilities.importTestBoard("puzzles/treetent/rules/TooManyTentsContradictionRule/TooManyTentsBottomDown",treetent);
TreeNode rootNode = treetent.getTree().getRootNode();
TreeTransition transition = rootNode.getChildren().get(0);
transition.setRule(RULE);
TreeTentBoard board = (TreeTentBoard) transition.getBoard();
- TreeTentCell cell1 = board.getCell(0, 1);
- TreeTentCell cell2 = board.getCell(2, 1);
+ TreeTentCell cell1 = board.getCell(0,1);
+ TreeTentCell cell2 = board.getCell(2,1);
Assert.assertNull(RULE.checkContradiction(board));
@@ -49,9 +194,78 @@ public void TooManyTentsContradictionRule_Column_Row() throws InvalidFileFormatE
Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
}
else {
- // The TooManyTentsContradictionRule checks the col and row the cell is in
- // Therefore, even if a cell(0, 0) is empty, it follows the contradiction rule because
- // the row it is in follows the contradiciton rule. (And because cell(1, 0) has tent row tent total is 0)
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ }
+ }
+ }
+ }
+
+ /**
+ * @throws InvalidFileFormatException
+ * Tests for TooManyTents if the Top Tent is completely accounted for, but not the bottom
+ * Row Tent Counts: 1,0,0
+ * Column Tent Counts: 0,1,0
+ */
+ @Test
+ public void TooManyTentsContradictionRule_TopAccount() throws InvalidFileFormatException{
+ TestUtilities.importTestBoard("puzzles/treetent/rules/TooManyTentsContradictionRule/TooManyTentsTopAccount",treetent);
+ TreeNode rootNode = treetent.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ TreeTentBoard board = (TreeTentBoard) transition.getBoard();
+
+ TreeTentCell cell1 = board.getCell(0,0);
+ TreeTentCell cell2 = board.getCell(1,0);
+ TreeTentCell cell3 = board.getCell(0,1);
+ TreeTentCell cell4 = board.getCell(1,1);
+
+ Assert.assertNull(RULE.checkContradiction(board));
+
+ for (int i = 0; i < board.getHeight(); i++) {
+ for (int k = 0; k < board.getWidth(); k++) {
+ Point point = new Point(k, i);
+ if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) ||
+ point.equals(cell3.getLocation()) || point.equals(cell4.getLocation())) {
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ }
+ else {
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ }
+ }
+ }
+ }
+
+ /**
+ * @throws InvalidFileFormatException
+ * Tests for TooManyTents if the Bottom Tent is completely accounted for, but not the Top
+ * Row Tent Counts: 0,0,1
+ * Column Tent Counts: 0,0,1
+ */
+ @Test
+ public void TooManyTentsContradictionRule_BottomAccount() throws InvalidFileFormatException{
+ TestUtilities.importTestBoard("puzzles/treetent/rules/TooManyTentsContradictionRule/TooManyTentsBottomAccount",treetent);
+ TreeNode rootNode = treetent.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ TreeTentBoard board = (TreeTentBoard) transition.getBoard();
+
+ TreeTentCell cell1 = board.getCell(0,1);
+ TreeTentCell cell2 = board.getCell(2,1);
+ TreeTentCell cell3 = board.getCell(0,2);
+ TreeTentCell cell4 = board.getCell(2,2);
+
+ Assert.assertNull(RULE.checkContradiction(board));
+
+ for (int i = 0; i < board.getHeight(); i++) {
+ for (int k = 0; k < board.getWidth(); k++) {
+ Point point = new Point(k, i);
+ if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) ||
+ point.equals(cell3.getLocation()) || point.equals(cell4.getLocation())) {
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
+ }
+ else {
Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i)));
}
}
diff --git a/src/test/java/puzzles/treetent/rules/TouchingTentsContradictionRuleTest.java b/src/test/java/puzzles/treetent/rules/TouchingTentsContradictionRuleTest.java
index 79fc70118..f48afe5d7 100644
--- a/src/test/java/puzzles/treetent/rules/TouchingTentsContradictionRuleTest.java
+++ b/src/test/java/puzzles/treetent/rules/TouchingTentsContradictionRuleTest.java
@@ -10,13 +10,9 @@
import edu.rpi.legup.puzzle.treetent.TreeTent;
import edu.rpi.legup.puzzle.treetent.TreeTentBoard;
-import edu.rpi.legup.puzzle.treetent.TreeTentCell;
-import edu.rpi.legup.puzzle.treetent.TreeTentType;
import edu.rpi.legup.puzzle.treetent.rules.TouchingTentsContradictionRule;
import edu.rpi.legup.save.InvalidFileFormatException;
-import java.awt.*;
-
public class TouchingTentsContradictionRuleTest {
private static final TouchingTentsContradictionRule RULE = new TouchingTentsContradictionRule();
@@ -28,8 +24,14 @@ public static void setUp() {
treetent = new TreeTent();
}
+ //DIAGONAL TESTS
+ /**
+ * @throws InvalidFileFormatException
+ * Tests a tent diagonal of orientation T
+ * T
+ **/
@Test
- public void TouchingTentsContradictionRule_Diagonal() throws InvalidFileFormatException {
+ public void TouchingTentsContradictionRule_DiagonalUpLeftToDownRight() throws InvalidFileFormatException {
TestUtilities.importTestBoard("puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsDiagonal", treetent);
TreeNode rootNode = treetent.getTree().getRootNode();
TreeTransition transition = rootNode.getChildren().get(0);
@@ -44,8 +46,35 @@ public void TouchingTentsContradictionRule_Diagonal() throws InvalidFileFormatEx
Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(1, 0)));
}
+ /**
+ * @throws InvalidFileFormatException
+ * Tests a tent diagonal of orientation T
+ * T
+ **/
@Test
- public void TouchingTentsContradictionRule_Adjacent() throws InvalidFileFormatException {
+ public void TouchingTentsContradictionRule_DiagonalDownLeftToUpRight() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsDiagonalAlt",treetent);
+ TreeNode rootNode = treetent.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ TreeTentBoard board = (TreeTentBoard) transition.getBoard();
+
+ Assert.assertNull(RULE.checkContradiction(board));
+ Assert.assertNull(RULE.checkRuleAt(transition,board.getCell(1,0)));
+ Assert.assertNull(RULE.checkRuleAt(transition,board.getCell(0,1)));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(0, 0)));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(1, 1)));
+ }
+
+ //ADJACENT TESTS
+ /**
+ * @throws InvalidFileFormatException
+ * Tests a tent adjacent of orientation T
+ * T
+ **/
+ @Test
+ public void TouchingTentsContradictionRule_AdjacentVertical() throws InvalidFileFormatException {
TestUtilities.importTestBoard("puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsAdjacent", treetent);
TreeNode rootNode = treetent.getTree().getRootNode();
TreeTransition transition = rootNode.getChildren().get(0);
@@ -59,6 +88,162 @@ public void TouchingTentsContradictionRule_Adjacent() throws InvalidFileFormatEx
Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(1, 0)));
Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(1, 1)));
}
+
+ /**
+ * @throws InvalidFileFormatException
+ * Tests a tent adjacent of orientation TT
+ **/
+ @Test
+ public void TouchingTentsContradictionRule_AdjacentHorizontal() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsAdjacentAlt", treetent);
+ TreeNode rootNode = treetent.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ TreeTentBoard board = (TreeTentBoard) transition.getBoard();
+
+ Assert.assertNull(RULE.checkContradiction(board));
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(0, 0)));
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(1, 0)));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(0, 1)));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(1, 1)));
+ }
+ //MIXED TESTS
+ /**
+ * @throws InvalidFileFormatException
+ * Tests a tent of orientation TT
+ * TT
+ **/
+ @Test
+ public void TouchingTentsContradictionRule_2By2Square() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsFull2By2",treetent);
+ TreeNode rootNode = treetent.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ TreeTentBoard board = (TreeTentBoard) transition.getBoard();
+
+ Assert.assertNull(RULE.checkContradiction(board));
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(0, 0)));
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(0, 1)));
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(1, 0)));
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(1, 1)));
+ }
+ /**
+ * @throws InvalidFileFormatException
+ * Tests a tent of orientation TT
+ * T
+ **/
+ @Test
+ public void TouchingTentsContradictionRule_UpLeft() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsMixedUpLeft",treetent);
+ TreeNode rootNode = treetent.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ TreeTentBoard board = (TreeTentBoard) transition.getBoard();
+
+ Assert.assertNull(RULE.checkContradiction(board));
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(0, 0)));
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(0, 1)));
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(1, 0)));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(1, 1)));
+ }
+ /**
+ * @throws InvalidFileFormatException
+ * Tests a tent of orientation TT
+ * T
+ **/
+ @Test
+ public void TouchingTentsContradictionRule_UpRight() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsMixedUpRight",treetent);
+ TreeNode rootNode = treetent.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ TreeTentBoard board = (TreeTentBoard) transition.getBoard();
+
+ Assert.assertNull(RULE.checkContradiction(board));
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(0, 0)));
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(0, 1)));
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(1, 1)));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(1, 0)));
+ }
+ /**
+ * @throws InvalidFileFormatException
+ * Tests a tent of orientation T
+ * TT
+ **/
+ @Test
+ public void TouchingTentsContradictionRule_DownLeft() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsMixedDownLeft",treetent);
+ TreeNode rootNode = treetent.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ TreeTentBoard board = (TreeTentBoard) transition.getBoard();
+
+ Assert.assertNull(RULE.checkContradiction(board));
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(0, 0)));
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(1, 0)));
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(1, 1)));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(0, 1)));
+ }
+ /**
+ * @throws InvalidFileFormatException
+ * Tests a tent of orientation T
+ * TT
+ **/
+ @Test
+ public void TouchingTentsContradictionRule_DownRight() throws InvalidFileFormatException {
+ TestUtilities.importTestBoard("puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsMixedDownRight",treetent);
+ TreeNode rootNode = treetent.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ TreeTentBoard board = (TreeTentBoard) transition.getBoard();
+
+ Assert.assertNull(RULE.checkContradiction(board));
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(0, 1)));
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(1, 0)));
+ Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(1, 1)));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(0, 0)));
+ }
+ /**
+ * @throws InvalidFileFormatException
+ * Tests if tree adjacent triggers a null
+ */
+ @Test
+ public void TouchingTentsContradictionRule_TreeAdjacent() throws InvalidFileFormatException{
+ TestUtilities.importTestBoard("puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsTreeAdjacent",treetent);
+ TreeNode rootNode = treetent.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ TreeTentBoard board = (TreeTentBoard) transition.getBoard();
+
+ Assert.assertNotNull(RULE.checkContradiction(board));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(0, 0)));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(0, 1)));
+ }
+ /**
+ * @throws InvalidFileFormatException
+ * Tests if tree diagonal triggers a null
+ */
+ @Test
+ public void TouchingTentsContradictionRule_TreeDiagonal() throws InvalidFileFormatException{
+ TestUtilities.importTestBoard("puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsTreeDiagonal",treetent);
+ TreeNode rootNode = treetent.getTree().getRootNode();
+ TreeTransition transition = rootNode.getChildren().get(0);
+ transition.setRule(RULE);
+
+ TreeTentBoard board = (TreeTentBoard) transition.getBoard();
+
+ Assert.assertNotNull(RULE.checkContradiction(board));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(0, 0)));
+ Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(1, 0)));
+ }
+
}
diff --git a/build/resources/test/puzzles/lightup/rules/BulbsInPathContradictionRule/LightInHorizontalPath b/src/test/resources/puzzles/lightup/rules/BulbsInPathContradictionRule/BlockInHorizontalPath
similarity index 84%
rename from build/resources/test/puzzles/lightup/rules/BulbsInPathContradictionRule/LightInHorizontalPath
rename to src/test/resources/puzzles/lightup/rules/BulbsInPathContradictionRule/BlockInHorizontalPath
index 633ccc80b..3c8786e54 100644
--- a/build/resources/test/puzzles/lightup/rules/BulbsInPathContradictionRule/LightInHorizontalPath
+++ b/src/test/resources/puzzles/lightup/rules/BulbsInPathContradictionRule/BlockInHorizontalPath
@@ -1,10 +1,11 @@
-
-
-
-
- |
- |
-
-
-
+
+
+
+
+ |
+ |
+ |
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/lightup/rules/CannotLightACellContradictionRule/CanLightTest b/src/test/resources/puzzles/lightup/rules/CannotLightACellContradictionRule/CanLightTest
new file mode 100644
index 000000000..4169bf382
--- /dev/null
+++ b/src/test/resources/puzzles/lightup/rules/CannotLightACellContradictionRule/CanLightTest
@@ -0,0 +1,18 @@
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/lightup/rules/EmptyCellinLightDirectRule/EmptyCells b/src/test/resources/puzzles/lightup/rules/EmptyCellinLightDirectRule/EmptyCells
index feca5b861..d6fba5369 100644
--- a/src/test/resources/puzzles/lightup/rules/EmptyCellinLightDirectRule/EmptyCells
+++ b/src/test/resources/puzzles/lightup/rules/EmptyCellinLightDirectRule/EmptyCells
@@ -1,6 +1,6 @@
-
+
|
|
diff --git a/src/test/resources/puzzles/nurikabe/rules/BlackBetweenRegionsDirectRule/FalseBlackBetweenRegions b/src/test/resources/puzzles/nurikabe/rules/BlackBetweenRegionsDirectRule/FalseBlackBetweenRegions
new file mode 100644
index 000000000..5aecd1575
--- /dev/null
+++ b/src/test/resources/puzzles/nurikabe/rules/BlackBetweenRegionsDirectRule/FalseBlackBetweenRegions
@@ -0,0 +1,13 @@
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/nurikabe/rules/BlackBottleNeckDirectRule/CornerBottleNeck b/src/test/resources/puzzles/nurikabe/rules/BlackBottleNeckDirectRule/CornerBottleNeck
new file mode 100644
index 000000000..77f38d5d4
--- /dev/null
+++ b/src/test/resources/puzzles/nurikabe/rules/BlackBottleNeckDirectRule/CornerBottleNeck
@@ -0,0 +1,11 @@
+
+
+
+
+ |
+ |
+ |
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/nurikabe/rules/BlackBottleNeckDirectRule/FalseBottleNeck b/src/test/resources/puzzles/nurikabe/rules/BlackBottleNeckDirectRule/FalseBottleNeck
new file mode 100644
index 000000000..3e3d7610a
--- /dev/null
+++ b/src/test/resources/puzzles/nurikabe/rules/BlackBottleNeckDirectRule/FalseBottleNeck
@@ -0,0 +1,11 @@
+
+
+
+
+ |
+ |
+ |
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/nurikabe/rules/BlackOrWhiteCaseRule/SimpleBlackOrWhite b/src/test/resources/puzzles/nurikabe/rules/BlackOrWhiteCaseRule/SimpleBlackOrWhite
new file mode 100644
index 000000000..fb5e45218
--- /dev/null
+++ b/src/test/resources/puzzles/nurikabe/rules/BlackOrWhiteCaseRule/SimpleBlackOrWhite
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/nurikabe/rules/BlackSquareContradictionRule/CornerBlackSquare b/src/test/resources/puzzles/nurikabe/rules/BlackSquareContradictionRule/CornerBlackSquare
new file mode 100644
index 000000000..98a01d8b5
--- /dev/null
+++ b/src/test/resources/puzzles/nurikabe/rules/BlackSquareContradictionRule/CornerBlackSquare
@@ -0,0 +1,12 @@
+
+
+
+
+ |
+ |
+ |
+ |
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/nurikabe/rules/BlackSquareContradictionRule/FalseBlackSquare b/src/test/resources/puzzles/nurikabe/rules/BlackSquareContradictionRule/FalseBlackSquare
new file mode 100644
index 000000000..813114443
--- /dev/null
+++ b/src/test/resources/puzzles/nurikabe/rules/BlackSquareContradictionRule/FalseBlackSquare
@@ -0,0 +1,11 @@
+
+
+
+
+ |
+ |
+ |
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/nurikabe/rules/CannotReachCellDirectRule/AllCellsReachable b/src/test/resources/puzzles/nurikabe/rules/CannotReachCellDirectRule/AllCellsReachable
new file mode 100644
index 000000000..63e38d25f
--- /dev/null
+++ b/src/test/resources/puzzles/nurikabe/rules/CannotReachCellDirectRule/AllCellsReachable
@@ -0,0 +1,11 @@
+
+
+
+
+ |
+ |
+ |
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/nurikabe/rules/CannotReachCellDirectRule/SimpleUnreachableCell b/src/test/resources/puzzles/nurikabe/rules/CannotReachCellDirectRule/SimpleUnreachableCell
new file mode 100644
index 000000000..e11487564
--- /dev/null
+++ b/src/test/resources/puzzles/nurikabe/rules/CannotReachCellDirectRule/SimpleUnreachableCell
@@ -0,0 +1,9 @@
+
+
+
+
+ |
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/nurikabe/rules/CornerBlackDirectRule/FalseCornerBlack b/src/test/resources/puzzles/nurikabe/rules/CornerBlackDirectRule/FalseCornerBlack
new file mode 100644
index 000000000..0599fdfa4
--- /dev/null
+++ b/src/test/resources/puzzles/nurikabe/rules/CornerBlackDirectRule/FalseCornerBlack
@@ -0,0 +1,12 @@
+
+
+
+
+ |
+ |
+ |
+ |
+
+
+
+
\ No newline at end of file
diff --git a/build/resources/test/puzzles/lightup/rules/BulbsInPathContradictionRule/BlockInVerticalPath b/src/test/resources/puzzles/nurikabe/rules/FillinBlackDirectRule/CornerBlack1
similarity index 58%
rename from build/resources/test/puzzles/lightup/rules/BulbsInPathContradictionRule/BlockInVerticalPath
rename to src/test/resources/puzzles/nurikabe/rules/FillinBlackDirectRule/CornerBlack1
index 5f27b3ec8..ae078229e 100644
--- a/build/resources/test/puzzles/lightup/rules/BulbsInPathContradictionRule/BlockInVerticalPath
+++ b/src/test/resources/puzzles/nurikabe/rules/FillinBlackDirectRule/CornerBlack1
@@ -1,10 +1,9 @@
-
+
- |
+ |
|
- |
diff --git a/src/test/resources/puzzles/nurikabe/rules/FillinBlackDirectRule/CornerBlack2 b/src/test/resources/puzzles/nurikabe/rules/FillinBlackDirectRule/CornerBlack2
new file mode 100644
index 000000000..f274fc774
--- /dev/null
+++ b/src/test/resources/puzzles/nurikabe/rules/FillinBlackDirectRule/CornerBlack2
@@ -0,0 +1,10 @@
+
+
+
+
+ |
+ |
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/nurikabe/rules/FillinBlackDirectRule/FalseFillinBlack b/src/test/resources/puzzles/nurikabe/rules/FillinBlackDirectRule/FalseFillinBlack
new file mode 100644
index 000000000..731e2dc74
--- /dev/null
+++ b/src/test/resources/puzzles/nurikabe/rules/FillinBlackDirectRule/FalseFillinBlack
@@ -0,0 +1,12 @@
+
+
+
+
+ |
+ |
+ |
+ |
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/nurikabe/rules/FillinWhiteDirectRule/CornerWhite1 b/src/test/resources/puzzles/nurikabe/rules/FillinWhiteDirectRule/CornerWhite1
new file mode 100644
index 000000000..de0ca4f71
--- /dev/null
+++ b/src/test/resources/puzzles/nurikabe/rules/FillinWhiteDirectRule/CornerWhite1
@@ -0,0 +1,11 @@
+
+
+
+
+ |
+ |
+ |
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/nurikabe/rules/FillinWhiteDirectRule/CornerWhite2 b/src/test/resources/puzzles/nurikabe/rules/FillinWhiteDirectRule/CornerWhite2
new file mode 100644
index 000000000..9fc228483
--- /dev/null
+++ b/src/test/resources/puzzles/nurikabe/rules/FillinWhiteDirectRule/CornerWhite2
@@ -0,0 +1,11 @@
+
+
+
+
+ |
+ |
+ |
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/nurikabe/rules/FillinWhiteDirectRule/FalseFillinWhite b/src/test/resources/puzzles/nurikabe/rules/FillinWhiteDirectRule/FalseFillinWhite
new file mode 100644
index 000000000..f2599c71f
--- /dev/null
+++ b/src/test/resources/puzzles/nurikabe/rules/FillinWhiteDirectRule/FalseFillinWhite
@@ -0,0 +1,12 @@
+
+
+
+
+ |
+ |
+ |
+ |
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/nurikabe/rules/IsolateBlackContradictionRule/DiagonalIsolateBlack b/src/test/resources/puzzles/nurikabe/rules/IsolateBlackContradictionRule/DiagonalIsolateBlack
new file mode 100644
index 000000000..7ff5dcf24
--- /dev/null
+++ b/src/test/resources/puzzles/nurikabe/rules/IsolateBlackContradictionRule/DiagonalIsolateBlack
@@ -0,0 +1,15 @@
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/nurikabe/rules/IsolateBlackContradictionRule/FalseIsolateBlack b/src/test/resources/puzzles/nurikabe/rules/IsolateBlackContradictionRule/FalseIsolateBlack
new file mode 100644
index 000000000..b4eb09302
--- /dev/null
+++ b/src/test/resources/puzzles/nurikabe/rules/IsolateBlackContradictionRule/FalseIsolateBlack
@@ -0,0 +1,10 @@
+
+
+
+
+ |
+ |
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/nurikabe/rules/MultipleNumbersContradictionRule/ComplexRegion b/src/test/resources/puzzles/nurikabe/rules/MultipleNumbersContradictionRule/ComplexRegion
new file mode 100644
index 000000000..5f8e607fe
--- /dev/null
+++ b/src/test/resources/puzzles/nurikabe/rules/MultipleNumbersContradictionRule/ComplexRegion
@@ -0,0 +1,19 @@
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/nurikabe/rules/MultipleNumbersContradictionRule/FalseContradiction b/src/test/resources/puzzles/nurikabe/rules/MultipleNumbersContradictionRule/FalseContradiction
new file mode 100644
index 000000000..0f14d6916
--- /dev/null
+++ b/src/test/resources/puzzles/nurikabe/rules/MultipleNumbersContradictionRule/FalseContradiction
@@ -0,0 +1,16 @@
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/nurikabe/rules/NoNumberContradictionRule/NoNumberReachable b/src/test/resources/puzzles/nurikabe/rules/NoNumberContradictionRule/FalseNoNumber
similarity index 100%
rename from src/test/resources/puzzles/nurikabe/rules/NoNumberContradictionRule/NoNumberReachable
rename to src/test/resources/puzzles/nurikabe/rules/NoNumberContradictionRule/FalseNoNumber
diff --git a/src/test/resources/puzzles/nurikabe/rules/NoNumberContradictionRule/FalseNoNumber2 b/src/test/resources/puzzles/nurikabe/rules/NoNumberContradictionRule/FalseNoNumber2
new file mode 100644
index 000000000..be1fc64f7
--- /dev/null
+++ b/src/test/resources/puzzles/nurikabe/rules/NoNumberContradictionRule/FalseNoNumber2
@@ -0,0 +1,18 @@
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/nurikabe/rules/NoNumberContradictionRule/NoNumberSurroundBlack b/src/test/resources/puzzles/nurikabe/rules/NoNumberContradictionRule/SimpleNoNumber
similarity index 100%
rename from src/test/resources/puzzles/nurikabe/rules/NoNumberContradictionRule/NoNumberSurroundBlack
rename to src/test/resources/puzzles/nurikabe/rules/NoNumberContradictionRule/SimpleNoNumber
diff --git a/src/test/resources/puzzles/nurikabe/rules/PreventBlackSquareDirectRule/FalseBlackSquare b/src/test/resources/puzzles/nurikabe/rules/PreventBlackSquareDirectRule/FalseBlackSquare
new file mode 100644
index 000000000..2fd8e7d35
--- /dev/null
+++ b/src/test/resources/puzzles/nurikabe/rules/PreventBlackSquareDirectRule/FalseBlackSquare
@@ -0,0 +1,10 @@
+
+
+
+
+ |
+ |
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/nurikabe/rules/SurroundRegionDirectRule/FalseSurroundRegion b/src/test/resources/puzzles/nurikabe/rules/SurroundRegionDirectRule/FalseSurroundRegion
new file mode 100644
index 000000000..5e0b04f68
--- /dev/null
+++ b/src/test/resources/puzzles/nurikabe/rules/SurroundRegionDirectRule/FalseSurroundRegion
@@ -0,0 +1,10 @@
+
+
+
+
+ |
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/nurikabe/rules/TooFewSpacesContradictionRule/FalseTooFewSpaces b/src/test/resources/puzzles/nurikabe/rules/TooFewSpacesContradictionRule/FalseTooFewSpaces
new file mode 100644
index 000000000..ca3e9be84
--- /dev/null
+++ b/src/test/resources/puzzles/nurikabe/rules/TooFewSpacesContradictionRule/FalseTooFewSpaces
@@ -0,0 +1,17 @@
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/nurikabe/rules/TooFewSpacesContradictionRule/InsufficientSpace b/src/test/resources/puzzles/nurikabe/rules/TooFewSpacesContradictionRule/InsufficientSpace
new file mode 100644
index 000000000..22163947a
--- /dev/null
+++ b/src/test/resources/puzzles/nurikabe/rules/TooFewSpacesContradictionRule/InsufficientSpace
@@ -0,0 +1,17 @@
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/nurikabe/rules/TooManySpacesContradictionRule/ExtraDiagonalSpace b/src/test/resources/puzzles/nurikabe/rules/TooManySpacesContradictionRule/ExtraDiagonalSpace
new file mode 100644
index 000000000..5d9ad70e1
--- /dev/null
+++ b/src/test/resources/puzzles/nurikabe/rules/TooManySpacesContradictionRule/ExtraDiagonalSpace
@@ -0,0 +1,14 @@
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/nurikabe/rules/TooManySpacesContradictionRule/MultipleNumberRegion b/src/test/resources/puzzles/nurikabe/rules/TooManySpacesContradictionRule/MultipleNumberRegion
new file mode 100644
index 000000000..3ec126199
--- /dev/null
+++ b/src/test/resources/puzzles/nurikabe/rules/TooManySpacesContradictionRule/MultipleNumberRegion
@@ -0,0 +1,11 @@
+
+
+
+
+ |
+ |
+ |
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/nurikabe/rules/UnreachableWhiteCellContradictionRule/AllCellsReachable b/src/test/resources/puzzles/nurikabe/rules/UnreachableWhiteCellContradictionRule/AllCellsReachable
new file mode 100644
index 000000000..dbc5fadb2
--- /dev/null
+++ b/src/test/resources/puzzles/nurikabe/rules/UnreachableWhiteCellContradictionRule/AllCellsReachable
@@ -0,0 +1,13 @@
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/nurikabe/rules/UnreachableWhiteCellContradictionRule/SimpleUnreachableTest b/src/test/resources/puzzles/nurikabe/rules/UnreachableWhiteCellContradictionRule/SimpleUnreachableTest
new file mode 100644
index 000000000..3d456bdb0
--- /dev/null
+++ b/src/test/resources/puzzles/nurikabe/rules/UnreachableWhiteCellContradictionRule/SimpleUnreachableTest
@@ -0,0 +1,10 @@
+
+
+
+
+ |
+ |
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/nurikabe/rules/WhiteBottleNeckDirectRule/FalseBottleNeck b/src/test/resources/puzzles/nurikabe/rules/WhiteBottleNeckDirectRule/FalseBottleNeck
new file mode 100644
index 000000000..521576aeb
--- /dev/null
+++ b/src/test/resources/puzzles/nurikabe/rules/WhiteBottleNeckDirectRule/FalseBottleNeck
@@ -0,0 +1,11 @@
+
+
+
+
+ |
+ |
+ |
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/AndCaseRule/ComplexStatement1_False b/src/test/resources/puzzles/shorttruthtable/rules/AndCaseRule/ComplexStatement1_False
new file mode 100644
index 000000000..f7e5824ff
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/AndCaseRule/ComplexStatement1_False
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/AndCaseRule/ComplexStatement1_True b/src/test/resources/puzzles/shorttruthtable/rules/AndCaseRule/ComplexStatement1_True
new file mode 100644
index 000000000..46dd5e603
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/AndCaseRule/ComplexStatement1_True
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/AndCaseRule/SimpleStatement1_False b/src/test/resources/puzzles/shorttruthtable/rules/AndCaseRule/SimpleStatement1_False
new file mode 100644
index 000000000..aa3ed2b55
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/AndCaseRule/SimpleStatement1_False
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/AndCaseRule/SimpleStatement1_True b/src/test/resources/puzzles/shorttruthtable/rules/AndCaseRule/SimpleStatement1_True
new file mode 100644
index 000000000..881a1063e
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/AndCaseRule/SimpleStatement1_True
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/AndEliminationDirectRule/FalseAnd b/src/test/resources/puzzles/shorttruthtable/rules/AndEliminationDirectRule/FalseAnd
new file mode 100644
index 000000000..f6f60abc3
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/AndEliminationDirectRule/FalseAnd
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/AndEliminationDirectRule/FalseAndWithKnownFalse b/src/test/resources/puzzles/shorttruthtable/rules/AndEliminationDirectRule/FalseAndWithKnownFalse
new file mode 100644
index 000000000..d8edf4a76
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/AndEliminationDirectRule/FalseAndWithKnownFalse
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/AndEliminationDirectRule/FalseAndWithKnownTrue b/src/test/resources/puzzles/shorttruthtable/rules/AndEliminationDirectRule/FalseAndWithKnownTrue
new file mode 100644
index 000000000..364d8faf6
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/AndEliminationDirectRule/FalseAndWithKnownTrue
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/AndEliminationDirectRule/TrueAnd b/src/test/resources/puzzles/shorttruthtable/rules/AndEliminationDirectRule/TrueAnd
new file mode 100644
index 000000000..307f6d14a
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/AndEliminationDirectRule/TrueAnd
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/AndIntroductionDirectRule/FUF b/src/test/resources/puzzles/shorttruthtable/rules/AndIntroductionDirectRule/FUF
new file mode 100644
index 000000000..003792ec0
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/AndIntroductionDirectRule/FUF
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/AndIntroductionDirectRule/FUT b/src/test/resources/puzzles/shorttruthtable/rules/AndIntroductionDirectRule/FUT
new file mode 100644
index 000000000..05803b88d
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/AndIntroductionDirectRule/FUT
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/AndIntroductionDirectRule/FUU b/src/test/resources/puzzles/shorttruthtable/rules/AndIntroductionDirectRule/FUU
new file mode 100644
index 000000000..b97eafdfe
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/AndIntroductionDirectRule/FUU
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/AndIntroductionDirectRule/TUF b/src/test/resources/puzzles/shorttruthtable/rules/AndIntroductionDirectRule/TUF
new file mode 100644
index 000000000..fc10f77bb
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/AndIntroductionDirectRule/TUF
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/AndIntroductionDirectRule/TUT b/src/test/resources/puzzles/shorttruthtable/rules/AndIntroductionDirectRule/TUT
new file mode 100644
index 000000000..dc99e3cdc
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/AndIntroductionDirectRule/TUT
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/AndIntroductionDirectRule/TUU b/src/test/resources/puzzles/shorttruthtable/rules/AndIntroductionDirectRule/TUU
new file mode 100644
index 000000000..2c592ef86
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/AndIntroductionDirectRule/TUU
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/AndIntroductionDirectRule/UUF b/src/test/resources/puzzles/shorttruthtable/rules/AndIntroductionDirectRule/UUF
new file mode 100644
index 000000000..39b5fb079
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/AndIntroductionDirectRule/UUF
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/AndIntroductionDirectRule/UUT b/src/test/resources/puzzles/shorttruthtable/rules/AndIntroductionDirectRule/UUT
new file mode 100644
index 000000000..261c035cd
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/AndIntroductionDirectRule/UUT
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/AndIntroductionDirectRule/UUU b/src/test/resources/puzzles/shorttruthtable/rules/AndIntroductionDirectRule/UUU
new file mode 100644
index 000000000..d9f415439
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/AndIntroductionDirectRule/UUU
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/AtomicDirectRule/Empty b/src/test/resources/puzzles/shorttruthtable/rules/AtomicDirectRule/Empty
new file mode 100644
index 000000000..6a6effadf
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/AtomicDirectRule/Empty
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/AtomicDirectRule/FalseA b/src/test/resources/puzzles/shorttruthtable/rules/AtomicDirectRule/FalseA
new file mode 100644
index 000000000..8c5ddc7b9
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/AtomicDirectRule/FalseA
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/AtomicDirectRule/TrueB b/src/test/resources/puzzles/shorttruthtable/rules/AtomicDirectRule/TrueB
new file mode 100644
index 000000000..46a1beb2d
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/AtomicDirectRule/TrueB
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalEliminationDirectRule/FalseBiconditional b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalEliminationDirectRule/FalseBiconditional
new file mode 100644
index 000000000..5ea1c8a63
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalEliminationDirectRule/FalseBiconditional
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalEliminationDirectRule/FalseBiconditionalWithFalseA b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalEliminationDirectRule/FalseBiconditionalWithFalseA
new file mode 100644
index 000000000..1f956a743
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalEliminationDirectRule/FalseBiconditionalWithFalseA
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalEliminationDirectRule/FalseBiconditionalWithFalseB b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalEliminationDirectRule/FalseBiconditionalWithFalseB
new file mode 100644
index 000000000..49fd4f49f
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalEliminationDirectRule/FalseBiconditionalWithFalseB
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalEliminationDirectRule/FalseBiconditionalWithTrueA b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalEliminationDirectRule/FalseBiconditionalWithTrueA
new file mode 100644
index 000000000..000a07d91
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalEliminationDirectRule/FalseBiconditionalWithTrueA
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalEliminationDirectRule/FalseBiconditionalWithTrueB b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalEliminationDirectRule/FalseBiconditionalWithTrueB
new file mode 100644
index 000000000..18cbd4156
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalEliminationDirectRule/FalseBiconditionalWithTrueB
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalEliminationDirectRule/TrueBiconditional b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalEliminationDirectRule/TrueBiconditional
new file mode 100644
index 000000000..cbf64468f
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalEliminationDirectRule/TrueBiconditional
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalEliminationDirectRule/TrueBiconditionalWithFalseA b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalEliminationDirectRule/TrueBiconditionalWithFalseA
new file mode 100644
index 000000000..9655bc7ae
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalEliminationDirectRule/TrueBiconditionalWithFalseA
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalEliminationDirectRule/TrueBiconditionalWithFalseB b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalEliminationDirectRule/TrueBiconditionalWithFalseB
new file mode 100644
index 000000000..032fc23df
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalEliminationDirectRule/TrueBiconditionalWithFalseB
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalEliminationDirectRule/TrueBiconditionalWithTrueA b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalEliminationDirectRule/TrueBiconditionalWithTrueA
new file mode 100644
index 000000000..44381c235
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalEliminationDirectRule/TrueBiconditionalWithTrueA
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalEliminationDirectRule/TrueBiconditionalWithTrueB b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalEliminationDirectRule/TrueBiconditionalWithTrueB
new file mode 100644
index 000000000..8e42c0032
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalEliminationDirectRule/TrueBiconditionalWithTrueB
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalIntroductionDirectRule/FUF b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalIntroductionDirectRule/FUF
new file mode 100644
index 000000000..817025f78
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalIntroductionDirectRule/FUF
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalIntroductionDirectRule/FUT b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalIntroductionDirectRule/FUT
new file mode 100644
index 000000000..4bb3cb635
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalIntroductionDirectRule/FUT
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalIntroductionDirectRule/FUU b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalIntroductionDirectRule/FUU
new file mode 100644
index 000000000..7ddeeb5c8
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalIntroductionDirectRule/FUU
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalIntroductionDirectRule/TUF b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalIntroductionDirectRule/TUF
new file mode 100644
index 000000000..fb40ff4d4
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalIntroductionDirectRule/TUF
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalIntroductionDirectRule/TUT b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalIntroductionDirectRule/TUT
new file mode 100644
index 000000000..6ce5ab64c
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalIntroductionDirectRule/TUT
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalIntroductionDirectRule/TUU b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalIntroductionDirectRule/TUU
new file mode 100644
index 000000000..9307de3ad
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalIntroductionDirectRule/TUU
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalIntroductionDirectRule/UUF b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalIntroductionDirectRule/UUF
new file mode 100644
index 000000000..c61474b96
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalIntroductionDirectRule/UUF
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalIntroductionDirectRule/UUT b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalIntroductionDirectRule/UUT
new file mode 100644
index 000000000..2dead7328
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalIntroductionDirectRule/UUT
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalIntroductionDirectRule/UUU b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalIntroductionDirectRule/UUU
new file mode 100644
index 000000000..04596d449
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalIntroductionDirectRule/UUU
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/ConditionalEliminationDirectRule/FalseConditional b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalEliminationDirectRule/FalseConditional
new file mode 100644
index 000000000..2da458f51
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalEliminationDirectRule/FalseConditional
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/ConditionalEliminationDirectRule/TrueConditional b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalEliminationDirectRule/TrueConditional
new file mode 100644
index 000000000..829861f75
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalEliminationDirectRule/TrueConditional
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/ConditionalEliminationDirectRule/TrueConditionalWithFalseB b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalEliminationDirectRule/TrueConditionalWithFalseB
new file mode 100644
index 000000000..85e42664a
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalEliminationDirectRule/TrueConditionalWithFalseB
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/ConditionalEliminationDirectRule/TrueConditionalWithTrueA b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalEliminationDirectRule/TrueConditionalWithTrueA
new file mode 100644
index 000000000..d77a27502
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalEliminationDirectRule/TrueConditionalWithTrueA
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/ConditionalEliminationDirectRule/TrueConditionalWithTrueB b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalEliminationDirectRule/TrueConditionalWithTrueB
new file mode 100644
index 000000000..86b10a7cc
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalEliminationDirectRule/TrueConditionalWithTrueB
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/ConditionalIntroductionDirectRule/FUF b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalIntroductionDirectRule/FUF
new file mode 100644
index 000000000..a2adf2297
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalIntroductionDirectRule/FUF
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/ConditionalIntroductionDirectRule/FUT b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalIntroductionDirectRule/FUT
new file mode 100644
index 000000000..5b849c7ac
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalIntroductionDirectRule/FUT
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/ConditionalIntroductionDirectRule/FUU b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalIntroductionDirectRule/FUU
new file mode 100644
index 000000000..48d5fd7c6
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalIntroductionDirectRule/FUU
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/ConditionalIntroductionDirectRule/TUF b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalIntroductionDirectRule/TUF
new file mode 100644
index 000000000..480a409ef
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalIntroductionDirectRule/TUF
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/ConditionalIntroductionDirectRule/TUT b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalIntroductionDirectRule/TUT
new file mode 100644
index 000000000..862ee1628
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalIntroductionDirectRule/TUT
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/ConditionalIntroductionDirectRule/TUU b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalIntroductionDirectRule/TUU
new file mode 100644
index 000000000..79b97ba46
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalIntroductionDirectRule/TUU
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/ConditionalIntroductionDirectRule/UUF b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalIntroductionDirectRule/UUF
new file mode 100644
index 000000000..e5c9c4c0d
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalIntroductionDirectRule/UUF
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/ConditionalIntroductionDirectRule/UUT b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalIntroductionDirectRule/UUT
new file mode 100644
index 000000000..efe86b390
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalIntroductionDirectRule/UUT
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/ConditionalIntroductionDirectRule/UUU b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalIntroductionDirectRule/UUU
new file mode 100644
index 000000000..b0aa8ba00
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalIntroductionDirectRule/UUU
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/NotEliminationDirectRule/BlankNot b/src/test/resources/puzzles/shorttruthtable/rules/NotEliminationDirectRule/BlankNot
new file mode 100644
index 000000000..e7bf96e4a
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/NotEliminationDirectRule/BlankNot
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/NotEliminationDirectRule/FalseNot b/src/test/resources/puzzles/shorttruthtable/rules/NotEliminationDirectRule/FalseNot
new file mode 100644
index 000000000..2e9ac998d
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/NotEliminationDirectRule/FalseNot
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/NotEliminationDirectRule/TrueNot b/src/test/resources/puzzles/shorttruthtable/rules/NotEliminationDirectRule/TrueNot
new file mode 100644
index 000000000..6f19fc871
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/NotEliminationDirectRule/TrueNot
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/NotIntroductionDirectRule/BlankA b/src/test/resources/puzzles/shorttruthtable/rules/NotIntroductionDirectRule/BlankA
new file mode 100644
index 000000000..e7bf96e4a
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/NotIntroductionDirectRule/BlankA
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/NotIntroductionDirectRule/FalseA b/src/test/resources/puzzles/shorttruthtable/rules/NotIntroductionDirectRule/FalseA
new file mode 100644
index 000000000..d4c178464
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/NotIntroductionDirectRule/FalseA
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/NotIntroductionDirectRule/TrueA b/src/test/resources/puzzles/shorttruthtable/rules/NotIntroductionDirectRule/TrueA
new file mode 100644
index 000000000..7c4f71984
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/NotIntroductionDirectRule/TrueA
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/OrCaseRule/ComplexStatement1_False b/src/test/resources/puzzles/shorttruthtable/rules/OrCaseRule/ComplexStatement1_False
new file mode 100644
index 000000000..1da467289
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/OrCaseRule/ComplexStatement1_False
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/OrCaseRule/ComplexStatement1_True b/src/test/resources/puzzles/shorttruthtable/rules/OrCaseRule/ComplexStatement1_True
new file mode 100644
index 000000000..e8067987e
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/OrCaseRule/ComplexStatement1_True
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/OrCaseRule/SimpleStatement1_False b/src/test/resources/puzzles/shorttruthtable/rules/OrCaseRule/SimpleStatement1_False
new file mode 100644
index 000000000..4daaabc88
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/OrCaseRule/SimpleStatement1_False
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/OrCaseRule/SimpleStatement1_True b/src/test/resources/puzzles/shorttruthtable/rules/OrCaseRule/SimpleStatement1_True
new file mode 100644
index 000000000..765aad7d8
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/OrCaseRule/SimpleStatement1_True
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/OrEliminationDirectRule/FTU b/src/test/resources/puzzles/shorttruthtable/rules/OrEliminationDirectRule/FTU
new file mode 100644
index 000000000..bda22c0e6
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/OrEliminationDirectRule/FTU
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/OrEliminationDirectRule/UFU b/src/test/resources/puzzles/shorttruthtable/rules/OrEliminationDirectRule/UFU
new file mode 100644
index 000000000..b7c23215e
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/OrEliminationDirectRule/UFU
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/OrEliminationDirectRule/UTF b/src/test/resources/puzzles/shorttruthtable/rules/OrEliminationDirectRule/UTF
new file mode 100644
index 000000000..60eaca2b8
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/OrEliminationDirectRule/UTF
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/OrEliminationDirectRule/UTU b/src/test/resources/puzzles/shorttruthtable/rules/OrEliminationDirectRule/UTU
new file mode 100644
index 000000000..c28ba1fde
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/OrEliminationDirectRule/UTU
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/OrIntroductionDirectRule/FUF b/src/test/resources/puzzles/shorttruthtable/rules/OrIntroductionDirectRule/FUF
new file mode 100644
index 000000000..2326f8df4
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/OrIntroductionDirectRule/FUF
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/OrIntroductionDirectRule/FUT b/src/test/resources/puzzles/shorttruthtable/rules/OrIntroductionDirectRule/FUT
new file mode 100644
index 000000000..447c91981
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/OrIntroductionDirectRule/FUT
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/OrIntroductionDirectRule/FUU b/src/test/resources/puzzles/shorttruthtable/rules/OrIntroductionDirectRule/FUU
new file mode 100644
index 000000000..083c30039
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/OrIntroductionDirectRule/FUU
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/OrIntroductionDirectRule/TUF b/src/test/resources/puzzles/shorttruthtable/rules/OrIntroductionDirectRule/TUF
new file mode 100644
index 000000000..ef36a432d
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/OrIntroductionDirectRule/TUF
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/OrIntroductionDirectRule/TUT b/src/test/resources/puzzles/shorttruthtable/rules/OrIntroductionDirectRule/TUT
new file mode 100644
index 000000000..05f65ad45
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/OrIntroductionDirectRule/TUT
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/OrIntroductionDirectRule/TUU b/src/test/resources/puzzles/shorttruthtable/rules/OrIntroductionDirectRule/TUU
new file mode 100644
index 000000000..d6e54b326
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/OrIntroductionDirectRule/TUU
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/OrIntroductionDirectRule/UUF b/src/test/resources/puzzles/shorttruthtable/rules/OrIntroductionDirectRule/UUF
new file mode 100644
index 000000000..5f69fb73f
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/OrIntroductionDirectRule/UUF
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/OrIntroductionDirectRule/UUT b/src/test/resources/puzzles/shorttruthtable/rules/OrIntroductionDirectRule/UUT
new file mode 100644
index 000000000..d7ef8cd88
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/OrIntroductionDirectRule/UUT
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/OrIntroductionDirectRule/UUU b/src/test/resources/puzzles/shorttruthtable/rules/OrIntroductionDirectRule/UUU
new file mode 100644
index 000000000..005a4f462
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/OrIntroductionDirectRule/UUU
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/test/resources/puzzles/shorttruthtable/rules/TrueOrFalseCaseRule/Statement b/src/test/resources/puzzles/shorttruthtable/rules/TrueOrFalseCaseRule/Statement
new file mode 100644
index 000000000..51a9d8b39
--- /dev/null
+++ b/src/test/resources/puzzles/shorttruthtable/rules/TrueOrFalseCaseRule/Statement
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
diff --git a/src/test/resources/puzzles/treetent/rules/EmptyFieldDirectRule/EmptyFieldFail b/src/test/resources/puzzles/treetent/rules/EmptyFieldDirectRule/EmptyFieldFail
new file mode 100644
index 000000000..f826667e3
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/EmptyFieldDirectRule/EmptyFieldFail
@@ -0,0 +1,23 @@
+
+
+
+
+ |
+ |
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/treetent/rules/EmptyFieldDirectRule/EmptyFieldFailBottom b/src/test/resources/puzzles/treetent/rules/EmptyFieldDirectRule/EmptyFieldFailBottom
new file mode 100644
index 000000000..80deadaea
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/EmptyFieldDirectRule/EmptyFieldFailBottom
@@ -0,0 +1,20 @@
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/treetent/rules/EmptyFieldDirectRule/EmptyFieldFailLeft b/src/test/resources/puzzles/treetent/rules/EmptyFieldDirectRule/EmptyFieldFailLeft
new file mode 100644
index 000000000..d19e01daf
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/EmptyFieldDirectRule/EmptyFieldFailLeft
@@ -0,0 +1,20 @@
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/treetent/rules/EmptyFieldDirectRule/EmptyFieldFailRight b/src/test/resources/puzzles/treetent/rules/EmptyFieldDirectRule/EmptyFieldFailRight
new file mode 100644
index 000000000..bf3954964
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/EmptyFieldDirectRule/EmptyFieldFailRight
@@ -0,0 +1,20 @@
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/treetent/rules/EmptyFieldDirectRule/EmptyFieldFailTop b/src/test/resources/puzzles/treetent/rules/EmptyFieldDirectRule/EmptyFieldFailTop
new file mode 100644
index 000000000..8eaa974ea
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/EmptyFieldDirectRule/EmptyFieldFailTop
@@ -0,0 +1,20 @@
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/treetent/rules/FinishWithGrassDirectRule/CornerTent b/src/test/resources/puzzles/treetent/rules/FinishWithGrassDirectRule/CornerTent
new file mode 100644
index 000000000..daba3648e
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/FinishWithGrassDirectRule/CornerTent
@@ -0,0 +1,20 @@
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/treetent/rules/FinishWithGrassDirectRule/FailTent b/src/test/resources/puzzles/treetent/rules/FinishWithGrassDirectRule/FailTent
new file mode 100644
index 000000000..9fa14ebe4
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/FinishWithGrassDirectRule/FailTent
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/treetent/rules/FinishWithGrassDirectRule/FinishWithGrass b/src/test/resources/puzzles/treetent/rules/FinishWithGrassDirectRule/FinishWithGrassJustRow
similarity index 100%
rename from src/test/resources/puzzles/treetent/rules/FinishWithGrassDirectRule/FinishWithGrass
rename to src/test/resources/puzzles/treetent/rules/FinishWithGrassDirectRule/FinishWithGrassJustRow
diff --git a/src/test/resources/puzzles/treetent/rules/FinishWithGrassDirectRule/FinishWithGrassJustTent b/src/test/resources/puzzles/treetent/rules/FinishWithGrassDirectRule/FinishWithGrassJustTent
new file mode 100644
index 000000000..cbd3662e6
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/FinishWithGrassDirectRule/FinishWithGrassJustTent
@@ -0,0 +1,16 @@
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/treetent/rules/FinishWithGrassDirectRule/MiddleTent b/src/test/resources/puzzles/treetent/rules/FinishWithGrassDirectRule/MiddleTent
new file mode 100644
index 000000000..8f71a57f9
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/FinishWithGrassDirectRule/MiddleTent
@@ -0,0 +1,20 @@
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/treetent/rules/FinishWithGrassDirectRule/NoTent b/src/test/resources/puzzles/treetent/rules/FinishWithGrassDirectRule/NoTent
new file mode 100644
index 000000000..a13c7cc55
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/FinishWithGrassDirectRule/NoTent
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/treetent/rules/FinishWithGrassDirectRule/SpacedOutTent b/src/test/resources/puzzles/treetent/rules/FinishWithGrassDirectRule/SpacedOutTent
new file mode 100644
index 000000000..f7b523b0a
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/FinishWithGrassDirectRule/SpacedOutTent
@@ -0,0 +1,30 @@
+
+
+
+
+ |
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/treetent/rules/FinishWithTentsDirectRule/AdditionalTents b/src/test/resources/puzzles/treetent/rules/FinishWithTentsDirectRule/AdditionalTents
new file mode 100644
index 000000000..6fea9f102
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/FinishWithTentsDirectRule/AdditionalTents
@@ -0,0 +1,20 @@
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/treetent/rules/FinishWithTentsDirectRule/AmbiguousTents b/src/test/resources/puzzles/treetent/rules/FinishWithTentsDirectRule/AmbiguousTents
new file mode 100644
index 000000000..96f2ed729
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/FinishWithTentsDirectRule/AmbiguousTents
@@ -0,0 +1,20 @@
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/treetent/rules/FinishWithTentsDirectRule/FinishWithHorizontalTents b/src/test/resources/puzzles/treetent/rules/FinishWithTentsDirectRule/FinishWithHorizontalTents
new file mode 100644
index 000000000..a10c04124
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/FinishWithTentsDirectRule/FinishWithHorizontalTents
@@ -0,0 +1,20 @@
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/treetent/rules/FinishWithTentsDirectRule/FinishWithTents b/src/test/resources/puzzles/treetent/rules/FinishWithTentsDirectRule/FinishWithTents
index a10c04124..a292cc972 100644
--- a/src/test/resources/puzzles/treetent/rules/FinishWithTentsDirectRule/FinishWithTents
+++ b/src/test/resources/puzzles/treetent/rules/FinishWithTentsDirectRule/FinishWithTents
@@ -2,16 +2,16 @@
- |
+ |
-
-
+
+
-
+
diff --git a/src/test/resources/puzzles/treetent/rules/FinishWithTentsDirectRule/FinishWithTentsBothWays b/src/test/resources/puzzles/treetent/rules/FinishWithTentsDirectRule/FinishWithTentsBothWays
new file mode 100644
index 000000000..c4d58ef60
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/FinishWithTentsDirectRule/FinishWithTentsBothWays
@@ -0,0 +1,20 @@
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/treetent/rules/FinishWithTentsDirectRule/FinishWithTentsFail b/src/test/resources/puzzles/treetent/rules/FinishWithTentsDirectRule/FinishWithTentsFail
new file mode 100644
index 000000000..a13c7cc55
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/FinishWithTentsDirectRule/FinishWithTentsFail
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/treetent/rules/FinishWithTentsDirectRule/FinishWithVerticalTents b/src/test/resources/puzzles/treetent/rules/FinishWithTentsDirectRule/FinishWithVerticalTents
new file mode 100644
index 000000000..0a340cd17
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/FinishWithTentsDirectRule/FinishWithVerticalTents
@@ -0,0 +1,20 @@
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/treetent/rules/FinishWithTentsDirectRule/TooManyTents b/src/test/resources/puzzles/treetent/rules/FinishWithTentsDirectRule/TooManyTents
new file mode 100644
index 000000000..8f71a57f9
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/FinishWithTentsDirectRule/TooManyTents
@@ -0,0 +1,20 @@
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/treetent/rules/LastCampingSpotDirectRule/LastCampingSpotDown b/src/test/resources/puzzles/treetent/rules/LastCampingSpotDirectRule/LastCampingSpotDown
new file mode 100644
index 000000000..cb19ab33f
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/LastCampingSpotDirectRule/LastCampingSpotDown
@@ -0,0 +1,23 @@
+
+
+
+
+ |
+ |
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/treetent/rules/LastCampingSpotDirectRule/LastCampingSpotLeft b/src/test/resources/puzzles/treetent/rules/LastCampingSpotDirectRule/LastCampingSpotLeft
new file mode 100644
index 000000000..e70dc4be5
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/LastCampingSpotDirectRule/LastCampingSpotLeft
@@ -0,0 +1,23 @@
+
+
+
+
+ |
+ |
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/treetent/rules/LastCampingSpotDirectRule/LastCampingSpotRight b/src/test/resources/puzzles/treetent/rules/LastCampingSpotDirectRule/LastCampingSpotRight
new file mode 100644
index 000000000..64ddf29db
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/LastCampingSpotDirectRule/LastCampingSpotRight
@@ -0,0 +1,23 @@
+
+
+
+
+ |
+ |
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/treetent/rules/LastCampingSpotDirectRule/LastCampingSpot b/src/test/resources/puzzles/treetent/rules/LastCampingSpotDirectRule/LastCampingSpotUp
similarity index 100%
rename from src/test/resources/puzzles/treetent/rules/LastCampingSpotDirectRule/LastCampingSpot
rename to src/test/resources/puzzles/treetent/rules/LastCampingSpotDirectRule/LastCampingSpotUp
diff --git a/src/test/resources/puzzles/treetent/rules/NoTentForTreeContradictionRule/NoTentForTreeDiagonal b/src/test/resources/puzzles/treetent/rules/NoTentForTreeContradictionRule/NoTentForTreeDiagonal
new file mode 100644
index 000000000..af0b49e31
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/NoTentForTreeContradictionRule/NoTentForTreeDiagonal
@@ -0,0 +1,21 @@
+
+
+
+
+ |
+ |
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/treetent/rules/NoTentForTreeContradictionRule/NoTentForTreeTwoTrees b/src/test/resources/puzzles/treetent/rules/NoTentForTreeContradictionRule/NoTentForTreeTwoTrees
new file mode 100644
index 000000000..5111e0585
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/NoTentForTreeContradictionRule/NoTentForTreeTwoTrees
@@ -0,0 +1,21 @@
+
+
+
+
+ |
+ |
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/treetent/rules/NoTentForTreeContradictionRule/NoTentForTreeTwoTreesDiagonal b/src/test/resources/puzzles/treetent/rules/NoTentForTreeContradictionRule/NoTentForTreeTwoTreesDiagonal
new file mode 100644
index 000000000..10391b85c
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/NoTentForTreeContradictionRule/NoTentForTreeTwoTreesDiagonal
@@ -0,0 +1,21 @@
+
+
+
+
+ |
+ |
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/treetent/rules/NoTreeForTentContradictionRule/NoTreeForTent3x3 b/src/test/resources/puzzles/treetent/rules/NoTreeForTentContradictionRule/NoTreeForTent3x3
new file mode 100644
index 000000000..9c5e81936
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/NoTreeForTentContradictionRule/NoTreeForTent3x3
@@ -0,0 +1,28 @@
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/treetent/rules/NoTreeForTentContradictionRule/NoTreeForTentDiagonals b/src/test/resources/puzzles/treetent/rules/NoTreeForTentContradictionRule/NoTreeForTentDiagonals
new file mode 100644
index 000000000..ad086bbc1
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/NoTreeForTentContradictionRule/NoTreeForTentDiagonals
@@ -0,0 +1,28 @@
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/treetent/rules/NoTreeForTentContradictionRule/NoTreeForTentJustTent b/src/test/resources/puzzles/treetent/rules/NoTreeForTentContradictionRule/NoTreeForTentJustTent
new file mode 100644
index 000000000..93aaf451f
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/NoTreeForTentContradictionRule/NoTreeForTentJustTent
@@ -0,0 +1,28 @@
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/treetent/rules/NoTreeForTentContradictionRule/NoTreeForTentNE b/src/test/resources/puzzles/treetent/rules/NoTreeForTentContradictionRule/NoTreeForTentNE
new file mode 100644
index 000000000..80ffb9525
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/NoTreeForTentContradictionRule/NoTreeForTentNE
@@ -0,0 +1,21 @@
+
+
+
+
+ |
+ |
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/treetent/rules/NoTreeForTentContradictionRule/NoTreeForTent b/src/test/resources/puzzles/treetent/rules/NoTreeForTentContradictionRule/NoTreeForTentNW
similarity index 100%
rename from src/test/resources/puzzles/treetent/rules/NoTreeForTentContradictionRule/NoTreeForTent
rename to src/test/resources/puzzles/treetent/rules/NoTreeForTentContradictionRule/NoTreeForTentNW
diff --git a/src/test/resources/puzzles/treetent/rules/NoTreeForTentContradictionRule/NoTreeForTentSE b/src/test/resources/puzzles/treetent/rules/NoTreeForTentContradictionRule/NoTreeForTentSE
new file mode 100644
index 000000000..c2fc5206d
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/NoTreeForTentContradictionRule/NoTreeForTentSE
@@ -0,0 +1,21 @@
+
+
+
+
+ |
+ |
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/treetent/rules/NoTreeForTentContradictionRule/NoTreeForTentSW b/src/test/resources/puzzles/treetent/rules/NoTreeForTentContradictionRule/NoTreeForTentSW
new file mode 100644
index 000000000..8e8249b27
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/NoTreeForTentContradictionRule/NoTreeForTentSW
@@ -0,0 +1,21 @@
+
+
+
+
+ |
+ |
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/treetent/rules/NoTreeForTentContradictionRule/NoTreeForTentYesTree b/src/test/resources/puzzles/treetent/rules/NoTreeForTentContradictionRule/NoTreeForTentYesTree
new file mode 100644
index 000000000..f46e4b5a5
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/NoTreeForTentContradictionRule/NoTreeForTentYesTree
@@ -0,0 +1,28 @@
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/treetent/rules/SurroundTentWithGrassDirectRule/SurroundTentWithGrassBad b/src/test/resources/puzzles/treetent/rules/SurroundTentWithGrassDirectRule/SurroundTentWithGrassBad
new file mode 100644
index 000000000..6065d42cd
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/SurroundTentWithGrassDirectRule/SurroundTentWithGrassBad
@@ -0,0 +1,20 @@
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/treetent/rules/SurroundTentWithGrassDirectRule/SurroundTentWithGrassTrees b/src/test/resources/puzzles/treetent/rules/SurroundTentWithGrassDirectRule/SurroundTentWithGrassTrees
new file mode 100644
index 000000000..e8fef64dc
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/SurroundTentWithGrassDirectRule/SurroundTentWithGrassTrees
@@ -0,0 +1,28 @@
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/treetent/rules/TentOrGrassCaseRule/TentOrGrassTest b/src/test/resources/puzzles/treetent/rules/TentOrGrassCaseRule/TentOrGrassTest
new file mode 100644
index 000000000..9ae8455e1
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/TentOrGrassCaseRule/TentOrGrassTest
@@ -0,0 +1,20 @@
+
+
+
+
+ |
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/treetent/rules/TentOrGrassCaseRule/TestPuzzle b/src/test/resources/puzzles/treetent/rules/TentOrGrassCaseRule/TestPuzzle
new file mode 100644
index 000000000..a13c7cc55
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/TentOrGrassCaseRule/TestPuzzle
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/treetent/rules/TooFewTentsContradictionRule/TooFewTents2x2Column b/src/test/resources/puzzles/treetent/rules/TooFewTentsContradictionRule/TooFewTents2x2Column
new file mode 100644
index 000000000..0f78702c4
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/TooFewTentsContradictionRule/TooFewTents2x2Column
@@ -0,0 +1,19 @@
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/treetent/rules/TooFewTentsContradictionRule/TooFewTents2x2Row b/src/test/resources/puzzles/treetent/rules/TooFewTentsContradictionRule/TooFewTents2x2Row
new file mode 100644
index 000000000..c423b179b
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/TooFewTentsContradictionRule/TooFewTents2x2Row
@@ -0,0 +1,19 @@
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/treetent/rules/TooFewTentsContradictionRule/TooFewTents3x3Column b/src/test/resources/puzzles/treetent/rules/TooFewTentsContradictionRule/TooFewTents3x3Column
new file mode 100644
index 000000000..d1e79a76e
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/TooFewTentsContradictionRule/TooFewTents3x3Column
@@ -0,0 +1,22 @@
+
+
+
+
+ |
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/treetent/rules/TooFewTentsContradictionRule/TooFewTents3x3DoubleColumn b/src/test/resources/puzzles/treetent/rules/TooFewTentsContradictionRule/TooFewTents3x3DoubleColumn
new file mode 100644
index 000000000..e71832f08
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/TooFewTentsContradictionRule/TooFewTents3x3DoubleColumn
@@ -0,0 +1,27 @@
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/treetent/rules/TooFewTentsContradictionRule/TooFewTentsDoubleBad b/src/test/resources/puzzles/treetent/rules/TooFewTentsContradictionRule/TooFewTentsDoubleBad
new file mode 100644
index 000000000..ecc8988c6
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/TooFewTentsContradictionRule/TooFewTentsDoubleBad
@@ -0,0 +1,16 @@
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/treetent/rules/TooFewTentsContradictionRule/TooFewTents b/src/test/resources/puzzles/treetent/rules/TooFewTentsContradictionRule/TooFewTentsJustY
similarity index 100%
rename from src/test/resources/puzzles/treetent/rules/TooFewTentsContradictionRule/TooFewTents
rename to src/test/resources/puzzles/treetent/rules/TooFewTentsContradictionRule/TooFewTentsJustY
diff --git a/src/test/resources/puzzles/treetent/rules/TooFewTentsContradictionRule/TooFewTentsNoContradiction b/src/test/resources/puzzles/treetent/rules/TooFewTentsContradictionRule/TooFewTentsNoContradiction
new file mode 100644
index 000000000..2f609e161
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/TooFewTentsContradictionRule/TooFewTentsNoContradiction
@@ -0,0 +1,19 @@
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/treetent/rules/TooFewTentsContradictionRule/TooFewTentsWithTent b/src/test/resources/puzzles/treetent/rules/TooFewTentsContradictionRule/TooFewTentsWithTent
new file mode 100644
index 000000000..8ae51f0a3
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/TooFewTentsContradictionRule/TooFewTentsWithTent
@@ -0,0 +1,16 @@
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/treetent/rules/TooManyTentsContradictionRule/TooManyTentsBottomAccount b/src/test/resources/puzzles/treetent/rules/TooManyTentsContradictionRule/TooManyTentsBottomAccount
new file mode 100644
index 000000000..8474e916a
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/TooManyTentsContradictionRule/TooManyTentsBottomAccount
@@ -0,0 +1,22 @@
+
+
+
+
+ |
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/treetent/rules/TooManyTentsContradictionRule/TooManyTentsContradictionRuleColumn_Row b/src/test/resources/puzzles/treetent/rules/TooManyTentsContradictionRule/TooManyTentsBottomDown
similarity index 93%
rename from src/test/resources/puzzles/treetent/rules/TooManyTentsContradictionRule/TooManyTentsContradictionRuleColumn_Row
rename to src/test/resources/puzzles/treetent/rules/TooManyTentsContradictionRule/TooManyTentsBottomDown
index 78e956c35..8051a5501 100644
--- a/src/test/resources/puzzles/treetent/rules/TooManyTentsContradictionRule/TooManyTentsContradictionRuleColumn_Row
+++ b/src/test/resources/puzzles/treetent/rules/TooManyTentsContradictionRule/TooManyTentsBottomDown
@@ -8,7 +8,7 @@
-
+
diff --git a/src/test/resources/puzzles/treetent/rules/TooManyTentsContradictionRule/TooManyTentsBottomMissDown b/src/test/resources/puzzles/treetent/rules/TooManyTentsContradictionRule/TooManyTentsBottomMissDown
new file mode 100644
index 000000000..3cbb1cdb4
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/TooManyTentsContradictionRule/TooManyTentsBottomMissDown
@@ -0,0 +1,22 @@
+
+
+
+
+ |
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/treetent/rules/TooManyTentsContradictionRule/TooManyTentsBottomMissRight b/src/test/resources/puzzles/treetent/rules/TooManyTentsContradictionRule/TooManyTentsBottomMissRight
new file mode 100644
index 000000000..d22778c4e
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/TooManyTentsContradictionRule/TooManyTentsBottomMissRight
@@ -0,0 +1,22 @@
+
+
+
+
+ |
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/treetent/rules/TooManyTentsContradictionRule/TooManyTentsBottomRight b/src/test/resources/puzzles/treetent/rules/TooManyTentsContradictionRule/TooManyTentsBottomRight
new file mode 100644
index 000000000..aeb4cd148
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/TooManyTentsContradictionRule/TooManyTentsBottomRight
@@ -0,0 +1,22 @@
+
+
+
+
+ |
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/treetent/rules/TooManyTentsContradictionRule/TooManyTentsTopAccount b/src/test/resources/puzzles/treetent/rules/TooManyTentsContradictionRule/TooManyTentsTopAccount
new file mode 100644
index 000000000..258e32d47
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/TooManyTentsContradictionRule/TooManyTentsTopAccount
@@ -0,0 +1,22 @@
+
+
+
+
+ |
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/treetent/rules/TooManyTentsContradictionRule/TooManyTentsTopDown b/src/test/resources/puzzles/treetent/rules/TooManyTentsContradictionRule/TooManyTentsTopDown
new file mode 100644
index 000000000..58d4bbddf
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/TooManyTentsContradictionRule/TooManyTentsTopDown
@@ -0,0 +1,22 @@
+
+
+
+
+ |
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/treetent/rules/TooManyTentsContradictionRule/TooManyTentsTopRight b/src/test/resources/puzzles/treetent/rules/TooManyTentsContradictionRule/TooManyTentsTopRight
new file mode 100644
index 000000000..dd5b7b935
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/TooManyTentsContradictionRule/TooManyTentsTopRight
@@ -0,0 +1,22 @@
+
+
+
+
+ |
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/treetent/rules/TooManyTentsContradictionRule/TooManyTentsTotalFail b/src/test/resources/puzzles/treetent/rules/TooManyTentsContradictionRule/TooManyTentsTotalFail
new file mode 100644
index 000000000..9fbb8b82f
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/TooManyTentsContradictionRule/TooManyTentsTotalFail
@@ -0,0 +1,22 @@
+
+
+
+
+ |
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsAdjacentAlt b/src/test/resources/puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsAdjacentAlt
new file mode 100644
index 000000000..902fb3ee7
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsAdjacentAlt
@@ -0,0 +1,19 @@
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsDiagonalAlt b/src/test/resources/puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsDiagonalAlt
new file mode 100644
index 000000000..9b35fb998
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsDiagonalAlt
@@ -0,0 +1,19 @@
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsFull2By2 b/src/test/resources/puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsFull2By2
new file mode 100644
index 000000000..59805ca35
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsFull2By2
@@ -0,0 +1,21 @@
+
+
+
+
+ |
+ |
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsMixedDownLeft b/src/test/resources/puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsMixedDownLeft
new file mode 100644
index 000000000..af4ca0831
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsMixedDownLeft
@@ -0,0 +1,20 @@
+
+
+
+
+ |
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsMixedDownRight b/src/test/resources/puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsMixedDownRight
new file mode 100644
index 000000000..05b7a7667
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsMixedDownRight
@@ -0,0 +1,20 @@
+
+
+
+
+ |
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsMixedUpLeft b/src/test/resources/puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsMixedUpLeft
new file mode 100644
index 000000000..b8b81c7b4
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsMixedUpLeft
@@ -0,0 +1,20 @@
+
+
+
+
+ |
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsMixedUpRight b/src/test/resources/puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsMixedUpRight
new file mode 100644
index 000000000..af7fb5df2
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsMixedUpRight
@@ -0,0 +1,20 @@
+
+
+
+
+ |
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsTreeAdjacent b/src/test/resources/puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsTreeAdjacent
new file mode 100644
index 000000000..4c63558c2
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsTreeAdjacent
@@ -0,0 +1,19 @@
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsTreeDiagonal b/src/test/resources/puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsTreeDiagonal
new file mode 100644
index 000000000..b2f54aef3
--- /dev/null
+++ b/src/test/resources/puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsTreeDiagonal
@@ -0,0 +1,19 @@
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file