From 0f024bbfc79059a032dd850b82f7fb0506f4a86a Mon Sep 17 00:00:00 2001 From: ProAndrewLi Date: Fri, 6 Dec 2024 00:00:31 -0500 Subject: [PATCH] Allowed Required Direct Rules to work for all general cases instead of needing the remaining unknown cells to all have to be the filled or empty. --- .../rules/RequiredEmptyDirectRule.java | 9 ++-- .../rules/RequiredFilledDirectRule.java | 41 +++++++++++++++---- .../UnreachableSumContradictionRule.java | 15 +++++-- 3 files changed, 49 insertions(+), 16 deletions(-) diff --git a/src/main/java/edu/rpi/legup/puzzle/kakurasu/rules/RequiredEmptyDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/kakurasu/rules/RequiredEmptyDirectRule.java index cf97a1671..3218d9023 100644 --- a/src/main/java/edu/rpi/legup/puzzle/kakurasu/rules/RequiredEmptyDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/kakurasu/rules/RequiredEmptyDirectRule.java @@ -57,7 +57,6 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem * @return if the cell is forced to be at its position on the board */ private boolean isForced(KakurasuBoard board, KakurasuCell cell) { - // TODO: Fix this so it doesn't only work if all are empty Point loc = cell.getLocation(); List filledRow = board.getRowCol(loc.y, KakurasuType.FILLED, true); List filledCol = board.getRowCol(loc.x, KakurasuType.FILLED, false); @@ -67,14 +66,16 @@ private boolean isForced(KakurasuBoard board, KakurasuCell cell) { for(KakurasuCell kc : filledRow) { rowSum += kc.getLocation().x + 1; } - if(rowSum == board.getClue(board.getWidth(), loc.y).getData()) return true; + // If setting this cell to filled causes the clue to fail, this cell must be empty + if(rowSum + loc.x + 1 > board.getClue(board.getWidth(), loc.y).getData()) return true; int colSum = 0; for(KakurasuCell kc : filledCol) { colSum += kc.getLocation().y + 1; } - // Return true if the clue is fulfilled, false if it isn't - return (colSum == board.getClue(loc.x, board.getHeight()).getData()); + // Return true if the clue is exceeded if this cell is filled, + // Return false if setting the cell to filled keeps the col total to under the clue value + return (colSum + loc.y + 1> board.getClue(loc.x, board.getHeight()).getData()); } /** diff --git a/src/main/java/edu/rpi/legup/puzzle/kakurasu/rules/RequiredFilledDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/kakurasu/rules/RequiredFilledDirectRule.java index e34409a6a..6aa952085 100644 --- a/src/main/java/edu/rpi/legup/puzzle/kakurasu/rules/RequiredFilledDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/kakurasu/rules/RequiredFilledDirectRule.java @@ -10,6 +10,7 @@ import edu.rpi.legup.puzzle.kakurasu.KakurasuType; import java.awt.*; +import java.util.ArrayList; import java.util.List; public class RequiredFilledDirectRule extends DirectRule { @@ -65,24 +66,48 @@ private boolean isForced(KakurasuBoard board, KakurasuCell cell) { List unknownCol = board.getRowCol(loc.x, KakurasuType.UNKNOWN, false); // Check if the remaining locations available must be filled to fulfill the clue value - int rowSum = 0; + int rowValueRemaining = board.getClue(board.getWidth(), loc.y).getData(); for(KakurasuCell kc : filledRow) { - rowSum += kc.getLocation().x + 1; + rowValueRemaining -= kc.getLocation().x + 1; } + ArrayList rowValues = new ArrayList<>(); + // Add all the unknown row values to the Arraylist except for the one being checked by the function for(KakurasuCell kc : unknownRow) { - rowSum += kc.getLocation().x + 1; + if(kc.getLocation() != loc) rowValues.add(kc.getLocation().x + 1); } - if(rowSum == board.getClue(board.getWidth(), loc.y).getData()) return true; + // If the clue is not reachable without the current cell being filled, but is possible with it filled, + // then that means the current cell is a required fill on this board + if(!isReachable(rowValueRemaining, 0, rowValues) && + isReachable(rowValueRemaining-(loc.x+1), 0, rowValues)) return true; - int colSum = 0; + int colValueRemaining = board.getClue(loc.x, board.getHeight()).getData(); for(KakurasuCell kc : filledCol) { - colSum += kc.getLocation().y + 1; + colValueRemaining -= kc.getLocation().y + 1; } + ArrayList colValues = new ArrayList<>(); + // Add all the unknown col values to the Arraylist except for the one being checked by the function for(KakurasuCell kc : unknownCol) { - colSum += kc.getLocation().y + 1; + if(kc.getLocation() != loc) colValues.add(kc.getLocation().y + 1); } // Return true if the clue is fulfilled, false if it isn't - return (colSum == board.getClue(loc.x, board.getHeight()).getData()); + return (!isReachable(colValueRemaining, 0, rowValues) && + isReachable(colValueRemaining-(loc.y+1), 0, colValues)); + } + + /** + * Helper function that checks if the target clue is reachable given a list of KakurasuCells + * This function only works if the list of values are given in increasing index order (which it currently is) + * + * @param target The integer that we are trying to add up to, given the values + * @param currentIndex The index of the next value that we are considering + * @param values Values that we are given to try to sum up to the target + * @return If it's possible to sum the values in a way to get the target value + */ + private boolean isReachable(int target, int currentIndex, ArrayList values) { + if(target == 0) return true; + if(target < 0 || currentIndex >= values.size()) return false; + return (isReachable(target, currentIndex+1, values) || + isReachable(target - values.get(currentIndex), currentIndex+1, values)); } /** diff --git a/src/main/java/edu/rpi/legup/puzzle/kakurasu/rules/UnreachableSumContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/kakurasu/rules/UnreachableSumContradictionRule.java index 4deea2370..9096fc189 100644 --- a/src/main/java/edu/rpi/legup/puzzle/kakurasu/rules/UnreachableSumContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/kakurasu/rules/UnreachableSumContradictionRule.java @@ -64,7 +64,7 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { rowValues.add(kc.getLocation().x + 1); rowTotal += kc.getLocation().x + 1; } - // If the remaining unknown cells' values is less than the remaining value, + // If the remaining unknown cells' values is less than the remaining clue value, // this requires the usage of a different contradiction rule, not this one. if(rowTotal < rowValueRemaining) return super.getNoContradictionMessage(); rowPossible = isReachable(rowValueRemaining, 0, rowValues); @@ -75,7 +75,7 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { colValues.add(kc.getLocation().y + 1); colTotal += kc.getLocation().y + 1; } - // If the remaining unknown cells' values is less than the remaining value, + // If the remaining unknown cells' values is less than the remaining clue value, // this requires the usage of a different contradiction rule, not this one. if(colTotal < colValueRemaining) return super.getNoContradictionMessage(); colPossible = isReachable(colValueRemaining, 0, colValues); @@ -88,8 +88,15 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { } } - // Helper function that checks if the target clue is reachable given a list of KakurasuCells - // This function only works if the list of values are given in increasing index order (which it currently is) + /** + * Helper function that checks if the target clue is reachable given a list of KakurasuCells + * This function only works if the list of values are given in increasing index order (which it currently is) + * + * @param target The integer that we are trying to add up to, given the values + * @param currentIndex The index of the next value that we are considering + * @param values Values that we are given to try to sum up to the target + * @return If it's possible to sum the values in a way to get the target value + */ private boolean isReachable(int target, int currentIndex, ArrayList values) { if(target == 0) return true; if(target < 0 || currentIndex >= values.size()) return false;