diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuCellFactory.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuCellFactory.java index 90f84d519..8c383acc7 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuCellFactory.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuCellFactory.java @@ -16,6 +16,7 @@ public class SudokuCellFactory extends ElementFactory { * * @param node node that represents the puzzleElement * @param board board to add the newly created cell + * @param board board to add the newly created cell * @return newly created cell from the xml document Node * @throws InvalidFileFormatException if file is invalid */ diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/LastCellForNumberDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/LastCellForNumberDirectRule.java index 51d963247..13a257dba 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/LastCellForNumberDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/LastCellForNumberDirectRule.java @@ -12,7 +12,7 @@ public class LastCellForNumberDirectRule extends DirectRule { public LastCellForNumberDirectRule() { - super("SUDO-BASC-0002", "Last Cell for Number", + super("SUDO-BASC-0001", "Last Cell for Number", "This is the only cell open in its group for some number.", "edu/rpi/legup/images/sudoku/forcedByElimination.png"); } diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/LastNumberForCellDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/LastNumberForCellDirectRule.java index 28e64ce7b..dc73b7f3c 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/LastNumberForCellDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/LastNumberForCellDirectRule.java @@ -13,7 +13,7 @@ public class LastNumberForCellDirectRule extends DirectRule { public LastNumberForCellDirectRule() { - super("SUDO-BASC-0003", "Last Number for Cell", + super("SUDO-BASC-0002", "Last Number for Cell", "This is the only number left that can fit in the cell of a group.", "edu/rpi/legup/images/sudoku/forcedByDeduction.png"); } diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoSolutionContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberContradictionRule.java similarity index 91% rename from src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoSolutionContradictionRule.java rename to src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberContradictionRule.java index fb87764fe..a308e1dfc 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoSolutionContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberContradictionRule.java @@ -9,10 +9,10 @@ import java.util.HashSet; import java.util.Set; -public class NoSolutionContradictionRule extends ContradictionRule { +public class NoCellForNumberContradictionRule extends ContradictionRule { - public NoSolutionContradictionRule() { - super("SUDO-CONT-0001", "No Solution for Cell", + public NoCellForNumberContradictionRule() { + super("SUDO-CONT-0001", "No Cell for Number", "Process of elimination yields no valid numbers for an empty cell.", "edu/rpi/legup/images/sudoku/NoSolution.png"); } diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleNumberCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleNumberCaseRule.java index 27d6b58b7..1f16536af 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleNumberCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleNumberCaseRule.java @@ -49,16 +49,15 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem @Override public CaseBoard getCaseBoard(Board board) { - SudokuBoard sudokuBoard = (SudokuBoard) board; - PossibleNumberCaseBoard caseBoard = new PossibleNumberCaseBoard(sudokuBoard, this, null); - for (int i = 0; i < sudokuBoard.getSize(); i++) { - caseBoard.addPickableRegion(i); - caseBoard.addPickableRow(i); - caseBoard.addPickableCol(i); + SudokuBoard sudokuBoard = (SudokuBoard) board.copy(); + CaseBoard caseBoard = new CaseBoard(sudokuBoard, this); + for (PuzzleElement puzzleElement : sudokuBoard.getPuzzleElements()) { + if (((SudokuCell) puzzleElement).getData() == 0) { + caseBoard.addPickableElement(puzzleElement); + } } return caseBoard; } - /** * Gets the possible cases at a specific location based on this case rule * @@ -86,41 +85,9 @@ public ArrayList getCases(Board board, PuzzleElement puzzleElement, int v List caseCells = new ArrayList<>(); SudokuCell cell = (SudokuCell) puzzleElement; - Set group; - if (groupType == GroupType.REGION) { - group = sudokuBoard.getRegion(cell.getGroupIndex()); - } - else { - if (groupType == GroupType.ROW) { - group = sudokuBoard.getRow(cell.getLocation().y); - } - else { - group = sudokuBoard.getCol(cell.getLocation().x); - } - } - - for (SudokuCell c : group) { - if (c.getData() == 0) { - Set blockableCells = sudokuBoard.getRegion(c.getGroupIndex()); - blockableCells.addAll(sudokuBoard.getRow(c.getLocation().y)); - blockableCells.addAll(sudokuBoard.getCol(c.getLocation().x)); - - boolean repeat = false; - for (SudokuCell bc : blockableCells) { - if (bc.getData() == value) { - repeat = true; - break; - } - } - if (!repeat) { - caseCells.add(c); - } - } - } - - for (SudokuCell c : caseCells) { + for (int i = 0; i < 9; i++) { Board newCase = sudokuBoard.copy(); - PuzzleElement element = newCase.getPuzzleElement(c); + PuzzleElement element = newCase.getPuzzleElement(puzzleElement); element.setData(value); newCase.addModifiedData(element); cases.add(newCase); diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleNumberForRowCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleNumberForRowCaseRule.java new file mode 100644 index 000000000..33ca0e18e --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleNumberForRowCaseRule.java @@ -0,0 +1,96 @@ +package edu.rpi.legup.puzzle.sudoku.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.CaseBoard; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.CaseRule; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.sudoku.GroupType; +import edu.rpi.legup.puzzle.sudoku.SudokuBoard; +import edu.rpi.legup.puzzle.sudoku.SudokuCell; + +import java.util.ArrayList; +import java.util.List; + +public class PossibleNumberForRowCaseRule extends CaseRule { + + public PossibleNumberForRowCaseRule() { + super("SUDO-CASE-0003", "Possible Numbers for Row", + "An empty cell has a limited set of possible numbers that can fill it.", + "edu/rpi/legup/images/sudoku/PossibleValues.png"); + } + + /** + * Checks whether the transition logically follows from the parent node using this rule + * + * @param transition transition to check + * @return null if the child node logically follow from the parent node, otherwise error message + */ + @Override + public String checkRuleRaw(TreeTransition transition) { + return null; + } + + /** + * Checks whether the child node logically follows from the parent node + * at the specific puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified puzzleElement, + * otherwise error message + */ + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + return null; + } + + @Override + public CaseBoard getCaseBoard(Board board) { + SudokuBoard sudokuBoard = (SudokuBoard) board.copy(); + CaseBoard caseBoard = new CaseBoard(sudokuBoard, this); + for (PuzzleElement puzzleElement : sudokuBoard.getPuzzleElements()) { + if (((SudokuCell) puzzleElement).getData() == 0) { + caseBoard.addPickableElement(puzzleElement); + } + } + return caseBoard; + } + /** + * Gets the possible cases at a specific location based on this case rule + * + * @param board the current board state + * @param puzzleElement equivalent puzzleElement + * @return a list of elements the specified could be + */ + @Override + public ArrayList getCases(Board board, PuzzleElement puzzleElement) { + return getCases(board, puzzleElement, 1, GroupType.REGION); + } + + /** + * Gets the possible cases at a specific location based on this case rule + * + * @param board the current board state + * @param puzzleElement equivalent puzzleElement + * @param value value that the rule will be applied from + * @param groupType group type + * @return a list of elements the specified could be + */ + public ArrayList getCases(Board board, PuzzleElement puzzleElement, int value, GroupType groupType) { + ArrayList cases = new ArrayList<>(); + SudokuBoard sudokuBoard = (SudokuBoard) board; + List caseCells = new ArrayList<>(); + SudokuCell cell = (SudokuCell) puzzleElement; + //not sure what we would do here! + for (int i = 0; i < 9; i++) { + Board newCase = sudokuBoard.copy(); + PuzzleElement element = newCase.getPuzzleElement(puzzleElement); + element.setData(value); + newCase.addModifiedData(element); + cases.add(newCase); + } + + return cases; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/RepeatedNumberContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/RepeatedNumberContradictionRule.java index 4a5cc2074..edfe2f0cf 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/RepeatedNumberContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/RepeatedNumberContradictionRule.java @@ -37,29 +37,27 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { Set row = sudokuBoard.getRow(cell.getLocation().y); Set col = sudokuBoard.getCol(cell.getLocation().x); - Set regionDup = new HashSet<>(); - Set rowDup = new HashSet<>(); - Set colDup = new HashSet<>(); - + Set duplicates = new HashSet<>(); for (SudokuCell c : region) { - if (regionDup.contains(c.getData())) { + if (duplicates.contains(c.getData())) { return null; } - regionDup.add(c.getData()); + duplicates.add(c.getData()); } + duplicates.clear(); for (SudokuCell c : row) { - if (rowDup.contains(c.getData())) { + if (duplicates.contains(c.getData())) { return null; } - rowDup.add(c.getData()); + duplicates.add(c.getData()); } - + duplicates.clear(); for (SudokuCell c : col) { - if (colDup.contains(c.getData())) { + if (duplicates.contains(c.getData())) { return null; } - colDup.add(c.getData()); + duplicates.add(c.getData()); } return super.getNoContradictionMessage(); diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/AdvancedDeductionDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/depreciated/AdvancedDeductionDirectRule.java similarity index 96% rename from src/main/java/edu/rpi/legup/puzzle/sudoku/rules/AdvancedDeductionDirectRule.java rename to src/main/java/edu/rpi/legup/puzzle/sudoku/rules/depreciated/AdvancedDeductionDirectRule.java index 0be30fa36..00be317d9 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/AdvancedDeductionDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/depreciated/AdvancedDeductionDirectRule.java @@ -1,96 +1,96 @@ -package edu.rpi.legup.puzzle.sudoku.rules; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.DirectRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -import edu.rpi.legup.puzzle.sudoku.SudokuBoard; -import edu.rpi.legup.puzzle.sudoku.SudokuCell; - -public class AdvancedDeductionDirectRule extends DirectRule { - - public AdvancedDeductionDirectRule() { - super("SUDO-BASC-0001", "Advanced Deduction", - "Use of group logic deduces more answers by means of forced by Location and forced by Deduction", - "edu/rpi/legup/images/sudoku/AdvancedDeduction.png"); - } - - /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule - * - * @param transition transition to check - * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message - */ - public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - SudokuBoard initialBoard = (SudokuBoard) transition.getParents().get(0).getBoard(); - SudokuBoard finalBoard = (SudokuBoard) transition.getBoard(); - - SudokuCell cell = (SudokuCell) finalBoard.getPuzzleElement(puzzleElement); - int index = cell.getIndex(); - int groupSize = initialBoard.getWidth(); - int groupDim = (int) Math.sqrt(groupSize); - int rowIndex = index / groupSize; - int colIndex = index % groupSize; - int relX = rowIndex / groupDim; - int relY = colIndex % groupDim; - int groupNum = rowIndex / groupDim * groupDim + colIndex / groupDim; - boolean[][] possible = new boolean[groupDim][groupDim]; - for (int y = 0; y < groupDim; y++) { - for (int x = 0; x < groupDim; x++) { - SudokuCell c = initialBoard.getCell(groupNum, x, y); - if (c.getData() == cell.getData() && x != relX && y != relY) { - return super.getRuleName() + ": Duplicate value in sub-region"; - } - possible[y][x] = c.getData() == 0; - } - } - for (int y = 0; y < groupDim; y++) { - for (int x = 0; x < groupSize; x++) { - SudokuCell r = initialBoard.getCell(x, (groupNum / groupDim) * groupDim + y); - SudokuCell c = initialBoard.getCell((groupNum % groupDim) * groupDim + y, x); - if (r.getData() == cell.getData()) { - for (int i = 0; i < groupDim; i++) { - possible[y][i] = false; - } - } - if (c.getData() == cell.getData()) { - for (int i = 0; i < groupDim; i++) { - possible[i][y] = false; - } - } - } - } - boolean isForced = false; - for (int y = 0; y < groupDim; y++) { - for (int x = 0; x < groupDim; x++) { - if (possible[y][x] && !isForced) { - isForced = true; - } - else { - if (possible[y][x]) { - return super.getInvalidUseOfRuleMessage() + ": Not forced"; - } - } - } - } - if (!isForced) { - return super.getInvalidUseOfRuleMessage() + ": Not forced"; - } - return null; - } - - /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. - * - * @param node tree node used to create default transition board - * @return default board or null if this rule cannot be applied to this tree node - */ - @Override - public Board getDefaultBoard(TreeNode node) { - return null; - } -} +package edu.rpi.legup.puzzle.sudoku.rules.depreciated; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.sudoku.SudokuBoard; +import edu.rpi.legup.puzzle.sudoku.SudokuCell; + +public class AdvancedDeductionDirectRule extends DirectRule { + + public AdvancedDeductionDirectRule() { + super("SUDO-BASC-0001", "Advanced Deduction", + "Use of group logic deduces more answers by means of forced by Location and forced by Deduction", + "edu/rpi/legup/images/sudoku/AdvancedDeduction.png"); + } + + /** + * Checks whether the child node logically follows from the parent node + * at the specific puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified puzzleElement, + * otherwise error message + */ + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + SudokuBoard initialBoard = (SudokuBoard) transition.getParents().get(0).getBoard(); + SudokuBoard finalBoard = (SudokuBoard) transition.getBoard(); + + SudokuCell cell = (SudokuCell) finalBoard.getPuzzleElement(puzzleElement); + int index = cell.getIndex(); + int groupSize = initialBoard.getWidth(); + int groupDim = (int) Math.sqrt(groupSize); + int rowIndex = index / groupSize; + int colIndex = index % groupSize; + int relX = rowIndex / groupDim; + int relY = colIndex % groupDim; + int groupNum = rowIndex / groupDim * groupDim + colIndex / groupDim; + boolean[][] possible = new boolean[groupDim][groupDim]; + for (int y = 0; y < groupDim; y++) { + for (int x = 0; x < groupDim; x++) { + SudokuCell c = initialBoard.getCell(groupNum, x, y); + if (c.getData() == cell.getData() && x != relX && y != relY) { + return super.getRuleName() + ": Duplicate value in sub-region"; + } + possible[y][x] = c.getData() == 0; + } + } + for (int y = 0; y < groupDim; y++) { + for (int x = 0; x < groupSize; x++) { + SudokuCell r = initialBoard.getCell(x, (groupNum / groupDim) * groupDim + y); + SudokuCell c = initialBoard.getCell((groupNum % groupDim) * groupDim + y, x); + if (r.getData() == cell.getData()) { + for (int i = 0; i < groupDim; i++) { + possible[y][i] = false; + } + } + if (c.getData() == cell.getData()) { + for (int i = 0; i < groupDim; i++) { + possible[i][y] = false; + } + } + } + } + boolean isForced = false; + for (int y = 0; y < groupDim; y++) { + for (int x = 0; x < groupDim; x++) { + if (possible[y][x] && !isForced) { + isForced = true; + } + else { + if (possible[y][x]) { + return super.getInvalidUseOfRuleMessage() + ": Not forced"; + } + } + } + } + if (!isForced) { + return super.getInvalidUseOfRuleMessage() + ": Not forced"; + } + return null; + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/sudoku_reference_sheet.txt b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/sudoku_reference_sheet.txt index a8635330d..87cd4fc36 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/sudoku_reference_sheet.txt +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/sudoku_reference_sheet.txt @@ -1,6 +1,5 @@ -SUDO-BASC-0001 : AdvancedDeductionDirectRule -SUDO-BASC-0002 : LastCellForNumberDirectRule -SUDO-BASC-0003 : LastNumberForCellDirectRule +SUDO-BASC-0001 : LastCellForNumberDirectRule +SUDO-BASC-0002 : LastNumberForCellDirectRule SUDO-CONT-0001 : NoSolutionContradictionRule SUDO-CONT-0002 : RepeatedNumberContradictionRule