From 87d7ac1a33555fb75b115810f9335ea7b1d18321 Mon Sep 17 00:00:00 2001 From: Bram van Heuveln <56417002+jadeandtea@users.noreply.github.com> Date: Wed, 25 Sep 2024 21:06:35 -0400 Subject: [PATCH 1/7] Test Commit to see how reverting works --- puzzles files/nurikabe/test | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 puzzles files/nurikabe/test diff --git a/puzzles files/nurikabe/test b/puzzles files/nurikabe/test new file mode 100644 index 000000000..a94928e90 --- /dev/null +++ b/puzzles files/nurikabe/test @@ -0,0 +1,12 @@ + + + + + + + + + + + + From c04eef1b49a531ce9e29d460b5df03702df9a79b Mon Sep 17 00:00:00 2001 From: Bram van Heuveln <56417002+jadeandtea@users.noreply.github.com> Date: Wed, 25 Sep 2024 21:08:56 -0400 Subject: [PATCH 2/7] Revert "Test Commit to see how reverting works" This reverts commit 87d7ac1a33555fb75b115810f9335ea7b1d18321. --- puzzles files/nurikabe/test | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 puzzles files/nurikabe/test diff --git a/puzzles files/nurikabe/test b/puzzles files/nurikabe/test deleted file mode 100644 index a94928e90..000000000 --- a/puzzles files/nurikabe/test +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - From 476486d85d87abf4b0b25702f971981b476a2537 Mon Sep 17 00:00:00 2001 From: Bram van Heuveln <56417002+jadeandtea@users.noreply.github.com> Date: Wed, 25 Sep 2024 21:09:35 -0400 Subject: [PATCH 3/7] Test commit to see how reverting a merge works --- puzzles files/test | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 puzzles files/test diff --git a/puzzles files/test b/puzzles files/test new file mode 100644 index 000000000..e69de29bb From 1044f1cb02c64278d464a40342ef034d3c9a6fcf Mon Sep 17 00:00:00 2001 From: Bram van Heuveln <56417002+jadeandtea@users.noreply.github.com> Date: Fri, 27 Sep 2024 16:00:49 -0400 Subject: [PATCH 4/7] Revert "Test commit to see how reverting a merge works" This reverts commit 476486d85d87abf4b0b25702f971981b476a2537. --- puzzles files/test | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 puzzles files/test diff --git a/puzzles files/test b/puzzles files/test deleted file mode 100644 index e69de29bb..000000000 From e0d3b3a92e811dd7a14862fad48911eb03428b92 Mon Sep 17 00:00:00 2001 From: Bram van Heuveln Date: Fri, 27 Sep 2024 20:28:47 +0000 Subject: [PATCH 5/7] Automated Java code formatting changes --- src/main/java/edu/rpi/legup/app/Config.java | 14 +- .../edu/rpi/legup/app/GameBoardFacade.java | 37 ++-- .../rpi/legup/app/InvalidConfigException.java | 3 +- .../edu/rpi/legup/app/LegupPreferences.java | 13 +- .../edu/rpi/legup/controller/Controller.java | 5 +- .../legup/controller/CursorController.java | 5 +- .../controller/EditorElementController.java | 5 +- .../rpi/legup/controller/RuleController.java | 6 +- .../rpi/legup/controller/TreeController.java | 4 +- .../legup/history/AddTreeElementCommand.java | 13 +- .../ApplyDefaultDirectRuleCommand.java | 14 +- .../legup/history/AutoCaseRuleCommand.java | 23 ++- .../edu/rpi/legup/history/CommandError.java | 7 +- .../edu/rpi/legup/history/CommandState.java | 4 +- .../history/DeleteTreeElementCommand.java | 26 +-- .../rpi/legup/history/EditDataCommand.java | 21 +- .../java/edu/rpi/legup/history/History.java | 14 +- .../java/edu/rpi/legup/history/ICommand.java | 16 +- .../rpi/legup/history/IHistoryListener.java | 10 +- .../rpi/legup/history/IHistorySubject.java | 12 +- .../InvalidCommandStateTransition.java | 4 +- .../edu/rpi/legup/history/MergeCommand.java | 12 +- .../edu/rpi/legup/history/PuzzleCommand.java | 38 ++-- .../history/ValidateCaseRuleCommand.java | 13 +- .../ValidateContradictionRuleCommand.java | 16 +- .../history/ValidateDirectRuleCommand.java | 18 +- src/main/java/edu/rpi/legup/model/Puzzle.java | 58 +++--- .../edu/rpi/legup/model/PuzzleExporter.java | 17 +- .../edu/rpi/legup/model/PuzzleImporter.java | 22 ++- .../edu/rpi/legup/model/RegisterPuzzle.java | 4 +- .../edu/rpi/legup/model/elements/Element.java | 7 +- .../rpi/legup/model/elements/ElementType.java | 6 +- .../model/elements/NonPlaceableElement.java | 6 +- .../model/elements/PlaceableElement.java | 12 +- .../legup/model/elements/RegisterElement.java | 6 +- .../edu/rpi/legup/model/gameboard/Board.java | 5 +- .../rpi/legup/model/gameboard/CaseBoard.java | 8 +- .../rpi/legup/model/gameboard/GridCell.java | 6 +- .../rpi/legup/model/gameboard/GridRegion.java | 4 +- .../legup/model/gameboard/PuzzleElement.java | 3 +- .../legup/model/observer/IBoardListener.java | 4 +- .../legup/model/observer/IBoardSubject.java | 4 +- .../legup/model/observer/ITreeListener.java | 4 +- .../legup/model/observer/ITreeSubject.java | 4 +- .../edu/rpi/legup/model/rules/CaseRule.java | 5 +- .../legup/model/rules/ContradictionRule.java | 5 +- .../edu/rpi/legup/model/rules/DirectRule.java | 4 +- .../edu/rpi/legup/model/rules/MergeRule.java | 4 +- .../rpi/legup/model/rules/RegisterRule.java | 5 +- .../java/edu/rpi/legup/model/rules/Rule.java | 7 +- .../edu/rpi/legup/model/rules/RuleType.java | 4 +- .../java/edu/rpi/legup/model/tree/Tree.java | 7 +- .../edu/rpi/legup/model/tree/TreeElement.java | 3 +- .../rpi/legup/model/tree/TreeElementType.java | 4 +- .../edu/rpi/legup/model/tree/TreeNode.java | 10 +- .../rpi/legup/model/tree/TreeTransition.java | 7 +- .../edu/rpi/legup/puzzle/binary/Binary.java | 7 +- .../rpi/legup/puzzle/binary/BinaryBoard.java | 8 +- .../rpi/legup/puzzle/binary/BinaryCell.java | 15 +- .../legup/puzzle/binary/BinaryController.java | 11 +- .../puzzle/binary/BinaryElementView.java | 4 +- .../legup/puzzle/binary/BinaryExporter.java | 4 +- .../legup/puzzle/binary/BinaryImporter.java | 1 + .../rpi/legup/puzzle/binary/BinaryType.java | 17 +- .../rpi/legup/puzzle/binary/BinaryView.java | 7 +- .../puzzle/binary/elements/NumberTile.java | 3 +- .../puzzle/binary/elements/UnknownTile.java | 2 +- .../rules/CompleteRowColumnDirectRule.java | 4 +- .../EliminateTheImpossibleDirectRule.java | 47 ++--- .../binary/rules/PreventTrioDirectRule.java | 5 +- .../RepeatedRowColumnContradictionRule.java | 6 +- .../binary/rules/SaveBlockerDirectRule.java | 7 +- .../binary/rules/TrioContradictionRule.java | 12 +- .../UnbalancedRowColumnContradictionRule.java | 2 - .../rules/UniqueRowColumnDirectRule.java | 85 ++++---- .../rules/WastedBlockerContradictionRule.java | 24 +-- .../binary/rules/ZeroOrOneCaseRule.java | 9 +- .../puzzle/nurikabe/NurikabeController.java | 11 +- .../nurikabe/rules/FinishRoomCaseRule.java | 119 +++++++---- .../skyscrapers/SkyscrapersClueView.java | 15 +- .../rpi/legup/puzzle/sudoku/SudokuCell.java | 18 +- .../rpi/legup/puzzle/sudoku/SudokuView.java | 12 +- .../puzzle/sudoku/elements/NumberTile.java | 3 +- .../puzzle/sudoku/elements/UnknownTile.java | 2 +- .../rpi/legup/puzzle/treetent/TreeTent.java | 1 - .../edu/rpi/legup/ui/CreatePuzzleDialog.java | 34 ++-- .../java/edu/rpi/legup/ui/DynamicView.java | 12 +- .../edu/rpi/legup/ui/DynamicViewType.java | 5 +- src/main/java/edu/rpi/legup/ui/HomePanel.java | 50 ++--- .../java/edu/rpi/legup/ui/LegupPanel.java | 11 +- src/main/java/edu/rpi/legup/ui/LegupUI.java | 15 +- .../java/edu/rpi/legup/ui/PickGameDialog.java | 14 +- .../edu/rpi/legup/ui/PreferencesDialog.java | 32 ++- .../edu/rpi/legup/ui/ProofEditorPanel.java | 187 +++++++++--------- .../edu/rpi/legup/ui/PuzzleEditorPanel.java | 164 +++++++-------- .../java/edu/rpi/legup/ui/ScrollView.java | 8 +- .../java/edu/rpi/legup/ui/ToolbarName.java | 4 +- .../java/edu/rpi/legup/ui/ZoomWidget.java | 8 +- .../edu/rpi/legup/ui/boardview/BoardView.java | 9 +- .../legup/ui/boardview/DataSelectionView.java | 4 +- .../legup/ui/boardview/ElementSelection.java | 19 +- .../rpi/legup/ui/boardview/ElementView.java | 47 +++-- .../rpi/legup/ui/boardview/GridBoardView.java | 17 +- .../legup/ui/boardview/GridElementView.java | 5 +- .../legup/ui/boardview/SelectionItemView.java | 24 ++- .../rulesview/CaseRulePanel.java | 8 +- .../rulesview/ContradictionRulePanel.java | 11 +- .../rulesview/DirectRulePanel.java | 10 +- .../proofeditorui/rulesview/RuleButton.java | 6 +- .../ui/proofeditorui/rulesview/RuleFrame.java | 12 +- .../ui/proofeditorui/rulesview/RulePanel.java | 14 +- .../rulesview/SearchBarPanel.java | 6 +- .../treeview/TreeElementView.java | 7 +- .../proofeditorui/treeview/TreeNodeView.java | 47 +++-- .../ui/proofeditorui/treeview/TreePanel.java | 32 ++- .../treeview/TreeToolBarButton.java | 4 +- .../treeview/TreeToolbarPanel.java | 5 +- .../treeview/TreeTransitionView.java | 44 +++-- .../ui/proofeditorui/treeview/TreeView.java | 69 ++++--- .../treeview/TreeViewSelection.java | 6 +- .../elementsview/ElementFrame.java | 21 +- .../NonPlaceableElementPanel.java | 8 +- src/test/java/legup/TestUtilities.java | 4 +- .../rules/FinishRoomCaseRuleTest.java | 8 +- 124 files changed, 1013 insertions(+), 1037 deletions(-) diff --git a/src/main/java/edu/rpi/legup/app/Config.java b/src/main/java/edu/rpi/legup/app/Config.java index 1016838c7..b04ef9b88 100644 --- a/src/main/java/edu/rpi/legup/app/Config.java +++ b/src/main/java/edu/rpi/legup/app/Config.java @@ -13,9 +13,9 @@ import org.xml.sax.SAXException; /** - * The {@code Config} class manages the configuration for puzzles by loading configuration data - * from an XML file. It provides methods to access puzzle class names, display names, and their - * file creation statuses + * The {@code Config} class manages the configuration for puzzles by loading configuration data from + * an XML file. It provides methods to access puzzle class names, display names, and their file + * creation statuses */ public class Config { private static final Logger Logger = LogManager.getLogger(Config.class.getName()); @@ -80,8 +80,8 @@ public static String convertClassNameToDisplayName(String className) { } /** - * Converts the display name of the puzzle back to its corresponding class name. - * For example: convertDisplayNameToClassName("Tree Tent") returns "TreeTent" + * Converts the display name of the puzzle back to its corresponding class name. For example: + * convertDisplayNameToClassName("Tree Tent") returns "TreeTent" * * @param displayName the display name of the puzzle * @return the class name of the puzzle as a String @@ -110,8 +110,8 @@ public List getPuzzleNames() { } /** - * Returns a list of the display names of the puzzles that can have files created and edited within - * the proof editor + * Returns a list of the display names of the puzzles that can have files created and edited + * within the proof editor * * @return a List of puzzle display names as Strings with file creation enabled */ diff --git a/src/main/java/edu/rpi/legup/app/GameBoardFacade.java b/src/main/java/edu/rpi/legup/app/GameBoardFacade.java index 835041c3c..c6f92e5b5 100644 --- a/src/main/java/edu/rpi/legup/app/GameBoardFacade.java +++ b/src/main/java/edu/rpi/legup/app/GameBoardFacade.java @@ -32,8 +32,9 @@ import org.xml.sax.SAXException; /** - * {@code GameBoardFacade} is a class designed to manage the game board operations within the application. - * It integrates various components such as UI elements, puzzle management, and history tracking + * {@code GameBoardFacade} is a class designed to manage the game board operations within the + * application. It integrates various components such as UI elements, puzzle management, and history + * tracking */ public class GameBoardFacade implements IHistorySubject { private static final Logger LOGGER = LogManager.getLogger(GameBoardFacade.class.getName()); @@ -76,9 +77,7 @@ public static synchronized GameBoardFacade getInstance() { return instance; } - /** - * Initializes the UI components - */ + /** Initializes the UI components */ public void initializeUI() { EventQueue.invokeLater( () -> { @@ -101,18 +100,14 @@ public void setPuzzle(Puzzle puzzle) { this.history.clear(); } - /** - * Clears the current puzzle - */ + /** Clears the current puzzle */ public void clearPuzzle() { this.puzzle = null; this.curFileName = null; this.history.clear(); } - /** - * Sets up the configuration by initializing the Config object - */ + /** Sets up the configuration by initializing the Config object */ public static void setupConfig() { Config config = null; try { @@ -203,7 +198,7 @@ public boolean validateTextInput(String game, String[] statements) throws Runtim * @param columns the number of columns on the board */ public void loadPuzzle(String game, int rows, int columns) throws RuntimeException { - if (!game.equals("")) { + if (!game.isEmpty()) { String qualifiedClassName = config.getPuzzleClassForName(game); LOGGER.debug("Loading " + qualifiedClassName); @@ -235,15 +230,14 @@ public void loadPuzzle(String game, int rows, int columns) throws RuntimeExcepti } catch (IllegalArgumentException exception) { throw new IllegalArgumentException(exception.getMessage()); } catch (ClassNotFoundException - | NoSuchMethodException - | InvocationTargetException - | IllegalAccessException - | InstantiationException e) { + | NoSuchMethodException + | InvocationTargetException + | IllegalAccessException + | InstantiationException e) { LOGGER.error(e); throw new RuntimeException("Puzzle creation error"); } } - } /** @@ -297,7 +291,8 @@ public void loadPuzzle(String game, String[] statements) { * Loads a puzzle file from the specified file * * @param fileName file name of the board file - * @throws InvalidFileFormatException if the file format is invalid or if the file cannot be created + * @throws InvalidFileFormatException if the file format is invalid or if the file cannot be + * created */ public void loadPuzzle(String fileName) throws InvalidFileFormatException { try { @@ -314,7 +309,8 @@ public void loadPuzzle(String fileName) throws InvalidFileFormatException { * Loads a puzzle into the editor from the specified file name * * @param fileName the name of the file to load - * @throws InvalidFileFormatException if the file format is invalid or if the file cannot be created + * @throws InvalidFileFormatException if the file format is invalid or if the file cannot be + * created */ public void loadPuzzleEditor(String fileName) throws InvalidFileFormatException { try { @@ -331,7 +327,8 @@ public void loadPuzzleEditor(String fileName) throws InvalidFileFormatException * Loads a puzzle into the editor from the specified input stream * * @param inputStream the input stream to load the puzzle from - * @throws InvalidFileFormatException if the input stream cannot be processed or the file format is invalid + * @throws InvalidFileFormatException if the input stream cannot be processed or the file format + * is invalid */ public void loadPuzzleEditor(InputStream inputStream) throws InvalidFileFormatException { Document document; diff --git a/src/main/java/edu/rpi/legup/app/InvalidConfigException.java b/src/main/java/edu/rpi/legup/app/InvalidConfigException.java index c66b23ec2..cad80b5ce 100644 --- a/src/main/java/edu/rpi/legup/app/InvalidConfigException.java +++ b/src/main/java/edu/rpi/legup/app/InvalidConfigException.java @@ -1,7 +1,8 @@ package edu.rpi.legup.app; /** - * {@code InvalidConfigException} is a custom exception class for handling invalid configuration errors + * {@code InvalidConfigException} is a custom exception class for handling invalid configuration + * errors */ public class InvalidConfigException extends Exception { /** diff --git a/src/main/java/edu/rpi/legup/app/LegupPreferences.java b/src/main/java/edu/rpi/legup/app/LegupPreferences.java index 03b8be8d9..3d17233bd 100644 --- a/src/main/java/edu/rpi/legup/app/LegupPreferences.java +++ b/src/main/java/edu/rpi/legup/app/LegupPreferences.java @@ -5,8 +5,9 @@ import java.util.prefs.Preferences; /** - * {@code LegupPreferences} is a class responsible for managing user preferences within the application. - * It uses Java's Preferences API to store and retrieve preferences, and it provides methods for accessing and updating these preferences. + * {@code LegupPreferences} is a class responsible for managing user preferences within the + * application. It uses Java's Preferences API to store and retrieve preferences, and it provides + * methods for accessing and updating these preferences. */ public class LegupPreferences { @@ -77,8 +78,8 @@ public class LegupPreferences { } /** - * Gets the legup preferences singleton instance - * This method ensures that only one instance of LegupPreferences exists + * Gets the legup preferences singleton instance This method ensures that only one instance of + * LegupPreferences exists * * @return the singleton instance of LegupPreferences */ @@ -90,8 +91,8 @@ public static LegupPreferences getInstance() { } /** - * Private constructor to prevent instantiation from outside the class - * Use {@link #getInstance()} to access the singleton instance + * Private constructor to prevent instantiation from outside the class Use {@link + * #getInstance()} to access the singleton instance */ private LegupPreferences() {} diff --git a/src/main/java/edu/rpi/legup/controller/Controller.java b/src/main/java/edu/rpi/legup/controller/Controller.java index 47ef70e17..823bac716 100644 --- a/src/main/java/edu/rpi/legup/controller/Controller.java +++ b/src/main/java/edu/rpi/legup/controller/Controller.java @@ -6,8 +6,9 @@ import javax.swing.*; /** - * {@code Controller} is an abstract class designed to handle various mouse events and provide control functionality for a {@code ScrollView}. - * It implements several mouse event interfaces to manage interactions such as panning and zooming within a {@code ScrollView} + * {@code Controller} is an abstract class designed to handle various mouse events and provide + * control functionality for a {@code ScrollView}. It implements several mouse event interfaces to + * manage interactions such as panning and zooming within a {@code ScrollView} */ public abstract class Controller implements MouseMotionListener, MouseListener, MouseWheelListener { protected ScrollView viewer; diff --git a/src/main/java/edu/rpi/legup/controller/CursorController.java b/src/main/java/edu/rpi/legup/controller/CursorController.java index 6a3ab018d..aad7eaf46 100644 --- a/src/main/java/edu/rpi/legup/controller/CursorController.java +++ b/src/main/java/edu/rpi/legup/controller/CursorController.java @@ -7,8 +7,9 @@ import java.util.TimerTask; /** - * {@code CursorController} provides functionality for managing the cursor appearance during actions that take a certain amount of time. - * It allows for the display of a busy cursor while an action is being processed and reverts to the default cursor afterward + * {@code CursorController} provides functionality for managing the cursor appearance during actions + * that take a certain amount of time. It allows for the display of a busy cursor while an action is + * being processed and reverts to the default cursor afterward */ public class CursorController { public static final Cursor BUSY_CURSOR = new Cursor(Cursor.WAIT_CURSOR); diff --git a/src/main/java/edu/rpi/legup/controller/EditorElementController.java b/src/main/java/edu/rpi/legup/controller/EditorElementController.java index 040610137..050f5bd65 100644 --- a/src/main/java/edu/rpi/legup/controller/EditorElementController.java +++ b/src/main/java/edu/rpi/legup/controller/EditorElementController.java @@ -10,8 +10,9 @@ import javax.swing.*; /** - * {@code EditorElementController} manages actions related to UI elements within the puzzle editor environment. - * It handles button presses, updates element selection, and manages visual states of buttons + * {@code EditorElementController} manages actions related to UI elements within the puzzle editor + * environment. It handles button presses, updates element selection, and manages visual states of + * buttons */ public class EditorElementController implements ActionListener { protected Object lastSource; diff --git a/src/main/java/edu/rpi/legup/controller/RuleController.java b/src/main/java/edu/rpi/legup/controller/RuleController.java index 491e02f74..df4def59e 100644 --- a/src/main/java/edu/rpi/legup/controller/RuleController.java +++ b/src/main/java/edu/rpi/legup/controller/RuleController.java @@ -17,9 +17,9 @@ import java.util.List; /** - * The RuleController class is responsible for handling UI events related to rule buttons - * in the RulePanel of the Legup application. It implements ActionListener to process action - * events triggered by rule buttons and applies rules to the puzzle accordingly + * The RuleController class is responsible for handling UI events related to rule buttons in the + * RulePanel of the Legup application. It implements ActionListener to process action events + * triggered by rule buttons and applies rules to the puzzle accordingly */ public class RuleController implements ActionListener { protected Object lastSource; diff --git a/src/main/java/edu/rpi/legup/controller/TreeController.java b/src/main/java/edu/rpi/legup/controller/TreeController.java index 2b12268ac..6e4ce9fd9 100644 --- a/src/main/java/edu/rpi/legup/controller/TreeController.java +++ b/src/main/java/edu/rpi/legup/controller/TreeController.java @@ -12,8 +12,8 @@ import javax.swing.*; /** - * The TreeController class handles UI events from a TreePanel. - * It extends the Controller class to provide specific behavior for tree interactions + * The TreeController class handles UI events from a TreePanel. It extends the Controller class to + * provide specific behavior for tree interactions */ public class TreeController extends Controller { /** diff --git a/src/main/java/edu/rpi/legup/history/AddTreeElementCommand.java b/src/main/java/edu/rpi/legup/history/AddTreeElementCommand.java index 92a887f71..421cea438 100644 --- a/src/main/java/edu/rpi/legup/history/AddTreeElementCommand.java +++ b/src/main/java/edu/rpi/legup/history/AddTreeElementCommand.java @@ -10,10 +10,9 @@ import java.util.List; import java.util.Map; - /** - * The AddTreeElementCommand class represents a command to add tree elements to the proof tree. - * It extends the PuzzleCommand class to handle the addition of tree elements and undo operation. + * The AddTreeElementCommand class represents a command to add tree elements to the proof tree. It + * extends the PuzzleCommand class to handle the addition of tree elements and undo operation. */ public class AddTreeElementCommand extends PuzzleCommand { @@ -33,8 +32,8 @@ public AddTreeElementCommand(TreeViewSelection selection) { } /** - * Executes the command to add selected tree elements to the tree. - * Updates the puzzle and tree view accordingly + * Executes the command to add selected tree elements to the tree. Updates the puzzle and tree + * view accordingly */ @Override public void executeCommand() { @@ -104,8 +103,8 @@ public String getErrorString() { } /** - * Undoes the command by removing the added tree elements. - * Updates the puzzle and tree view accordingly + * Undoes the command by removing the added tree elements. Updates the puzzle and tree view + * accordingly */ @Override public void undoCommand() { diff --git a/src/main/java/edu/rpi/legup/history/ApplyDefaultDirectRuleCommand.java b/src/main/java/edu/rpi/legup/history/ApplyDefaultDirectRuleCommand.java index ad89ab636..e3e89ddd0 100644 --- a/src/main/java/edu/rpi/legup/history/ApplyDefaultDirectRuleCommand.java +++ b/src/main/java/edu/rpi/legup/history/ApplyDefaultDirectRuleCommand.java @@ -11,9 +11,9 @@ import java.util.Map; /** - * The ApplyDefaultDirectRuleCommand class represents a command to apply a default direct rule - * to selected tree nodes in the proof tree. - * It extends the PuzzleCommand class to handle rule application and undo operation. + * The ApplyDefaultDirectRuleCommand class represents a command to apply a default direct rule to + * selected tree nodes in the proof tree. It extends the PuzzleCommand class to handle rule + * application and undo operation. */ public class ApplyDefaultDirectRuleCommand extends PuzzleCommand { @@ -75,8 +75,8 @@ public String getErrorString() { } /** - * Executes the command to apply the default rule to the selected tree nodes. - * Updates the puzzle and tree view accordingly. + * Executes the command to apply the default rule to the selected tree nodes. Updates the puzzle + * and tree view accordingly. */ @Override public void executeCommand() { @@ -118,8 +118,8 @@ public void executeCommand() { } /** - * Undoes the command by removing the applied default rule from the tree nodes. - * Updates the puzzle and tree view accordingly. + * Undoes the command by removing the applied default rule from the tree nodes. Updates the + * puzzle and tree view accordingly. */ @Override public void undoCommand() { diff --git a/src/main/java/edu/rpi/legup/history/AutoCaseRuleCommand.java b/src/main/java/edu/rpi/legup/history/AutoCaseRuleCommand.java index b86cda6ea..4717b25ae 100644 --- a/src/main/java/edu/rpi/legup/history/AutoCaseRuleCommand.java +++ b/src/main/java/edu/rpi/legup/history/AutoCaseRuleCommand.java @@ -15,8 +15,8 @@ /** * The AutoCaseRuleCommand class represents a command to automatically apply a case rule to a - * selected tree node in the proof tree. - * It extends the PuzzleCommand class to handle case rule application and undo operation. + * selected tree node in the proof tree. It extends the PuzzleCommand class to handle case rule + * application and undo operation. */ public class AutoCaseRuleCommand extends PuzzleCommand { @@ -52,8 +52,8 @@ public AutoCaseRuleCommand( } /** - * Executes the command to apply the case rule to the selected tree node. - * Updates the puzzle and tree view accordingly. + * Executes the command to apply the case rule to the selected tree node. Updates the puzzle and + * tree view accordingly. */ @Override public void executeCommand() { @@ -64,10 +64,11 @@ public void executeCommand() { TreeNode node = (TreeNode) selection.getFirstSelection().getTreeElement(); if (caseTrans.isEmpty()) { - List cases = caseRule.getCases(caseBoard.getBaseBoard(), elementView.getPuzzleElement()); + List cases = + caseRule.getCases(caseBoard.getBaseBoard(), elementView.getPuzzleElement()); for (Board board : cases) { final TreeTransition transition = (TreeTransition) tree.addTreeElement(node); - //board.setModifiable(false); + // board.setModifiable(false); transition.setBoard(board); transition.setRule(caseRule); transition.setSelection(elementView.getPuzzleElement().copy()); @@ -118,11 +119,13 @@ public String getErrorString() { return "The selected data element is not pickable with this case rule."; } - if (caseRule.getCases(caseBoard.getBaseBoard(), elementView.getPuzzleElement()).size() == 0) { + if (caseRule.getCases(caseBoard.getBaseBoard(), elementView.getPuzzleElement()).size() + == 0) { return "The selection must produce at least one case"; } - int numberOfCaseRules = caseRule.getCases(caseBoard.getBaseBoard(), elementView.getPuzzleElement()).size(); + int numberOfCaseRules = + caseRule.getCases(caseBoard.getBaseBoard(), elementView.getPuzzleElement()).size(); System.out.println("Number of cases:" + numberOfCaseRules); if (numberOfCaseRules > caseRule.MAX_CASES) { return "The selection can produce a max of " + caseRule.MAX_CASES + " cases"; @@ -135,8 +138,8 @@ public String getErrorString() { } /** - * Undoes the command by removing the applied case rules from the tree node. - * Updates the puzzle and tree view accordingly + * Undoes the command by removing the applied case rules from the tree node. Updates the puzzle + * and tree view accordingly */ @Override public void undoCommand() { diff --git a/src/main/java/edu/rpi/legup/history/CommandError.java b/src/main/java/edu/rpi/legup/history/CommandError.java index 26959cccd..78027f6ab 100644 --- a/src/main/java/edu/rpi/legup/history/CommandError.java +++ b/src/main/java/edu/rpi/legup/history/CommandError.java @@ -2,15 +2,16 @@ /** * The CommandError enum represents various error conditions that can occur when executing or - * validating commands related to tree elements in the proof tree. - * Each error condition is associated with a descriptive message. + * validating commands related to tree elements in the proof tree. Each error condition is + * associated with a descriptive message. */ public enum CommandError { NO_SELECTED_VIEWS("The selection does not have any tree elements."), ONE_SELECTED_VIEW("The selection must have exactly one tree element."), UNMODIFIABLE_BOARD("The selection contains a board which is not modifiable."), UNMODIFIABLE_DATA("The selection contains a board where the data element is not modifiable."), - UNMODIFIABLE_DATA_CASE_RULE("The proof tree contains a future case rule, causing previous transitions to become unmodifiable."), + UNMODIFIABLE_DATA_CASE_RULE( + "The proof tree contains a future case rule, causing previous transitions to become unmodifiable."), CONTAINS_ROOT("The selection contains the root tree node."), ONE_CHILD("The selection contains a tree node that does not have exactly one child."), ADD_WITH_CHILD("The selection contains a tree transition that already has a child tree node."), diff --git a/src/main/java/edu/rpi/legup/history/CommandState.java b/src/main/java/edu/rpi/legup/history/CommandState.java index 326490e28..b72f15480 100644 --- a/src/main/java/edu/rpi/legup/history/CommandState.java +++ b/src/main/java/edu/rpi/legup/history/CommandState.java @@ -1,8 +1,8 @@ package edu.rpi.legup.history; /** - * The CommandState enum represents the various states that a command can be in during its lifecycle. - * Each state is associated with a descriptive name. + * The CommandState enum represents the various states that a command can be in during its + * lifecycle. Each state is associated with a descriptive name. */ public enum CommandState { CREATED("Created"), diff --git a/src/main/java/edu/rpi/legup/history/DeleteTreeElementCommand.java b/src/main/java/edu/rpi/legup/history/DeleteTreeElementCommand.java index e82197898..bfd9cd7f5 100644 --- a/src/main/java/edu/rpi/legup/history/DeleteTreeElementCommand.java +++ b/src/main/java/edu/rpi/legup/history/DeleteTreeElementCommand.java @@ -8,9 +8,9 @@ import java.util.List; /** - * The DeleteTreeElementCommand class represents a command to delete tree elements from a proof tree. - * It extends PuzzleCommand and implements the functionality to remove selected tree elements and - * handle undo operations. + * The DeleteTreeElementCommand class represents a command to delete tree elements from a proof + * tree. It extends PuzzleCommand and implements the functionality to remove selected tree elements + * and handle undo operations. */ public class DeleteTreeElementCommand extends PuzzleCommand { private TreeViewSelection selection; @@ -25,9 +25,7 @@ public DeleteTreeElementCommand(TreeViewSelection selection) { this.selection = selection.copy(); } - /** - * Executes the delete command, removing the selected tree elements from the tree. - */ + /** Executes the delete command, removing the selected tree elements from the tree. */ @Override public void executeCommand() { Tree tree = GameBoardFacade.getInstance().getTree(); @@ -41,11 +39,13 @@ public void executeCommand() { TreeElementView firstSelectedView = selectedViews.get(0); TreeElementView newSelectedView; if (firstSelectedView.getType() == TreeElementType.NODE) { - //System.out.println("FIRST SELECTION NODE, total selection views: " + selectedViews.size()); + // System.out.println("FIRST SELECTION NODE, total selection views: " + + // selectedViews.size()); TreeNodeView nodeView = (TreeNodeView) firstSelectedView; newSelectedView = nodeView.getParentView(); } else { - //System.out.println("FIRST SELECTION TRANS, total selection views: " + selectedViews.size()); + // System.out.println("FIRST SELECTION TRANS, total selection views: " + + // selectedViews.size()); TreeTransitionView transitionView = (TreeTransitionView) firstSelectedView; newSelectedView = transitionView.getParentViews().get(0); } @@ -58,8 +58,10 @@ public void executeCommand() { } final TreeViewSelection newSelection = new TreeViewSelection(newSelectedView); - puzzle.notifyBoardListeners(listener -> listener.onTreeElementChanged(newSelectedView.getTreeElement())); - puzzle.notifyTreeListeners((ITreeListener listener) -> listener.onTreeSelectionChanged(newSelection)); + puzzle.notifyBoardListeners( + listener -> listener.onTreeElementChanged(newSelectedView.getTreeElement())); + puzzle.notifyTreeListeners( + (ITreeListener listener) -> listener.onTreeSelectionChanged(newSelection)); } /** @@ -84,9 +86,7 @@ public String getErrorString() { return null; } - /** - * Undoes the delete command, re-adding the previously deleted tree elements. - */ + /** Undoes the delete command, re-adding the previously deleted tree elements. */ @Override public void undoCommand() { Puzzle puzzle = GameBoardFacade.getInstance().getPuzzleModule(); diff --git a/src/main/java/edu/rpi/legup/history/EditDataCommand.java b/src/main/java/edu/rpi/legup/history/EditDataCommand.java index a629aa085..0d51cc717 100644 --- a/src/main/java/edu/rpi/legup/history/EditDataCommand.java +++ b/src/main/java/edu/rpi/legup/history/EditDataCommand.java @@ -11,16 +11,15 @@ import edu.rpi.legup.ui.boardview.ElementView; import edu.rpi.legup.ui.lookandfeel.materialdesign.MaterialColors; import edu.rpi.legup.ui.proofeditorui.treeview.*; - -import javax.swing.*; import java.awt.*; import java.awt.event.MouseEvent; import java.util.List; +import javax.swing.*; /** - * The EditDataCommand class represents a command to edit the data of a puzzle element within - * a tree transition. It extends PuzzleCommand and provides functionality to execute and undo - * changes made to puzzle elements. + * The EditDataCommand class represents a command to edit the data of a puzzle element within a tree + * transition. It extends PuzzleCommand and provides functionality to execute and undo changes made + * to puzzle elements. */ public class EditDataCommand extends PuzzleCommand { private TreeTransition transition; @@ -47,9 +46,7 @@ public EditDataCommand(ElementView elementView, TreeViewSelection selection, Mou this.transition = null; } - /** - * Executes the edit data command, modifying the puzzle element and propagating changes - */ + /** Executes the edit data command, modifying the puzzle element and propagating changes */ @SuppressWarnings("unchecked") @Override public void executeCommand() { @@ -142,9 +139,7 @@ public String getErrorString() { return null; } - /** - * Causes the TreeView background to flash red for a short duration when an error occurs. - */ + /** Causes the TreeView background to flash red for a short duration when an error occurs. */ private void flashTreeViewRed() { TreeView treeView = getInstance().getLegupUI().getTreePanel().getTreeView(); Color originalColor = treeView.getBackground(); @@ -154,9 +149,7 @@ private void flashTreeViewRed() { timer.start(); } - /** - * Undoes the edit data command, restoring the previous state of the puzzle element. - */ + /** Undoes the edit data command, restoring the previous state of the puzzle element. */ @SuppressWarnings("unchecked") @Override public void undoCommand() { diff --git a/src/main/java/edu/rpi/legup/history/History.java b/src/main/java/edu/rpi/legup/history/History.java index b244e8f88..9eaeb3e75 100644 --- a/src/main/java/edu/rpi/legup/history/History.java +++ b/src/main/java/edu/rpi/legup/history/History.java @@ -7,8 +7,9 @@ import org.apache.logging.log4j.Logger; /** - * The History class manages a stack of commands for undo and redo operations on the board and tree structure. - * It maintains a list of commands and a current index to track the position in the history stack. + * The History class manages a stack of commands for undo and redo operations on the board and tree + * structure. It maintains a list of commands and a current index to track the position in the + * history stack. */ public class History { private static final Logger LOGGER = LogManager.getLogger(History.class.getName()); @@ -18,8 +19,8 @@ public class History { private int curIndex; /** - * Constructs a History object to keep track of changes and allow undo and redo operations. - * The history is implemented as a stack, with curIndex pointing to the top of the stack. + * Constructs a History object to keep track of changes and allow undo and redo operations. The + * history is implemented as a stack, with curIndex pointing to the top of the stack. */ public History() { history = new ArrayList<>(); @@ -58,7 +59,6 @@ public void undo() { command.undo(); LOGGER.info("Undoed " + command.getClass().getSimpleName()); - GameBoardFacade.getInstance() .notifyHistoryListeners( l -> l.onUndo(curIndex < 0, curIndex == history.size() - 1)); @@ -83,9 +83,7 @@ public void redo() { } } - /** - * Clears all actions from the history stack and resets the current index - */ + /** Clears all actions from the history stack and resets the current index */ public void clear() { history.clear(); curIndex = -1; diff --git a/src/main/java/edu/rpi/legup/history/ICommand.java b/src/main/java/edu/rpi/legup/history/ICommand.java index 4f867dbab..fe10bd693 100644 --- a/src/main/java/edu/rpi/legup/history/ICommand.java +++ b/src/main/java/edu/rpi/legup/history/ICommand.java @@ -1,13 +1,11 @@ package edu.rpi.legup.history; /** - * The ICommand interface defines the structure for command objects in a command pattern. - * It provides methods to execute, undo, redo commands, and to check if a command can be executed. + * The ICommand interface defines the structure for command objects in a command pattern. It + * provides methods to execute, undo, redo commands, and to check if a command can be executed. */ public interface ICommand { - /** - * Executes the command. The specific behavior depends on the implementation - */ + /** Executes the command. The specific behavior depends on the implementation */ void execute(); /** @@ -25,13 +23,9 @@ public interface ICommand { */ String getError(); - /** - * Undoes the command. Reverts the changes made by the execute method - */ + /** Undoes the command. Reverts the changes made by the execute method */ void undo(); - /** - * Redoes the command. Re-applies the changes made by the execute method after undoing - */ + /** Redoes the command. Re-applies the changes made by the execute method after undoing */ void redo(); } diff --git a/src/main/java/edu/rpi/legup/history/IHistoryListener.java b/src/main/java/edu/rpi/legup/history/IHistoryListener.java index 48690168d..a752cd53a 100644 --- a/src/main/java/edu/rpi/legup/history/IHistoryListener.java +++ b/src/main/java/edu/rpi/legup/history/IHistoryListener.java @@ -1,9 +1,9 @@ package edu.rpi.legup.history; /** - * The IHistoryListener interface defines methods for listening to changes in the history of commands. - * Implementations of this interface can respond to events related to command history such as pushing, - * undoing, redoing commands, and clearing the history. + * The IHistoryListener interface defines methods for listening to changes in the history of + * commands. Implementations of this interface can respond to events related to command history such + * as pushing, undoing, redoing commands, and clearing the history. */ public interface IHistoryListener { @@ -30,8 +30,6 @@ public interface IHistoryListener { */ void onRedo(boolean isBottom, boolean isTop); - /** - * Called when the history stack is cleared. - */ + /** Called when the history stack is cleared. */ void onClearHistory(); } diff --git a/src/main/java/edu/rpi/legup/history/IHistorySubject.java b/src/main/java/edu/rpi/legup/history/IHistorySubject.java index 431adbb93..b526c7cf3 100644 --- a/src/main/java/edu/rpi/legup/history/IHistorySubject.java +++ b/src/main/java/edu/rpi/legup/history/IHistorySubject.java @@ -3,9 +3,9 @@ import java.util.function.Consumer; /** - * The IHistorySubject interface defines methods for managing and notifying listeners - * about changes in the command history. Implementations of this interface can add, remove, - * and notify history listeners. + * The IHistorySubject interface defines methods for managing and notifying listeners about changes + * in the command history. Implementations of this interface can add, remove, and notify history + * listeners. */ public interface IHistorySubject { @@ -17,7 +17,8 @@ public interface IHistorySubject { void addHistoryListener(IHistoryListener listener); /** - * Removes a history listener, so it no longer receives updates about changes in the command history. + * Removes a history listener, so it no longer receives updates about changes in the command + * history. * * @param listener the listener to remove */ @@ -26,7 +27,8 @@ public interface IHistorySubject { /** * Notifies all registered listeners about a change in the command history. * - * @param algorithm a Consumer function that takes an IHistoryListener and performs some action with it + * @param algorithm a Consumer function that takes an IHistoryListener and performs some action + * with it */ void notifyHistoryListeners(Consumer algorithm); } diff --git a/src/main/java/edu/rpi/legup/history/InvalidCommandStateTransition.java b/src/main/java/edu/rpi/legup/history/InvalidCommandStateTransition.java index 201babb9e..0e1ba1b0d 100644 --- a/src/main/java/edu/rpi/legup/history/InvalidCommandStateTransition.java +++ b/src/main/java/edu/rpi/legup/history/InvalidCommandStateTransition.java @@ -1,8 +1,8 @@ package edu.rpi.legup.history; /** - * The InvalidCommandStateTransition exception is thrown when an invalid state transition - * is attempted on a PuzzleCommand + * The InvalidCommandStateTransition exception is thrown when an invalid state transition is + * attempted on a PuzzleCommand */ public class InvalidCommandStateTransition extends RuntimeException { diff --git a/src/main/java/edu/rpi/legup/history/MergeCommand.java b/src/main/java/edu/rpi/legup/history/MergeCommand.java index c2851bced..2d180465b 100644 --- a/src/main/java/edu/rpi/legup/history/MergeCommand.java +++ b/src/main/java/edu/rpi/legup/history/MergeCommand.java @@ -11,8 +11,8 @@ import java.util.Set; /** - * The MergeCommand class represents a command to merge selected tree nodes into a single node - * and create a transition to represent the merge + * The MergeCommand class represents a command to merge selected tree nodes into a single node and + * create a transition to represent the merge */ public class MergeCommand extends PuzzleCommand { private TreeViewSelection selection; @@ -28,9 +28,7 @@ public MergeCommand(TreeViewSelection selection) { this.transition = null; } - /** - * Executes the merge command - */ + /** Executes the merge command */ @Override public void executeCommand() { List selectedViews = selection.getSelectedViews(); @@ -77,9 +75,7 @@ public void executeCommand() { puzzle.notifyTreeListeners(listener -> listener.onTreeSelectionChanged(newSelection)); } - /** - * Undoes the merge command - */ + /** Undoes the merge command */ @Override public void undoCommand() { Tree tree = GameBoardFacade.getInstance().getTree(); diff --git a/src/main/java/edu/rpi/legup/history/PuzzleCommand.java b/src/main/java/edu/rpi/legup/history/PuzzleCommand.java index d4385b3e8..54e58c667 100644 --- a/src/main/java/edu/rpi/legup/history/PuzzleCommand.java +++ b/src/main/java/edu/rpi/legup/history/PuzzleCommand.java @@ -1,27 +1,23 @@ package edu.rpi.legup.history; /** - * The PuzzleCommand class is an abstract base class for commands that can be executed, undone, and redone - * within the puzzle model. It implements the ICommand interface and maintains the state and error handling - * for the command. + * The PuzzleCommand class is an abstract base class for commands that can be executed, undone, and + * redone within the puzzle model. It implements the ICommand interface and maintains the state and + * error handling for the command. */ public abstract class PuzzleCommand implements ICommand { private CommandState state; private boolean isCached; private String cachedError; - /** - * Puzzle Command Constructor for creating an undoable and redoable change to the model - */ + /** Puzzle Command Constructor for creating an undoable and redoable change to the model */ protected PuzzleCommand() { this.state = CommandState.CREATED; this.isCached = false; this.cachedError = null; } - /** - * Executes the command if it can be executed - */ + /** Executes the command if it can be executed */ @Override public final void execute() { if (canExecute()) { @@ -30,9 +26,7 @@ public final void execute() { } } - /** - * Determines whether the command can be executed by checking the error state - */ + /** Determines whether the command can be executed by checking the error state */ @Override public final boolean canExecute() { cachedError = getError(); @@ -64,20 +58,18 @@ public final String getError() { public abstract String getErrorString(); /** - * Executes the command. - * This method must be implemented by subclasses to define the command's execution behavior. + * Executes the command. This method must be implemented by subclasses to define the command's + * execution behavior. */ public abstract void executeCommand(); /** - * Undoes the command. - * This method must be implemented by subclasses to define the command's undo behavior. + * Undoes the command. This method must be implemented by subclasses to define the command's + * undo behavior. */ public abstract void undoCommand(); - /** - * Redoes the command. This method is called if the command was previously undone. - */ + /** Redoes the command. This method is called if the command was previously undone. */ public void redoCommand() { if (state == CommandState.UNDOED) { executeCommand(); @@ -87,9 +79,7 @@ public void redoCommand() { } } - /** - * Undoes the command if it was executed or redone - */ + /** Undoes the command if it was executed or redone */ @Override public final void undo() { if (state == CommandState.EXECUTED || state == CommandState.REDOED) { @@ -100,9 +90,7 @@ public final void undo() { } } - /** - * Redoes the command if it was previously undone. - */ + /** Redoes the command if it was previously undone. */ public final void redo() { if (state == CommandState.UNDOED) { redoCommand(); diff --git a/src/main/java/edu/rpi/legup/history/ValidateCaseRuleCommand.java b/src/main/java/edu/rpi/legup/history/ValidateCaseRuleCommand.java index 6827436e8..3f534bcda 100644 --- a/src/main/java/edu/rpi/legup/history/ValidateCaseRuleCommand.java +++ b/src/main/java/edu/rpi/legup/history/ValidateCaseRuleCommand.java @@ -13,8 +13,8 @@ import java.util.Map; /** - * The ValidateCaseRuleCommand class represents a command for validating a CaseRule in the tree structure. - * It extends the PuzzleCommand class and implements the ICommand interface. + * The ValidateCaseRuleCommand class represents a command for validating a CaseRule in the tree + * structure. It extends the PuzzleCommand class and implements the ICommand interface. */ public class ValidateCaseRuleCommand extends PuzzleCommand { @@ -37,9 +37,7 @@ public ValidateCaseRuleCommand(TreeViewSelection selection, CaseRule caseRule) { this.addNode = new HashMap<>(); } - /** - * Executes the command to validate the CaseRule - */ + /** Executes the command to validate the CaseRule */ @Override public void executeCommand() { Tree tree = getInstance().getTree(); @@ -111,10 +109,7 @@ public String getErrorString() { return null; } - - /** - * Undoes the validation command, restoring the previous state - */ + /** Undoes the validation command, restoring the previous state */ @Override public void undoCommand() { Puzzle puzzle = GameBoardFacade.getInstance().getPuzzleModule(); diff --git a/src/main/java/edu/rpi/legup/history/ValidateContradictionRuleCommand.java b/src/main/java/edu/rpi/legup/history/ValidateContradictionRuleCommand.java index b106a6072..0a8b9414f 100644 --- a/src/main/java/edu/rpi/legup/history/ValidateContradictionRuleCommand.java +++ b/src/main/java/edu/rpi/legup/history/ValidateContradictionRuleCommand.java @@ -11,8 +11,9 @@ import java.util.Map; /** - * The ValidateContradictionRuleCommand class represents a command for validating and applying a ContradictionRule - * within a tree structure. It extends the PuzzleCommand class and implements the ICommand interface. + * The ValidateContradictionRuleCommand class represents a command for validating and applying a + * ContradictionRule within a tree structure. It extends the PuzzleCommand class and implements the + * ICommand interface. */ public class ValidateContradictionRuleCommand extends PuzzleCommand { private TreeViewSelection selection; @@ -35,9 +36,7 @@ public ValidateContradictionRuleCommand(TreeViewSelection selection, Contradicti this.addTran = new HashMap<>(); } - /** - * Executes the command to validate and apply the ContradictionRule. - */ + /** Executes the command to validate and apply the ContradictionRule. */ @Override public void executeCommand() { Tree tree = GameBoardFacade.getInstance().getTree(); @@ -92,8 +91,7 @@ public void executeCommand() { TreeNodeView nodeView = (TreeNodeView) firstSelectedView; if (!nodeView.getChildrenViews().isEmpty()) { finalTreeElement = nodeView.getChildrenViews().get(0).getTreeElement(); - } - else { + } else { finalTreeElement = null; } } else { @@ -136,9 +134,7 @@ public String getErrorString() { return null; } - /** - * Undoes the validation command, restoring the previous state. - */ + /** Undoes the validation command, restoring the previous state. */ @Override public void undoCommand() { Puzzle puzzle = GameBoardFacade.getInstance().getPuzzleModule(); diff --git a/src/main/java/edu/rpi/legup/history/ValidateDirectRuleCommand.java b/src/main/java/edu/rpi/legup/history/ValidateDirectRuleCommand.java index f7694cc0a..49bf378ee 100644 --- a/src/main/java/edu/rpi/legup/history/ValidateDirectRuleCommand.java +++ b/src/main/java/edu/rpi/legup/history/ValidateDirectRuleCommand.java @@ -6,16 +6,16 @@ import edu.rpi.legup.model.rules.Rule; import edu.rpi.legup.model.tree.*; import edu.rpi.legup.ui.proofeditorui.treeview.*; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - import java.util.HashMap; import java.util.List; import java.util.Map; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; /** * The ValidateDirectRuleCommand class represents a command for validating and applying a DirectRule - * to a set of selected tree elements. It extends the PuzzleCommand class and implements the ICommand interface. + * to a set of selected tree elements. It extends the PuzzleCommand class and implements the + * ICommand interface. */ public class ValidateDirectRuleCommand extends PuzzleCommand { private static final Logger LOGGER = LogManager.getLogger(History.class.getName()); @@ -38,9 +38,7 @@ public ValidateDirectRuleCommand(TreeViewSelection selection, DirectRule rule) { this.addNode = new HashMap<>(); } - /** - * Executes the command to validate and apply the DirectRule. - */ + /** Executes the command to validate and apply the DirectRule. */ @Override public void executeCommand() { Tree tree = GameBoardFacade.getInstance().getTree(); @@ -116,7 +114,6 @@ public void executeCommand() { puzzle.notifyTreeListeners(listener -> listener.onTreeSelectionChanged(newSelection)); } - /** * Gets the reason why the command cannot be executed * @@ -146,9 +143,7 @@ public String getErrorString() { return null; } - /** - * Undoes the validation command, restoring the previous state. - */ + /** Undoes the validation command, restoring the previous state. */ @Override public void undoCommand() { Tree tree = GameBoardFacade.getInstance().getTree(); @@ -162,7 +157,6 @@ public void undoCommand() { transitionView = nodeView.getChildrenViews().get(0); } else { transitionView = (TreeTransitionView) selectedView; - } TreeTransition transition = transitionView.getTreeElement(); diff --git a/src/main/java/edu/rpi/legup/model/Puzzle.java b/src/main/java/edu/rpi/legup/model/Puzzle.java index 6cc92f347..8024c99ed 100644 --- a/src/main/java/edu/rpi/legup/model/Puzzle.java +++ b/src/main/java/edu/rpi/legup/model/Puzzle.java @@ -36,9 +36,9 @@ import org.xml.sax.SAXException; /** - * Abstract class representing a puzzle. - * The Puzzle class manages the core components of a puzzle game, including the board, rules, and elements. - * It also handles importing and exporting puzzle configurations and notifies listeners about changes. + * Abstract class representing a puzzle. The Puzzle class manages the core components of a puzzle + * game, including the board, rules, and elements. It also handles importing and exporting puzzle + * configurations and notifies listeners about changes. */ public abstract class Puzzle implements IBoardSubject, ITreeSubject { private static final Logger LOGGER = LogManager.getLogger(Puzzle.class.getName()); @@ -75,8 +75,8 @@ public Puzzle() { } /** - * Registers puzzle elements from the package of the derived class. - * Scans for classes annotated with {@link RegisterElement} and initializes them. + * Registers puzzle elements from the package of the derived class. Scans for classes annotated + * with {@link RegisterElement} and initializes them. */ private void registerPuzzleElements() { String packageName = this.getClass().getPackage().toString().replace("package ", ""); @@ -87,7 +87,8 @@ private void registerPuzzleElements() { for (Class c : possElements) { String classPackageName = c.getPackage().getName(); - if (!classPackageName.startsWith("edu.rpi.legup.puzzle.") || !classPackageName.endsWith(".elements")) { + if (!classPackageName.startsWith("edu.rpi.legup.puzzle.") + || !classPackageName.endsWith(".elements")) { continue; } System.out.println("possible element: " + c.getName()); @@ -122,8 +123,8 @@ private void registerPuzzleElements() { } /** - * Registers rules from the package of the derived class. - * Scans for classes annotated with {@link RegisterRule} and initializes them. + * Registers rules from the package of the derived class. Scans for classes annotated with + * {@link RegisterRule} and initializes them. */ private void registerRules() { String packageName = this.getClass().getPackage().toString().replace("package ", ""); @@ -134,7 +135,8 @@ private void registerRules() { for (Class c : possRules) { String classPackageName = c.getPackage().getName(); - if (!classPackageName.startsWith("edu.rpi.legup.puzzle.") || !classPackageName.endsWith(".rules")) { + if (!classPackageName.startsWith("edu.rpi.legup.puzzle.") + || !classPackageName.endsWith(".rules")) { continue; } System.out.println("possible rule: " + c.getName()); @@ -176,9 +178,7 @@ private void registerRules() { } } - /** - * Initializes the view. Called by the invoker of the class - */ + /** Initializes the view. Called by the invoker of the class */ public abstract void initializeView(); /** @@ -584,8 +584,8 @@ public void setFactory(ElementFactory factory) { } /** - * Adds a board listener to the list of listeners. - * This allows the puzzle to notify the listener about changes to the board. + * Adds a board listener to the list of listeners. This allows the puzzle to notify the listener + * about changes to the board. * * @param listener The IBoardListener to be added to the list of listeners. */ @@ -595,8 +595,8 @@ public void addBoardListener(IBoardListener listener) { } /** - * Removes a board listener from the list of listeners. - * This prevents the puzzle from notifying the listener about future changes to the board. + * Removes a board listener from the list of listeners. This prevents the puzzle from notifying + * the listener about future changes to the board. * * @param listener The IBoardListener to be removed from the list of listeners. */ @@ -606,10 +606,11 @@ public void removeBoardListener(IBoardListener listener) { } /** - * Notifies all registered board listeners about changes. - * The provided algorithm is applied to each listener to process the notification. + * Notifies all registered board listeners about changes. The provided algorithm is applied to + * each listener to process the notification. * - * @param algorithm A Consumer function that takes an IBoardListener and performs operations to notify the listener. + * @param algorithm A Consumer function that takes an IBoardListener and performs operations to + * notify the listener. */ @Override public void notifyBoardListeners(Consumer algorithm) { @@ -617,8 +618,8 @@ public void notifyBoardListeners(Consumer algorithm) { } /** - * Adds a tree listener to the list of listeners. - * This allows the puzzle to notify the listener about changes to the tree. + * Adds a tree listener to the list of listeners. This allows the puzzle to notify the listener + * about changes to the tree. * * @param listener The ITreeListener to be added to the list of listeners. */ @@ -628,8 +629,8 @@ public void addTreeListener(ITreeListener listener) { } /** - * Removes a tree listener from the list of listeners. - * This prevents the puzzle from notifying the listener about future changes to the tree. + * Removes a tree listener from the list of listeners. This prevents the puzzle from notifying + * the listener about future changes to the tree. * * @param listener The ITreeListener to be removed from the list of listeners. */ @@ -639,10 +640,11 @@ public void removeTreeListener(ITreeListener listener) { } /** - * Notifies all registered tree listeners about changes. - * The provided algorithm is applied to each listener to process the notification. + * Notifies all registered tree listeners about changes. The provided algorithm is applied to + * each listener to process the notification. * - * @param algorithm A Consumer function that takes an ITreeListener and performs operations to notify the listener. + * @param algorithm A Consumer function that takes an ITreeListener and performs operations to + * notify the listener. */ @Override public void notifyTreeListeners(Consumer algorithm) { @@ -650,8 +652,8 @@ public void notifyTreeListeners(Consumer algorithm) { } /** - * Checks if the puzzle is valid. - * The implementation of this method can vary based on the specific criteria for puzzle validity. + * Checks if the puzzle is valid. The implementation of this method can vary based on the + * specific criteria for puzzle validity. * * @return true if the puzzle is valid, false otherwise. */ diff --git a/src/main/java/edu/rpi/legup/model/PuzzleExporter.java b/src/main/java/edu/rpi/legup/model/PuzzleExporter.java index 234d0f25c..13107bb54 100644 --- a/src/main/java/edu/rpi/legup/model/PuzzleExporter.java +++ b/src/main/java/edu/rpi/legup/model/PuzzleExporter.java @@ -21,9 +21,9 @@ import org.w3c.dom.Element; /** - * Abstract class for exporting puzzle data to XML format. - * This class provides functionality to export a puzzle object, including its board and tree structure, to an XML file. - * Subclasses must implement methods to create specific elements for the board and the tree. + * Abstract class for exporting puzzle data to XML format. This class provides functionality to + * export a puzzle object, including its board and tree structure, to an XML file. Subclasses must + * implement methods to create specific elements for the board and the tree. */ public abstract class PuzzleExporter { private static final Logger LOGGER = LogManager.getLogger(PuzzleExporter.class.getName()); @@ -97,8 +97,8 @@ public void exportPuzzle(String fileName) throws ExportFileException { } /** - * Creates an XML element representing the board of the puzzle. - * Subclasses must implement this method to provide the XML structure for the board. + * Creates an XML element representing the board of the puzzle. Subclasses must implement this + * method to provide the XML structure for the board. * * @param newDocument The XML document to create elements within. * @return An XML element representing the puzzle's board. @@ -107,7 +107,8 @@ public void exportPuzzle(String fileName) throws ExportFileException { /** * Creates an XML element representing the proof of the puzzle, including its tree structure. - * This method is used to generate the proof section of the XML, which contains the tree representation. + * This method is used to generate the proof section of the XML, which contains the tree + * representation. * * @param newDocument The XML document to create elements within. * @return An XML element representing the proof of the puzzle. @@ -120,8 +121,8 @@ protected Element createProofElement(Document newDocument) { } /** - * Creates an XML element representing the tree structure of the puzzle. - * This method traverses the tree nodes and transitions, and creates XML elements for each. + * Creates an XML element representing the tree structure of the puzzle. This method traverses + * the tree nodes and transitions, and creates XML elements for each. * * @param newDocument The XML document to create elements within. * @return An XML element representing the puzzle's tree structure. diff --git a/src/main/java/edu/rpi/legup/model/PuzzleImporter.java b/src/main/java/edu/rpi/legup/model/PuzzleImporter.java index b1e8a2dd9..9d16d94e9 100644 --- a/src/main/java/edu/rpi/legup/model/PuzzleImporter.java +++ b/src/main/java/edu/rpi/legup/model/PuzzleImporter.java @@ -14,10 +14,10 @@ import org.w3c.dom.NodeList; /** - * Abstract class for importing puzzle data from various sources into a puzzle object. - * This class provides methods to initialize and set up a puzzle, including its board and proof structure, - * from different input formats such as dimensions, statements, or XML files. - * Subclasses must implement methods to handle specific formats for board initialization and proof creation. + * Abstract class for importing puzzle data from various sources into a puzzle object. This class + * provides methods to initialize and set up a puzzle, including its board and proof structure, from + * different input formats such as dimensions, statements, or XML files. Subclasses must implement + * methods to handle specific formats for board initialization and proof creation. */ public abstract class PuzzleImporter { private static final Logger LOGGER = LogManager.getLogger(PuzzleImporter.class.getName()); @@ -57,7 +57,8 @@ public void initializePuzzle(int rows, int columns) throws RuntimeException { * * @param statements the statements used to initialize the puzzle * @throws InputMismatchException if the input statements are invalid - * @throws IllegalArgumentException if the statements are not suitable for initializing the puzzle + * @throws IllegalArgumentException if the statements are not suitable for initializing the + * puzzle */ public void initializePuzzle(String[] statements) throws InputMismatchException, IllegalArgumentException { @@ -145,7 +146,8 @@ public void initializePuzzle(Node node) throws InvalidFileFormatException { * * @param statements the statements used to initialize the board * @throws UnsupportedOperationException if the operation is not supported - * @throws IllegalArgumentException if the statements are not suitable for initializing the board + * @throws IllegalArgumentException if the statements are not suitable for initializing the + * board */ public abstract void initializeBoard(String[] statements) throws UnsupportedOperationException, IllegalArgumentException; @@ -314,7 +316,6 @@ protected void createTree(Node node) throws InvalidFileFormatException { } } - protected void validateTreeStructure( HashMap nodes, HashMap transitions) throws InvalidFileFormatException { @@ -394,7 +395,8 @@ protected void validateTreeStructure( * * @param transition the TreeTransition object representing the transition to be updated * @param transElement the XML node containing the transition data - * @throws InvalidFileFormatException if the XML node format is incorrect or unknown nodes are encountered + * @throws InvalidFileFormatException if the XML node format is incorrect or unknown nodes are + * encountered */ protected void makeTransitionChanges(TreeTransition transition, Node transElement) throws InvalidFileFormatException { @@ -440,8 +442,8 @@ protected void makeTransitionChanges(TreeTransition transition, Node transElemen } /** - * Creates a default proof tree with a single root node. The root node is initialized with the current board state. - * The created tree is then set as the proof tree for the puzzle. + * Creates a default proof tree with a single root node. The root node is initialized with the + * current board state. The created tree is then set as the proof tree for the puzzle. */ protected void createDefaultTree() { TreeNode root = new TreeNode(puzzle.getCurrentBoard()); diff --git a/src/main/java/edu/rpi/legup/model/RegisterPuzzle.java b/src/main/java/edu/rpi/legup/model/RegisterPuzzle.java index c473e0ecd..df2a9bc5b 100644 --- a/src/main/java/edu/rpi/legup/model/RegisterPuzzle.java +++ b/src/main/java/edu/rpi/legup/model/RegisterPuzzle.java @@ -5,9 +5,7 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -/** - * Annotation for registering puzzle classes with the puzzle framework. - */ +/** Annotation for registering puzzle classes with the puzzle framework. */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface RegisterPuzzle {} diff --git a/src/main/java/edu/rpi/legup/model/elements/Element.java b/src/main/java/edu/rpi/legup/model/elements/Element.java index 0adbbaf91..ed47f6523 100644 --- a/src/main/java/edu/rpi/legup/model/elements/Element.java +++ b/src/main/java/edu/rpi/legup/model/elements/Element.java @@ -5,8 +5,8 @@ import javax.swing.*; /** - * The Element class serves as an abstract base class for various elements used in the system. - * It handles basic properties such as ID, name, description, and image associated with the element. + * The Element class serves as an abstract base class for various elements used in the system. It + * handles basic properties such as ID, name, description, and image associated with the element. */ @RegisterElement public abstract class Element { @@ -39,7 +39,8 @@ public Element(String elementID, String elementName, String description, String } /** - * Loads the image for the element and resizes it to a width of 100 pixels while maintaining aspect ratio + * Loads the image for the element and resizes it to a width of 100 pixels while maintaining + * aspect ratio */ private void loadImage() { if (imageName != null) { diff --git a/src/main/java/edu/rpi/legup/model/elements/ElementType.java b/src/main/java/edu/rpi/legup/model/elements/ElementType.java index 4fee79d4f..142427efe 100644 --- a/src/main/java/edu/rpi/legup/model/elements/ElementType.java +++ b/src/main/java/edu/rpi/legup/model/elements/ElementType.java @@ -1,9 +1,7 @@ package edu.rpi.legup.model.elements; -/** - * Enum representing the different types of elements that can be used in the system - */ +/** Enum representing the different types of elements that can be used in the system */ public enum ElementType { PLACEABLE - //NONPLACEABLE COMBINED ALL PLACEABLE AND NONPLACEABLE INTO JUST ONE CATEGORY + // NONPLACEABLE COMBINED ALL PLACEABLE AND NONPLACEABLE INTO JUST ONE CATEGORY } diff --git a/src/main/java/edu/rpi/legup/model/elements/NonPlaceableElement.java b/src/main/java/edu/rpi/legup/model/elements/NonPlaceableElement.java index 019001128..5c4e96556 100644 --- a/src/main/java/edu/rpi/legup/model/elements/NonPlaceableElement.java +++ b/src/main/java/edu/rpi/legup/model/elements/NonPlaceableElement.java @@ -1,9 +1,9 @@ -//package edu.rpi.legup.model.elements; +// package edu.rpi.legup.model.elements; // -//public abstract class NonPlaceableElement extends Element { +// public abstract class NonPlaceableElement extends Element { // public NonPlaceableElement( // String elementID, String elementName, String description, String imageName) { // super(elementID, elementName, description, imageName); // this.elementType = ElementType.PLACEABLE; // } -//} +// } diff --git a/src/main/java/edu/rpi/legup/model/elements/PlaceableElement.java b/src/main/java/edu/rpi/legup/model/elements/PlaceableElement.java index 79a0dcff8..820dc08dd 100644 --- a/src/main/java/edu/rpi/legup/model/elements/PlaceableElement.java +++ b/src/main/java/edu/rpi/legup/model/elements/PlaceableElement.java @@ -1,18 +1,18 @@ package edu.rpi.legup.model.elements; /** - * Abstract class representing elements that can be placed within the system. - * Inherits from the {@link Element} class and sets the {@link ElementType} to {@link ElementType#PLACEABLE}. + * Abstract class representing elements that can be placed within the system. Inherits from the + * {@link Element} class and sets the {@link ElementType} to {@link ElementType#PLACEABLE}. */ public abstract class PlaceableElement extends Element { /** * Constructs a PlaceableElement with the specified details * - * @param elementID Unique identifier for the element - * @param elementName Name of the element - * @param description Description of the element - * @param imageName Name of the image file representing the element + * @param elementID Unique identifier for the element + * @param elementName Name of the element + * @param description Description of the element + * @param imageName Name of the image file representing the element */ public PlaceableElement( String elementID, String elementName, String description, String imageName) { diff --git a/src/main/java/edu/rpi/legup/model/elements/RegisterElement.java b/src/main/java/edu/rpi/legup/model/elements/RegisterElement.java index 5f59ad795..916719ebc 100644 --- a/src/main/java/edu/rpi/legup/model/elements/RegisterElement.java +++ b/src/main/java/edu/rpi/legup/model/elements/RegisterElement.java @@ -4,9 +4,9 @@ import java.lang.annotation.ElementType; /** - * Annotation to mark classes as elements that should be registered. - * This annotation is used to indicate that a class is an element within the system and should be registered - * for use within the application. + * Annotation to mark classes as elements that should be registered. This annotation is used to + * indicate that a class is an element within the system and should be registered for use within the + * application. */ @Inherited @Target(ElementType.TYPE) diff --git a/src/main/java/edu/rpi/legup/model/gameboard/Board.java b/src/main/java/edu/rpi/legup/model/gameboard/Board.java index 4544caa36..9e7d93441 100644 --- a/src/main/java/edu/rpi/legup/model/gameboard/Board.java +++ b/src/main/java/edu/rpi/legup/model/gameboard/Board.java @@ -6,9 +6,8 @@ import java.util.Set; /** - * Abstract class representing a game board. - * This class provides functionality for managing puzzle elements, tracking modifications, - * and determining if the board is modifiable. + * Abstract class representing a game board. This class provides functionality for managing puzzle + * elements, tracking modifications, and determining if the board is modifiable. */ public abstract class Board { diff --git a/src/main/java/edu/rpi/legup/model/gameboard/CaseBoard.java b/src/main/java/edu/rpi/legup/model/gameboard/CaseBoard.java index 14dcb8609..07cc2947d 100644 --- a/src/main/java/edu/rpi/legup/model/gameboard/CaseBoard.java +++ b/src/main/java/edu/rpi/legup/model/gameboard/CaseBoard.java @@ -6,8 +6,8 @@ import java.util.Set; /** - * Represents a game board with specific rules for selecting puzzle elements. - * Extends the abstract `Board` class and adds functionality for handling pickable elements and case rules. + * Represents a game board with specific rules for selecting puzzle elements. Extends the abstract + * `Board` class and adds functionality for handling pickable elements and case rules. */ public class CaseBoard extends Board { protected Board baseBoard; @@ -100,10 +100,8 @@ public int getCount() { return pickablePuzzleElements.size(); } - /** - * Performs a deep copy of this CaseBoard. - * CURRENTLY NOT IMPLEMENTED AND RETURNS NULL + * Performs a deep copy of this CaseBoard. CURRENTLY NOT IMPLEMENTED AND RETURNS NULL * * @return a new copy of the CaseBoard */ diff --git a/src/main/java/edu/rpi/legup/model/gameboard/GridCell.java b/src/main/java/edu/rpi/legup/model/gameboard/GridCell.java index 5d6fe1ff3..671b89e9b 100644 --- a/src/main/java/edu/rpi/legup/model/gameboard/GridCell.java +++ b/src/main/java/edu/rpi/legup/model/gameboard/GridCell.java @@ -3,9 +3,9 @@ import java.awt.*; /** - * GridCell represents a cell within a grid-based board. It holds data of type T and tracks its location - * on the board using a {@link Point}. The class extends from PuzzleElement and supports deep copying of - * the grid cell. + * GridCell represents a cell within a grid-based board. It holds data of type T and tracks its + * location on the board using a {@link Point}. The class extends from PuzzleElement and supports + * deep copying of the grid cell. * * @param the type of data held by the GridCell */ diff --git a/src/main/java/edu/rpi/legup/model/gameboard/GridRegion.java b/src/main/java/edu/rpi/legup/model/gameboard/GridRegion.java index b2a10a153..79027d9d1 100644 --- a/src/main/java/edu/rpi/legup/model/gameboard/GridRegion.java +++ b/src/main/java/edu/rpi/legup/model/gameboard/GridRegion.java @@ -4,8 +4,8 @@ import java.util.List; /** - * GridRegion represents a collection of cells within a grid. It manages a list of cells and provides - * methods to add, remove, and retrieve cells from the region. + * GridRegion represents a collection of cells within a grid. It manages a list of cells and + * provides methods to add, remove, and retrieve cells from the region. * * @param the type of cell managed by the GridRegion */ diff --git a/src/main/java/edu/rpi/legup/model/gameboard/PuzzleElement.java b/src/main/java/edu/rpi/legup/model/gameboard/PuzzleElement.java index a92b3efb0..eca6f3be4 100644 --- a/src/main/java/edu/rpi/legup/model/gameboard/PuzzleElement.java +++ b/src/main/java/edu/rpi/legup/model/gameboard/PuzzleElement.java @@ -5,7 +5,8 @@ /** * PuzzleElement represents a single element in a puzzle grid. It holds data and provides various - * methods to manage and retrieve its properties, including modifiability, modification status, and validity. + * methods to manage and retrieve its properties, including modifiability, modification status, and + * validity. * * @param the type of data held by the PuzzleElement */ diff --git a/src/main/java/edu/rpi/legup/model/observer/IBoardListener.java b/src/main/java/edu/rpi/legup/model/observer/IBoardListener.java index fa440369c..7ba886fd4 100644 --- a/src/main/java/edu/rpi/legup/model/observer/IBoardListener.java +++ b/src/main/java/edu/rpi/legup/model/observer/IBoardListener.java @@ -5,8 +5,8 @@ import edu.rpi.legup.model.tree.TreeElement; /** - * IBoardListener defines methods for receiving notifications about changes to the board, - * including updates to tree elements, case boards, and puzzle elements. + * IBoardListener defines methods for receiving notifications about changes to the board, including + * updates to tree elements, case boards, and puzzle elements. */ public interface IBoardListener { /** diff --git a/src/main/java/edu/rpi/legup/model/observer/IBoardSubject.java b/src/main/java/edu/rpi/legup/model/observer/IBoardSubject.java index 53bfe444b..6cdcd7dc2 100644 --- a/src/main/java/edu/rpi/legup/model/observer/IBoardSubject.java +++ b/src/main/java/edu/rpi/legup/model/observer/IBoardSubject.java @@ -3,8 +3,8 @@ import java.util.function.Consumer; /** - * IBoardSubject defines methods for managing and notifying board listeners. - * It allows for adding and removing listeners, and for notifying them using a specified algorithm. + * IBoardSubject defines methods for managing and notifying board listeners. It allows for adding + * and removing listeners, and for notifying them using a specified algorithm. */ public interface IBoardSubject { /** diff --git a/src/main/java/edu/rpi/legup/model/observer/ITreeListener.java b/src/main/java/edu/rpi/legup/model/observer/ITreeListener.java index c5a0355ca..713b464e2 100644 --- a/src/main/java/edu/rpi/legup/model/observer/ITreeListener.java +++ b/src/main/java/edu/rpi/legup/model/observer/ITreeListener.java @@ -4,8 +4,8 @@ import edu.rpi.legup.ui.proofeditorui.treeview.TreeViewSelection; /** - * ITreeListener defines methods for handling events related to changes in the tree. - * Implementations of this interface are notified of additions, removals, and selection changes in the tree. + * ITreeListener defines methods for handling events related to changes in the tree. Implementations + * of this interface are notified of additions, removals, and selection changes in the tree. */ public interface ITreeListener { /** diff --git a/src/main/java/edu/rpi/legup/model/observer/ITreeSubject.java b/src/main/java/edu/rpi/legup/model/observer/ITreeSubject.java index 0b0aee348..f7c033529 100644 --- a/src/main/java/edu/rpi/legup/model/observer/ITreeSubject.java +++ b/src/main/java/edu/rpi/legup/model/observer/ITreeSubject.java @@ -3,8 +3,8 @@ import java.util.function.Consumer; /** - * ITreeSubject defines methods for managing and notifying listeners about changes to the tree model. - * Implementations of this interface handle adding, removing, and notifying listeners. + * ITreeSubject defines methods for managing and notifying listeners about changes to the tree + * model. Implementations of this interface handle adding, removing, and notifying listeners. */ public interface ITreeSubject { /** diff --git a/src/main/java/edu/rpi/legup/model/rules/CaseRule.java b/src/main/java/edu/rpi/legup/model/rules/CaseRule.java index ee5c91229..aac4fd352 100644 --- a/src/main/java/edu/rpi/legup/model/rules/CaseRule.java +++ b/src/main/java/edu/rpi/legup/model/rules/CaseRule.java @@ -12,8 +12,9 @@ import java.util.Set; /** - * CaseRule is an abstract class representing a rule that can be applied with multiple cases in a puzzle board. - * It defines methods for applying and checking the rule, as well as retrieving the necessary elements. + * CaseRule is an abstract class representing a rule that can be applied with multiple cases in a + * puzzle board. It defines methods for applying and checking the rule, as well as retrieving the + * necessary elements. */ public abstract class CaseRule extends Rule { diff --git a/src/main/java/edu/rpi/legup/model/rules/ContradictionRule.java b/src/main/java/edu/rpi/legup/model/rules/ContradictionRule.java index cd2e20081..c80a551ec 100644 --- a/src/main/java/edu/rpi/legup/model/rules/ContradictionRule.java +++ b/src/main/java/edu/rpi/legup/model/rules/ContradictionRule.java @@ -7,8 +7,9 @@ import edu.rpi.legup.model.tree.TreeTransition; /** - * ContradictionRule is an abstract class representing a rule that identifies contradictions in a puzzle. - * It provides methods to check for contradictions both globally and at specific puzzle elements. + * ContradictionRule is an abstract class representing a rule that identifies contradictions in a + * puzzle. It provides methods to check for contradictions both globally and at specific puzzle + * elements. */ public abstract class ContradictionRule extends Rule { diff --git a/src/main/java/edu/rpi/legup/model/rules/DirectRule.java b/src/main/java/edu/rpi/legup/model/rules/DirectRule.java index 613574989..8efe119b6 100644 --- a/src/main/java/edu/rpi/legup/model/rules/DirectRule.java +++ b/src/main/java/edu/rpi/legup/model/rules/DirectRule.java @@ -8,8 +8,8 @@ import edu.rpi.legup.model.tree.TreeTransition; /** - * DirectRule is an abstract class representing a direct rule for transitions in a puzzle. - * It provides methods for checking whether transitions and specific puzzle elements follow the rule. + * DirectRule is an abstract class representing a direct rule for transitions in a puzzle. It + * provides methods for checking whether transitions and specific puzzle elements follow the rule. */ public abstract class DirectRule extends Rule { /** diff --git a/src/main/java/edu/rpi/legup/model/rules/MergeRule.java b/src/main/java/edu/rpi/legup/model/rules/MergeRule.java index f7bd887f3..86c63fb7c 100644 --- a/src/main/java/edu/rpi/legup/model/rules/MergeRule.java +++ b/src/main/java/edu/rpi/legup/model/rules/MergeRule.java @@ -11,8 +11,8 @@ import java.util.List; /** - * MergeRule is an implementation of a rule that merges multiple nodes into one. - * It validates if the merging of nodes is done correctly. + * MergeRule is an implementation of a rule that merges multiple nodes into one. It validates if the + * merging of nodes is done correctly. */ public class MergeRule extends Rule { /** MergeRule Constructor merges to board states together */ diff --git a/src/main/java/edu/rpi/legup/model/rules/RegisterRule.java b/src/main/java/edu/rpi/legup/model/rules/RegisterRule.java index d357e0d86..0ee2a686e 100644 --- a/src/main/java/edu/rpi/legup/model/rules/RegisterRule.java +++ b/src/main/java/edu/rpi/legup/model/rules/RegisterRule.java @@ -3,9 +3,8 @@ import java.lang.annotation.*; /** - * Annotation to register a class as a rule in the system. - * This annotation can be applied to rule classes to indicate that they should be registered - * in the rule system. + * Annotation to register a class as a rule in the system. This annotation can be applied to rule + * classes to indicate that they should be registered in the rule system. */ @Inherited @Target(ElementType.TYPE) diff --git a/src/main/java/edu/rpi/legup/model/rules/Rule.java b/src/main/java/edu/rpi/legup/model/rules/Rule.java index 107e72712..edcab550b 100644 --- a/src/main/java/edu/rpi/legup/model/rules/Rule.java +++ b/src/main/java/edu/rpi/legup/model/rules/Rule.java @@ -9,10 +9,9 @@ import javax.swing.ImageIcon; /** - * Abstract base class for defining rules. - * This class encapsulates the common functionality and attributes of all rules, - * including rule identification, description, image handling, and validation logic. - * Subclasses must provide implementations for specific rule checking logic. + * Abstract base class for defining rules. This class encapsulates the common functionality and + * attributes of all rules, including rule identification, description, image handling, and + * validation logic. Subclasses must provide implementations for specific rule checking logic. */ @RegisterRule public abstract class Rule { diff --git a/src/main/java/edu/rpi/legup/model/rules/RuleType.java b/src/main/java/edu/rpi/legup/model/rules/RuleType.java index e72118e3c..7eee80ea3 100644 --- a/src/main/java/edu/rpi/legup/model/rules/RuleType.java +++ b/src/main/java/edu/rpi/legup/model/rules/RuleType.java @@ -1,8 +1,8 @@ package edu.rpi.legup.model.rules; /** - * Enumeration representing different types of rules in the rule-based system. - * This enum categorizes rules into various types based on their functionality and application. + * Enumeration representing different types of rules in the rule-based system. This enum categorizes + * rules into various types based on their functionality and application. */ public enum RuleType { BASIC, diff --git a/src/main/java/edu/rpi/legup/model/tree/Tree.java b/src/main/java/edu/rpi/legup/model/tree/Tree.java index 3e68015a1..545976fd1 100644 --- a/src/main/java/edu/rpi/legup/model/tree/Tree.java +++ b/src/main/java/edu/rpi/legup/model/tree/Tree.java @@ -2,18 +2,15 @@ import edu.rpi.legup.controller.TreeController; import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.rules.CaseRule; import edu.rpi.legup.ui.proofeditorui.treeview.TreeView; - import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; /** - * Represents a tree structure in a puzzle. - * The tree consists of {@link TreeNode}s and {@link TreeTransition}s - * and allows adding, removing, and validating elements. + * Represents a tree structure in a puzzle. The tree consists of {@link TreeNode}s and {@link + * TreeTransition}s and allows adding, removing, and validating elements. */ public class Tree { private TreeNode rootNode; diff --git a/src/main/java/edu/rpi/legup/model/tree/TreeElement.java b/src/main/java/edu/rpi/legup/model/tree/TreeElement.java index 2f6f45e4d..8c865b89b 100644 --- a/src/main/java/edu/rpi/legup/model/tree/TreeElement.java +++ b/src/main/java/edu/rpi/legup/model/tree/TreeElement.java @@ -3,7 +3,8 @@ import edu.rpi.legup.model.gameboard.Board; /** - * Represents an element in a tree structure, which can be either a {@link TreeNode} or a {@link TreeTransition}. + * Represents an element in a tree structure, which can be either a {@link TreeNode} or a {@link + * TreeTransition}. */ public abstract class TreeElement { protected TreeElementType type; diff --git a/src/main/java/edu/rpi/legup/model/tree/TreeElementType.java b/src/main/java/edu/rpi/legup/model/tree/TreeElementType.java index 3a6dbb124..eb585329e 100644 --- a/src/main/java/edu/rpi/legup/model/tree/TreeElementType.java +++ b/src/main/java/edu/rpi/legup/model/tree/TreeElementType.java @@ -1,8 +1,8 @@ package edu.rpi.legup.model.tree; /** - * Enum representing the type of a tree element. - * Tree elements can be either nodes or transitions in the tree structure. + * Enum representing the type of a tree element. Tree elements can be either nodes or transitions in + * the tree structure. */ public enum TreeElementType { NODE, diff --git a/src/main/java/edu/rpi/legup/model/tree/TreeNode.java b/src/main/java/edu/rpi/legup/model/tree/TreeNode.java index 85a5e717b..d4095afa5 100644 --- a/src/main/java/edu/rpi/legup/model/tree/TreeNode.java +++ b/src/main/java/edu/rpi/legup/model/tree/TreeNode.java @@ -5,9 +5,9 @@ import java.util.*; /** - * Represents a node in a tree structure. Extends {@link TreeElement}. - * A {@code TreeNode} contains a board, references to its parent and children transitions, and indicates - * if it is the root node of the tree. + * Represents a node in a tree structure. Extends {@link TreeElement}. A {@code TreeNode} contains a + * board, references to its parent and children transitions, and indicates if it is the root node of + * the tree. */ public class TreeNode extends TreeElement { private TreeTransition parent; @@ -332,8 +332,8 @@ public void setRoot(boolean isRoot) { } /** - * Clears all children transitions from this tree node. - * After calling this method, the node will have no child transitions. + * Clears all children transitions from this tree node. After calling this method, the node will + * have no child transitions. */ public void clearChildren() { this.children.clear(); diff --git a/src/main/java/edu/rpi/legup/model/tree/TreeTransition.java b/src/main/java/edu/rpi/legup/model/tree/TreeTransition.java index 9e441ac55..10c8fc7a0 100644 --- a/src/main/java/edu/rpi/legup/model/tree/TreeTransition.java +++ b/src/main/java/edu/rpi/legup/model/tree/TreeTransition.java @@ -9,9 +9,9 @@ import java.util.List; /** - * Represents a transition between two nodes in a tree structure within a game. - * A transition is responsible for propagating changes through the tree and managing - * and verifying the associated rules and puzzle elements. + * Represents a transition between two nodes in a tree structure within a game. A transition is + * responsible for propagating changes through the tree and managing and verifying the associated + * rules and puzzle elements. */ public class TreeTransition extends TreeElement { private ArrayList parents; @@ -355,7 +355,6 @@ public void addChild(TreeNode child) { parents.add(child); } - /** * Gets the rule associated with this transition * diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/Binary.java b/src/main/java/edu/rpi/legup/puzzle/binary/Binary.java index d2dd0b181..7b70a43a1 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/Binary.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/Binary.java @@ -68,16 +68,15 @@ public boolean isBoardComplete(Board board) { @Override public void onBoardChange(Board board) {} - /** * Determines if the given dimensions are valid for Binary * - * @param rows the number of rows - * @param columns the number of columns + * @param rows the number of rows + * @param columns the number of columns * @return true if the given dimensions are valid for Binary, false otherwise */ @Override - public boolean isValidDimensions(int rows, int columns){ + public boolean isValidDimensions(int rows, int columns) { return rows >= 2 && rows % 2 == 0 && rows == columns; } } diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java index 34819410b..d5d65ed26 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java @@ -2,7 +2,6 @@ import edu.rpi.legup.model.gameboard.GridBoard; import edu.rpi.legup.model.gameboard.PuzzleElement; - import java.util.ArrayList; import java.util.HashSet; import java.util.Set; @@ -55,7 +54,7 @@ public Set getRowCells(int rowNum) { } /** - * Get all the binary cells in a column + * Get all the binary cells in a column * * @param colNum column number * @return set of all binary cells in specified colNum @@ -69,7 +68,7 @@ public Set getColCells(int colNum) { } /** - * Get all the binary types in a row + * Get all the binary types in a row * * @param rowNum row number * @return ArrayList of all binary types in specified rowNum @@ -84,7 +83,7 @@ public ArrayList getRowTypes(int rowNum) { } /** - * Get all the binary types in a column + * Get all the binary types in a column * * @param colNum column number * @return ArrayList of all binary types in specified colNum @@ -100,6 +99,7 @@ public ArrayList getColTypes(int colNum) { /** * Get a copy of the binary board + * * @return copy of current BinaryBoard */ @Override diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java index d09f7115e..0edb8444e 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java @@ -5,7 +5,6 @@ import java.awt.Point; import java.awt.event.MouseEvent; - public class BinaryCell extends GridCell { /** * BinaryCell Constructor - creates a BinaryCell from the specified value and location @@ -63,24 +62,20 @@ public void setType(Element e, MouseEvent m) { if (m.getButton() == MouseEvent.BUTTON1) { if (this.data == 2) { this.data = 0; - } - else { + } else { this.data = this.data + 1; } - } - else { + } else { if (m.getButton() == MouseEvent.BUTTON3) { if (this.data > 0) { this.data = this.data - 1; - } - else { + } else { this.data = 2; } } } - } - else { // unknown tile + } else { // unknown tile this.data = 2; } } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryController.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryController.java index caf62f3fe..5ec6669a0 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryController.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryController.java @@ -7,13 +7,12 @@ public class BinaryController extends ElementController { /** - * Handles cell state changes in the binary puzzle when a mouse event occurs - * If the left mouse button is clicked: - * - If the control key is held down, shows a context menu at the mouse position - * - Otherwise, toggles the cell data state between 0, 1, and 2 in a cyclic manner - * If the right mouse button is clicked, the cell state is also toggled between 2, 1, and 0 + * Handles cell state changes in the binary puzzle when a mouse event occurs If the left mouse + * button is clicked: - If the control key is held down, shows a context menu at the mouse + * position - Otherwise, toggles the cell data state between 0, 1, and 2 in a cyclic manner If + * the right mouse button is clicked, the cell state is also toggled between 2, 1, and 0 * - * @param e MouseEvent triggered by the user interaction + * @param e MouseEvent triggered by the user interaction * @param data PuzzleElement representing the cell being modified */ @Override diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryElementView.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryElementView.java index f5ea33d4a..74a761e89 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryElementView.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryElementView.java @@ -24,7 +24,6 @@ public BinaryCell getPuzzleElement() { return (BinaryCell) super.getPuzzleElement(); } - /** * Draws the cells provided in the puzzle's .xml file with light gray background * @@ -49,7 +48,7 @@ public void drawElement(Graphics2D graphics2D) { * Helper method to handle drawing the cell based on its type and background color * * @param graphics2D The graphics object to draw on - * @param bgColor The background color for the cell + * @param bgColor The background color for the cell */ private void drawCell(Graphics2D graphics2D, Color bgColor) { BinaryCell cell = (BinaryCell) puzzleElement; @@ -86,4 +85,3 @@ private void drawCenteredText(Graphics2D graphics2D) { graphics2D.drawString(value, xText, yText); } } - diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryExporter.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryExporter.java index f12a07378..c032b63a9 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryExporter.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryExporter.java @@ -11,8 +11,8 @@ public BinaryExporter(Binary binary) { } /** - * Generates an XML element for the binary puzzle board, including its dimensions and the - * state of each cell. Binary cells that are not in the `UNKNOWN` state are included in the XML. + * Generates an XML element for the binary puzzle board, including its dimensions and the state + * of each cell. Binary cells that are not in the `UNKNOWN` state are included in the XML. * * @param newDocument The XML document to which the board element belongs. * @return The XML element representing the board. diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryImporter.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryImporter.java index 8a4bad01e..419789060 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryImporter.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryImporter.java @@ -129,6 +129,7 @@ public void initializeBoard(Node node) throws InvalidFileFormatException { /** * Initializes a board with text + * * @param statements the text being used * @throws UnsupportedOperationException Binary does not use text input */ diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryType.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryType.java index f03f2ee08..7e8e162e6 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryType.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryType.java @@ -3,20 +3,17 @@ /** * Enum representing the possible states of a binary puzzle cell * - * The states include: - * - ZERO: Represents a cell with a value of 0 - * - ONE: Represents a cell with a value of 1 - * - UNKNOWN: Represents an empty cell - * + *

The states include: - ZERO: Represents a cell with a value of 0 - ONE: Represents a cell with + * a value of 1 - UNKNOWN: Represents an empty cell */ public enum BinaryType { - ZERO, // Enum constant 0 - ONE, // Enum constant 1 - UNKNOWN; // Enum constant 2 + ZERO, // Enum constant 0 + ONE, // Enum constant 1 + UNKNOWN; // Enum constant 2 /** - * The `toValue` method returns the ordinal value of the enum constant, - * which can be used to convert the enum to an integer representation. + * The `toValue` method returns the ordinal value of the enum constant, which can be used to + * convert the enum to an integer representation. */ public int toValue() { return this.ordinal(); diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryView.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryView.java index e1869de6b..b428ce32c 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryView.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryView.java @@ -7,9 +7,10 @@ public class BinaryView extends GridBoardView { - /** Creates and arranges the visual components for each cell in the binary puzzle. Initializes - * the view by setting up the board controller, binary controller, and the grid dimensions. - * For each cell in the BinaryBoard, it creates a corresponding BinaryElementView, sets its index, + /** + * Creates and arranges the visual components for each cell in the binary puzzle. Initializes + * the view by setting up the board controller, binary controller, and the grid dimensions. For + * each cell in the BinaryBoard, it creates a corresponding BinaryElementView, sets its index, * size, and location, and adds it to the list of element views to be displayed. * * @param board The BinaryBoard representing the current state of the binary puzzle diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/elements/NumberTile.java b/src/main/java/edu/rpi/legup/puzzle/binary/elements/NumberTile.java index e996e246b..dc3d75e00 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/elements/NumberTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/elements/NumberTile.java @@ -1,4 +1,3 @@ - package edu.rpi.legup.puzzle.binary.elements; import edu.rpi.legup.model.elements.PlaceableElement; @@ -11,4 +10,4 @@ public NumberTile() { "A number tile", "edu/rpi/legup/images/binary/tiles/NumberTile.png"); } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/elements/UnknownTile.java b/src/main/java/edu/rpi/legup/puzzle/binary/elements/UnknownTile.java index 8c60ea8c3..e32a2d12f 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/elements/UnknownTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/elements/UnknownTile.java @@ -10,4 +10,4 @@ public UnknownTile() { "A blank tile", "edu/rpi/legup/images/binary/tiles/UnknownTile.png"); } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java index 359433685..6ced37a9c 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java @@ -15,8 +15,8 @@ public CompleteRowColumnDirectRule() { super( "BINA-BASC-0003", "Complete Row/Column", - "If a row/column of length n contains n/2 of a single value, the remaining " + - "cells must contain the other value", + "If a row/column of length n contains n/2 of a single value, the remaining " + + "cells must contain the other value", "edu/rpi/legup/images/binary/rules/CompleteRowColumnDirectRule.png"); } diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java index 02c1c2c31..df84dd540 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java @@ -1,33 +1,35 @@ -//package edu.rpi.legup.puzzle.binary.rules; -// -//import edu.rpi.legup.model.gameboard.Board; -//import edu.rpi.legup.model.gameboard.PuzzleElement; -//import edu.rpi.legup.model.rules.DirectRule; -//import edu.rpi.legup.model.tree.TreeNode; -//import edu.rpi.legup.model.tree.TreeTransition; -//import edu.rpi.legup.puzzle.binary.BinaryBoard; -//import edu.rpi.legup.puzzle.binary.BinaryCell; -//import edu.rpi.legup.puzzle.binary.BinaryType; -// -//import java.util.LinkedList; -//import java.util.Queue; -//import java.lang.Math.*; -//import java.lang.reflect.Array; -//import java.util.ArrayList; -// -//public class EliminateTheImpossibleDirectRule extends DirectRule { +// package edu.rpi.legup.puzzle.binary.rules; +// +// import edu.rpi.legup.model.gameboard.Board; +// import edu.rpi.legup.model.gameboard.PuzzleElement; +// import edu.rpi.legup.model.rules.DirectRule; +// import edu.rpi.legup.model.tree.TreeNode; +// import edu.rpi.legup.model.tree.TreeTransition; +// import edu.rpi.legup.puzzle.binary.BinaryBoard; +// import edu.rpi.legup.puzzle.binary.BinaryCell; +// import edu.rpi.legup.puzzle.binary.BinaryType; +// +// import java.util.LinkedList; +// import java.util.Queue; +// import java.lang.Math.*; +// import java.lang.reflect.Array; +// import java.util.ArrayList; +// +// public class EliminateTheImpossibleDirectRule extends DirectRule { // private final String INVALID_USE_MESSAGE = "Number at cell is incorrect"; // // public EliminateTheImpossibleDirectRule() { // super( // "BINA-BASC-0004", // "Eliminate The Impossible", -// "Out of the remaining empty cells in this row or column, this digit must go here, otherwise there will be a future contradiction", +// "Out of the remaining empty cells in this row or column, this digit must go here, +// otherwise there will be a future contradiction", // "edu/rpi/legup/images/binary/rules/EliminateTheImpossibleDirectRule.png"); // } // // // Function to generate all binary strings -// void generatePossibilitites(int spots, ArrayList possibilities, int zeroCount, int oneCount) +// void generatePossibilitites(int spots, ArrayList possibilities, int zeroCount, int +// oneCount) // // This function generates all the possible combinations of 0s and 1s for a // // certain size, it does this // // by basically just counting from 0 to the number - 1, so if you want all the @@ -122,7 +124,8 @@ // // unknown spots left, // // an ArrayList that will be populated with the possible results (in String // // form), the amount of zeros left and ones left -// generatePossibilitites((size - rowNumZeros - rowNumOnes), rowResult, size / 2 - rowNumZeros, size / 2 - rowNumOnes); +// generatePossibilitites((size - rowNumZeros - rowNumOnes), rowResult, size / 2 - +// rowNumZeros, size / 2 - rowNumOnes); // // // Create deep copies of each row // ArrayList> rowCopies = new ArrayList<>(); @@ -198,4 +201,4 @@ // public Board getDefaultBoard(TreeNode node) { // return null; // } -//} +// } diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/PreventTrioDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/PreventTrioDirectRule.java index 745e35d4e..728ec8e10 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/PreventTrioDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/PreventTrioDirectRule.java @@ -35,7 +35,8 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem BinaryCell binaryCell = (BinaryCell) puzzleElement; BinaryBoard modified = origBoard.copy(); - // Flip the cell and check to see if there will be a trio contradiction, if so the rule is applied correctly + // Flip the cell and check to see if there will be a trio contradiction, if so the rule is + // applied correctly modified.getPuzzleElement(puzzleElement).setData(Math.abs(binaryCell.getData() - 1)); if (contraRule.checkContradictionAt(modified, binaryCell) == null) { return null; @@ -55,4 +56,4 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem public Board getDefaultBoard(TreeNode node) { return null; } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/RepeatedRowColumnContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/RepeatedRowColumnContradictionRule.java index 13eb35283..a7a4ced12 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/RepeatedRowColumnContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/RepeatedRowColumnContradictionRule.java @@ -35,7 +35,8 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { BinaryBoard binaryBoard = (BinaryBoard) board; BinaryCell cell = (BinaryCell) binaryBoard.getPuzzleElement(puzzleElement); - // Compare each row with row of current cell to see if they are equal, if so the rule is applied correctly + // Compare each row with row of current cell to see if they are equal, if so the rule is + // applied correctly ArrayList row = binaryBoard.getRowTypes(cell.getLocation().y); int size = row.size(); for (int i = 0; i < size; i++) { @@ -47,7 +48,8 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { } } - // Compare each column with column of current cell to see if they are equal, if so the rule is applied correctly + // Compare each column with column of current cell to see if they are equal, if so the rule + // is applied correctly ArrayList col = binaryBoard.getColTypes(cell.getLocation().x); for (int i = 0; i < size; i++) { if (i != cell.getLocation().x) { diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/SaveBlockerDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/SaveBlockerDirectRule.java index 5f76c4f59..6cc28446d 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/SaveBlockerDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/SaveBlockerDirectRule.java @@ -8,7 +8,7 @@ import edu.rpi.legup.puzzle.binary.BinaryBoard; import edu.rpi.legup.puzzle.binary.BinaryCell; -public class SaveBlockerDirectRule extends DirectRule { +public class SaveBlockerDirectRule extends DirectRule { private final String INVALID_USE_MESSAGE = "Number at cell is incorrect"; @@ -35,7 +35,8 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem BinaryCell binaryCell = (BinaryCell) puzzleElement; BinaryBoard modified = origBoard.copy(); - // Flip the cell and check to see if a blocker digit is wasted, if so the rule is applied correctly + // Flip the cell and check to see if a blocker digit is wasted, if so the rule is applied + // correctly modified.getPuzzleElement(puzzleElement).setData(Math.abs(binaryCell.getData() - 1)); if (contraRule.checkContradictionAt(modified, binaryCell) == null) { return null; @@ -55,6 +56,4 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem public Board getDefaultBoard(TreeNode node) { return null; } - - } diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/TrioContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/TrioContradictionRule.java index dce7fe371..fc5cd4165 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/TrioContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/TrioContradictionRule.java @@ -21,8 +21,8 @@ public TrioContradictionRule() { } /** - * This method checks the surrounding cells of a given puzzle element at a specified distance - * in both the vertical and horizontal directions + * This method checks the surrounding cells of a given puzzle element at a specified distance in + * both the vertical and horizontal directions * * @param board The board where the puzzle elements are located * @param puzzleElement The puzzle element from which the distance is calculated @@ -58,8 +58,8 @@ public BinaryCell[] getCellsNAway(Board board, PuzzleElement puzzleElement, int } /** - * Checks whether the cell and its two surrounding cells form a trio of zeros or ones; - * If a trio is found, it indicates a contradiction + * Checks whether the cell and its two surrounding cells form a trio of zeros or ones; If a trio + * is found, it indicates a contradiction * * @param board The board where the puzzle elements are located * @param puzzleElement The puzzle element to check for contradiction @@ -120,8 +120,8 @@ public boolean checkSurroundPair(Board board, PuzzleElement puzzleElement) { } /** - * Checks whether there are two of the same cell type separated by one cell that also has - * the same type in any direction. If a trio is found, it indicates a contradiction + * Checks whether there are two of the same cell type separated by one cell that also has the + * same type in any direction. If a trio is found, it indicates a contradiction * * @param board The board where the puzzle elements are located * @param puzzleElement The puzzle element to check for contradiction diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowColumnContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowColumnContradictionRule.java index 82f658013..1d00f4da9 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowColumnContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowColumnContradictionRule.java @@ -6,7 +6,6 @@ import edu.rpi.legup.puzzle.binary.BinaryBoard; import edu.rpi.legup.puzzle.binary.BinaryCell; import edu.rpi.legup.puzzle.binary.BinaryType; - import java.util.Set; public class UnbalancedRowColumnContradictionRule extends ContradictionRule { @@ -56,7 +55,6 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { return null; } - Set col = binaryBoard.getColCells(cell.getLocation().x); size = col.size(); diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UniqueRowColumnDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UniqueRowColumnDirectRule.java index 3f90510e3..0250a4c74 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UniqueRowColumnDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UniqueRowColumnDirectRule.java @@ -5,12 +5,9 @@ import edu.rpi.legup.model.rules.DirectRule; import edu.rpi.legup.model.tree.TreeNode; import edu.rpi.legup.model.tree.TreeTransition; -import edu.rpi.legup.puzzle.binary.Binary; import edu.rpi.legup.puzzle.binary.BinaryBoard; import edu.rpi.legup.puzzle.binary.BinaryCell; import edu.rpi.legup.puzzle.binary.BinaryType; - -import java.lang.reflect.Array; import java.util.ArrayList; public class UniqueRowColumnDirectRule extends DirectRule { @@ -20,8 +17,8 @@ public UniqueRowColumnDirectRule() { super( "BINA-BASC-0004", "Unique Row/Column", - "If an unfinished row/column only differs by empty cells from a finished one, " + - "fill contradicting empty cells with opposite digit to prevent a repeated row/column", + "If an unfinished row/column only differs by empty cells from a finished one, " + + "fill contradicting empty cells with opposite digit to prevent a repeated row/column", "edu/rpi/legup/images/binary/rules/UniqueRowColumnDirectRule.png"); } @@ -50,8 +47,11 @@ private int getNumEmpty(ArrayList seq) { * @param rowOrColumn Flag to indicate whether checking a row (0) or a column (1) * @return Null if a valid opposite digit is found, otherwise an error message */ - private String checkOppositeDigitDifference(ArrayList seq, BinaryBoard origBoard, - BinaryCell binaryCell, int rowOrColumn) { + private String checkOppositeDigitDifference( + ArrayList seq, + BinaryBoard origBoard, + BinaryCell binaryCell, + int rowOrColumn) { // rowOrColumn : 0 for row, 1 for column int numEmpty = getNumEmpty(seq); @@ -83,7 +83,8 @@ private String checkOppositeDigitDifference(ArrayList seq, BinaryBoa valid = false; break; } - // Count differences between the sequences, stopping if more than 1 difference is found + // Count differences between the sequences, stopping if more than 1 difference is + // found if (!seq.get(j).equals(currSeq.get(j)) && !seq.get(j).equals(BinaryType.UNKNOWN)) { if (++numDifferentCells > 1 || numEmpty != 1) { valid = false; @@ -92,17 +93,18 @@ private String checkOppositeDigitDifference(ArrayList seq, BinaryBoa } // Check if there's a contradiction with the current cell, if not mark as valid - if (currSeq.get(j).equals(BinaryType.ZERO) && seq.get(j).equals(BinaryType.UNKNOWN) + if (currSeq.get(j).equals(BinaryType.ZERO) + && seq.get(j).equals(BinaryType.UNKNOWN) && binaryCell.getType().equals(BinaryType.ONE)) { - if ((rowOrColumn == 0 && binaryCell.getLocation().x == j) || rowOrColumn == 1 - && binaryCell.getLocation().y == j) { + if ((rowOrColumn == 0 && binaryCell.getLocation().x == j) + || rowOrColumn == 1 && binaryCell.getLocation().y == j) { valid = true; } - } - else if (currSeq.get(j).equals(BinaryType.ONE) && seq.get(j).equals(BinaryType.UNKNOWN) + } else if (currSeq.get(j).equals(BinaryType.ONE) + && seq.get(j).equals(BinaryType.UNKNOWN) && binaryCell.getType().equals(BinaryType.ZERO)) { - if ((rowOrColumn == 0 && binaryCell.getLocation().x == j) || rowOrColumn == 1 - && binaryCell.getLocation().y == j) { + if ((rowOrColumn == 0 && binaryCell.getLocation().x == j) + || rowOrColumn == 1 && binaryCell.getLocation().y == j) { valid = true; } } @@ -130,8 +132,12 @@ else if (currSeq.get(j).equals(BinaryType.ONE) && seq.get(j).equals(BinaryType.U * @param zeroOrOne Flag to indicate whether checking for 0s (0) or 1s (1) * @return Null if the rule can be applied, otherwise an error message */ - private String checkRemainingOneDigitDifference(ArrayList seq, BinaryBoard origBoard, - BinaryCell binaryCell, int rowOrColumn, int zeroOrOne) { + private String checkRemainingOneDigitDifference( + ArrayList seq, + BinaryBoard origBoard, + BinaryCell binaryCell, + int rowOrColumn, + int zeroOrOne) { // zeroOrOne: zero for 0, one for 1 for (int i = 0; i < seq.size(); i++) { @@ -141,8 +147,7 @@ private String checkRemainingOneDigitDifference(ArrayList seq, Binar continue; } currSeq = origBoard.getRowTypes(i); - } - else { + } else { if (i == binaryCell.getLocation().x) { continue; } @@ -172,24 +177,27 @@ private String checkRemainingOneDigitDifference(ArrayList seq, Binar currSeqCell = currSeq.get(binaryCell.getLocation().y); } - // Check if this sequence has only one more zero remaining and current sequence fills that zero in, + // Check if this sequence has only one more zero remaining and current sequence + // fills that zero in, // if so, zero in this seq must go in another cell to prevent repetition if (zeroOrOne == 0) { - if (currSeqCell.equals(BinaryType.ZERO) && binaryCell.getType().equals(BinaryType.ONE)) { + if (currSeqCell.equals(BinaryType.ZERO) + && binaryCell.getType().equals(BinaryType.ONE)) { return null; } } - // Check if this sequence has only one more one remaining and current sequence fills that one in, + // Check if this sequence has only one more one remaining and current sequence fills + // that one in, // if so, one in this seq must go in another cell to prevent repetition else if (zeroOrOne == 1) { - if (currSeqCell.equals(BinaryType.ONE) && binaryCell.getType().equals(BinaryType.ZERO)) { + if (currSeqCell.equals(BinaryType.ONE) + && binaryCell.getType().equals(BinaryType.ZERO)) { return null; } } } } - return "There does not exist a sequence that can be prevented by a remaining digit difference"; } @@ -206,7 +214,8 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem BinaryBoard origBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); BinaryCell binaryCell = (BinaryCell) puzzleElement; - // Check if filling the current cell with the opposite digit would prevent repetition with another row + // Check if filling the current cell with the opposite digit would prevent repetition with + // another row ArrayList row = origBoard.getRowTypes(binaryCell.getLocation().y); if (checkOppositeDigitDifference(row, origBoard, binaryCell, 0) == null) { return null; @@ -216,15 +225,14 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem for (int i = 0; i < row.size(); i++) { if (row.get(i).equals(BinaryType.ZERO)) { numZeros++; - } - else if (row.get(i).equals(BinaryType.ONE)) { + } else if (row.get(i).equals(BinaryType.ONE)) { numOnes++; } } // Check if only one more zero is needed, then see this row will be repeated by another row // if current cell is filled in with last zero as well - if (numZeros == row.size()/2 - 1) { + if (numZeros == row.size() / 2 - 1) { if (checkRemainingOneDigitDifference(row, origBoard, binaryCell, 0, 0) == null) { return null; } @@ -232,13 +240,14 @@ else if (row.get(i).equals(BinaryType.ONE)) { // Check if only one more one is needed, then see this row will be repeated by another row // if current cell is filled in with last one as well - if (numOnes == row.size()/2 - 1) { + if (numOnes == row.size() / 2 - 1) { if (checkRemainingOneDigitDifference(row, origBoard, binaryCell, 0, 1) == null) { return null; } } - // Check if filling the current cell with the opposite digit would prevent repetition with another column + // Check if filling the current cell with the opposite digit would prevent repetition with + // another column ArrayList col = origBoard.getColTypes(binaryCell.getLocation().x); if (checkOppositeDigitDifference(col, origBoard, binaryCell, 1) == null) { return null; @@ -249,29 +258,31 @@ else if (row.get(i).equals(BinaryType.ONE)) { for (int i = 0; i < col.size(); i++) { if (col.get(i).equals(BinaryType.ZERO)) { numZeros++; - } - else if (col.get(i).equals(BinaryType.ONE)) { + } else if (col.get(i).equals(BinaryType.ONE)) { numOnes++; } } - // Check if only one more zero is needed, then see this column will be repeated by another column + // Check if only one more zero is needed, then see this column will be repeated by another + // column // if current cell is filled in with last zero as well - if (numZeros == col.size()/2 - 1) { + if (numZeros == col.size() / 2 - 1) { if (checkRemainingOneDigitDifference(col, origBoard, binaryCell, 1, 0) == null) { return null; } } - // Check if only one more one is needed, then see this column will be repeated by another column + // Check if only one more one is needed, then see this column will be repeated by another + // column // if current cell is filled in with last one as well - if (numOnes == col.size()/2 - 1) { + if (numOnes == col.size() / 2 - 1) { if (checkRemainingOneDigitDifference(col, origBoard, binaryCell, 1, 1) == null) { return null; } } - return "There is no row/column that forces this cell to be a " + binaryCell.getData().toString(); + return "There is no row/column that forces this cell to be a " + + binaryCell.getData().toString(); } /** diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/WastedBlockerContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/WastedBlockerContradictionRule.java index e7ab51b41..ef5fc0e7e 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/WastedBlockerContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/WastedBlockerContradictionRule.java @@ -6,18 +6,18 @@ import edu.rpi.legup.puzzle.binary.BinaryBoard; import edu.rpi.legup.puzzle.binary.BinaryCell; import edu.rpi.legup.puzzle.binary.BinaryType; - import java.util.ArrayList; public class WastedBlockerContradictionRule extends ContradictionRule { - private final String NO_CONTRADICTION_MESSAGE = "Does not contain a contradiction at this index"; + private final String NO_CONTRADICTION_MESSAGE = + "Does not contain a contradiction at this index"; public WastedBlockerContradictionRule() { super( "BINA-CONT-0004", "Wasted Blocker", - "There exists a cell in this row/column that allocates a digit unnecessarily and" + - " will cause a future trio to appear", + "There exists a cell in this row/column that allocates a digit unnecessarily and" + + " will cause a future trio to appear", "edu/rpi/legup/images/binary/rules/WastedBlockerContradictionRule.png"); } @@ -29,7 +29,8 @@ public WastedBlockerContradictionRule() { neededZeros = ( n + i + j ) / 3 */ /** - * Calculates the number of zeros needed in a sequence based on the values on either side and the number of empty cells. + * Calculates the number of zeros needed in a sequence based on the values on either side and + * the number of empty cells. * * @param leftVal The value on the left side of the empty cells * @param rightVal The value on the right side of the empty cells @@ -56,7 +57,8 @@ private int calculateNeededZeros(int leftVal, int rightVal, int emptyCellsInCurS neededOnes = ( n + ( 1 - i ) + ( 1 - j ) ) / 3 */ /** - * Calculates the number of ones needed in a sequence based on the values on either side and the number of empty cells + * Calculates the number of ones needed in a sequence based on the values on either side and the + * number of empty cells * * @param leftVal The value on the left side of the empty cells * @param rightVal The value on the right side of the empty cells @@ -102,10 +104,10 @@ private String checkSequence(ArrayList seq) { int leftVal; int rightVal; // Check if left cell is out of bounds - if (i-emptyCellsInCurSec-1 < 0) { + if (i - emptyCellsInCurSec - 1 < 0) { leftVal = -1; } else { - leftVal = seq.get(i-emptyCellsInCurSec-1).toValue(); + leftVal = seq.get(i - emptyCellsInCurSec - 1).toValue(); } rightVal = seq.get(i).toValue(); neededZeros += calculateNeededZeros(leftVal, rightVal, emptyCellsInCurSec); @@ -128,10 +130,10 @@ private String checkSequence(ArrayList seq) { int leftVal; int rightVal; // Check if left cell is out of bounds - if (seq.size()-1-emptyCellsInCurSec-1 < 0) { + if (seq.size() - 1 - emptyCellsInCurSec - 1 < 0) { leftVal = -1; } else { - leftVal = seq.get(seq.size()-1-emptyCellsInCurSec).toValue(); + leftVal = seq.get(seq.size() - 1 - emptyCellsInCurSec).toValue(); } rightVal = -1; neededZeros += calculateNeededZeros(leftVal, rightVal, emptyCellsInCurSec); @@ -141,7 +143,7 @@ private String checkSequence(ArrayList seq) { // Check if the number of needed zeros or ones exceeds half the sequence length // If so, return null to indicate contradiction has occurred - if ((numZeros + neededZeros > seq.size()/2) || (numOnes + neededOnes > seq.size()/2)) { + if ((numZeros + neededZeros > seq.size() / 2) || (numOnes + neededOnes > seq.size() / 2)) { return null; } diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ZeroOrOneCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ZeroOrOneCaseRule.java index 3ae7a424d..f47fe55b9 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ZeroOrOneCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ZeroOrOneCaseRule.java @@ -39,18 +39,21 @@ public String checkRuleRaw(TreeTransition transition) { TreeTransition case2 = childTransitions.get(1); if (case1.getBoard().getModifiedData().size() != 1 || case2.getBoard().getModifiedData().size() != 1) { - return super.getInvalidUseOfRuleMessage() + ": This case rule must have 1 modified cell for each case."; + return super.getInvalidUseOfRuleMessage() + + ": This case rule must have 1 modified cell for each case."; } BinaryCell mod1 = (BinaryCell) case1.getBoard().getModifiedData().iterator().next(); BinaryCell mod2 = (BinaryCell) case2.getBoard().getModifiedData().iterator().next(); if (!mod1.getLocation().equals(mod2.getLocation())) { - return super.getInvalidUseOfRuleMessage() + ": This case rule must modify the same cell for each case."; + return super.getInvalidUseOfRuleMessage() + + ": This case rule must modify the same cell for each case."; } if (!((mod1.getType() == BinaryType.ZERO && mod2.getType() == BinaryType.ONE) || (mod2.getType() == BinaryType.ZERO && mod1.getType() == BinaryType.ONE))) { - return super.getInvalidUseOfRuleMessage() + ": This case rule must modify an empty cell."; + return super.getInvalidUseOfRuleMessage() + + ": This case rule must modify an empty cell."; } return null; diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeController.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeController.java index f2fad0d50..44ead6fac 100644 --- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeController.java +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeController.java @@ -7,13 +7,12 @@ public class NurikabeController extends ElementController { /** - * Handles cell state changes in the nurikabe puzzle when a mouse event occurs - * If the left mouse button is clicked: - * - If the control key is held down, shows a context menu at the mouse position - * - Otherwise, toggles the cell data state between 0, -1, and -2 in a cyclic manner - * If the right mouse button is clicked, the cell data state is also toggled between -2, -1, and 0 + * Handles cell state changes in the nurikabe puzzle when a mouse event occurs If the left mouse + * button is clicked: - If the control key is held down, shows a context menu at the mouse + * position - Otherwise, toggles the cell data state between 0, -1, and -2 in a cyclic manner If + * the right mouse button is clicked, the cell data state is also toggled between -2, -1, and 0 * - * @param e MouseEvent triggered by the user interaction + * @param e MouseEvent triggered by the user interaction * @param data PuzzleElement representing the cell being modified */ @Override diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/FinishRoomCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/FinishRoomCaseRule.java index dd8943cdb..025212d96 100644 --- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/FinishRoomCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/FinishRoomCaseRule.java @@ -17,8 +17,10 @@ import java.util.Set; public class FinishRoomCaseRule extends CaseRule { - private int legitCases = 0; // placeholder for amount of cases originally generated in case user tries to delete + private int legitCases = + 0; // placeholder for amount of cases originally generated in case user tries to delete private Set uniqueCases; // stores the unique case hashes + // cases public FinishRoomCaseRule() { @@ -84,19 +86,27 @@ public CaseBoard getCaseBoard(Board board) { DisjointSets regions = NurikabeUtilities.getNurikabeRegions(nurikabeBoard); nurikabeBoard.setModifiable(false); - for (PuzzleElement element : nurikabeBoard.getPuzzleElements()) { // loops all puzzle elements - if (((NurikabeCell) element).getType() == NurikabeType.NUMBER) { // if the tile is a white number block - Set disRow = regions.getSet(((NurikabeCell) element)); // store the row of the white region - boolean only = true; // placeholder boolean of if the element being tested is the only number block in the room or not + for (PuzzleElement element : + nurikabeBoard.getPuzzleElements()) { // loops all puzzle elements + if (((NurikabeCell) element).getType() + == NurikabeType.NUMBER) { // if the tile is a white number block + Set disRow = + regions.getSet( + ((NurikabeCell) element)); // store the row of the white region + boolean only = + true; // placeholder boolean of if the element being tested is the only + // number block in the room or not for (NurikabeCell d : disRow) { // loops through tiles in the room - // if found another number tile and it's data is different from the element we're working with + // if found another number tile and it's data is different from the element + // we're working with if ((d.getType() == NurikabeType.NUMBER) && !(d.getData().equals(((NurikabeCell) element).getData()))) { only = false; } } - // if size of region is 1 less than the number block and the number block is only number block in the region + // if size of region is 1 less than the number block and the number block is only + // number block in the region if (disRow.size() < ((NurikabeCell) element).getData() && only) { caseBoard.addPickableElement(element); // add that room as a pickable element } @@ -120,10 +130,12 @@ public ArrayList getCases(Board board, PuzzleElement puzzleElement) { } NurikabeBoard nuriBoard = (NurikabeBoard) board.copy(); // nurikabe board to edit - NurikabeCell numberCell = nuriBoard.getCell( - ((NurikabeCell) puzzleElement).getLocation().x, - ((NurikabeCell) puzzleElement).getLocation().y - ); // number cell whose room we want to fill + NurikabeCell numberCell = + nuriBoard.getCell( + ((NurikabeCell) puzzleElement).getLocation().x, + ((NurikabeCell) puzzleElement) + .getLocation() + .y); // number cell whose room we want to fill Point origPoint = new Point(numberCell.getLocation().x, numberCell.getLocation().y); int filledRoomSize = numberCell.getData(); // size of room we want afterward @@ -138,12 +150,16 @@ public ArrayList getCases(Board board, PuzzleElement puzzleElement) { directions.add(top); directions.add(bot); - Set checkedPoints = new HashSet<>(); // add all into checked points and continue at start of loop if inside - DisjointSets regions = NurikabeUtilities.getNurikabeRegions(nuriBoard); // gathers regions + Set checkedPoints = + new HashSet<>(); // add all into checked points and continue at start of loop if + // inside + DisjointSets regions = + NurikabeUtilities.getNurikabeRegions(nuriBoard); // gathers regions Set numberCellRegion = regions.getSet(numberCell); // set of white spaces for (NurikabeCell d : numberCellRegion) { // loops through white spaces - generateCases(nuriBoard, d, filledRoomSize, directions, checkedPoints, cases, origPoint); + generateCases( + nuriBoard, d, filledRoomSize, directions, checkedPoints, cases, origPoint); } legitCases = cases.size(); @@ -162,16 +178,24 @@ public ArrayList getCases(Board board, PuzzleElement puzzleElement) { * @param cases the list of valid board cases generated * @param origPoint the original point of the number cell initiating the room filling */ - private void generateCases(NurikabeBoard nuriBoard, NurikabeCell currentCell, int filledRoomSize, - Set directions, Set checkedPoints, ArrayList cases, Point origPoint) { + private void generateCases( + NurikabeBoard nuriBoard, + NurikabeCell currentCell, + int filledRoomSize, + Set directions, + Set checkedPoints, + ArrayList cases, + Point origPoint) { for (Point direction : directions) { - Point newPoint = new Point( - currentCell.getLocation().x + direction.x, - currentCell.getLocation().y + direction.y - ); + Point newPoint = + new Point( + currentCell.getLocation().x + direction.x, + currentCell.getLocation().y + direction.y); - if (newPoint.x < 0 || newPoint.y < 0 || - newPoint.x >= nuriBoard.getWidth() || newPoint.y >= nuriBoard.getHeight()) { + if (newPoint.x < 0 + || newPoint.y < 0 + || newPoint.x >= nuriBoard.getWidth() + || newPoint.y >= nuriBoard.getHeight()) { continue; // out of bounds } @@ -181,15 +205,21 @@ private void generateCases(NurikabeBoard nuriBoard, NurikabeCell currentCell, in } if (newCell.getType() == NurikabeType.UNKNOWN) { - newCell.setData(NurikabeType.WHITE.toValue()); // changes adjacent cell color to white + newCell.setData( + NurikabeType.WHITE.toValue()); // changes adjacent cell color to white newCell.setModifiable(false); checkedPoints.add(newPoint); - DisjointSets regions = NurikabeUtilities.getNurikabeRegions(nuriBoard); // update regions variable - Set newRoomSet = regions.getSet(newCell); // gets set of cells in room with new white cell added + DisjointSets regions = + NurikabeUtilities.getNurikabeRegions(nuriBoard); // update regions variable + Set newRoomSet = + regions.getSet( + newCell); // gets set of cells in room with new white cell added - if (!touchesDifferentRoom(nuriBoard, newCell, filledRoomSize, directions, origPoint)) { - if (newRoomSet.size() == filledRoomSize) { // if adding white fills the room to exact size of + if (!touchesDifferentRoom( + nuriBoard, newCell, filledRoomSize, directions, origPoint)) { + if (newRoomSet.size() + == filledRoomSize) { // if adding white fills the room to exact size of // number block and doesn't connect with another room Board caseBoard = nuriBoard.copy(); // check if case for board already exists @@ -205,7 +235,14 @@ private void generateCases(NurikabeBoard nuriBoard, NurikabeCell currentCell, in cases.add(caseBoard); } } else if (newRoomSet.size() < filledRoomSize) { - generateCases(nuriBoard, newCell, filledRoomSize, directions, checkedPoints, cases, origPoint); + generateCases( + nuriBoard, + newCell, + filledRoomSize, + directions, + checkedPoints, + cases, + origPoint); } } newCell.setData(NurikabeType.UNKNOWN.toValue()); @@ -216,7 +253,8 @@ private void generateCases(NurikabeBoard nuriBoard, NurikabeCell currentCell, in } /** - * Determines if a given cell touches a different room by checking adjacent cells in specified directions. + * Determines if a given cell touches a different room by checking adjacent cells in specified + * directions. * * @param board the current Nurikabe board state * @param cell the cell being evaluated @@ -225,20 +263,27 @@ private void generateCases(NurikabeBoard nuriBoard, NurikabeCell currentCell, in * @param origPoint the original point of the number cell initiating the room filling * @return true if the cell touches a different room, false otherwise */ - private boolean touchesDifferentRoom(NurikabeBoard board, NurikabeCell cell, int origRoomSize, Set directions, Point origPoint) { + private boolean touchesDifferentRoom( + NurikabeBoard board, + NurikabeCell cell, + int origRoomSize, + Set directions, + Point origPoint) { for (Point direction : directions) { - Point adjacentPoint = new Point( - cell.getLocation().x + direction.x, - cell.getLocation().y + direction.y - ); + Point adjacentPoint = + new Point( + cell.getLocation().x + direction.x, cell.getLocation().y + direction.y); - if (adjacentPoint.x >= 0 && adjacentPoint.y >= 0 && - adjacentPoint.x < board.getWidth() && adjacentPoint.y < board.getHeight()) { // check if out of bounds + if (adjacentPoint.x >= 0 + && adjacentPoint.y >= 0 + && adjacentPoint.x < board.getWidth() + && adjacentPoint.y < board.getHeight()) { // check if out of bounds NurikabeCell adjacentCell = board.getCell(adjacentPoint.x, adjacentPoint.y); // check if the adjacent cell is a number cell if (adjacentCell.getType() == NurikabeType.NUMBER) { // check if it's different from the original number cell - if (origRoomSize != adjacentCell.getData() || (adjacentPoint.x != origPoint.x || adjacentPoint.y != origPoint.y)) { + if (origRoomSize != adjacentCell.getData() + || (adjacentPoint.x != origPoint.x || adjacentPoint.y != origPoint.y)) { return true; } } diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersClueView.java b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersClueView.java index 0e6345ff1..cfb3388ff 100644 --- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersClueView.java +++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersClueView.java @@ -55,13 +55,16 @@ public void drawElement(Graphics2D graphics2D) { int xText = location.x + (size.width - metrics.stringWidth(value)) / 2; int yText = location.y + ((size.height - metrics.getHeight()) / 2) + metrics.getAscent(); - // REPRESENT NO CLUE AS EMPTY STRING INSTEAD OF 0, SOLVING PUZZLES WITH NO CLUE IS CURRENTLY NOT WORKING - // IF YOU ARE IMPLEMENTING NO CLUE FUNCTIONALITY, UNCOMMENT BELOW CODE AND DELETE OTHER IF STATEMENT, - // ADDITIONALLY, GO TO SkyscrapersBoard AND EDIT LINES 220 AND 223 SO YOU CAN CYCLE FOR NO CLUE + // REPRESENT NO CLUE AS EMPTY STRING INSTEAD OF 0, SOLVING PUZZLES WITH NO CLUE IS CURRENTLY + // NOT WORKING + // IF YOU ARE IMPLEMENTING NO CLUE FUNCTIONALITY, UNCOMMENT BELOW CODE AND DELETE OTHER IF + // STATEMENT, + // ADDITIONALLY, GO TO SkyscrapersBoard AND EDIT LINES 220 AND 223 SO YOU CAN CYCLE FOR NO + // CLUE // IN THE SKYSCRAPERS PUZZLE EDITOR -// if (value.equals("0")) { -// value = ""; -// } + // if (value.equals("0")) { + // value = ""; + // } if (value.equals("0")) { value = "1"; clue.setData(1); diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuCell.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuCell.java index 4e194ae2c..75e5820a0 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuCell.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuCell.java @@ -15,10 +15,10 @@ public class SudokuCell extends GridCell { /** * SudokuCell Constructor - creates a new Sudoku cell to hold the puzzleElement * - * @param value value of the sudoku cell - * @param location location of the cell on the board + * @param value value of the sudoku cell + * @param location location of the cell on the board * @param groupIndex index of the group the cell is in on the board - * @param size size of the sudoku cell + * @param size size of the sudoku cell */ public SudokuCell(int value, Point location, int groupIndex, int size) { super(value, location); @@ -73,23 +73,19 @@ public void setType(Element e, MouseEvent m) { if (m.getButton() == MouseEvent.BUTTON1) { if (this.data <= 0 || this.data > 8) { this.data = 1; - } - else { + } else { this.data = this.data + 1; } - } - else { + } else { if (m.getButton() == MouseEvent.BUTTON3) { if (this.data > 1) { this.data = this.data - 1; - } - else { + } else { this.data = 9; } } } - } - else if (e.getElementName().equals("Unknown Tile")) { + } else if (e.getElementName().equals("Unknown Tile")) { this.data = 0; } } diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuView.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuView.java index d2a8d95ab..474feb342 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuView.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuView.java @@ -22,12 +22,12 @@ public SudokuView(SudokuBoard board) { for (int k = 0; k < gridSize.width; k++) { Point location = new Point( - k * elementSize.width + (k / minorSize) * 4 + 5,// - i * elementSize.height + (i / minorSize) * 4 + 5); -// Point location = -// new Point( -// k * elementSize.width, -// i * elementSize.height); + k * elementSize.width + (k / minorSize) * 4 + 5, // + i * elementSize.height + (i / minorSize) * 4 + 5); + // Point location = + // new Point( + // k * elementSize.width, + // i * elementSize.height); SudokuElementView element = new SudokuElementView(board.getCell(k, i)); element.setIndex(i * gridSize.width + k); element.setIndex(i * gridSize.width); diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/elements/NumberTile.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/elements/NumberTile.java index b8f4a596c..a94d10e64 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/elements/NumberTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/elements/NumberTile.java @@ -1,4 +1,3 @@ - package edu.rpi.legup.puzzle.sudoku.elements; import edu.rpi.legup.model.elements.PlaceableElement; @@ -11,4 +10,4 @@ public NumberTile() { "A number tile", "edu/rpi/legup/images/sudoku/tiles/NumberTile.png"); } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/elements/UnknownTile.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/elements/UnknownTile.java index 162ba46d1..eb9a2c103 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/elements/UnknownTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/elements/UnknownTile.java @@ -10,4 +10,4 @@ public UnknownTile() { "A blank tile", "edu/rpi/legup/images/sudoku/tiles/UnknownTile.png"); } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTent.java b/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTent.java index 4b0113232..35993303a 100644 --- a/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTent.java +++ b/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTent.java @@ -4,7 +4,6 @@ import edu.rpi.legup.model.gameboard.Board; import edu.rpi.legup.model.gameboard.PuzzleElement; import edu.rpi.legup.model.rules.ContradictionRule; - import java.util.List; public class TreeTent extends Puzzle { diff --git a/src/main/java/edu/rpi/legup/ui/CreatePuzzleDialog.java b/src/main/java/edu/rpi/legup/ui/CreatePuzzleDialog.java index b1aa24eca..bde2df3d5 100644 --- a/src/main/java/edu/rpi/legup/ui/CreatePuzzleDialog.java +++ b/src/main/java/edu/rpi/legup/ui/CreatePuzzleDialog.java @@ -11,8 +11,8 @@ import javax.swing.*; /** - * Provides the user interface components for creating a new puzzle in the Legup application. - * This package includes classes for displaying dialog boxes to configure and initialize puzzles. + * Provides the user interface components for creating a new puzzle in the Legup application. This + * package includes classes for displaying dialog boxes to configure and initialize puzzles. */ public class CreatePuzzleDialog extends JDialog { private HomePanel homePanel; @@ -22,11 +22,12 @@ public class CreatePuzzleDialog extends JDialog { private ActionListener gameBoxListener = new ActionListener() { /** - * An ActionListener that handles changes in the drop-down menu for selecting puzzle types. - * When a new item is selected in the drop-down menu, this listener updates the visibility of - * the text input area and the row/column input fields based on the selected puzzle type. - * If "ShortTruthTable" is selected, the text input area is shown and the row/column fields are hidden. - * For other puzzle types, the row/column fields are shown and the text input area is hidden. + * An ActionListener that handles changes in the drop-down menu for selecting puzzle + * types. When a new item is selected in the drop-down menu, this listener updates + * the visibility of the text input area and the row/column input fields based on + * the selected puzzle type. If "ShortTruthTable" is selected, the text input area + * is shown and the row/column fields are hidden. For other puzzle types, the + * row/column fields are shown and the text input area is hidden. */ @Override public void actionPerformed(ActionEvent e) { @@ -76,9 +77,7 @@ public void actionPerformed(ActionEvent ae) { return; } if (!game.equals("ShortTruthTable") - && (game.isEmpty() - || getRows().isEmpty() - || getColumns().isEmpty())) { + && (game.isEmpty() || getRows().isEmpty() || getColumns().isEmpty())) { System.out.println("Unfilled fields"); return; } @@ -200,8 +199,8 @@ public CreatePuzzleDialog(JFrame parent, HomePanel homePanel) { } /** - * Initializes the puzzle options available for selection in the dialog. - * The options are retrieved from the game board facade and sorted alphabetically. + * Initializes the puzzle options available for selection in the dialog. The options are + * retrieved from the game board facade and sorted alphabetically. */ public void initPuzzles() { this.games = @@ -213,9 +212,9 @@ public void initPuzzles() { gameBox = new JComboBox(this.games); } - /** - * Handles the action events for the dialog, including interactions with the Ok and Cancel buttons + * Handles the action events for the dialog, including interactions with the Ok and Cancel + * buttons * * @param e The action event to be processed */ @@ -235,7 +234,8 @@ public void actionPerformed(ActionEvent e) { } this.setVisible(false); } catch (IllegalArgumentException exception) { - // Do nothing. This is here to prevent the dialog from closing if the dimensions are invalid. + // Do nothing. This is here to prevent the dialog from closing if the dimensions are + // invalid. } } else { if (e.getSource() == cancel) { @@ -278,5 +278,7 @@ public String getColumns() { * * @return an array of strings, each representing as a line of text */ - public String[] getTextArea() { return textArea.getText().split("\n"); } + public String[] getTextArea() { + return textArea.getText().split("\n"); + } } diff --git a/src/main/java/edu/rpi/legup/ui/DynamicView.java b/src/main/java/edu/rpi/legup/ui/DynamicView.java index 344885783..fa0004d0b 100644 --- a/src/main/java/edu/rpi/legup/ui/DynamicView.java +++ b/src/main/java/edu/rpi/legup/ui/DynamicView.java @@ -244,16 +244,12 @@ public void updateError(String message) { status.setText(message); } - /** - * Clears the status label - */ + /** Clears the status label */ public void resetStatus() { status.setText(""); } - /** - * Resets the view to its default state and zooms the content to fit the screen - */ + /** Resets the view to its default state and zooms the content to fit the screen */ public void reset() { Puzzle puzzle = GameBoardFacade.getInstance().getPuzzleModule(); Board board1 = GameBoardFacade.getInstance().getBoard(); @@ -262,9 +258,7 @@ public void reset() { this.getScrollView().zoomFit(); } - /** - * Fits the board view to the screen - */ + /** Fits the board view to the screen */ protected void fitBoardViewToScreen() { scrollView.zoomFit(); } diff --git a/src/main/java/edu/rpi/legup/ui/DynamicViewType.java b/src/main/java/edu/rpi/legup/ui/DynamicViewType.java index d161f5b9c..c4bb940e0 100644 --- a/src/main/java/edu/rpi/legup/ui/DynamicViewType.java +++ b/src/main/java/edu/rpi/legup/ui/DynamicViewType.java @@ -3,9 +3,10 @@ /** * An enumeration representing the different types of dynamic views supported by the application. * The two types of views are: + * *

    - *
  • {@code BOARD} - Represents a dynamic view of a game board
  • - *
  • {@code PROOF_TREE} - Represents a dynamic view of a proof tree
  • + *
  • {@code BOARD} - Represents a dynamic view of a game board + *
  • {@code PROOF_TREE} - Represents a dynamic view of a proof tree *
*/ public enum DynamicViewType { diff --git a/src/main/java/edu/rpi/legup/ui/HomePanel.java b/src/main/java/edu/rpi/legup/ui/HomePanel.java index f12ffdbf0..75761c475 100644 --- a/src/main/java/edu/rpi/legup/ui/HomePanel.java +++ b/src/main/java/edu/rpi/legup/ui/HomePanel.java @@ -26,10 +26,9 @@ import org.xml.sax.helpers.DefaultHandler; /** - * The {@code HomePanel} class represents the home panel of the LEGUP application. - * This panel provides buttons for functionalities of opening the proof editor, - * opening the puzzle editor, and performing batch grading. It also includes a menu bar with - * options for preferences. + * The {@code HomePanel} class represents the home panel of the LEGUP application. This panel + * provides buttons for functionalities of opening the proof editor, opening the puzzle editor, and + * performing batch grading. It also includes a menu bar with options for preferences. */ public class HomePanel extends LegupPanel { private static final Logger LOGGER = LogManager.getLogger(HomePanel.class.getName()); @@ -42,9 +41,7 @@ public class HomePanel extends LegupPanel { private final int buttonSize = 100; - /** - * Initialize the proof solver to an empty panel with no puzzle - */ + /** Initialize the proof solver to an empty panel with no puzzle */ private ActionListener openProofListener = new ActionListener() { @Override @@ -101,9 +98,7 @@ public JMenuBar getMenuBar() { return this.menuBar; } - /** - * Makes the panel visible and sets the menu bar of the frame - */ + /** Makes the panel visible and sets the menu bar of the frame */ @Override public void makeVisible() { render(); @@ -124,9 +119,7 @@ private static ImageIcon resizeButtonIcon(ImageIcon icon, int width, int height) return new ImageIcon(resizedImage); } - /** - * Initializes the buttons for this panel - */ + /** Initializes the buttons for this panel */ private void initButtons() { this.buttons = new JButton[3]; @@ -188,8 +181,8 @@ public void actionPerformed(ActionEvent e) { } /** - * Opens a folder chooser dialog and grades puzzles in the selected folder. - * The results are written to a CSV file. + * Opens a folder chooser dialog and grades puzzles in the selected folder. The results are + * written to a CSV file. */ public void checkFolder() { GameBoardFacade facade = GameBoardFacade.getInstance(); @@ -276,12 +269,12 @@ public void checkFolder() { } /** - * Processes XML files within a selected directory and generates a CSV report on their "solved?" status. - * The method allows the user to select a directory, and evaluates each XML file for a "solved?" status. - * Results are saved in a "result.csv" file. + * Processes XML files within a selected directory and generates a CSV report on their "solved?" + * status. The method allows the user to select a directory, and evaluates each XML file for a + * "solved?" status. Results are saved in a "result.csv" file. * - * @effect Selects a directory, processes each XML file to check for "solved?" status, - * and writes results to "result.csv". Opens the CSV file upon completion. + * @effect Selects a directory, processes each XML file to check for "solved?" status, and + * writes results to "result.csv". Opens the CSV file upon completion. */ private void use_xml_to_check() { /* Select a folder, go through each .xml file in the subfolders, look for "isSolved" flag */ @@ -481,8 +474,8 @@ public void endDocument() throws SAXException { } /** - * Initializes the text labels for the user interface. - * Sets up labels for welcome message, led by Bram, and version information. + * Initializes the text labels for the user interface. Sets up labels for welcome message, led + * by Bram, and version information. */ private void initText() { // TODO: add version text after auto-changing version label is implemented. (text[2] = @@ -505,9 +498,7 @@ private void initText() { this.text[1] = credits; } - /** - * Renders the user interface components - */ + /** Renders the user interface components */ private void render() { this.removeAll(); @@ -536,7 +527,8 @@ private void render() { /** * Opens the puzzle editor dialog with no selected puzzle, leaving a blank panel * - * @throws IllegalArgumentException if the configuration parameters are invalid (should never happen) + * @throws IllegalArgumentException if the configuration parameters are invalid (should never + * happen) */ private void openPuzzleEditorDialog() { String game = ""; @@ -668,11 +660,10 @@ private void traverseDir(File folder, BufferedWriter writer, String path) throws */ public void openEditorWithNewPuzzle(String game, int rows, int columns) throws IllegalArgumentException { - if (game.equals("")) { + if (game.isEmpty()) { this.legupUI.displayPanel(2); this.legupUI.getPuzzleEditor().loadPuzzleFromHome(game, rows, columns); - } - else { + } else { // Validate the dimensions GameBoardFacade facade = GameBoardFacade.getInstance(); boolean isValidDimensions = facade.validateDimensions(game, rows, columns); @@ -695,7 +686,6 @@ public void openEditorWithNewPuzzle(String game, int rows, int columns) this.legupUI.displayPanel(2); this.legupUI.getPuzzleEditor().loadPuzzleFromHome(game, rows, columns); } - } /** diff --git a/src/main/java/edu/rpi/legup/ui/LegupPanel.java b/src/main/java/edu/rpi/legup/ui/LegupPanel.java index 38c44cbe4..639f21211 100644 --- a/src/main/java/edu/rpi/legup/ui/LegupPanel.java +++ b/src/main/java/edu/rpi/legup/ui/LegupPanel.java @@ -3,17 +3,14 @@ import javax.swing.*; /** - * An abstract base class for panels in the LEGUP application. - * This class extends {@link JPanel} and defines common properties and methods - * for all panels in the LEGUP user interface - * (currently only implements toolbar scale) + * An abstract base class for panels in the LEGUP application. This class extends {@link JPanel} and + * defines common properties and methods for all panels in the LEGUP user interface (currently only + * implements toolbar scale) */ public abstract class LegupPanel extends JPanel { /** Alerts panel that it will be going visible now */ protected final int TOOLBAR_ICON_SCALE = 40; - /** - * Abstract method to make the panel visible - */ + /** Abstract method to make the panel visible */ public abstract void makeVisible(); } diff --git a/src/main/java/edu/rpi/legup/ui/LegupUI.java b/src/main/java/edu/rpi/legup/ui/LegupUI.java index 30857f05f..75f822a6c 100644 --- a/src/main/java/edu/rpi/legup/ui/LegupUI.java +++ b/src/main/java/edu/rpi/legup/ui/LegupUI.java @@ -15,9 +15,9 @@ import org.apache.logging.log4j.Logger; /** - * The main user interface class for the LEGUP application. - * This class extends {@link JFrame} and implements {@link WindowListener} - * to manage the overall window and provide functionality for displaying various panels. + * The main user interface class for the LEGUP application. This class extends {@link JFrame} and + * implements {@link WindowListener} to manage the overall window and provide functionality for + * displaying various panels. */ public class LegupUI extends JFrame implements WindowListener { private static final Logger LOGGER = LogManager.getLogger(LegupUI.class.getName()); @@ -96,10 +96,7 @@ public void keyTyped(KeyEvent e) { setVisible(true); } - /** - * Initializes the panels used in the UI. - * Sets up the layout and adds panels to the window. - */ + /** Initializes the panels used in the UI. Sets up the layout and adds panels to the window. */ private void initPanels() { window = new JPanel(); window.setLayout(new BorderLayout()); @@ -148,9 +145,7 @@ public PuzzleEditorPanel getPuzzleEditor() { return (PuzzleEditorPanel) panels[2]; } - /** - * Repaints the tree view in the proof editor. - */ + /** Repaints the tree view in the proof editor. */ public void repaintTree() { getProofEditor().repaintTree(); } diff --git a/src/main/java/edu/rpi/legup/ui/PickGameDialog.java b/src/main/java/edu/rpi/legup/ui/PickGameDialog.java index a6501e2a0..3b66931a7 100644 --- a/src/main/java/edu/rpi/legup/ui/PickGameDialog.java +++ b/src/main/java/edu/rpi/legup/ui/PickGameDialog.java @@ -16,9 +16,8 @@ import javax.swing.JTextField; /** - * A dialog for selecting a game. - * This class extends {@link JDialog} and implements {@link ActionListener} - * to handle user interactions for selecting a game type and puzzle file. + * A dialog for selecting a game. This class extends {@link JDialog} and implements {@link + * ActionListener} to handle user interactions for selecting a game type and puzzle file. */ public class PickGameDialog extends JDialog implements ActionListener { JLabel gameLabel = new JLabel("Game:"); @@ -112,8 +111,8 @@ public PickGameDialog(JFrame parent, boolean pickBothAtOnce) { } /** - * Initializes the available games and puzzles. - * Populates the {@link JComboBox} with game types and sets up the puzzle options. + * Initializes the available games and puzzles. Populates the {@link JComboBox} with game types + * and sets up the puzzle options. */ public void initPuzzles() { Object[] o = GameBoardFacade.getInstance().getConfig().getPuzzleClassNames().toArray(); @@ -156,9 +155,8 @@ public String getGame() { } /** - * Handles action events for the dialog components. - * Responds to user interactions such as selecting a puzzle, choosing a puzzle file, - * and pressing the 'Ok' or 'Cancel' buttons. + * Handles action events for the dialog components. Responds to user interactions such as + * selecting a puzzle, choosing a puzzle file, and pressing the 'Ok' or 'Cancel' buttons. * * @param e the action event */ diff --git a/src/main/java/edu/rpi/legup/ui/PreferencesDialog.java b/src/main/java/edu/rpi/legup/ui/PreferencesDialog.java index c8639f796..e90d06640 100644 --- a/src/main/java/edu/rpi/legup/ui/PreferencesDialog.java +++ b/src/main/java/edu/rpi/legup/ui/PreferencesDialog.java @@ -18,10 +18,10 @@ import javax.swing.*; /** - * A dialog for managing user preferences in the LEGUP application. - * This dialog allows users to configure various settings such as screen mode, - * update preferences, work directory path, and specific features related to board and tree views. - * Users can access this dialog from the home screen or proof editor. + * A dialog for managing user preferences in the LEGUP application. This dialog allows users to + * configure various settings such as screen mode, update preferences, work directory path, and + * specific features related to board and tree views. Users can access this dialog from the home + * screen or proof editor. */ public class PreferencesDialog extends JDialog { @@ -364,10 +364,9 @@ private JScrollPane createPuzzleTab(Puzzle puzzle) { } /** - * Creates a JPanel that represents a single row for a rule in the rule list. - * Each row displays the rule's name and an area for showing keyboard shortcuts - * associated with the rule. The keyboard shortcuts are dynamically updated based - * on user input. + * Creates a JPanel that represents a single row for a rule in the rule list. Each row displays + * the rule's name and an area for showing keyboard shortcuts associated with the rule. The + * keyboard shortcuts are dynamically updated based on user input. * * @param rule the rule object to be displayed * @return a JPanel representing the row for the rule @@ -425,9 +424,8 @@ public void keyPressed(KeyEvent e) { } /** - * Creates a JPanel containing a left-aligned label with the specified text. - * This label is typically used for section headings or descriptive text in the - * preferences dialog. + * Creates a JPanel containing a left-aligned label with the specified text. This label is + * typically used for section headings or descriptive text in the preferences dialog. * * @param text the text to be displayed on the label * @return a JPanel containing the left-aligned label @@ -446,8 +444,8 @@ private JPanel createLeftLabel(String text) { } /** - * Creates a JSeparator with a maximum height of 5 pixels. - * This separator is used to visually divide sections in the preferences dialog. + * Creates a JSeparator with a maximum height of 5 pixels. This separator is used to visually + * divide sections in the preferences dialog. * * @return a JSeparator with a fixed height */ @@ -458,10 +456,10 @@ private JSeparator createLineSeparator() { } /** - * Applies the current user preferences and updates the associated components. - * This method retrieves user preferences from the dialog's components and stores - * them in the {@link LegupPreferences} instance. It also updates the rule panels - * in the rules frame if it is not null. + * Applies the current user preferences and updates the associated components. This method + * retrieves user preferences from the dialog's components and stores them in the {@link + * LegupPreferences} instance. It also updates the rule panels in the rules frame if it is not + * null. */ public void applyPreferences() { LegupPreferences prefs = LegupPreferences.getInstance(); diff --git a/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java b/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java index 88c1ee427..5ecbd5564 100644 --- a/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java +++ b/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java @@ -17,7 +17,6 @@ import edu.rpi.legup.ui.boardview.BoardView; import edu.rpi.legup.ui.proofeditorui.rulesview.RuleFrame; import edu.rpi.legup.ui.proofeditorui.treeview.TreePanel; -import edu.rpi.legup.ui.proofeditorui.treeview.TreeTransitionView; import edu.rpi.legup.ui.proofeditorui.treeview.TreeViewSelection; import edu.rpi.legup.user.Submission; import java.awt.*; @@ -38,12 +37,11 @@ import org.apache.logging.log4j.Logger; /** - * {@code ProofEditorPanel} is a panel that serves as the main user interface - * component for the proof editing functionality of LEGUP. It provides - * the graphical components and interactive elements necessary for editing and managing - * proofs, including toolbars, menus, and views for different aspects of proof editing. - * It also manages interactions with the rest of the application and updates the UI - * based on user actions and application state changes. + * {@code ProofEditorPanel} is a panel that serves as the main user interface component for the + * proof editing functionality of LEGUP. It provides the graphical components and interactive + * elements necessary for editing and managing proofs, including toolbars, menus, and views for + * different aspects of proof editing. It also manages interactions with the rest of the application + * and updates the UI based on user actions and application state changes. */ public class ProofEditorPanel extends LegupPanel implements IHistoryListener { private static final Logger LOGGER = LogManager.getLogger(ProofEditorPanel.class.getName()); @@ -136,8 +134,8 @@ public ProofEditorPanel(FileDialog fileDialog, JFrame frame, LegupUI legupUI) { } /** - * Makes the panel visible by setting up the toolbar and content components. - * This method also sets the menu bar of the frame to the one used by this panel. + * Makes the panel visible by setting up the toolbar and content components. This method also + * sets the menu bar of the frame to the one used by this panel. */ @Override public void makeVisible() { @@ -149,20 +147,22 @@ public void makeVisible() { } /** - * Constructs and returns the {@code JMenuBar} for this panel. - * It populates it with various {@code JMenu} and {@code JMenuItem} components related - * to file operations, editing, viewing, and proof management. - * The menu bar includes: + * Constructs and returns the {@code JMenuBar} for this panel. It populates it with various + * {@code JMenu} and {@code JMenuItem} components related to file operations, editing, viewing, + * and proof management. The menu bar includes: + * *
    - *
  • {@code File} menu with options to open a new puzzle, reset the puzzle, save the proof, - * access preferences, and exit the editor.
  • - *
  • {@code Edit} menu with options for undo, redo, and fitting the board or tree to the screen.
  • - *
  • {@code Proof} menu with options for adding, deleting, merging, collapsing elements, - * and toggling settings related to rule applications and feedback.
  • - *
  • {@code About} menu with options to view information about the application and access help resources.
  • + *
  • {@code File} menu with options to open a new puzzle, reset the puzzle, save the proof, + * access preferences, and exit the editor. + *
  • {@code Edit} menu with options for undo, redo, and fitting the board or tree to the + * screen. + *
  • {@code Proof} menu with options for adding, deleting, merging, collapsing elements, and + * toggling settings related to rule applications and feedback. + *
  • {@code About} menu with options to view information about the application and access + * help resources. *
- *

- * Accelerator keys are set based on the operating system (Mac or non-Mac). + * + *

Accelerator keys are set based on the operating system (Mac or non-Mac). * * @return the {@code JMenuBar} instance containing the menus and menu items for this panel */ @@ -497,8 +497,8 @@ public void actionPerformed(ActionEvent e) { } /** - * Clears the current puzzle, resets the UI to display the initial panel, - * and nullifies the references to the tree panel and board view. + * Clears the current puzzle, resets the UI to display the initial panel, and nullifies the + * references to the tree panel and board view. */ public void exitEditor() { // Wipes the puzzle entirely as if LEGUP just started @@ -510,10 +510,11 @@ public void exitEditor() { /** * Opens a file chooser dialog allowing the user to select a directory. It uses the user's - * preferred directory or the last saved path if available. The selected directory is used - * to set the new working directory. + * preferred directory or the last saved path if available. The selected directory is used to + * set the new working directory. * - * @return an array containing the file name and the selected file, or {@code null} if the operation was canceled + * @return an array containing the file name and the selected file, or {@code null} if the + * operation was canceled */ public Object[] promptPuzzle() { GameBoardFacade facade = GameBoardFacade.getInstance(); @@ -559,10 +560,10 @@ public Object[] promptPuzzle() { } /** - * Calls {@link #promptPuzzle()} to get the file information and then loads the puzzle using - * the provided file name and file object. Updates the frame title to reflect the puzzle name. - * If the file is not valid or an error occurs, an error message is shown, and the user is - * prompted to try loading another puzzle. + * Calls {@link #promptPuzzle()} to get the file information and then loads the puzzle using the + * provided file name and file object. Updates the frame title to reflect the puzzle name. If + * the file is not valid or an error occurs, an error message is shown, and the user is prompted + * to try loading another puzzle. */ public void loadPuzzle() { Object[] items = promptPuzzle(); @@ -576,16 +577,16 @@ public void loadPuzzle() { } /** - * Attempts to load a puzzle from the given file. If successful, it updates the - * UI to display the puzzle and changes the frame title to include the puzzle name. If the - * file is invalid or cannot be read, it shows an appropriate error message and prompts the - * user to try loading another puzzle. + * Attempts to load a puzzle from the given file. If successful, it updates the UI to display + * the puzzle and changes the frame title to include the puzzle name. If the file is invalid or + * cannot be read, it shows an appropriate error message and prompts the user to try loading + * another puzzle. * * @param fileName the name of the file to load * @param puzzleFile the file object representing the puzzle file */ public void loadPuzzle(String fileName, File puzzleFile) { - if (puzzleFile == null && fileName.equals("")) { + if (puzzleFile == null && fileName.isEmpty()) { legupUI.displayPanel(1); } if (puzzleFile != null && puzzleFile.exists()) { @@ -623,9 +624,9 @@ public void loadPuzzle(String fileName, File puzzleFile) { } /** - * Uses the current puzzle and its associated exporter to save the puzzle data - * to the file currently being used. If the puzzle or exporter is null, or if an error occurs - * during export, the method will catch the exception and print the stack trace. + * Uses the current puzzle and its associated exporter to save the puzzle data to the file + * currently being used. If the puzzle or exporter is null, or if an error occurs during export, + * the method will catch the exception and print the stack trace. */ private void direct_save() { Puzzle puzzle = GameBoardFacade.getInstance().getPuzzleModule(); @@ -648,8 +649,8 @@ private void direct_save() { /** * Opens a file chooser dialog for the user to select a directory. The chosen directory is used - * to determine where the puzzle file will be saved. If an exporter is available, it will be used - * to export the puzzle data to the selected path. + * to determine where the puzzle file will be saved. If an exporter is available, it will be + * used to export the puzzle data to the selected path. */ private void saveProofAs() { Puzzle puzzle = GameBoardFacade.getInstance().getPuzzleModule(); @@ -689,9 +690,9 @@ private void saveProofAs() { // Hyperlink for help button; links to wiki page for tutorials /** - * Opens the default web browser to a help page related to the type of puzzle currently being used. - * The URL is chosen based on the name of the puzzle. If the puzzle type is not recognized, a general - * tutorial page is opened. + * Opens the default web browser to a help page related to the type of puzzle currently being + * used. The URL is chosen based on the name of the puzzle. If the puzzle type is not + * recognized, a general tutorial page is opened. */ private void helpTutorial() { // redirecting to certain help link in wiki @@ -745,9 +746,9 @@ public void actionPerformed(ActionEvent e) { } /** - * Saves the puzzle using the current file name and shows a message dialog to - * confirm that the save operation was successful. If the puzzle or exporter is null, or if - * an error occurs during export, the method will catch the exception and print the stack trace. + * Saves the puzzle using the current file name and shows a message dialog to confirm that the + * save operation was successful. If the puzzle or exporter is null, or if an error occurs + * during export, the method will catch the exception and print the stack trace. */ private void saveProofChange() { Puzzle puzzle = GameBoardFacade.getInstance().getPuzzleModule(); @@ -826,9 +827,9 @@ protected void setupContent() { } /** - * Initializes the first toolbar, configures its appearance, and adds an 'Open' button - * with an associated icon. An action listener is attached to the button to trigger the loading of - * a puzzle when clicked. + * Initializes the first toolbar, configures its appearance, and adds an 'Open' button with an + * associated icon. An action listener is attached to the button to trigger the loading of a + * puzzle when clicked. */ private void setupToolBar1() { toolBar1 = new JToolBar(); @@ -862,14 +863,15 @@ private void setupToolBar1() { } /** - * Initializes the second toolbar, configures its appearance, and adds four buttons each - * with associated icons. Action listeners are attached to each button to trigger their respective + * Initializes the second toolbar, configures its appearance, and adds four buttons each with + * associated icons. Action listeners are attached to each button to trigger their respective * actions when clicked: + * *

    - *
  • 'Directions' button triggers the `directionsToolButton` method.
  • - *
  • 'Undo' button triggers the undo action in the puzzle's history.
  • - *
  • 'Redo' button triggers the redo action in the puzzle's history.
  • - *
  • 'Check' button triggers the `checkProof` method.
  • + *
  • 'Directions' button triggers the `directionsToolButton` method. + *
  • 'Undo' button triggers the undo action in the puzzle's history. + *
  • 'Redo' button triggers the redo action in the puzzle's history. + *
  • 'Check' button triggers the `checkProof` method. *
*/ private void setupToolBar2() { @@ -933,9 +935,10 @@ private void setupToolBar2() { JButton redo = new JButton("Redo", RedoImageIcon); redo.setFocusPainted(false); - redo.addActionListener((ActionEvent) -> { - GameBoardFacade.getInstance().getHistory().redo(); - }); + redo.addActionListener( + (ActionEvent) -> { + GameBoardFacade.getInstance().getHistory().redo(); + }); getToolBar2Buttons()[2] = redo; toolBar2.add(getToolBar2Buttons()[2]); @@ -960,7 +963,6 @@ private void setupToolBar2() { getToolBar2Buttons()[3] = check; toolBar2.add(getToolBar2Buttons()[3]); - this.add(toolBar2, BorderLayout.NORTH); } @@ -1001,8 +1003,9 @@ public JButton[] getToolBar2Buttons() { } /** - * Uses the {@link GameBoardFacade} to obtain the current puzzle and board. If the puzzle is complete, - * it notifies the user of a correct proof. If not, it alerts the user that the board is not solved. + * Uses the {@link GameBoardFacade} to obtain the current puzzle and board. If the puzzle is + * complete, it notifies the user of a correct proof. If not, it alerts the user that the board + * is not solved. */ private void checkProof() { GameBoardFacade facade = GameBoardFacade.getInstance(); @@ -1031,42 +1034,49 @@ private void checkProof() { } /** - * Retrieves the puzzle name from the `GameBoardFacade` and opens a corresponding rules page in the default web browser. + * Retrieves the puzzle name from the `GameBoardFacade` and opens a corresponding rules page in + * the default web browser. * * @throws IOException if an error occurs while trying to open the web page */ private void directionsToolButton() { String puzzleName = GameBoardFacade.getInstance().getPuzzleModule().getName(); - //System.out.println(puzzleName); + // System.out.println(puzzleName); try { if (puzzleName.equals("Fillapix")) { java.awt.Desktop.getDesktop() - .browse(URI.create("https://github.com/Bram-Hub/LEGUP/wiki/Fill-a-pix-rules")); - } - else if (puzzleName.equals("LightUp")) { + .browse( + URI.create( + "https://github.com/Bram-Hub/LEGUP/wiki/Fill-a-pix-rules")); + } else if (puzzleName.equals("LightUp")) { java.awt.Desktop.getDesktop() - .browse(URI.create("https://github.com/Bram-Hub/LEGUP/wiki/Light-up-rules")); - } - else if (puzzleName.equals("TreeTent")) { + .browse( + URI.create( + "https://github.com/Bram-Hub/LEGUP/wiki/Light-up-rules")); + } else if (puzzleName.equals("TreeTent")) { java.awt.Desktop.getDesktop() - .browse(URI.create("https://github.com/Bram-Hub/LEGUP/wiki/Tree-tent-rules")); - } - else if (puzzleName.equals("ShortTruthTables")) { + .browse( + URI.create( + "https://github.com/Bram-Hub/LEGUP/wiki/Tree-tent-rules")); + } else if (puzzleName.equals("ShortTruthTables")) { java.awt.Desktop.getDesktop() - .browse(URI.create("https://github.com/Bram-Hub/LEGUP/wiki/Short-truth-table-rules")); - } - else { + .browse( + URI.create( + "https://github.com/Bram-Hub/LEGUP/wiki/Short-truth-table-rules")); + } else { java.awt.Desktop.getDesktop() - .browse(URI.create("https://github.com/Bram-Hub/LEGUP/wiki/" + puzzleName + "-rules")); + .browse( + URI.create( + "https://github.com/Bram-Hub/LEGUP/wiki/" + + puzzleName + + "-rules")); } } catch (IOException e) { LOGGER.error("Can't open web page"); } } - /** - * Repaints the board view and tree panel - */ + /** Repaints the board view and tree panel */ private void repaintAll() { boardView.repaint(); treePanel.repaint(); @@ -1081,7 +1091,6 @@ private void repaintAll() { public void setPuzzleView(Puzzle puzzle) { this.boardView = puzzle.getBoardView(); - dynamicBoardView = new DynamicView(boardView, DynamicViewType.BOARD); this.topHalfPanel.setRightComponent(dynamicBoardView); this.topHalfPanel.setVisible(true); @@ -1107,12 +1116,11 @@ public void setPuzzleView(Puzzle puzzle) { reloadGui(); } - /** - * Calls {@code repaintTree()} to refresh the tree view. - */ + /** Calls {@code repaintTree()} to refresh the tree view. */ public void reloadGui() { repaintTree(); } + /** * Updates the tree view displayed in the tree panel to reflect the current state of the tree. */ @@ -1242,7 +1250,6 @@ public BoardView getBoardView() { return boardView; } - /** * Returns the current dynamic board view. * @@ -1278,12 +1285,11 @@ public void onPushChange(ICommand command) { } /** - * Updates the state of the undo and redo buttons to reflect that there are no actions - * available to undo or redo. It disables both buttons when the history is cleared. + * Updates the state of the undo and redo buttons to reflect that there are no actions available + * to undo or redo. It disables both buttons when the history is cleared. */ @Override - public void onClearHistory() { - } + public void onClearHistory() {} /** * Called when an action is redone @@ -1359,10 +1365,7 @@ public void showStatus(String status, boolean error, int timer) { // TODO: implement } - - /** - * Zooms the tree view to fit within the available screen space - */ + /** Zooms the tree view to fit within the available screen space */ protected void fitTreeViewToScreen() { this.treePanel.getTreeView().zoomFit(); } diff --git a/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java b/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java index 2f3c16eac..7c2ba06ff 100644 --- a/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java +++ b/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java @@ -10,14 +10,9 @@ import edu.rpi.legup.history.IHistoryListener; import edu.rpi.legup.model.Puzzle; import edu.rpi.legup.model.PuzzleExporter; -import edu.rpi.legup.model.tree.Tree; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; import edu.rpi.legup.save.ExportFileException; import edu.rpi.legup.save.InvalidFileFormatException; -import edu.rpi.legup.ui.HomePanel; import edu.rpi.legup.ui.boardview.BoardView; -import edu.rpi.legup.ui.proofeditorui.treeview.TreeViewSelection; import edu.rpi.legup.ui.puzzleeditorui.elementsview.ElementFrame; import java.awt.*; import java.awt.event.ActionEvent; @@ -27,7 +22,6 @@ import java.io.IOException; import java.net.URI; import java.net.URL; -import java.util.List; import java.util.Objects; import javax.swing.*; import javax.swing.border.TitledBorder; @@ -35,9 +29,9 @@ import org.apache.logging.log4j.Logger; /** - * Represents the panel used for puzzle editor in the LEGUP. - * This panel includes a variety of UI components such as toolbars, menus, and split panes. - * It handles puzzle file operations, including creating and editing puzzles. + * Represents the panel used for puzzle editor in the LEGUP. This panel includes a variety of UI + * components such as toolbars, menus, and split panes. It handles puzzle file operations, including + * creating and editing puzzles. */ public class PuzzleEditorPanel extends LegupPanel implements IHistoryListener { @@ -71,7 +65,8 @@ public class PuzzleEditorPanel extends LegupPanel implements IHistoryListener { private File puzzleFile; /** - * Constructs a {@code PuzzleEditorPanel} with the specified file dialog, frame, and Legup UI instance + * Constructs a {@code PuzzleEditorPanel} with the specified file dialog, frame, and Legup UI + * instance * * @param fileDialog the file dialog used for file operations * @param frame the main application frame @@ -86,8 +81,8 @@ public PuzzleEditorPanel(FileDialog fileDialog, JFrame frame, LegupUI legupUI) { } /** - * Sets up the content of the panel, including the layout and UI components. - * Initializes and configures the {@code DynamicView} and {@code ElementFrame}, and adds them to the panel. + * Sets up the content of the panel, including the layout and UI components. Initializes and + * configures the {@code DynamicView} and {@code ElementFrame}, and adds them to the panel. */ protected void setupContent() { JSplitPane splitPanel; @@ -121,9 +116,8 @@ protected void setupContent() { } /** - * Configures the menu bar with menus and menu items for the application. - * Adds actions for opening, creating, and exiting puzzles. - * Also sets up help and about menu items. + * Configures the menu bar with menus and menu items for the application. Adds actions for + * opening, creating, and exiting puzzles. Also sets up help and about menu items. */ public void setMenuBar() { String os = LegupUI.getOS(); @@ -147,13 +141,14 @@ public void setMenuBar() { } // file>create JMenuItem createPuzzle = new JMenuItem("Create"); - createPuzzle.addActionListener((ActionEvent) -> { - hp = new HomePanel(this.frame, this.legupUI); - cpd = new CreatePuzzleDialog(this.frame, hp); - cpd.setLocationRelativeTo(null); - cpd.setVisible(true); - existingPuzzle = false; - }); + createPuzzle.addActionListener( + (ActionEvent) -> { + hp = new HomePanel(this.frame, this.legupUI); + cpd = new CreatePuzzleDialog(this.frame, hp); + cpd.setLocationRelativeTo(null); + cpd.setVisible(true); + existingPuzzle = false; + }); if (os.equals("mac")) { createPuzzle.setAccelerator( KeyStroke.getKeyStroke( @@ -162,7 +157,6 @@ public void setMenuBar() { createPuzzle.setAccelerator(KeyStroke.getKeyStroke('C', InputEvent.CTRL_DOWN_MASK)); } - JMenuItem exit = new JMenuItem("Exit"); exit.addActionListener((ActionEvent) -> exitEditor()); if (os.equals("mac")) { @@ -174,7 +168,7 @@ public void setMenuBar() { } menus[0].add(openPuzzle); menus[0].add(createPuzzle); - //menus[0].add(directSavePuzzle); + // menus[0].add(directSavePuzzle); menus[0].add(exit); // EDIT @@ -186,7 +180,7 @@ public void setMenuBar() { fitBoardToScreen = new JMenuItem("Fit Board to Screen"); // TODO: Undo operation currently does not get updated correctly in history - //menus[1].add(undo); + // menus[1].add(undo); undo.addActionListener((ActionEvent) -> GameBoardFacade.getInstance().getHistory().undo()); if (os.equals("mac")) { undo.setAccelerator( @@ -197,7 +191,7 @@ public void setMenuBar() { } // TODO: Redo operation currently does not get updated correctly in history - //menus[1].add(redo); + // menus[1].add(redo); // Created action to support two keybinds (CTRL-SHIFT-Z, CTRL-Y) Action redoAction = new AbstractAction() { @@ -272,10 +266,9 @@ public void actionPerformed(ActionEvent e) { } /** - * Exits the puzzle editor and resets the application state to its initial condition. - * This method clears the current puzzle from the {@code GameBoardFacade}, - * resets the display to the initial panel, and nullifies references to the - * tree panel and board view. + * Exits the puzzle editor and resets the application state to its initial condition. This + * method clears the current puzzle from the {@code GameBoardFacade}, resets the display to the + * initial panel, and nullifies references to the tree panel and board view. */ public void exitEditor() { // Wipes the puzzle entirely as if LEGUP just started @@ -286,8 +279,8 @@ public void exitEditor() { } /** - * Makes the panel visible by setting up the toolbar, content, and menu bar. - * This method is called to refresh the panel's user interface. + * Makes the panel visible by setting up the toolbar, content, and menu bar. This method is + * called to refresh the panel's user interface. */ @Override public void makeVisible() { @@ -298,8 +291,8 @@ public void makeVisible() { } /** - * Sets up the first toolbar with buttons for opening and creating puzzles. - * This method initializes the toolbar buttons with their icons and actions. + * Sets up the first toolbar with buttons for opening and creating puzzles. This method + * initializes the toolbar buttons with their icons and actions. */ private void setupToolBar1() { setToolBar1Buttons(new JButton[2]); @@ -341,13 +334,14 @@ private void setupToolBar1() { JButton create = new JButton("Create", CreateImageIcon); create.setFocusPainted(false); - create.addActionListener((ActionEvent) -> { - hp = new HomePanel(this.frame, this.legupUI); - cpd = new CreatePuzzleDialog(this.frame, hp); - cpd.setLocationRelativeTo(null); - cpd.setVisible(true); - existingPuzzle = false; - }); + create.addActionListener( + (ActionEvent) -> { + hp = new HomePanel(this.frame, this.legupUI); + cpd = new CreatePuzzleDialog(this.frame, hp); + cpd.setLocationRelativeTo(null); + cpd.setVisible(true); + existingPuzzle = false; + }); getToolBar1Buttons()[1] = create; toolBar1.setFloatable(false); @@ -383,19 +377,22 @@ private void setupToolBar2() { resetButton.setFocusPainted(false); resetButton.addActionListener( - a -> { - if (existingPuzzle) { - legupUI.getPuzzleEditor().loadPuzzle(fileName, puzzleFile); - } - else { - if (cpd.getGame().equals("ShortTruthTable")) { - GameBoardFacade.getInstance().loadPuzzle(cpd.getGame(), cpd.getTextArea()); - } - else { - GameBoardFacade.getInstance().loadPuzzle(cpd.getGame(), Integer.valueOf(cpd.getRows()), Integer.valueOf(cpd.getColumns())); + a -> { + if (existingPuzzle) { + legupUI.getPuzzleEditor().loadPuzzle(fileName, puzzleFile); + } else { + if (cpd.getGame().equals("ShortTruthTable")) { + GameBoardFacade.getInstance() + .loadPuzzle(cpd.getGame(), cpd.getTextArea()); + } else { + GameBoardFacade.getInstance() + .loadPuzzle( + cpd.getGame(), + Integer.valueOf(cpd.getRows()), + Integer.valueOf(cpd.getColumns())); + } } - } - }); + }); getToolBar2Buttons()[0] = resetButton; toolBar2.add(getToolBar2Buttons()[0]); @@ -500,11 +497,12 @@ public void loadPuzzleFromHome(String game, String[] statements) { } /** - * Prompts the user to select a puzzle file to open. - * Opens a file chooser dialog and returns the selected file's name and file object. - * If a puzzle is currently loaded, prompts the user to confirm if they want to open a new puzzle. + * Prompts the user to select a puzzle file to open. Opens a file chooser dialog and returns the + * selected file's name and file object. If a puzzle is currently loaded, prompts the user to + * confirm if they want to open a new puzzle. * - * @return an array containing the selected file name and file object, or null if the operation was canceled + * @return an array containing the selected file name and file object, or null if the operation + * was canceled */ public Object[] promptPuzzle() { GameBoardFacade facade = GameBoardFacade.getInstance(); @@ -548,9 +546,9 @@ public Object[] promptPuzzle() { } /** - * Loads a puzzle by prompting the user to select a puzzle file. - * If the user cancels the operation, no action is taken. If a puzzle file is selected, - * it will be loaded using the file name and file object. + * Loads a puzzle by prompting the user to select a puzzle file. If the user cancels the + * operation, no action is taken. If a puzzle file is selected, it will be loaded using the file + * name and file object. */ public void loadPuzzle() { Object[] items = promptPuzzle(); @@ -564,9 +562,8 @@ public void loadPuzzle() { } /** - * Loads a puzzle from the specified file. - * If the puzzle file is valid and exists, it loads the puzzle and updates the UI. - * If the file format is invalid, an error message is displayed. + * Loads a puzzle from the specified file. If the puzzle file is valid and exists, it loads the + * puzzle and updates the UI. If the file format is invalid, an error message is displayed. * * @param fileName the name of the puzzle file * @param puzzleFile the file object representing the puzzle file @@ -595,9 +592,8 @@ public void loadPuzzle(String fileName, File puzzleFile) { } /** - * Displays a confirmation dialog with the given instruction message. - * The method returns true if the user selected "No" or cancelled the dialog, - * and false if the user selected "Yes". + * Displays a confirmation dialog with the given instruction message. The method returns true if + * the user selected "No" or cancelled the dialog, and false if the user selected "Yes". * * @param instr the instruction message to display in the confirmation dialog * @return true if the user selected "No" or canceled; false if the user selected "Yes" @@ -607,31 +603,21 @@ public boolean noQuit(String instr) { return n != JOptionPane.YES_OPTION; } - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ @Override public void onPushChange(ICommand command) {} - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ @Override public void onUndo(boolean isBottom, boolean isTop) {} - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ @Override public void onRedo(boolean isBottom, boolean isTop) {} - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ @Override - public void onClearHistory() { - } - + public void onClearHistory() {} /** * Returns the current board view @@ -678,16 +664,14 @@ public void setToolBar2Buttons(JButton[] toolBar2Buttons) { this.toolBar2Buttons = toolBar2Buttons; } - /** - * Repaints the current board view - */ + /** Repaints the current board view */ private void repaintAll() { boardView.repaint(); } /** - * Sets the puzzle view based on the provided puzzle object. - * Updates the UI components to display the new puzzle. + * Sets the puzzle view based on the provided puzzle object. Updates the UI components to + * display the new puzzle. * * @param puzzle the puzzle object to display */ @@ -734,11 +718,11 @@ private void direct_save() { } /** - * Saves the current puzzle to a user-selected directory. - * Prompts the user to select a directory and saves the puzzle to that directory. - * Returns the path where the puzzle was saved. + * Saves the current puzzle to a user-selected directory. Prompts the user to select a directory + * and saves the puzzle to that directory. Returns the path where the puzzle was saved. * - * @return the path where the puzzle was saved, or an empty string if the save operation was canceled + * @return the path where the puzzle was saved, or an empty string if the save operation was + * canceled */ private String savePuzzle() { Puzzle puzzle = GameBoardFacade.getInstance().getPuzzleModule(); diff --git a/src/main/java/edu/rpi/legup/ui/ScrollView.java b/src/main/java/edu/rpi/legup/ui/ScrollView.java index 18aff4d1c..589573154 100644 --- a/src/main/java/edu/rpi/legup/ui/ScrollView.java +++ b/src/main/java/edu/rpi/legup/ui/ScrollView.java @@ -7,8 +7,9 @@ import javax.swing.*; /** - * ScrollView extends {@link JScrollPane} to provide a customizable view with zoom and scroll capabilities. - * It uses a {@link ZoomablePane} as the canvas and allows for zooming and scrolling with respect to the canvas content. + * ScrollView extends {@link JScrollPane} to provide a customizable view with zoom and scroll + * capabilities. It uses a {@link ZoomablePane} as the canvas and allows for zooming and scrolling + * with respect to the canvas content. */ public class ScrollView extends JScrollPane { private static final Logger LOGGER = Logger.getLogger(ScrollView.class.getName()); @@ -170,7 +171,8 @@ public void zoom(int n, Point point) { } /** - * Adjusts the zoom level to the given scale and centers the viewport on the current center point + * Adjusts the zoom level to the given scale and centers the viewport on the current center + * point * * @param newScale the new scale to set */ diff --git a/src/main/java/edu/rpi/legup/ui/ToolbarName.java b/src/main/java/edu/rpi/legup/ui/ToolbarName.java index 53936a141..622d16d8d 100644 --- a/src/main/java/edu/rpi/legup/ui/ToolbarName.java +++ b/src/main/java/edu/rpi/legup/ui/ToolbarName.java @@ -1,8 +1,8 @@ package edu.rpi.legup.ui; /** - * This enum defines constants for toolbar names used in the user interface. - * Each represents a specific toolbar action. + * This enum defines constants for toolbar names used in the user interface. Each represents a + * specific toolbar action. */ public enum ToolbarName { DIRECTIONS, diff --git a/src/main/java/edu/rpi/legup/ui/ZoomWidget.java b/src/main/java/edu/rpi/legup/ui/ZoomWidget.java index 34e828250..40f36113f 100644 --- a/src/main/java/edu/rpi/legup/ui/ZoomWidget.java +++ b/src/main/java/edu/rpi/legup/ui/ZoomWidget.java @@ -36,17 +36,13 @@ public ZoomWidget(ScrollView parent) { addMouseListener(open); } - /** - * A {@code JPopupMenu} subclass that contains a vertical slider for adjusting zoom level. - */ + /** A {@code JPopupMenu} subclass that contains a vertical slider for adjusting zoom level. */ private class PopupSlider extends JPopupMenu implements ChangeListener { private static final long serialVersionUID = 8225019381200459814L; private JSlider slider; - /** - * Constructs a {@code PopupSlider} with a vertical slider - */ + /** Constructs a {@code PopupSlider} with a vertical slider */ public PopupSlider() { slider = new JSlider(SwingConstants.VERTICAL, 0, 400, 200); slider.setMajorTickSpacing(25); diff --git a/src/main/java/edu/rpi/legup/ui/boardview/BoardView.java b/src/main/java/edu/rpi/legup/ui/boardview/BoardView.java index fa3ec70b7..18b47d98b 100644 --- a/src/main/java/edu/rpi/legup/ui/boardview/BoardView.java +++ b/src/main/java/edu/rpi/legup/ui/boardview/BoardView.java @@ -12,8 +12,8 @@ import java.util.ArrayList; /** - * An abstract class representing a view for a board in the puzzle game. - * It handles the visual representation and user interactions with the board elements. + * An abstract class representing a view for a board in the puzzle game. It handles the visual + * representation and user interactions with the board elements. */ public abstract class BoardView extends ScrollView implements IBoardListener { protected TreeElement treeElement; @@ -129,9 +129,7 @@ public void setBoard(Board board) { } } - /** - * Configures the view to handle case interactions - */ + /** Configures the view to handle case interactions */ protected void setCasePickable() { CaseBoard caseBoard = (CaseBoard) board; Board baseBoard = caseBoard.getBaseBoard(); @@ -199,7 +197,6 @@ public ElementController getElementController() { return elementController; } - @Override public void draw(Graphics2D graphics2D) { drawBoard(graphics2D); diff --git a/src/main/java/edu/rpi/legup/ui/boardview/DataSelectionView.java b/src/main/java/edu/rpi/legup/ui/boardview/DataSelectionView.java index a3d82b461..bc40e3d58 100644 --- a/src/main/java/edu/rpi/legup/ui/boardview/DataSelectionView.java +++ b/src/main/java/edu/rpi/legup/ui/boardview/DataSelectionView.java @@ -6,8 +6,8 @@ import javax.swing.border.BevelBorder; /** - * DataSelectionView is a popup menu used for selecting data elements. - * It extends JPopupMenu and is styled with a gray background and a raised bevel border. + * DataSelectionView is a popup menu used for selecting data elements. It extends JPopupMenu and is + * styled with a gray background and a raised bevel border. */ public class DataSelectionView extends JPopupMenu { diff --git a/src/main/java/edu/rpi/legup/ui/boardview/ElementSelection.java b/src/main/java/edu/rpi/legup/ui/boardview/ElementSelection.java index 9ad4132d6..eaa85082d 100644 --- a/src/main/java/edu/rpi/legup/ui/boardview/ElementSelection.java +++ b/src/main/java/edu/rpi/legup/ui/boardview/ElementSelection.java @@ -4,8 +4,8 @@ import java.util.ArrayList; /** - * ElementSelection manages the selection and hover states of ElementViews. - * It maintains a list of selected elements, the currently hovered element, and the mouse point location. + * ElementSelection manages the selection and hover states of ElementViews. It maintains a list of + * selected elements, the currently hovered element, and the mouse point location. */ public class ElementSelection { private ArrayList selection; @@ -40,8 +40,8 @@ public ElementView getFirstSelection() { } /** - * Toggles the selection state of an ElementView. - * If the ElementView is currently selected, it is deselected. Otherwise, it is selected. + * Toggles the selection state of an ElementView. If the ElementView is currently selected, it + * is deselected. Otherwise, it is selected. * * @param elementView the ElementView to toggle */ @@ -56,7 +56,8 @@ public void toggleSelection(ElementView elementView) { } /** - * Sets a new selection, clearing the previous selection and selecting the specified ElementView. + * Sets a new selection, clearing the previous selection and selecting the specified + * ElementView. * * @param elementView the ElementView to select */ @@ -66,9 +67,7 @@ public void newSelection(ElementView elementView) { elementView.setSelected(true); } - /** - * Clears the selection and deselects all ElementViews - */ + /** Clears the selection and deselects all ElementViews */ public void clearSelection() { for (ElementView elementView : selection) { elementView.setSelected(false); @@ -98,9 +97,7 @@ public void newHover(ElementView newHovered) { hover = newHovered; } - /** - * Clears the current hover state if there exists one - */ + /** Clears the current hover state if there exists one */ public void clearHover() { if (hover != null) { hover.setHover(false); diff --git a/src/main/java/edu/rpi/legup/ui/boardview/ElementView.java b/src/main/java/edu/rpi/legup/ui/boardview/ElementView.java index ad6cd3d3f..eab13cc1d 100644 --- a/src/main/java/edu/rpi/legup/ui/boardview/ElementView.java +++ b/src/main/java/edu/rpi/legup/ui/boardview/ElementView.java @@ -10,8 +10,8 @@ import javax.swing.*; /** - * ElementView represents a visual representation of a PuzzleElement. - * It handles drawing, selection, hover states, and interaction with the PuzzleElement. + * ElementView represents a visual representation of a PuzzleElement. It handles drawing, selection, + * hover states, and interaction with the PuzzleElement. */ public abstract class ElementView implements Shape { protected int index; @@ -78,7 +78,8 @@ public void draw(Graphics2D graphics2D) { } /** - * Draws the basic element representation (e.g., border, text) on the provided Graphics2D context. + * Draws the basic element representation (e.g., border, text) on the provided Graphics2D + * context. * * @param graphics2D the Graphics2D context to use for drawing */ @@ -331,7 +332,8 @@ public JMenuItem getSelectionMenuItem() { * * @param x the x-coordinate of the point to check * @param y the y-coordinate of the point to check - * @return {@code true} if the point is within the bounds of this ElementView; {@code false} otherwise + * @return {@code true} if the point is within the bounds of this ElementView; {@code false} + * otherwise */ @Override public boolean contains(double x, double y) { @@ -345,7 +347,8 @@ public boolean contains(double x, double y) { * Determines if the specified Point2D object is within the bounds of this ElementView * * @param point the Point2D object representing the point to check - * @return {@code true} if the point is within the bounds of this ElementView; {@code false} otherwise + * @return {@code true} if the point is within the bounds of this ElementView; {@code false} + * otherwise */ @Override public boolean contains(Point2D point) { @@ -353,13 +356,15 @@ public boolean contains(Point2D point) { } /** - * Determines if the specified rectangle defined by (x, y, width, height) intersects with the bounds of this ElementView. + * Determines if the specified rectangle defined by (x, y, width, height) intersects with the + * bounds of this ElementView. * * @param x The x-coordinate of the rectangle to check * @param y The y-coordinate of the rectangle to check * @param width The width of the rectangle to check * @param height The height of the rectangle to check - * @return {@code true} if the rectangle intersects with the bounds of this ElementView; {@code false} otherwise + * @return {@code true} if the rectangle intersects with the bounds of this ElementView; {@code + * false} otherwise */ @Override public boolean intersects(double x, double y, double width, double height) { @@ -368,10 +373,12 @@ public boolean intersects(double x, double y, double width, double height) { } /** - * Determines if the specified Rectangle2D object intersects with the bounds of this ElementView. + * Determines if the specified Rectangle2D object intersects with the bounds of this + * ElementView. * * @param rectangle2D the Rectangle2D object representing the rectangle to check - * @return {@code true} if the rectangle intersects with the bounds of this ElementView; {@code false} otherwise + * @return {@code true} if the rectangle intersects with the bounds of this ElementView; {@code + * false} otherwise */ @Override public boolean intersects(Rectangle2D rectangle2D) { @@ -383,13 +390,15 @@ public boolean intersects(Rectangle2D rectangle2D) { } /** - * Determines if the specified rectangle defined by (x, y, width, height) is entirely contained within the bounds of this ElementView + * Determines if the specified rectangle defined by (x, y, width, height) is entirely contained + * within the bounds of this ElementView * * @param x the x-coordinate of the rectangle to check * @param y the y-coordinate of the rectangle to check * @param width the width of the rectangle to check * @param height the height of the rectangle to check - * @return {@code true} if the rectangle is entirely contained within the bounds of this ElementView; {@code false} otherwise + * @return {@code true} if the rectangle is entirely contained within the bounds of this + * ElementView; {@code false} otherwise */ @Override public boolean contains(double x, double y, double width, double height) { @@ -398,10 +407,12 @@ public boolean contains(double x, double y, double width, double height) { } /** - * Determines if the specified Rectangle2D object is entirely contained within the bounds of this ElementView. + * Determines if the specified Rectangle2D object is entirely contained within the bounds of + * this ElementView. * * @param rectangle2D the Rectangle2D object representing the rectangle to check - * @return {@code true} if the rectangle is entirely contained within the bounds of this ElementView; {@code false} otherwise + * @return {@code true} if the rectangle is entirely contained within the bounds of this + * ElementView; {@code false} otherwise */ @Override public boolean contains(Rectangle2D rectangle2D) { @@ -412,10 +423,9 @@ public boolean contains(Rectangle2D rectangle2D) { rectangle2D.getHeight()); } - /** - * Returns an iterator over the path geometry of this ElementView. The iterator provides access to the path's - * segments and their coordinates, which can be used for rendering or hit testing. + * Returns an iterator over the path geometry of this ElementView. The iterator provides access + * to the path's segments and their coordinates, which can be used for rendering or hit testing. * * @param at the AffineTransform to apply to the path geometry * @return a PathIterator that iterates over the path geometry of this ElementView @@ -426,8 +436,9 @@ public PathIterator getPathIterator(AffineTransform at) { } /** - * Returns an iterator over the path geometry of this ElementView with the specified flatness. The iterator provides - * access to the path's segments and their coordinates, which can be used for rendering or hit testing. + * Returns an iterator over the path geometry of this ElementView with the specified flatness. + * The iterator provides access to the path's segments and their coordinates, which can be used + * for rendering or hit testing. * * @param at the AffineTransform to apply to the path geometry * @param flatness the maximum distance that the line segments can deviate from the true path diff --git a/src/main/java/edu/rpi/legup/ui/boardview/GridBoardView.java b/src/main/java/edu/rpi/legup/ui/boardview/GridBoardView.java index 1baa34b3a..e2b8bbc12 100644 --- a/src/main/java/edu/rpi/legup/ui/boardview/GridBoardView.java +++ b/src/main/java/edu/rpi/legup/ui/boardview/GridBoardView.java @@ -6,9 +6,8 @@ import java.awt.Dimension; /** - * A view class for a grid-based board that displays elements in a grid layout. - * This class extends BoardView and is responsible for managing and rendering - * grid-based elements. + * A view class for a grid-based board that displays elements in a grid layout. This class extends + * BoardView and is responsible for managing and rendering grid-based elements. */ public class GridBoardView extends BoardView { protected Dimension gridSize; @@ -57,8 +56,8 @@ public GridElementView getElement(int index) { } /** - * Retrieves the GridElementView at the specified grid coordinates (xIndex, yIndex). - * Returns null if the coordinates are out of bounds. + * Retrieves the GridElementView at the specified grid coordinates (xIndex, yIndex). Returns + * null if the coordinates are out of bounds. * * @param xIndex the x-coordinate (column) of the element view to retrieve * @param yIndex the y-coordinate (row) of the element view to retrieve @@ -72,8 +71,8 @@ public GridElementView getElement(int xIndex, int yIndex) { } /** - * Initializes the initial dimension of the viewport for the GridBoardView. - * Sets the size of the board view and adjusts the zoom to fit. + * Initializes the initial dimension of the viewport for the GridBoardView. Sets the size of the + * board view and adjusts the zoom to fit. */ @Override public void initSize() { @@ -94,8 +93,8 @@ protected Dimension getProperSize() { } /** - * Retrieves the selection popup menu for data selection. - * Currently returns null as there is no implementation. + * Retrieves the selection popup menu for data selection. Currently returns null as there is no + * implementation. * * @return null */ diff --git a/src/main/java/edu/rpi/legup/ui/boardview/GridElementView.java b/src/main/java/edu/rpi/legup/ui/boardview/GridElementView.java index 31e8fcd6c..587ba9efb 100644 --- a/src/main/java/edu/rpi/legup/ui/boardview/GridElementView.java +++ b/src/main/java/edu/rpi/legup/ui/boardview/GridElementView.java @@ -3,9 +3,8 @@ import edu.rpi.legup.model.gameboard.GridCell; /** - * A view class for a grid cell element in the board. - * This class extends ElementView and represents a specific type of element view - * associated with a GridCell. + * A view class for a grid cell element in the board. This class extends ElementView and represents + * a specific type of element view associated with a GridCell. */ public class GridElementView extends ElementView { public GridElementView(GridCell cell) { diff --git a/src/main/java/edu/rpi/legup/ui/boardview/SelectionItemView.java b/src/main/java/edu/rpi/legup/ui/boardview/SelectionItemView.java index 15deb86d1..6a1429a61 100644 --- a/src/main/java/edu/rpi/legup/ui/boardview/SelectionItemView.java +++ b/src/main/java/edu/rpi/legup/ui/boardview/SelectionItemView.java @@ -4,17 +4,16 @@ import javax.swing.*; /** - * A menu item view class that represents a selectable item in a menu, associated with a PuzzleElement. - * This class extends JMenuItem and provides additional functionality to - * handle PuzzleElement data. + * A menu item view class that represents a selectable item in a menu, associated with a + * PuzzleElement. This class extends JMenuItem and provides additional functionality to handle + * PuzzleElement data. */ public class SelectionItemView extends JMenuItem { private PuzzleElement data; /** - * Constructs a SelectionItemView with the specified PuzzleElement and icon. - * Initializes the menu item with the given icon and associates it with the - * provided PuzzleElement. + * Constructs a SelectionItemView with the specified PuzzleElement and icon. Initializes the + * menu item with the given icon and associates it with the provided PuzzleElement. * * @param data the PuzzleElement associated with this menu item * @param icon the icon to be displayed on the menu item @@ -25,9 +24,8 @@ public SelectionItemView(PuzzleElement data, Icon icon) { } /** - * Constructs a SelectionItemView with the specified PuzzleElement and display text. - * Initializes the menu item with the given display text and associates it with the - * provided PuzzleElement. + * Constructs a SelectionItemView with the specified PuzzleElement and display text. Initializes + * the menu item with the given display text and associates it with the provided PuzzleElement. * * @param data the PuzzleElement associated with this menu item * @param display the text to be displayed on the menu item @@ -39,8 +37,8 @@ public SelectionItemView(PuzzleElement data, String display) { /** * Constructs a SelectionItemView with the specified PuzzleElement and display integer. - * Initializes the menu item with the integer converted to a string and associates it with - * the provided PuzzleElement. + * Initializes the menu item with the integer converted to a string and associates it with the + * provided PuzzleElement. * * @param data the PuzzleElement associated with this menu item * @param display the integer to be displayed on the menu item @@ -51,8 +49,8 @@ public SelectionItemView(PuzzleElement data, int display) { } /** - * Constructs a SelectionItemView with the specified PuzzleElement. - * Initializes the menu item with the data's integer representation as display text. + * Constructs a SelectionItemView with the specified PuzzleElement. Initializes the menu item + * with the data's integer representation as display text. * * @param data the PuzzleElement associated with this menu item */ diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/CaseRulePanel.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/CaseRulePanel.java index 849c5c145..4d7bb378d 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/CaseRulePanel.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/CaseRulePanel.java @@ -3,10 +3,10 @@ import javax.swing.ImageIcon; /** - * The {@code CaseRulePanel} class is a specialized panel that represents case rules - * within a {@link RuleFrame}. It extends the {@link RulePanel} and provides - * specific functionality and UI components related to case rules. - * This class initializes with an icon and name that are specific to case rules. + * The {@code CaseRulePanel} class is a specialized panel that represents case rules within a {@link + * RuleFrame}. It extends the {@link RulePanel} and provides specific functionality and UI + * components related to case rules. This class initializes with an icon and name that are specific + * to case rules. */ public class CaseRulePanel extends RulePanel { /** diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/ContradictionRulePanel.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/ContradictionRulePanel.java index 5bed7e17d..92e747305 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/ContradictionRulePanel.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/ContradictionRulePanel.java @@ -3,13 +3,12 @@ import javax.swing.*; /** - * The {@code ContradictionRulePanel} class is a specialized panel that represents contradiction rules - * within a {@link RuleFrame}. It extends the {@link RulePanel} and provides - * specific functionality and UI components related to contradiction rules. - * This class initializes with an icon and name that are specific to contradiction rules. + * The {@code ContradictionRulePanel} class is a specialized panel that represents contradiction + * rules within a {@link RuleFrame}. It extends the {@link RulePanel} and provides specific + * functionality and UI components related to contradiction rules. This class initializes with an + * icon and name that are specific to contradiction rules. */ - - public class ContradictionRulePanel extends RulePanel { +public class ContradictionRulePanel extends RulePanel { /** * ContradictionRulePanel Constructor creates a ContradictionRulePanel * diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/DirectRulePanel.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/DirectRulePanel.java index c1562eb70..17fcac5bb 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/DirectRulePanel.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/DirectRulePanel.java @@ -5,12 +5,12 @@ import org.apache.logging.log4j.Logger; /** - * The {@code DirectRulePanel} class is a specialized panel that represents direct rules - * within a {@link RuleFrame}. It extends the {@link RulePanel} and provides - * specific functionality and UI components related to direct rules. - * This class initializes with an icon and name that are specific to direct rules. + * The {@code DirectRulePanel} class is a specialized panel that represents direct rules within a + * {@link RuleFrame}. It extends the {@link RulePanel} and provides specific functionality and UI + * components related to direct rules. This class initializes with an icon and name that are + * specific to direct rules. */ - public class DirectRulePanel extends RulePanel { +public class DirectRulePanel extends RulePanel { private static final Logger LOGGER = LogManager.getLogger(DirectRulePanel.class.getName()); /** diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RuleButton.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RuleButton.java index 7222603bc..929f211d0 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RuleButton.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RuleButton.java @@ -4,9 +4,9 @@ import javax.swing.*; /** - * The {@code RuleButton} class is a custom button that represents a rule in the user interface. - * It extends {@link JButton} and is designed to display a rule's name and icon. - * The button is initialized with a {@link Rule} object, which provides the name and icon for the button. + * The {@code RuleButton} class is a custom button that represents a rule in the user interface. It + * extends {@link JButton} and is designed to display a rule's name and icon. The button is + * initialized with a {@link Rule} object, which provides the name and icon for the button. */ public class RuleButton extends JButton { private Rule rule; diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RuleFrame.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RuleFrame.java index 3131f474d..b14091351 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RuleFrame.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RuleFrame.java @@ -12,10 +12,10 @@ /** * The {@code RuleFrame} class is a panel that contains and manages multiple rule-related panels - * within a tabbed interface. It extends {@link JPanel} and organizes the display of various rule types - * such as direct rules, contradiction rules, and case rules. - * The frame uses a {@link JTabbedPane} to allow users to switch between different rule panels. - * It also includes a search bar panel and a status label for displaying additional information. + * within a tabbed interface. It extends {@link JPanel} and organizes the display of various rule + * types such as direct rules, contradiction rules, and case rules. The frame uses a {@link + * JTabbedPane} to allow users to switch between different rule panels. It also includes a search + * bar panel and a status label for displaying additional information. */ public class RuleFrame extends JPanel { private static final String checkBox = " \u2714 "; @@ -36,8 +36,8 @@ public class RuleFrame extends JPanel { private RuleController controller; /** - * Constructs a new {@code RuleFrame} instance. - * Initializes the frame with tabs for the different rule panels, a search bar panel, and a status label. + * Constructs a new {@code RuleFrame} instance. Initializes the frame with tabs for the + * different rule panels, a search bar panel, and a status label. * * @param controller the {@link RuleController} instance that manages the rules for this frame */ diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RulePanel.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RulePanel.java index 4c9ebf882..85ddf82b5 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RulePanel.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RulePanel.java @@ -10,8 +10,8 @@ import javax.swing.*; /** - * Abstract base class for panels displaying rules. Each subclass will represent a specific type - * of rule panel (e.g., DirectRulePanel, CaseRulePanel). + * Abstract base class for panels displaying rules. Each subclass will represent a specific type of + * rule panel (e.g., DirectRulePanel, CaseRulePanel). */ public abstract class RulePanel extends JPanel { protected ImageIcon icon; @@ -59,7 +59,8 @@ public void setRules(List rules) { Rule rule = rules.get(i); ruleButtons[i] = new RuleButton(rule); - ruleButtons[i].setPreferredSize(new Dimension(150, 150)); // adjust the size of each RuleButton + ruleButtons[i].setPreferredSize( + new Dimension(150, 150)); // adjust the size of each RuleButton if (rule.getRuleName().length() > 18) { ruleButtons[i].setFont(new Font("Segoe UI", Font.PLAIN, 11)); @@ -73,16 +74,15 @@ public void setRules(List rules) { ruleButtons[i].setVerticalTextPosition(JButton.BOTTOM); ruleFrame.getButtonGroup().add(ruleButtons[i]); - ruleButtons[i].setToolTipText(rule.getRuleName() + ": " + rule.getDescription()); // showing description + ruleButtons[i].setToolTipText( + rule.getRuleName() + ": " + rule.getDescription()); // showing description ruleButtons[i].addActionListener(ruleFrame.getController()); add(ruleButtons[i]); } revalidate(); } - /** - * Updates the rules displayed by reloading images and setting the rules again. - */ + /** Updates the rules displayed by reloading images and setting the rules again. */ public void updateRules() { for (Rule rule : rules) { rule.loadImage(); diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/SearchBarPanel.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/SearchBarPanel.java index 842859ce2..60e24b986 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/SearchBarPanel.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/SearchBarPanel.java @@ -2,10 +2,10 @@ import javax.swing.*; - /** - * The {@code SearchBarPanel} class creates a panel that allows users to search for rules within the rule frame. - * This panel provides a search bar for entering rule names and finding corresponding rules. + * The {@code SearchBarPanel} class creates a panel that allows users to search for rules within the + * rule frame. This panel provides a search bar for entering rule names and finding corresponding + * rules. */ public class SearchBarPanel extends RulePanel { /** diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeElementView.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeElementView.java index 228e69950..e5e523e11 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeElementView.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeElementView.java @@ -5,10 +5,9 @@ import java.awt.*; /** - * Abstract base class for views of tree elements in the tree structure. - * This class implements the Shape interface to support custom drawing and interaction - * with tree elements. - * It holds properties for rendering, interaction, and layout of the tree elements. + * Abstract base class for views of tree elements in the tree structure. This class implements the + * Shape interface to support custom drawing and interaction with tree elements. It holds properties + * for rendering, interaction, and layout of the tree elements. */ public abstract class TreeElementView implements Shape { protected TreeElement treeElement; diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeNodeView.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeNodeView.java index 0e2a31bbf..c9aedaef3 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeNodeView.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeNodeView.java @@ -8,10 +8,10 @@ import java.util.ArrayList; /** - * Represents a view of a tree node in the tree structure. - * This class extends {@link TreeElementView} and provides specific rendering and interaction - * functionality for tree nodes. It includes visual properties and methods to manage the - * node's appearance, location, and its relationships with other nodes. + * Represents a view of a tree node in the tree structure. This class extends {@link + * TreeElementView} and provides specific rendering and interaction functionality for tree nodes. It + * includes visual properties and methods to manage the node's appearance, location, and its + * relationships with other nodes. */ public class TreeNodeView extends TreeElementView { static final int RADIUS = 25; @@ -291,7 +291,8 @@ public Rectangle2D getBounds2D() { * * @param x the x-coordinate of the point to check * @param y the y-coordinate of the point to check - * @return {@code true} if the point is within the bounds of this TreeNodeView; {@code false} otherwise + * @return {@code true} if the point is within the bounds of this TreeNodeView; {@code false} + * otherwise */ @Override public boolean contains(double x, double y) { @@ -302,7 +303,8 @@ public boolean contains(double x, double y) { * Determines if the specified Point2D object is within the bounds of this TreeNodeView * * @param p the Point2D object representing the point to check - * @return {@code true} if the point is within the bounds of this TreeNodeView; {@code false} otherwise + * @return {@code true} if the point is within the bounds of this TreeNodeView; {@code false} + * otherwise */ @Override public boolean contains(Point2D p) { @@ -310,13 +312,15 @@ public boolean contains(Point2D p) { } /** - * Determines if the specified rectangle defined by (x, y, width, height) intersects with the bounds of this TreeNodeView. + * Determines if the specified rectangle defined by (x, y, width, height) intersects with the + * bounds of this TreeNodeView. * * @param x The x-coordinate of the rectangle to check * @param y The y-coordinate of the rectangle to check * @param w The width of the rectangle to check * @param h The height of the rectangle to check - * @return {@code true} if the rectangle intersects with the bounds of this TreeNodeView; {@code false} otherwise + * @return {@code true} if the rectangle intersects with the bounds of this TreeNodeView; {@code + * false} otherwise */ @Override public boolean intersects(double x, double y, double w, double h) { @@ -324,10 +328,12 @@ public boolean intersects(double x, double y, double w, double h) { } /** - * Determines if the specified Rectangle2D object intersects with the bounds of this TreeNodeView. + * Determines if the specified Rectangle2D object intersects with the bounds of this + * TreeNodeView. * * @param r the Rectangle2D object representing the rectangle to check - * @return {@code true} if the rectangle intersects with the bounds of this TreeNodeView; {@code false} otherwise + * @return {@code true} if the rectangle intersects with the bounds of this TreeNodeView; {@code + * false} otherwise */ @Override public boolean intersects(Rectangle2D r) { @@ -335,13 +341,15 @@ public boolean intersects(Rectangle2D r) { } /** - * Determines if the specified rectangle defined by (x, y, width, height) is entirely contained within the bounds of this TreeNodeView + * Determines if the specified rectangle defined by (x, y, width, height) is entirely contained + * within the bounds of this TreeNodeView * * @param x the x-coordinate of the rectangle to check * @param y the y-coordinate of the rectangle to check * @param w the width of the rectangle to check * @param h the height of the rectangle to check - * @return {@code true} if the rectangle is entirely contained within the bounds of this TreeNodeView; {@code false} otherwise + * @return {@code true} if the rectangle is entirely contained within the bounds of this + * TreeNodeView; {@code false} otherwise */ @Override public boolean contains(double x, double y, double w, double h) { @@ -349,10 +357,12 @@ public boolean contains(double x, double y, double w, double h) { } /** - * Determines if the specified Rectangle2D object is entirely contained within the bounds of this TreeNodeView. + * Determines if the specified Rectangle2D object is entirely contained within the bounds of + * this TreeNodeView. * * @param r the Rectangle2D object representing the rectangle to check - * @return {@code true} if the rectangle is entirely contained within the bounds of this TreeNodeView; {@code false} otherwise + * @return {@code true} if the rectangle is entirely contained within the bounds of this + * TreeNodeView; {@code false} otherwise */ @Override public boolean contains(Rectangle2D r) { @@ -360,8 +370,8 @@ public boolean contains(Rectangle2D r) { } /** - * Returns an iterator over the path geometry of this TreeNodeView. The iterator provides access to the path's - * segments and their coordinates, which can be used for rendering or hit testing. + * Returns an iterator over the path geometry of this TreeNodeView. The iterator provides access + * to the path's segments and their coordinates, which can be used for rendering or hit testing. * * @param at the AffineTransform to apply to the path geometry * @return a PathIterator that iterates over the path geometry of this TreeNodeView @@ -372,8 +382,9 @@ public PathIterator getPathIterator(AffineTransform at) { } /** - * Returns an iterator over the path geometry of this TreeNodeView with the specified flatness. The iterator provides - * access to the path's segments and their coordinates, which can be used for rendering or hit testing. + * Returns an iterator over the path geometry of this TreeNodeView with the specified flatness. + * The iterator provides access to the path's segments and their coordinates, which can be used + * for rendering or hit testing. * * @param at the AffineTransform to apply to the path geometry * @param flatness the maximum distance that the line segments can deviate from the true path diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreePanel.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreePanel.java index 4bef664bd..936b0de95 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreePanel.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreePanel.java @@ -17,11 +17,10 @@ import javax.swing.JPanel; import javax.swing.border.TitledBorder; - /** - * {@code TreePanel} is a JPanel that manages and displays a tree view with associated toolbar and status information. - * It provides methods to interact with the tree view, such as adding, deleting, and merging tree elements, - * and updating the status based on actions performed. + * {@code TreePanel} is a JPanel that manages and displays a tree view with associated toolbar and + * status information. It provides methods to interact with the tree view, such as adding, deleting, + * and merging tree elements, and updating the status based on actions performed. */ public class TreePanel extends JPanel { public boolean modifiedSinceSave = false; @@ -35,9 +34,7 @@ public class TreePanel extends JPanel { private JLabel status; - /** - * Constructs a {@code TreePanel} and initializes the UI components. - */ + /** Constructs a {@code TreePanel} and initializes the UI components. */ public TreePanel(/*LegupUI legupUI*/ ) { // this.legupUI = legupUI; @@ -91,9 +88,8 @@ public void boardDataChanged(Board board) { } /** - * Updates the status display based on the status timer. - * If the timer is greater than 0, the status will not be updated. - * Otherwise, it clears the status text. + * Updates the status display based on the status timer. If the timer is greater than 0, the + * status will not be updated. Otherwise, it clears the status text. */ public void updateStatus() { updateStatusTimer = ((updateStatusTimer - 1) > 0) ? (updateStatusTimer - 1) : 0; @@ -135,8 +131,8 @@ public TreeView getTreeView() { } /** - * Adds a new tree element by executing an {@link AddTreeElementCommand}. - * If the command cannot be executed, it updates the status display with an error and error message. + * Adds a new tree element by executing an {@link AddTreeElementCommand}. If the command cannot + * be executed, it updates the status display with an error and error message. */ public void add() { TreeViewSelection selection = treeView.getSelection(); @@ -151,8 +147,8 @@ public void add() { } /** - * Deletes the selected tree element by executing a {@link DeleteTreeElementCommand}. - * If the command cannot be executed, it updates the status display with an error and an error message. + * Deletes the selected tree element by executing a {@link DeleteTreeElementCommand}. If the + * command cannot be executed, it updates the status display with an error and an error message. */ public void delete() { TreeViewSelection selection = treeView.getSelection(); @@ -167,8 +163,8 @@ public void delete() { } /** - * Merges selected tree elements by executing a {@link MergeCommand}. - * If the command cannot be executed, it updates the status display with an error and an error message. + * Merges selected tree elements by executing a {@link MergeCommand}. If the command cannot be + * executed, it updates the status display with an error and an error message. */ public void merge() { TreeViewSelection selection = treeView.getSelection(); @@ -183,8 +179,8 @@ public void merge() { } /** - * Toggles the collapsed state of the selected tree elements. - * If an element is collapsed, it will be expanded, and vice versa. + * Toggles the collapsed state of the selected tree elements. If an element is collapsed, it + * will be expanded, and vice versa. */ public void collapse() { TreeViewSelection selection = treeView.getSelection(); diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeToolBarButton.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeToolBarButton.java index 214c735df..232498723 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeToolBarButton.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeToolBarButton.java @@ -3,9 +3,7 @@ import java.awt.Dimension; import javax.swing.*; -/** - * {@code TreeToolBarButton} is a JButton that represents a button in the tree toolbar. - */ +/** {@code TreeToolBarButton} is a JButton that represents a button in the tree toolbar. */ public class TreeToolBarButton extends JButton { private TreeToolBarName name; diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeToolbarPanel.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeToolbarPanel.java index 500ed29c5..06af84c57 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeToolbarPanel.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeToolbarPanel.java @@ -3,10 +3,9 @@ import java.awt.*; import javax.swing.*; - /** - * {@code TreeToolbarPanel} is a JPanel that provides a toolbar for managing tree elements in the tree view. - * It includes buttons for adding, deleting, merging, and collapsing nodes. + * {@code TreeToolbarPanel} is a JPanel that provides a toolbar for managing tree elements in the + * tree view. It includes buttons for adding, deleting, merging, and collapsing nodes. */ public class TreeToolbarPanel extends JPanel { private TreePanel treePanel; diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeTransitionView.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeTransitionView.java index 25c67bb5a..5a3aa7d5c 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeTransitionView.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeTransitionView.java @@ -11,8 +11,8 @@ import java.util.List; /** - * {@code TreeTransitionView} is a visual representation of a tree transition in the tree view. - * It extends TreeElementView and displays a transition arrow between tree nodes and handles various + * {@code TreeTransitionView} is a visual representation of a tree transition in the tree view. It + * extends TreeElementView and displays a transition arrow between tree nodes and handles various * visual states such as selection, hover, and correctness. */ public class TreeTransitionView extends TreeElementView { @@ -342,7 +342,8 @@ public Rectangle2D getBounds2D() { * * @param x the x-coordinate of the point to check * @param y the y-coordinate of the point to check - * @return {@code true} if the point is within the bounds of this TreeTransitionView; {@code false} otherwise + * @return {@code true} if the point is within the bounds of this TreeTransitionView; {@code + * false} otherwise */ @Override public boolean contains(double x, double y) { @@ -353,7 +354,8 @@ public boolean contains(double x, double y) { * Determines if the specified Point2D object is within the bounds of this TreeTransitionView * * @param p the Point2D object representing the point to check - * @return {@code true} if the point is within the bounds of this TreeTransitionView; {@code false} otherwise + * @return {@code true} if the point is within the bounds of this TreeTransitionView; {@code + * false} otherwise */ @Override public boolean contains(Point2D p) { @@ -361,13 +363,15 @@ public boolean contains(Point2D p) { } /** - * Determines if the specified rectangle defined by (x, y, width, height) intersects with the bounds of this TreeTransitionView. + * Determines if the specified rectangle defined by (x, y, width, height) intersects with the + * bounds of this TreeTransitionView. * * @param x The x-coordinate of the rectangle to check * @param y The y-coordinate of the rectangle to check * @param w The width of the rectangle to check * @param h The height of the rectangle to check - * @return {@code true} if the rectangle intersects with the bounds of this TreeTransitionView; {@code false} otherwise + * @return {@code true} if the rectangle intersects with the bounds of this TreeTransitionView; + * {@code false} otherwise */ @Override public boolean intersects(double x, double y, double w, double h) { @@ -375,10 +379,12 @@ public boolean intersects(double x, double y, double w, double h) { } /** - * Determines if the specified Rectangle2D object intersects with the bounds of this TreeTransitionView. + * Determines if the specified Rectangle2D object intersects with the bounds of this + * TreeTransitionView. * * @param r the Rectangle2D object representing the rectangle to check - * @return {@code true} if the rectangle intersects with the bounds of this TreeTransitionView; {@code false} otherwise + * @return {@code true} if the rectangle intersects with the bounds of this TreeTransitionView; + * {@code false} otherwise */ @Override public boolean intersects(Rectangle2D r) { @@ -386,13 +392,15 @@ public boolean intersects(Rectangle2D r) { } /** - * Determines if the specified rectangle defined by (x, y, width, height) is entirely contained within the bounds of this TreeTransitionView + * Determines if the specified rectangle defined by (x, y, width, height) is entirely contained + * within the bounds of this TreeTransitionView * * @param x the x-coordinate of the rectangle to check * @param y the y-coordinate of the rectangle to check * @param w the width of the rectangle to check * @param h the height of the rectangle to check - * @return {@code true} if the rectangle is entirely contained within the bounds of this TreeTransitionView; {@code false} otherwise + * @return {@code true} if the rectangle is entirely contained within the bounds of this + * TreeTransitionView; {@code false} otherwise */ @Override public boolean contains(double x, double y, double w, double h) { @@ -400,10 +408,12 @@ public boolean contains(double x, double y, double w, double h) { } /** - * Determines if the specified Rectangle2D object is entirely contained within the bounds of this TreeTransitionView. + * Determines if the specified Rectangle2D object is entirely contained within the bounds of + * this TreeTransitionView. * * @param r the Rectangle2D object representing the rectangle to check - * @return {@code true} if the rectangle is entirely contained within the bounds of this TreeTransitionView; {@code false} otherwise + * @return {@code true} if the rectangle is entirely contained within the bounds of this + * TreeTransitionView; {@code false} otherwise */ @Override public boolean contains(Rectangle2D r) { @@ -411,8 +421,9 @@ public boolean contains(Rectangle2D r) { } /** - * Returns an iterator over the path geometry of this TreeTransitionView. The iterator provides access to the path's - * segments and their coordinates, which can be used for rendering or hit testing. + * Returns an iterator over the path geometry of this TreeTransitionView. The iterator provides + * access to the path's segments and their coordinates, which can be used for rendering or hit + * testing. * * @param at the AffineTransform to apply to the path geometry * @return a PathIterator that iterates over the path geometry of this TreeTransitionView @@ -423,8 +434,9 @@ public PathIterator getPathIterator(AffineTransform at) { } /** - * Returns an iterator over the path geometry of this TreeTransitionView with the specified flatness. The iterator provides - * access to the path's segments and their coordinates, which can be used for rendering or hit testing. + * Returns an iterator over the path geometry of this TreeTransitionView with the specified + * flatness. The iterator provides access to the path's segments and their coordinates, which + * can be used for rendering or hit testing. * * @param at the AffineTransform to apply to the path geometry * @param flatness the maximum distance that the line segments can deviate from the true path 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 490cf1480..65f49ff0a 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 @@ -28,9 +28,9 @@ /** * The {@code TreeView} class provides a graphical representation of a {@code Tree} structure, - * allowing interaction and visualization of tree elements, transitions, and selections. - * It extends {@code ScrollView} and implements {@code ITreeListener} to respond to updates - * in the tree structure. + * allowing interaction and visualization of tree elements, transitions, and selections. It extends + * {@code ScrollView} and implements {@code ITreeListener} to respond to updates in the tree + * structure. */ public class TreeView extends ScrollView implements ITreeListener { private static final Logger LOGGER = LogManager.getLogger(TreeView.class.getName()); @@ -169,9 +169,7 @@ public void setTree(Tree tree) { this.tree = tree; } - /** - * Updates the size of the tree view based on the bounds of its tree - */ + /** Updates the size of the tree view based on the bounds of its tree */ public void updateTreeSize() { if (GameBoardFacade.getInstance().getTree() == null) { return; @@ -179,9 +177,7 @@ public void updateTreeSize() { setSize(bounds.getSize()); } - /** - * Resets the view if the tree bounds have been modified - */ + /** Resets the view if the tree bounds have been modified */ public void reset() { if (bounds.x != 0 || bounds.y != 0) { updateTreeSize(); @@ -189,8 +185,8 @@ public void reset() { } /** - * Adjusts the zoom level to fit the entire tree within the viewport when - * the Resize Proof button is selected + * Adjusts the zoom level to fit the entire tree within the viewport when the Resize Proof + * button is selected */ public void zoomFit() { final int MIN_HEIGHT = 200; @@ -272,7 +268,8 @@ public void draw(Graphics2D graphics2D) { } /** - * Resets the zoom level to its default state and positions the viewport from the top-left corner + * Resets the zoom level to its default state and positions the viewport from the top-left + * corner */ public void zoomReset() { zoomTo(1.0); @@ -333,9 +330,7 @@ public void drawMouseOver(Graphics2D g) { } } - /** - * Resets the view by clearing the current tree, root node view, and selection - */ + /** Resets the view by clearing the current tree, root node view, and selection */ public void resetView() { this.tree = null; this.rootNodeView = null; @@ -538,7 +533,8 @@ public void removeTreeTransition(TreeTransition trans) { // Update transition modifiability if removing a case rule List parents = trans.getParents(); for (TreeNode parent : parents) { - // if transition is a case rule, unlock ancestor elements up until latest case rule or root node + // if transition is a case rule, unlock ancestor elements up until latest case rule or + // root node boolean nextAncestorIsCaseRule = false; Rule rule = trans.getRule(); if (rule instanceof CaseRule) { @@ -551,7 +547,8 @@ public void removeTreeTransition(TreeTransition trans) { break; } for (PuzzleElement element : parent.getBoard().getPuzzleElements()) { - PuzzleElement curElement = ancestors.get(i).getParent().getBoard().getPuzzleElement(element); + PuzzleElement curElement = + ancestors.get(i).getParent().getBoard().getPuzzleElement(element); if (!curElement.isModifiableCaseRule()) { curElement.setModifiableCaseRule(true); } @@ -593,7 +590,8 @@ private void addTreeNode(TreeNode node) { continue; } for (PuzzleElement element : - caseRule.dependentElements(node.getBoard(), node.getChildren().get(0).getSelection())) { + caseRule.dependentElements( + node.getBoard(), node.getChildren().get(0).getSelection())) { // increment and lock PuzzleElement oldElement = ancestor.getParent().getBoard().getPuzzleElement(element); @@ -634,7 +632,8 @@ private void addTreeTransition(TreeTransition trans) { } for (PuzzleElement element : parent.getBoard().getPuzzleElements()) { - PuzzleElement curElement = ancestor.getParent().getBoard().getPuzzleElement(element); + PuzzleElement curElement = + ancestor.getParent().getBoard().getPuzzleElement(element); curElement.setModifiableCaseRule(false); } } @@ -715,9 +714,9 @@ public void createViews(TreeNodeView nodeView) { } /** - * Calculates the layout locations (x and y coordinates) of the nodes in the tree. - * This method recursively traverses the tree and updates the positions of - * nodes and transitions based on their depth and parent relationships. + * Calculates the layout locations (x and y coordinates) of the nodes in the tree. This method + * recursively traverses the tree and updates the positions of nodes and transitions based on + * their depth and parent relationships. * * @param nodeView the node view to calculate the positions for * @param depth the depth of the node in the tree, used to calculate its x-coordinate @@ -828,9 +827,9 @@ public void calculateViewLocations(TreeNodeView nodeView, int depth) { } /** - * Calculates the span (height) required for the given view, including its children. - * This method recursively determines the span for nodes and transitions based on their - * children and the merging branches they belong to. + * Calculates the span (height) required for the given view, including its children. This method + * recursively determines the span for nodes and transitions based on their children and the + * merging branches they belong to. * * @param view the view whose span is to be calculated */ @@ -902,12 +901,12 @@ public void calcSpan(TreeElementView view) { } /** - * Calculates the span of a subtree rooted at the specified view, stopping at the given - * stop view. The stop view is not included in the span calculation. + * Calculates the span of a subtree rooted at the specified view, stopping at the given stop + * view. The stop view is not included in the span calculation. * * @param view the root view of the subtree to calculate the span for - * @param stop the view at which to stop the span calculation. The stop view itself is - * not included in the span calculation + * @param stop the view at which to stop the span calculation. The stop view itself is not + * included in the span calculation */ private void subCalcSpan(TreeElementView view, TreeElementView stop) { // safe-guard for infinite loop @@ -982,14 +981,14 @@ private void subCalcSpan(TreeElementView view, TreeElementView stop) { } /** - * Reorders the branches of a given node such that branches that merge are grouped together sequentially. - * Transitions are kept in their relative order based on their original positions in the list of child transitions - * of the specified node. This ensures that the visual representation of the branches and transitions maintains - * a logical and readable structure. + * Reorders the branches of a given node such that branches that merge are grouped together + * sequentially. Transitions are kept in their relative order based on their original positions + * in the list of child transitions of the specified node. This ensures that the visual + * representation of the branches and transitions maintains a logical and readable structure. * * @param node the root node whose branches are to be reordered - * @param branches a DisjointSets structure representing the merging relationships of the child branches of the - * specified node. This determines which branches should be grouped together + * @param branches a DisjointSets structure representing the merging relationships of the child + * branches of the specified node. This determines which branches should be grouped together */ private void reorderBranches(TreeNode node, DisjointSets branches) { List children = node.getChildren(); diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeViewSelection.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeViewSelection.java index c7893b168..c509b6cb9 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeViewSelection.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeViewSelection.java @@ -4,10 +4,10 @@ import java.util.ArrayList; import java.util.List; - /** - * {@code TreeViewSelection} manages the selection and hover state of tree element views in a tree view. - * It maintains a list of selected views, tracks the currently hovered view, and manages the mouse position. + * {@code TreeViewSelection} manages the selection and hover state of tree element views in a tree + * view. It maintains a list of selected views, tracks the currently hovered view, and manages the + * mouse position. */ public class TreeViewSelection { private ArrayList selectedViews; diff --git a/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/ElementFrame.java b/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/ElementFrame.java index 97c76919e..1619ecbaa 100644 --- a/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/ElementFrame.java +++ b/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/ElementFrame.java @@ -2,7 +2,6 @@ import edu.rpi.legup.controller.EditorElementController; import edu.rpi.legup.model.Puzzle; -import edu.rpi.legup.ui.lookandfeel.components.MaterialTabbedPaneUI; import java.awt.*; import javax.swing.*; import javax.swing.border.TitledBorder; @@ -14,7 +13,7 @@ public class ElementFrame extends JPanel { private static final String htmlTail = ""; private PlaceableElementPanel placeableElementPanel; - //private JTabbedPane tabbedPane; + // private JTabbedPane tabbedPane; private ButtonGroup buttonGroup; private EditorElementController controller; @@ -53,12 +52,12 @@ public ButtonGroup getButtonGroup() { return buttonGroup; } -// public void resetSize() { -// int buttonWidth = -// ((ElementPanel) tabbedPane.getSelectedComponent()) -// .getElementButtons()[0].getWidth(); -// this.setMinimumSize(new Dimension(2 * buttonWidth + 64, this.getHeight())); -// } + // public void resetSize() { + // int buttonWidth = + // ((ElementPanel) tabbedPane.getSelectedComponent()) + // .getElementButtons()[0].getWidth(); + // this.setMinimumSize(new Dimension(2 * buttonWidth + 64, this.getHeight())); + // } public void setElements(Puzzle puzzle) { if (puzzle != null) { @@ -70,9 +69,9 @@ public EditorElementController getController() { return controller; } -// public JTabbedPane getTabbedPane() { -// return tabbedPane; -// } + // public JTabbedPane getTabbedPane() { + // return tabbedPane; + // } public PlaceableElementPanel getPlaceableElementPanel() { return placeableElementPanel; diff --git a/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/NonPlaceableElementPanel.java b/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/NonPlaceableElementPanel.java index 796d1ae68..91e8d2e49 100644 --- a/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/NonPlaceableElementPanel.java +++ b/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/NonPlaceableElementPanel.java @@ -1,8 +1,8 @@ -//package edu.rpi.legup.ui.puzzleeditorui.elementsview; +// package edu.rpi.legup.ui.puzzleeditorui.elementsview; // -//import javax.swing.*; +// import javax.swing.*; // -//public class NonPlaceableElementPanel extends ElementPanel { +// public class NonPlaceableElementPanel extends ElementPanel { // public NonPlaceableElementPanel(ElementFrame elementFrame) { // super(elementFrame); // this.icon = @@ -12,4 +12,4 @@ // this.name = "Non-Placeable Elements"; // this.toolTip = "Non-Placeable Elements"; // } -//} +// } diff --git a/src/test/java/legup/TestUtilities.java b/src/test/java/legup/TestUtilities.java index d48d648d7..cd9f4a935 100644 --- a/src/test/java/legup/TestUtilities.java +++ b/src/test/java/legup/TestUtilities.java @@ -6,7 +6,6 @@ import edu.rpi.legup.model.tree.TreeNode; import edu.rpi.legup.model.tree.TreeTransition; import edu.rpi.legup.save.InvalidFileFormatException; - import java.io.InputStream; public final class TestUtilities { @@ -15,7 +14,8 @@ public static void importTestBoard(String fileName, Puzzle puzzle) InputStream inputStream = ClassLoader.getSystemResourceAsStream(fileName); if (inputStream == null) { - throw new IllegalArgumentException("InputStream cannot be null. File not found: " + fileName); + throw new IllegalArgumentException( + "InputStream cannot be null. File not found: " + fileName); } puzzle.importPuzzle(inputStream); diff --git a/src/test/java/puzzles/nurikabe/rules/FinishRoomCaseRuleTest.java b/src/test/java/puzzles/nurikabe/rules/FinishRoomCaseRuleTest.java index a29a1c934..32a440d13 100644 --- a/src/test/java/puzzles/nurikabe/rules/FinishRoomCaseRuleTest.java +++ b/src/test/java/puzzles/nurikabe/rules/FinishRoomCaseRuleTest.java @@ -27,13 +27,11 @@ public static void setUp() { nurikabe = new Nurikabe(); } - /** - * Tests the Finish Room case rule by ensuring it produces the correct number of children - */ - + /** Tests the Finish Room case rule by ensuring it produces the correct number of children */ @Test public void FinishRoomCaseRule_FinishRoomCaseRuleBaseTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/nurikabe/rules/FinishRoomCaseRule/FinishRoomCaseRuleBase", nurikabe); + TestUtilities.importTestBoard( + "puzzles/nurikabe/rules/FinishRoomCaseRule/FinishRoomCaseRuleBase", nurikabe); TreeNode rootNode = nurikabe.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); From 53f29b06f16dd633d4ae3937457ac3c48743ab6a Mon Sep 17 00:00:00 2001 From: Bram van Heuveln <56417002+jadeandtea@users.noreply.github.com> Date: Sun, 6 Oct 2024 17:29:15 -0400 Subject: [PATCH 6/7] Remove extraneous check of package name 'c' is found using LegupUtils.getClasses("edu.rpi.legup.puzzle"), so it will start with it. Fixes issue with STT rules not showing up. --- src/main/java/edu/rpi/legup/model/Puzzle.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/edu/rpi/legup/model/Puzzle.java b/src/main/java/edu/rpi/legup/model/Puzzle.java index 8024c99ed..da8f76ddd 100644 --- a/src/main/java/edu/rpi/legup/model/Puzzle.java +++ b/src/main/java/edu/rpi/legup/model/Puzzle.java @@ -135,8 +135,7 @@ private void registerRules() { for (Class c : possRules) { String classPackageName = c.getPackage().getName(); - if (!classPackageName.startsWith("edu.rpi.legup.puzzle.") - || !classPackageName.endsWith(".rules")) { + if (!classPackageName.contains(".rules")) { continue; } System.out.println("possible rule: " + c.getName()); From 13a38b3623aa5f0e5ba8e58b3a8dfb548e96e1ac Mon Sep 17 00:00:00 2001 From: Bram van Heuveln <56417002+jadeandtea@users.noreply.github.com> Date: Fri, 11 Oct 2024 16:26:40 -0400 Subject: [PATCH 7/7] Fixing Merge Conflict --- .../LastCellForNumberDirectRule/TestBoard | 19 ++ .../LastNumberForCellDirectRule/FullRegion | 19 ++ .../rules/RepeatedNumberContradictionRule/a | 0 .../10x10 Binary Hard/10x10 Binary Hard 1 | 111 +++++++++ .../10x10 Binary Hard/10x10 Binary Hard 2 | 111 +++++++++ .../10x10 Binary Hard/10x10 Binary Hard 3 | 111 +++++++++ .../10x10 Binary Medium/10x10 Binary Medium 1 | 111 +++++++++ .../10x10 Binary Medium/10x10 Binary Medium 2 | 111 +++++++++ .../10x10 Binary Medium/10x10 Binary Medium 3 | 111 +++++++++ .../10x10 Binary Very Hard 1 | 111 +++++++++ .../binary/6x6 Binary Easy/6x6 Binary Easy 1 | 22 ++ .../binary/6x6 Binary Easy/6x6 Binary Easy 2 | 21 ++ .../binary/6x6 Binary Easy/6x6 Binary Easy 3 | 25 ++ .../binary/6x6 Binary Easy/6x6 Binary Easy 4 | 28 +++ .../binary/6x6 Binary Easy/6x6 Binary Easy 5 | 47 ++++ .../binary/6x6 Binary Hard/6x6 Binary Hard 1 | 47 ++++ .../binary/6x6 Binary Hard/6x6 Binary Hard 2 | 47 ++++ .../binary/6x6 Binary Hard/6x6 Binary Hard 3 | 47 ++++ .../6x6 Binary Medium/6x6 Binary Medium 1 | 47 ++++ .../6x6 Binary Medium/6x6 Binary Medium 2 | 47 ++++ .../6x6 Binary Medium/6x6 Binary Medium 3 | 47 ++++ .../6x6 Binary Very Hard 1 | 47 ++++ .../6x6 Binary Very Hard 2 | 47 ++++ .../6x6 Binary Very Hard 3 | 47 ++++ .../binary/8x8 Binary Easy/8x8 Binary Easy 1 | 75 ++++++ .../binary/8x8 Binary Easy/8x8 Binary Easy 2 | 75 ++++++ .../binary/8x8 Binary Easy/8x8 Binary Easy 3 | 75 ++++++ .../binary/8x8 Binary Hard/8x8 Binary Hard 1 | 75 ++++++ .../binary/8x8 Binary Hard/8x8 Binary Hard 2 | 75 ++++++ .../binary/8x8 Binary Hard/8x8 Binary Hard 3 | 75 ++++++ .../8x8 Binary Medium/8x8 Binary Medium 1 | 75 ++++++ .../8x8 Binary Medium/8x8 Binary Medium 2 | 75 ++++++ .../8x8 Binary Medium/8x8 Binary Medium 3 | 75 ++++++ .../8x8 Binary Very Hard 1 | 75 ++++++ .../8x8 Binary Very Hard 2 | 75 ++++++ .../8x8 Binary Very Hard 3 | 75 ++++++ puzzles files/light-color-theme.txt | 99 ++++++++ .../5x5 Star Battle 1 star Normal 1.xml | 53 ---- .../6x6 Star Battle 1star Normal1.xml | 68 ----- .../6x6 Star Battle 1star Normal2.xml | 68 ----- .../6x6 StarBattle 1star Normal3.xml | 68 ----- .../7x7 Star Battle 1star Hard1.xml | 85 ------- .../7x7 Star Battle 1star Normal.xml | 85 ------- .../7x7 Star Battle 1star Normal1.xml | 85 ------- .../7x7 Star Battle 1star Normal2.xml | 85 ------- .../8x8 Star Battle 1star Normal1.xml | 105 -------- .../8x8 Star Battle 1star Normal2.xml | 104 -------- .../8x8 Star Battle 1star Normal3.xml | 104 -------- src/main/java/edu/rpi/legup/app/Config.java | 5 + .../edu/rpi/legup/app/GameBoardFacade.java | 33 ++- .../rpi/legup/app/InvalidConfigException.java | 5 + .../edu/rpi/legup/app/LegupPreferences.java | 27 +- .../edu/rpi/legup/controller/Controller.java | 5 + .../controller/EditorElementController.java | 16 +- .../legup/controller/ElementController.java | 18 +- .../edu/rpi/legup/history/CommandError.java | 10 + .../edu/rpi/legup/history/CommandState.java | 10 + .../history/DeleteTreeElementCommand.java | 4 + .../rpi/legup/history/EditDataCommand.java | 22 +- .../java/edu/rpi/legup/history/History.java | 10 +- .../rpi/legup/history/IHistoryListener.java | 9 +- .../rpi/legup/history/IHistorySubject.java | 9 +- .../InvalidCommandStateTransition.java | 7 + .../history/ValidateDirectRuleCommand.java | 31 ++- src/main/java/edu/rpi/legup/model/Puzzle.java | 55 ++-- .../edu/rpi/legup/model/PuzzleImporter.java | 22 +- .../edu/rpi/legup/model/elements/Element.java | 43 ++++ .../edu/rpi/legup/model/gameboard/Board.java | 15 +- .../rpi/legup/model/gameboard/CaseBoard.java | 48 ++++ .../legup/model/gameboard/ElementFactory.java | 3 + .../rpi/legup/model/gameboard/GridBoard.java | 5 + .../rpi/legup/model/gameboard/GridRegion.java | 7 +- .../legup/model/gameboard/PuzzleElement.java | 20 ++ .../legup/model/observer/IBoardListener.java | 2 +- .../legup/model/observer/IBoardSubject.java | 2 +- .../legup/model/observer/ITreeSubject.java | 4 +- .../edu/rpi/legup/model/rules/MergeRule.java | 2 +- .../java/edu/rpi/legup/model/rules/Rule.java | 5 + .../java/edu/rpi/legup/model/tree/Tree.java | 51 +++- .../edu/rpi/legup/model/tree/TreeElement.java | 2 +- .../edu/rpi/legup/model/tree/TreeNode.java | 4 +- .../edu/rpi/legup/puzzle/binary/Binary.java | 23 +- .../rpi/legup/puzzle/binary/BinaryBoard.java | 14 +- .../rpi/legup/puzzle/binary/BinaryCell.java | 21 +- .../puzzle/binary/BinaryCellFactory.java | 16 +- .../legup/puzzle/binary/BinaryController.java | 6 +- .../puzzle/binary/BinaryElementView.java | 104 ++------ .../legup/puzzle/binary/BinaryExporter.java | 2 +- .../legup/puzzle/binary/BinaryImporter.java | 23 +- .../puzzle/binary/elements/BlankTile.java | 1 - .../binary_elements_reference_sheet.txt | 2 + .../rules/CompleteRowColumnDirectRule.java | 22 +- .../binary/rules/OneTileGapDirectRule.java | 64 ----- ...> RepeatedRowColumnContradictionRule.java} | 26 +- .../binary/rules/SurroundPairDirectRule.java | 48 ---- .../rules/ThreeAdjacentContradictionRule.java | 127 ---------- ...UnbalancedRowColumnContradictionRule.java} | 27 +- ...roCaseRule.java => ZeroOrOneCaseRule.java} | 48 +++- .../binary/rules/binary_reference_sheet.txt | 16 +- .../legup/puzzle/fillapix/FillapixCell.java | 6 +- .../puzzle/fillapix/elements/BlackTile.java | 2 +- .../puzzle/fillapix/elements/NumberTile.java | 6 +- .../puzzle/fillapix/elements/UnknownTile.java | 6 +- .../puzzle/fillapix/elements/WhiteTile.java | 2 +- .../fillapix_elements_reference_sheet.txt | 9 +- .../fillapix/rules/BlackOrWhiteCaseRule.java | 3 + .../fillapix/rules/SatisfyClueCaseRule.java | 3 + .../edu/rpi/legup/puzzle/lightup/LightUp.java | 2 +- .../legup/puzzle/lightup/LightUpBoard.java | 6 +- .../rpi/legup/puzzle/lightup/LightUpCell.java | 8 +- .../puzzle/lightup/elements/BlackTile.java | 6 +- .../puzzle/lightup/elements/BulbTile.java | 2 +- .../puzzle/lightup/elements/NumberTile.java | 8 +- .../puzzle/lightup/elements/UnknownTile.java | 6 +- .../lightup_elements_reference_sheet.txt | 4 + .../lightup/rules/LightOrEmptyCaseRule.java | 4 + .../lightup/rules/SatisfyNumberCaseRule.java | 6 +- .../rules/TooFewBulbsContradictionRule.java | 2 +- .../puzzle/minesweeper/elements/BombTile.java | 4 +- .../minesweeper/elements/UnsetTile.java | 4 +- .../legup/puzzle/nurikabe/NurikabeCell.java | 6 +- .../puzzle/nurikabe/NurikabeExporter.java | 7 + .../puzzle/nurikabe/elements/BlackTile.java | 2 +- .../puzzle/nurikabe/elements/NumberTile.java | 6 +- .../puzzle/nurikabe/elements/UnknownTile.java | 6 +- .../puzzle/nurikabe/elements/WhiteTile.java | 2 +- .../nurikabe_elements_reference_sheet.txt | 4 + .../nurikabe/rules/BlackOrWhiteCaseRule.java | 6 +- .../nurikabe/rules/FinishRoomCaseRule.java | 59 ++--- .../shorttruthtable/ShortTruthTableCell.java | 10 +- .../elements/ArgumentElement.java | 6 +- .../elements/GreenElement.java | 2 +- .../elements/LogicSymbolElement.java | 6 +- .../shorttruthtable/elements/RedElement.java | 2 +- .../elements/UnknownElement.java | 2 +- .../shorttruthtable_elements_reference_sheet | 11 +- .../rules/caserule/CaseRuleAtomic.java | 3 + .../caserule/CaseRule_GenericStatement.java | 5 + .../legup/puzzle/skyscrapers/Skyscrapers.java | 2 +- .../puzzle/skyscrapers/SkyscrapersBoard.java | 6 +- .../puzzle/skyscrapers/SkyscrapersCell.java | 4 +- .../skyscrapers/SkyscrapersClueView.java | 6 +- .../puzzle/skyscrapers/elements/ClueTile.java | 14 -- .../skyscrapers/elements/NumberTile.java | 6 +- .../skyscrapers/elements/UnknownTile.java | 6 +- .../skyscrapers_elements_reference_sheet.txt | 5 +- .../rules/CellForNumberCaseRule.java | 3 + .../rules/NumberForCellCaseRule.java | 3 + .../rpi/legup/puzzle/starbattle/allfiles.txt | 235 ------------------ .../puzzle/starbattle/elements/BlackTile.java | 4 +- .../puzzle/starbattle/elements/StarTile.java | 4 +- .../starbattle/elements/UnknownTile.java | 4 +- .../starbattle_elements_reference_sheet.txt | 4 + .../starbattle/rules/StarOrEmptyCaseRule.java | 4 + .../rules/starbattle_reference_sheet.txt | 19 -- .../legup/puzzle/sudoku/ModelSudokuBoard.java | 17 ++ .../sudoku/PossibleNumberCaseBoard.java | 4 +- .../edu/rpi/legup/puzzle/sudoku/Sudoku.java | 2 + .../rpi/legup/puzzle/sudoku/SudokuCell.java | 2 + .../puzzle/sudoku/SudokuCellController.java | 2 +- .../legup/puzzle/sudoku/SudokuImporter.java | 10 - .../rpi/legup/puzzle/sudoku/SudokuView.java | 1 + .../puzzle/sudoku/elements/NumberTile.java | 9 +- .../sudoku_elements_reference_sheet.txt | 2 + .../rules/AdvancedDeductionDirectRule.java | 99 -------- .../rules/LastCellForNumberDirectRule.java | 136 ++++++++-- .../rules/LastNumberForCellDirectRule.java | 25 +- ...oCellForNumberColumnContradictionRule.java | 90 +++++++ ...oCellForNumberRegionContradictionRule.java | 90 +++++++ .../NoCellForNumberRowContradictionRule.java | 90 +++++++ ... => NoNumberForCellContradictionRule.java} | 30 ++- ...PossibleCellsForNumberColumnCaseRule.java} | 82 +++--- .../PossibleCellsForNumberRegionCaseRule.java | 104 ++++++++ .../PossibleCellsForNumberRowCaseRule.java | 107 ++++++++ ...va => PossibleNumbersForCellCaseRule.java} | 73 +++--- .../RepeatedNumberContradictionRule.java | 64 +++-- .../sudoku/rules/sudoku_reference_sheet.txt | 14 +- .../rpi/legup/puzzle/treetent/TreeTent.java | 15 +- .../puzzle/treetent/elements/GrassTile.java | 2 +- .../puzzle/treetent/elements/TentTile.java | 2 +- .../puzzle/treetent/elements/TreeTile.java | 6 +- .../puzzle/treetent/elements/UnknownTile.java | 6 +- .../treetent_elements_reference_sheet.txt | 4 + .../treetent/rules/FillinRowCaseRule.java | 4 + .../treetent/rules/LinkTentCaseRule.java | 4 + .../treetent/rules/LinkTreeCaseRule.java | 4 + .../edu/rpi/legup/ui/CreatePuzzleDialog.java | 14 +- .../java/edu/rpi/legup/ui/DynamicView.java | 35 +++ src/main/java/edu/rpi/legup/ui/HomePanel.java | 113 ++++----- src/main/java/edu/rpi/legup/ui/LegupUI.java | 67 +++-- .../java/edu/rpi/legup/ui/PickGameDialog.java | 10 + .../edu/rpi/legup/ui/PreferencesDialog.java | 22 ++ .../edu/rpi/legup/ui/ProofEditorPanel.java | 174 ++++++------- .../edu/rpi/legup/ui/PuzzleEditorPanel.java | 199 ++++++++------- .../java/edu/rpi/legup/ui/ScrollView.java | 5 + .../java/edu/rpi/legup/ui/ToolbarName.java | 5 +- .../java/edu/rpi/legup/ui/ZoomWidget.java | 9 + .../java/edu/rpi/legup/ui/ZoomablePane.java | 4 + .../edu/rpi/legup/ui/boardview/BoardView.java | 15 ++ .../legup/ui/boardview/DataSelectionView.java | 5 + .../legup/ui/boardview/ElementSelection.java | 33 +++ .../rpi/legup/ui/boardview/ElementView.java | 46 ++++ .../rpi/legup/ui/boardview/GridBoardView.java | 9 +- .../legup/ui/boardview/SelectionItemView.java | 5 + .../ui/proofeditorui/rulesview/RuleFrame.java | 27 +- .../ui/proofeditorui/rulesview/RulePanel.java | 32 ++- .../treeview/TreeElementView.java | 4 +- .../proofeditorui/treeview/TreeNodeView.java | 10 + .../ui/proofeditorui/treeview/TreePanel.java | 25 ++ .../treeview/TreeToolBarButton.java | 11 + .../treeview/TreeToolBarName.java | 4 + .../treeview/TreeTransitionView.java | 52 ++-- .../ui/proofeditorui/treeview/TreeView.java | 100 ++++++-- .../elementsview/ElementFrame.java | 42 ++-- .../elementsview/ElementPanel.java | 3 +- .../edu/rpi/legup/images/Legup/Reset.png | Bin 0 -> 662 bytes .../rules/CompleteRowColumnDirectRule.png | Bin 2835 -> 2174 bytes .../DuplicateRowOrColumnContradictionRule.png | Bin 3455 -> 0 bytes .../images/binary/rules/OneOrZeroCaseRule.png | Bin 5578 -> 0 bytes .../binary/rules/OneTileGapDirectRule.png | Bin 2751 -> 0 bytes .../binary/rules/PreventTrioDirectRule.png | Bin 0 -> 1944 bytes .../RepeatedRowColumnContradictionRule.png | Bin 0 -> 2124 bytes .../binary/rules/SaveBlockerDirectRule.png | Bin 0 -> 2204 bytes .../binary/rules/SurroundPairDirectRule.png | Bin 2982 -> 0 bytes .../rules/ThreeAdjacentContradictionRule.png | Bin 2508 -> 0 bytes .../binary/rules/TrioContradictionRule.png | Bin 0 -> 2071 bytes .../UnbalancedRowColumnContradictionRule.png | Bin 2793 -> 1783 bytes .../rules/UniqueRowColumnDirectRule.png | Bin 0 -> 3304 bytes .../rules/WastedBlockerContradictionRule.png | Bin 0 -> 2006 bytes .../images/binary/rules/ZeroOrOneCaseRule.png | Bin 0 -> 2186 bytes .../legup/images/binary/tiles/NumberTile.png | Bin 0 -> 370 bytes .../legup/images/binary/tiles/UnknownTile.png | Bin 0 -> 7231 bytes .../skyscrapers/cases/CellForNumber.png | Bin 1871 -> 1531 bytes .../skyscrapers/cases/NumberForCell.png | Bin 1875 -> 1603 bytes .../contradictions/DuplicateNumber.png | Bin 954 -> 1991 bytes .../contradictions/ExceedingVisibility.png | Bin 1184 -> 1949 bytes .../contradictions/InsufficientVisibility.png | Bin 1291 -> 2071 bytes .../contradictions/PreemptiveVisibility.png | Bin 1101 -> 1784 bytes .../contradictions/UnresolvedCell.png | Bin 1165 -> 2108 bytes .../contradictions/UnresolvedNumber.png | Bin 1357 -> 2658 bytes .../images/skyscrapers/rules/FixedMax.png | Bin 1225 -> 1783 bytes .../images/skyscrapers/rules/LastCell.png | Bin 1352 -> 2174 bytes .../images/skyscrapers/rules/LastNumber.png | Bin 1335 -> 2083 bytes .../legup/images/skyscrapers/rules/NEdge.png | Bin 1523 -> 2027 bytes .../images/skyscrapers/rules/OneEdge.png | Bin 934 -> 1455 bytes .../edu/rpi/legup/images/starbattle/black.gif | Bin 856 -> 0 bytes .../starbattle/cases/StarOrEmptyCaseRule.png | Bin 4437 -> 0 bytes .../ClashingOrbitContradictionRule.png | Bin 5135 -> 0 bytes .../TooFewStarsContradictionRule.png | Bin 3218 -> 0 bytes .../TooManyStarsContradictionRule.png | Bin 6199 -> 0 bytes .../edu/rpi/legup/images/starbattle/empty.gif | Bin 857 -> 0 bytes .../starbattle/rules/BlackOutDirectRule.png | Bin 4717 -> 0 bytes .../rules/ColumnsWithinRegionsDirectRule.png | Bin 6456 -> 0 bytes .../rules/ColumnsWithinRowsDirectRule.png | Bin 5331 -> 0 bytes .../rules/FinishWithStarDirectRule.png | Bin 4326 -> 0 bytes .../rules/RegionsWithinColumnsDirectRule.png | Bin 6402 -> 0 bytes .../rules/RegionsWithinRowsDirectRule.png | Bin 6269 -> 0 bytes .../rules/RowsWithinColumnsDirectRule.png | Bin 5117 -> 0 bytes .../rules/RowsWithinRegionsDirectRule.png | Bin 6477 -> 0 bytes .../images/starbattle/rules/SurroundStar.png | Bin 5102 -> 0 bytes .../edu/rpi/legup/images/starbattle/star.gif | Bin 545 -> 0 bytes .../legup/images/sudoku/AdvancedDeduction.png | Bin 3351 -> 0 bytes .../sudoku/rules/NoCellForNumberColumn.png | Bin 0 -> 958 bytes .../sudoku/rules/NoCellForNumberRegion.png | Bin 0 -> 1077 bytes .../sudoku/rules/NoCellForNumberRow.png | Bin 0 -> 916 bytes .../images/sudoku/{ => rules}/NoSolution.png | Bin .../sudoku/{ => rules}/PossibleValues.png | Bin .../sudoku/{ => rules}/RepeatedNumber.png | Bin .../sudoku/{ => rules}/forcedByDeduction.png | Bin .../{ => rules}/forcedByElimination.png | Bin .../{ => rules}/possible_cells_number.png | Bin .../rules/possible_cells_number_column.png | Bin 0 -> 3336 bytes .../rules/possible_cells_number_region.png | Bin 0 -> 3623 bytes .../rules/possible_cells_number_row.png | Bin 0 -> 803 bytes .../legup/images/sudoku/{ => rules}/tem.png | Bin .../white.gif => sudoku/tiles/NumberTile.png} | Bin 9700 -> 10067 bytes .../tiles}/UnknownTile.png | Bin src/main/resources/edu/rpi/legup/legup/config | 30 +-- .../rules/FinishRoomCaseRuleTest.java | 30 +-- ...LastNumberForCellDirectRuleRegionTest.java | 100 ++++++++ .../RepeatedNumberContradictionRuleTest.java | 88 +++++++ .../SurroundTwoZerosWithTwoOnes | 10 + .../binary/rules/SurroundPairDirectRule/test | 0 .../SurroundTwoZerosWithTwoOnes | 10 + .../BlackoutDirectRule/ColumnBlackout | 40 --- .../BlackoutDirectRule/RegionBlackout | 36 --- .../BlackoutDirectRule/RowBlackout | 36 --- .../CorneredRegion | 14 ++ .../LastNumberForCellDirectRule/FullMixed | 18 ++ .../LastNumberForCellDirectRule/FullRegion | 18 ++ .../rules/LastNumberForCellDirectRule/FullRow | 18 ++ .../BlankBoard4 | 12 + .../BlankBoard7 | 11 + 293 files changed, 4995 insertions(+), 2620 deletions(-) create mode 100644 output_path/test/src/resources/puzzles/sudoku/rules/LastCellForNumberDirectRule/TestBoard create mode 100644 output_path/test/src/resources/puzzles/sudoku/rules/LastNumberForCellDirectRule/FullRegion create mode 100644 output_path/test/src/resources/puzzles/sudoku/rules/RepeatedNumberContradictionRule/a create mode 100644 puzzles files/binary/10x10 Binary Hard/10x10 Binary Hard 1 create mode 100644 puzzles files/binary/10x10 Binary Hard/10x10 Binary Hard 2 create mode 100644 puzzles files/binary/10x10 Binary Hard/10x10 Binary Hard 3 create mode 100644 puzzles files/binary/10x10 Binary Medium/10x10 Binary Medium 1 create mode 100644 puzzles files/binary/10x10 Binary Medium/10x10 Binary Medium 2 create mode 100644 puzzles files/binary/10x10 Binary Medium/10x10 Binary Medium 3 create mode 100644 puzzles files/binary/10x10 Binary Very Hard/10x10 Binary Very Hard 1 create mode 100644 puzzles files/binary/6x6 Binary Easy/6x6 Binary Easy 1 create mode 100644 puzzles files/binary/6x6 Binary Easy/6x6 Binary Easy 2 create mode 100644 puzzles files/binary/6x6 Binary Easy/6x6 Binary Easy 3 create mode 100644 puzzles files/binary/6x6 Binary Easy/6x6 Binary Easy 4 create mode 100644 puzzles files/binary/6x6 Binary Easy/6x6 Binary Easy 5 create mode 100644 puzzles files/binary/6x6 Binary Hard/6x6 Binary Hard 1 create mode 100644 puzzles files/binary/6x6 Binary Hard/6x6 Binary Hard 2 create mode 100644 puzzles files/binary/6x6 Binary Hard/6x6 Binary Hard 3 create mode 100644 puzzles files/binary/6x6 Binary Medium/6x6 Binary Medium 1 create mode 100644 puzzles files/binary/6x6 Binary Medium/6x6 Binary Medium 2 create mode 100644 puzzles files/binary/6x6 Binary Medium/6x6 Binary Medium 3 create mode 100644 puzzles files/binary/6x6 Binary Very Hard/6x6 Binary Very Hard 1 create mode 100644 puzzles files/binary/6x6 Binary Very Hard/6x6 Binary Very Hard 2 create mode 100644 puzzles files/binary/6x6 Binary Very Hard/6x6 Binary Very Hard 3 create mode 100644 puzzles files/binary/8x8 Binary Easy/8x8 Binary Easy 1 create mode 100644 puzzles files/binary/8x8 Binary Easy/8x8 Binary Easy 2 create mode 100644 puzzles files/binary/8x8 Binary Easy/8x8 Binary Easy 3 create mode 100644 puzzles files/binary/8x8 Binary Hard/8x8 Binary Hard 1 create mode 100644 puzzles files/binary/8x8 Binary Hard/8x8 Binary Hard 2 create mode 100644 puzzles files/binary/8x8 Binary Hard/8x8 Binary Hard 3 create mode 100644 puzzles files/binary/8x8 Binary Medium/8x8 Binary Medium 1 create mode 100644 puzzles files/binary/8x8 Binary Medium/8x8 Binary Medium 2 create mode 100644 puzzles files/binary/8x8 Binary Medium/8x8 Binary Medium 3 create mode 100644 puzzles files/binary/8x8 Binary Very Hard/8x8 Binary Very Hard 1 create mode 100644 puzzles files/binary/8x8 Binary Very Hard/8x8 Binary Very Hard 2 create mode 100644 puzzles files/binary/8x8 Binary Very Hard/8x8 Binary Very Hard 3 create mode 100644 puzzles files/light-color-theme.txt delete mode 100644 puzzles files/starbattle/5x5 Star Battle 1 star Normal/5x5 Star Battle 1 star Normal 1.xml delete mode 100644 puzzles files/starbattle/6x6 Star Battle 1 star Normal/6x6 Star Battle 1star Normal1.xml delete mode 100644 puzzles files/starbattle/6x6 Star Battle 1 star Normal/6x6 Star Battle 1star Normal2.xml delete mode 100644 puzzles files/starbattle/6x6 Star Battle 1 star Normal/6x6 StarBattle 1star Normal3.xml delete mode 100644 puzzles files/starbattle/7x7 Star Battle 1 star Hard/7x7 Star Battle 1star Hard1.xml delete mode 100644 puzzles files/starbattle/7x7 Star Battle 1 star Normal/7x7 Star Battle 1star Normal.xml delete mode 100644 puzzles files/starbattle/7x7 Star Battle 1 star Normal/7x7 Star Battle 1star Normal1.xml delete mode 100644 puzzles files/starbattle/7x7 Star Battle 1 star Normal/7x7 Star Battle 1star Normal2.xml delete mode 100644 puzzles files/starbattle/8x8 Star Battle 1 star Normal/8x8 Star Battle 1star Normal1.xml delete mode 100644 puzzles files/starbattle/8x8 Star Battle 1 star Normal/8x8 Star Battle 1star Normal2.xml delete mode 100644 puzzles files/starbattle/8x8 Star Battle 1 star Normal/8x8 Star Battle 1star Normal3.xml delete mode 100644 src/main/java/edu/rpi/legup/puzzle/binary/elements/BlankTile.java create mode 100644 src/main/java/edu/rpi/legup/puzzle/binary/elements/binary_elements_reference_sheet.txt delete mode 100644 src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java rename src/main/java/edu/rpi/legup/puzzle/binary/rules/{DuplicateRowsOrColumnsContradictionRule.java => RepeatedRowColumnContradictionRule.java} (69%) delete mode 100644 src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java delete mode 100644 src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java rename src/main/java/edu/rpi/legup/puzzle/binary/rules/{UnbalancedRowOrColumnContradictionRule.java => UnbalancedRowColumnContradictionRule.java} (66%) rename src/main/java/edu/rpi/legup/puzzle/binary/rules/{OneOrZeroCaseRule.java => ZeroOrOneCaseRule.java} (64%) create mode 100644 src/main/java/edu/rpi/legup/puzzle/lightup/elements/lightup_elements_reference_sheet.txt create mode 100644 src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/nurikabe_elements_reference_sheet.txt delete mode 100644 src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/ClueTile.java delete mode 100644 src/main/java/edu/rpi/legup/puzzle/starbattle/allfiles.txt create mode 100644 src/main/java/edu/rpi/legup/puzzle/starbattle/elements/starbattle_elements_reference_sheet.txt delete mode 100644 src/main/java/edu/rpi/legup/puzzle/starbattle/rules/starbattle_reference_sheet.txt create mode 100644 src/main/java/edu/rpi/legup/puzzle/sudoku/ModelSudokuBoard.java create mode 100644 src/main/java/edu/rpi/legup/puzzle/sudoku/elements/sudoku_elements_reference_sheet.txt delete mode 100644 src/main/java/edu/rpi/legup/puzzle/sudoku/rules/AdvancedDeductionDirectRule.java create mode 100644 src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberColumnContradictionRule.java create mode 100644 src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberRegionContradictionRule.java create mode 100644 src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberRowContradictionRule.java rename src/main/java/edu/rpi/legup/puzzle/sudoku/rules/{NoSolutionContradictionRule.java => NoNumberForCellContradictionRule.java} (72%) rename src/main/java/edu/rpi/legup/puzzle/sudoku/rules/{PossibleNumberCaseRule.java => PossibleCellsForNumberColumnCaseRule.java} (53%) create mode 100644 src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberRegionCaseRule.java create mode 100644 src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberRowCaseRule.java rename src/main/java/edu/rpi/legup/puzzle/sudoku/rules/{PossibleCellCaseRule.java => PossibleNumbersForCellCaseRule.java} (59%) create mode 100644 src/main/java/edu/rpi/legup/puzzle/treetent/elements/treetent_elements_reference_sheet.txt create mode 100644 src/main/resources/edu/rpi/legup/images/Legup/Reset.png delete mode 100644 src/main/resources/edu/rpi/legup/images/binary/rules/DuplicateRowOrColumnContradictionRule.png delete mode 100644 src/main/resources/edu/rpi/legup/images/binary/rules/OneOrZeroCaseRule.png delete mode 100644 src/main/resources/edu/rpi/legup/images/binary/rules/OneTileGapDirectRule.png create mode 100644 src/main/resources/edu/rpi/legup/images/binary/rules/PreventTrioDirectRule.png create mode 100644 src/main/resources/edu/rpi/legup/images/binary/rules/RepeatedRowColumnContradictionRule.png create mode 100644 src/main/resources/edu/rpi/legup/images/binary/rules/SaveBlockerDirectRule.png delete mode 100644 src/main/resources/edu/rpi/legup/images/binary/rules/SurroundPairDirectRule.png delete mode 100644 src/main/resources/edu/rpi/legup/images/binary/rules/ThreeAdjacentContradictionRule.png create mode 100644 src/main/resources/edu/rpi/legup/images/binary/rules/TrioContradictionRule.png create mode 100644 src/main/resources/edu/rpi/legup/images/binary/rules/UniqueRowColumnDirectRule.png create mode 100644 src/main/resources/edu/rpi/legup/images/binary/rules/WastedBlockerContradictionRule.png create mode 100644 src/main/resources/edu/rpi/legup/images/binary/rules/ZeroOrOneCaseRule.png create mode 100644 src/main/resources/edu/rpi/legup/images/binary/tiles/NumberTile.png create mode 100644 src/main/resources/edu/rpi/legup/images/binary/tiles/UnknownTile.png delete mode 100644 src/main/resources/edu/rpi/legup/images/starbattle/black.gif delete mode 100644 src/main/resources/edu/rpi/legup/images/starbattle/cases/StarOrEmptyCaseRule.png delete mode 100644 src/main/resources/edu/rpi/legup/images/starbattle/contradictions/ClashingOrbitContradictionRule.png delete mode 100644 src/main/resources/edu/rpi/legup/images/starbattle/contradictions/TooFewStarsContradictionRule.png delete mode 100644 src/main/resources/edu/rpi/legup/images/starbattle/contradictions/TooManyStarsContradictionRule.png delete mode 100644 src/main/resources/edu/rpi/legup/images/starbattle/empty.gif delete mode 100644 src/main/resources/edu/rpi/legup/images/starbattle/rules/BlackOutDirectRule.png delete mode 100644 src/main/resources/edu/rpi/legup/images/starbattle/rules/ColumnsWithinRegionsDirectRule.png delete mode 100644 src/main/resources/edu/rpi/legup/images/starbattle/rules/ColumnsWithinRowsDirectRule.png delete mode 100644 src/main/resources/edu/rpi/legup/images/starbattle/rules/FinishWithStarDirectRule.png delete mode 100644 src/main/resources/edu/rpi/legup/images/starbattle/rules/RegionsWithinColumnsDirectRule.png delete mode 100644 src/main/resources/edu/rpi/legup/images/starbattle/rules/RegionsWithinRowsDirectRule.png delete mode 100644 src/main/resources/edu/rpi/legup/images/starbattle/rules/RowsWithinColumnsDirectRule.png delete mode 100644 src/main/resources/edu/rpi/legup/images/starbattle/rules/RowsWithinRegionsDirectRule.png delete mode 100644 src/main/resources/edu/rpi/legup/images/starbattle/rules/SurroundStar.png delete mode 100644 src/main/resources/edu/rpi/legup/images/starbattle/star.gif delete mode 100644 src/main/resources/edu/rpi/legup/images/sudoku/AdvancedDeduction.png create mode 100644 src/main/resources/edu/rpi/legup/images/sudoku/rules/NoCellForNumberColumn.png create mode 100644 src/main/resources/edu/rpi/legup/images/sudoku/rules/NoCellForNumberRegion.png create mode 100644 src/main/resources/edu/rpi/legup/images/sudoku/rules/NoCellForNumberRow.png rename src/main/resources/edu/rpi/legup/images/sudoku/{ => rules}/NoSolution.png (100%) rename src/main/resources/edu/rpi/legup/images/sudoku/{ => rules}/PossibleValues.png (100%) rename src/main/resources/edu/rpi/legup/images/sudoku/{ => rules}/RepeatedNumber.png (100%) rename src/main/resources/edu/rpi/legup/images/sudoku/{ => rules}/forcedByDeduction.png (100%) rename src/main/resources/edu/rpi/legup/images/sudoku/{ => rules}/forcedByElimination.png (100%) rename src/main/resources/edu/rpi/legup/images/sudoku/{ => rules}/possible_cells_number.png (100%) create mode 100644 src/main/resources/edu/rpi/legup/images/sudoku/rules/possible_cells_number_column.png create mode 100644 src/main/resources/edu/rpi/legup/images/sudoku/rules/possible_cells_number_region.png create mode 100644 src/main/resources/edu/rpi/legup/images/sudoku/rules/possible_cells_number_row.png rename src/main/resources/edu/rpi/legup/images/sudoku/{ => rules}/tem.png (100%) rename src/main/resources/edu/rpi/legup/images/{starbattle/white.gif => sudoku/tiles/NumberTile.png} (82%) rename src/main/resources/edu/rpi/legup/images/{starbattle => sudoku/tiles}/UnknownTile.png (100%) create mode 100644 src/test/java/puzzles/sudoku/rules/LastNumberForCellDirectRuleRegionTest.java create mode 100644 src/test/java/puzzles/sudoku/rules/RepeatedNumberContradictionRuleTest.java create mode 100644 src/test/resources/puzzles/binary/rules/SurroundPairDirectRule/SurroundTwoZerosWithTwoOnes create mode 100644 src/test/resources/puzzles/binary/rules/SurroundPairDirectRule/test create mode 100644 src/test/resources/puzzles/nurikabe/rules/BlackBetweenRegionsDirectRule/SurroundTwoZerosWithTwoOnes delete mode 100644 src/test/resources/puzzles/starbattle.rules/BlackoutDirectRule/ColumnBlackout delete mode 100644 src/test/resources/puzzles/starbattle.rules/BlackoutDirectRule/RegionBlackout delete mode 100644 src/test/resources/puzzles/starbattle.rules/BlackoutDirectRule/RowBlackout create mode 100644 src/test/resources/puzzles/sudoku/rules/LastCellForNumberDirectRule/CorneredRegion create mode 100644 src/test/resources/puzzles/sudoku/rules/LastNumberForCellDirectRule/FullMixed create mode 100644 src/test/resources/puzzles/sudoku/rules/LastNumberForCellDirectRule/FullRegion create mode 100644 src/test/resources/puzzles/sudoku/rules/LastNumberForCellDirectRule/FullRow create mode 100644 src/test/resources/puzzles/sudoku/rules/RepeatedNumberContradictionRule/BlankBoard4 create mode 100644 src/test/resources/puzzles/sudoku/rules/RepeatedNumberContradictionRule/BlankBoard7 diff --git a/output_path/test/src/resources/puzzles/sudoku/rules/LastCellForNumberDirectRule/TestBoard b/output_path/test/src/resources/puzzles/sudoku/rules/LastCellForNumberDirectRule/TestBoard new file mode 100644 index 000000000..a41ad749c --- /dev/null +++ b/output_path/test/src/resources/puzzles/sudoku/rules/LastCellForNumberDirectRule/TestBoard @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/output_path/test/src/resources/puzzles/sudoku/rules/LastNumberForCellDirectRule/FullRegion b/output_path/test/src/resources/puzzles/sudoku/rules/LastNumberForCellDirectRule/FullRegion new file mode 100644 index 000000000..49dae4aa6 --- /dev/null +++ b/output_path/test/src/resources/puzzles/sudoku/rules/LastNumberForCellDirectRule/FullRegion @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/output_path/test/src/resources/puzzles/sudoku/rules/RepeatedNumberContradictionRule/a b/output_path/test/src/resources/puzzles/sudoku/rules/RepeatedNumberContradictionRule/a new file mode 100644 index 000000000..e69de29bb diff --git a/puzzles files/binary/10x10 Binary Hard/10x10 Binary Hard 1 b/puzzles files/binary/10x10 Binary Hard/10x10 Binary Hard 1 new file mode 100644 index 000000000..42ccf371b --- /dev/null +++ b/puzzles files/binary/10x10 Binary Hard/10x10 Binary Hard 1 @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/10x10 Binary Hard/10x10 Binary Hard 2 b/puzzles files/binary/10x10 Binary Hard/10x10 Binary Hard 2 new file mode 100644 index 000000000..d73caa5d2 --- /dev/null +++ b/puzzles files/binary/10x10 Binary Hard/10x10 Binary Hard 2 @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/10x10 Binary Hard/10x10 Binary Hard 3 b/puzzles files/binary/10x10 Binary Hard/10x10 Binary Hard 3 new file mode 100644 index 000000000..99ec9769b --- /dev/null +++ b/puzzles files/binary/10x10 Binary Hard/10x10 Binary Hard 3 @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/10x10 Binary Medium/10x10 Binary Medium 1 b/puzzles files/binary/10x10 Binary Medium/10x10 Binary Medium 1 new file mode 100644 index 000000000..d203617c8 --- /dev/null +++ b/puzzles files/binary/10x10 Binary Medium/10x10 Binary Medium 1 @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/10x10 Binary Medium/10x10 Binary Medium 2 b/puzzles files/binary/10x10 Binary Medium/10x10 Binary Medium 2 new file mode 100644 index 000000000..db56f04f3 --- /dev/null +++ b/puzzles files/binary/10x10 Binary Medium/10x10 Binary Medium 2 @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/10x10 Binary Medium/10x10 Binary Medium 3 b/puzzles files/binary/10x10 Binary Medium/10x10 Binary Medium 3 new file mode 100644 index 000000000..11940a6eb --- /dev/null +++ b/puzzles files/binary/10x10 Binary Medium/10x10 Binary Medium 3 @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/10x10 Binary Very Hard/10x10 Binary Very Hard 1 b/puzzles files/binary/10x10 Binary Very Hard/10x10 Binary Very Hard 1 new file mode 100644 index 000000000..828a450cf --- /dev/null +++ b/puzzles files/binary/10x10 Binary Very Hard/10x10 Binary Very Hard 1 @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/6x6 Binary Easy/6x6 Binary Easy 1 b/puzzles files/binary/6x6 Binary Easy/6x6 Binary Easy 1 new file mode 100644 index 000000000..7b22ffc10 --- /dev/null +++ b/puzzles files/binary/6x6 Binary Easy/6x6 Binary Easy 1 @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/puzzles files/binary/6x6 Binary Easy/6x6 Binary Easy 2 b/puzzles files/binary/6x6 Binary Easy/6x6 Binary Easy 2 new file mode 100644 index 000000000..ea8ef93b0 --- /dev/null +++ b/puzzles files/binary/6x6 Binary Easy/6x6 Binary Easy 2 @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/puzzles files/binary/6x6 Binary Easy/6x6 Binary Easy 3 b/puzzles files/binary/6x6 Binary Easy/6x6 Binary Easy 3 new file mode 100644 index 000000000..0f0ff745e --- /dev/null +++ b/puzzles files/binary/6x6 Binary Easy/6x6 Binary Easy 3 @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/puzzles files/binary/6x6 Binary Easy/6x6 Binary Easy 4 b/puzzles files/binary/6x6 Binary Easy/6x6 Binary Easy 4 new file mode 100644 index 000000000..da76d067b --- /dev/null +++ b/puzzles files/binary/6x6 Binary Easy/6x6 Binary Easy 4 @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/puzzles files/binary/6x6 Binary Easy/6x6 Binary Easy 5 b/puzzles files/binary/6x6 Binary Easy/6x6 Binary Easy 5 new file mode 100644 index 000000000..a1ea13988 --- /dev/null +++ b/puzzles files/binary/6x6 Binary Easy/6x6 Binary Easy 5 @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/6x6 Binary Hard/6x6 Binary Hard 1 b/puzzles files/binary/6x6 Binary Hard/6x6 Binary Hard 1 new file mode 100644 index 000000000..5f7f72a8a --- /dev/null +++ b/puzzles files/binary/6x6 Binary Hard/6x6 Binary Hard 1 @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/6x6 Binary Hard/6x6 Binary Hard 2 b/puzzles files/binary/6x6 Binary Hard/6x6 Binary Hard 2 new file mode 100644 index 000000000..a4ed30c31 --- /dev/null +++ b/puzzles files/binary/6x6 Binary Hard/6x6 Binary Hard 2 @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/6x6 Binary Hard/6x6 Binary Hard 3 b/puzzles files/binary/6x6 Binary Hard/6x6 Binary Hard 3 new file mode 100644 index 000000000..fc0e413c1 --- /dev/null +++ b/puzzles files/binary/6x6 Binary Hard/6x6 Binary Hard 3 @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/6x6 Binary Medium/6x6 Binary Medium 1 b/puzzles files/binary/6x6 Binary Medium/6x6 Binary Medium 1 new file mode 100644 index 000000000..a5ab8a2dc --- /dev/null +++ b/puzzles files/binary/6x6 Binary Medium/6x6 Binary Medium 1 @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/6x6 Binary Medium/6x6 Binary Medium 2 b/puzzles files/binary/6x6 Binary Medium/6x6 Binary Medium 2 new file mode 100644 index 000000000..4be5fdaad --- /dev/null +++ b/puzzles files/binary/6x6 Binary Medium/6x6 Binary Medium 2 @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/6x6 Binary Medium/6x6 Binary Medium 3 b/puzzles files/binary/6x6 Binary Medium/6x6 Binary Medium 3 new file mode 100644 index 000000000..eba370cab --- /dev/null +++ b/puzzles files/binary/6x6 Binary Medium/6x6 Binary Medium 3 @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/6x6 Binary Very Hard/6x6 Binary Very Hard 1 b/puzzles files/binary/6x6 Binary Very Hard/6x6 Binary Very Hard 1 new file mode 100644 index 000000000..faa68fa5e --- /dev/null +++ b/puzzles files/binary/6x6 Binary Very Hard/6x6 Binary Very Hard 1 @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/6x6 Binary Very Hard/6x6 Binary Very Hard 2 b/puzzles files/binary/6x6 Binary Very Hard/6x6 Binary Very Hard 2 new file mode 100644 index 000000000..3c707bdaa --- /dev/null +++ b/puzzles files/binary/6x6 Binary Very Hard/6x6 Binary Very Hard 2 @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/6x6 Binary Very Hard/6x6 Binary Very Hard 3 b/puzzles files/binary/6x6 Binary Very Hard/6x6 Binary Very Hard 3 new file mode 100644 index 000000000..217a032d8 --- /dev/null +++ b/puzzles files/binary/6x6 Binary Very Hard/6x6 Binary Very Hard 3 @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/8x8 Binary Easy/8x8 Binary Easy 1 b/puzzles files/binary/8x8 Binary Easy/8x8 Binary Easy 1 new file mode 100644 index 000000000..befd674f9 --- /dev/null +++ b/puzzles files/binary/8x8 Binary Easy/8x8 Binary Easy 1 @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/8x8 Binary Easy/8x8 Binary Easy 2 b/puzzles files/binary/8x8 Binary Easy/8x8 Binary Easy 2 new file mode 100644 index 000000000..724426c26 --- /dev/null +++ b/puzzles files/binary/8x8 Binary Easy/8x8 Binary Easy 2 @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/8x8 Binary Easy/8x8 Binary Easy 3 b/puzzles files/binary/8x8 Binary Easy/8x8 Binary Easy 3 new file mode 100644 index 000000000..92a96c72b --- /dev/null +++ b/puzzles files/binary/8x8 Binary Easy/8x8 Binary Easy 3 @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/8x8 Binary Hard/8x8 Binary Hard 1 b/puzzles files/binary/8x8 Binary Hard/8x8 Binary Hard 1 new file mode 100644 index 000000000..34eaf8388 --- /dev/null +++ b/puzzles files/binary/8x8 Binary Hard/8x8 Binary Hard 1 @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/8x8 Binary Hard/8x8 Binary Hard 2 b/puzzles files/binary/8x8 Binary Hard/8x8 Binary Hard 2 new file mode 100644 index 000000000..9ef23277e --- /dev/null +++ b/puzzles files/binary/8x8 Binary Hard/8x8 Binary Hard 2 @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/8x8 Binary Hard/8x8 Binary Hard 3 b/puzzles files/binary/8x8 Binary Hard/8x8 Binary Hard 3 new file mode 100644 index 000000000..287ff6f68 --- /dev/null +++ b/puzzles files/binary/8x8 Binary Hard/8x8 Binary Hard 3 @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/8x8 Binary Medium/8x8 Binary Medium 1 b/puzzles files/binary/8x8 Binary Medium/8x8 Binary Medium 1 new file mode 100644 index 000000000..47dae23dc --- /dev/null +++ b/puzzles files/binary/8x8 Binary Medium/8x8 Binary Medium 1 @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/8x8 Binary Medium/8x8 Binary Medium 2 b/puzzles files/binary/8x8 Binary Medium/8x8 Binary Medium 2 new file mode 100644 index 000000000..ae4cb8bb0 --- /dev/null +++ b/puzzles files/binary/8x8 Binary Medium/8x8 Binary Medium 2 @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/8x8 Binary Medium/8x8 Binary Medium 3 b/puzzles files/binary/8x8 Binary Medium/8x8 Binary Medium 3 new file mode 100644 index 000000000..2f951ecc4 --- /dev/null +++ b/puzzles files/binary/8x8 Binary Medium/8x8 Binary Medium 3 @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/8x8 Binary Very Hard/8x8 Binary Very Hard 1 b/puzzles files/binary/8x8 Binary Very Hard/8x8 Binary Very Hard 1 new file mode 100644 index 000000000..9c875523b --- /dev/null +++ b/puzzles files/binary/8x8 Binary Very Hard/8x8 Binary Very Hard 1 @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/8x8 Binary Very Hard/8x8 Binary Very Hard 2 b/puzzles files/binary/8x8 Binary Very Hard/8x8 Binary Very Hard 2 new file mode 100644 index 000000000..14f2e4ad2 --- /dev/null +++ b/puzzles files/binary/8x8 Binary Very Hard/8x8 Binary Very Hard 2 @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/8x8 Binary Very Hard/8x8 Binary Very Hard 3 b/puzzles files/binary/8x8 Binary Very Hard/8x8 Binary Very Hard 3 new file mode 100644 index 000000000..ad319a4b7 --- /dev/null +++ b/puzzles files/binary/8x8 Binary Very Hard/8x8 Binary Very Hard 3 @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/light-color-theme.txt b/puzzles files/light-color-theme.txt new file mode 100644 index 000000000..5c45bc71b --- /dev/null +++ b/puzzles files/light-color-theme.txt @@ -0,0 +1,99 @@ +correct: BLUE +incorrect: RED +error: RED_700 +info: GRAY_900 +ui-movement: GRAY_300 +password-field-background: LIGHT_BLUE_400 +password-field-unfocused-background: GRAY_200 +progress-bar-background: GRAY_200 +progress-bar-foreground: LIGHT_BLUE_400 +text-field-background: LIGHT_BLUE_400 +text-field-unfocused-background: GRAY_200 +light-line-border: GRAY_200 +thick-line-border: GRAY_200 +data-selection-background: GRAY +element-view: BLACK +button-highlight: GRAY_300 +button-background: GRAY_200 +button-foreground: BLACK +checkbox-background: WHITE +checkbox-foreground: BLACK +combobox-background: WHITE +combobox-foreground: BLACK +combobox-button-background: GRAY_300 +combobox-selection-background: WHITE +combobox-selection-foreground: BLACK +combobox-selected-in-drop-down-background: GRAY_200 +label-background: WHITE +label-foreground: BLACK +menu-background: LIGHT_BLUE_100 +menu-foreground: BLACK +menu-selection-background: GRAY_200 +menu-selection-foreground: BLACK +menu-disabled-foreground: #000 +menu-bar-background: WHITE +menu-bar-foreground: BLACK +menu-item-disabled-foreground: #000 +menu-item-selection-background: GRAY_200 +menu-item-selection-foreground: BLACK +menu-item-background: WHITE +menu-item-foreground: BLACK +option-pane-background: WHITE +panel-background-color: WHITE +popup-menu-background: WHITE +popup-menu-foreground: BLACK +radio-button-background: WHITE +radio-button-foreground: BLACK +spinner-background: WHITE +spinner-foreground: BLACK +spinner-arrow-button-background: GRAY_200 +scroll-bar-track: GRAY_200 +scroll-bar-thumb: GRAY_300 +scroll-bar-thumb-dark-shadow: GRAY_300 +scroll-bar-thumb-highlight: GRAY_300 +scroll-bar-thumb-shadow: GRAY_300 +scroll-bar-arrow-button-background: GRAY_300 +scroll-pane-background: WHITE +slider-background: WHITE +slider-foreground: GRAY_700 +slider-track-color: BLACK +split-pane-background: WHITE +tabbed-pane-background: WHITE +tabbed-pane-foreground: BLACK +tabbed-pane-highlight: GRAY_200 +tabbed-pane-border-highlight: GRAY_300 +table-selection-background: GRAY_100 +table-selection-foreground: BLACK +table-background: WHITE +table-grid-color: GRAY_200 +table-header-background: GRAY_200 +text-area-background: GRAY_200 +text-area-foreground: BLACK +toggle-button-background: WHITE +toggle-button-foreground: BLACK +tool-bar-background: WHITE +tool-bar-foreground: BLACK +tool-bar-docking-background: LIGHT_GREEN_A100 +tool-bar-floating-background: GRAY_200 +tree-selection-foreground: BLACK +tree-foreground: BLACK +tree-selection-background: GRAY_200 +tree-background: WHITE +radio-button-menu-item-foreground: BLACK +radio-button-menu-item-selection-foreground: BLACK +radio-button-menu-item-selection-background: GRAY_200 +checkbox-menu-item-selection-background: GRAY_200 +checkbox-menu-item-foreground: BLACK +checkbox-menu-item-selection-foreground: BLACK +text-pane-background: GRAY_50 +text-pane-selection-background: LIGHT_BLUE_200 +text-pane-inactive-foreground: GRAY_500 +editor-pane-background: GRAY_50 +editor-pane-selection-background: LIGHT_BLUE_200 +editor-pane-inactive-foreground: GRAY_500 +separator-background: GRAY_300 +separator-foreground: GRAY_300 +tool-tip-background: GRAY_500 +tool-tip-foreground: GRAY_50 +color-chooser-background: WHITE +color-chooser-foreground: BLACK diff --git a/puzzles files/starbattle/5x5 Star Battle 1 star Normal/5x5 Star Battle 1 star Normal 1.xml b/puzzles files/starbattle/5x5 Star Battle 1 star Normal/5x5 Star Battle 1 star Normal 1.xml deleted file mode 100644 index b86e16ff2..000000000 --- a/puzzles files/starbattle/5x5 Star Battle 1 star Normal/5x5 Star Battle 1 star Normal 1.xml +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/puzzles files/starbattle/6x6 Star Battle 1 star Normal/6x6 Star Battle 1star Normal1.xml b/puzzles files/starbattle/6x6 Star Battle 1 star Normal/6x6 Star Battle 1star Normal1.xml deleted file mode 100644 index 110dd9abe..000000000 --- a/puzzles files/starbattle/6x6 Star Battle 1 star Normal/6x6 Star Battle 1star Normal1.xml +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/puzzles files/starbattle/6x6 Star Battle 1 star Normal/6x6 Star Battle 1star Normal2.xml b/puzzles files/starbattle/6x6 Star Battle 1 star Normal/6x6 Star Battle 1star Normal2.xml deleted file mode 100644 index 49efeba59..000000000 --- a/puzzles files/starbattle/6x6 Star Battle 1 star Normal/6x6 Star Battle 1star Normal2.xml +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/puzzles files/starbattle/6x6 Star Battle 1 star Normal/6x6 StarBattle 1star Normal3.xml b/puzzles files/starbattle/6x6 Star Battle 1 star Normal/6x6 StarBattle 1star Normal3.xml deleted file mode 100644 index 855943612..000000000 --- a/puzzles files/starbattle/6x6 Star Battle 1 star Normal/6x6 StarBattle 1star Normal3.xml +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/puzzles files/starbattle/7x7 Star Battle 1 star Hard/7x7 Star Battle 1star Hard1.xml b/puzzles files/starbattle/7x7 Star Battle 1 star Hard/7x7 Star Battle 1star Hard1.xml deleted file mode 100644 index c1d7770f6..000000000 --- a/puzzles files/starbattle/7x7 Star Battle 1 star Hard/7x7 Star Battle 1star Hard1.xml +++ /dev/null @@ -1,85 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/puzzles files/starbattle/7x7 Star Battle 1 star Normal/7x7 Star Battle 1star Normal.xml b/puzzles files/starbattle/7x7 Star Battle 1 star Normal/7x7 Star Battle 1star Normal.xml deleted file mode 100644 index cab0a0a5e..000000000 --- a/puzzles files/starbattle/7x7 Star Battle 1 star Normal/7x7 Star Battle 1star Normal.xml +++ /dev/null @@ -1,85 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/puzzles files/starbattle/7x7 Star Battle 1 star Normal/7x7 Star Battle 1star Normal1.xml b/puzzles files/starbattle/7x7 Star Battle 1 star Normal/7x7 Star Battle 1star Normal1.xml deleted file mode 100644 index 70b81e376..000000000 --- a/puzzles files/starbattle/7x7 Star Battle 1 star Normal/7x7 Star Battle 1star Normal1.xml +++ /dev/null @@ -1,85 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/puzzles files/starbattle/7x7 Star Battle 1 star Normal/7x7 Star Battle 1star Normal2.xml b/puzzles files/starbattle/7x7 Star Battle 1 star Normal/7x7 Star Battle 1star Normal2.xml deleted file mode 100644 index c541ece06..000000000 --- a/puzzles files/starbattle/7x7 Star Battle 1 star Normal/7x7 Star Battle 1star Normal2.xml +++ /dev/null @@ -1,85 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/puzzles files/starbattle/8x8 Star Battle 1 star Normal/8x8 Star Battle 1star Normal1.xml b/puzzles files/starbattle/8x8 Star Battle 1 star Normal/8x8 Star Battle 1star Normal1.xml deleted file mode 100644 index 02dd5d6c0..000000000 --- a/puzzles files/starbattle/8x8 Star Battle 1 star Normal/8x8 Star Battle 1star Normal1.xml +++ /dev/null @@ -1,105 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/puzzles files/starbattle/8x8 Star Battle 1 star Normal/8x8 Star Battle 1star Normal2.xml b/puzzles files/starbattle/8x8 Star Battle 1 star Normal/8x8 Star Battle 1star Normal2.xml deleted file mode 100644 index 0df84ef62..000000000 --- a/puzzles files/starbattle/8x8 Star Battle 1 star Normal/8x8 Star Battle 1star Normal2.xml +++ /dev/null @@ -1,104 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/puzzles files/starbattle/8x8 Star Battle 1 star Normal/8x8 Star Battle 1star Normal3.xml b/puzzles files/starbattle/8x8 Star Battle 1 star Normal/8x8 Star Battle 1star Normal3.xml deleted file mode 100644 index 725c91d7f..000000000 --- a/puzzles files/starbattle/8x8 Star Battle 1 star Normal/8x8 Star Battle 1star Normal3.xml +++ /dev/null @@ -1,104 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/app/Config.java b/src/main/java/edu/rpi/legup/app/Config.java index 3d212a597..b04ef9b88 100644 --- a/src/main/java/edu/rpi/legup/app/Config.java +++ b/src/main/java/edu/rpi/legup/app/Config.java @@ -96,6 +96,11 @@ public static String convertDisplayNameToClassName(String displayName) { return className; } + /** + * Gets a list of all available puzzle display names + * + * @return a List of puzzle display names as Strings + */ public List getPuzzleNames() { List names = new LinkedList(); for (String puzzle : this.getPuzzleClassNames()) { diff --git a/src/main/java/edu/rpi/legup/app/GameBoardFacade.java b/src/main/java/edu/rpi/legup/app/GameBoardFacade.java index 12f6b73d0..c6f92e5b5 100644 --- a/src/main/java/edu/rpi/legup/app/GameBoardFacade.java +++ b/src/main/java/edu/rpi/legup/app/GameBoardFacade.java @@ -89,6 +89,11 @@ public void initializeUI() { }); } + /** + * Sets the current puzzle in the game board + * + * @param puzzle the Puzzle to set + */ public void setPuzzle(Puzzle puzzle) { this.puzzle = puzzle; this.puzzleSolver.setPuzzleView(puzzle); @@ -113,11 +118,21 @@ public static void setupConfig() { GameBoardFacade.getInstance().setConfig(config); } + /** + * Sets the current puzzle editor with the given puzzle + * + * @param puzzle the Puzzle to set in the editor + */ public void setPuzzleEditor(Puzzle puzzle) { this.puzzle = puzzle; this.puzzleEditor.setPuzzleView(puzzle); } + /** + * Sets the configuration object for the GameBoardFacade + * + * @param config config the Config object to set + */ public void setConfig(Config config) { this.config = config; } @@ -176,7 +191,7 @@ public boolean validateTextInput(String game, String[] statements) throws Runtim } /** - * Loads an empty puzzle + * Loads an empty puzzle with the specified dimensions * * @param game name of the puzzle * @param rows the number of rows on the board @@ -187,10 +202,10 @@ public void loadPuzzle(String game, int rows, int columns) throws RuntimeExcepti String qualifiedClassName = config.getPuzzleClassForName(game); LOGGER.debug("Loading " + qualifiedClassName); - try { - Class c = Class.forName(qualifiedClassName); - Constructor cons = c.getConstructor(); - Puzzle puzzle = (Puzzle) cons.newInstance(); + try { + Class c = Class.forName(qualifiedClassName); + Constructor cons = c.getConstructor(); + Puzzle puzzle = (Puzzle) cons.newInstance(); PuzzleImporter importer = puzzle.getImporter(); if (importer == null) { @@ -225,6 +240,12 @@ public void loadPuzzle(String game, int rows, int columns) throws RuntimeExcepti } } + /** + * Loads an empty puzzle with the specified input + * + * @param game name of the puzzle + * @param statements an array of statements to load the puzzle with + */ public void loadPuzzle(String game, String[] statements) { String qualifiedClassName = config.getPuzzleClassForName(game); LOGGER.debug("Loading " + qualifiedClassName); @@ -267,7 +288,7 @@ public void loadPuzzle(String game, String[] statements) { } /** - * Loads a puzzle file + * Loads a puzzle file from the specified file * * @param fileName file name of the board file * @throws InvalidFileFormatException if the file format is invalid or if the file cannot be diff --git a/src/main/java/edu/rpi/legup/app/InvalidConfigException.java b/src/main/java/edu/rpi/legup/app/InvalidConfigException.java index 2526b3776..cad80b5ce 100644 --- a/src/main/java/edu/rpi/legup/app/InvalidConfigException.java +++ b/src/main/java/edu/rpi/legup/app/InvalidConfigException.java @@ -5,6 +5,11 @@ * errors */ public class InvalidConfigException extends Exception { + /** + * Constructs a new InvalidConfigException with the specified detail message + * + * @param message the detail message + */ public InvalidConfigException(String message) { super(message); } diff --git a/src/main/java/edu/rpi/legup/app/LegupPreferences.java b/src/main/java/edu/rpi/legup/app/LegupPreferences.java index 0bca27b49..3d17233bd 100644 --- a/src/main/java/edu/rpi/legup/app/LegupPreferences.java +++ b/src/main/java/edu/rpi/legup/app/LegupPreferences.java @@ -81,7 +81,7 @@ public class LegupPreferences { * Gets the legup preferences singleton instance This method ensures that only one instance of * LegupPreferences exists * - * @return legup preferences + * @return the singleton instance of LegupPreferences */ public static LegupPreferences getInstance() { if (instance == null) { @@ -100,23 +100,30 @@ private LegupPreferences() {} * Gets the user preference by the string key * * @param key key name of the preference - * @return value of the preference + * @return value of the preference or {@code null} if the preference does not exist */ public String getUserPref(String key) { return preferencesMap.get(key); } /** - * Gets the user preference by the string key, value pair + * Sets the user preference for the specified key to the provided value * - * @param key key name of the preference - * @param value value of the preference + * @param key key to set for the preference + * @param value value to set for the preference */ public void setUserPref(String key, String value) { preferences.put(key, value); preferencesMap.put(key, value); } + /** + * Retrieves the user preference associated with the specified key as a boolean + * + * @param key the key for the preference to retrieve + * @return the boolean value of the preference + * @throws RuntimeException if the preference value cannot be interpreted as a boolean + */ public boolean getUserPrefAsBool(String key) { if (preferencesMap.get(key).equalsIgnoreCase(Boolean.toString(true))) { return true; @@ -129,10 +136,20 @@ public boolean getUserPrefAsBool(String key) { } } + /** + * Gets the saved path + * + * @return the saved path as a String + */ public String getSavedPath() { return SAVED_PATH; } + /** + * Sets the saved path to the specified value + * + * @param path the new saved path + */ public void setSavedPath(String path) { SAVED_PATH = path; } diff --git a/src/main/java/edu/rpi/legup/controller/Controller.java b/src/main/java/edu/rpi/legup/controller/Controller.java index 4910e24d9..823bac716 100644 --- a/src/main/java/edu/rpi/legup/controller/Controller.java +++ b/src/main/java/edu/rpi/legup/controller/Controller.java @@ -24,6 +24,11 @@ public Controller() { pan = false; } + /** + * Sets the ScrollView instance that this controller manages + * + * @param viewer The ScrollView instance to be set + */ public void setViewer(ScrollView viewer) { this.viewer = viewer; } diff --git a/src/main/java/edu/rpi/legup/controller/EditorElementController.java b/src/main/java/edu/rpi/legup/controller/EditorElementController.java index 9922ccaed..050f5bd65 100644 --- a/src/main/java/edu/rpi/legup/controller/EditorElementController.java +++ b/src/main/java/edu/rpi/legup/controller/EditorElementController.java @@ -25,19 +25,33 @@ public EditorElementController() { prevButton = null; } + /** + * Sets the ElementController instance for this controller + * + * @param elementController the ElementController instance to be set + */ public void setElementController(ElementController elementController) { this.elementController = elementController; } + /** + * Handles the event when a button associated with an Element is pressed + * + * @param element the Element associated with the button that was pressed + */ public void buttonPressed(Element element) { // TODO: implement what happens when element is pressed - System.out.printf("%s button pressed!\n", element.getElementName()); if (elementController != null) { elementController.setSelectedElement(element); } } + /** + * Handles action events triggered by buttons + * + * @param e the event to be processed + */ @Override public void actionPerformed(ActionEvent e) { lastSource = e.getSource(); diff --git a/src/main/java/edu/rpi/legup/controller/ElementController.java b/src/main/java/edu/rpi/legup/controller/ElementController.java index 5840650e1..436b078b9 100644 --- a/src/main/java/edu/rpi/legup/controller/ElementController.java +++ b/src/main/java/edu/rpi/legup/controller/ElementController.java @@ -26,13 +26,17 @@ import java.awt.*; import java.awt.event.*; +/** + * The ElementController class manages UI interactions related to elements in a {@link BoardView}. + * It handles mouse events, key events, and actions related to element selection and manipulation + */ public class ElementController implements MouseListener, MouseMotionListener, ActionListener, KeyListener { protected BoardView boardView; private Element selectedElement; /** - * ElementController Constructor controller to handles ui events associated interacting with a + * ElementController Constructor controller to handle ui events associated interacting with a * {@link BoardView} */ public ElementController() { @@ -86,6 +90,7 @@ public void mouseReleased(MouseEvent e) { if (boardView == null) { boardView = getInstance().getLegupUI().getEditorBoardView(); } + Board board = boardView.getBoard(); ElementView elementView = boardView.getElement(e.getPoint()); TreeViewSelection selection = null; @@ -137,17 +142,8 @@ public void mouseReleased(MouseEvent e) { if (this.boardView.getBoard() instanceof TreeTentBoard) { scaledPoint.setLocation(scaledPoint.getX() - 1, scaledPoint.getY() - 1); } - System.out.printf( - "selected Element is NOT null, attempting to change board at (%d, %d)\n", - scaledPoint.x, scaledPoint.y); - // System.out.println("Before: " + b.getCell(scaledPoint.x, - // scaledPoint.y).getData()); + b.setCell(scaledPoint.x, scaledPoint.y, this.selectedElement, e); - // System.out.println("After: " + b.getCell(scaledPoint.x, - // scaledPoint.y).getData()); - // } else { - // System.out.println("selected Element is null!"); - // } boardView.repaint(); } diff --git a/src/main/java/edu/rpi/legup/history/CommandError.java b/src/main/java/edu/rpi/legup/history/CommandError.java index f848485eb..78027f6ab 100644 --- a/src/main/java/edu/rpi/legup/history/CommandError.java +++ b/src/main/java/edu/rpi/legup/history/CommandError.java @@ -25,10 +25,20 @@ public enum CommandError { private String value; + /** + * Constructs a CommandError with the specified error message + * + * @param value The error message associated with the command error + */ CommandError(String value) { this.value = value; } + /** + * Returns the error message associated with this CommandError + * + * @return The error message + */ @Override public String toString() { return value; diff --git a/src/main/java/edu/rpi/legup/history/CommandState.java b/src/main/java/edu/rpi/legup/history/CommandState.java index 90e44b70c..b72f15480 100644 --- a/src/main/java/edu/rpi/legup/history/CommandState.java +++ b/src/main/java/edu/rpi/legup/history/CommandState.java @@ -12,10 +12,20 @@ public enum CommandState { private String value; + /** + * Constructs a CommandState with the specified state name + * + * @param value The name associated with the command state + */ CommandState(String value) { this.value = value; } + /** + * Returns the name associated with this CommandState + * + * @return The state name + */ @Override public String toString() { return value; diff --git a/src/main/java/edu/rpi/legup/history/DeleteTreeElementCommand.java b/src/main/java/edu/rpi/legup/history/DeleteTreeElementCommand.java index f56437400..bfd9cd7f5 100644 --- a/src/main/java/edu/rpi/legup/history/DeleteTreeElementCommand.java +++ b/src/main/java/edu/rpi/legup/history/DeleteTreeElementCommand.java @@ -32,6 +32,9 @@ public void executeCommand() { Puzzle puzzle = GameBoardFacade.getInstance().getPuzzleModule(); List selectedViews = selection.getSelectedViews(); + if (selectedViews.isEmpty()) { + return; + } TreeElementView firstSelectedView = selectedViews.get(0); TreeElementView newSelectedView; @@ -48,6 +51,7 @@ public void executeCommand() { } for (TreeElementView selectedView : selectedViews) { + System.out.println("DELETED"); TreeElement element = selectedView.getTreeElement(); tree.removeTreeElement(element); puzzle.notifyTreeListeners(listener -> listener.onTreeElementRemoved(element)); diff --git a/src/main/java/edu/rpi/legup/history/EditDataCommand.java b/src/main/java/edu/rpi/legup/history/EditDataCommand.java index a06a26854..0d51cc717 100644 --- a/src/main/java/edu/rpi/legup/history/EditDataCommand.java +++ b/src/main/java/edu/rpi/legup/history/EditDataCommand.java @@ -9,6 +9,7 @@ import edu.rpi.legup.model.tree.*; import edu.rpi.legup.ui.boardview.BoardView; import edu.rpi.legup.ui.boardview.ElementView; +import edu.rpi.legup.ui.lookandfeel.materialdesign.MaterialColors; import edu.rpi.legup.ui.proofeditorui.treeview.*; import java.awt.*; import java.awt.event.MouseEvent; @@ -33,7 +34,7 @@ public class EditDataCommand extends PuzzleCommand { * EditDataCommand Constructor create a puzzle command for editing a board * * @param elementView currently selected puzzle puzzleElement view that is being edited - * @param selection currently selected tree puzzleElement views that is being edited + * @param selection currently selected tree puzzleElement views that are being edited * @param event mouse event */ public EditDataCommand(ElementView elementView, TreeViewSelection selection, MouseEvent event) { @@ -61,16 +62,13 @@ public void executeCommand() { if (treeElement.getType() == TreeElementType.NODE) { TreeNode treeNode = (TreeNode) treeElement; - if (treeNode.getChildren().isEmpty()) { if (transition == null) { transition = tree.addNewTransition(treeNode); } puzzle.notifyTreeListeners(listener -> listener.onTreeElementAdded(transition)); } - board = transition.getBoard(); - puzzleElement = board.getPuzzleElement(selectedPuzzleElement); savePuzzleElement = puzzleElement.copy(); } else { @@ -80,7 +78,6 @@ public void executeCommand() { } Board prevBoard = transition.getParents().get(0).getBoard(); - boardView.getElementController().changeCell(event, puzzleElement); if (prevBoard.getPuzzleElement(selectedPuzzleElement).equalsData(puzzleElement)) { @@ -109,28 +106,33 @@ public void executeCommand() { public String getErrorString() { List selectedViews = selection.getSelectedViews(); if (selectedViews.size() != 1) { + flashTreeViewRed(); return CommandError.ONE_SELECTED_VIEW.toString(); } TreeElementView selectedView = selection.getFirstSelection(); Board board = selectedView.getTreeElement().getBoard(); PuzzleElement selectedPuzzleElement = elementView.getPuzzleElement(); if (selectedView.getType() == TreeElementType.NODE) { - TreeNodeView nodeView = (TreeNodeView) selectedView; if (!nodeView.getChildrenViews().isEmpty()) { + flashTreeViewRed(); return CommandError.UNMODIFIABLE_BOARD.toString(); - } else { - if (!board.getPuzzleElement(selectedPuzzleElement).isModifiable()) { - return CommandError.UNMODIFIABLE_DATA.toString(); - } + } else if (!board.getPuzzleElement(selectedPuzzleElement).isModifiable()) { + flashTreeViewRed(); + return CommandError.UNMODIFIABLE_DATA.toString(); } } else { TreeTransitionView transitionView = (TreeTransitionView) selectedView; if (!transitionView.getTreeElement().getBoard().isModifiable()) { + flashTreeViewRed(); return CommandError.UNMODIFIABLE_BOARD.toString(); } else { if (!board.getPuzzleElement(selectedPuzzleElement).isModifiable()) { + flashTreeViewRed(); return CommandError.UNMODIFIABLE_DATA.toString(); + } else if (!board.getPuzzleElement(selectedPuzzleElement).isModifiableCaseRule()) { + flashTreeViewRed(); + return CommandError.UNMODIFIABLE_DATA_CASE_RULE.toString(); } } } diff --git a/src/main/java/edu/rpi/legup/history/History.java b/src/main/java/edu/rpi/legup/history/History.java index 091d381ac..9eaeb3e75 100644 --- a/src/main/java/edu/rpi/legup/history/History.java +++ b/src/main/java/edu/rpi/legup/history/History.java @@ -48,7 +48,10 @@ public void pushChange(ICommand command) { } } - /** Undoes an action */ + /** + * Undoes the last action by calling the undo method of the command at the current index. + * Updates the current index and notifies listeners. + */ public void undo() { synchronized (lock) { if (curIndex > -1) { @@ -63,7 +66,10 @@ public void undo() { } } - /** Redoes an action */ + /** + * Redoes the next action by calling the redo method of the command at the current index. + * Updates the current index and notifies listeners. + */ public void redo() { synchronized (lock) { if (curIndex < history.size() - 1) { diff --git a/src/main/java/edu/rpi/legup/history/IHistoryListener.java b/src/main/java/edu/rpi/legup/history/IHistoryListener.java index 344d8ede7..a752cd53a 100644 --- a/src/main/java/edu/rpi/legup/history/IHistoryListener.java +++ b/src/main/java/edu/rpi/legup/history/IHistoryListener.java @@ -6,15 +6,16 @@ * as pushing, undoing, redoing commands, and clearing the history. */ public interface IHistoryListener { + /** - * Called when a action is pushed onto the edu.rpi.legup.history stack + * Called when a command is pushed onto the history stack. * - * @param command action to push onto the stack + * @param command the command that was pushed onto the stack */ void onPushChange(ICommand command); /** - * Called when an action is undone + * Called when a command is undone. * * @param isBottom true if there are no more actions to undo, false otherwise * @param isTop true if there are no more changes to redo, false otherwise @@ -22,7 +23,7 @@ public interface IHistoryListener { void onUndo(boolean isBottom, boolean isTop); /** - * Called when an action is redone + * Called when a command is redone. * * @param isBottom true if there are no more actions to undo, false otherwise * @param isTop true if there are no more changes to redo, false otherwise diff --git a/src/main/java/edu/rpi/legup/history/IHistorySubject.java b/src/main/java/edu/rpi/legup/history/IHistorySubject.java index 5c10e9b25..b526c7cf3 100644 --- a/src/main/java/edu/rpi/legup/history/IHistorySubject.java +++ b/src/main/java/edu/rpi/legup/history/IHistorySubject.java @@ -8,10 +8,11 @@ * listeners. */ public interface IHistorySubject { + /** - * Adds a history listener + * Adds a history listener to receive updates about changes in the command history. * - * @param listener listener to add + * @param listener the listener to add */ void addHistoryListener(IHistoryListener listener); @@ -19,12 +20,12 @@ public interface IHistorySubject { * Removes a history listener, so it no longer receives updates about changes in the command * history. * - * @param listener listener to remove + * @param listener the listener to remove */ void removeHistoryListener(IHistoryListener listener); /** - * Notifies listeners + * Notifies all registered listeners about a change in the command history. * * @param algorithm a Consumer function that takes an IHistoryListener and performs some action * with it diff --git a/src/main/java/edu/rpi/legup/history/InvalidCommandStateTransition.java b/src/main/java/edu/rpi/legup/history/InvalidCommandStateTransition.java index 692c572d7..0e1ba1b0d 100644 --- a/src/main/java/edu/rpi/legup/history/InvalidCommandStateTransition.java +++ b/src/main/java/edu/rpi/legup/history/InvalidCommandStateTransition.java @@ -6,6 +6,13 @@ */ public class InvalidCommandStateTransition extends RuntimeException { + /** + * Constructs a new InvalidCommandStateTransition exception with a detailed message + * + * @param puzzleCommand the PuzzleCommand involved in the invalid transition + * @param from the state from which the transition was attempted + * @param to the state to which the transition was attempted + */ public InvalidCommandStateTransition( PuzzleCommand puzzleCommand, CommandState from, CommandState to) { super( diff --git a/src/main/java/edu/rpi/legup/history/ValidateDirectRuleCommand.java b/src/main/java/edu/rpi/legup/history/ValidateDirectRuleCommand.java index b0daee986..49bf378ee 100644 --- a/src/main/java/edu/rpi/legup/history/ValidateDirectRuleCommand.java +++ b/src/main/java/edu/rpi/legup/history/ValidateDirectRuleCommand.java @@ -18,6 +18,7 @@ * ICommand interface. */ public class ValidateDirectRuleCommand extends PuzzleCommand { + private static final Logger LOGGER = LogManager.getLogger(History.class.getName()); private TreeViewSelection selection; private Map oldRules; @@ -49,14 +50,15 @@ public void executeCommand() { for (TreeElementView selectedView : selectedViews) { TreeElement element = selectedView.getTreeElement(); TreeTransitionView transitionView; + if (element.getType() == TreeElementType.NODE) { TreeNodeView nodeView = (TreeNodeView) selectedView; transitionView = nodeView.getChildrenViews().get(0); } else { transitionView = (TreeTransitionView) selectedView; } - TreeTransition transition = transitionView.getTreeElement(); + TreeTransition transition = transitionView.getTreeElement(); oldRules.put(transition, transition.getRule()); transition.setRule(newRule); @@ -73,17 +75,41 @@ public void executeCommand() { final TreeNode finalNode = childNode; puzzle.notifyTreeListeners(listener -> listener.onTreeElementAdded(finalNode)); } - newSelection.addToSelection(treeView.getElementView(childNode)); + + TreeElementView childView = treeView.getElementView(childNode); + if (childView == null) { + LOGGER.error("Child view is null for child node: " + childNode); + continue; + } + newSelection.addToSelection(childView); } + TreeElementView firstSelectedView = selection.getFirstSelection(); + final TreeElement finalTreeElement; if (firstSelectedView.getType() == TreeElementType.NODE) { TreeNodeView nodeView = (TreeNodeView) firstSelectedView; + if (nodeView.getChildrenViews().isEmpty()) { + LOGGER.error("NodeView has no children views"); + return; + } finalTreeElement = nodeView.getChildrenViews().get(0).getTreeElement(); } else { TreeTransitionView transitionView = (TreeTransitionView) firstSelectedView; + TreeNodeView childView = transitionView.getChildView(); + if (childView == null) { + LOGGER.error("Child view is null for transition view: " + transitionView); + TreeNode childNode = transitionView.getTreeElement().getChildNode(); + childView = (TreeNodeView) treeView.getElementView(childNode); + transitionView.setChildView(childView); + } + TreeTransition transition = transitionView.getTreeElement(); + if (transition.getParents().get(0).getChildren().isEmpty()) { + transition.getParents().get(0).addChild(transition); + } finalTreeElement = transitionView.getChildView().getTreeElement(); } + puzzle.notifyBoardListeners(listener -> listener.onTreeElementChanged(finalTreeElement)); puzzle.notifyTreeListeners(listener -> listener.onTreeSelectionChanged(newSelection)); } @@ -133,6 +159,7 @@ public void undoCommand() { transitionView = (TreeTransitionView) selectedView; } TreeTransition transition = transitionView.getTreeElement(); + transition.setRule(oldRules.get(transition)); if (addNode.get(transition) != null) { diff --git a/src/main/java/edu/rpi/legup/model/Puzzle.java b/src/main/java/edu/rpi/legup/model/Puzzle.java index 1e3d0b3fe..da8f76ddd 100644 --- a/src/main/java/edu/rpi/legup/model/Puzzle.java +++ b/src/main/java/edu/rpi/legup/model/Puzzle.java @@ -58,7 +58,6 @@ public abstract class Puzzle implements IBoardSubject, ITreeSubject { protected List contradictionRules; protected List caseRules; protected List placeableElements; - protected List nonPlaceableElements; /** Puzzle Constructor - creates a new Puzzle */ public Puzzle() { @@ -70,7 +69,6 @@ public Puzzle() { this.caseRules = new ArrayList<>(); this.placeableElements = new ArrayList<>(); - this.nonPlaceableElements = new ArrayList<>(); registerRules(); registerPuzzleElements(); @@ -109,9 +107,6 @@ private void registerPuzzleElements() { case PLACEABLE: this.addPlaceableElement((PlaceableElement) element); break; - case NONPLACEABLE: - this.addNonPlaceableElement((NonPlaceableElement) element); - break; default: break; } @@ -122,14 +117,6 @@ private void registerPuzzleElements() { } } } - - // } catch (IOException | ClassNotFoundException | NoSuchMethodException | - // InstantiationException | IllegalAccessException | - // InvocationTargetException - // e) { - // LOGGER.error("Unable to find rules for " + - // this.getClass().getSimpleName(), e); - // } } catch (Exception e) { LOGGER.error("Unable to find elements for " + this.getClass().getSimpleName(), e); } @@ -185,14 +172,6 @@ private void registerRules() { } } } - - // } catch (IOException | ClassNotFoundException | NoSuchMethodException | - // InstantiationException | IllegalAccessException | - // InvocationTargetException - // e) { - // LOGGER.error("Unable to find rules for " + - // this.getClass().getSimpleName(), e); - // } } catch (Exception e) { LOGGER.error("Unable to find rules for " + this.getClass().getSimpleName(), e); } @@ -221,10 +200,10 @@ public boolean isValidDimensions(int rows, int columns) { } /** - * Checks if the given array of statements is valid text input for the given puzzle + * Checks if the provided text input is valid for the puzzle. * - * @param statements - * @return + * @param statements array of statements to check + * @return true if input is valid, false otherwise */ public boolean isValidTextInput(String[] statements) { return statements.length > 0; @@ -356,14 +335,15 @@ public List getDirectRules() { return directRules; } + /** + * Gets the list of placeable elements. + * + * @return list of PlaceableElement instances + */ public List getPlaceableElements() { return placeableElements; } - public List getNonPlaceableElements() { - return nonPlaceableElements; - } - /** * Sets the list of direct rules * @@ -382,14 +362,15 @@ public void addDirectRule(DirectRule rule) { directRules.add(rule); } + /** + * Adds a placeable element to this puzzle. + * + * @param element PlaceableElement to add + */ public void addPlaceableElement(PlaceableElement element) { placeableElements.add(element); } - public void addNonPlaceableElement(NonPlaceableElement element) { - nonPlaceableElements.add(element); - } - /** * Remove a basic rule from this Puzzle * @@ -605,7 +586,7 @@ public void setFactory(ElementFactory factory) { * Adds a board listener to the list of listeners. This allows the puzzle to notify the listener * about changes to the board. * - * @param listener listener to add + * @param listener The IBoardListener to be added to the list of listeners. */ @Override public void addBoardListener(IBoardListener listener) { @@ -616,7 +597,7 @@ public void addBoardListener(IBoardListener listener) { * Removes a board listener from the list of listeners. This prevents the puzzle from notifying * the listener about future changes to the board. * - * @param listener listener to remove + * @param listener The IBoardListener to be removed from the list of listeners. */ @Override public void removeBoardListener(IBoardListener listener) { @@ -639,7 +620,7 @@ public void notifyBoardListeners(Consumer algorithm) { * Adds a tree listener to the list of listeners. This allows the puzzle to notify the listener * about changes to the tree. * - * @param listener listener to add + * @param listener The ITreeListener to be added to the list of listeners. */ @Override public void addTreeListener(ITreeListener listener) { @@ -650,7 +631,7 @@ public void addTreeListener(ITreeListener listener) { * Removes a tree listener from the list of listeners. This prevents the puzzle from notifying * the listener about future changes to the tree. * - * @param listener listener to remove + * @param listener The ITreeListener to be removed from the list of listeners. */ @Override public void removeTreeListener(ITreeListener listener) { @@ -673,7 +654,7 @@ public void notifyTreeListeners(Consumer algorithm) { * Checks if the puzzle is valid. The implementation of this method can vary based on the * specific criteria for puzzle validity. * - * @return if the puzzle is valid + * @return true if the puzzle is valid, false otherwise. */ public boolean checkValidity() { return true; diff --git a/src/main/java/edu/rpi/legup/model/PuzzleImporter.java b/src/main/java/edu/rpi/legup/model/PuzzleImporter.java index 848e3169a..9d16d94e9 100644 --- a/src/main/java/edu/rpi/legup/model/PuzzleImporter.java +++ b/src/main/java/edu/rpi/legup/model/PuzzleImporter.java @@ -69,10 +69,10 @@ public void initializePuzzle(String[] statements) } /** - * Initializes the puzzle attributes + * Initializes the puzzle attributes from the XML document node * - * @param node xml document node - * @throws InvalidFileFormatException if file is invalid + * @param node the XML document node representing the puzzle + * @throws InvalidFileFormatException if the file format is invalid */ public void initializePuzzle(Node node) throws InvalidFileFormatException { if (node.getNodeName().equalsIgnoreCase("puzzle")) { @@ -125,19 +125,19 @@ public void initializePuzzle(Node node) throws InvalidFileFormatException { } /** - * Creates the board for building + * Initializes the board with the specified number of rows and columns. * - * @param rows number of rows on the puzzle - * @param columns number of columns on the puzzle - * @throws RuntimeException if board can not be created + * @param rows the number of rows on the puzzle + * @param columns the number of columns on the puzzle + * @throws RuntimeException if the board cannot be created with the provided dimensions */ public abstract void initializeBoard(int rows, int columns); /** - * Creates an empty board for building + * Initializes the board from the XML document node. * - * @param node xml document node - * @throws InvalidFileFormatException if file is invalid + * @param node the XML document node representing the board + * @throws InvalidFileFormatException if the file format is invalid */ public abstract void initializeBoard(Node node) throws InvalidFileFormatException; @@ -454,7 +454,7 @@ protected void createDefaultTree() { } /** - * Gets the result of building the Puzzle + * Gets the result of building the Puzzle object. * * @return puzzle */ diff --git a/src/main/java/edu/rpi/legup/model/elements/Element.java b/src/main/java/edu/rpi/legup/model/elements/Element.java index 6f100c27d..ed47f6523 100644 --- a/src/main/java/edu/rpi/legup/model/elements/Element.java +++ b/src/main/java/edu/rpi/legup/model/elements/Element.java @@ -21,6 +21,14 @@ public abstract class Element { private final String INVALID_USE_MESSAGE; + /** + * Constructs an Element with the specified ID, name, description, and image name + * + * @param elementID Unique identifier for the element + * @param elementName Name of the element + * @param description Description of the element + * @param imageName File name of the image associated with the element + */ public Element(String elementID, String elementName, String description, String imageName) { this.elementID = elementID; this.elementName = elementName; @@ -55,30 +63,65 @@ private void loadImage() { } } + /** + * Gets the name of the element + * + * @return The name of the element + */ public String getElementName() { return elementName; } + /** + * Sets the name of the element + * + * @param elementName The new name for the element + */ public void setElementName(String elementName) { this.elementName = elementName; } + /** + * Gets the unique identifier of the element + * + * @return The ID of the element + */ public String getElementID() { return elementID; } + /** + * Gets the description of the element + * + * @return The description of the element + */ public String getDescription() { return description; } + /** + * Gets the image icon associated with the element + * + * @return The ImageIcon for the element + */ public ImageIcon getImageIcon() { return image; } + /** + * Gets the type of the element + * + * @return The ElementType of the element + */ public ElementType getElementType() { return elementType; } + /** + * Gets the message for invalid use of the rule + * + * @return The invalid use message + */ public String getInvalidUseOfRuleMessage() { return this.INVALID_USE_MESSAGE; } diff --git a/src/main/java/edu/rpi/legup/model/gameboard/Board.java b/src/main/java/edu/rpi/legup/model/gameboard/Board.java index f1fd27ad2..9e7d93441 100644 --- a/src/main/java/edu/rpi/legup/model/gameboard/Board.java +++ b/src/main/java/edu/rpi/legup/model/gameboard/Board.java @@ -35,21 +35,24 @@ public Board(int size) { } /** - * Gets a specific {@link PuzzleElement} on this board. + * Gets a specific {@link PuzzleElement} from the board. * - * @param puzzleElement equivalent puzzleElement - * @return equivalent puzzleElement on this board + * @param puzzleElement the puzzle element to retrieve + * @return the puzzle element at the corresponding index, or null if not found */ public PuzzleElement getPuzzleElement(PuzzleElement puzzleElement) { + if (puzzleElement == null) { + return null; + } int index = puzzleElement.getIndex(); return index < puzzleElements.size() ? puzzleElements.get(index) : null; } /** - * Sets a specific {@link PuzzleElement} on the board. + * Sets a specific {@link PuzzleElement} on the board * * @param index index of the puzzleElement - * @param puzzleElement new puzzleElement at the index + * @param puzzleElement the puzzleElement to set at the index */ public void setPuzzleElement(int index, PuzzleElement puzzleElement) { if (index < puzzleElements.size()) { @@ -58,7 +61,7 @@ public void setPuzzleElement(int index, PuzzleElement puzzleElement) { } /** - * Gets the number of elements on the board. + * Gets the number of elements on the board * * @return number of elements on the board */ diff --git a/src/main/java/edu/rpi/legup/model/gameboard/CaseBoard.java b/src/main/java/edu/rpi/legup/model/gameboard/CaseBoard.java index 55484a2fc..07cc2947d 100644 --- a/src/main/java/edu/rpi/legup/model/gameboard/CaseBoard.java +++ b/src/main/java/edu/rpi/legup/model/gameboard/CaseBoard.java @@ -14,40 +14,88 @@ public class CaseBoard extends Board { protected CaseRule caseRule; protected Set pickablePuzzleElements; + /** + * Constructs a CaseBoard with a base board and a case rule. + * + * @param baseBoard the base board to use for this CaseBoard + * @param caseRule the case rule applied to this CaseBoard + */ public CaseBoard(Board baseBoard, CaseRule caseRule) { this.baseBoard = baseBoard; this.caseRule = caseRule; this.pickablePuzzleElements = new HashSet<>(); } + /** + * Adds a puzzle element to the set of pickable elements. + * + * @param puzzleElement the puzzle element to add + */ public void addPickableElement(PuzzleElement puzzleElement) { pickablePuzzleElements.add(puzzleElement); } + /** + * Removes a puzzle element from the set of pickable elements. + * + * @param puzzleElement the puzzle element to remove + */ public void removePickableElement(PuzzleElement puzzleElement) { pickablePuzzleElements.remove(puzzleElement); } + /** + * Checks if a puzzle element is pickable based on the mouse event. + * + * @param puzzleElement the puzzle element to check + * @param e the mouse event + * @return true if the puzzle element is pickable, false otherwise + */ public boolean isPickable(PuzzleElement puzzleElement, MouseEvent e) { return pickablePuzzleElements.contains(baseBoard.getPuzzleElement(puzzleElement)); } + /** + * Retrieves the base board for this CaseBoard. + * + * @return the base board + */ public Board getBaseBoard() { return baseBoard; } + /** + * Sets the base board for this CaseBoard. + * + * @param baseBoard the new base board + */ public void setBaseBoard(Board baseBoard) { this.baseBoard = baseBoard; } + /** + * Retrieves the case rule for this CaseBoard. + * + * @return the case rule + */ public CaseRule getCaseRule() { return caseRule; } + /** + * Sets the case rule for this CaseBoard. + * + * @param caseRule the new case rule + */ public void setCaseRule(CaseRule caseRule) { this.caseRule = caseRule; } + /** + * Gets the count of pickable puzzle elements. + * + * @return the number of pickable elements + */ public int getCount() { return pickablePuzzleElements.size(); } diff --git a/src/main/java/edu/rpi/legup/model/gameboard/ElementFactory.java b/src/main/java/edu/rpi/legup/model/gameboard/ElementFactory.java index bfc785bdd..131feb122 100644 --- a/src/main/java/edu/rpi/legup/model/gameboard/ElementFactory.java +++ b/src/main/java/edu/rpi/legup/model/gameboard/ElementFactory.java @@ -5,6 +5,9 @@ import org.w3c.dom.Element; import org.w3c.dom.Node; +/** + * ElementFactory is an abstract class for importing and exporting {@link PuzzleElement} instances. + */ public abstract class ElementFactory { /** diff --git a/src/main/java/edu/rpi/legup/model/gameboard/GridBoard.java b/src/main/java/edu/rpi/legup/model/gameboard/GridBoard.java index 9593690ce..7338132f8 100644 --- a/src/main/java/edu/rpi/legup/model/gameboard/GridBoard.java +++ b/src/main/java/edu/rpi/legup/model/gameboard/GridBoard.java @@ -6,6 +6,11 @@ import java.awt.*; import java.awt.event.MouseEvent; +/** + * GridBoard represents a grid-based board where each cell can be manipulated based on its + * coordinates. The board supports operations such as getting and setting cells, and provides + * dimensions of the grid. It also supports deep copying of the board. + */ public class GridBoard extends Board { protected Dimension dimension; diff --git a/src/main/java/edu/rpi/legup/model/gameboard/GridRegion.java b/src/main/java/edu/rpi/legup/model/gameboard/GridRegion.java index a4e2343b2..79027d9d1 100644 --- a/src/main/java/edu/rpi/legup/model/gameboard/GridRegion.java +++ b/src/main/java/edu/rpi/legup/model/gameboard/GridRegion.java @@ -30,7 +30,7 @@ public void addCell(T cell) { /** * Removes the cell from the region * - * @param cell cell to be remove from the region + * @param cell cell to be removed from the region */ public void removeCell(T cell) { regionCells.remove(cell); @@ -53,9 +53,4 @@ public List getCells() { public int getSize() { return regionCells.size(); } - - /* - public void colorRegion(){} - */ - } diff --git a/src/main/java/edu/rpi/legup/model/gameboard/PuzzleElement.java b/src/main/java/edu/rpi/legup/model/gameboard/PuzzleElement.java index 7664c7aa0..eca6f3be4 100644 --- a/src/main/java/edu/rpi/legup/model/gameboard/PuzzleElement.java +++ b/src/main/java/edu/rpi/legup/model/gameboard/PuzzleElement.java @@ -15,6 +15,7 @@ public abstract class PuzzleElement { protected T data; protected boolean isModifiable; protected boolean isModified; + protected boolean isModifiableCaseRule; protected boolean isGiven; protected boolean isValid; protected int casesDepended; @@ -24,6 +25,7 @@ public PuzzleElement() { this.index = -1; this.data = null; this.isModifiable = true; + this.isModifiableCaseRule = true; this.isModified = false; this.isGiven = false; this.isValid = true; @@ -80,6 +82,24 @@ public void setModifiable(boolean isModifiable) { this.isModifiable = isModifiable; } + /** + * Gets whether this puzzle element is modifiable as a result of a case rule. + * + * @return true if this puzzle element is modifiable, false otherwise + */ + public boolean isModifiableCaseRule() { + return isModifiableCaseRule; + } + + /** + * Sets whether this puzzle element is modifiable as a result of a case rule. + * + * @param isModifiableCaseRule true if this puzzle element is modifiable, false otherwise + */ + public void setModifiableCaseRule(boolean isModifiableCaseRule) { + this.isModifiableCaseRule = isModifiableCaseRule; + } + /** * Gets whether the puzzle element has been modified. * diff --git a/src/main/java/edu/rpi/legup/model/observer/IBoardListener.java b/src/main/java/edu/rpi/legup/model/observer/IBoardListener.java index 7f5122a3d..7ba886fd4 100644 --- a/src/main/java/edu/rpi/legup/model/observer/IBoardListener.java +++ b/src/main/java/edu/rpi/legup/model/observer/IBoardListener.java @@ -17,7 +17,7 @@ public interface IBoardListener { void onTreeElementChanged(TreeElement treeElement); /** - * Called when the a case board has been added to the view. + * Called when a case board has been added to the view. * * @param caseBoard case board to be added */ diff --git a/src/main/java/edu/rpi/legup/model/observer/IBoardSubject.java b/src/main/java/edu/rpi/legup/model/observer/IBoardSubject.java index 2f9a3ff9b..6cdcd7dc2 100644 --- a/src/main/java/edu/rpi/legup/model/observer/IBoardSubject.java +++ b/src/main/java/edu/rpi/legup/model/observer/IBoardSubject.java @@ -22,7 +22,7 @@ public interface IBoardSubject { void removeBoardListener(IBoardListener listener); /** - * Notifies all of the listeners using the specified algorithm. + * Notifies all the listeners using the specified algorithm. * * @param algorithm algorithm used to notify the listeners */ diff --git a/src/main/java/edu/rpi/legup/model/observer/ITreeSubject.java b/src/main/java/edu/rpi/legup/model/observer/ITreeSubject.java index 6bb44296f..f7c033529 100644 --- a/src/main/java/edu/rpi/legup/model/observer/ITreeSubject.java +++ b/src/main/java/edu/rpi/legup/model/observer/ITreeSubject.java @@ -8,7 +8,7 @@ */ public interface ITreeSubject { /** - * Adds a board listener. + * Adds a tree listener. * * @param listener listener to add */ @@ -22,7 +22,7 @@ public interface ITreeSubject { void removeTreeListener(ITreeListener listener); /** - * Notifies all of the listeners using the specified algorithm. + * Notifies all the tree listeners using the specified algorithm. * * @param algorithm algorithm used to notify the listeners */ diff --git a/src/main/java/edu/rpi/legup/model/rules/MergeRule.java b/src/main/java/edu/rpi/legup/model/rules/MergeRule.java index e7e3fd277..86c63fb7c 100644 --- a/src/main/java/edu/rpi/legup/model/rules/MergeRule.java +++ b/src/main/java/edu/rpi/legup/model/rules/MergeRule.java @@ -27,7 +27,7 @@ public MergeRule() { /** * Checks whether the transition logically follows from the parent node using this rule. This - * method is the one that should overridden in child classes + * method is the one that should have overridden in child classes * * @param transition transition to check * @return null if the child node logically follow from the parent node, otherwise error message diff --git a/src/main/java/edu/rpi/legup/model/rules/Rule.java b/src/main/java/edu/rpi/legup/model/rules/Rule.java index 6f5b1fd5c..edcab550b 100644 --- a/src/main/java/edu/rpi/legup/model/rules/Rule.java +++ b/src/main/java/edu/rpi/legup/model/rules/Rule.java @@ -164,6 +164,11 @@ public RuleType getRuleType() { return ruleType; } + /** + * Gets the message indicating an invalid use of the rule. + * + * @return the invalid use message + */ public String getInvalidUseOfRuleMessage() { return this.INVALID_USE_MESSAGE; } diff --git a/src/main/java/edu/rpi/legup/model/tree/Tree.java b/src/main/java/edu/rpi/legup/model/tree/Tree.java index 2f74ca3af..545976fd1 100644 --- a/src/main/java/edu/rpi/legup/model/tree/Tree.java +++ b/src/main/java/edu/rpi/legup/model/tree/Tree.java @@ -1,5 +1,6 @@ package edu.rpi.legup.model.tree; +import edu.rpi.legup.controller.TreeController; import edu.rpi.legup.model.gameboard.Board; import edu.rpi.legup.ui.proofeditorui.treeview.TreeView; import java.util.ArrayList; @@ -29,6 +30,12 @@ public Tree() { this.rootNode = null; } + /** + * Adds a new transition to the specified node. + * + * @param treeNode the node to add a transition to + * @return the created transition + */ public TreeTransition addNewTransition(TreeNode treeNode) { TreeTransition transition = new TreeTransition(treeNode, treeNode.getBoard().copy()); treeNode.addChild(transition); @@ -36,13 +43,12 @@ public TreeTransition addNewTransition(TreeNode treeNode) { return transition; } - public TreeNode addNode(TreeTransition transition) { - TreeNode treeNode = new TreeNode(transition.getBoard().copy()); - transition.setChildNode(treeNode); - treeNode.setParent(transition); - return treeNode; - } - + /** + * Adds a tree element (node or transition) to the tree. + * + * @param element the tree element to add + * @return the added tree element + */ public TreeElement addTreeElement(TreeElement element) { if (element.getType() == TreeElementType.NODE) { TreeNode treeNode = (TreeNode) element; @@ -51,30 +57,55 @@ public TreeElement addTreeElement(TreeElement element) { } else { TreeTransition transition = (TreeTransition) element; Board copyBoard = transition.board.copy(); - copyBoard.setModifiable(false); + copyBoard.setModifiable(true); return addTreeElement(transition, new TreeNode(copyBoard)); } } + /** + * Adds a tree node and its associated transition to the tree. + * + * @param treeNode the tree node to add + * @param transition the transition to associate with the node + * @return the added transition + */ public TreeElement addTreeElement(TreeNode treeNode, TreeTransition transition) { treeNode.addChild(transition); treeNode.getChildren().forEach(TreeTransition::reverify); return transition; } + /** + * Adds a transition and its associated tree node to the tree. + * + * @param transition the transition to add + * @param treeNode the tree node to associate with the transition + * @return the added tree node + */ public TreeElement addTreeElement(TreeTransition transition, TreeNode treeNode) { transition.setChildNode(treeNode); treeNode.setParent(transition); return treeNode; } + /** + * Removes a tree element (node or transition) from the tree. + * + * @param element the tree element to remove + */ public void removeTreeElement(TreeElement element) { if (element.getType() == TreeElementType.NODE) { TreeNode node = (TreeNode) element; + + node.getParent().removeChild(node); node.getParent().setChildNode(null); } else { TreeTransition transition = (TreeTransition) element; + transition.getParents().forEach(n -> n.removeChild(transition)); + TreeController treeController = new TreeController(); + TreeView treeView = new TreeView(treeController); + treeView.removeTreeTransition(transition); transition.getParents().get(0).getChildren().forEach(TreeTransition::reverify); } } @@ -101,10 +132,10 @@ public Set getLeafTreeElements() { } /** - * Gets a Set of TreeNodes that are leaf nodes from the sub tree rooted at the specified node + * Gets a Set of TreeNodes that are leaf nodes from the subtree rooted at the specified node * * @param node node that is input - * @return Set of TreeNodes that are leaf nodes from the sub tree + * @return Set of TreeNodes that are leaf nodes from the subtree */ public Set getLeafTreeElements(TreeNode node) { Set leafs = new HashSet<>(); diff --git a/src/main/java/edu/rpi/legup/model/tree/TreeElement.java b/src/main/java/edu/rpi/legup/model/tree/TreeElement.java index e668a5c8f..8c865b89b 100644 --- a/src/main/java/edu/rpi/legup/model/tree/TreeElement.java +++ b/src/main/java/edu/rpi/legup/model/tree/TreeElement.java @@ -28,7 +28,7 @@ public TreeElement(TreeElementType type) { public abstract boolean isContradictoryBranch(); /** - * Recursively determines if the sub-tree rooted at this tree puzzleElement is valid by checking + * Recursively determines if the subtree rooted at this tree puzzleElement is valid by checking * whether this tree puzzleElement and all descendants of this tree puzzleElement is justified * and justified correctly * diff --git a/src/main/java/edu/rpi/legup/model/tree/TreeNode.java b/src/main/java/edu/rpi/legup/model/tree/TreeNode.java index 2fe5ffcd2..d4095afa5 100644 --- a/src/main/java/edu/rpi/legup/model/tree/TreeNode.java +++ b/src/main/java/edu/rpi/legup/model/tree/TreeNode.java @@ -61,9 +61,9 @@ public boolean isValidBranch() { } /** - * Gets all of the ancestors of this node + * Gets a list of the ancestors of this node * - * @return list of all of the ancestors for this node + * @return list of all the ancestors for this node */ public List getAncestors() { List ancestors = new ArrayList<>(); diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/Binary.java b/src/main/java/edu/rpi/legup/puzzle/binary/Binary.java index d304dbb24..7b70a43a1 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/Binary.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/Binary.java @@ -36,18 +36,12 @@ public Board generatePuzzle(int difficulty) { return null; } - // /** - // * Determines if the given dimensions are valid for Binary - // * - // * @param rows the number of rows - // * @param columns the number of columns - // * @return true if the given dimensions are valid for Binary, false otherwise - // */ - // @Override - // public boolean isValidDimensions(int rows, int columns){ - // return rows >= 2 && rows % 2 == 0 && columns >= 2 && columns % 2 == 0; - // } - + /** + * Determines if the current board is a valid state + * + * @param board board to check for validity + * @return true if board is valid, false otherwise + */ @Override public boolean isBoardComplete(Board board) { BinaryBoard binaryBoard = (BinaryBoard) board; @@ -66,6 +60,11 @@ public boolean isBoardComplete(Board board) { return true; } + /** + * Callback for when the board puzzleElement changes + * + * @param board the board that has changed + */ @Override public void onBoardChange(Board board) {} diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java index 9a3d0f083..d5d65ed26 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java @@ -19,6 +19,13 @@ public BinaryBoard(int size) { this.size = size; } + /** + * Gets the cell at the (x,y) position + * + * @param x x-coordinate + * @param y y-coordinate + * @return BinaryCell cell at (x,y) + */ @Override public BinaryCell getCell(int x, int y) { if (y * dimension.width + x >= puzzleElements.size() @@ -31,6 +38,12 @@ public BinaryCell getCell(int x, int y) { return (BinaryCell) super.getCell(x, y); } + /** + * Get all the binary cells in a row + * + * @param rowNum row number + * @return set of all binary cells in specified rowNum + */ public Set getRowCells(int rowNum) { Set row = new HashSet<>(); for (int i = 0; i < size; i++) { @@ -91,7 +104,6 @@ public ArrayList getColTypes(int colNum) { */ @Override public BinaryBoard copy() { - System.out.println("BinaryBoard copy()"); BinaryBoard copy = new BinaryBoard(dimension.width, dimension.height); for (int x = 0; x < this.dimension.width; x++) { for (int y = 0; y < this.dimension.height; y++) { diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java index e7be09b8d..0edb8444e 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java @@ -1,14 +1,26 @@ package edu.rpi.legup.puzzle.binary; +import edu.rpi.legup.model.elements.Element; import edu.rpi.legup.model.gameboard.GridCell; import java.awt.Point; import java.awt.event.MouseEvent; public class BinaryCell extends GridCell { - public BinaryCell(int valueInt, Point location) { - super(valueInt, location); + /** + * BinaryCell Constructor - creates a BinaryCell from the specified value and location + * + * @param value value of the BinaryCell + * @param location position of the BinaryCell + */ + public BinaryCell(int value, Point location) { + super(value, location); } + /** + * Gets the type of this BinaryCell + * + * @return type of BinaryCell + */ public BinaryType getType() { switch (data) { case 0: @@ -25,6 +37,11 @@ public BinaryType getType() { return null; } + /** + * Performs a deep copy on the BinaryCell + * + * @return a new copy of the BinaryCell that is independent of this one + */ @Override public BinaryCell copy() { BinaryCell copy = new BinaryCell(data, (Point) location.clone()); diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCellFactory.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCellFactory.java index 890c26656..a819177d6 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCellFactory.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCellFactory.java @@ -10,7 +10,14 @@ import org.w3c.dom.Node; public class BinaryCellFactory extends ElementFactory { - + /** + * Creates a puzzleElement based on the xml document Node and adds it to the board + * + * @param node node that represents the puzzleElement + * @param board board to add the newly created cell + * @return newly created cell from the xml document Node + * @throws InvalidFileFormatException if file is invalid + */ public BinaryCell importCell(Node node, Board board) throws InvalidFileFormatException { try { if (!node.getNodeName().equalsIgnoreCase("cell")) { @@ -45,6 +52,13 @@ public BinaryCell importCell(Node node, Board board) throws InvalidFileFormatExc } } + /** + * Creates a xml document puzzleElement from a cell for exporting + * + * @param document xml document + * @param puzzleElement PuzzleElement cell + * @return xml PuzzleElement + */ public org.w3c.dom.Element exportCell(Document document, PuzzleElement puzzleElement) { org.w3c.dom.Element cellElement = document.createElement("cell"); diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryController.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryController.java index f2a735c4d..5ec6669a0 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryController.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryController.java @@ -39,13 +39,13 @@ public void changeCell(MouseEvent e, PuzzleElement data) { } } else { if (e.getButton() == MouseEvent.BUTTON3) { - if (cell.getData() == 0) { + if (cell.getData() == 2) { data.setData(1); } else { if (cell.getData() == 1) { - data.setData(2); - } else { data.setData(0); + } else { + data.setData(2); } } } diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryElementView.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryElementView.java index b523a74a9..74a761e89 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryElementView.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryElementView.java @@ -7,6 +7,8 @@ public class BinaryElementView extends GridElementView { private static final Font FONT = new Font("TimesRoman", Font.BOLD, 17); private static final Color FONT_COLOR = Color.BLACK; + private static final Color GIVEN_COLOR = Color.LIGHT_GRAY; + private static final Color ELEMENT_COLOR = Color.WHITE; public BinaryElementView(BinaryCell cell) { super(cell); @@ -51,95 +53,35 @@ public void drawElement(Graphics2D graphics2D) { private void drawCell(Graphics2D graphics2D, Color bgColor) { BinaryCell cell = (BinaryCell) puzzleElement; BinaryType type = cell.getType(); - if (type == BinaryType.ZERO) { + + if (type == BinaryType.ZERO || type == BinaryType.ONE) { graphics2D.setStroke(new BasicStroke(1)); - graphics2D.setColor(Color.LIGHT_GRAY); + graphics2D.setColor(bgColor); graphics2D.fillRect(location.x, location.y, size.width, size.height); graphics2D.setColor(Color.BLACK); graphics2D.drawRect(location.x, location.y, size.width, size.height); - graphics2D.setColor(FONT_COLOR); - graphics2D.setFont(FONT); - FontMetrics metrics = graphics2D.getFontMetrics(FONT); - String value = String.valueOf(puzzleElement.getData()); - int xText = location.x + (size.width - metrics.stringWidth(value)) / 2; - int yText = - location.y + ((size.height - metrics.getHeight()) / 2) + metrics.getAscent(); - graphics2D.drawString(String.valueOf(puzzleElement.getData()), xText, yText); - } else { - if (type == BinaryType.ONE) { - graphics2D.setStroke(new BasicStroke(1)); - graphics2D.setColor(Color.LIGHT_GRAY); - graphics2D.fillRect(location.x, location.y, size.width, size.height); - graphics2D.setColor(Color.BLACK); - graphics2D.drawRect(location.x, location.y, size.width, size.height); - graphics2D.setColor(FONT_COLOR); - graphics2D.setFont(FONT); - FontMetrics metrics = graphics2D.getFontMetrics(FONT); - String value = String.valueOf(puzzleElement.getData()); - int xText = location.x + (size.width - metrics.stringWidth(value)) / 2; - int yText = - location.y - + ((size.height - metrics.getHeight()) / 2) - + metrics.getAscent(); - graphics2D.drawString(String.valueOf(puzzleElement.getData()), xText, yText); - - } else { - if (type == BinaryType.UNKNOWN) { - graphics2D.setStroke(new BasicStroke(0)); - graphics2D.setColor(Color.WHITE); - graphics2D.fillRect(location.x, location.y, size.width, size.height); - graphics2D.setColor(Color.BLACK); - graphics2D.drawRect(location.x, location.y, size.width, size.height); - } - } - } - } - - @Override - public void drawElement(Graphics2D graphics2D) { - BinaryCell cell = (BinaryCell) puzzleElement; - BinaryType type = cell.getType(); - if (type == BinaryType.ZERO) { - graphics2D.setStroke(new BasicStroke(1)); + drawCenteredText(graphics2D); + } else if (type == BinaryType.UNKNOWN) { + graphics2D.setStroke(new BasicStroke(0)); graphics2D.setColor(Color.WHITE); graphics2D.fillRect(location.x, location.y, size.width, size.height); graphics2D.setColor(Color.BLACK); graphics2D.drawRect(location.x, location.y, size.width, size.height); - graphics2D.setColor(FONT_COLOR); - graphics2D.setFont(FONT); - FontMetrics metrics = graphics2D.getFontMetrics(FONT); - String value = String.valueOf(puzzleElement.getData()); - int xText = location.x + (size.width - metrics.stringWidth(value)) / 2; - int yText = - location.y + ((size.height - metrics.getHeight()) / 2) + metrics.getAscent(); - graphics2D.drawString(String.valueOf(puzzleElement.getData()), xText, yText); - } else { - if (type == BinaryType.ONE) { - graphics2D.setStroke(new BasicStroke(1)); - graphics2D.setColor(Color.WHITE); - graphics2D.fillRect(location.x, location.y, size.width, size.height); - graphics2D.setColor(Color.BLACK); - graphics2D.drawRect(location.x, location.y, size.width, size.height); - graphics2D.setColor(FONT_COLOR); - graphics2D.setFont(FONT); - FontMetrics metrics = graphics2D.getFontMetrics(FONT); - String value = String.valueOf(puzzleElement.getData()); - int xText = location.x + (size.width - metrics.stringWidth(value)) / 2; - int yText = - location.y - + ((size.height - metrics.getHeight()) / 2) - + metrics.getAscent(); - graphics2D.drawString(String.valueOf(puzzleElement.getData()), xText, yText); - - } else { - if (type == BinaryType.UNKNOWN) { - graphics2D.setStroke(new BasicStroke(0)); - graphics2D.setColor(Color.WHITE); - graphics2D.fillRect(location.x, location.y, size.width, size.height); - graphics2D.setColor(Color.BLACK); - graphics2D.drawRect(location.x, location.y, size.width, size.height); - } - } } } + + /** + * Helper method to draw the centered text within the cell + * + * @param graphics2D The graphics object to draw on + */ + private void drawCenteredText(Graphics2D graphics2D) { + graphics2D.setColor(FONT_COLOR); + graphics2D.setFont(FONT); + FontMetrics metrics = graphics2D.getFontMetrics(FONT); + String value = String.valueOf(puzzleElement.getData()); + int xText = location.x + (size.width - metrics.stringWidth(value)) / 2; + int yText = location.y + ((size.height - metrics.getHeight()) / 2) + metrics.getAscent(); + graphics2D.drawString(value, xText, yText); + } } diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryExporter.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryExporter.java index 43ea8caf4..c032b63a9 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryExporter.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryExporter.java @@ -33,7 +33,7 @@ protected org.w3c.dom.Element createBoardElement(Document newDocument) { org.w3c.dom.Element cellsElement = newDocument.createElement("cells"); for (PuzzleElement puzzleElement : board.getPuzzleElements()) { BinaryCell cell = (BinaryCell) puzzleElement; - if (cell.getData() != -2) { + if (cell.getData() != BinaryType.UNKNOWN.toValue()) { org.w3c.dom.Element cellElement = puzzle.getFactory().exportCell(newDocument, puzzleElement); cellsElement.appendChild(cellElement); diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryImporter.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryImporter.java index 746d3b4b6..419789060 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryImporter.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryImporter.java @@ -12,16 +12,33 @@ public BinaryImporter(Binary binary) { super(binary); } + /** + * Determines if puzzle uses row and column input + * + * @return true if row and column input is used, false otherwise + */ @Override public boolean acceptsRowsAndColumnsInput() { return true; } + /** + * Determines if puzzle uses text input + * + * @return true if text input is used, false otherwise + */ @Override public boolean acceptsTextInput() { return false; } + /** + * Creates an empty board for building + * + * @param rows the number of rows on the board + * @param columns the number of columns on the board + * @throws RuntimeException if board can not be created + */ @Override public void initializeBoard(int rows, int columns) { BinaryBoard binaryBoard = new BinaryBoard(columns, rows); @@ -48,12 +65,12 @@ public void initializeBoard(Node node) throws InvalidFileFormatException { try { if (!node.getNodeName().equalsIgnoreCase("board")) { throw new InvalidFileFormatException( - "binary Importer: cannot find board puzzleElement"); + "Binary Importer: cannot find board puzzleElement"); } Element boardElement = (Element) node; if (boardElement.getElementsByTagName("cells").getLength() == 0) { throw new InvalidFileFormatException( - "binary Importer: no puzzleElement found for board"); + "Binary Importer: no puzzleElement found for board"); } Element dataElement = (Element) boardElement.getElementsByTagName("cells").item(0); @@ -76,7 +93,7 @@ public void initializeBoard(Node node) throws InvalidFileFormatException { int height = binaryBoard.getHeight(); if (binaryBoard == null || width % 2 != 0 || height % 2 != 0) { - throw new InvalidFileFormatException("binary Importer: invalid board dimensions"); + throw new InvalidFileFormatException("Binary Importer: invalid board dimensions"); } for (int i = 0; i < elementDataList.getLength(); i++) { diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/elements/BlankTile.java b/src/main/java/edu/rpi/legup/puzzle/binary/elements/BlankTile.java deleted file mode 100644 index 8b1378917..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/binary/elements/BlankTile.java +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/elements/binary_elements_reference_sheet.txt b/src/main/java/edu/rpi/legup/puzzle/binary/elements/binary_elements_reference_sheet.txt new file mode 100644 index 000000000..54db0ee0b --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/elements/binary_elements_reference_sheet.txt @@ -0,0 +1,2 @@ +BINA-ELEM-0001 : NumberTile +BINA-ELEM-0002 : UnknownTile \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java index 09cca6dc5..6ced37a9c 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java @@ -32,23 +32,27 @@ public CompleteRowColumnDirectRule() { @Override public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { BinaryBoard origBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); - ContradictionRule contraRule = new UnbalancedRowOrColumnContradictionRule(); + ContradictionRule contraRule = new UnbalancedRowColumnContradictionRule(); BinaryCell binaryCell = (BinaryCell) puzzleElement; BinaryBoard modified = origBoard.copy(); - BinaryCell c = (BinaryCell) modified.getPuzzleElement(puzzleElement); - // System.out.println("ORIG" + binaryCell.getData()); - // System.out.println("AFTER" + Math.abs(binaryCell.getData() - 1)); - modified.getPuzzleElement(puzzleElement).setData(binaryCell.getData()); - System.out.println(contraRule.checkContradictionAt(modified, puzzleElement)); - - if (contraRule.checkContradictionAt(modified, puzzleElement) != null) { + // Flip the cell and check to see if there will be an unbalanced row/column contradiction, + // if so the rule is applied correctly + modified.getPuzzleElement(puzzleElement).setData(Math.abs(binaryCell.getData() - 1)); + if (contraRule.checkContradictionAt(modified, puzzleElement) == null) { return null; } - return "Grouping of Three Ones or Zeros not found"; + return "Unbalanced row/column found"; } + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ @Override public Board getDefaultBoard(TreeNode node) { return null; diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java deleted file mode 100644 index 2e1e96fa5..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneTileGapDirectRule.java +++ /dev/null @@ -1,64 +0,0 @@ -package edu.rpi.legup.puzzle.binary.rules; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.ContradictionRule; -import edu.rpi.legup.model.rules.DirectRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -import edu.rpi.legup.puzzle.binary.BinaryBoard; -import edu.rpi.legup.puzzle.binary.BinaryCell; - -public class OneTileGapDirectRule extends DirectRule { - private final String INVALID_USE_MESSAGE = "Number at cell is incorrect"; - - public OneTileGapDirectRule() { - super( - "BINA-BASC-0002", - "One Tile Gap", - "If an empty tile is in between the same value, fill the gap with the other value.", - "edu/rpi/legup/images/binary/rules/OneTileGapDirectRule.png"); - } - - boolean checkLeftRight(BinaryCell c, BinaryBoard board) { - int x = c.getLocation().x; - int y = c.getLocation().y; - return board.getCell(x - 1, y).getType() != c.getType() - || board.getCell(x + 1, y).getType() != c.getType(); - } - - boolean checkUpDown(BinaryCell c, BinaryBoard board) { - int x = c.getLocation().x; - int y = c.getLocation().y; - return board.getCell(x, y - 1).getType() != c.getType() - || board.getCell(x, y + 1).getType() != c.getType(); - } - - @Override - public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - BinaryBoard origBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); - ContradictionRule contraRule = new ThreeAdjacentContradictionRule(); - BinaryCell binaryCell = (BinaryCell) puzzleElement; - BinaryBoard modified = origBoard.copy(); - - // System.out.println("ORIG" + binaryCell.getData()); - // System.out.println("AFTER" + Math.abs(binaryCell.getData() - 1)); - modified.getPuzzleElement(puzzleElement).setData(Math.abs(binaryCell.getData() - 1)); - - PuzzleElement newP = binaryCell; - - System.out.println(contraRule.checkContradictionAt(modified, newP)); - - if (contraRule.checkContradictionAt(modified, newP) == null) { - return null; - } - modified.getPuzzleElement(puzzleElement).setData(Math.abs(binaryCell.getData() - 1)); - - return "Grouping of Three Ones or Zeros not found"; - } - - @Override - public Board getDefaultBoard(TreeNode node) { - return null; - } -} diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsOrColumnsContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/RepeatedRowColumnContradictionRule.java similarity index 69% rename from src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsOrColumnsContradictionRule.java rename to src/main/java/edu/rpi/legup/puzzle/binary/rules/RepeatedRowColumnContradictionRule.java index 6e009f123..a7a4ced12 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/DuplicateRowsOrColumnsContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/RepeatedRowColumnContradictionRule.java @@ -8,19 +8,28 @@ import edu.rpi.legup.puzzle.binary.BinaryType; import java.util.ArrayList; -public class DuplicateRowsOrColumnsContradictionRule extends ContradictionRule { +public class RepeatedRowColumnContradictionRule extends ContradictionRule { private final String NO_CONTRADICTION_MESSAGE = "Does not contain a contradiction at this index"; private final String INVALID_USE_MESSAGE = "Row or column must have a value in each cell"; - public DuplicateRowsOrColumnsContradictionRule() { + public RepeatedRowColumnContradictionRule() { super( "BINA-CONT-0003", - "Duplicate Rows Or Columns", - "There must not be two rows or two columns that are duplicates", - "edu/rpi/legup/images/binary/rules/DuplicateRowOrColumnContradictionRule.png"); + "Repeated Row/Column", + "There must not be two of the same row or two of the same column in the puzzle", + "edu/rpi/legup/images/binary/rules/RepeatedRowColumnContradictionRule.png"); } + /** + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule + * + * @param board board to check contradiction + * @param puzzleElement equivalent puzzleElement + * @return null if the transition contains a contradiction at the specified puzzleElement, + * otherwise error message + */ @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { BinaryBoard binaryBoard = (BinaryBoard) board; @@ -29,11 +38,9 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { // Compare each row with row of current cell to see if they are equal, if so the rule is // applied correctly ArrayList row = binaryBoard.getRowTypes(cell.getLocation().y); - int size = row.size(); - for (int i = 0; i < size; i++) { - if (i > cell.getLocation().y) { + if (i != cell.getLocation().y) { ArrayList currRow = binaryBoard.getRowTypes(i); if (currRow.equals(row)) { return null; @@ -44,9 +51,8 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { // Compare each column with column of current cell to see if they are equal, if so the rule // is applied correctly ArrayList col = binaryBoard.getColTypes(cell.getLocation().x); - for (int i = 0; i < size; i++) { - if (i > cell.getLocation().x) { + if (i != cell.getLocation().x) { ArrayList currCol = binaryBoard.getColTypes(i); if (currCol.equals(col)) { return null; diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java deleted file mode 100644 index dc2f07c8b..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/SurroundPairDirectRule.java +++ /dev/null @@ -1,48 +0,0 @@ -package edu.rpi.legup.puzzle.binary.rules; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.ContradictionRule; -import edu.rpi.legup.model.rules.DirectRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -import edu.rpi.legup.puzzle.binary.BinaryBoard; -import edu.rpi.legup.puzzle.binary.BinaryCell; - -public class SurroundPairDirectRule extends DirectRule { - - public SurroundPairDirectRule() { - super( - "BINA-BASC-0001", - "Surround Pair", - "If two adjacent tiles have the same value, surround the tiles with the other value.", - "edu/rpi/legup/images/binary/rules/SurroundPairDirectRule.png"); - } - - public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - BinaryBoard origBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); - ContradictionRule contraRule = new ThreeAdjacentContradictionRule(); - BinaryCell binaryCell = (BinaryCell) puzzleElement; - BinaryBoard modified = origBoard.copy(); - - // System.out.println("ORIG" + binaryCell.getData()); - // System.out.println("AFTER" + Math.abs(binaryCell.getData() - 1)); - modified.getPuzzleElement(puzzleElement).setData(Math.abs(binaryCell.getData() - 1)); - - PuzzleElement newP = binaryCell; - - System.out.println(contraRule.checkContradictionAt(modified, newP)); - - if (contraRule.checkContradictionAt(modified, newP) == null) { - return null; - } - modified.getPuzzleElement(puzzleElement).setData(Math.abs(binaryCell.getData() - 1)); - - return "Grouping of Three Ones or Zeros not found"; - } - - @Override - public Board getDefaultBoard(TreeNode node) { - return null; - } -} diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java deleted file mode 100644 index 075642246..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ThreeAdjacentContradictionRule.java +++ /dev/null @@ -1,127 +0,0 @@ -package edu.rpi.legup.puzzle.binary.rules; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.ContradictionRule; -import edu.rpi.legup.puzzle.binary.BinaryBoard; -import edu.rpi.legup.puzzle.binary.BinaryCell; -import edu.rpi.legup.puzzle.binary.BinaryType; - -public class ThreeAdjacentContradictionRule extends ContradictionRule { - private final String NO_CONTRADICTION_MESSAGE = - "Does not contain a contradiction at this index"; - private final String INVALID_USE_MESSAGE = "Contradiction must be a zero or one"; - - public ThreeAdjacentContradictionRule() { - super( - "BINA-CONT-0001", - "Three Adjacent", - "There must not be three adjacent zeros or three adjacent ones in a row or column", - "edu/rpi/legup/images/binary/rules/ThreeAdjacentContradictionRule.png"); - } - - @Override - public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { - BinaryBoard binaryBoard = (BinaryBoard) board; - int height = binaryBoard.getHeight(); - int width = binaryBoard.getWidth(); - - BinaryCell cell = (BinaryCell) binaryBoard.getPuzzleElement(puzzleElement); - System.out.println("THE CELL IS : " + cell.getType()); - int cellX = cell.getLocation().x; - int cellY = cell.getLocation().y; - BinaryCell oneUp = null; - BinaryCell oneDown = null; - BinaryCell oneForward = null; - BinaryCell oneBackward = null; - BinaryCell twoUp = null; - BinaryCell twoDown = null; - BinaryCell twoForward = null; - BinaryCell twoBackward = null; - if (binaryBoard.getCell(cellX, cellY + 1) != null) { - oneUp = binaryBoard.getCell(cellX, cellY + 1); - } - if (binaryBoard.getCell(cellX, cellY - 1) != null) { - oneDown = binaryBoard.getCell(cellX, cellY - 1); - } - if (binaryBoard.getCell(cellX + 1, cellY) != null) { - oneForward = binaryBoard.getCell(cellX + 1, cellY); - } - if (binaryBoard.getCell(cellX - 1, cellY) != null) { - oneBackward = binaryBoard.getCell(cellX - 1, cellY); - } - if (binaryBoard.getCell(cellX, cellY + 2) != null) { - twoUp = binaryBoard.getCell(cellX, cellY + 2); - } - if (binaryBoard.getCell(cellX, cellY - 2) != null) { - twoDown = binaryBoard.getCell(cellX, cellY - 2); - } - if (binaryBoard.getCell(cellX + 2, cellY) != null) { - twoForward = binaryBoard.getCell(cellX + 2, cellY); - } - if (binaryBoard.getCell(cellX - 2, cellY) != null) { - twoBackward = binaryBoard.getCell(cellX - 2, cellY); - } - - if (cell.getType() == BinaryType.ONE || cell.getType() == BinaryType.ZERO) { - if (twoBackward != null - && oneBackward != null - && twoBackward.getType() != BinaryType.UNKNOWN - && oneBackward.getType() != BinaryType.UNKNOWN) { - if (twoBackward.getType() == cell.getType() - && oneBackward.getType() == cell.getType()) { - System.out.println("1"); - return null; - } - } - if (twoForward != null - && oneForward != null - && twoForward.getType() != BinaryType.UNKNOWN - && oneForward.getType() != BinaryType.UNKNOWN) { - if (twoForward.getType() == cell.getType() - && oneForward.getType() == cell.getType()) { - System.out.println("2"); - return null; - } - } - if (twoDown != null - && oneDown != null - && twoDown.getType() != BinaryType.UNKNOWN - && oneDown.getType() != BinaryType.UNKNOWN) { - if (twoDown.getType() == cell.getType() && oneDown.getType() == cell.getType()) { - System.out.println("3"); - return null; - } - } - if (twoUp != null - && oneUp != null - && twoUp.getType() != BinaryType.UNKNOWN - && oneUp.getType() != BinaryType.UNKNOWN) { - if (twoUp.getType() == cell.getType() && oneUp.getType() == cell.getType()) { - System.out.println("4"); - return null; - } - } - if (oneBackward != null - && oneForward != null - && oneBackward.getType() != BinaryType.UNKNOWN - && oneForward.getType() != BinaryType.UNKNOWN) { - if (oneBackward.getType() == cell.getType() - && oneForward.getType() == cell.getType()) { - System.out.println("5"); - return null; - } - } - if (oneUp != null - && oneDown != null - && oneUp.getType() != BinaryType.UNKNOWN - && oneDown.getType() != BinaryType.UNKNOWN) { - if (oneUp.getType() == cell.getType() && oneDown.getType() == cell.getType()) { - System.out.println("6"); - return null; - } - } - } - return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE; - } -} diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowOrColumnContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowColumnContradictionRule.java similarity index 66% rename from src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowOrColumnContradictionRule.java rename to src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowColumnContradictionRule.java index 301cc6ec1..1d00f4da9 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowOrColumnContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowColumnContradictionRule.java @@ -8,20 +8,29 @@ import edu.rpi.legup.puzzle.binary.BinaryType; import java.util.Set; -public class UnbalancedRowOrColumnContradictionRule extends ContradictionRule { +public class UnbalancedRowColumnContradictionRule extends ContradictionRule { private final String NO_CONTRADICTION_MESSAGE = "Does not contain a contradiction at this index"; private final String INVALID_USE_MESSAGE = "Row or column must have a value in each cell"; - public UnbalancedRowOrColumnContradictionRule() { + public UnbalancedRowColumnContradictionRule() { super( "BINA-CONT-0002", - "Unbalanced Row Or Column", + "Unbalanced Row/Column", "Each row or column must contain an equal number of zeros and ones", "edu/rpi/legup/images/binary/rules/UnbalancedRowColumnContradictionRule.png"); } + /** + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule + * + * @param board board to check contradiction + * @param puzzleElement equivalent puzzleElement + * @return null if the transition contains a contradiction at the specified puzzleElement, + * otherwise error message + */ @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { BinaryBoard binaryBoard = (BinaryBoard) board; @@ -41,8 +50,9 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { } } - if (rowNumZeros == size / 2 && rowNumOnes == size / 2) { - return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE; + // if there are too many zeros or ones in this row + if (rowNumZeros > size / 2 || rowNumOnes > size / 2) { + return null; } Set col = binaryBoard.getColCells(cell.getLocation().x); @@ -59,10 +69,11 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { } } - if (colNumZeros == size / 2 && colNumOnes == size / 2) { - return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE; + // if there are too many zeros or ones in this column + if (colNumZeros > size / 2 || colNumOnes > size / 2) { + return null; } - return null; + return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE; } } diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneOrZeroCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ZeroOrOneCaseRule.java similarity index 64% rename from src/main/java/edu/rpi/legup/puzzle/binary/rules/OneOrZeroCaseRule.java rename to src/main/java/edu/rpi/legup/puzzle/binary/rules/ZeroOrOneCaseRule.java index 21ee0dd5b..f47fe55b9 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/OneOrZeroCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ZeroOrOneCaseRule.java @@ -11,16 +11,23 @@ import java.util.ArrayList; import java.util.List; -public class OneOrZeroCaseRule extends CaseRule { +public class ZeroOrOneCaseRule extends CaseRule { - public OneOrZeroCaseRule() { + public ZeroOrOneCaseRule() { super( "BINA-CASE-0001", - "One or Zero", - "Each blank cell is either a one or a zero.", - "edu/rpi/legup/images/binary/rules/OneOrZeroCaseRule.png"); + "Zero Or One", + "Each blank cell is either a zero or a one", + "edu/rpi/legup/images/binary/rules/ZeroOrOneCaseRule.png"); } + /** + * Checks whether the {@link TreeTransition} logically follows from the parent node using this + * rule. This method is the one that should be overridden in child classes. + * + * @param transition transition to check + * @return null if the child node logically follow from the parent node, otherwise error message + */ @Override public String checkRuleRaw(TreeTransition transition) { List childTransitions = transition.getParents().get(0).getChildren(); @@ -52,6 +59,13 @@ public String checkRuleRaw(TreeTransition transition) { return null; } + /** + * Generates a {@link CaseBoard} that includes all blank cells from the given board that this + * case rule can be applied to + * + * @param board The board to find locations where this case rule can be applied + * @return A CaseBoard containing pickable elements where the case rule can be applied + */ @Override public CaseBoard getCaseBoard(Board board) { BinaryBoard binaryBoard = (BinaryBoard) board.copy(); @@ -65,24 +79,44 @@ public CaseBoard getCaseBoard(Board board) { return caseBoard; } + /** + * Gets the possible cases at a specific location based on this case rule + * + * @param board the current board state + * @param puzzleElement equivalent puzzleElement + * @return a list of elements the specified could be + */ @Override public ArrayList getCases(Board board, PuzzleElement puzzleElement) { ArrayList cases = new ArrayList<>(); + if (puzzleElement == null) { + return cases; + } + Board case1 = board.copy(); PuzzleElement data1 = case1.getPuzzleElement(puzzleElement); - data1.setData(BinaryType.ZERO.toValue()); + data1.setData(BinaryType.ONE.toValue()); case1.addModifiedData(data1); cases.add(case1); Board case2 = board.copy(); PuzzleElement data2 = case2.getPuzzleElement(puzzleElement); - data2.setData(BinaryType.ONE.toValue()); + data2.setData(BinaryType.ZERO.toValue()); case2.addModifiedData(data2); cases.add(case2); return cases; } + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ @Override public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { return null; diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/binary_reference_sheet.txt b/src/main/java/edu/rpi/legup/puzzle/binary/rules/binary_reference_sheet.txt index c8cb0d1b9..619d183a5 100644 --- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/binary_reference_sheet.txt +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/binary_reference_sheet.txt @@ -1,9 +1,11 @@ -BINA-BASC-0001 : SurroundPairDirectRule -BINA-BASC-0002 : OneTileGapDirectRule -BINA-BASC-0003 : CompleteRowColumnDirectRule +BINA-BASC-0001 : PreventTrioContradictionRule +BINA-BASC-0002 : CompleteRowColumnDirectRule +BINA-BASC-0003 : SaveBlockerDirectRule +BINA-BASC-0004 : UniqueRowColumnDirectRule -BINA-CONT-0001 : ThreeAdjacentContradictionRule -BINA-CONT-0002 : UnbalancedRowOrColumnContradictionRule -BINA-CONT-0003 : DuplicateRowsOrColumnsContradictionRule +BINA-CONT-0001 : TrioContradictionRule +BINA-CONT-0002 : UnbalancedRowColumnContradictionRule +BINA-CONT-0003 : RepeatedRowColumnContradictionRule +BINA-CONT-0004 : WastedBlockerContradictionRule -BINA-CASE-0001 : OneOrZeroCaseRule \ No newline at end of file +BINA-CASE-0001 : ZeroOrOneCaseRule \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/fillapix/FillapixCell.java b/src/main/java/edu/rpi/legup/puzzle/fillapix/FillapixCell.java index a9e5aa2df..40c5e4a54 100644 --- a/src/main/java/edu/rpi/legup/puzzle/fillapix/FillapixCell.java +++ b/src/main/java/edu/rpi/legup/puzzle/fillapix/FillapixCell.java @@ -42,13 +42,13 @@ public void setCellType(FillapixCellType type) { @Override public void setType(Element e, MouseEvent m) { switch (e.getElementID()) { - case "FPIX-PLAC-0001": + case "FPIX-ELEM-0001": this.setCellType(FillapixCellType.BLACK); break; - case "FPIX-PLAC-0002": + case "FPIX-ELEM-0004": this.setCellType(FillapixCellType.WHITE); break; - case "FPIX-UNPL-0001": + case "FPIX-ELEM-0002": int n = this.getNumber(); switch (m.getButton()) { case MouseEvent.BUTTON1: diff --git a/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/BlackTile.java b/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/BlackTile.java index 1d7c038a3..a6993778d 100644 --- a/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/BlackTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/BlackTile.java @@ -5,7 +5,7 @@ public class BlackTile extends PlaceableElement { public BlackTile() { super( - "FPIX-PLAC-0001", + "FPIX-ELEM-0001", "Black Tile", "The black tile", "edu/rpi/legup/images/fillapix/tiles/BlackTile.png"); diff --git a/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/NumberTile.java b/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/NumberTile.java index e869aeaf9..5852c1ad7 100644 --- a/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/NumberTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/NumberTile.java @@ -1,13 +1,13 @@ package edu.rpi.legup.puzzle.fillapix.elements; -import edu.rpi.legup.model.elements.NonPlaceableElement; +import edu.rpi.legup.model.elements.PlaceableElement; -public class NumberTile extends NonPlaceableElement { +public class NumberTile extends PlaceableElement { private int object_num; public NumberTile() { super( - "FPIX-UNPL-0001", + "FPIX-ELEM-0002", "Number Tile", "A numbered tile", "edu/rpi/legup/images/fillapix/tiles/NumberTile.png"); diff --git a/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/UnknownTile.java b/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/UnknownTile.java index 6778c1758..82d0dffb9 100644 --- a/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/UnknownTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/UnknownTile.java @@ -1,11 +1,11 @@ package edu.rpi.legup.puzzle.fillapix.elements; -import edu.rpi.legup.model.elements.NonPlaceableElement; +import edu.rpi.legup.model.elements.PlaceableElement; -public class UnknownTile extends NonPlaceableElement { +public class UnknownTile extends PlaceableElement { public UnknownTile() { super( - "FPIX-UNPL-0002", + "FPIX-ELEM-0003", "Unknown Tile", "A blank tile", "edu/rpi/legup/images/fillapix/tiles/UnknownTile.png"); diff --git a/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/WhiteTile.java b/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/WhiteTile.java index 67065a7e9..b2eedfc09 100644 --- a/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/WhiteTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/WhiteTile.java @@ -5,7 +5,7 @@ public class WhiteTile extends PlaceableElement { public WhiteTile() { super( - "FPIX-PLAC-0002", + "FPIX-ELEM-0004", "White Tile", "The white tile", "edu/rpi/legup/images/fillapix/tiles/WhiteTile.png"); diff --git a/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/fillapix_elements_reference_sheet.txt b/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/fillapix_elements_reference_sheet.txt index 0409fa800..1aece4b97 100644 --- a/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/fillapix_elements_reference_sheet.txt +++ b/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/fillapix_elements_reference_sheet.txt @@ -1,5 +1,4 @@ -FPIX-PLAC-0001 : BlackTile -FPIX-PLAC-0002 : WhiteTile - -FPIX-UNPL-0001 : NumberTile -FPIX-UNPL-0002 : UnknownTile \ No newline at end of file +FPIX-ELEM-0001 : BlackTile +FPIX-ELEM-0002 : NumberTile +FPIX-ELEM-0003 : UnknownTile +FPIX-ELEM-0004 : WhiteTile \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/BlackOrWhiteCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/BlackOrWhiteCaseRule.java index 860a6c011..f0194bd39 100644 --- a/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/BlackOrWhiteCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/BlackOrWhiteCaseRule.java @@ -37,6 +37,9 @@ public CaseBoard getCaseBoard(Board board) { @Override public ArrayList getCases(Board board, PuzzleElement puzzleElement) { ArrayList cases = new ArrayList<>(); + if (puzzleElement == null) { + return cases; + } Board case1 = board.copy(); FillapixCell cell1 = (FillapixCell) case1.getPuzzleElement(puzzleElement); diff --git a/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/SatisfyClueCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/SatisfyClueCaseRule.java index 7db833f76..f8bb2d4f5 100644 --- a/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/SatisfyClueCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/SatisfyClueCaseRule.java @@ -45,6 +45,9 @@ public CaseBoard getCaseBoard(Board board) { @Override public ArrayList getCases(Board board, PuzzleElement puzzleElement) { ArrayList cases = new ArrayList(); + if (puzzleElement == null) { + return cases; + } // get value of cell FillapixBoard fillapixBoard = (FillapixBoard) board.copy(); diff --git a/src/main/java/edu/rpi/legup/puzzle/lightup/LightUp.java b/src/main/java/edu/rpi/legup/puzzle/lightup/LightUp.java index ab95c4658..a73806cd7 100644 --- a/src/main/java/edu/rpi/legup/puzzle/lightup/LightUp.java +++ b/src/main/java/edu/rpi/legup/puzzle/lightup/LightUp.java @@ -47,7 +47,7 @@ public Board generatePuzzle(int difficulty) { * @return true if the given dimensions are valid for Light Up, false otherwise */ public boolean isValidDimensions(int rows, int columns) { - return rows > 0 && columns > 0; + return rows >= 0 && columns >= 0; } /** diff --git a/src/main/java/edu/rpi/legup/puzzle/lightup/LightUpBoard.java b/src/main/java/edu/rpi/legup/puzzle/lightup/LightUpBoard.java index 217ef79a8..21084b8c7 100644 --- a/src/main/java/edu/rpi/legup/puzzle/lightup/LightUpBoard.java +++ b/src/main/java/edu/rpi/legup/puzzle/lightup/LightUpBoard.java @@ -134,12 +134,12 @@ public int getNumAdjLite(LightUpCell cell) { } /** - * Gets the number of adjacent cells that are placable + * Gets the number of adjacent cells that are placeable * * @param cell specified cell - * @return number of adjacent cells that are placable + * @return number of adjacent cells that are placeable */ - public int getNumPlacble(LightUpCell cell) { + public int getNumPlaceable(LightUpCell cell) { int num = 0; Set adjCells = getAdj(cell); for (LightUpCell c : adjCells) { diff --git a/src/main/java/edu/rpi/legup/puzzle/lightup/LightUpCell.java b/src/main/java/edu/rpi/legup/puzzle/lightup/LightUpCell.java index 8adf84cb4..6d890e67b 100644 --- a/src/main/java/edu/rpi/legup/puzzle/lightup/LightUpCell.java +++ b/src/main/java/edu/rpi/legup/puzzle/lightup/LightUpCell.java @@ -16,16 +16,16 @@ public LightUpCell(int valueInt, Point location) { @Override public void setType(Element e, MouseEvent m) { switch (e.getElementID()) { - case "LTUP-PLAC-0001": + case "LTUP-ELEM-0002": this.data = -4; break; - case "LTUP-UNPL-0002": + case "LTUP-ELEM-0001": this.data = -1; break; - case "LTUP-UNPL-0003": + case "LTUP-ELEM-0004": this.data = -2; break; - case "LTUP-UNPL-0001": + case "LTUP-ELEM-0003": switch (m.getButton()) { case MouseEvent.BUTTON1: if (this.data < 0 || this.data > 3) { diff --git a/src/main/java/edu/rpi/legup/puzzle/lightup/elements/BlackTile.java b/src/main/java/edu/rpi/legup/puzzle/lightup/elements/BlackTile.java index 2ddb4f754..eed3795d7 100644 --- a/src/main/java/edu/rpi/legup/puzzle/lightup/elements/BlackTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/lightup/elements/BlackTile.java @@ -1,11 +1,11 @@ package edu.rpi.legup.puzzle.lightup.elements; -import edu.rpi.legup.model.elements.NonPlaceableElement; +import edu.rpi.legup.model.elements.PlaceableElement; -public class BlackTile extends NonPlaceableElement { +public class BlackTile extends PlaceableElement { public BlackTile() { super( - "LTUP-UNPL-0002", + "LTUP-ELEM-0001", "Black Tile", "The black tile", "edu/rpi/legup/images/lightup/black.gif"); diff --git a/src/main/java/edu/rpi/legup/puzzle/lightup/elements/BulbTile.java b/src/main/java/edu/rpi/legup/puzzle/lightup/elements/BulbTile.java index d238baa56..61ebac3d0 100644 --- a/src/main/java/edu/rpi/legup/puzzle/lightup/elements/BulbTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/lightup/elements/BulbTile.java @@ -5,7 +5,7 @@ public class BulbTile extends PlaceableElement { public BulbTile() { super( - "LTUP-PLAC-0001", + "LTUP-ELEM-0002", "Bulb Tile", "The bulb tile", "edu/rpi/legup/images/lightup/light.png"); diff --git a/src/main/java/edu/rpi/legup/puzzle/lightup/elements/NumberTile.java b/src/main/java/edu/rpi/legup/puzzle/lightup/elements/NumberTile.java index ae314a4cf..26f9be46c 100644 --- a/src/main/java/edu/rpi/legup/puzzle/lightup/elements/NumberTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/lightup/elements/NumberTile.java @@ -1,15 +1,15 @@ package edu.rpi.legup.puzzle.lightup.elements; -import edu.rpi.legup.model.elements.NonPlaceableElement; +import edu.rpi.legup.model.elements.PlaceableElement; -public class NumberTile extends NonPlaceableElement { +public class NumberTile extends PlaceableElement { int object_number; // Follow the default format and resolves the NoSuchMethod error public NumberTile() { super( - "LTUP-UNPL-0001", + "LTUP-ELEM-0003", "Number Tile", "The number tile", "edu/rpi/legup/images/lightup/1.gif"); @@ -17,7 +17,7 @@ public NumberTile() { public NumberTile(int num) { super( - "LTUP-UNPL-0001", + "LTUP-ELEM-0003", "Number Tile", "The number tile", "edu/rpi/legup/images/lightup/" + num + ".gif"); diff --git a/src/main/java/edu/rpi/legup/puzzle/lightup/elements/UnknownTile.java b/src/main/java/edu/rpi/legup/puzzle/lightup/elements/UnknownTile.java index 24d420fe8..a724be600 100644 --- a/src/main/java/edu/rpi/legup/puzzle/lightup/elements/UnknownTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/lightup/elements/UnknownTile.java @@ -1,11 +1,11 @@ package edu.rpi.legup.puzzle.lightup.elements; -import edu.rpi.legup.model.elements.NonPlaceableElement; +import edu.rpi.legup.model.elements.PlaceableElement; -public class UnknownTile extends NonPlaceableElement { +public class UnknownTile extends PlaceableElement { public UnknownTile() { super( - "LTUP-UNPL-0003", + "LTUP-ELEM-0004", "Unknown Tile", "A blank tile", "edu/rpi/legup/images/lightup/UnknownTile.png"); diff --git a/src/main/java/edu/rpi/legup/puzzle/lightup/elements/lightup_elements_reference_sheet.txt b/src/main/java/edu/rpi/legup/puzzle/lightup/elements/lightup_elements_reference_sheet.txt new file mode 100644 index 000000000..93c97de1c --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/lightup/elements/lightup_elements_reference_sheet.txt @@ -0,0 +1,4 @@ +LTUP-ELEM-0001 : BlackTile +LTUP-ELEM-0002 : BulbTile +LTUP-ELEM-0003 : NumberTile +LTUP-ELEM-0004 : UnknownTile \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/lightup/rules/LightOrEmptyCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/lightup/rules/LightOrEmptyCaseRule.java index 4ba754731..53efb6587 100644 --- a/src/main/java/edu/rpi/legup/puzzle/lightup/rules/LightOrEmptyCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/lightup/rules/LightOrEmptyCaseRule.java @@ -44,6 +44,10 @@ public CaseBoard getCaseBoard(Board board) { @Override public ArrayList getCases(Board board, PuzzleElement puzzleElement) { ArrayList cases = new ArrayList<>(); + if (puzzleElement == null) { + return cases; + } + Board case1 = board.copy(); PuzzleElement data1 = case1.getPuzzleElement(puzzleElement); data1.setData(-4); diff --git a/src/main/java/edu/rpi/legup/puzzle/lightup/rules/SatisfyNumberCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/lightup/rules/SatisfyNumberCaseRule.java index 490122874..f73a34b2d 100644 --- a/src/main/java/edu/rpi/legup/puzzle/lightup/rules/SatisfyNumberCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/lightup/rules/SatisfyNumberCaseRule.java @@ -47,6 +47,11 @@ public CaseBoard getCaseBoard(Board board) { */ @Override public ArrayList getCases(Board board, PuzzleElement puzzleElement) { + ArrayList cases = new ArrayList<>(); + if (puzzleElement == null) { + return cases; + } + LightUpBoard lightUpBoard = (LightUpBoard) board; LightUpCell cell = (LightUpCell) puzzleElement; Point loc = cell.getLocation(); @@ -96,7 +101,6 @@ public ArrayList getCases(Board board, PuzzleElement puzzleElement) { } } - ArrayList cases = new ArrayList<>(); if (numNeeded == 0) { return cases; } diff --git a/src/main/java/edu/rpi/legup/puzzle/lightup/rules/TooFewBulbsContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/lightup/rules/TooFewBulbsContradictionRule.java index 8cf68e570..de1f85edc 100644 --- a/src/main/java/edu/rpi/legup/puzzle/lightup/rules/TooFewBulbsContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/lightup/rules/TooFewBulbsContradictionRule.java @@ -36,7 +36,7 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { } int bulbs = lightUpBoard.getNumAdj(cell, LightUpCellType.BULB); - int placeable = lightUpBoard.getNumPlacble(cell); + int placeable = lightUpBoard.getNumPlaceable(cell); if (bulbs + placeable < cell.getData()) { return null; diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/BombTile.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/BombTile.java index 78a5d320c..cd5577eeb 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/BombTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/BombTile.java @@ -1,8 +1,8 @@ package edu.rpi.legup.puzzle.minesweeper.elements; -import edu.rpi.legup.model.elements.NonPlaceableElement; +import edu.rpi.legup.model.elements.PlaceableElement; -public class BombTile extends NonPlaceableElement { +public class BombTile extends PlaceableElement { public BombTile() { super( "MINE-UNPL-0001", diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/UnsetTile.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/UnsetTile.java index 447e2840c..6cfc34c8d 100644 --- a/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/UnsetTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/UnsetTile.java @@ -1,8 +1,8 @@ package edu.rpi.legup.puzzle.minesweeper.elements; -import edu.rpi.legup.model.elements.NonPlaceableElement; +import edu.rpi.legup.model.elements.PlaceableElement; -public class UnsetTile extends NonPlaceableElement { +public class UnsetTile extends PlaceableElement { public UnsetTile() { super( diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeCell.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeCell.java index c6cd2c64e..1e0e85ed8 100644 --- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeCell.java +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeCell.java @@ -46,13 +46,13 @@ public NurikabeType getType() { @Override public void setType(Element e, MouseEvent m) { switch (e.getElementID()) { - case "NURI-PLAC-0001": + case "NURI-ELEM-0001": this.data = -1; break; - case "NURI-PLAC-0002": + case "NURI-ELEM-0004": this.data = 0; break; - case "NURI-UNPL-0001": + case "NURI-ELEM-0002": switch (m.getButton()) { case MouseEvent.BUTTON1: if (this.data <= 0 || this.data > 8) { diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeExporter.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeExporter.java index 23efd4724..e01821639 100644 --- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeExporter.java +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeExporter.java @@ -10,6 +10,13 @@ public NurikabeExporter(Nurikabe nurikabe) { super(nurikabe); } + /** + * Generates an XML element for the nurikabe puzzle board, including its dimensions and the + * state of each cell. Nurikabe cells that are not empty are included in the XML. + * + * @param newDocument The XML document to which the board element belongs. + * @return The XML element representing the board. + */ @Override protected org.w3c.dom.Element createBoardElement(Document newDocument) { NurikabeBoard board; diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/BlackTile.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/BlackTile.java index 459a809e0..a7972b9b2 100644 --- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/BlackTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/BlackTile.java @@ -5,7 +5,7 @@ public class BlackTile extends PlaceableElement { public BlackTile() { super( - "NURI-PLAC-0001", + "NURI-ELEM-0001", "Black Tile", "The black tile", "edu/rpi/legup/images/nurikabe/tiles/BlackTile.png"); diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/NumberTile.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/NumberTile.java index 475b278da..2015d990b 100644 --- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/NumberTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/NumberTile.java @@ -1,13 +1,13 @@ package edu.rpi.legup.puzzle.nurikabe.elements; -import edu.rpi.legup.model.elements.NonPlaceableElement; +import edu.rpi.legup.model.elements.PlaceableElement; -public class NumberTile extends NonPlaceableElement { +public class NumberTile extends PlaceableElement { private int object_num; public NumberTile() { super( - "NURI-UNPL-0001", + "NURI-ELEM-0002", "Number Tile", "A numbered tile", "edu/rpi/legup/images/nurikabe/tiles/NumberTile.png"); diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/UnknownTile.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/UnknownTile.java index 85d47e208..8a18c80cc 100644 --- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/UnknownTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/UnknownTile.java @@ -1,11 +1,11 @@ package edu.rpi.legup.puzzle.nurikabe.elements; -import edu.rpi.legup.model.elements.NonPlaceableElement; +import edu.rpi.legup.model.elements.PlaceableElement; -public class UnknownTile extends NonPlaceableElement { +public class UnknownTile extends PlaceableElement { public UnknownTile() { super( - "NURI-UNPL-0002", + "NURI-ELEM-0003", "Unknown Tile", "A blank tile", "edu/rpi/legup/images/nurikabe/tiles/UnknownTile.png"); diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/WhiteTile.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/WhiteTile.java index 35eb63b81..ae07c6d76 100644 --- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/WhiteTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/WhiteTile.java @@ -5,7 +5,7 @@ public class WhiteTile extends PlaceableElement { public WhiteTile() { super( - "NURI-PLAC-0002", + "NURI-ELEM-0004", "White Tile", "The white tile", "edu/rpi/legup/images/nurikabe/tiles/WhiteTile.png"); diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/nurikabe_elements_reference_sheet.txt b/src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/nurikabe_elements_reference_sheet.txt new file mode 100644 index 000000000..667972fd6 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/nurikabe_elements_reference_sheet.txt @@ -0,0 +1,4 @@ +NURI-ELEM-0001 : BlackTile +NURI-ELEM-0002 : NumberTile +NURI-ELEM-0003 : UnknownTile +NURI-ELEM-0004 : WhiteTile diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/BlackOrWhiteCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/BlackOrWhiteCaseRule.java index ac0ab6df6..1c87d5cfa 100644 --- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/BlackOrWhiteCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/BlackOrWhiteCaseRule.java @@ -24,7 +24,7 @@ public BlackOrWhiteCaseRule() { /** * Checks whether the {@link TreeTransition} logically follows from the parent node using this - * rule. This method is the one that should overridden in child classes. + * rule. This method is the one that should be overridden in child classes. * * @param transition transition to check * @return null if the child node logically follow from the parent node, otherwise error message @@ -84,6 +84,10 @@ public CaseBoard getCaseBoard(Board board) { @Override public ArrayList getCases(Board board, PuzzleElement puzzleElement) { ArrayList cases = new ArrayList<>(); + if (puzzleElement == null) { + return cases; + } + Board case1 = board.copy(); PuzzleElement data1 = case1.getPuzzleElement(puzzleElement); data1.setData(NurikabeType.WHITE.toValue()); diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/FinishRoomCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/FinishRoomCaseRule.java index 24a261ec9..025212d96 100644 --- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/FinishRoomCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/FinishRoomCaseRule.java @@ -27,15 +27,16 @@ public FinishRoomCaseRule() { super( "NURI-CASE-0002", "Finish Room", - "Room can be finished in up to five ways", + "Room can be finished in up to nine ways", "edu/rpi/legup/images/nurikabe/cases/FinishRoom.png"); - this.MAX_CASES = 5; - this.MIN_CASES = 2; + this.MAX_CASES = 9; + this.MIN_CASES = 1; + this.uniqueCases = new HashSet<>(); } /** * Checks whether the {@link TreeTransition} logically follows from the parent node using this - * rule. This method is the one that should overridden in child classes. + * rule. This method is the one that should have overridden in child classes. * * @param transition transition to check * @return null if the child node logically follow from the parent node, otherwise error message @@ -44,18 +45,18 @@ public FinishRoomCaseRule() { public String checkRuleRaw(TreeTransition transition) { NurikabeBoard destBoardState = (NurikabeBoard) transition.getBoard(); List childTransitions = transition.getParents().get(0).getChildren(); - if (childTransitions.size() > 5) { + if (childTransitions.size() > MAX_CASES) { return super.getInvalidUseOfRuleMessage() - + ": This case rule must have 5 or less children."; + + ": This case rule must have 9 or less children."; } - if (childTransitions.size() < 2) { + if (childTransitions.size() < MIN_CASES) { return super.getInvalidUseOfRuleMessage() - + ": This case rule must have 2 or more children."; + + ": This case rule must have 1 or more children."; } if (childTransitions.size() != legitCases) { return super.getInvalidUseOfRuleMessage() + ": Cases can not be removed from the branch."; - } // stops user from deleting 1 or mose generated cases and still having path show as green + } // stops user from deleting 1 or more generated cases and still having path show as green Set locations = new HashSet<>(); for (TreeTransition t1 : childTransitions) { locations.add( @@ -100,14 +101,8 @@ public CaseBoard getCaseBoard(Board board) { // if found another number tile and it's data is different from the element // we're working with if ((d.getType() == NurikabeType.NUMBER) - && !(d.getData() - .equals( - ((NurikabeCell) element) - .getData()))) { // if found another number tile - // and it's data is different - // than the element we're - // working with - only = false; // set only to false + && !(d.getData().equals(((NurikabeCell) element).getData()))) { + only = false; } } // if size of region is 1 less than the number block and the number block is only @@ -130,6 +125,10 @@ public CaseBoard getCaseBoard(Board board) { @Override public ArrayList getCases(Board board, PuzzleElement puzzleElement) { ArrayList cases = new ArrayList<>(); // makes array list of cases + if (puzzleElement == null) { + return cases; + } + NurikabeBoard nuriBoard = (NurikabeBoard) board.copy(); // nurikabe board to edit NurikabeCell numberCell = nuriBoard.getCell( @@ -231,23 +230,9 @@ private void generateCases( break; } } - if (!alreadyIn) { // if point wasn't already in - Board casey = - nuriBoard.copy(); // copy the current board with white tile - // changed - PuzzleElement datacasey = - curr; // gets changed white tile as a puzzle element - datacasey.setData( - NurikabeType.WHITE - .toValue()); // ensure set to white, probably redundant - casey.addModifiedData(datacasey); // ensure confirmed white change - regions = - NurikabeUtilities.getNurikabeRegions( - nuriBoard); // update regions - cases.add(casey); // add this case to list of cases - locations.add( - here); // add location of new white tile to list of locations so - // that we don't accidentally add it again later + if (unique) { + caseBoard.addModifiedData(newCell); + cases.add(caseBoard); } } else if (newRoomSet.size() < filledRoomSize) { generateCases( @@ -301,14 +286,10 @@ private boolean touchesDifferentRoom( || (adjacentPoint.x != origPoint.x || adjacentPoint.y != origPoint.y)) { return true; } - curr.setData(NurikabeType.UNKNOWN.toValue()); // set cell type back to unknown - nuriBoard.addModifiedData(curr); // confirms change back to unknown - regions = NurikabeUtilities.getNurikabeRegions(nuriBoard); // updates regions } } - legitCases = cases.size(); } - return cases; + return false; } /** diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/ShortTruthTableCell.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/ShortTruthTableCell.java index 75bba369f..ffd7c491d 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/ShortTruthTableCell.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/ShortTruthTableCell.java @@ -135,22 +135,22 @@ public void setType(Element e, MouseEvent m) { } // Red Element - if (e.getElementID().equals("STTT-PLAC-0002")) { + if (e.getElementID().equals("STTT-ELEM-0004")) { this.data = ShortTruthTableCellType.FALSE; } // Green Element else { - if (e.getElementID().equals("STTT-PLAC-0001")) { + if (e.getElementID().equals("STTT-ELEM-0002")) { this.data = ShortTruthTableCellType.TRUE; } // Unknown Element else { - if (e.getElementID().equals("STTT-PLAC-0003")) { + if (e.getElementID().equals("STTT-ELEM-0005")) { this.data = ShortTruthTableCellType.UNKNOWN; } // Argument Element else { - if (e.getElementID().equals("STTT-UNPL-0001")) { + if (e.getElementID().equals("STTT-ELEM-0001")) { // Prevents non-argument symbols from being changed if (!(this.symbol >= 'A' && this.symbol <= 'Z')) { return; @@ -172,7 +172,7 @@ public void setType(Element e, MouseEvent m) { } // And/Or Element else { - if (e.getElementID().equals("STTT-UNPL-0002")) { + if (e.getElementID().equals("STTT-ELEM-0003")) { if (m.getButton() == MouseEvent.BUTTON1) { if (this.symbol == '^') { this.symbol = '|'; diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/ArgumentElement.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/ArgumentElement.java index 9294fba4e..912fd2672 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/ArgumentElement.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/ArgumentElement.java @@ -1,11 +1,11 @@ package edu.rpi.legup.puzzle.shorttruthtable.elements; -import edu.rpi.legup.model.elements.NonPlaceableElement; +import edu.rpi.legup.model.elements.PlaceableElement; -public class ArgumentElement extends NonPlaceableElement { +public class ArgumentElement extends PlaceableElement { public ArgumentElement() { super( - "STTT-UNPL-0001", + "STTT-ELEM-0001", "Argument Element", "Argument of logic statement element", "edu/rpi/legup/images/shorttruthtable/tiles/LetterTile.png"); diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/GreenElement.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/GreenElement.java index 783186baa..56221fef3 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/GreenElement.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/GreenElement.java @@ -5,7 +5,7 @@ public class GreenElement extends PlaceableElement { public GreenElement() { super( - "STTT-PLAC-0001", + "STTT-ELEM-0002", "Green Element", "A green tile to set certain tiles to true", "edu/rpi/legup/images/shorttruthtable/tiles/GreenTile.png"); diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/LogicSymbolElement.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/LogicSymbolElement.java index 5fed4b1df..b82ebc2cb 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/LogicSymbolElement.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/LogicSymbolElement.java @@ -1,11 +1,11 @@ package edu.rpi.legup.puzzle.shorttruthtable.elements; -import edu.rpi.legup.model.elements.NonPlaceableElement; +import edu.rpi.legup.model.elements.PlaceableElement; -public class LogicSymbolElement extends NonPlaceableElement { +public class LogicSymbolElement extends PlaceableElement { public LogicSymbolElement() { super( - "STTT-UNPL-0002", + "STTT-ELEM-0003", "Logic Symbol Element", "Logic symbol element", "edu/rpi/legup/images/shorttruthtable/tiles/ConditionalBiconditionalTile.png"); diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/RedElement.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/RedElement.java index e2a589b65..2114e62ec 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/RedElement.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/RedElement.java @@ -5,7 +5,7 @@ public class RedElement extends PlaceableElement { public RedElement() { super( - "STTT-PLAC-0002", + "STTT-ELEM-0004", "Red Element", "A red tile to set certain tiles to false", "edu/rpi/legup/images/shorttruthtable/tiles/RedTile.png"); diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/UnknownElement.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/UnknownElement.java index d475bc05d..52b54f202 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/UnknownElement.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/UnknownElement.java @@ -5,7 +5,7 @@ public class UnknownElement extends PlaceableElement { public UnknownElement() { super( - "STTT-PLAC-0003", + "STTT-ELEM-0005", "Unknown Element", "A blank tile", "edu/rpi/legup/images/shorttruthtable/tiles/UnknownTile.png"); diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/shorttruthtable_elements_reference_sheet b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/shorttruthtable_elements_reference_sheet index 471631553..c5421169f 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/shorttruthtable_elements_reference_sheet +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/shorttruthtable_elements_reference_sheet @@ -1,6 +1,5 @@ -STTT-UNPL-0001 : ArgumentElement -STTT-UNPL-0002 : ConditionalBiconditionalElement - -STTT-PLAC-0001 : GreenElement -STTT-PLAC-0002 : RedElement -STTT-PLAC-0003 : UnknownElement \ No newline at end of file +STTT-ELEM-0001 : ArgumentElement +STTT-ELEM-0002 : GreenElement +STTT-ELEM-0003 : LogicSymbolElement +STTT-ELEM-0004 : RedElement +STTT-ELEM-0005 : UnknownElement \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRuleAtomic.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRuleAtomic.java index 58d2068b2..22b49fd77 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRuleAtomic.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRuleAtomic.java @@ -44,6 +44,9 @@ public CaseBoard getCaseBoard(Board board) { @Override public ArrayList getCases(Board board, PuzzleElement puzzleElement) { ArrayList cases = new ArrayList<>(); + if (puzzleElement == null) { + return cases; + } Board case1 = board.copy(); PuzzleElement data1 = case1.getPuzzleElement(puzzleElement); diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRule_GenericStatement.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRule_GenericStatement.java index 99f771246..8aeb51a46 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRule_GenericStatement.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRule_GenericStatement.java @@ -85,6 +85,11 @@ public CaseBoard getCaseBoard(Board board) { @SuppressWarnings("unchecked") @Override public ArrayList getCases(Board board, PuzzleElement puzzleElement) { + + if (puzzleElement == null) { + return new ArrayList(); + } + ShortTruthTableBoard sttBoard = ((ShortTruthTableBoard) board); ShortTruthTableCell cell = sttBoard.getCellFromElement(puzzleElement); diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/Skyscrapers.java b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/Skyscrapers.java index df5ba78a3..44f416cef 100644 --- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/Skyscrapers.java +++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/Skyscrapers.java @@ -46,7 +46,7 @@ public Board generatePuzzle(int difficulty) { * @return true if the given dimensions are valid for Skyscrapers, false otherwise */ public boolean isValidDimensions(int rows, int columns) { - return rows >= 4 && rows == columns; + return rows >= 3 && rows == columns; } /** diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersBoard.java b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersBoard.java index 4cd09b254..0fc133786 100644 --- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersBoard.java +++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersBoard.java @@ -209,7 +209,7 @@ public void setCell(int x, int y, Element e, MouseEvent m) { SkyscrapersClue clue = this.getClue(x, y); if (e == null) return; if (clue != null) { - if (!e.getElementID().equals("SKYS-UNPL-0003")) { + if (!e.getElementID().equals("SKYS-ELEM-0001")) { return; } @@ -217,10 +217,10 @@ public void setCell(int x, int y, Element e, MouseEvent m) { if (clue.getData() < dimension.height) { clue.setData(clue.getData() + 1); } else { - clue.setData(0); + clue.setData(1); } } else { - if (clue.getData() > 0) { + if (clue.getData() > 1) { clue.setData(clue.getData() - 1); } else { clue.setData(dimension.height); diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersCell.java b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersCell.java index 1cf9a357b..9e7283b20 100644 --- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersCell.java +++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersCell.java @@ -27,10 +27,10 @@ public SkyscrapersType getType() { @Override public void setType(Element e, MouseEvent m) { switch (e.getElementID()) { - case "SKYS-UNPL-0001": + case "SKYS-ELEM-0002": this.data = 0; break; - case "SKYS-UNPL-0002": + case "SKYS-ELEM-0001": switch (m.getButton()) { case MouseEvent.BUTTON1: if (this.data <= 0 || this.data >= this.max) { diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersClueView.java b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersClueView.java index 4c75f0695..cfb3388ff 100644 --- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersClueView.java +++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersClueView.java @@ -25,11 +25,11 @@ public SkyscrapersClue getPuzzleElement() { @Override public void draw(Graphics2D graphics2D) { drawElement(graphics2D); + if (this.isHover()) { + drawHover(graphics2D); + } if (this.isShowCasePicker() && this.isCaseRulePickable()) { drawCase(graphics2D); - if (this.isHover()) { - drawHover(graphics2D); - } } } diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/ClueTile.java b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/ClueTile.java deleted file mode 100644 index 64c9033e6..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/ClueTile.java +++ /dev/null @@ -1,14 +0,0 @@ -package edu.rpi.legup.puzzle.skyscrapers.elements; - -import edu.rpi.legup.model.elements.NonPlaceableElement; - -public class ClueTile extends NonPlaceableElement { - - public ClueTile() { - super( - "SKYS-UNPL-0003", - "Clue Tile", - "Clue Updater", - "edu/rpi/legup/images/skyscrapers/tiles/ClueTile.png"); - } -} diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/NumberTile.java b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/NumberTile.java index 4d6b37c9a..f60e5fe8b 100644 --- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/NumberTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/NumberTile.java @@ -1,11 +1,11 @@ package edu.rpi.legup.puzzle.skyscrapers.elements; -import edu.rpi.legup.model.elements.NonPlaceableElement; +import edu.rpi.legup.model.elements.PlaceableElement; -public class NumberTile extends NonPlaceableElement { +public class NumberTile extends PlaceableElement { public NumberTile() { super( - "SKYS-UNPL-0002", + "SKYS-ELEM-0001", "Number Tile", "A numbered tile", "edu/rpi/legup/images/skyscrapers/tiles/ClueTile.png"); diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/UnknownTile.java b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/UnknownTile.java index 2fb21193a..07f6a1238 100644 --- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/UnknownTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/UnknownTile.java @@ -1,11 +1,11 @@ package edu.rpi.legup.puzzle.skyscrapers.elements; -import edu.rpi.legup.model.elements.NonPlaceableElement; +import edu.rpi.legup.model.elements.PlaceableElement; -public class UnknownTile extends NonPlaceableElement { +public class UnknownTile extends PlaceableElement { public UnknownTile() { super( - "SKYS-UNPL-0001", + "SKYS-ELEM-0002", "Unknown", "A blank tile", "edu/rpi/legup/images/skyscrapers/tiles/UnknownTile.png"); diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/skyscrapers_elements_reference_sheet.txt b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/skyscrapers_elements_reference_sheet.txt index 604e1824e..14e76a29d 100644 --- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/skyscrapers_elements_reference_sheet.txt +++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/skyscrapers_elements_reference_sheet.txt @@ -1,3 +1,2 @@ -SKYS-UNPL-0001: Unknown Tile -SKYS-UNPL-0002: Number Tile -SKYS-UNPL-0003: Clue "Tile" \ No newline at end of file +SKYS-ELEM-0001: NumberTile +SKYS-ELEM-0002: UnknownTile \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/CellForNumberCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/CellForNumberCaseRule.java index 45bdadea3..b48962c41 100644 --- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/CellForNumberCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/CellForNumberCaseRule.java @@ -61,6 +61,9 @@ public CaseBoard getCaseBoard(Board board) { public ArrayList getCasesFor(Board board, PuzzleElement puzzleElement, Integer number) { ArrayList cases = new ArrayList<>(); + if (puzzleElement == null) { + return cases; + } SkyscrapersClue clue = (SkyscrapersClue) puzzleElement; SkyscrapersBoard skyscrapersboard = (SkyscrapersBoard) board; diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/NumberForCellCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/NumberForCellCaseRule.java index 145dd6ee2..4f8e1df6b 100644 --- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/NumberForCellCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/NumberForCellCaseRule.java @@ -47,6 +47,9 @@ public CaseBoard getCaseBoard(Board board) { @Override public ArrayList getCases(Board board, PuzzleElement puzzleElement) { ArrayList cases = new ArrayList<>(); + if (puzzleElement == null) { + return cases; + } SkyscrapersCell cell = (SkyscrapersCell) puzzleElement; SkyscrapersBoard skyscrapersboard = (SkyscrapersBoard) board; diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/allfiles.txt b/src/main/java/edu/rpi/legup/puzzle/starbattle/allfiles.txt deleted file mode 100644 index 5a9ec0f0a..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/allfiles.txt +++ /dev/null @@ -1,235 +0,0 @@ -//StarBattle.java - -package edu.rpi.legup.puzzle.starbattle; - -import edu.rpi.legup.model.Puzzle; -import edu.rpi.legup.model.gameboard.Board; - -public class StarBattle extends Puzzle { - public StarBattle() { - super(); - this.name = "StarBattle"; - - this.importer = new StarBattleImporter(this); - this.exporter = new StarBattleExporter(this); - - this.factory = new StarBattleCellFactory(); - } - - @Override - public void initializeView() { - } - - @Override - public Board generatePuzzle(int difficulty) { - return null; - } - - @Override - public boolean isBoardComplete(Board board) { - return true; - } - - @Override - public void onBoardChange(Board board) { - } -} - -//StarBattleBoard.java - -package edu.rpi.legup.puzzle.lightup; - -import edu.rpi.legup.model.gameboard.GridBoard; -import edu.rpi.legup.model.gameboard.PuzzleElement; - -import java.awt.*; -import java.util.HashSet; -import java.util.Set; - -public class StarBattleBoard extends GridBoard { - - private int size; - private vector group_sizes; - - /** - * StarBattleBoard Constructor - create a new Star Battle board - * - * @param size size of one side of the star battle board - */ - - public StarBattleBoard(int size) { - super(size, size); - group_sizes = vector(size); - } - - @Override - public StarBattleCell getCell(int x, int y) { - return (StarBattleCell) super.getCell(x, y); - } - - -} - -//StarBattleCell.java - -package edu.rpi.legup.puzzle.starbattle; - -import edu.rpi.legup.model.gameboard.GridCell; - -import java.awt.*; -import java.util.HashSet; -import java.util.Set; - -public class StarBattleCell extends GridCell { - private int groupIndex; - private int max; - - /** - * StarBattleCell Constructor - creates a new StarBattle cell to hold the puzzleElement - * - * @param valueInt value of the star battle cell denoting its state - * @param location location of the cell on the board - * @param size size of the star battle cell - */ - public StarBattleCell(int value, Point location, int groupIndex, int size) { - super(value, location); - this.groupIndex = groupIndex; - this.max = size; - } - - @Override - public void setType(Element e, MouseEvent m) { - switch (e.getElementID()) { - case "SBUP-PLAC-0001": - this.data = -3; - break; - case "SBUP-PLAC-0002": - this.data = -2; - break; - case "SBUP-PLAC-0003": - this.data = -1; - break; - case "SBUP-UNPL-0001"://Not sure how button events work - switch (m.getButton()){ - case MouseEvent.BUTTON1: - if (this.data < 0 || this.data > 3) { - this.data = 0; - } - else { - this.data = this.data + 1; - } - break; - case MouseEvent.BUTTON3: - if (this.data > 0) { - this.data = this.data - 1; - } - else { - this.data = 3;//Unsure - } - break; - } - break; - } - } - - public LightUpCellType getType() { - switch (data) { - case -3: - return LightUpCellType.UNKNOWN; - case -2: - return LightUpCellType.STAR; - case -1: - return LightUpCellType.BLACK; - default: - if (data >= 0) { - return StarBattleCellType.WHITE; - } - } - return null; - } - - /** - * Gets the region index of the cell - * - * @return group index of the cell - */ - public int getGroupIndex() { - return groupIndex; - } - - /** - * Gets the size of the cell - * - * @return size of the cell - */ - - public int getMax() { - return max; - } - -} - -//StarBattleCellController.java - -package edu.rpi.legup.puzzle.starbattle; - -import edu.rpi.legup.controller.ElementController; -import edu.rpi.legup.model.gameboard.PuzzleElement; - -import java.awt.event.MouseEvent; - -public class StarBattleCellController extends ElementController { - @Override - public void changeCell(MouseEvent e, PuzzleElement data) { - StarBattleCell cell = (StarBattleCell) data; - if (e.getButton() == MouseEvent.BUTTON1) { - if (e.isControlDown()) { - this.boardView.getSelectionPopupMenu().show(boardView, this.boardView.getCanvas().getX() + e.getX(), this.boardView.getCanvas().getY() + e.getY()); - } - else { - if (cell.getData() == 0) { - data.setData(-3); - } - else { - data.setData(cell.getData() + 1); - } - } - } - else { - if (e.getButton() == MouseEvent.BUTTON3) { - if (cell.getData() == -3) { - data.setData(0); - } - else { - data.setData(cell.getData() - 1); - } - } - } - } -} - -//StarBattleCellFactory.java - - - -//StarBattleCellType.java -package edu.rpi.legup.puzzle.starbattle; - -public enum StarBattleType { - UNKNOWN(-3), STAR(-2), BLACK(-1), WHITE(0); - - public int value; - - StarBattleCell(int value) { - this.value = value; - } -} - -//StarBattleExporter.java -//StarBattleImporter.java -//StarBattleView.java - -How to run Legup: - -./gradlew build -Java -jar build/libs/Legup.jar \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/elements/BlackTile.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/elements/BlackTile.java index 99f42886e..c4bbf7297 100644 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/elements/BlackTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/elements/BlackTile.java @@ -1,8 +1,8 @@ package edu.rpi.legup.puzzle.starbattle.elements; -import edu.rpi.legup.model.elements.NonPlaceableElement; +import edu.rpi.legup.model.elements.PlaceableElement; -public class BlackTile extends NonPlaceableElement { +public class BlackTile extends PlaceableElement { public BlackTile() { super( "STBL-PLAC-0002", diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/elements/StarTile.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/elements/StarTile.java index 13ada3f4d..793d4dbeb 100644 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/elements/StarTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/elements/StarTile.java @@ -1,8 +1,8 @@ package edu.rpi.legup.puzzle.starbattle.elements; -import edu.rpi.legup.model.elements.NonPlaceableElement; +import edu.rpi.legup.model.elements.PlaceableElement; -public class StarTile extends NonPlaceableElement { +public class StarTile extends PlaceableElement { public StarTile() { super( "STBL-PLAC-0001", diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/elements/UnknownTile.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/elements/UnknownTile.java index 425fb5d5e..30921de8d 100644 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/elements/UnknownTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/elements/UnknownTile.java @@ -1,8 +1,8 @@ package edu.rpi.legup.puzzle.starbattle.elements; -import edu.rpi.legup.model.elements.NonPlaceableElement; +import edu.rpi.legup.model.elements.PlaceableElement; -public class UnknownTile extends NonPlaceableElement { +public class UnknownTile extends PlaceableElement { public UnknownTile() { super( "STBL-UNPL-0001", diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/elements/starbattle_elements_reference_sheet.txt b/src/main/java/edu/rpi/legup/puzzle/starbattle/elements/starbattle_elements_reference_sheet.txt new file mode 100644 index 000000000..82352bd04 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/elements/starbattle_elements_reference_sheet.txt @@ -0,0 +1,4 @@ +STBL-ELEM-0001 : BlackTile +STBL-ELEM-0002 : StarTile +STBL-ELEM-0003 : UnknownTile +STBL-ELEM-0004 : WhiteTile \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/StarOrEmptyCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/StarOrEmptyCaseRule.java index df900dcd5..efd86bd7b 100644 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/StarOrEmptyCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/StarOrEmptyCaseRule.java @@ -84,6 +84,10 @@ public CaseBoard getCaseBoard(Board board) { @Override public ArrayList getCases(Board board, PuzzleElement puzzleElement) { ArrayList cases = new ArrayList<>(); + if (puzzleElement == null) { + return cases; + } + Board case1 = board.copy(); PuzzleElement data1 = case1.getPuzzleElement(puzzleElement); data1.setData(StarBattleCellType.STAR.value); diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/starbattle_reference_sheet.txt b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/starbattle_reference_sheet.txt deleted file mode 100644 index f18965fd6..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/starbattle_reference_sheet.txt +++ /dev/null @@ -1,19 +0,0 @@ -Case Rules: -Add Star: STBL-CASE-0001 -Star or Empty: STBL-CASE-0002 - -Basic Rules: -Blackout: STBL-BASC-0001 -Columns Within Regions: STBL-BASC-0002 -Columns Within Rows: STBL-BASC-0003 -Finish With Stars: STBL-BASC-0004 -Regions Within Columns: STBL-BASC-0005 -Regions Within Rows: STBL-BASC-0006 -Rows Within Columns: STBL-BASC-0007 -Rows Within Regions: STBL-BASC-0008 -Surround Star: STBL-BASC-0009 - -Contradiction Rules: -Too Many Stars: STBL-CONT-0001 -Too Few Stars: STBL-CONT-0002 -Clashing Orbit: STBL-CONT-0003 \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/ModelSudokuBoard.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/ModelSudokuBoard.java new file mode 100644 index 000000000..f7893ca32 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/ModelSudokuBoard.java @@ -0,0 +1,17 @@ +package edu.rpi.legup.puzzle.sudoku; + +public class ModelSudokuBoard { + public int getModelRegionNumbers(int index) { + int columnMod = index % 3 + 1; + int rowMod = ((index / 9) % 3) * 3; + return columnMod + rowMod; + } + + public int getModelRowNumbers(int index) { + return index % 9 + 1; + } + + public int getModelColumnNumbers(int index) { + return index / 9 + 1; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/PossibleNumberCaseBoard.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/PossibleNumberCaseBoard.java index 0b6971235..c5f9eec2a 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/PossibleNumberCaseBoard.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/PossibleNumberCaseBoard.java @@ -2,7 +2,7 @@ import edu.rpi.legup.model.gameboard.CaseBoard; import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.puzzle.sudoku.rules.PossibleNumberCaseRule; +import edu.rpi.legup.puzzle.sudoku.rules.PossibleCellsForNumberRegionCaseRule; import java.awt.event.MouseEvent; import java.util.HashSet; import java.util.Set; @@ -15,7 +15,7 @@ public class PossibleNumberCaseBoard extends CaseBoard { private Set pickableCols; public PossibleNumberCaseBoard( - SudokuBoard baseBoard, PossibleNumberCaseRule caseRule, SudokuCell cell) { + SudokuBoard baseBoard, PossibleCellsForNumberRegionCaseRule caseRule, SudokuCell cell) { super(baseBoard, caseRule); this.cell = cell; this.pickableRegions = new HashSet<>(); diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/Sudoku.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/Sudoku.java index 877c92665..c27269536 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/Sudoku.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/Sudoku.java @@ -29,6 +29,8 @@ public BoardView getBoardView() { @Override public void initializeView() { boardView = new SudokuView((SudokuBoard) currentBoard); + boardView.setBoard(currentBoard); + addBoardListener(boardView); } /** diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuCell.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuCell.java index da009a255..75e5820a0 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuCell.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuCell.java @@ -1,7 +1,9 @@ package edu.rpi.legup.puzzle.sudoku; +import edu.rpi.legup.model.elements.Element; import edu.rpi.legup.model.gameboard.GridCell; import java.awt.*; +import java.awt.event.MouseEvent; import java.util.HashSet; import java.util.Set; diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuCellController.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuCellController.java index 9b24f13da..bcad1a0ce 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuCellController.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuCellController.java @@ -8,7 +8,7 @@ public class SudokuCellController extends ElementController { @Override public void changeCell(MouseEvent e, PuzzleElement data) { SudokuCell cell = (SudokuCell) data; - System.out.print(111); + if (e.getButton() == MouseEvent.BUTTON1) { if (e.isControlDown()) { this.boardView diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuImporter.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuImporter.java index 68bf1e795..5084279c3 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuImporter.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuImporter.java @@ -110,16 +110,6 @@ public void initializeBoard(Node node) throws InvalidFileFormatException { } } } - // - // for(int y = 0; y < size; y++) - // { - // for(int x = 0; x < size; x++) - // { - // SudokuCell cell = sudokuBoard.getCell(x, y); - // System.err.println("(" + x + ", " + y + ") - " + - // cell.getGroupIndex()); - // } - // } puzzle.setCurrentBoard(sudokuBoard); } catch (NumberFormatException e) { diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuView.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuView.java index 9e8dc82ff..474feb342 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuView.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuView.java @@ -30,6 +30,7 @@ public SudokuView(SudokuBoard board) { // i * elementSize.height); SudokuElementView element = new SudokuElementView(board.getCell(k, i)); element.setIndex(i * gridSize.width + k); + element.setIndex(i * gridSize.width); element.setSize(elementSize); element.setLocation(location); elementViews.add(element); diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/elements/NumberTile.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/elements/NumberTile.java index a75f32c5a..a94d10e64 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/elements/NumberTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/elements/NumberTile.java @@ -3,10 +3,11 @@ import edu.rpi.legup.model.elements.PlaceableElement; public class NumberTile extends PlaceableElement { - private int object_num; - public NumberTile() { - super("SUDO-PLAC-0001", "Number Tile", "A numbered tile", null); - object_num = 0; + super( + "SUDO-ELEM-0001", + "Number Tile", + "A number tile", + "edu/rpi/legup/images/sudoku/tiles/NumberTile.png"); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/elements/sudoku_elements_reference_sheet.txt b/src/main/java/edu/rpi/legup/puzzle/sudoku/elements/sudoku_elements_reference_sheet.txt new file mode 100644 index 000000000..b8df27eb6 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/elements/sudoku_elements_reference_sheet.txt @@ -0,0 +1,2 @@ +SUDO-ELEM-0001 : NumberTile +SUDO-ELEM-0002 : UnknownTile \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/AdvancedDeductionDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/AdvancedDeductionDirectRule.java deleted file mode 100644 index 190679b41..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/AdvancedDeductionDirectRule.java +++ /dev/null @@ -1,99 +0,0 @@ -package edu.rpi.legup.puzzle.sudoku.rules; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.DirectRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -import edu.rpi.legup.puzzle.sudoku.SudokuBoard; -import edu.rpi.legup.puzzle.sudoku.SudokuCell; - -public class AdvancedDeductionDirectRule extends DirectRule { - - public AdvancedDeductionDirectRule() { - super( - "SUDO-BASC-0001", - "Advanced Deduction", - "Use of group logic deduces more answers by means of forced by Location and forced" - + " by Deduction", - "edu/rpi/legup/images/sudoku/AdvancedDeduction.png"); - } - - /** - * Checks whether the child node logically follows from the parent node at the specific - * puzzleElement index using this rule - * - * @param transition transition to check - * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified - * puzzleElement, otherwise error message - */ - public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - SudokuBoard initialBoard = (SudokuBoard) transition.getParents().get(0).getBoard(); - SudokuBoard finalBoard = (SudokuBoard) transition.getBoard(); - - SudokuCell cell = (SudokuCell) finalBoard.getPuzzleElement(puzzleElement); - int index = cell.getIndex(); - int groupSize = initialBoard.getWidth(); - int groupDim = (int) Math.sqrt(groupSize); - int rowIndex = index / groupSize; - int colIndex = index % groupSize; - int relX = rowIndex / groupDim; - int relY = colIndex % groupDim; - int groupNum = rowIndex / groupDim * groupDim + colIndex / groupDim; - boolean[][] possible = new boolean[groupDim][groupDim]; - for (int y = 0; y < groupDim; y++) { - for (int x = 0; x < groupDim; x++) { - SudokuCell c = initialBoard.getCell(groupNum, x, y); - if (c.getData() == cell.getData() && x != relX && y != relY) { - return super.getRuleName() + ": Duplicate value in sub-region"; - } - possible[y][x] = c.getData() == 0; - } - } - for (int y = 0; y < groupDim; y++) { - for (int x = 0; x < groupSize; x++) { - SudokuCell r = initialBoard.getCell(x, (groupNum / groupDim) * groupDim + y); - SudokuCell c = initialBoard.getCell((groupNum % groupDim) * groupDim + y, x); - if (r.getData() == cell.getData()) { - for (int i = 0; i < groupDim; i++) { - possible[y][i] = false; - } - } - if (c.getData() == cell.getData()) { - for (int i = 0; i < groupDim; i++) { - possible[i][y] = false; - } - } - } - } - boolean isForced = false; - for (int y = 0; y < groupDim; y++) { - for (int x = 0; x < groupDim; x++) { - if (possible[y][x] && !isForced) { - isForced = true; - } else { - if (possible[y][x]) { - return super.getInvalidUseOfRuleMessage() + ": Not forced"; - } - } - } - } - if (!isForced) { - return super.getInvalidUseOfRuleMessage() + ": Not forced"; - } - return null; - } - - /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link - * TreeNode}. - * - * @param node tree node used to create default transition board - * @return default board or null if this rule cannot be applied to this tree node - */ - @Override - public Board getDefaultBoard(TreeNode node) { - return null; - } -} diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/LastCellForNumberDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/LastCellForNumberDirectRule.java index fd03ef36c..6544bf7c3 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/LastCellForNumberDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/LastCellForNumberDirectRule.java @@ -15,7 +15,7 @@ public LastCellForNumberDirectRule() { "SUDO-BASC-0002", "Last Cell for Number", "This is the only cell open in its group for some number.", - "edu/rpi/legup/images/sudoku/forcedByElimination.png"); + "edu/rpi/legup/images/sudoku/rules/forcedByElimination.png"); } /** @@ -32,52 +32,146 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem SudokuBoard finalBoard = (SudokuBoard) transition.getBoard(); SudokuCell cell = (SudokuCell) finalBoard.getPuzzleElement(puzzleElement); + + // Check if empty cell placed if (cell.getData() == 0) { return super.getInvalidUseOfRuleMessage() + ": Cell is not forced at this index"; } - int size = initialBoard.getSize(); - + // Get defaults Set region = initialBoard.getRegion(cell.getGroupIndex()); Set row = initialBoard.getRow(cell.getLocation().y); Set col = initialBoard.getCol(cell.getLocation().x); - boolean contains = false; - if (region.size() == size - 1) { - for (SudokuCell c : region) { - if (cell.getData() == c.getData()) { + // Check if new cell conflicts group + for (SudokuCell c : region) { + if (c.getData() == cell.getData()) { + return super.getInvalidUseOfRuleMessage() + ": Cell is not forced at this index"; + } + } + for (SudokuCell c : row) { + if (c.getData() == cell.getData()) { + return super.getInvalidUseOfRuleMessage() + ": Cell is not forced at this index"; + } + } + for (SudokuCell c : col) { + if (c.getData() == cell.getData()) { + return super.getInvalidUseOfRuleMessage() + ": Cell is not forced at this index"; + } + } + + // // + // Loop to see if the number is constrained to the cell + boolean restrained = true; + for (SudokuCell c : region) { + // Test if its not a valid testing cell + if (c.getData() != 0) { + continue; + } + if (c.getLocation().y == cell.getLocation().y + && c.getLocation().x == cell.getLocation().x) { + continue; + } + // Check if cell is eligible to hold number + Set crow = initialBoard.getRow(c.getLocation().y); + Set ccol = initialBoard.getCol(c.getLocation().x); + boolean contains = false; + for (SudokuCell rc : crow) { + if (rc.getData() == cell.getData()) { contains = true; - break; } } + for (SudokuCell cc : ccol) { + if (cc.getData() == cell.getData()) { + contains = true; + } + } + // Stop if another cell can hold number if (!contains) { - return null; + restrained = false; + break; } } - if (row.size() == size - 1) { - contains = false; - for (SudokuCell c : row) { - if (cell.getData() == c.getData()) { + // Output if success + if (restrained) { + return null; + } + + // // + // Loop to see if the number is constrained to the cell + restrained = true; + for (SudokuCell c : row) { + // Test if its not a valid testing cell + if (c.getData() != 0) { + continue; + } + if (c.getLocation().y == cell.getLocation().y + && c.getLocation().x == cell.getLocation().x) { + continue; + } + // Check if cell is eligible to hold number + Set cregion = initialBoard.getRegion(c.getGroupIndex()); + Set ccol = initialBoard.getCol(c.getLocation().x); + boolean contains = false; + for (SudokuCell rc : cregion) { + if (rc.getData() == cell.getData()) { + contains = true; + } + } + for (SudokuCell cc : ccol) { + if (cc.getData() == cell.getData()) { contains = true; - break; } } + // Stop if another cell can hold number if (!contains) { - return null; + restrained = false; + break; } } - if (col.size() == size - 1) { - contains = false; - for (SudokuCell c : col) { - if (cell.getData() == c.getData()) { + // Output if success + if (restrained) { + return null; + } + + // // + // Loop to see if the number is constrained to the cell + restrained = true; + for (SudokuCell c : col) { + // Test if its not a valid testing cell + if (c.getData() != 0) { + continue; + } + if (c.getLocation().y == cell.getLocation().y + && c.getLocation().x == cell.getLocation().x) { + continue; + } + // Check if cell is eligible to hold number + Set cregion = initialBoard.getRegion(c.getGroupIndex()); + Set crow = initialBoard.getRow(c.getLocation().y); + boolean contains = false; + for (SudokuCell rc : cregion) { + if (rc.getData() == cell.getData()) { contains = true; - break; } } + for (SudokuCell cc : crow) { + if (cc.getData() == cell.getData()) { + contains = true; + } + } + // Stop if another cell can hold number if (!contains) { - return null; + restrained = false; + break; } } + // Output if success + if (restrained) { + return null; + } + + // Output fail return super.getInvalidUseOfRuleMessage() + ": Cell is not forced at this index"; } diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/LastNumberForCellDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/LastNumberForCellDirectRule.java index ca0ac3023..333d91749 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/LastNumberForCellDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/LastNumberForCellDirectRule.java @@ -16,7 +16,7 @@ public LastNumberForCellDirectRule() { "SUDO-BASC-0003", "Last Number for Cell", "This is the only number left that can fit in the cell of a group.", - "edu/rpi/legup/images/sudoku/forcedByDeduction.png"); + "edu/rpi/legup/images/sudoku/rules/forcedByDeduction.png"); } /** @@ -32,28 +32,37 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem SudokuBoard initialBoard = (SudokuBoard) transition.getParents().get(0).getBoard(); SudokuBoard finalBoard = (SudokuBoard) transition.getBoard(); - int index = puzzleElement.getIndex(); + // Assign basics int groupSize = initialBoard.getWidth(); int groupDim = (int) Math.sqrt(groupSize); + + // Get position info + int index = puzzleElement.getIndex(); int rowIndex = index / groupSize; int colIndex = index % groupSize; - int groupNum = rowIndex / groupDim * groupDim + colIndex % groupDim; + int groupNum = (rowIndex / groupDim) * groupDim + (colIndex / groupDim); + + // Create hashset of all numbers HashSet numbers = new HashSet<>(); for (int i = 1; i <= groupSize; i++) { numbers.add(i); } + + // Run through region, row, col to see contradicitng numbers for (int i = 0; i < groupSize; i++) { SudokuCell cell = initialBoard.getCell(groupNum, i % groupDim, i / groupDim); numbers.remove(cell.getData()); } for (int i = 0; i < groupSize; i++) { - SudokuCell cell = initialBoard.getCell(i, colIndex); + SudokuCell cell = initialBoard.getCell(i, rowIndex); numbers.remove(cell.getData()); } for (int i = 0; i < groupSize; i++) { - SudokuCell cell = initialBoard.getCell(rowIndex, i); + SudokuCell cell = initialBoard.getCell(colIndex, i); numbers.remove(cell.getData()); } + + // Check if plausible if (numbers.size() > 1) { return super.getInvalidUseOfRuleMessage() + ": The number at the index is not forced"; } else { @@ -64,7 +73,11 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem + ": The number at the index is forced but not correct"; } } - return null; + if (numbers.toArray(new Integer[1])[0] == puzzleElement.getData()) { + return null; + } + return super.getInvalidUseOfRuleMessage() + + ": The number at the index is forced but not correct"; } /** diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberColumnContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberColumnContradictionRule.java new file mode 100644 index 000000000..c8d627634 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberColumnContradictionRule.java @@ -0,0 +1,90 @@ +package edu.rpi.legup.puzzle.sudoku.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.ContradictionRule; +import edu.rpi.legup.puzzle.sudoku.SudokuBoard; +import edu.rpi.legup.puzzle.sudoku.SudokuCell; +import java.util.HashSet; +import java.util.Set; + +public class NoCellForNumberColumnContradictionRule extends ContradictionRule { + + public NoCellForNumberColumnContradictionRule() { + super( + "SUDO-CONT-0003", + "No Cell for Number (Column)", + "Process of elimination yields no valid numbers for an empty cell in a column.", + "edu/rpi/legup/images/sudoku/rules/NoCellForNumberColumn.png"); + } + + /** + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule + * + * @param board board to check contradiction + * @param puzzleElement equivalent puzzleElement + * @return null if the transition contains a contradiction at the specified puzzleElement, + * otherwise error message + */ + @Override + public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { + SudokuBoard sudokuBoard = (SudokuBoard) board; + SudokuCell cell = (SudokuCell) sudokuBoard.getPuzzleElement(puzzleElement); + if (cell.getData() != 0) { + return super.getNoContradictionMessage(); + } + + int groupSize = sudokuBoard.getSize(); + + Set col = sudokuBoard.getCol(cell.getGroupIndex()); + Set numbersNotInColumn = new HashSet<>(); + + for (int i = 1; i <= groupSize; i++) { + numbersNotInColumn.add(i); + } + for (SudokuCell c : col) { + if (c.getData() != 0) { + numbersNotInColumn.remove(c.getData()); + } + } + + for (Integer i : numbersNotInColumn) { + // Check if number can be in cell + boolean canFit = false; + for (SudokuCell c : col) { + if (c.getData() != 0) { + continue; + } + + // Get row and col groups + Set region = sudokuBoard.getRow(c.getLocation().y); + Set row = sudokuBoard.getCol(c.getLocation().x); + + // Check if it alr exists in row or col + boolean duplicate = false; + for (SudokuCell rc : region) { + if (rc.getData() == i) { + duplicate = true; + } + } + for (SudokuCell cc : row) { + if (cc.getData() == i) { + duplicate = true; + } + } + + // If there is no duplicate it can exist in the region + if (!duplicate) { + canFit = true; + break; + } + } + // If the number can't fit anywhere in region then contradiction + if (!canFit) { + return null; + } + } + return super.getNoContradictionMessage(); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberRegionContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberRegionContradictionRule.java new file mode 100644 index 000000000..f5106b858 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberRegionContradictionRule.java @@ -0,0 +1,90 @@ +package edu.rpi.legup.puzzle.sudoku.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.ContradictionRule; +import edu.rpi.legup.puzzle.sudoku.SudokuBoard; +import edu.rpi.legup.puzzle.sudoku.SudokuCell; +import java.util.HashSet; +import java.util.Set; + +public class NoCellForNumberRegionContradictionRule extends ContradictionRule { + + public NoCellForNumberRegionContradictionRule() { + super( + "SUDO-CONT-0001", + "No Cell for Number (Region)", + "Process of elimination yields no valid numbers for an empty cell in a region.", + "edu/rpi/legup/images/sudoku/rules/NoCellForNumberRegion.png"); + } + + /** + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule + * + * @param board board to check contradiction + * @param puzzleElement equivalent puzzleElement + * @return null if the transition contains a contradiction at the specified puzzleElement, + * otherwise error message + */ + @Override + public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { + SudokuBoard sudokuBoard = (SudokuBoard) board; + SudokuCell cell = (SudokuCell) sudokuBoard.getPuzzleElement(puzzleElement); + if (cell.getData() != 0) { + return super.getNoContradictionMessage(); + } + + int groupSize = sudokuBoard.getSize(); + + Set region = sudokuBoard.getRegion(cell.getGroupIndex()); + Set numbersNotInRegion = new HashSet<>(); + + for (int i = 1; i <= groupSize; i++) { + numbersNotInRegion.add(i); + } + for (SudokuCell c : region) { + if (c.getData() != 0) { + numbersNotInRegion.remove(c.getData()); + } + } + + for (Integer i : numbersNotInRegion) { + // Check if number can be in cell + boolean canFit = false; + for (SudokuCell c : region) { + if (c.getData() != 0) { + continue; + } + + // Get row and col groups + Set row = sudokuBoard.getRow(c.getLocation().y); + Set col = sudokuBoard.getCol(c.getLocation().x); + + // Check if it alr exists in row or col + boolean duplicate = false; + for (SudokuCell rc : row) { + if (rc.getData() == i) { + duplicate = true; + } + } + for (SudokuCell cc : col) { + if (cc.getData() == i) { + duplicate = true; + } + } + + // If there is no duplicate it can exist in the region + if (!duplicate) { + canFit = true; + break; + } + } + // If the number can't fit anywhere in region then contradiction + if (!canFit) { + return null; + } + } + return super.getNoContradictionMessage(); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberRowContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberRowContradictionRule.java new file mode 100644 index 000000000..e3f9f764a --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberRowContradictionRule.java @@ -0,0 +1,90 @@ +package edu.rpi.legup.puzzle.sudoku.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.ContradictionRule; +import edu.rpi.legup.puzzle.sudoku.SudokuBoard; +import edu.rpi.legup.puzzle.sudoku.SudokuCell; +import java.util.HashSet; +import java.util.Set; + +public class NoCellForNumberRowContradictionRule extends ContradictionRule { + + public NoCellForNumberRowContradictionRule() { + super( + "SUDO-CONT-0002", + "No Cell for Number (Row)", + "Process of elimination yields no valid numbers for an empty cell in a row.", + "edu/rpi/legup/images/sudoku/rules/NoCellForNumberRow.png"); + } + + /** + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule + * + * @param board board to check contradiction + * @param puzzleElement equivalent puzzleElement + * @return null if the transition contains a contradiction at the specified puzzleElement, + * otherwise error message + */ + @Override + public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { + SudokuBoard sudokuBoard = (SudokuBoard) board; + SudokuCell cell = (SudokuCell) sudokuBoard.getPuzzleElement(puzzleElement); + if (cell.getData() != 0) { + return super.getNoContradictionMessage(); + } + + int groupSize = sudokuBoard.getSize(); + + Set row = sudokuBoard.getRow(cell.getGroupIndex()); + Set numbersNotInRow = new HashSet<>(); + + for (int i = 1; i <= groupSize; i++) { + numbersNotInRow.add(i); + } + for (SudokuCell c : row) { + if (c.getData() != 0) { + numbersNotInRow.remove(c.getData()); + } + } + + for (Integer i : numbersNotInRow) { + // Check if number can be in cell + boolean canFit = false; + for (SudokuCell c : row) { + if (c.getData() != 0) { + continue; + } + + // Get row and col groups + Set region = sudokuBoard.getRow(c.getLocation().y); + Set col = sudokuBoard.getCol(c.getLocation().x); + + // Check if it alr exists in row or col + boolean duplicate = false; + for (SudokuCell rc : region) { + if (rc.getData() == i) { + duplicate = true; + } + } + for (SudokuCell cc : col) { + if (cc.getData() == i) { + duplicate = true; + } + } + + // If there is no duplicate it can exist in the region + if (!duplicate) { + canFit = true; + break; + } + } + // If the number can't fit anywhere in region then contradiction + if (!canFit) { + return null; + } + } + return super.getNoContradictionMessage(); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoSolutionContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoNumberForCellContradictionRule.java similarity index 72% rename from src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoSolutionContradictionRule.java rename to src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoNumberForCellContradictionRule.java index e44728d3e..6ea8f0a2a 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoSolutionContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoNumberForCellContradictionRule.java @@ -8,14 +8,14 @@ import java.util.HashSet; import java.util.Set; -public class NoSolutionContradictionRule extends ContradictionRule { +public class NoNumberForCellContradictionRule extends ContradictionRule { - public NoSolutionContradictionRule() { + public NoNumberForCellContradictionRule() { super( - "SUDO-CONT-0001", - "No Solution for Cell", + "SUDO-CONT-0004", + "No Number for Cell", "Process of elimination yields no valid numbers for an empty cell.", - "edu/rpi/legup/images/sudoku/NoSolution.png"); + "edu/rpi/legup/images/sudoku/rules/NoSolution.png"); } /** @@ -41,21 +41,19 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { Set row = sudokuBoard.getRow(cell.getLocation().y); Set col = sudokuBoard.getCol(cell.getLocation().x); Set solution = new HashSet<>(); - for (int i = 1; i <= groupSize; i++) { - solution.add(i); + for (SudokuCell s : region) { + solution.add(s.getData()); } - - for (SudokuCell c : region) { - solution.remove(c.getData()); - } - for (SudokuCell c : row) { - solution.remove(c.getData()); + for (SudokuCell s : row) { + solution.add(s.getData()); } - for (SudokuCell c : col) { - solution.remove(c.getData()); + + for (SudokuCell s : col) { + solution.add(s.getData()); } + solution.remove(0); - if (solution.isEmpty()) { + if (solution.size() == 9) { return null; } diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleNumberCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberColumnCaseRule.java similarity index 53% rename from src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleNumberCaseRule.java rename to src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberColumnCaseRule.java index e6ab0e64c..bab0bc79b 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleNumberCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberColumnCaseRule.java @@ -6,21 +6,26 @@ import edu.rpi.legup.model.rules.CaseRule; import edu.rpi.legup.model.tree.TreeTransition; import edu.rpi.legup.puzzle.sudoku.GroupType; -import edu.rpi.legup.puzzle.sudoku.PossibleNumberCaseBoard; +import edu.rpi.legup.puzzle.sudoku.ModelSudokuBoard; import edu.rpi.legup.puzzle.sudoku.SudokuBoard; import edu.rpi.legup.puzzle.sudoku.SudokuCell; import java.util.ArrayList; -import java.util.List; import java.util.Set; -public class PossibleNumberCaseRule extends CaseRule { +public class PossibleCellsForNumberColumnCaseRule extends CaseRule { - public PossibleNumberCaseRule() { + // Board math for translating indexes to numbers + private ModelSudokuBoard model = new ModelSudokuBoard(); + + // Old board for caseBoard reference + private SudokuBoard lagBoard; + + public PossibleCellsForNumberColumnCaseRule() { super( - "SUDO-CASE-0002", - "Possible Numbers for Cell", + "SUDO-CASE-0004", + "Possible Cells for Number - Column", "An empty cell has a limited set of possible numbers that can fill it.", - "edu/rpi/legup/images/sudoku/PossibleValues.png"); + "edu/rpi/legup/images/sudoku/rules/possible_cells_number_column.png"); } /** @@ -50,12 +55,12 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem @Override public CaseBoard getCaseBoard(Board board) { - SudokuBoard sudokuBoard = (SudokuBoard) board; - PossibleNumberCaseBoard caseBoard = new PossibleNumberCaseBoard(sudokuBoard, this, null); - for (int i = 0; i < sudokuBoard.getSize(); i++) { - caseBoard.addPickableRegion(i); - caseBoard.addPickableRow(i); - caseBoard.addPickableCol(i); + SudokuBoard sudokuBoard = (SudokuBoard) board.copy(); + lagBoard = (SudokuBoard) sudokuBoard.copy(); + CaseBoard caseBoard = new CaseBoard(sudokuBoard, this); + for (PuzzleElement puzzleElement : sudokuBoard.getPuzzleElements()) { + puzzleElement.setData(model.getModelColumnNumbers(puzzleElement.getIndex())); + caseBoard.addPickableElement(puzzleElement); } return caseBoard; } @@ -69,7 +74,7 @@ public CaseBoard getCaseBoard(Board board) { */ @Override public ArrayList getCases(Board board, PuzzleElement puzzleElement) { - return getCases(board, puzzleElement, 1, GroupType.REGION); + return getCases(board, puzzleElement, 1, GroupType.COLUMN); } /** @@ -84,48 +89,19 @@ public ArrayList getCases(Board board, PuzzleElement puzzleElement) { public ArrayList getCases( Board board, PuzzleElement puzzleElement, int value, GroupType groupType) { ArrayList cases = new ArrayList<>(); - SudokuBoard sudokuBoard = (SudokuBoard) board; - List caseCells = new ArrayList<>(); - SudokuCell cell = (SudokuCell) puzzleElement; + SudokuBoard sudokuBoard = lagBoard; + SudokuCell sourceCell = (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); + Set group = sudokuBoard.getCol(sourceCell.getLocation().x); + for (SudokuCell cell : group) { + if (cell.getData() == 0) { + Board newCase = sudokuBoard.copy(); + PuzzleElement element = newCase.getPuzzleElement(cell); + element.setData(model.getModelColumnNumbers(sourceCell.getIndex())); + newCase.addModifiedData(element); + cases.add(newCase); } } - - 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) { - Board newCase = sudokuBoard.copy(); - PuzzleElement element = newCase.getPuzzleElement(c); - element.setData(value); - newCase.addModifiedData(element); - cases.add(newCase); - } - return cases; } } diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberRegionCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberRegionCaseRule.java new file mode 100644 index 000000000..47e408369 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberRegionCaseRule.java @@ -0,0 +1,104 @@ +package edu.rpi.legup.puzzle.sudoku.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.CaseBoard; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.CaseRule; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.sudoku.*; +import java.util.ArrayList; +import java.util.Set; + +public class PossibleCellsForNumberRegionCaseRule extends CaseRule { + + // Board math for translating indexes to numbers + private ModelSudokuBoard model = new ModelSudokuBoard(); + + // Old board for caseBoard reference + private SudokuBoard lagBoard; + + public PossibleCellsForNumberRegionCaseRule() { + super( + "SUDO-CASE-0002", + "Possible Cells for Number - Region", + "An empty cell has a limited set of possible numbers that can fill it.", + "edu/rpi/legup/images/sudoku/rules/possible_cells_number_region.png"); + } + + /** + * Checks whether the transition logically follows from the parent node using this rule + * + * @param transition transition to check + * @return null if the child node logically follow from the parent node, otherwise error message + */ + @Override + public String checkRuleRaw(TreeTransition transition) { + return null; + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + return null; + } + + @Override + public CaseBoard getCaseBoard(Board board) { + SudokuBoard sudokuBoard = (SudokuBoard) board.copy(); + lagBoard = (SudokuBoard) sudokuBoard.copy(); + CaseBoard caseBoard = new CaseBoard(sudokuBoard, this); + for (PuzzleElement puzzleElement : sudokuBoard.getPuzzleElements()) { + puzzleElement.setData(model.getModelRegionNumbers(puzzleElement.getIndex())); + caseBoard.addPickableElement(puzzleElement); + } + return caseBoard; + } + + /** + * Gets the possible cases at a specific location based on this case rule + * + * @param board the current board state + * @param puzzleElement equivalent puzzleElement + * @return a list of elements the specified could be + */ + @Override + public ArrayList getCases(Board board, PuzzleElement puzzleElement) { + return getCases(board, puzzleElement, 1, GroupType.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 = lagBoard; + SudokuCell sourceCell = (SudokuCell) puzzleElement; + + Set group = sudokuBoard.getRegion(sourceCell.getGroupIndex()); + for (SudokuCell cell : group) { + if (cell.getData() == 0) { + Board newCase = sudokuBoard.copy(); + PuzzleElement element = newCase.getPuzzleElement(cell); + element.setData(model.getModelRegionNumbers(sourceCell.getIndex())); + newCase.addModifiedData(element); + cases.add(newCase); + } + } + return cases; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberRowCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberRowCaseRule.java new file mode 100644 index 000000000..868541377 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberRowCaseRule.java @@ -0,0 +1,107 @@ +package edu.rpi.legup.puzzle.sudoku.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.CaseBoard; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.CaseRule; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.sudoku.GroupType; +import edu.rpi.legup.puzzle.sudoku.ModelSudokuBoard; +import edu.rpi.legup.puzzle.sudoku.SudokuBoard; +import edu.rpi.legup.puzzle.sudoku.SudokuCell; +import java.util.ArrayList; +import java.util.Set; + +public class PossibleCellsForNumberRowCaseRule extends CaseRule { + + // Board math for translating indexes to numbers + private ModelSudokuBoard model = new ModelSudokuBoard(); + + // Old board for caseBoard reference + private SudokuBoard lagBoard; + + public PossibleCellsForNumberRowCaseRule() { + super( + "SUDO-CASE-0003", + "Possible Cells for Number - Row", + "An empty cell has a limited set of possible numbers that can fill it.", + "edu/rpi/legup/images/sudoku/rules/possible_cells_number_row.png"); + } + + /** + * Checks whether the transition logically follows from the parent node using this rule + * + * @param transition transition to check + * @return null if the child node logically follow from the parent node, otherwise error message + */ + @Override + public String checkRuleRaw(TreeTransition transition) { + return null; + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + return null; + } + + @Override + public CaseBoard getCaseBoard(Board board) { + SudokuBoard sudokuBoard = (SudokuBoard) board.copy(); + lagBoard = (SudokuBoard) sudokuBoard.copy(); + CaseBoard caseBoard = new CaseBoard(sudokuBoard, this); + for (PuzzleElement puzzleElement : sudokuBoard.getPuzzleElements()) { + puzzleElement.setData(model.getModelRowNumbers(puzzleElement.getIndex())); + caseBoard.addPickableElement(puzzleElement); + } + return caseBoard; + } + + /** + * Gets the possible cases at a specific location based on this case rule + * + * @param board the current board state + * @param puzzleElement equivalent puzzleElement + * @return a list of elements the specified could be + */ + @Override + public ArrayList getCases(Board board, PuzzleElement puzzleElement) { + return getCases(board, puzzleElement, 1, GroupType.ROW); + } + + /** + * Gets the possible cases at a specific location based on this case rule + * + * @param board the current board state + * @param puzzleElement equivalent puzzleElement + * @param value value that the rule will be applied from + * @param groupType group type + * @return a list of elements the specified could be + */ + public ArrayList getCases( + Board board, PuzzleElement puzzleElement, int value, GroupType groupType) { + ArrayList cases = new ArrayList<>(); + SudokuBoard sudokuBoard = lagBoard; + SudokuCell sourceCell = (SudokuCell) puzzleElement; + + Set group = sudokuBoard.getRow(sourceCell.getLocation().y); + for (SudokuCell cell : group) { + if (cell.getData() == 0) { + Board newCase = sudokuBoard.copy(); + PuzzleElement element = newCase.getPuzzleElement(cell); + element.setData(model.getModelRowNumbers(sourceCell.getIndex())); + newCase.addModifiedData(element); + cases.add(newCase); + } + } + return cases; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleNumbersForCellCaseRule.java similarity index 59% rename from src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellCaseRule.java rename to src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleNumbersForCellCaseRule.java index fb6da62d4..e17acc26b 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleNumbersForCellCaseRule.java @@ -5,19 +5,18 @@ 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.SudokuBoard; -import edu.rpi.legup.puzzle.sudoku.SudokuCell; +import edu.rpi.legup.puzzle.sudoku.*; import java.util.ArrayList; -import java.util.HashSet; -import java.util.Set; +import java.util.List; -public class PossibleCellCaseRule extends CaseRule { - public PossibleCellCaseRule() { +public class PossibleNumbersForCellCaseRule extends CaseRule { + + public PossibleNumbersForCellCaseRule() { super( "SUDO-CASE-0001", - "Possible Cells for Number", - "A number has a limited set of cells in which it can be placed.", - "edu/rpi/legup/images/sudoku/possible_cells_number.png"); + "Possible Numbers for Cell", + "An empty cell has a limited set of possible numbers that can fill it.", + "edu/rpi/legup/images/sudoku/rules/PossibleValues.png"); } /** @@ -66,42 +65,34 @@ public CaseBoard getCaseBoard(Board board) { */ @Override public ArrayList getCases(Board board, PuzzleElement puzzleElement) { - ArrayList cases = new ArrayList<>(); - SudokuBoard sudokuBoard = (SudokuBoard) board; - SudokuCell cell = (SudokuCell) puzzleElement; - - Set possibleValue = new HashSet<>(); - for (int i = 1; i <= sudokuBoard.getSize(); i++) { - possibleValue.add(i); - } - - int groupNum = cell.getGroupIndex(); - for (SudokuCell c : sudokuBoard.getRegion(groupNum)) { - if (c.getData().equals(c.getData())) { - possibleValue.remove(c.getData()); - } - } - - int rowNum = cell.getLocation().y; - for (SudokuCell c : sudokuBoard.getRegion(rowNum)) { - if (c.getData().equals(c.getData())) { - possibleValue.remove(c.getData()); - } - } + return getCases(board, puzzleElement, 1, GroupType.REGION); + } - int colNum = cell.getLocation().x; - for (SudokuCell c : sudokuBoard.getRegion(colNum)) { - if (c.getData().equals(c.getData())) { - possibleValue.remove(c.getData()); - } + /** + * 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<>(); + if (puzzleElement == null) { + return cases; } - for (Integer i : possibleValue) { - SudokuBoard newCase = sudokuBoard.copy(); + SudokuBoard sudokuBoard = (SudokuBoard) board; + List caseCells = new ArrayList<>(); + SudokuCell cell = (SudokuCell) puzzleElement; - PuzzleElement newCasePuzzleElement = newCase.getPuzzleElement(puzzleElement); - newCasePuzzleElement.setData(i); - newCase.addModifiedData(newCasePuzzleElement); + for (int i = 1; i <= 9; i++) { + Board newCase = sudokuBoard.copy(); + PuzzleElement element = newCase.getPuzzleElement(puzzleElement); + element.setData(i); + newCase.addModifiedData(element); cases.add(newCase); } diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/RepeatedNumberContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/RepeatedNumberContradictionRule.java index 955414e8e..f8172d071 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/RepeatedNumberContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/RepeatedNumberContradictionRule.java @@ -12,10 +12,10 @@ public class RepeatedNumberContradictionRule extends ContradictionRule { public RepeatedNumberContradictionRule() { super( - "SUDO-CONT-0002", + "SUDO-CONT-0005", "Repeated Numbers", "Two identical numbers are placed in the same group.", - "edu/rpi/legup/images/sudoku/RepeatedNumber.png"); + "edu/rpi/legup/images/sudoku/rules/RepeatedNumber.png"); } /** @@ -29,39 +29,51 @@ public RepeatedNumberContradictionRule() { */ @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { + // Get board to check SudokuBoard sudokuBoard = (SudokuBoard) board; - SudokuCell cell = (SudokuCell) sudokuBoard.getPuzzleElement(puzzleElement); - if (cell.getData() == 0) { - return super.getNoContradictionMessage(); - } - Set region = sudokuBoard.getRegion(cell.getGroupIndex()); - Set row = sudokuBoard.getRow(cell.getLocation().y); - Set col = sudokuBoard.getCol(cell.getLocation().x); + // Loop all group indexes + for (int i = 0; i < 9; i++) { + // Get regions and sets to check duplicates + Set region = sudokuBoard.getRegion(i); + Set regionDup = new HashSet<>(); + + Set row = sudokuBoard.getRow(i); + Set rowDup = new HashSet<>(); - Set regionDup = new HashSet<>(); - Set rowDup = new HashSet<>(); - Set colDup = new HashSet<>(); + Set col = sudokuBoard.getCol(i); + Set colDup = new HashSet<>(); - for (SudokuCell c : region) { - if (regionDup.contains(c.getData())) { - return null; + // Check for non zero duplicates to trigger contradiction + for (SudokuCell c : region) { + if (c.getData() == 0) { + continue; + } + if (regionDup.contains(c.getData())) { + return null; + } + regionDup.add(c.getData()); } - regionDup.add(c.getData()); - } - for (SudokuCell c : row) { - if (rowDup.contains(c.getData())) { - return null; + for (SudokuCell c : row) { + if (c.getData() == 0) { + continue; + } + if (rowDup.contains(c.getData())) { + return null; + } + rowDup.add(c.getData()); } - rowDup.add(c.getData()); - } - for (SudokuCell c : col) { - if (colDup.contains(c.getData())) { - return null; + for (SudokuCell c : col) { + if (c.getData() == 0) { + continue; + } + if (colDup.contains(c.getData())) { + return null; + } + colDup.add(c.getData()); } - colDup.add(c.getData()); } return super.getNoContradictionMessage(); 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..ceffa168c 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/sudoku_reference_sheet.txt +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/sudoku_reference_sheet.txt @@ -1,9 +1,13 @@ -SUDO-BASC-0001 : AdvancedDeductionDirectRule SUDO-BASC-0002 : LastCellForNumberDirectRule SUDO-BASC-0003 : LastNumberForCellDirectRule -SUDO-CONT-0001 : NoSolutionContradictionRule -SUDO-CONT-0002 : RepeatedNumberContradictionRule +SUDO-CONT-0001 : NoCellForNumberRegionContradictionRule +SUDO-CONT-0002 : NoCellForNumberRowContradictionRule +SUDO-CONT-0003 : NoCellForNumberColumnContradictionRule +SUDO-CONT-0004 : NoNumberForCellContradictionRule +SUDO-CONT-0005 : RepeatedNumberContradictionRule -SUDO-CASE-0001 : PossibleCellCaseRule -SUDO-CASE-0002 : PossibleNumberCaseRule \ No newline at end of file +SUDO-CASE-0001 : PossibleNumbersForCellCaseRule +SUDO-CASE-0002 : PossibleCellsForNumberRegionCaseRule +SUDO-CASE-0003 : PossibleCellsForNumberRowCaseRule +SUDO-CASE-0004 : PossibleCellsForNumberColumnCaseRule \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTent.java b/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTent.java index 5ec135a22..35993303a 100644 --- a/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTent.java +++ b/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTent.java @@ -59,7 +59,20 @@ public boolean isValidDimensions(int rows, int columns) { */ @Override public boolean isBoardComplete(Board board) { - return false; + TreeTentBoard treeTentBoard = (TreeTentBoard) board; + + for (ContradictionRule rule : contradictionRules) { + if (rule.checkContradiction(treeTentBoard) == null) { + return false; + } + } + for (PuzzleElement data : treeTentBoard.getPuzzleElements()) { + TreeTentCell cell = (TreeTentCell) data; + if (cell.getType() == TreeTentType.UNKNOWN) { + return false; + } + } + return true; } /** diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/elements/GrassTile.java b/src/main/java/edu/rpi/legup/puzzle/treetent/elements/GrassTile.java index 5356120a8..1d33b9035 100644 --- a/src/main/java/edu/rpi/legup/puzzle/treetent/elements/GrassTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/treetent/elements/GrassTile.java @@ -6,7 +6,7 @@ public class GrassTile extends PlaceableElement { public GrassTile() { super( - "TREE-PlAC-0002", + "TREE-ELEM-0001", "Grass Tile", "The grass crest tile", "edu/rpi/legup/images/treetent/grass.png"); diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/elements/TentTile.java b/src/main/java/edu/rpi/legup/puzzle/treetent/elements/TentTile.java index 950aebfa7..96124a98d 100644 --- a/src/main/java/edu/rpi/legup/puzzle/treetent/elements/TentTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/treetent/elements/TentTile.java @@ -6,7 +6,7 @@ public class TentTile extends PlaceableElement { public TentTile() { super( - "TREE-PLAC-0001", + "TREE-ELEM-0002", "Tent Tile", "The tent tile", "edu/rpi/legup/images/treetent/tent.png"); diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/elements/TreeTile.java b/src/main/java/edu/rpi/legup/puzzle/treetent/elements/TreeTile.java index d04886ed5..3d94cbfba 100644 --- a/src/main/java/edu/rpi/legup/puzzle/treetent/elements/TreeTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/treetent/elements/TreeTile.java @@ -1,12 +1,12 @@ package edu.rpi.legup.puzzle.treetent.elements; -import edu.rpi.legup.model.elements.NonPlaceableElement; +import edu.rpi.legup.model.elements.PlaceableElement; -public class TreeTile extends NonPlaceableElement { +public class TreeTile extends PlaceableElement { public TreeTile() { super( - "TREE-UNPL-0001", + "TREE-ELEM-0003", "Tree Tile", "The tree tile", "edu/rpi/legup/images/treetent/tree.png"); diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/elements/UnknownTile.java b/src/main/java/edu/rpi/legup/puzzle/treetent/elements/UnknownTile.java index a54240efd..99b75b60c 100644 --- a/src/main/java/edu/rpi/legup/puzzle/treetent/elements/UnknownTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/treetent/elements/UnknownTile.java @@ -1,11 +1,11 @@ package edu.rpi.legup.puzzle.treetent.elements; -import edu.rpi.legup.model.elements.NonPlaceableElement; +import edu.rpi.legup.model.elements.PlaceableElement; -public class UnknownTile extends NonPlaceableElement { +public class UnknownTile extends PlaceableElement { public UnknownTile() { super( - "TREE-UNPL-0002", + "TREE-ELEM-0004", "Unknown Tile", "The blank tile", "edu/rpi/legup/images/treetent/UnknownTile.png"); diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/elements/treetent_elements_reference_sheet.txt b/src/main/java/edu/rpi/legup/puzzle/treetent/elements/treetent_elements_reference_sheet.txt new file mode 100644 index 000000000..e0cfc1dfa --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/treetent/elements/treetent_elements_reference_sheet.txt @@ -0,0 +1,4 @@ +TREE-ELEM-0001 : GrassTile +TREE-ELEM-0002 : TentTile +TREE-ELEM-0003 : TreeTile +TREE-ELEM-0004 : UnknownTile \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/rules/FillinRowCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/treetent/rules/FillinRowCaseRule.java index aaa1a8fbc..8fe9b6873 100644 --- a/src/main/java/edu/rpi/legup/puzzle/treetent/rules/FillinRowCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/treetent/rules/FillinRowCaseRule.java @@ -61,7 +61,11 @@ public CaseBoard getCaseBoard(Board board) { */ @Override public ArrayList getCases(Board board, PuzzleElement puzzleElement) { + if (puzzleElement == null) { + return new ArrayList(); + } ArrayList cases; + List group; int tentsLeft; TreeTentClue clue = ((TreeTentClue) puzzleElement); diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/rules/LinkTentCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/treetent/rules/LinkTentCaseRule.java index bd303174a..cbe91c3a7 100644 --- a/src/main/java/edu/rpi/legup/puzzle/treetent/rules/LinkTentCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/treetent/rules/LinkTentCaseRule.java @@ -60,6 +60,10 @@ public CaseBoard getCaseBoard(Board board) { @Override public ArrayList getCases(Board board, PuzzleElement puzzleElement) { ArrayList cases = new ArrayList(); + if (puzzleElement == null) { + return cases; + } + TreeTentCell cell = (TreeTentCell) puzzleElement; List adj = ((TreeTentBoard) board).getAdjacent(cell, TreeTentType.TREE); List lines = ((TreeTentBoard) board).getLines(); diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/rules/LinkTreeCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/treetent/rules/LinkTreeCaseRule.java index 03d039898..153692ad0 100644 --- a/src/main/java/edu/rpi/legup/puzzle/treetent/rules/LinkTreeCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/treetent/rules/LinkTreeCaseRule.java @@ -62,6 +62,10 @@ public CaseBoard getCaseBoard(Board board) { @Override public ArrayList getCases(Board board, PuzzleElement puzzleElement) { ArrayList cases = new ArrayList<>(); + if (puzzleElement == null) { + return cases; + } + TreeTentBoard treeTentBoard = (TreeTentBoard) board; TreeTentCell cell = (TreeTentCell) puzzleElement; List adjCells = treeTentBoard.getAdjacent(cell, TreeTentType.TENT); diff --git a/src/main/java/edu/rpi/legup/ui/CreatePuzzleDialog.java b/src/main/java/edu/rpi/legup/ui/CreatePuzzleDialog.java index 32ddca34f..bde2df3d5 100644 --- a/src/main/java/edu/rpi/legup/ui/CreatePuzzleDialog.java +++ b/src/main/java/edu/rpi/legup/ui/CreatePuzzleDialog.java @@ -69,9 +69,7 @@ public void actionPerformed(ActionEvent e) { */ @Override public void actionPerformed(ActionEvent ae) { - String game = - Config.convertDisplayNameToClassName( - (String) gameBox.getSelectedItem()); + String game = getGame(); // Check if all 3 TextFields are filled if (game.equals("ShortTruthTable") && textArea.getText().isEmpty()) { @@ -91,8 +89,8 @@ public void actionPerformed(ActionEvent ae) { } else { homePanel.openEditorWithNewPuzzle( game, - Integer.valueOf(rows.getText()), - Integer.valueOf(columns.getText())); + Integer.valueOf(getRows()), + Integer.valueOf(getColumns())); } setVisible(false); } catch (IllegalArgumentException e) { @@ -116,6 +114,12 @@ public void actionPerformed(ActionEvent e) { } }; + /** + * Constructs a new CreatePuzzleDialog + * + * @param parent the parent frame of the dialog + * @param homePanel the home panel where the created puzzle will be added + */ public CreatePuzzleDialog(JFrame parent, HomePanel homePanel) { super(parent, true); diff --git a/src/main/java/edu/rpi/legup/ui/DynamicView.java b/src/main/java/edu/rpi/legup/ui/DynamicView.java index d6dbfb4c3..fa0004d0b 100644 --- a/src/main/java/edu/rpi/legup/ui/DynamicView.java +++ b/src/main/java/edu/rpi/legup/ui/DynamicView.java @@ -16,6 +16,10 @@ import javax.swing.*; import javax.swing.event.ChangeEvent; +/** + * A JPanel that provides a dynamic view with zooming capabilities for different types of content. + * This class supports views such as game boards or proof trees, allowing users to zoom in and out. + */ public class DynamicView extends JPanel { private ScrollView scrollView; @@ -29,6 +33,12 @@ public class DynamicView extends JPanel { private static final Font INFO_FONT = MaterialFonts.REGULAR; private static final Color INFO_COLOR = MaterialColors.GRAY_900; + /** + * Constructs a new DynamicView with the specified ScrollView and view type + * + * @param scrollView the ScrollView that provides the content to be displayed and zoomed + * @param type the type of dynamic view to set up (e.g., BOARD or PROOF_TREE) + */ public DynamicView(ScrollView scrollView, DynamicViewType type) { this.scrollView = scrollView; @@ -185,24 +195,49 @@ public void componentResized(ComponentEvent e) { return zoomWrapper; } + /** + * Gets the ScrollView component associated with this DynamicView + * + * @return the ScrollView component + */ public ScrollView getScrollView() { return this.scrollView; } + /** + * Gets the zoom wrapper that contains the zooming controls + * + * @return the zoom wrapper with zooming controls + */ public JPanel getZoomWrapper() { return this.zoomWrapper; } + /** + * Gets the zoomer that contains the zoomer component + * + * @return the zoomer with the zoomer component + */ public JPanel getZoomer() { return this.zoomer; } + /** + * Updates the status label with an informational message + * + * @param message the informational message to display + */ public void updateInfo(String message) { status.setFont(INFO_FONT); status.setForeground(INFO_COLOR); status.setText(message); } + /** + * Updates the status label with an error message + * + * @param message the error message to display + */ public void updateError(String message) { status.setFont(ERROR_FONT); status.setForeground(ERROR_COLOR); diff --git a/src/main/java/edu/rpi/legup/ui/HomePanel.java b/src/main/java/edu/rpi/legup/ui/HomePanel.java index 9e83dc9de..75761c475 100644 --- a/src/main/java/edu/rpi/legup/ui/HomePanel.java +++ b/src/main/java/edu/rpi/legup/ui/HomePanel.java @@ -46,40 +46,30 @@ public class HomePanel extends LegupPanel { new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - Object[] items = legupUI.getProofEditor().promptPuzzle(); - if (items == null) { - // The attempt to prompt a puzzle ended gracefully (cancel) - return; - } - String fileName = (String) items[0]; - File puzzleFile = (File) items[1]; - legupUI.getProofEditor().loadPuzzle(fileName, puzzleFile); + legupUI.getProofEditor().loadPuzzle("", null); } }; - private ActionListener openPuzzleListener = - new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - Object[] items = legupUI.getPuzzleEditor().promptPuzzle(); - if (items == null) { - // The attempt to prompt a puzzle ended gracefully (cancel) - return; - } - String fileName = (String) items[0]; - File puzzleFile = (File) items[1]; - legupUI.getPuzzleEditor().loadPuzzle(fileName, puzzleFile); - } - }; - - public HomePanel(FileDialog fileDialog, JFrame frame, LegupUI legupUI) { + /** + * Constructs a {@code HomePanel} with the specified {@code JFrame} and {@code LegupUI}. + * + * @param frame the main application frame + * @param legupUI the LEGUP user interface + */ + public HomePanel(JFrame frame, LegupUI legupUI) { this.legupUI = legupUI; this.frame = frame; setLayout(new GridLayout(1, 2)); + setPreferredSize(new Dimension(440, 250)); initText(); initButtons(); } + /** + * Creates and returns the menu bar for this panel + * + * @return the menu bar + */ public JMenuBar getMenuBar() { this.menuBar = new JMenuBar(); JMenu settings = new JMenu("Settings"); @@ -115,6 +105,14 @@ public void makeVisible() { frame.setJMenuBar(this.getMenuBar()); } + /** + * Resizes the provided icon to the specified width and height + * + * @param icon the icon to resize + * @param width the target width + * @param height the target height + * @return the resized icon + */ private static ImageIcon resizeButtonIcon(ImageIcon icon, int width, int height) { Image image = icon.getImage(); Image resizedImage = image.getScaledInstance(width, height, Image.SCALE_SMOOTH); @@ -123,10 +121,10 @@ private static ImageIcon resizeButtonIcon(ImageIcon icon, int width, int height) /** Initializes the buttons for this panel */ private void initButtons() { - this.buttons = new JButton[4]; + this.buttons = new JButton[3]; this.buttons[0] = - new JButton("Solve Puzzle") { + new JButton("Puzzle Solver") { { setSize(buttonSize, buttonSize); setMaximumSize(getSize()); @@ -144,7 +142,7 @@ private void initButtons() { this.buttons[0].addActionListener(CursorController.createListener(this, openProofListener)); this.buttons[1] = - new JButton("Create Puzzle") { + new JButton("Puzzle Editor") { { setSize(buttonSize, buttonSize); setMaximumSize(getSize()); @@ -158,35 +156,17 @@ private void initButtons() { this.buttons[1].setIcon(resizeButtonIcon(button1Icon, this.buttonSize, this.buttonSize)); this.buttons[1].setHorizontalTextPosition(AbstractButton.CENTER); this.buttons[1].setVerticalTextPosition(AbstractButton.BOTTOM); - this.buttons[1].addActionListener(l -> this.openNewPuzzleDialog()); - - this.buttons[2] = - new JButton("Edit Puzzle") { - { - setSize(buttonSize, buttonSize); - setMaximumSize(getSize()); - } - }; - URL button2IconLocation = - ClassLoader.getSystemClassLoader() - .getResource("edu/rpi/legup/images/Legup/homepanel/puzzle_file.png"); - ImageIcon button2Icon = new ImageIcon(button2IconLocation); - this.buttons[2].setFocusPainted(false); - this.buttons[2].setIcon(resizeButtonIcon(button2Icon, this.buttonSize, this.buttonSize)); - this.buttons[2].setHorizontalTextPosition(AbstractButton.CENTER); - this.buttons[2].setVerticalTextPosition(AbstractButton.BOTTOM); - this.buttons[2].addActionListener( - CursorController.createListener(this, openPuzzleListener)); // PLACEHOLDER + this.buttons[1].addActionListener(l -> this.openPuzzleEditorDialog()); for (int i = 0; i < this.buttons.length - 1; i++) { // -1 to avoid the batch grader button this.buttons[i].setBounds(200, 200, 700, 700); } - this.buttons[3] = new JButton("Batch Grader"); - this.buttons[3].setFocusPainted(false); - this.buttons[3].setHorizontalTextPosition(AbstractButton.CENTER); - this.buttons[3].setVerticalTextPosition(AbstractButton.BOTTOM); + this.buttons[2] = new JButton("Batch Grader"); + this.buttons[2].setFocusPainted(false); + this.buttons[2].setHorizontalTextPosition(AbstractButton.CENTER); + this.buttons[2].setVerticalTextPosition(AbstractButton.BOTTOM); - this.buttons[3].addActionListener( + this.buttons[2].addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { @@ -284,7 +264,7 @@ public void checkFolder() { } } catch (IOException ex) { LOGGER.error(ex.getMessage()); - this.buttons[3].addActionListener((ActionEvent e) -> use_xml_to_check()); + this.buttons[2].addActionListener((ActionEvent e) -> use_xml_to_check()); } } @@ -523,7 +503,7 @@ private void render() { this.removeAll(); this.setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS)); - this.legupUI.setTitle("LEGUP: A Better Way to Learn Formal Logic"); + this.legupUI.setTitle("LEGUP: A Better Way To Learn Formal Logic"); JPanel buttons = new JPanel(); buttons.add(Box.createRigidArea(new Dimension(5, 0))); @@ -531,11 +511,8 @@ private void render() { buttons.add(Box.createRigidArea(new Dimension(5, 0))); buttons.add(this.buttons[1]); buttons.add(Box.createRigidArea(new Dimension(5, 0))); - buttons.add(this.buttons[2]); - buttons.add(Box.createRigidArea(new Dimension(5, 0))); - JPanel batchGraderButton = new JPanel(); - batchGraderButton.add(this.buttons[3]); + batchGraderButton.add(this.buttons[2]); batchGraderButton.setAlignmentX(Component.CENTER_ALIGNMENT); this.add(Box.createRigidArea(new Dimension(0, 5))); @@ -566,6 +543,10 @@ private void openPuzzleEditorDialog() { } } + /** + * Opens a dialog to select a directory, recursively processes the directory to grade puzzles, + * and generates a CSV report of the grading results. + */ private void checkProofAll() { /* * Select dir to grade; recursively grade sub-dirs using traverseDir() @@ -609,6 +590,14 @@ private void checkProofAll() { JOptionPane.showMessageDialog(null, "Batch grading complete."); } + /** + * Recursively traverses directories to grade puzzles and writes results to a CSV file + * + * @param folder the folder to traverse + * @param writer the BufferedWriter to write results to the CSV file + * @param path the current path within the directory structure + * @throws IOException if an I/O error occurs while writing to the CSV file + */ private void traverseDir(File folder, BufferedWriter writer, String path) throws IOException { // Recursively traverse directory GameBoardFacade facade = GameBoardFacade.getInstance(); @@ -661,6 +650,14 @@ private void traverseDir(File folder, BufferedWriter writer, String path) throws } } + /** + * Opens the puzzle editor for the specified puzzle with the specified dimensions + * + * @param game the name of the game + * @param rows the number of rows in the puzzle + * @param columns the number of columns in the puzzle + * @throws IllegalArgumentException if the dimensions are invalid + */ public void openEditorWithNewPuzzle(String game, int rows, int columns) throws IllegalArgumentException { if (game.isEmpty()) { @@ -692,7 +689,7 @@ public void openEditorWithNewPuzzle(String game, int rows, int columns) } /** - * Opens the puzzle editor for the specified game with the given statements + * Opens the puzzle editor for the specified puzzle with the given statements * * @param game a String containing the name of the game * @param statements an array of statements diff --git a/src/main/java/edu/rpi/legup/ui/LegupUI.java b/src/main/java/edu/rpi/legup/ui/LegupUI.java index 201a2d4c7..75f822a6c 100644 --- a/src/main/java/edu/rpi/legup/ui/LegupUI.java +++ b/src/main/java/edu/rpi/legup/ui/LegupUI.java @@ -41,7 +41,7 @@ public static String getOS() { return os; } - /** LegupUI Constructor - creates a new LegupUI to setup the menu and toolbar */ + /** LegupUI Constructor - creates a new LegupUI to set up the menu and toolbar */ public LegupUI() { setTitle("LEGUP"); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); @@ -103,11 +103,17 @@ private void initPanels() { add(window); panels = new LegupPanel[3]; - panels[0] = new HomePanel(this.fileDialog, this, this); + panels[0] = new HomePanel(this, this); panels[1] = new ProofEditorPanel(this.fileDialog, this, this); panels[2] = new PuzzleEditorPanel(this.fileDialog, this, this); } + /** + * Displays the specified panel + * + * @param option the index of the panel to display + * @throws InvalidParameterException if the option is out of range + */ protected void displayPanel(int option) { if (option > panels.length || option < 0) { throw new InvalidParameterException("Invalid option"); @@ -121,10 +127,20 @@ protected void displayPanel(int option) { repaint(); } + /** + * Gets the ProofEditorPanel instance + * + * @return the ProofEditorPanel + */ public ProofEditorPanel getProofEditor() { return (ProofEditorPanel) panels[1]; } + /** + * Gets the PuzzleEditorPanel instance + * + * @return the PuzzleEditorPanel + */ public PuzzleEditorPanel getPuzzleEditor() { return (PuzzleEditorPanel) panels[2]; } @@ -134,17 +150,6 @@ public void repaintTree() { getProofEditor().repaintTree(); } - private void directions() { - JOptionPane.showMessageDialog( - null, - "For every move you make, you must provide a rules for it (located in the Rules" - + " panel).\n" - + "While working on the edu.rpi.legup.puzzle, you may click on the \"Check\"" - + " button to test your proof for correctness.", - "Directions", - JOptionPane.PLAIN_MESSAGE); - } - public void showStatus(String status, boolean error) { showStatus(status, error, 1); } @@ -157,8 +162,13 @@ public void showStatus(String status, boolean error, int timer) { // TODO: implement } - // ask to edu.rpi.legup.save current proof - public boolean noquit(String instr) { + /** + * Prompts the user to confirm if they want to exit LEGUP + * + * @param instr the prompt message + * @return true if the user chooses not to quit, false otherwise + */ + public boolean exit(String instr) { int n = JOptionPane.showConfirmDialog(null, instr, "Confirm", JOptionPane.YES_NO_OPTION); return n != JOptionPane.YES_OPTION; } @@ -168,7 +178,7 @@ public void windowOpened(WindowEvent e) {} public void windowClosing(WindowEvent e) { if (GameBoardFacade.getInstance().getHistory().getIndex() > -1) { - if (noquit("Exiting LEGUP?")) { + if (exit("Exiting LEGUP?")) { this.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); } else { this.setDefaultCloseOperation(EXIT_ON_CLOSE); @@ -190,22 +200,47 @@ public void windowActivated(WindowEvent e) {} public void windowDeactivated(WindowEvent e) {} + /** + * Gets the BoardView instance from the proof editor + * + * @return the BoardView + */ public BoardView getBoardView() { return getProofEditor().getBoardView(); } + /** + * Gets the BoardView instance from the puzzle editor + * + * @return the BoardView + */ public BoardView getEditorBoardView() { return getPuzzleEditor().getBoardView(); } + /** + * Gets the DynamicView instance from the proof editor + * + * @return the DynamicView + */ public DynamicView getDynamicBoardView() { return getProofEditor().getDynamicBoardView(); } + /** + * Gets the DynamicView instance from the puzzle editor. + * + * @return the DynamicView + */ public DynamicView getEditorDynamicBoardView() { return getPuzzleEditor().getDynamicBoardView(); } + /** + * Gets the TreePanel instance from the proof editor + * + * @return the TreePanel + */ public TreePanel getTreePanel() { return getProofEditor().getTreePanel(); } diff --git a/src/main/java/edu/rpi/legup/ui/PickGameDialog.java b/src/main/java/edu/rpi/legup/ui/PickGameDialog.java index ed510c6b6..3b66931a7 100644 --- a/src/main/java/edu/rpi/legup/ui/PickGameDialog.java +++ b/src/main/java/edu/rpi/legup/ui/PickGameDialog.java @@ -136,10 +136,20 @@ public void initPuzzles() { gameBox = new JComboBox(games); } + /** + * Gets the selected puzzle file path + * + * @return the puzzle file path as a String + */ public String getPuzzle() { return puzzleBox.getText(); } + /** + * Returns the selected puzzle + * + * @return the selected puzzle as a String + */ public String getGame() { return (String) gameBox.getSelectedItem(); } diff --git a/src/main/java/edu/rpi/legup/ui/PreferencesDialog.java b/src/main/java/edu/rpi/legup/ui/PreferencesDialog.java index e9a0df4a2..e90d06640 100644 --- a/src/main/java/edu/rpi/legup/ui/PreferencesDialog.java +++ b/src/main/java/edu/rpi/legup/ui/PreferencesDialog.java @@ -53,12 +53,24 @@ public class PreferencesDialog extends JDialog { } } + /** + * Creates a new instance of PreferencesDialog for the proof editor + * + * @param frame the parent frame + * @param rules the RuleFrame associated with the proof editor + * @return a new instance of PreferencesDialog + */ public static PreferencesDialog CreateDialogForProofEditor(Frame frame, RuleFrame rules) { PreferencesDialog p = new PreferencesDialog(frame); p.rulesFrame = rules; return p; } + /** + * Constructs a PreferencesDialog + * + * @param frame the parent frame + */ public PreferencesDialog(Frame frame) { super(frame); @@ -108,6 +120,11 @@ public PreferencesDialog(Frame frame) { setVisible(true); } + /** + * Toggles between dark mode and light mode based on the given preferences + * + * @param prefs the LegupPreferences instance holding user preferences + */ private void toggleDarkMode(LegupPreferences prefs) { try { if (Boolean.valueOf(prefs.getUserPref(LegupPreferences.DARK_MODE))) { @@ -121,6 +138,11 @@ private void toggleDarkMode(LegupPreferences prefs) { } } + /** + * Creates the general preferences tab + * + * @return a JScrollPane containing the general preferences panel + */ private JScrollPane createGeneralTab() { LegupPreferences prefs = LegupPreferences.getInstance(); JScrollPane scrollPane = new JScrollPane(); diff --git a/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java b/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java index ddabb5705..5ecbd5564 100644 --- a/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java +++ b/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java @@ -53,8 +53,8 @@ public class ProofEditorPanel extends LegupPanel implements IHistoryListener { private DynamicView dynamicBoardView; private JSplitPane topHalfPanel, mainPanel; private TitledBorder boardBorder; - - private JButton[] toolBarButtons; + private JButton[] toolBar1Buttons; + private JButton[] toolBar2Buttons; private JMenu file; private JMenuItem newPuzzle, resetPuzzle, @@ -74,7 +74,8 @@ public class ProofEditorPanel extends LegupPanel implements IHistoryListener { private JMenu about, help; private JMenuItem helpLegup, aboutLegup; - private JToolBar toolBar; + private JToolBar toolBar1; + private JToolBar toolBar2; private BoardView boardView; private JFileChooser folderBrowser; @@ -88,7 +89,6 @@ public class ProofEditorPanel extends LegupPanel implements IHistoryListener { public static final int IMD_FEEDBACK = 32; public static final int INTERN_RO = 64; public static final int AUTO_JUST = 128; - static final int[] TOOLBAR_SEPARATOR_BEFORE = {2, 4, 8}; private static final String[] PROFILES = { "No Assistance", "Rigorous Proof", @@ -118,6 +118,13 @@ public class ProofEditorPanel extends LegupPanel implements IHistoryListener { protected JMenuItem testAI = new JMenuItem("Test AI!"); protected JMenuItem hintAI = new JMenuItem("Hint"); + /** + * Constructs a new {@code ProofEditorPanel} with the specified parameters + * + * @param fileDialog the {@code FileDialog} used for file operations + * @param frame the {@code JFrame} that contains this panel + * @param legupUI the {@code LegupUI} instance managing the user interface + */ public ProofEditorPanel(FileDialog fileDialog, JFrame frame, LegupUI legupUI) { this.fileDialog = fileDialog; this.frame = frame; @@ -134,7 +141,7 @@ public ProofEditorPanel(FileDialog fileDialog, JFrame frame, LegupUI legupUI) { public void makeVisible() { this.removeAll(); - setupToolBar(); + setupToolBar1(); setupContent(); frame.setJMenuBar(getMenuBar()); } @@ -165,7 +172,7 @@ public JMenuBar getMenuBar() { file = new JMenu("File"); newPuzzle = new JMenuItem("Open"); - resetPuzzle = new JMenuItem("Reset Puzzle"); + resetPuzzle = new JMenuItem("Reset"); // genPuzzle = new JMenuItem("Puzzle Generators"); // TODO: implement puzzle // generator saveProofAs = new JMenuItem("Save As"); // create a new file to save @@ -341,6 +348,7 @@ public JMenuBar getMenuBar() { } else { resetPuzzle.setAccelerator(KeyStroke.getKeyStroke('R', InputEvent.CTRL_DOWN_MASK)); } + file.addSeparator(); file.add(saveProofAs); @@ -547,6 +555,7 @@ public Object[] promptPuzzle() { return null; } + System.out.println(preferences.getSavedPath()); return new Object[] {fileName, puzzleFile}; } @@ -712,16 +721,14 @@ private void helpTutorial() { default: url = "https://github.com/Bram-Hub/Legup/wiki/LEGUP-Tutorial"; } - Runtime rt = Runtime.getRuntime(); try { - // rt.exec("rundll32 url.dll,FileProtocolHandler "+url); java.awt.Desktop.getDesktop().browse(java.net.URI.create(url)); } catch (IOException e) { e.printStackTrace(); } } - // add the new function need to implement + // unfinished public void add_drop() { // add the mouse event then we can use the new listener to implement and // we should create a need jbuttom for it to ship the rule we select. @@ -765,13 +772,22 @@ private void saveProofChange() { } } - // ask to edu.rpi.legup.save current proof + /** + * Displays a confirmation dialog with a specified message. Returns {@code true} if the user + * selects "No" or cancels the action, and {@code false} if the user selects "Yes". + * + * @param instr the message to display in the confirmation dialog + * @return {@code true} if the user chooses not to quit, {@code false} otherwise + */ public boolean noquit(String instr) { int n = JOptionPane.showConfirmDialog(null, instr, "Confirm", JOptionPane.YES_NO_OPTION); return n != JOptionPane.YES_OPTION; } - /** Sets the main content for the edu.rpi.legup.user interface */ + /** + * Configures the layout and components for the main user interface. This includes setting up + * panels, split panes, and borders, and adding them to the main content pane. + */ protected void setupContent() { // JPanel consoleBox = new JPanel(new BorderLayout()); JPanel treeBox = new JPanel(new BorderLayout()); @@ -804,16 +820,9 @@ protected void setupContent() { ruleBox.add(boardPanel); treeBox.add(ruleBox); this.add(treeBox); - // consoleBox.add(treeBox); - // - // getContentPane().add(consoleBox); - - // JPopupPanel popupPanel = new JPopupPanel(); - // setGlassPane(popupPanel); - // popupPanel.setVisible(true); mainPanel.setDividerLocation(mainPanel.getMaximumDividerLocation() + 100); - // frame.pack(); + revalidate(); } @@ -828,68 +837,29 @@ private void setupToolBar1() { toolBar1.setRollover(true); setToolBar2Buttons(new JButton[1]); - // Scale the image icons down to make the buttons smaller - ImageIcon imageIcon = new ImageIcon(resourceLocation); - Image image = imageIcon.getImage(); - imageIcon = - new ImageIcon( - image.getScaledInstance( - this.TOOLBAR_ICON_SCALE, - this.TOOLBAR_ICON_SCALE, - Image.SCALE_SMOOTH)); - - JButton button = new JButton(toolBarName, imageIcon); - button.setFocusPainted(false); - getToolBarButtons()[i] = button; - } + URL open_url = + ClassLoader.getSystemClassLoader() + .getResource("edu/rpi/legup/images/Legup/Open.png"); - toolBar = new JToolBar(); - toolBar.setFloatable(false); - toolBar.setRollover(true); + // Scale the image icons down to make the buttons smaller + ImageIcon OpenImageIcon = new ImageIcon(open_url); + Image OpenImage = OpenImageIcon.getImage(); + OpenImageIcon = + new ImageIcon( + OpenImage.getScaledInstance( + this.TOOLBAR_ICON_SCALE, + this.TOOLBAR_ICON_SCALE, + Image.SCALE_SMOOTH)); - for (int i = 0; i < getToolBarButtons().length; i++) { - for (int s = 0; s < TOOLBAR_SEPARATOR_BEFORE.length; s++) { - if (i == TOOLBAR_SEPARATOR_BEFORE[s]) { - toolBar.addSeparator(); - } - } - String toolBarName = ToolbarName.values()[i].toString(); + JButton open = new JButton("Open", OpenImageIcon); + open.setFocusPainted(false); - toolBar.add(getToolBarButtons()[i]); - getToolBarButtons()[i].setToolTipText(toolBarName); + open.addActionListener((ActionEvent) -> loadPuzzle()); - getToolBarButtons()[i].setVerticalTextPosition(SwingConstants.BOTTOM); - getToolBarButtons()[i].setHorizontalTextPosition(SwingConstants.CENTER); - } + getToolBar2Buttons()[0] = open; + toolBar1.add(getToolBar2Buttons()[0]); - // toolBarButtons[ToolbarName.OPEN_PUZZLE.ordinal()].addActionListener((ActionEvent - // e) -> - // promptPuzzle()); - // toolBarButtons[ToolbarName.SAVE.ordinal()].addActionListener((ActionEvent e) -> - // saveProof()); - // toolBarButtons[ToolbarName.UNDO.ordinal()].addActionListener((ActionEvent e) -> - // GameBoardFacade.getInstance().getHistory().undo()); - // toolBarButtons[ToolbarName.REDO.ordinal()].addActionListener((ActionEvent e) -> - // GameBoardFacade.getInstance().getHistory().redo()); - toolBarButtons[ToolbarName.HINT.ordinal()].addActionListener((ActionEvent e) -> {}); - toolBarButtons[ToolbarName.CHECK.ordinal()].addActionListener( - (ActionEvent e) -> checkProof()); - toolBarButtons[ToolbarName.SUBMIT.ordinal()].addActionListener((ActionEvent e) -> {}); - toolBarButtons[ToolbarName.DIRECTIONS.ordinal()].addActionListener((ActionEvent e) -> {}); - - toolBarButtons[ToolbarName.CHECK_ALL.ordinal()].addActionListener( - (ActionEvent e) -> checkProofAll()); - - // toolBarButtons[ToolbarName.SAVE.ordinal()].setEnabled(false); - // toolBarButtons[ToolbarName.UNDO.ordinal()].setEnabled(false); - // toolBarButtons[ToolbarName.REDO.ordinal()].setEnabled(false); - toolBarButtons[ToolbarName.HINT.ordinal()].setEnabled(false); - toolBarButtons[ToolbarName.CHECK.ordinal()].setEnabled(false); - toolBarButtons[ToolbarName.SUBMIT.ordinal()].setEnabled(false); - toolBarButtons[ToolbarName.DIRECTIONS.ordinal()].setEnabled(false); - toolBarButtons[ToolbarName.CHECK_ALL.ordinal()].setEnabled(true); - - this.add(toolBar, BorderLayout.NORTH); + this.add(toolBar1, BorderLayout.NORTH); } /** @@ -999,19 +969,19 @@ private void setupToolBar2() { /** * Sets the toolbar1 buttons * - * @param toolBarButtons toolbar buttons + * @param toolBar1Buttons toolbar buttons */ - public void setToolBarButtons(JButton[] toolBarButtons) { - this.toolBarButtons = toolBarButtons; + public void setToolBar1Buttons(JButton[] toolBar1Buttons) { + this.toolBar1Buttons = toolBar1Buttons; } /** - * Gets the toolbar buttons + * Sets the toolbar2 buttons * - * @return toolbar buttons + * @param toolBar2Buttons toolbar buttons */ - public JButton[] getToolBarButtons() { - return toolBarButtons; + public void setToolBar2Buttons(JButton[] toolBar2Buttons) { + this.toolBar2Buttons = toolBar2Buttons; } /** @@ -1112,6 +1082,12 @@ private void repaintAll() { treePanel.repaint(); } + /** + * Initializes the dynamic board view, updates the tree panel, and sets rules and search panels + * based on the provided puzzle. It also updates toolbars and reloads the GUI. + * + * @param puzzle the puzzle to be displayed + */ public void setPuzzleView(Puzzle puzzle) { this.boardView = puzzle.getBoardView(); @@ -1135,9 +1111,8 @@ public void setPuzzleView(Puzzle puzzle) { ruleFrame.getContradictionPanel().setRules(puzzle.getContradictionRules()); ruleFrame.getSearchPanel().setSearchBar(puzzle); - toolBarButtons[ToolbarName.CHECK.ordinal()].setEnabled(true); - // toolBarButtons[ToolbarName.SAVE.ordinal()].setEnabled(true); - + toolBar1.setVisible(false); + setupToolBar2(); reloadGui(); } @@ -1203,6 +1178,15 @@ private boolean basicCheckProof(int[][] origCells) { return false; } + /** + * Traverses a given directory, grades the proofs found in the directory, and writes the results + * to the specified CSV writer. + * + * @param folder the folder to traverse + * @param writer the CSV writer + * @param path the current path in the directory traversal + * @throws IOException if an error occurs while writing to the CSV file + */ private void traverseDir(File folder, BufferedWriter writer, String path) throws IOException { // Recursively traverse directory GameBoardFacade facade = GameBoardFacade.getInstance(); @@ -1257,6 +1241,11 @@ private void traverseDir(File folder, BufferedWriter writer, String path) throws } } + /** + * Returns the current board view. + * + * @return the current {@link BoardView} + */ public BoardView getBoardView() { return boardView; } @@ -1270,12 +1259,17 @@ public DynamicView getDynamicBoardView() { return dynamicBoardView; } + /** + * Returns the current tree panel. + * + * @return the current {@link TreePanel} + */ public TreePanel getTreePanel() { return treePanel; } /** - * Called when a action is pushed onto the edu.rpi.legup.history stack + * Called when an action is pushed onto the edu.rpi.legup.history stack * * @param command action to push onto the stack */ @@ -1283,9 +1277,7 @@ public TreePanel getTreePanel() { public void onPushChange(ICommand command) { LOGGER.info("Pushing " + command.getClass().getSimpleName() + " to stack."); undo.setEnabled(true); - // toolBarButtons[ToolbarName.UNDO.ordinal()].setEnabled(true); redo.setEnabled(false); - // toolBarButtons[ToolbarName.REDO.ordinal()].setEnabled(false); String puzzleName = GameBoardFacade.getInstance().getPuzzleModule().getName(); File puzzleFile = new File(GameBoardFacade.getInstance().getCurFileName()); @@ -1308,9 +1300,7 @@ public void onClearHistory() {} @Override public void onRedo(boolean isBottom, boolean isTop) { undo.setEnabled(!isBottom); - // toolBarButtons[ToolbarName.UNDO.ordinal()].setEnabled(!isBottom); redo.setEnabled(!isTop); - // toolBarButtons[ToolbarName.REDO.ordinal()].setEnabled(!isTop); if (isBottom) { String puzzleName = GameBoardFacade.getInstance().getPuzzleModule().getName(); File puzzleFile = new File(GameBoardFacade.getInstance().getCurFileName()); @@ -1331,9 +1321,7 @@ public void onRedo(boolean isBottom, boolean isTop) { @Override public void onUndo(boolean isBottom, boolean isTop) { undo.setEnabled(!isBottom); - // toolBarButtons[ToolbarName.UNDO.ordinal()].setEnabled(!isBottom); redo.setEnabled(!isTop); - // toolBarButtons[ToolbarName.REDO.ordinal()].setEnabled(!isTop); String puzzleName = GameBoardFacade.getInstance().getPuzzleModule().getName(); File puzzleFile = new File(GameBoardFacade.getInstance().getCurFileName()); if (isBottom) { diff --git a/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java b/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java index 6b65e72f7..7c2ba06ff 100644 --- a/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java +++ b/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java @@ -39,12 +39,14 @@ public class PuzzleEditorPanel extends LegupPanel implements IHistoryListener { private JMenu[] menus; private JMenuItem helpLegup, aboutLegup; private JMenuBar menuBar; - private JToolBar toolBar; + private JToolBar toolBar1; + private JToolBar toolBar2; private JFileChooser folderBrowser; private JFrame frame; private JButton[] buttons; JSplitPane splitPanel; - private JButton[] toolBarButtons; + private JButton[] toolBar1Buttons; + private JButton[] toolBar2Buttons; private JPanel elementPanel; private DynamicView dynamicBoardView; private BoardView boardView; @@ -56,7 +58,11 @@ public class PuzzleEditorPanel extends LegupPanel implements IHistoryListener { private JPanel treePanel; private LegupUI legupUI; private EditorElementController editorElementController; - static final int[] TOOLBAR_SEPARATOR_BEFORE = {2, 4, 8}; + private CreatePuzzleDialog cpd; + private HomePanel hp; + private boolean existingPuzzle; + private String fileName; + private File puzzleFile; /** * Constructs a {@code PuzzleEditorPanel} with the specified file dialog, frame, and Legup UI @@ -124,14 +130,14 @@ public void setMenuBar() { menus[0] = new JMenu("File"); // file>new - JMenuItem newPuzzle = new JMenuItem("New"); - newPuzzle.addActionListener((ActionEvent) -> loadPuzzle()); + JMenuItem openPuzzle = new JMenuItem("Open"); + openPuzzle.addActionListener((ActionEvent) -> loadPuzzle()); if (os.equals("mac")) { - newPuzzle.setAccelerator( + openPuzzle.setAccelerator( KeyStroke.getKeyStroke( - 'N', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); + 'O', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); } else { - newPuzzle.setAccelerator(KeyStroke.getKeyStroke('N', InputEvent.CTRL_DOWN_MASK)); + openPuzzle.setAccelerator(KeyStroke.getKeyStroke('O', InputEvent.CTRL_DOWN_MASK)); } // file>create JMenuItem createPuzzle = new JMenuItem("Create"); @@ -144,11 +150,11 @@ public void setMenuBar() { existingPuzzle = false; }); if (os.equals("mac")) { - newPuzzle.setAccelerator( + createPuzzle.setAccelerator( KeyStroke.getKeyStroke( - 'D', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); + 'C', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); } else { - newPuzzle.setAccelerator(KeyStroke.getKeyStroke('D', InputEvent.CTRL_DOWN_MASK)); + createPuzzle.setAccelerator(KeyStroke.getKeyStroke('C', InputEvent.CTRL_DOWN_MASK)); } JMenuItem exit = new JMenuItem("Exit"); @@ -279,8 +285,7 @@ public void exitEditor() { @Override public void makeVisible() { this.removeAll(); - - setupToolBar(); + setupToolBar1(); setupContent(); setMenuBar(); } @@ -292,21 +297,21 @@ public void makeVisible() { private void setupToolBar1() { setToolBar1Buttons(new JButton[2]); - // Scale the image icons down to make the buttons smaller - ImageIcon imageIcon = new ImageIcon(resourceLocation); - Image image = imageIcon.getImage(); - imageIcon = - new ImageIcon( - image.getScaledInstance( - this.TOOLBAR_ICON_SCALE, - this.TOOLBAR_ICON_SCALE, - Image.SCALE_SMOOTH)); - - JButton button = new JButton(toolBarName, imageIcon); - button.setFocusPainted(false); - getToolBarButtons()[i] = button; - lastone = i; - } + URL open_url = + ClassLoader.getSystemClassLoader() + .getResource("edu/rpi/legup/images/Legup/Open.png"); + ImageIcon OpenImageIcon = new ImageIcon(open_url); + Image OpenImage = OpenImageIcon.getImage(); + OpenImageIcon = + new ImageIcon( + OpenImage.getScaledInstance( + this.TOOLBAR_ICON_SCALE, + this.TOOLBAR_ICON_SCALE, + Image.SCALE_SMOOTH)); + + JButton open = new JButton("Open", OpenImageIcon); + open.setFocusPainted(false); + open.addActionListener((ActionEvent) -> loadPuzzle()); getToolBar1Buttons()[0] = open; @@ -414,81 +419,51 @@ private void setupToolBar2() { URL save_and_solve = ClassLoader.getSystemClassLoader() .getResource("edu/rpi/legup/images/Legup/Check.png"); - ImageIcon imageIcon = new ImageIcon(check_and_save); - Image image = imageIcon.getImage(); - imageIcon = + ImageIcon SaveSolveImageIcon = new ImageIcon(save_and_solve); + Image SaveSolveImage = SaveSolveImageIcon.getImage(); + SaveSolveImageIcon = new ImageIcon( - image.getScaledInstance( + SaveSolveImage.getScaledInstance( this.TOOLBAR_ICON_SCALE, this.TOOLBAR_ICON_SCALE, Image.SCALE_SMOOTH)); - JButton checkandsave = new JButton("check and Save", imageIcon); - checkandsave.setFocusPainted(false); - checkandsave.addActionListener( + JButton saveandsolve = new JButton("Save & Solve", SaveSolveImageIcon); + saveandsolve.setFocusPainted(false); + saveandsolve.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - // savePuzzle(); - String filename = savePuzzle(); - File puzzlename = new File(filename); - System.out.println(filename); - - GameBoardFacade.getInstance().getLegupUI().displayPanel(1); - GameBoardFacade.getInstance() - .getLegupUI() - .getProofEditor() - .loadPuzzle(filename, new File(filename)); - String puzzleName = - GameBoardFacade.getInstance().getPuzzleModule().getName(); - frame.setTitle(puzzleName + " - " + puzzlename.getName()); + if (GameBoardFacade.getInstance().getPuzzleModule() != null) { + String filename = savePuzzle(); + File puzzlename = new File(filename); + System.out.println(filename); + + GameBoardFacade.getInstance().getLegupUI().displayPanel(1); + GameBoardFacade.getInstance() + .getLegupUI() + .getProofEditor() + .loadPuzzle(filename, new File(filename)); + String puzzleName = + GameBoardFacade.getInstance().getPuzzleModule().getName(); + frame.setTitle(puzzleName + " - " + puzzlename.getName()); + } } }); - getToolBarButtons()[lastone + 1] = checkandsave; - System.out.println("it is create new file"); - - toolBar = new JToolBar(); - toolBar.setFloatable(false); - toolBar.setRollover(true); - - for (int i = 0; i < getToolBarButtons().length - 1; i++) { - for (int s = 0; s < TOOLBAR_SEPARATOR_BEFORE.length; s++) { - if (i == TOOLBAR_SEPARATOR_BEFORE[s]) { - toolBar.addSeparator(); - } - } - String toolBarName = ToolbarName.values()[i].toString(); - - toolBar.add(getToolBarButtons()[i]); - getToolBarButtons()[i].setToolTipText(toolBarName); - - getToolBarButtons()[i].setVerticalTextPosition(SwingConstants.BOTTOM); - getToolBarButtons()[i].setHorizontalTextPosition(SwingConstants.CENTER); - } + getToolBar2Buttons()[2] = saveandsolve; + toolBar2.add(getToolBar2Buttons()[2]); - // toolBarButtons[ToolbarName.OPEN_PUZZLE.ordinal()].addActionListener((ActionEvent - // e) -> - // promptPuzzle()); - // toolBarButtons[ToolbarName.SAVE.ordinal()].addActionListener((ActionEvent e) -> - // saveProof()); - // toolBarButtons[ToolbarName.UNDO.ordinal()].addActionListener((ActionEvent e) -> - // GameBoardFacade.getInstance().getHistory().undo()); - // toolBarButtons[ToolbarName.REDO.ordinal()].addActionListener((ActionEvent e) -> - // GameBoardFacade.getInstance().getHistory().redo()); - toolBarButtons[ToolbarName.HINT.ordinal()].addActionListener((ActionEvent e) -> {}); - toolBarButtons[ToolbarName.SUBMIT.ordinal()].addActionListener((ActionEvent e) -> {}); - toolBarButtons[ToolbarName.DIRECTIONS.ordinal()].addActionListener((ActionEvent e) -> {}); - - // toolBarButtons[ToolbarName.SAVE.ordinal()].setEnabled(false); - // toolBarButtons[ToolbarName.UNDO.ordinal()].setEnabled(false); - // toolBarButtons[ToolbarName.REDO.ordinal()].setEnabled(false); - toolBarButtons[ToolbarName.HINT.ordinal()].setEnabled(false); - toolBarButtons[ToolbarName.SUBMIT.ordinal()].setEnabled(false); - toolBarButtons[ToolbarName.DIRECTIONS.ordinal()].setEnabled(false); - - this.add(toolBar, BorderLayout.NORTH); + this.add(toolBar2, BorderLayout.NORTH); } + /** + * Initializes a puzzle based on the provided game name, rows, and columns. + * + * @param game the name of the game or puzzle to load + * @param rows the number of rows in the puzzle + * @param columns the number of columns in the puzzle + * @throws IllegalArgumentException if the provided arguments are invalid + */ public void loadPuzzleFromHome(String game, int rows, int columns) throws IllegalArgumentException { GameBoardFacade facade = GameBoardFacade.getInstance(); @@ -502,6 +477,13 @@ public void loadPuzzleFromHome(String game, int rows, int columns) } } + /** + * Initializes a puzzle based on the provided game name and an array of statements. + * + * @param game the name of the game or puzzle to load + * @param statements an array of statements to initialize the puzzle + * @throws IllegalArgumentException if the provided arguments are invalid + */ public void loadPuzzleFromHome(String game, String[] statements) { GameBoardFacade facade = GameBoardFacade.getInstance(); try { @@ -525,7 +507,7 @@ public void loadPuzzleFromHome(String game, String[] statements) { public Object[] promptPuzzle() { GameBoardFacade facade = GameBoardFacade.getInstance(); if (facade.getBoard() != null) { - if (noQuit("Opening a new puzzle?")) { + if (noQuit("Open an existing puzzle?")) { return new Object[0]; } } @@ -549,7 +531,6 @@ public Object[] promptPuzzle() { fileBrowser.setAcceptAllFileFilterUsed(false); File puzzlePath = fileBrowser.getSelectedFile(); - System.out.println(puzzlePath.getAbsolutePath()); if (puzzlePath != null) { fileName = puzzlePath.getAbsolutePath(); @@ -594,6 +575,9 @@ public void loadPuzzle(String fileName, File puzzleFile) { GameBoardFacade.getInstance().loadPuzzleEditor(fileName); String puzzleName = GameBoardFacade.getInstance().getPuzzleModule().getName(); frame.setTitle(puzzleName + " - " + puzzleFile.getName()); + existingPuzzle = true; + this.fileName = fileName; + this.puzzleFile = puzzleFile; } catch (InvalidFileFormatException e) { legupUI.displayPanel(0); LOGGER.error(e.getMessage()); @@ -644,12 +628,22 @@ public BoardView getBoardView() { return boardView; } - public JButton[] getToolBarButtons() { - return toolBarButtons; + /** + * Returns the array of buttons for the first toolbar + * + * @return the array of toolbar1 buttons + */ + public JButton[] getToolBar1Buttons() { + return toolBar1Buttons; } - public void setToolBarButtons(JButton[] toolBarButtons) { - this.toolBarButtons = toolBarButtons; + /** + * Sets the array of buttons for the first toolbar + * + * @param toolBar1Buttons the array of toolbar1 buttons + */ + public void setToolBar1Buttons(JButton[] toolBar1Buttons) { + this.toolBar1Buttons = toolBar1Buttons; } /** @@ -696,13 +690,11 @@ public void setPuzzleView(Puzzle puzzle) { dynamicBoardView.setBorder(titleBoard); puzzle.addBoardListener(puzzle.getBoardView()); - System.out.println("Setting elements"); if (this.elementFrame != null) { elementFrame.setElements(puzzle); } - - toolBarButtons[ToolbarName.CHECK.ordinal()].setEnabled(true); - // toolBarButtons[ToolbarName.SAVE.ordinal()].setEnabled(true); + toolBar1.setVisible(false); + setupToolBar2(); } /** Saves a puzzle */ @@ -768,7 +760,7 @@ private String savePuzzle() { folderBrowser.setAcceptAllFileFilterUsed(false); String path = folderBrowser.getSelectedFile().getAbsolutePath(); - + preferences.setSavedPath(path); if (path != null) { try { PuzzleExporter exporter = puzzle.getExporter(); @@ -783,6 +775,11 @@ private String savePuzzle() { return path; } + /** + * Returns the current dynamic board view + * + * @return the dynamic board view + */ public DynamicView getDynamicBoardView() { return dynamicBoardView; } diff --git a/src/main/java/edu/rpi/legup/ui/ScrollView.java b/src/main/java/edu/rpi/legup/ui/ScrollView.java index 4d53cd747..589573154 100644 --- a/src/main/java/edu/rpi/legup/ui/ScrollView.java +++ b/src/main/java/edu/rpi/legup/ui/ScrollView.java @@ -293,6 +293,11 @@ public void setSize(Dimension size) { updateSize(); } + /** + * Gets the canvas for this {@code ScrollView} + * + * @return the ZoomablePane instance used as the canvas + */ public ZoomablePane getCanvas() { return canvas; } diff --git a/src/main/java/edu/rpi/legup/ui/ToolbarName.java b/src/main/java/edu/rpi/legup/ui/ToolbarName.java index 5cf9b5923..622d16d8d 100644 --- a/src/main/java/edu/rpi/legup/ui/ToolbarName.java +++ b/src/main/java/edu/rpi/legup/ui/ToolbarName.java @@ -5,11 +5,8 @@ * specific toolbar action. */ public enum ToolbarName { - HINT, - CHECK, - SUBMIT, DIRECTIONS, - CHECK_ALL; + CHECK; /** * Gets the String representation of the ToolbarName enum diff --git a/src/main/java/edu/rpi/legup/ui/ZoomWidget.java b/src/main/java/edu/rpi/legup/ui/ZoomWidget.java index 3207462ed..40f36113f 100644 --- a/src/main/java/edu/rpi/legup/ui/ZoomWidget.java +++ b/src/main/java/edu/rpi/legup/ui/ZoomWidget.java @@ -10,6 +10,10 @@ import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; +/** + * The {@code ZoomWidget} displays a zoom icon that, when clicked, shows a popup slider to adjust + * the zoom level of the associated {@code ScrollView}. + */ public class ZoomWidget extends JLabel { private ScrollView parent; private PopupSlider palette = new PopupSlider(); @@ -48,6 +52,11 @@ public PopupSlider() { slider.addChangeListener(this); } + /** + * Handles state changes in the slider by adjusting the zoom level of the {@code ScrollView} + * + * @param e the {@code ChangeEvent} indicating that the slider's state has changed + */ public void stateChanged(ChangeEvent e) { if (slider.getValueIsAdjusting()) { parent.zoomTo((double) slider.getValue() / 100.0); diff --git a/src/main/java/edu/rpi/legup/ui/ZoomablePane.java b/src/main/java/edu/rpi/legup/ui/ZoomablePane.java index 934d31c53..66af90abd 100644 --- a/src/main/java/edu/rpi/legup/ui/ZoomablePane.java +++ b/src/main/java/edu/rpi/legup/ui/ZoomablePane.java @@ -5,6 +5,10 @@ import java.awt.Graphics2D; import javax.swing.*; +/** + * The {@code ZoomablePane} class is used to display components in a zoomable and scalable manner. + * It uses {@code ScrollView} to handle scaling and drawing of the content. + */ public class ZoomablePane extends JLayeredPane { private ScrollView viewer; diff --git a/src/main/java/edu/rpi/legup/ui/boardview/BoardView.java b/src/main/java/edu/rpi/legup/ui/boardview/BoardView.java index 0b395c774..18b47d98b 100644 --- a/src/main/java/edu/rpi/legup/ui/boardview/BoardView.java +++ b/src/main/java/edu/rpi/legup/ui/boardview/BoardView.java @@ -188,6 +188,11 @@ public ArrayList getElementViews() { return elementViews; } + /** + * Gets the ElementController associated with this board view. + * + * @return the ElementController + */ public ElementController getElementController() { return elementController; } @@ -197,6 +202,11 @@ public void draw(Graphics2D graphics2D) { drawBoard(graphics2D); } + /** + * Draws the board and its elements. + * + * @param graphics2D the Graphics2D context used for drawing + */ public void drawBoard(Graphics2D graphics2D) { for (ElementView element : elementViews) { element.draw(graphics2D); @@ -213,5 +223,10 @@ public void onBoardDataChanged(PuzzleElement puzzleElement) { repaint(); } + /** + * Gets the selection popup menu for this board view. + * + * @return the DataSelectionView associated with this view + */ public abstract DataSelectionView getSelectionPopupMenu(); } diff --git a/src/main/java/edu/rpi/legup/ui/boardview/DataSelectionView.java b/src/main/java/edu/rpi/legup/ui/boardview/DataSelectionView.java index 44cee38fb..bc40e3d58 100644 --- a/src/main/java/edu/rpi/legup/ui/boardview/DataSelectionView.java +++ b/src/main/java/edu/rpi/legup/ui/boardview/DataSelectionView.java @@ -11,6 +11,11 @@ */ public class DataSelectionView extends JPopupMenu { + /** + * Constructs a DataSelectionView with the given controller. + * + * @param controller The ElementController to handle UI events. + */ public DataSelectionView(ElementController controller) { setBackground(Color.GRAY); setBorder(new BevelBorder(BevelBorder.RAISED)); diff --git a/src/main/java/edu/rpi/legup/ui/boardview/ElementSelection.java b/src/main/java/edu/rpi/legup/ui/boardview/ElementSelection.java index 5ddbab909..eaa85082d 100644 --- a/src/main/java/edu/rpi/legup/ui/boardview/ElementSelection.java +++ b/src/main/java/edu/rpi/legup/ui/boardview/ElementSelection.java @@ -12,16 +12,29 @@ public class ElementSelection { private ElementView hover; private Point mousePoint; + /** + * Constructs an ElementSelection instance with an empty selection and no hover or mouse point + */ public ElementSelection() { this.selection = new ArrayList<>(); this.hover = null; this.mousePoint = null; } + /** + * Gets the list of currently selected ElementViews. + * + * @return the list of selected ElementViews + */ public ArrayList getSelection() { return selection; } + /** + * Gets the first ElementView in the selection, or null if the selection is empty. + * + * @return the first selected ElementView, or null if there are no selections + */ public ElementView getFirstSelection() { return selection.size() == 0 ? null : selection.get(0); } @@ -62,10 +75,20 @@ public void clearSelection() { selection.clear(); } + /** + * Gets the currently hovered ElementView. + * + * @return the currently hovered ElementView, or null if no element is hovered + */ public ElementView getHover() { return hover; } + /** + * Sets a new hovered ElementView, updating the hover state of the previous and new elements. + * + * @param newHovered the new ElementView to be hovered + */ public void newHover(ElementView newHovered) { newHovered.setHover(true); if (hover != null) { @@ -82,10 +105,20 @@ public void clearHover() { } } + /** + * Gets the current mouse point location. + * + * @return the current mouse point location + */ public Point getMousePoint() { return mousePoint; } + /** + * Sets the mouse point location. + * + * @param point the new mouse point location + */ public void setMousePoint(Point point) { this.mousePoint = point; } diff --git a/src/main/java/edu/rpi/legup/ui/boardview/ElementView.java b/src/main/java/edu/rpi/legup/ui/boardview/ElementView.java index 48a33493c..eab13cc1d 100644 --- a/src/main/java/edu/rpi/legup/ui/boardview/ElementView.java +++ b/src/main/java/edu/rpi/legup/ui/boardview/ElementView.java @@ -97,8 +97,19 @@ public void drawElement(Graphics2D graphics2D) { graphics2D.drawString(String.valueOf(puzzleElement.getData()), xText, yText); } + /** + * Draws additional elements for given PuzzleElements (default implementation does nothing). + * Overriden in some puzzle element views. + * + * @param graphics2D the Graphics2D context to use for drawing + */ public void drawGiven(Graphics2D graphics2D) {} + /** + * Draws a hover effect on the ElementView. + * + * @param graphics2D the Graphics2D context to use for drawing + */ public void drawHover(Graphics2D graphics2D) { graphics2D.setColor(hoverColor); graphics2D.setStroke(new BasicStroke(2)); @@ -107,6 +118,11 @@ public void drawHover(Graphics2D graphics2D) { location.x + 1.5f, location.y + 1.5f, size.width - 3, size.height - 3)); } + /** + * Draws a modified effect on the ElementView. + * + * @param graphics2D the Graphics2D context to use for drawing + */ public void drawModified(Graphics2D graphics2D) { graphics2D.setColor(puzzleElement.isValid() ? modifiedColor : invalidColor); graphics2D.setStroke(new BasicStroke(2)); @@ -115,6 +131,11 @@ public void drawModified(Graphics2D graphics2D) { location.x + 1.5f, location.y + 1.5f, size.width - 3, size.height - 3)); } + /** + * Draws a case rule picker on the ElementView. + * + * @param graphics2D the Graphics2D context to use for drawing + */ public void drawCase(Graphics2D graphics2D) { graphics2D.setColor(caseColor); graphics2D.fill( @@ -122,6 +143,11 @@ public void drawCase(Graphics2D graphics2D) { location.x + 1.5f, location.y + 1.5f, size.width - 3, size.height - 3)); } + /** + * Creates an image representation of the ElementView. + * + * @return a BufferedImage of the ElementView + */ public BufferedImage getImage() { BufferedImage image = new BufferedImage(size.width, size.height, BufferedImage.TYPE_INT_RGB); @@ -203,10 +229,20 @@ public void setPuzzleElement(PuzzleElement data) { this.puzzleElement = data; } + /** + * Checks if the case picker should be shown for this ElementView + * + * @return true if the case picker should be shown, false otherwise + */ public boolean isShowCasePicker() { return showCasePicker; } + /** + * Sets whether the case picker should be shown for this ElementView + * + * @param showCasePicker true if the case picker should be shown, false otherwise + */ public void setShowCasePicker(boolean showCasePicker) { this.showCasePicker = showCasePicker; } @@ -414,11 +450,21 @@ public PathIterator getPathIterator(AffineTransform at, double flatness) { .getPathIterator(at, flatness); } + /** + * Returns the bounding rectangle of this ElementView + * + * @return a Rectangle representing the bounding box of this ElementView + */ @Override public Rectangle getBounds() { return new Rectangle(location.x, location.y, size.width, size.height); } + /** + * Returns the bounding rectangle of this ElementView as a Rectangle2D + * + * @return a Rectangle2D representing the bounding box of this ElementView + */ @Override public Rectangle2D getBounds2D() { return new Rectangle(location.x, location.y, size.width, size.height); diff --git a/src/main/java/edu/rpi/legup/ui/boardview/GridBoardView.java b/src/main/java/edu/rpi/legup/ui/boardview/GridBoardView.java index db5ccbc82..e2b8bbc12 100644 --- a/src/main/java/edu/rpi/legup/ui/boardview/GridBoardView.java +++ b/src/main/java/edu/rpi/legup/ui/boardview/GridBoardView.java @@ -81,9 +81,9 @@ public void initSize() { } /** - * Helper method to determine the proper dimension of the grid view + * Determines the proper dimension of the grid view based on grid size and element size. * - * @return proper dimension of the grid view + * @return the dimension of the grid view */ protected Dimension getProperSize() { Dimension boardViewSize = new Dimension(); @@ -102,6 +102,11 @@ public DataSelectionView getSelectionPopupMenu() { return null; } + /** + * Gets the size of each element in the grid + * + * @return the dimension of each element in the grid + */ public Dimension getElementSize() { return this.elementSize; } diff --git a/src/main/java/edu/rpi/legup/ui/boardview/SelectionItemView.java b/src/main/java/edu/rpi/legup/ui/boardview/SelectionItemView.java index e3bb3592f..6a1429a61 100644 --- a/src/main/java/edu/rpi/legup/ui/boardview/SelectionItemView.java +++ b/src/main/java/edu/rpi/legup/ui/boardview/SelectionItemView.java @@ -58,6 +58,11 @@ public SelectionItemView(PuzzleElement data) { this(data, (Integer) data.getData()); } + /** + * Gets the PuzzleElement associated with this menu item + * + * @return the PuzzleElement associated with this menu item + */ public PuzzleElement getData() { return data; } diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RuleFrame.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RuleFrame.java index cf01f3ede..b14091351 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RuleFrame.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RuleFrame.java @@ -131,7 +131,7 @@ public void resetSize() { /** * Set the status label to a value. Use resetStatus to clear it. * - * @param check true iff we want a check box, if false we'll have a red x box + * @param check true if we want a checkbox, if false we'll have a red x box * @param text the text we're setting the label to display */ public void setStatus(boolean check, String text) { @@ -169,22 +169,47 @@ public RuleController getController() { return controller; } + /** + * Gets the JTabbedPane used in this frame + * + * @return the JTabbedPane instance + */ public JTabbedPane getTabbedPane() { return tabbedPane; } + /** + * Gets the {@code DirectRulePanel} contained in this frame + * + * @return the {@link DirectRulePanel} instance + */ public DirectRulePanel getDirectRulePanel() { return DirectRulePanel; } + /** + * Gets the {@code CaseRulePanel} contained in this frame + * + * @return the {@link CaseRulePanel} instance + */ public CaseRulePanel getCasePanel() { return casePanel; } + /** + * Gets the {@code ContradictionRulePanel} contained in this frame + * + * @return the {@link ContradictionRulePanel} instance + */ public ContradictionRulePanel getContradictionPanel() { return contradictionPanel; } + /** + * Gets the {@code SearchBarPanel} contained in this frame + * + * @return the {@link SearchBarPanel} instance + */ public SearchBarPanel getSearchPanel() { return searchPanel; } diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RulePanel.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RulePanel.java index c5e7327fd..85ddf82b5 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RulePanel.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RulePanel.java @@ -36,7 +36,7 @@ public RulePanel(RuleFrame ruleFrame) { } /** - * Gets the rule rule buttons + * Gets the array of rule buttons * * @return rule ruleButtons */ @@ -338,28 +338,58 @@ public List getRules() { return rules; } + /** + * Gets the icon associated with this panel + * + * @return The ImageIcon associated with this panel + */ public ImageIcon getIcon() { return icon; } + /** + * Sets the icon for this panel + * + * @return the ImageIcon associated with this panel + */ public void setIcon(ImageIcon icon) { this.icon = icon; } + /** + * Gets the name of this panel + * + * @return the name of this panel in a String + */ @Override public String getName() { return name; } + /** + * Sets the name of this panel + * + * @param name the name to set for this panel + */ @Override public void setName(String name) { this.name = name; } + /** + * Gets the tooltip text associated with this panel + * + * @return the tooltip text of this panel + */ public String getToolTip() { return toolTip; } + /** + * Sets the tooltip text for this panel + * + * @param toolTip the tooltip text to set for this panel + */ public void setToolTip(String toolTip) { this.toolTip = toolTip; } diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeElementView.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeElementView.java index 0233ec6d4..e5e523e11 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeElementView.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeElementView.java @@ -41,7 +41,7 @@ protected TreeElementView(TreeElementType type, TreeElement treeElement) { public abstract void draw(Graphics2D graphics2D); /** - * Gets the span for the sub tree rooted at this view + * Gets the span for the subtree rooted at this view * * @return span bounded y span */ @@ -50,7 +50,7 @@ public double getSpan() { } /** - * Sets the span for the sub tree rooted at this view. + * Sets the span for the subtree rooted at this view. * * @param span bounded y span */ diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeNodeView.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeNodeView.java index 8e9562d10..c9aedaef3 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeNodeView.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeNodeView.java @@ -266,11 +266,21 @@ public int getRadius() { return RADIUS; } + /** + * Returns the bounding rectangle of this TreeNodeView + * + * @return a Rectangle representing the bounding box of this TreeNodeView + */ @Override public Rectangle getBounds() { return new Rectangle(location.x, location.y, DIAMETER, DIAMETER); } + /** + * Returns the bounding rectangle of this TreeNodeView as a Rectangle2D + * + * @return a Rectangle2D representing the bounding box of this TreeNodeView + */ @Override public Rectangle2D getBounds2D() { return new Rectangle(location.x, location.y, DIAMETER, DIAMETER); diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreePanel.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreePanel.java index 9efeb8dfb..936b0de95 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreePanel.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreePanel.java @@ -66,10 +66,20 @@ public TreePanel(/*LegupUI legupUI*/ ) { updateStatusTimer = 0; } + /** + * Repaints the tree view with the provided {@link Tree} object + * + * @param tree the {@link Tree} object to update the view with + */ public void repaintTreeView(Tree tree) { treeView.updateTreeView(tree); } + /** + * Updates the status of the panel based on changes to the {@link Board} + * + * @param board the {@link Board} object representing the current board state + */ public void boardDataChanged(Board board) { modifiedSinceSave = true; modifiedSinceUndoPush = true; @@ -89,18 +99,33 @@ public void updateStatus() { this.status.setText(""); } + /** + * Updates the status display with the given status string + * + * @param statusString the status string to display + */ public void updateStatus(String statusString) { status.setForeground(Color.BLACK); status.setFont(MaterialFonts.REGULAR); status.setText(statusString); } + /** + * Updates the status display as an error with an error message + * + * @param error the error message to display + */ public void updateError(String error) { status.setForeground(Color.RED); status.setFont(MaterialFonts.ITALIC); status.setText(error); } + /** + * Gets the {@link TreeView} instance associated with this panel + * + * @return the {@link TreeView} instance + */ public TreeView getTreeView() { return treeView; } diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeToolBarButton.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeToolBarButton.java index 2718f733d..232498723 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeToolBarButton.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeToolBarButton.java @@ -9,6 +9,12 @@ public class TreeToolBarButton extends JButton { private TreeToolBarName name; private final Dimension MINIMUM_DIMENSION = new Dimension(60, 60); + /** + * Constructs a {@code TreeToolBarButton} with the specified icon and name. + * + * @param imageIcon the {@link ImageIcon} to be displayed on the button + * @param name the {@link TreeToolBarName} associated with this button + */ public TreeToolBarButton(ImageIcon imageIcon, TreeToolBarName name) { super(imageIcon); this.name = name; @@ -17,6 +23,11 @@ public TreeToolBarButton(ImageIcon imageIcon, TreeToolBarName name) { this.setFocusPainted(false); } + /** + * Gets the {@link TreeToolBarName} associated with this button + * + * @return the {@link TreeToolBarName} associated with this button + */ public TreeToolBarName getToolBarName() { return name; } diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeToolBarName.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeToolBarName.java index c805021be..3aec664be 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeToolBarName.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeToolBarName.java @@ -1,5 +1,9 @@ package edu.rpi.legup.ui.proofeditorui.treeview; +/** + * {@code TreeToolBarName} defines the names of actions represented by buttons in the tree toolbar. + * These actions are used for managing tree elements within the UI. + */ public enum TreeToolBarName { ADD_CHILD, DEL_CHILD, diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeTransitionView.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeTransitionView.java index 70546616d..5a3aa7d5c 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeTransitionView.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeTransitionView.java @@ -271,47 +271,67 @@ public void removeParentView(TreeNodeView nodeView) { } } - public Point getEndPoint() { - return endPoint; - } - - public void setEndPoint(Point endPoint) { - this.endPoint = endPoint; - } - + /** + * Gets the x-coordinate of the end point of the transition arrow + * + * @return the x-coordinate of the end point + */ public int getEndX() { return endPoint.x; } + /** + * Sets the x-coordinate of the end point of the transition arrow + * + * @param x the new x-coordinate of the end point + */ public void setEndX(int x) { this.endPoint.x = x; } + /** + * Gets the y-coordinate of the end point of the transition arrow + * + * @return the y-coordinate of the end point + */ public int getEndY() { return endPoint.y; } + /** + * Sets the y-coordinate of the end point of the transition arrow + * + * @param y the new y-coordinate of the end point + */ public void setEndY(int y) { this.endPoint.y = y; } - public List getLineStartPoints() { - return lineStartPoints; - } - - public void setLineStartPoints(List lineStartPoints) { - this.lineStartPoints = lineStartPoints; - } - + /** + * Gets the start point at the specified index from the list of start points + * + * @param index the index of the start point to retrieve + * @return the start point at the specified index, or null if the index is out of range + */ public Point getLineStartPoint(int index) { return index < lineStartPoints.size() ? lineStartPoints.get(index) : null; } + /** + * Returns the bounding rectangle of this TreeTransitionView + * + * @return a Rectangle representing the bounding box of this TreeTransitionView + */ @Override public Rectangle getBounds() { return arrowhead.getBounds(); } + /** + * Returns the bounding rectangle of this TreeTransitionView as a Rectangle2D + * + * @return a Rectangle2D representing the bounding box of this TreeTransitionView + */ @Override public Rectangle2D getBounds2D() { return arrowhead.getBounds2D(); 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 3d74d1e08..65f49ff0a 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 @@ -57,6 +57,11 @@ public class TreeView extends ScrollView implements ITreeListener { private TreeViewSelection selection; + /** + * Constructs a {@code TreeView} with the specified {@code TreeController}. + * + * @param treeController the {@code TreeController} used to manage tree operations + */ public TreeView(TreeController treeController) { super(treeController); currentStateBoxes = new ArrayList<>(); @@ -68,6 +73,11 @@ public TreeView(TreeController treeController) { selection = new TreeViewSelection(); } + /** + * Gets the current tree view selection + * + * @return the {@code TreeViewSelection} object representing the current selection + */ public TreeViewSelection getSelection() { return selection; } @@ -137,6 +147,11 @@ private TreeElementView getTreeElementView(Point point, TreeElementView elementV return null; } + /** + * Updates the tree view with the specified {@code Tree} + * + * @param tree the {@code Tree} to display in the view + */ public void updateTreeView(Tree tree) { this.tree = tree; if (selection.getSelectedViews().size() == 0) { @@ -174,8 +189,9 @@ public void reset() { * button is selected */ public void zoomFit() { - double fitWidth = (viewport.getWidth() - 8.0) / (getSize().width - 200); - double fitHeight = (viewport.getHeight() - 8.0) / (getSize().height - 120); + final int MIN_HEIGHT = 200; + double fitWidth = (viewport.getWidth() - 7.0) / (getSize().width - 75); + double fitHeight = (viewport.getHeight()) / Math.max((getSize().height - 115), MIN_HEIGHT); zoomTo(Math.min(fitWidth, fitHeight)); viewport.setViewPosition(new Point(0, viewport.getHeight() / 2)); } @@ -224,6 +240,11 @@ public void layoutContainer(Container parent) { }; } + /** + * Draws the tree view on the provided {@code Graphics2D} context + * + * @param graphics2D the {@code Graphics2D} context to draw on + */ public void draw(Graphics2D graphics2D) { currentStateBoxes.clear(); Tree tree = GameBoardFacade.getInstance().getTree(); @@ -255,6 +276,12 @@ public void zoomReset() { viewport.setViewPosition(new Point(0, 0)); } + /** + * Recursively redraws the tree starting from the specified node view + * + * @param graphics2D the {@code Graphics2D} context to draw on + * @param nodeView the {@code TreeNodeView} to start drawing from + */ private void redrawTree(Graphics2D graphics2D, TreeNodeView nodeView) { if (nodeView != null) { nodeView.draw(graphics2D); @@ -265,6 +292,11 @@ private void redrawTree(Graphics2D graphics2D, TreeNodeView nodeView) { } } + /** + * Removes the specified {@code TreeElementView} from the tree view + * + * @param view the {@code TreeElementView} to remove + */ public void removeTreeElement(TreeElementView view) { if (view.getType() == NODE) { TreeNodeView nodeView = (TreeNodeView) view; @@ -424,8 +456,17 @@ public TreeElementView getElementView(TreeElement element) { return viewMap.get(element); } - private void removeTreeNode(TreeNode node) { + /** + * Removes the specified {@link TreeNode} and its associated views + * + * @param node the {@link TreeNode} to be removed + */ + public void removeTreeNode(TreeNode node) { viewMap.remove(node); + if (node.getChildren() != null) { + node.getChildren().forEach(t -> removeTreeTransition(t)); + } + List children = node.getChildren(); // if child is a case rule, unlock ancestor elements @@ -452,11 +493,13 @@ private void removeTreeNode(TreeNode node) { } // set modifiable if started modifiable - boolean modifiable = - tree.getRootNode() - .getBoard() - .getPuzzleElement(oldElement) - .isModifiable(); + boolean modifiable = false; + if (tree != null) { + tree.getRootNode() + .getBoard() + .getPuzzleElement(oldElement) + .isModifiable(); + } // unmodifiable if already modified TreeNode modNode = ancestor.getParent().getParents().get(0); @@ -474,10 +517,14 @@ private void removeTreeNode(TreeNode node) { } } } - node.getChildren().forEach(t -> removeTreeTransition(t)); } - private void removeTreeTransition(TreeTransition trans) { + /** + * Removes the specified {@link TreeTransition} and its associated views + * + * @param trans the {@link TreeTransition} to be removed + */ + public void removeTreeTransition(TreeTransition trans) { viewMap.remove(trans); if (trans.getChildNode() != null) { removeTreeNode(trans.getChildNode()); @@ -514,12 +561,16 @@ private void removeTreeTransition(TreeTransition trans) { } } + /** + * Adds the specified {@link TreeNode} and its associated views + * + * @param node the {@link TreeNode} to be added + */ private void addTreeNode(TreeNode node) { TreeTransition parent = node.getParent(); - TreeNodeView nodeView = new TreeNodeView(node); - TreeTransitionView parentView = (TreeTransitionView) viewMap.get(parent); + TreeTransitionView parentView = (TreeTransitionView) viewMap.get(parent); nodeView.setParentView(parentView); parentView.setChildView(nodeView); @@ -554,20 +605,25 @@ private void addTreeNode(TreeNode node) { } } + /** + * Adds the specified {@link TreeTransition} and its associated views + * + * @param trans The {@link TreeTransition} to be added + */ private void addTreeTransition(TreeTransition trans) { List parents = trans.getParents(); - TreeTransitionView transView = new TreeTransitionView(trans); + for (TreeNode parent : parents) { TreeNodeView parentNodeView = (TreeNodeView) viewMap.get(parent); transView.addParentView(parentNodeView); parentNodeView.addChildrenView(transView); + viewMap.put(trans, transView); + // if transition is a new case rule, lock dependent ancestor elements Rule rule = trans.getRule(); if (rule instanceof CaseRule && parent.getChildren().size() == 1) { - CaseRule caseRule = (CaseRule) rule; - List ancestors = parent.getAncestors(); for (TreeNode ancestor : ancestors) { // for all ancestors but root @@ -584,15 +640,16 @@ private void addTreeTransition(TreeTransition trans) { } } - viewMap.put(trans, transView); - if (trans.getChildNode() != null) { addTreeNode(trans.getChildNode()); } } - /// New Draw Methods - + /** + * Draws the tree using the provided {@link Graphics2D} object + * + * @param graphics2D the {@link Graphics2D} object used for drawing the tree + */ public void drawTree(Graphics2D graphics2D) { if (tree == null) { LOGGER.error("Unable to draw tree."); @@ -618,6 +675,11 @@ public void drawTree(Graphics2D graphics2D) { } } + /** + * Creates views for the given {@link TreeNodeView} and its children + * + * @param nodeView the {@link TreeNodeView} for which to create views + */ public void createViews(TreeNodeView nodeView) { if (nodeView != null) { viewMap.put(nodeView.getTreeElement(), nodeView); diff --git a/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/ElementFrame.java b/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/ElementFrame.java index bcb69f6c0..1619ecbaa 100644 --- a/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/ElementFrame.java +++ b/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/ElementFrame.java @@ -19,45 +19,30 @@ public class ElementFrame extends JPanel { private EditorElementController controller; public ElementFrame(EditorElementController controller) { + this.controller = controller; - MaterialTabbedPaneUI tabOverride = - new MaterialTabbedPaneUI() { - // this prevents the tabs from moving around when you select them - @Override - protected boolean shouldRotateTabRuns(int i) { - return false; - } - }; - - this.tabbedPane = new JTabbedPane(); - tabbedPane.setUI(tabOverride); + JLabel status = new JLabel("", SwingConstants.CENTER); this.buttonGroup = new ButtonGroup(); - nonPlaceableElementPanel = new NonPlaceableElementPanel(this); - // nonPlaceableElementPanel.setMinimumSize(new Dimension(100,200)); - tabbedPane.addTab( - nonPlaceableElementPanel.getName(), - nonPlaceableElementPanel.getIcon(), - new JScrollPane(nonPlaceableElementPanel), - nonPlaceableElementPanel.getToolTip()); + // Parent panel to hold all elements + JPanel elementPanel = new JPanel(); + elementPanel.setLayout(new BoxLayout(elementPanel, BoxLayout.Y_AXIS)); placeableElementPanel = new PlaceableElementPanel(this); - // placeableElementPanel.setMinimuSize(new Dimension(100,200)); - tabbedPane.addTab( - placeableElementPanel.getName(), - placeableElementPanel.getIcon(), - new JScrollPane(placeableElementPanel), - placeableElementPanel.getToolTip()); - tabbedPane.setTabPlacement(JTabbedPane.TOP); + placeableElementPanel.setMinimumSize(new Dimension(100, 200)); + elementPanel.add(new JScrollPane(placeableElementPanel)); + // Set layout and dimensions for the main panel setLayout(new BorderLayout()); setMinimumSize(new Dimension(250, 256)); setPreferredSize(new Dimension(330, 256)); - add(tabbedPane); + // Add components to the main panel + add(elementPanel, BorderLayout.CENTER); add(status, BorderLayout.SOUTH); + // Center-align the titled border TitledBorder title = BorderFactory.createTitledBorder("Elements"); title.setTitleJustification(TitledBorder.CENTER); setBorder(title); @@ -75,8 +60,9 @@ public ButtonGroup getButtonGroup() { // } public void setElements(Puzzle puzzle) { - nonPlaceableElementPanel.setElements(puzzle.getNonPlaceableElements()); - placeableElementPanel.setElements(puzzle.getPlaceableElements()); + if (puzzle != null) { + placeableElementPanel.setElements(puzzle.getPlaceableElements()); + } } public EditorElementController getController() { diff --git a/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/ElementPanel.java b/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/ElementPanel.java index 46198e226..70826d25c 100644 --- a/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/ElementPanel.java +++ b/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/ElementPanel.java @@ -20,7 +20,7 @@ public ElementPanel(ElementFrame eFrame) { setLayout(new WrapLayout()); } - public void setElements(List elements) { + public int setElements(List elements) { this.elements = elements; clearButtons(); @@ -38,6 +38,7 @@ public void setElements(List elements) { add(elementButtons[i]); } revalidate(); + return elements.size(); } protected void clearButtons() { diff --git a/src/main/resources/edu/rpi/legup/images/Legup/Reset.png b/src/main/resources/edu/rpi/legup/images/Legup/Reset.png new file mode 100644 index 0000000000000000000000000000000000000000..fd6ffefa0fd001bd771519e6094c57919b51f2ba GIT binary patch literal 662 zcmV;H0%`q;P)(^b8FWQhbW?9;ba!ELWdL_~cP?peYja~^aAhuUa%Y?FJQ@H10ryEnK~z{r?UqSO z#6TEE+hL&~;Jf$e3Vblb4i~dmL!9j@J(*YIms31lg-lTkxUpb^2)X4Dqu}o z(3TvO)t~@=^_R498?s&U9g}QguSKwN%OB=r+gBXy{GGua~04_B}z_KKR zEHb^>l?>b|fAYr)K>iIt23cf!!HVY|QguHK0Z_oZ)BYV~kVPihzlg73V_vdQ_T&W( z0q{#%^~i)k23cf!t%UB)ckXuV<3Z!!#7ckR+3A=7>n%f(}Xb zukwzDf*^}bvY8_yZ4LYfnVV0t0RBEy+a{^DD99p{Z03ka7VsfYDyO9hcPs+SBAYoP z(r&?_JI=Uc5zM-yWmlz^jVO((8&MW{x8gK{w_?cqFiOH$GRO*g7(t%LaU7c*$;!p5 zv=E;c5}*%#Z5$aj@z*OEa!woH(TBc_VQe8}y_CKWWh72gaC{&})GxDgXcg07*qoM6N<$f~1Tez5oCK literal 0 HcmV?d00001 diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/CompleteRowColumnDirectRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/CompleteRowColumnDirectRule.png index a74654d4301f75defc639727604f3d59f05612a3..27ccec97290109fe20d727d468465a57af330906 100644 GIT binary patch literal 2174 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 W-$D%jr3*N)f}HK$?8r8Oq<;bxYC}%| diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/DuplicateRowOrColumnContradictionRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/DuplicateRowOrColumnContradictionRule.png deleted file mode 100644 index 214aa53483ccc0f6749bffda004ccfc2f70ded29..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3455 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 diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/OneOrZeroCaseRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/OneOrZeroCaseRule.png deleted file mode 100644 index 73072f2ce5ea9d189fe55058aa6a4fa09ecc3979..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5578 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 diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/OneTileGapDirectRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/OneTileGapDirectRule.png deleted file mode 100644 index b68f67e441d3519f17daffd48da37f35e9b3bcfb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2751 zcmai$3sh3s8pp{CWlla)Oe`nS#-N;3%6vr{iYaM?_=-%^AvA^|Qy`ycLq%pzn$J{9 zqa5@73MNIgNqb>Lr6Xym>15ne!)HX6-s3cD&Aqc`=AL!V*=K)yuk-D-zu))&_E`en zOIK&D4hRI&#d%|iKq~>Bd)mu^_x|~Z$AJdSaK{B`16Q*4;WVIc%JkgN^pB2Y#zn+Z zKv74d>69%Dax8^%lyM}QsrpyDD==xx(j<>qN(7S{eH0!*rBgrwED9Xu0LL7Qg>SXn zY7e)wciDz=0W5^Qa8GQ&6CG>{2&4nUVKD*myorH`Y<}ySGgH6Ti1fp)bgeH`pQ<+u zx8mlt##jyNvt#PLrY414aLG_WFlk$m^mUdS7I%L*w)r6V7Ju=(P*9c@M+<2H-8I~< zUU=$^pg-rx@5S}ZI&|2j2^?Pc zkG16gNEO;d87p}(a&|5I!8e4)uXE6{LnME@P4df1XMq=2f98Z1W*Jmlr*szq1o`al z`%;h&7(##}|7VE*QfxxbfO=X42I2w(N5n%d)dT0s23DqX82EI)fs)6=BdA5YTh&D9 z=~;F=D?w!JFEYwS0EWQ4v^29!uLm<9Bfrl?ajm=7p}$pAfAIVFaRhST!vd@r z53u#a$SHR&)P?!5$ zF&T6mA?#F@v~6`RB=hpxc-hA`os=jkE=r2}pv!4=&+y>vlr)ZSQGEh>;nG0Mp27*E z>Sq3_wbO>V5T6yp%3n^Gw&F?oZ$Ngl>9=I%#j*}m>R#_KS`o-O!TzPLhDYX1ciJ-o zUrsF>Yq2?qG3Qf@Xd;;^N~-EV^IaTg8XGE?*RSe0rrTvtRWV(rewkeNG9iVo*1Wt| zF(9h_BGC$g)amUXGp()M>};k-lna3E<%UKduF0z%dn-%|m1Afmg*ha(hxO&h7vTve z)mbL0ke9f^58AC}I4_NILiIhcgH>+J^xCLQSC1N;Fg*C}+ zb_3l#y!*!;mOst=J#vh>)V?AUvT~1{MU>C6{9&yn>V?Q7+oRQ*u{Kq6C33RHBs&S# zxkg)puX+7(Mv9Fw$MjWf@7Tl*ldaCZG_rZ>0GLvK6G-W$i~%O~#kz1OD#%_0I4PeV z>OKqDq^dTzj=e9Gz$a=pu||6Gwxf;ef>I+@v?T119a7Daey&@CMuIo+sCVn{|60ln zH4$FNLUbi!s&Vz%_>#u2>mp3K!;v{w7gSkx<4;M7cf*0zf>_s*J4uW3?@jOdWuSaJ zQjKU6+mYRpyDhb&@o2+rV-5uJyke{<=dmq)A!5Dvvj3aX^-l6CdWb34B4CRxs>GuB z+X?m%LOpwTXU|e#2j>sVGYRt!#NR{%aF1T^@yoQ~Kk16k@xmh#L3u0MakRf+GGhIo z<>OBr{tkzM{eOjjKP`usJ)jmtJue)d*i@u8B|qFavHol1BWC~x9wXM}(lzQ@V96DF zj*!DuC+Dbu&B?6O84)T6*pR0{6Gd5Y%+#PyV4&r66r&i}%jbHX>(`Jo%=A`h89tV| zZksEpkezZ}gW+tYAKVZtI`kshq@s z5frU2DSG6#c;2jpwzs5ks358QI!CKIk3z~?R8C+>j67}D@m-4E*+K$hT(kbP4U!ypTM!1ET4rEih-i+L>~e#U4!_tX-(6qUJZ> zpAg^FgwAIzt^ZZXGC+lz`ZCkLLJdz2-bmjcg;rrm`SSXQ2seDO$M(HOOlafHi4JQL z%}T~F>o3a5pLqDJOLa}#{ZS=_yw5cDJp6;k@V})|ITlA8<{6QFp9*YAtM=qmp4eVb z{A#p+23`K{J~%X!GsknHma!M^>e@f`-Za`v0b>Z3juIqZ(MwU}`QQl#Ce}gc4ev$S z*oJMc5ZY`&avh!{~R zr`uFz^yk-H3K{sy%51c(ZvHHce2pHWQI@1;UwpmJL&Wg(tM8QzA2T5P5-pa%Wy>BE z3HMw~!D7?-X&=-Ly?gwiem8bt5^lpbBwY4tn7egg=7;mIg3oIr`Q4HDhQj`x`C^8) z#0W?M;2zg;P>S1E{@nU*NzxqMLWYb&L`G2TqMbH}^Ao9Cqbxo<;>v0Cr*ZvJdg5<9 z2*=Z_I%%t+$2|Su$Q_=_)GbScZ{0d$>ntO|kZej{uN5}4biC)|+xcxMMS0qnONw}@ zv|kBis{VccD)Jf+zeyREH_BUsvx10vSS_8|G3z#~DG^WJxBo%8ZlVpm@si?gf$O8gXF zxK8-V48wcVgZmU67fP`gbg(yIxgU806m1BT8`ikb)R_`8dkfoxm?xT+|l| zV7U>n?4)t2eHS2WD(S@^1_Gib0^1hF6V`wy_WiK(YD!D3$mC4dXl%2YO+lCE+sQ#h uTqJ0rCdzuJ`EtlDbHy?6@29KNi_1(v%rOsAUJ`J)1mQgK*jo2+&VK+~O8lz; diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/PreventTrioDirectRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/PreventTrioDirectRule.png new file mode 100644 index 0000000000000000000000000000000000000000..ed0701f26fc1880098ae5f07e8c309e113a63662 GIT binary patch literal 1944 zcmbVN`8OK~7mZpHwfAFCu|!)MM6D$)v46IvRHJr+qKa0fG|ea_H4!9bx~SG(2{N&E zYFA5Yr$eJgYKyHXB2%?hFqwa$=iK|=x#zs|&bjaY@QALL?In(%JPrT=Bpe-V-S|E1 zKY~Q~RoTjSkKY6^ZuZuI$`9Zbz7PttLRtX;HIK!3fx>((8tveP;g6>LM**&q!5RPn zggM$;p|Jkzc|JE}Jro`uA!{37>~|r9APZ-ZkYR^jJj~5u1ZU-{BraT&_#+h20igi#ojLq7dHy0oD~tYL!BN$_r_vo-cOn49brRL&vy{vVf)Po z7N&!_In{5D5)3hihM3T~V*rMZxK-!EQ%EYTM^C(Bk+-+0XJS&%zTi$NFBhejmdg8< z(u_<@7~|vP$*U+iF`p01%VoJt#=^pBaVe>Rmns?>8tCiSZO6V#XGD2&!%2ENgr7uR zZb`{$cqu_n`4HX4aNPVoLo?U()DPRHHRap=W)fKJf2Kzs#H*Xf{pLcx!K`elc>gK_=h) z*X_;*sNAEJln(j^lsCc>$(NFdPMKGLH@e9LhRPn60!~HER@YU7I;R5r=PmVM!=0y4##7ZE9U^Wu-0znC_&muHHUjAzAQXOJCM_AEMqZeE2Y+(%t6i#S`(< zfIqX}TMg~BS^BzVD72TInCzocsf8^q;7Y${k(!#C7!r=oq{2#DTm4?;j&z9bew%PR zTc(`!*sOUL-{7+7ZOl6#d(0cRS{P9eOfd5nt09hfFR*WXq|vk*a9gwoUq_P8XqK_O z+d&U|@+2BZHnd^kGG23UY)FOu9S0Ef3lctvYgn)mQ6#*B0d0E6aCs4V@-x@#d*$~(tDbArirdEf-FmN9+EiHL^+TS#q z4OnBnu`iiQXjAQE45?78^Udxbo2b7{=Rh&Unb4hp&njTK%7E(d5Kael;O{x zk0T0P?t^L3r-A#3@ega`HG(l1OqT)u4^B$JyLhil9+kdODvQO6-u!~Z@^)*=&dKxM zdDcZui2UJE^~->3##d9+tb-({5eo~SYKqOw&DF`KEp?`d1>KB&RAGM7C0485w0g54 z;Q+_Qn#DlXeTG9_oGeV+sgVr^|$1%y0?IVpU7pwa0PK{ z9v+V`M(F9OQMFjLAz}+lOExw(__E*tp$)@wvlu-x-;DfRA@1{CzGdLl)KoNQ5}s8d zCo9{2u)kCE`n3)Hs&JghKOrZ^S>_2m)5z%-#hVck&y*>TNwV9(p( z;a5%)w7A%~yB5IgU?sGlTzh0#Xy}(`7L&Yv_@1#~^=8Fu*Id+@zjY<4t-FF3iW0u7 z8Qt|@%oJ4N77xJMl9K}TwIN4)*~g}}I~eZ3tQ5(*x)7|qPENV1@7$Fp=n|y>xROE~V^HjmF+LfbkfTMeYVVacM??MRn4*+C>B**8XCpF==@faf zMR1s0BEm&X;|D+3;W&H-q?+xNjEfxVeW@}iNuS-qg&?JnNMtu2C?&qxJ98`T|$CPGbez2o-NW+6xHbT#B6n+jq zJ=L^k&%&)j3dS@uU&iYTb#c) zcZIBvK-^kh7%jir&E;0pSBj|A?&a0hC&uQZpFSy?o152Cfdj;;FN08(-2($tO9ZN} z2v>a+6kYfKpESomi4U1`ge0B2$ApiGb?D!LLZP)(0y>h>sZ!rPjCYB+F0c#i(WWcP TsFd*d-xT0zciFbm8lC(vAL*4l literal 0 HcmV?d00001 diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/RepeatedRowColumnContradictionRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/RepeatedRowColumnContradictionRule.png new file mode 100644 index 0000000000000000000000000000000000000000..5cc030a7671f6e567d56c9d71ddd640bd5a33336 GIT binary patch literal 2124 zcmai0dpHy7AK#k$t&OG`5l(UtO|E4!*H&_gL#7RLmI>}({(;9>v(KoWh< z@)AFL^MfEF#9!U;*d%@ek}lbp1Ij)s%=3YO59%Tc04Prv-}4gWW6>Mu+(-bxk;K0O zn9g1!006?1XiJnc8Ml<@cP`si;eAxdTlw4PoMme-AL_3WIsbEx`aO5Z9S5;G;v)n& zyu8*yZ*W+w$t10wU^;F$H_Lsq5Vh_Z>5vOty! zH$*BKk?HSeL$8mISDVc46dI{4NC`KBgr3#M3R||!EiZ>i`FzZ$hL7v%85mgC21<|B zQfzF}6ejDtxPj8K)9K*XT==}4qB5QwpELTc`V6`Zybm({wV&ATmrn8^7$^pPWT+-}W<4rav_N-04uiopVBb`D!IC6EO@!pk9(TKYRcH{co<$T`mUOF)%prE2wwz&_NyoPge()RX^(*3lPC+#F* zt3^9_@<}7eCI!~G?ccBga~iLUV0mwRdSFr712gc4rOKU3V0n5c`y@)pHL+kQ50SV6yzwyg2mOQ6=NX!w7J+d_NHhp=#zB85< z+ZGfQ^r^qpJ*+i$(>8`o%h+BS?-UmhFp8J_!0X5}?CtHf9H|WO_OhkO`4^f-v~7*O z3)MM8@UVnh_+Z@J&{Qfl|I z(nBPL^C|PV{fqTPnVRz?|2dn}J|&s^_K=Y-D?_gn4cju=9ZeBd%7|vDHjv4iAMw^I=~I z1j5|}1Zq1ac(H%&GBR+?1XCNXZ!I{hwmWnDvCQ!{z_b9FNTapY=-Jr1XM!tGUj z6yh=l!|x2exzMM%WjS6HT7aZvsoB!Z0^Bc0j#oP5Kw6b=k6JFmJK-+vgFH}G{A(MF6^7^@DCQ4CadHYILqr2V zY^6_DY(4;&ZI;mR$rPgBK2cL$dcrKuvkM5s8UTUeDhtu{nM+ZFjbknSFFM6n1V6M^ z_-0^7?huTf!-`SZp+|;dSkaor?*Wavy9)yr{2?yzJNrm~B+A*9v*$NZ`NtnEWRn$1 zwQ3G0Bv;=rYvUDU95nN>;Q2BQ0S>t7m$PtY^9Qe-lSJ?pmRAl>tpv7eZLHM;>b~2o>t&zStShF+ zRLJ53$f}k_0t+&kY0uDm27`>QpV?1;V*2 z95`PwLykw*&51?soQ&8F3ML$k@3U7J!Ag|>iX|v literal 0 HcmV?d00001 diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/SaveBlockerDirectRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/SaveBlockerDirectRule.png new file mode 100644 index 0000000000000000000000000000000000000000..7695ae2da1303c723d962d0da95bbb4fb9abee98 GIT binary patch literal 2204 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 diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/ThreeAdjacentContradictionRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/ThreeAdjacentContradictionRule.png deleted file mode 100644 index 862408b63a9c6d72d815b79064ea587657bc5e5e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2508 zcma)83p|@y7Ee`YLd#NAwMww9R6QD{q}w7D)x;~}Q4+LDWE9aRD2<}VdY5`@Cdjr$ zsd(1An4yAr^?auDb%+7wl`+eu$bI-ZId(Ziw|NW9M_SQ1e zhonIukPPY~5(`K+@b-Ye0={nIfiOTwQqH5C!N3y<_DuxFDj`;GAx^=5Ave9r1Q3xF z97NEg_>c(%66KrVkmcPSW`L32j*%sq;2q*0OoBN32N6Kdp#%u*Gz4*-3^6=uXaqTF zbjHvWXb_AY#0u$rWbU932qbkBg+w@q(*=_V@=TKwOIYe$UWan6V+SG&kZ({(I`Rby zS%`dL_q|fY>b!I3C71W4_u`ar}h@v4pK0QUV^9La|f%4u<^=c~2Ow|#Iq?KfBMVYT^ zjWv5!y=n-0S%27P_PXgKePXWhh#A2UD&F#3mz$+>`l2l_da}RnP)}bGyfofo%ViJTUOuytPATheT2gm8x^1TBlve|e#U@S_ zWJUXthgY>ErAGbW?AuC!E||;w)So{>NKEWi=auSv-#B|+QV}f8u)u)!0H={tw7A0n zNlWg*K%g<5(+GdAYeoGuU17N`PNL|2yxen~jbN{hyZ9b23>T^-WM zbURm&+-$2T4=);SjlrzWyK`t+OC3hW&#zMCC5zWr7y~NCXneJ7mDUpmsCjdR5!i@d9j4j3 zs_f$7Ba!@hwWEOY8!ooIToc+ms#$dF?j;lTbm$CchNpH#H^ISLSt^-gpBBw@ua z<(X54*XF`qvJmfDDx2yX;>~I^0}P7mZU(;npx3;H63Q-kD9X#G<(;8ZMALFUsW-?- ze_BaXj$o!;*X0JFb`6WM=PwPY20e|KsGj@sB^dV zzrjiZvFrB`CxM8N?|Q%)f(v=Xnw-wz>d|9m1&oS`YHCdV+G)Y}xbJ?76RYs3HKT05 zI#k1^nbVz1x^a+EoRHVyex&^ujAaV!iC-Y*K0xzDy4N%W1#6FmzaIMnuvYWrde=%7 zy_DyPwOEZfZknHFaO3#FbV%uIRNL@;CJV3hKCE>%FDVszF=~Hq45MO%zO*T9r@`6Y zPqm;YjEUJ-kP&H&3TOWS+8iJiwb%=q&=cK#+s$A$da!wyU*7z}PEU%x?)~TYUtHj0 zs%BAxM-c91aBXwMj(0X}-VUTTIdRFQ`&_aF!o9}&2|K-LJg<5sQnu)ge6|v0s83iW zm|+F!SYE1xU7%Brqn-9@M1s-D4b<3LvZY(Rlt-v%ipVRi=b?vw-pJfJqk-OvrOhr; ze3b#*D(19U`3;?VYLDqc%s!UFAlU-r1vU|wr`s6(Q8u#lbUisrjXw>(aL17aa9#8{ z&I>-CEXbNZGSm#!R8=(yHC=e$t-(4tGn@FzXt1K018@2lrzPiOj2r$pAO_F=Cgc1H z8XEqXiu&W*5f(v0M)-0!?!q$d@0yce5^OaTv-^OQbe6-?DN_%tck7{__jJYlYTaK*ZfEMipV;Cys58|Gl%#h^@%$aE-m7yH4NQ+JPAkQ6 zvE_h|Z3frqO{nhv>=J+Qu4LB#wR_vOTb@;%;>C3%%NasneS%yv{$2DsHP1u*C_I6p zpA7!G#|DTd^+qC$WeR^_Wal)2`+-Ll@{~PWVHZ+iW&QUFGW8Dk_o2%u$Y&xe4k#?_yKc7UweQ3_)RWjD(}SUUa{2X#QFp@fT z*x%8;JS?^rOR;D0HN28?fgM&TYH#lpt1%JT$ILSA8JA+CReX5#>*=I>Ps-W)Q23}l z#x-!l*7S4~L-dx2?PrF?K2SWr{$VJ0rYGNLsF|Dmc}DgvAO6>!l9bY+4#98YmCO^y z@AKE=L|!eGt%s!pn5wb~6~ujo!$kRwZ90u#54)hBXTyF~NFG8>iQGr*F@=xI%bT{$ zc!v{?#z7W7!dr>j>9bfML=UnR&{`Zv2dz-S#KV7H#lM&3{6O!%pf>Hhf0JpQ9jACH ztY`3-J%6)KkFgHU70AVgFS{dU3<%{mpGX+cv+n;uGC!IZ*`n}x&#E=>rv*Y;*&{2@ HUy1z(|GtR) diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/TrioContradictionRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/TrioContradictionRule.png new file mode 100644 index 0000000000000000000000000000000000000000..e292ec9faabb7c263093b94a3bacdaf56e0d05d7 GIT binary patch literal 2071 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 YvemvPddB(hz{-lj)78&qol`;+093R}SpWb4 literal 2793 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 diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/UniqueRowColumnDirectRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/UniqueRowColumnDirectRule.png new file mode 100644 index 0000000000000000000000000000000000000000..7785d198c051b4d12db29f526f8cd33d2cd3dadd GIT binary patch literal 3304 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/WastedBlockerContradictionRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/WastedBlockerContradictionRule.png new file mode 100644 index 0000000000000000000000000000000000000000..8813d79560f6a76fb82ef540090b7a0733a9cfe7 GIT binary patch literal 2006 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 Sv5EbE0GOFrq3V$CN&f<_R|ZM| literal 0 HcmV?d00001 diff --git a/src/main/resources/edu/rpi/legup/images/binary/tiles/NumberTile.png b/src/main/resources/edu/rpi/legup/images/binary/tiles/NumberTile.png new file mode 100644 index 0000000000000000000000000000000000000000..41fb61dfa57c243c91f79eccd78abb00c0926052 GIT binary patch literal 370 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 delta 1821 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 WkIb#St||U~0D$=WIeZz;EAn4d&G7yJ delta 1825 zcmai#`9IT-1ILH3v*1TY^61bQna0;S7b1Ngq< zZyEeSeXx;k7e#cu+y!We?{)f3DY55&!IzRv&{nY`W>=`Qc-eWbdY4!751OcOEcFLm zGe=3HKAiu}q3e{ZJw-w-wzu!-@JP?@AmHSbF*@zGHPd}CvWhue@3qOS4ympFtVCrm z;$x_3pXERdy~;nvy1J9wP%br|5w@%iU4J zaHR2`c?7TYiuCu^Uk$;}OC8S#%-I7fOGRjrkA#R&gI|9bm@$h7$~w<^>MPaQFHNaXnQo%+|(FyY>ObI z{zXbru|xRz`B^$Rs63r%_Ol%Y2`nA9gmhp&OjLX2m%ZRSpZHq(rgFlQZ%jOq7>Ba0 zGA(szKya!i^k?2&J7n7c%Ncr@R3Z<*;G32HOr+4r!c0?8K4a-?&TaLOBdRWCG3w{W zq_)q!lb&lr1j&s4zE*734Dmt{a5LnHl;pQPZ>*%E@@L5LfybAGGIg)YP+Eqxo^L@T zb=z=5KjYMKb)1o(em%fq`Ev$xw9GMOx+!QS_pFAl5yq-G2r3C^5!_AC;@}Hf{_FPx z_u09GbRBa175#swAo?x~QNllGTt5w?MfdQ^2{n+$uw3bb`FDEz(ll~`)005gHUd}H zg6RQ9yY|U9%hNd~F>*Y7XQl;cDRyYM$MoO$Km(QS!!>YW>r&#{Po}<S1>J-Y%9!2Hc$sn zfZ$zK1qFq|)bd+yrXU`EvoI~{k6D%zi3uGvmG6p^%#Y}U(;?aA-doT~dzk0T1WDGu z1>DW^_m4TsY%5oscXmA1I?CmwRDe5vsW-(d(f01$+&mSt6+TMfW;!mk!gE+zLYMO1 z$KhXa_M-?vz_HndXhPiyw-58FlEXZ_sW()b6aiD z-sTr`E?pX?=hwz$zBJnGT`RMbLxi8R;SlzPm-kq?!AOanm>zhxesA*|5(b0O6N!AF zG<}BaPyv}9`p>w>lQrG1U`Rvgd(w??VH0hJ9Z<{2l0iqP5e-O|x1*=+`3yH4BCLJIY!K zP9Ij1tgcov19$Q`TV@iFk8)rR#X7&{Jp&$l817Sh)b7+0vvR|KJr!-?w>pFmxSq(e zA)(;G;F<}inv1CWLWPY9FMo*H)p*l4CTqPi3X6-2hey~B0Bq8QYpFdFYAgKdDp@dV zmB8TU>EN5+b%zOnU0o7!hW4YKfn)0hD}y@PuM|xw=#aK*ax-+ZzlG6s)p}vN)c7lD zO@_nS8xGgEDZy|4LL!l_pVM{eL>``bj_pkAl=tY^@2nEL+Ep`!z{sMy6^_H2ST`tc z$O{Vu|0elwOynZeV=3G+lAXJ}!EIP76EisOQs=M?pkA z&x#3oL{|9{nh{xO0bUkTcVDqLm2)U;Tx>Uw8Uo7te}RBslvXqLQ{A(gsfKW_5QI0j KxK(QC6!u@kxo!{u diff --git a/src/main/resources/edu/rpi/legup/images/skyscrapers/contradictions/DuplicateNumber.png b/src/main/resources/edu/rpi/legup/images/skyscrapers/contradictions/DuplicateNumber.png index 7ba489c2bb1b9dbdf7669a1f69c06abfc111e1a0..6ab3cd769669c4269dfbed60c311fcd7629d644f 100644 GIT binary patch literal 1991 zcmb`IX*e6`7RO_zwl=L0OSD{jFtnAZp{O>oM2Ib!d#83%5o?1`s+OT>?M!OlO1YBh zjH0#*?X4t&Xc$5Xy&bhz?RrCKJ8|#*bm!yT59dA4dH&};&-0%5Ilq(X>Wn&l^6W_f z0B{;@Z-W*2z+;n=5S^FbF5pE@jEqGg0Zm+$RZ(z)h;Tvx04@2aj{L<%v2=vJI~f2_ zy?1P4`HR~G06@|UZG-qO&S$-HI#l6%6}GLKJj)wlD{s2>Qb{QxTH{}~gV>64Xn0WQ zBlQ^TNVcTxiI*saZMO$Vgdt*2MoPQ%62jUB<0TjCMxHOWbxNulx!fB;Im9(RGp2Y7 z&+YqRxC?^bWn=Qv>|mvZ;S_TK%_E()&i_*P(@zc?|LisBy!j@psJK{>*3?vdbd*ps z$E~smq3hK`+Xt^H!h_fA(w^&DmqU`aR>yU3fBBsFbHe@>g3ssIQ>g=l{r&An{0k0L zbU3^q9pfRowmDb;l?c5QL?Y!Eb&}q8Yqd2uj}qbp8&&_C=ZD7{!A?T^Z{X!IIjNc3 zr4VuOBR{+))b1ryuN0D>>GuDTqdb5vJ-bFGweRZbbWaaYPw&Qp+QvpyxRMU9{#)e% zB=i^W2cv=jdoYf?Ufy;kUi-XYgXOSxR}$;#dr@3m+={`t_ur1VdU~!cL@Y4}?>IUPjoIXeP8pO(&6h^zgTj5Y=;c^ zVmJ80WJA&{QJeH9w(Db;k*Rp)krAvcqv|x;5Ti(J$&S3xb-4J2+Z2X%^%v z2Sem$snwfO4}!+?vHP#imel406(R%mVoVAd)8l7>pOQfgyebpdKt?#&K9OqUjAK%olYaTzcr>-Zx-8Np~rYRsP7yLNJ!X+q;7DJJk6 zYkR!Ui=_4U)+p3H{*q(bHyO_A_9W61%jC~qKFhM(fh+}s`r2BAxrN0<;@ALIRNxxi zGEw-QbCtP{!S_uM`upt!n(hCVB*kOvE_!z_Y{Z=R>T*>)@1ec8xY*>oq7{BM*OdvX z9P!fE*DoY+iU*mQU;@7_80+i1Y3?win`_7_NI7(5u~@CqtJpFl|J32i%eb4fUE48| zY;~4;x;Z;fmD1V@r#*g5(L&`7@Mt&!kLuQXdp9t)LT9|zL>{IhJ^T7u)MD1pzAt>B zF4czQrQt{-rV?LXQL(tQ$l1s8Mlm=<4W zf$nFk&QxEy6ENEq*^-Su(-=0>Ns3i|Cr?SM&4~}wb*?O!eoEvV>@HV=PbF1JFKW&U6-Nv6ORePy;XSpUXXixND*B^(|LxZ4uuwhm;i>NCk{s$t}t~8d{w^4 ztsWY3C~=t~{zu)4r@WR6^gk4AmY^xnXMn5#oK}>Dq4^u4+!u4jq6gr5=SDwB< z7vs|#|JT1`$~5V>)}vytPIYaK*APdlU-ex43MotJ`E8pzBI+w)VW4m$HFj^s&9reO zXrsCT0`H02?n`{X_Kub9Es@8YXXn!`#FUAUdPv83qYJ&9aZe_e1Q%?)F>ow4EW9fz z(+%`B*3Qt(!0j)+s)$+{)tK%GuQ=6qM{rZ{@fmp;PFE;wfcQu;22#G3oIQlVBNl#~ z>q|dX7UQ6ZH#358%|fXo(PexL0P^lYwamFlLmnot4Y8Kc_#t<^>?^)iaDaXW&?{Q` zLhF!`J#5hGw_b-R$4Tx=nCdk>JW|6ER$Gu>+6;ryj*)phVnfNOoGV);75ERb)3e|k zGDXWP){7lLEmVpBR9}ONcUOSpr>JO}+Wfgr)2=O+bmyh8$PY@2Y&aKYJQ@geL+a&0 z%+rBhQth|gkWL|#6vKcqzU?59NPzY;_ZZB$V?c|h_%FwR7SWo03}|uiJWRxI5v~8U zjC9WSPn4+PAn%&Z`G;8b7ZRib{KWDn|FBsyY>kfqp^<&EL+rffZ_|L5+fD7+av|6X tV1Ncil)iE&X70yAGWG4Hj0gTZGHWRGnasA}Wzq5lplzLPnvi~}zXNXnt#JSV delta 930 zcmV;T16};b54r~-iBL{Q4GJ0x0000DNk~Le0001F0000Q2nGNE071(6<&hyLe9qmNt0sJv`SJzp%fDk_2NZ^qDT!nTBJx? zdQqsL(1Vxs(5s+Ak?Of1v3L|Mr1UEEALv2+ps9g0Vne#6Nz=61&Bw0uPPU-XgOu4Y z+C1>G%M3faJI{P3t7I}63l5+te+oZ7j>n;Pb@Owl=yEC0YjreKmz^RW(=u_Y!;Kd+ zGboixcB*(B6=Ikso{rwdo2!?AYMs56Y3B-poO?W&Ui*oMH?L!0Jq1|obwt0Bi-~rt zxb-=U56L8U3I#huJPr%7@MJuOx0lbOM7^ZjFHQ>ez(xc9%^c$E8tx5Ve?vI4irU%! zW(ATM5l~s$Cj4~+k<|^nUs(7Lgj^Uv@y;mB+amxQT7=+oL(%d$IrRu}ZNDkx>k9N& zuVDpGGg*S}!-gsM%jfWa`-Dh(({UlHeRLe9Y5)}-N_kgEpv=bc{XM(%-=H*>ci1&Y z2~=x9okfdinUFSrM_Y(we;ivO2g`EVkWPr(?S|jaR$~r9<@fgX@}rDWq!FU3DtdZ) zplKQ=CMI}=iN@>oBArfSa&i)ZK!A&p4Jm|>3=%OrJBx5QjQRO_bar+MZNV`vGNcva#H34Q(rSz5E6e^hShl^0G(xDNXu{pv+Ja#i$mjDy z_aX;N>qH^}kH>>rt;Uzv^kU}$KF?-%;|`h+frsVrUBQ79C6 z(78-92x*2as+elE$}5S2hOJiYO=LqFA#IwpOo&AjC!4q}RZQ^zx(}OQC{6TzS~%&q zMu@6FVMCBoEI=t0#l#Ma-O`^@*g2)~yu+?JO0Z|9k13dyc;-DE#_^9Fo{f(papfYg zw+|S)oht}xy=;{<{e1%uZVV!nT>~l=y8;Drq6_eLAo}G8-u=s8oix})eSc&G(f%`B zjuUuT!(Ay?a4r~tZ*Lc-;!LOa!otV0js+&9=$H`T7Zs%k0Plyy0{{R307*qoM6N<$ Ef<;BAh5!Hn diff --git a/src/main/resources/edu/rpi/legup/images/skyscrapers/contradictions/ExceedingVisibility.png b/src/main/resources/edu/rpi/legup/images/skyscrapers/contradictions/ExceedingVisibility.png index ff999f4bc3b1e829029189e50cc9104fe20b0280..2f5b5237d1799d52b9256e3a8479912423bd4fad 100644 GIT binary patch literal 1949 zcmb7FX*3%M5DsF+y{M+G(uT0QbuAiqt8p~8gs#?6>WCw{;)n!|I=1d3j*4|uuu>LP zM7DKQX`N|ToZE(|V=HY4X+`M=82zxToEMIIWvkJ8FWaTMq3!ib3MEr_lTzRYN-$`H zXLB4L*oGJIYxkt;X0Q{fQrt{7P- zC#U+xMjQ3J)`r~fnY)OAqWt$z%58+Dnu#F>s5yXYC9ZYKa{PN7*9cjdYMWw%tC?Q~ zntJLU5Y`v0mp&5D>U&b)XPWE>T><7Ns%Kkk2f~suX)n74#KT~r;?170v0Jm$o%1AyEnH&lyfHrSjO5BhS;W_&eY&3?z zM|Y1-&Mo9~WTWfP%Ag_%vW0d5cl_%nItFi^6mQa9-ha=xf)9235(Vf#N7j6nmwDD> zUy^vzpV=SWe@OTgxB2WE7qm{@CRgQKJA?b)z!q0~AUbqA);a%<_Z@cw1Lf0}L1A_u$) z1VWD+YF`hRt7^e48jI-Za#(tgts$E!^^wLzRn4M+UhUz7cf=$fd2nJ9 z+1~&SM_{q7$7x$UR?5~^4EaLR{3E136@>{aT8-6PER5UVSuZt0%V{CWnF2wS&h-!KZEMh6Owc=ed9|Ts&J+5+WzXX+KimWhCtE^PR zEc6^an>u(d=sXiJno3>u?TKgM*_xM&OWj_$alvw8fi*9qprsjBVQcfCi(W@aLA)&%$TEW>H4Iw$;T#XF83 zCHMBFNsmZ1H#QFI98uF8_|p9_)~A1SMt}hejl0gQb&Hl%?WC4Ki8MNtR zv$Nr>M$pgczN4)7{r857(_)?Y5o4c?)CHV==wEe+;v#d>Ooi8JuJ_aDj{Wunq;2b- zD|XsD2Wb4cgze|u4=0x{lcV+z35g{*=rBUEXgD2r;cg_reQYb3>%-Le4cLZqGrlha zrY0BR4|bzTB;^q(8;e*%RpJd=rs8jwmdK`k?r?blWhe5a{WVPqX%(5~!&dFRniQiL zv@*veiEcynkuM{&Ci~Tr7cSr5gM{%`Z693nZ@_b`63|!EY@$h5#{<3$#!v?RV%>sYlWR1Jp>PY!uGs!f5mV$~$ z)hng-V~VXJ-`(0&5<{3PcI-b=)~c$d&5eymPW~7e#2RLzH8331G^0c}Do&L`Bz~ns zL_^|vY4W8kP`J)|YqjHlUbue(oquzHbF^8`vyaNOIb!jzXME+<|CEXI^|K;tS?BBK RNkU5nIM^X=o8f-R{{UTqkxT#p delta 1141 zcmV-*1d98e51XH+LoU2%NN8$*XJ-ey zySx0e)06AJaAD6$jP><(ba!{7p`iiEWD>GWDVaEE#x5@}qqDOUO-)URL?Tv=7)W5l zFi=%hh4%J#w6(RNx3?EHH8s|MH{8R8g5+{J-huu7ef~cQBodmXM@L8K>+8ez_O>JL zBoqoE7K>qyg|1s$TWD@>#>&bH78Vu|3gp)tq=|Q3PN$_koi(;{Vh=YRz?iMvo zV~M@s&%$HvC6xw(mSI?bQCiT{lt1i9Uzp&`DPG&VL04^Bi-wjg$h z=*Cd79B7}Kot@QBW@cu%IHFb~4LXIpQ&Urzn3%xy^fboD$I;W%Km3UKjjUCBNqhl# ze)tZNjc=e8!&p^dOE|5L!VqaAsKC2;A8KL`S~7ig-l_9jCnfek)Iix#kio*)zi*x7 z&cxebqQEC#om(gWzL#Y>a4(C_h3$J;MZrOUji;jbvVgw;Kv7WAojSH}00000NkvXX Hu0mjfdweZ6 diff --git a/src/main/resources/edu/rpi/legup/images/skyscrapers/contradictions/InsufficientVisibility.png b/src/main/resources/edu/rpi/legup/images/skyscrapers/contradictions/InsufficientVisibility.png index cfe04a503d478bcbf64d4484aa0cb57583efb426..285451ba1668936a8a70b3cce7f8dda36ea8e791 100644 GIT binary patch literal 2071 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 SQ+B7!0giUA=mwi$%6|cppUP(d delta 1270 zcmV5Q_>SiBL{Q4GJ0x0000DNk~Le0001F0000P2nGNE0LNa7OOYWbeDaS%kSh2Z}i=7Ao}`@^`b zfFR-&Qy6hZBYX&fgCQ1&e~?T_6-%VV!Ac(IEdQ)V{bc=B5ak7V$y0eLh|0LIf(R6_ zRfy^Yp@A|O3@9xv6*p1*yGQ3Ds@rHZvd@Bo0x5?dHk*yrO=dQmrBr#SN)QqwBW{Nm z7Z*`gRRyot%Lb4aR97$J4=aTTSktPCwJEwETDf6OK)Cs~?YR42&B z#s+3*XW2mM^?E6X4<#ifXm4*vZ*MR9`ucEmbcFi)dYDWmsl@X^UN<;6$m$yz8DVMD z)6-a6TSJk|TMAVPk`~V<4u=EP)z#dWD-xSLZh3hb{r&xzo0~&ZQxhVQh*aYFNhA_* zI-OWuUB%eg7@Jr`e;^Q$9kWy=NS1uu712^iGuLXhA`}X-G#Wti7|P>8DwRTAT^;;> zKWiiV9BplFtSvdHQjmN>15aK^-j_@!+44y7>hMrJ0CIvvAt<0vO-*5GX^FKZSM&=d zNEQmVw6yH(>@ab7ZX5`ze`aO|U0q%1=;)AA<#FKzp_xnTfBWd@C|km|wzlAQyVjcUsbK+~^5mc@L8#;F>+7)F?HC#w!ph1D_V@R>h(dKA92{VK zdmAp73&X?1f9#WXTr_Yz1Su{qX4~BE?r!w-^f2q}>_ls8E8_9ERO;y{fBpXXm&g?B zAw1#woepXAU<7#y?M^5V=Ys0d-dTp_=ez%1zh8SBsZRzV{Yj9QO9Y3$YQbBe-p(x546+C)_vM|LgyOV@}9P5 zd4HnH7;=$OUJwdyqDyBu7^~-Oe4!KZnR4efs)zMgL6j9ltApV4LhyR{*q?ik-|S^Y z(THLs;t)I!a+g1k{pDl*Rtm*}y5^e&ynp#silBV|6+)MGVjHa~1Mcdgv=e|Be56bc zkcXH`Oz_ox56b&*ycmCSxF;Tz7CxKAYgP+5O7Sl=fB(n`ctgnG@x=vS$p1WnAZ|>2 gifeCP$)g~^KlLY+KFX1xy8r+H07*qoM6N<$f-iqn&;S4c diff --git a/src/main/resources/edu/rpi/legup/images/skyscrapers/contradictions/PreemptiveVisibility.png b/src/main/resources/edu/rpi/legup/images/skyscrapers/contradictions/PreemptiveVisibility.png index 6d330baa6e76585ea860dd7d758c51d841081675..6c4a6e4574f8154ce20de311be3f35f38bc1bb09 100644 GIT binary patch literal 1784 zcma)7c~sJg7DiD@!!1OlM8#1{)3JW0Vj6BZxs*$4;$&`slxf*BBh6Q-|iSciwqt&imuud+xdSp7Y&v&-Y!rpU(+3 z)qScU5J=6_19w^;314kDMDFt)T1ws51S5S>WPa;p0$S$W`Kp;;3o-dKg@?0g} zBP0O?LS=n5h5YFy5(osz^TfFXUJsK#@bw5iq1UUd5!QTz+wEki|H7TyURl2q$hn=Z zudVI)*3HH+W+}o*_aBRsA%hjS^L{*od$bqF#>ZCBcfk{bgJCd zb=v=?&|!_7o13ezt8?4j+^lbCm{kdzQ4CvG6LmL|R$sPTBgJ?xFW!!N?%6XMC`ShM zp3&SNrRqJFKWC|z^|d|OFPV7#8lKS^8Rz5cD;Z+>4hw~zRA*;B{$!xbjVTwb-Z!ll zJ|%oUe~uG1R+}s?&_s&k59ef8)nn*3iE5st_40XZ9IOx!dfz6wnb@;GEByiTdKca1dxV8qi!{!^t^0D$LBG#x8{RFZJCuDG z>0hvt3d7f$s$=a%Ik~ICV5g+aW_~e4RA^o4&t2qNX(z89$e4*1^ubxmNXjcU zJCJp@=U1ov!Jo&&VrXkBj1PUUiy2^VXf);g2NPxbL0xQ~0SlFGsIiQ;TIOSeOJMQ| zi0bp!S(Y>|d`xM5t77Y2;ZpCyP57C;`(Z4Upa93;t&}qOyeq0#s{8i9SNMBBUM z0kL$nVGyI~oq3R5w}B4!_RisEwelgBQ4B-ymT+wBQA-Q<$fYqo-ee##HZG3-IWaNO zKOg}1?}34#-zW>)COA*Xv8T_Udp&*nwD^Y~yi80?I@lIET}9O2mOp%m{J5~d%F-~% zZY(cHAK6n$V4%TU`;o}D+Bu3v_S>-cJOEZiq z?}~|S=3yUE1_p?}>gsCTERo|(y4TT(yl5F48d0D!oiwrgdwJLi6B zy)n1Vp&ky0_W&T{h>+fU`45_!nxe*U9i)VY0za`>#~IYi4ojz3KFtpNT8cf(G>cD7 z^_iZYF5`kQpAZOy*`Y(;CmpATezyh@`vrn*jephD=yVr%Q}F;BSwY}ZS2x}_-v|s2 zCYL}@7V~&sat>(`>0o!*?P4*YYZ}G~gCQn*g!nz_R ztE#H#dvu1|&)JzEJsN9kU40*7t7c}RW8&hf=ya7ObggWZ7_q4P$JCUu{CNJpzWJJY zbyE`)69$|@+0OS6+shUvzGaSDrIj=qZF08uEgm?00imPwn8Wc89kD%n^fn>(W20BX zn^Q^m6lF1btV7XuBd_jX`VwUs(Du(x%Ftd=5gN=;B)d*&FbBnVcXNoiOEN#}Tx-SD zpPI>Cv}|Zl5&9ebK)ZPOd>M3m#1=aS$dbNGFHql!_SuT9DTvB-JE`Hk{9A!M-F z4l0%+v`7>PdNofT0{e&BS7{z-nbMZX82` z&`3#1NyyF3mGQV4MoUOYe?VqtCQihe;v$NYm6av0ySuy6PDTk?5E_Ru{^;nad}v=^ zA5v3O^;R{+$H!xSejc^8wPq>D=U$movpWqM#zG2 z2|ArlxLht7`q}Mvy+sYD{d46lE-o4#$a#|}4yZ#zLvpfCPEH~xeP=x&Na z!(-G-B$5huuLsCyAZUWV*jTU!_z8G*y$!1D64%zve%r092? zjUhppXydm5;`MrEn5q(P=3MsNM-C1S^xBI7H*dasMMVYX=H^gRQiAI0YV7RnNV|nf z$b!&VD=RD5-rknq1sLWnEG!s$*x%rQHa9o1w6rAsFJt(bf0-HBY&QLl$cB@1e0&`3 z?d|C4>5-+QqXVt2t%fqhhSKj8h0Bsx`bI_%XGKLnrQfe!gTMCyH21#V`ZE-T1Ea|7 zpP}UGiu?^8RK!#gyRSmLoSQa0$*rxe6>&O&^~`sP@G}|bV_le ziLiZBf01|u1cfLbg`Zt1vgrT8+jTTQc`i3~v;I0^!Z2!na=6>u3!ifx7P=Y5ScN8E xJYHnv=fkE)e=4CM+?=bbs?gHXVzMB>cPIA=MhldS4QK!W002ovPDHLkV1nN70}ucJ diff --git a/src/main/resources/edu/rpi/legup/images/skyscrapers/contradictions/UnresolvedCell.png b/src/main/resources/edu/rpi/legup/images/skyscrapers/contradictions/UnresolvedCell.png index 76947671dcfb96d6293f4a081d5f40e39ce2659e..ae78caf499ba352bc3c9227d1428b464832363e9 100644 GIT binary patch literal 2108 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 JPDHLkV1nhw1L^<( diff --git a/src/main/resources/edu/rpi/legup/images/skyscrapers/contradictions/UnresolvedNumber.png b/src/main/resources/edu/rpi/legup/images/skyscrapers/contradictions/UnresolvedNumber.png index 8862702f182093687b4fecb187ff755e7b4569cd..602f6270205809d635d11aba725e56ade53f80e5 100644 GIT binary patch literal 2658 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 diff --git a/src/main/resources/edu/rpi/legup/images/skyscrapers/rules/FixedMax.png b/src/main/resources/edu/rpi/legup/images/skyscrapers/rules/FixedMax.png index 8a26bbfebfd61453c82f1e8e4d60d86197bf26c4..86a4ee8a034221ea60892791a41b88414de80205 100644 GIT binary patch literal 1783 zcma)-dpy(oAIHChY1v7+Qs07&&2XU~!#bzd17^ zyz$lMX%al5U9@s{$&e@MLg5nD%kGxQ21}k2S3W}2)I2M4I*nvVrJvBM9?#S>ubZf9 z!PG6YjFD>YKkHoagDO@0uL8>Y#U82`{no9k%gb0Ic3b&y)X*OGB8^k#M!wGDA>>D~ z=u8h2tB^K_t%>C~E7Ps2**)Tp*C=Zrg6E(YcKnr~zt}eF8|{NZ7xPW&Il7$1Zq%Ra zUq)wU^54CSu{!?{u(h=nH`QvWD!qUI26o3O5e$JqYEt97wW7#+g-Po& zpIOcBEPo&?Jwg~@C#~p+5RO4@Mqb|jKVUsV2@$qwkC63)$t>depnV>C|D-}Q04H~3;Kqi4H zA8D13s@3Qh_otb=7SF$GPic0@?Q^;w#xMh-jUP+L`C+sAny?qgv^fX4k=o zY;2@zYHKrf7R~v|3Ily-gWTOSB)5@nh1X8bUS3@&`7~E83!P7?)w$#ex_`Qyo3Raq zpW{MIZ`=kGFFU%r#yxM28a51S!M~ZRw#?|Y?F$YLz8D|RZBJP*C@K<8rXik%(FTU7 z*48`sc5}#I@W1!(LY_Ta(a{m=dF_JR_0j2Rs$^AIb^ku-hvs-V4%hH4sRreZ(Jf^% z@$YBd4ct<7oPS*Itn#KA7=g%({j=0Trd=$4{<#)*s!^G=^15rN^ypCI!50rn1W6lV z&I^e|7W?^yhSJ`?MF*}QwMX^fX4-TE8$#?vNt@C{qKwg~!?I#LV6l2D;dy@N&S6&S z2L=Y9ZhQt}0rhA2q|47_;;XOuL8jN2$d+3mqw*AL{Q@mlze&jjq`LxrXB2R-r$3{@Xg027wRt!+K*;{*}i76VI1+&L$9n>JTf zZA(l{T$pC$?Xhvx>XQYQ&Zz(g=v`MsP_nSH7tDK?Sfy9D?c$J5vK?wks#7M;ou>MCePavS0pQg0az5 zFTEtj@Q6>SUe54Z^f#|v(LI_)*?kXza_vnw<&Y+ed7V{Kk4Q^7r uBxFNaxfLzmfoJ}e-v7Aszr05STM7qa6PBN;faISP03hJLp7kDKSN;N6UP^la delta 1204 zcmV;l1WWt(4ao^1iBL{Q4GJ0x0000DNk~Le0001F0000L2nGNE0I-}(Fp(iAe3`Im_)Oe-IiPipIu9Bqb%m<#LHv{YRxzVSjHQUuJ&=rz7z9 zDT9>w?dTAneQsv&cDn=Xwo<8t#bQBwdpqLegdn3$N5#kioL zAPjsrjPnmeu-@6=2+&G{UW4C94EVL_PZ&(W0Z$sTZ)Ro&X0sWosi}Mlf709Ai}CSs z+~41eSN+FeFreQf$Y0<8h_4+D$WoWV0jqfT-=P!2G48B}WkQYF`hDn(YP`I>h~lnK?oO|uzQ4| z72;2$wcvgia=a5k{!jQ6e?+U*vJ8qc6CR=9O7Tml(?Jjf@hU%1Hb(J~?E5E33Su&u zFf}!Wwzf8$pP#cp#uFNi2A-q@Jv}`b8yiDNNC;P=sMTuR-QA(PyBi}TBZ!QQ6z_P) zt01&0YHDgQIy%bIyPTXHTwh-^#d+Yh4%ph-LSkYfIyySg)YQagek+hf;ucXyeK-~p;55)u+nS69dE zG#ZU4FE5APZWo_;TWF;o92~F`;Pmtq1qB6IUtjm>`n?K5d38oc1{36!ii!$uI!sV4 z@$m3~va&MfzOu5ie`MJukOQ(KJ3E_smB+_NHl7U)4Q$m&AsIvHCE?-Wtl(Q(T7uPT z4S35zPRJHYI%xZXI-Z}O&jLIzkSOH3Zf|dyd!;x>;z%JW2xSJFo13Vutwm*JC3`6^ zF@y*U3u7*zsHlk9=xg@91+=v?I5>#Q%S$$CuCA^m6A!O~e^5t{j*d`TT8jSueir0u ztAH{Y9w0G_i;L0K)x~~qZ*QZsvl9-7gZ<`#sHi9u78YV*VF9tRv51b2MoLPGq?hq3 z2nFwb`LJZsC#%ScX6=4J*`Jfq37v$KQ4!$Z{9*W>2qM!fs> z&^YDh=3;Ga4RdpISX^9WF@)+8DI{YE{h2!X+IVsY1c~x$8>Q*ILF4u5`1ulpkQ9U` z0;#|G+feb&yAVVJ9YO>Z3_^rojglILz)yB4g>Za)e=OSpRbO8pCMPFlIjo_iqObJ_ zT>bO`4|k8S1!$#FuZ87jEq-bKgPj-#dO$_?O;1m=v^Fg*O|}Cn!BdILA_(mvksu_D z9K|EmJJ**taGN}S*Cm6~@%RG!tsCaBSO}i)f!as~-^IlR%k*MmVq_8o_z24s^+gWr SyFCB^3IG5}MNUMnLSTaQ;veGx diff --git a/src/main/resources/edu/rpi/legup/images/skyscrapers/rules/LastCell.png b/src/main/resources/edu/rpi/legup/images/skyscrapers/rules/LastCell.png index 216a0f3a1209d7b126eb41f358c417c5a999e974..8db8a3bbfd06e118b5052015f9e885c05aed2992 100644 GIT binary patch literal 2174 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 diff --git a/src/main/resources/edu/rpi/legup/images/skyscrapers/rules/LastNumber.png b/src/main/resources/edu/rpi/legup/images/skyscrapers/rules/LastNumber.png index 1e0555648434f497b65bd92d8c00607ebad0310c..dcf4cb2b8eb02a9029fc3da7f03e9c05f7e2a414 100644 GIT binary patch literal 2083 zcmai#cTm%58poqj1Oj9UNRSAEAv7sJ6(a~lrA9)FxEQJgkj_Fxnusga&;vn|qlt^6 zEXXPngA90>A_QeskRC+{A~8fnrGuC3&CSi;?aco1zVAHm%scPXzMqHW;pU_$zgr#z z0x4pg?Q!DsoMi2k5$~37`2_K??L5xu1n6!*d`@ggg&lW24g%dPR@exV7Ta=h&iL~n z(4Jh$+EzUCITQqvWnk=&dnE_VS7E|c@vxs?=Ocmm;6cWfNg{+T?Fn&DH3#yq%TR#S z14glXO|PnV_erT*8{E)Wb2qKf*rA2Io&o4gU)R;eAmjjTzqHUYzY!uj)M)oj3d>m>%Z<)5a zb~;8K!9pCiEK#tGn9s=S($5Vb{N|WB+!Cl?p7iNW`@RPZ#>mXV*5<`F{}M>q2>+NV zzrIaDWvvE|#i}A5yIILpm^Ad4vjl5wK?cdw9MFm|dH=i;_3Guzx~*n3w&2NG_TH)a z@rNRr`I)|oMZs(1Hvh}wH;)OBpG(|pZF}?8&G=8U74ApAHcHu8iJ$nyWErfeG1ChR z3-3n^An{#k?FE`Bw_9%2M#|c@lwxgk8D^Vwbhj{2r1tZ87EFd*qVQJj@Ppvt7Wx;l1bZELe5ZGGwaW?x=K^3fql zm}SnAw0$-QW9vP2zylVNcq#J_L>x9L!H;sz0#R$1AqtJzT@G4VA` zCMOTr{LwHsW?+ZD+9;)xG`LUniiS2aEO0oov2Ub)Z_9F-0zfLPTDNI0DZ3U`@?tsi zoyxRk@j(Uz3FR!$)}2e@$F4?|Qa0D~qZMYIBMeTRWNsUP2KycvXCn@WxiRjH&eYHB zMtto|E$klic+Q2*{=j_c;=~Kzblr+=p$O>c?b$GtPhY67!Be&)*3SQzK1`p5GmiKO zZgT5T)ysjP%XtZT2^SJ%<$)3=Eto*~V1jI&4d3Ejs2Z{*LoyFG9HN902mqjkM9M=4 zl#v`J%bq+$SV^w1U>$o`GIR^AqLafQ!>90BWIEx@fP>Q^6v`zk>eqEz<;~>0Tp8mW z_>m(%K0XryYVr`}W;IMIt|9fydsjn4Lvs81S?lyP<>keAIvs88>qC#G6~KTK z^jMz2_V=AQu$?+{hFfktBOGlNJ@aS8)nRD|95_XLKGr~#5xEakpjS}+$^D6<2}_#o zrANPJ)-$JQQY$vWW8>qzQEmx0aeXP~Vd83oy4_-0_MnK@!OMtc!EMt<%HIM@$_d*i zoxm^V$O<;Cfaym5E)$~NcyF0L4-fAUhi8~m6y*GFKfW`yjsO1rqc$cu!o9{?VFSe5`ln;Vvr3fvE!RpU9*>WmH}5;$wscRdxiF+A z6w-f9Ac#a|YxQVUUL(L9b%#}~rdTBCf%J`J6eqBqsAov{ke1UV7B6FTSj7EiqaySn7ar7>+Ff;r0m1--r(diR2-HG1> zr%|WuO6WgjJy2m*hRU!kvKM8G&K%BB3CLYjHQgHP+MUk+O&h1Q#|m*Ute>*asfba# zEF9gJl9F=wzR>BD_(Km-+}tZY?{15>OS@vCnZnqudq^^2_kfl*J)Oc=et@=jK~Pq?J>O+hwaXI;DkN=y z^n~>_Q^F5VDm7gU-|ssB`lOj2dqiav2GDO$K+A~v+-C4Thd%SBI70`8il#v`2bWFQ z+hj_2wi#_9Jhy1_wvH?(srk=%59s8W_ba|`D%h9frXy>bC7vWY$a}q4{CY4^>Ig$i z|HA;%k(is#u$WnmfbOA>U= c2J-v1plu?8L5$z3c(8*o4sP~$Pn^y87ys4PegFUf delta 1314 zcmV+-1>O3i5Vr~;iBL{Q4GJ0x0000DNk~Le0001F0000h2nGNE0FLY}?U5lTeQf4*;`bGzLEe+Y!tYQ@sh5;itA*ylii&+vRcAM*3_QC?mSuh%QJ ziUU2T*=&Yzg4k>}jE#+FMzM{n8zI7z_q#78W$HA+^+lkd)BY$h(E&r8DT*LBP@tus8$f2PKU_INW{m-OD)r! z$H$S7kbtA3BN&ZF>8`p_tssw&k2p9uz{$x8+plN^RSH64q@<)EF)>kU(GIGOA+%xS zwTl-C)e53j!h#5fY6YR(R4C6y4vPZ47Eq-il#|-s-G#|yLT_&`R#sM6zDf(Cs8SGe zS;@)CXl`ysXJ;oWD=QHZe-WXHAg|gbi$uA(xxv-d6{~M(#c_p$x?qF_5sa`Pf+4$v zOC?vHP;ed{9fk7?C(@p$;nB}0Hs}pH^!4?jqoaex9$t{+BZns!E;V%$V`^%OJs>a3 zNmlmFFK;M=2&>r=9H?|dCI+J(9?x$`vcJa;Jn(>?`TYDG)6>(ke?{RUNK{l5nwpw0 zJ3Gs2);yp=efRAY_CIyuZPIJpad>%Voe}zIAD(^LjS<(^Tn|oES65?rc$m38IdBuC zwY8PYe@F;gvc_M{!2QV&@FscSu)cyf@btb-IxBv@{}Hdvb9naEOMElg$8D@JF)^sE zt;NX52sc554eE~wf3TPNk@YitXmLFG`q=V0(u^O#AM8;L2<@^0!Iwxe{T??@zV6@) zit!-zC_Z7^D;WQZAe4=zc*ENw6I!XIhfrJ)3ex-g`{?QEVQwroHdeYL4{|tk;)Lqz z^q1_i7En|Wat(BFdTnhD$H&L)yl!J-BXcKmATcg4FWEjIe>XRm%|1HppoQ6@s35dA zDJv^OeSJM9CMH;0W@e`BeE^*@>F@8y-rgQoS6A8L>9)2uCXCuqe93xvcwjquN?BxO zWud*jUH0j7I+I1|6}#Pzl9Cc+XJ>N}S_Bjqgq9WBG#wru!sGEEFE5Wv93fFiY+`3; z2i@J>tWE7Ge=Z0)tGKv0EG#Ur8M3{-E!~k11@nf62KM6~G7nU=Qag$YLT7KO=6!c} z$G&G|WT3RPlzo;98H2^eML3;K6c!d@Zf*`1i$%JtUKACCT-MOg5K>c9QCC-o&CN~B z&(F)wB~iaLD=I1~P*haJmc@aA0X9q2j-rB`ot-hKf3>{4%mkqrLe^An@Fm;3wY7!G z$w`*}cez|F!N;@C@n4~+Ae6zRdO<-!0djJ3aC&;m#R-v1BP&g(O&ksfs;a6`TwMHa zX;d?c2XzvKW(lvNPzVx*W<==Hf*6G2f`s{J2rY;KCK!SvjMK+I`LgMauqs? z#gKO1cr!CIT+5kNbCc6aIkD9DK+CpGh1r`e4|7ju*M_zuV!+8%#l3|g<--4L& Y7pr?>TTCw0P5=M^07*qoM6N<$f|9&w@Bjb+ diff --git a/src/main/resources/edu/rpi/legup/images/skyscrapers/rules/NEdge.png b/src/main/resources/edu/rpi/legup/images/skyscrapers/rules/NEdge.png index d3dd36bbc10fb66ad83d8c04d0214e5f25836739..b238b36aa4cd9478d1c76172df4d667b0d9ec138 100644 GIT binary patch literal 2027 zcma)7c`)0H7ETG0isgs$MB}!xRc)oXu0~%&BKCc~);4xcMbvgnORFS7)ho3Y(QDV1 zX{e;?(h?pj7v=)k?P27x&eJsvvF6FA^dv^^RGYR(bgzbGQ`p+qb17!U}N z@lB58EUpKGKw>G@7_?i0|7xjUm>W*67q0|ICt2z6e0=K61HfGcOIT^ODxKCs^YAlz z;Sm-_cfH8;2$@^0EUBhZDWuvlBWDZ@+-OzbN?Augbg>;iRXL2wE}qV&>^Y#O55u4M zj!#Y(P5PJ;hF(g|FAXwcmf}M{{y7~vVrpt?wYviVcTOOWqcJ8o$wV+P2SL6BFlj1e z2u}L{B&2J}8B#xqS~@yPJ^cJY0?ie!*Kbmj2A)OzyP8g?TSFr}vniUX3AN4`uM-b8|IFR&Q^(K!8UwI(Q}1b-p3Wwzig@vLXI=+LH#`Zyo;&*zQ91Q0DIP zv#b3t3LR{9+pQS#+6=x>@_w&vp3fm%XJ$)&u_ctKTax5|?%f65cbF^3EsmALK3dSf zLt&c+&;qW#U%pgJ8QR_t8eF4=)Kijd7}?(R-7i1a8EnKEjvcImNT-m8*9!9W*Jp0q^UYe~mpY{+DrL zkgsAngpQuFr|p<1kd!HnTzu{PJ$-pX2IqXv+ud^MVIZRBpf82=r64O8GE5_iBv0^3 zSNSs)*|gHI$7pKW>u23zw_24f)`+_AP;$E8>xUH{L0c#gY!dRo6UkRqGL7aAA()Aq z)drS0%qh7_T#oX3nX(>AC2eP4|AHr&BME~E%C`=OUb%rk%JK(gHtIiDYY8o+MO#Sz zxj*O3PQY_>oxqYe!EK5W1VYvG_%&9xt-8?9X!3MN@;P@8kCDAiE+g;;>zOF9u9!awQse0Pm?hZ2x_WT$c~658aBb(~;&m2l*=ZfcaUZ0+)c7769C}?j-InW7H z#;sYxJuG$ERHT$L%F5f@n||Z)y8qen$9@C1czSZnm_K`0)7kJ1?nT6H=_?f&&cvfk|XQ5)&U-QC^k!2|L$l6YR$i`^A! zr%aYC?5oB3%gxO|r^|+2X*vXE90HCbtEs8A3%~NJXT5gx1==Ycdg&Z@u@7D&E>;s zwg!OuGWkspCQXuwyu6FU^wm6B0_&Q0h7v5=D|y~u`aZ z=kI8fCa&v0(~yUJ@UuJf&z?DZf4=Wrh7l$wCnczaAPA6rIvoGzLpaI<@T_{29ezYv z&6vBEgpAS{%t#{$hSroFKIjBJOjZMCFYQEP{UkigK1c{DyL>R4&6w>M(Ujc<$9r#L zZH?bYNs?eR8lfE_ULDF>op|eW7Ye0Q@Jh?d?)G64EV!j>!~L@f$UPa0e--gDGWDMz z0Izbz_Mn3v?%)*0Oh4h_>GzS?@+$&q3KDY7 ziG=!TblD_$L;UJ9iy}Vrq~VWq(fFXwhIm5?8lt;olKE^JA!6A7GrpBR#{3sf*v}2( zlJNoJ#bg9I2{8*I8dl%Me@M3rU#9=486l!_tSw}UJ<=lg3d%8hx|{^%-0-Wi>6L%K zs#yC6J~@Lu($asfi+lxTf7F(|7vcXQR~V#*wPxJTspOY z#bSZoZfBocVaq#G@Z#d)lp}Q@TZI1pet0|{L`6lhV>KY(CMG5@e=;(niJv4G3LM#b z^yralQs_TkzI+)64<1BUSJ#$4hP@jZ8yp-&K|z7)KT8dZh&X@#JnHJ|kdTmoJ9qA= zQa1T?=+Gf#W@f_abmG{tW2*clGQ3_dT3cJ0zZAeoRJ|E!EWUE(3ij^Z%k0+F)S$Pw zm)YJ7n-W5Sx_$dLe<~|0S>V*FIS>dSCnpCjEiD)t8e->`mzP-(ctFa%d-pEN%gfn> zQd?V#&dyFOEG%%Vn(SDuRvbNgl=*A3*_0hV5D8UPRmjfHMpIK0izx{w+%&eS=j0G& zMpjmqaz-8K&l0IiOG~J)uSZEq3HI#S1Ha#|T(LcbD}mckhPJ=RFH_QyLS&gJw0e_ zY(#W)w6eQ>P~a(e)SIqey^8McZmg`VD7&u)NGwG~MU0T~@o`jCR3IiMM%jHHe7VgD zDhFw4X{==FfAx9{4-d0XH6TK%E>~AqBQGycQ+2BaO_J0rX@DUCMuL|{2&uTVw3KBX zfj*BMIl>gg3o3!s=Pq2hfZ5quRto$2`ZlIH9#9sq4;mCu-hM>Cou8j)jh%cP8yjQi z&zw0EHjBgFjnw<($rJWn?Q;YDeqdk#v9YmiDxyh?f6{k#_1P!rNI`*`o14S_{rfRG zI*R7zW;R|H78Y)h&I4-1H*Vb6m@sE%X1GY9QlFHRgyQ02)-MkqKFlh@jvYJrnmPrL zN(&jgc=00I+uK!Z;CB`I7@QzsEp5J@N< z9UV+Sf4ug{Mq67O^O4AtHFydZ5kTsolwHp} zHK0I|&8L?dGS)#^Lbetc7ggIM8*aCo*^4A|!{#CpKrGYJs#%5``CelSLbxG6>)C`j z?xmBx67X+%)WZm)3Y%8Z472d;cx@44<-O?Vf3A&mk&oh2K57L`--mqqeI6W*kMXvD z7XlLh^rRPzm^A%@Kfg+W^OPNK;Xd9FGZ2*cnzbN^SP3n_Wf{YRlNm_<`ZuI{bLIOO zxHFdds2{@Q55Vb^SMUWD)$P5FyT&Q|l09JsV6q zHZ0zZN9?Y71bl0d=*5i+(0J_rJ%F>vzeD;vJ2fE0h`#~8KLw?V#0wSx0000sn=7$# zq%BM7x|kLbLfLZlFpE?hnO$5V72Wk8)H$#B=Y8J4e13bsi-|!vJsmS05D274z+*x+ z9{WvDu;!Mb#2k%nN)N^PfP_zWz1IZocyu5d1iD=Y`*M7XCT~r}N2Y^778ky0Q<-8h z4g}hQAz;v9EULO1g@?x*^?z*|7v1qBDEojrR>jr2X{=C=>nF3p^fMPaE_%fX?cv6Y^lb98YA z_vHK{%gNQ1JuyMO%;DHrmL0>5_N$hGow~HNG(%rs-`Umlr<9Nb-pJyXmV@ znSHz~ku|ldq!;Be8?vNF-Vcq89NmGW(P$4s;!3RzMIuq7PdR zxVCtq)WnX}X_@nthE0Z?n})K5W343e9+9P$6>9HOuhycqwM<4v2Cu%pH|^!}3UFQ; zEylbXom_|+w6@7`H(# zu-mhq5!S8RM_3S||JiLoPXU-Q`$Pu@3n7zl{?2!=WJ*Uuj~*iuYdaREtr75qxYuK2 zJCsVLlZVGewL00ZcYkDLWLsxv@9gYeFc_T5VAMCv+%PcR{b5_f*8agk9X_AmeD`jl zSnMgEm=IHtSN8w3`tF^!t*vbYm6|&q8ft?GNNBfTR=K1LnwtFL;_Sc>NO@INVzx03 z7?;T;a{0}bnu94ty09#J(sKk7S^W5M;G9~0Bjr4`MT?TtFApU2R8&-Rb93JEGIM#xn?$NmD>gi9^ie3(Ug)3UA%Ae_1}3Jv8QtdQ=FXm;rR(cw z7z{>CQqr&#=l&03=FO-}W^%F~lgXqLgV_U4#SdwGZOP}H zTFWyCU%O=C@8+Pd@Xr_yYRh+wdmd1*!Af&5y0dbX+Y~1;;|5@+GZPa{!`699e}5G- y{6V9!u!Y~C84=p&=*`;G14$)@z_}knuj~Hy*%ZJ2YL8sa$btxdK^UP=Ou_$bjIS#I delta 909 zcmV;819JSY3#JDkiBL{Q4GJ0x0000DNk~Le0001F0000K2nGNE0DHigksv64B1=)oRBDdZqtik|dPs^CRWD%R*Fl4{Iu$Y=A0Sp`9p%#Kj( z{>ZR9GhvvW|Gs^1-YEO~`$b59Kv5Lr^Lc#z5`kOs@m6an-V74SIImelRaMl~)IisD z-Xc!1SVUc29s2wGVHgH)m4h@v=z;Y_7H_@8X z42Q#kcs!29#YK#bjae4O=kp;P4r6+H8mUx@x5`1PAjY2@2EISV!vPI{uhlsig)`n; z9UiqFp9-(=`~7_^&;3N=EWvxkAVE$}P7sMiFg!eLc@fDvhK7bPH8mw&5S3r0LFVj) z3y-yzXxBnQ<&pNHG!7e${j5TBGOy;n6=aNY9nu9MN{@|vY0eoKLZ!gR_#e3yL2SgS zND%T54D+n!GE|MA-qI?&bC zg`=Y*Ta+u@CFFtpCg$honKPp{5on*1NFxj*c?xh(@Ef54l2FK`5Kq*Vl*R<70Gp zcO#un^PcLUoX_}w_&9cUcF@z)gTuo^W+5cF%_U_8p^Y4crnGRBRCBppyr+67Yunh^ zh+r_tLSR|J!d;>wA3~9qS*${vOxr51ry@bBMTHZN(#Z9SU#O@Gjd3ee`{z;i_V%Qt zRVjRB=ONK2?0_n#Q^r=zqLh*tj@mq86D?T&_)FMtnb6#1%mXS4D6Ec00m|UuASNd# zjS$*omRsC=vJzNuhHZzlE}i00000NkvXXu0mjf&Kau* diff --git a/src/main/resources/edu/rpi/legup/images/starbattle/black.gif b/src/main/resources/edu/rpi/legup/images/starbattle/black.gif deleted file mode 100644 index 13381a7179c2af7ad23ef064b743d3e479b56070..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 856 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 diff --git a/src/main/resources/edu/rpi/legup/images/starbattle/contradictions/ClashingOrbitContradictionRule.png b/src/main/resources/edu/rpi/legup/images/starbattle/contradictions/ClashingOrbitContradictionRule.png deleted file mode 100644 index d25340b407edf02eebfdbc35764b0527ecea59b7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5135 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 D%D^dv diff --git a/src/main/resources/edu/rpi/legup/images/starbattle/contradictions/TooManyStarsContradictionRule.png b/src/main/resources/edu/rpi/legup/images/starbattle/contradictions/TooManyStarsContradictionRule.png deleted file mode 100644 index b468ae6f6fb70271fd594e8cb6b5148dbd9153c5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6199 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 YEnSqZ8g?u{`D@=m$5i{drepa30M6m=2LJ#7 diff --git a/src/main/resources/edu/rpi/legup/images/starbattle/empty.gif b/src/main/resources/edu/rpi/legup/images/starbattle/empty.gif deleted file mode 100644 index 38b91d0a2b9c6599eb19d14466db047a86d2ea97..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 857 zcmZ?wbhEHbRA5kG_|Cxa|Nno6Q7{?;BQ*qcKpqF>1qKc~21X7Uj|~eBHggDT#hlo% z@Nm0;vez7sjf;+UOBiR}IkEBaF$M+Z0v^pz$tNbN+pdZ^xoPR?=?2NC=6GICbzrat E0QgHHq5uE@ diff --git a/src/main/resources/edu/rpi/legup/images/starbattle/rules/BlackOutDirectRule.png b/src/main/resources/edu/rpi/legup/images/starbattle/rules/BlackOutDirectRule.png deleted file mode 100644 index f72fd7d7f82687cfae12872a76855ab94d80fdcb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4717 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 G67esNMHw6b diff --git a/src/main/resources/edu/rpi/legup/images/starbattle/rules/ColumnsWithinRegionsDirectRule.png b/src/main/resources/edu/rpi/legup/images/starbattle/rules/ColumnsWithinRegionsDirectRule.png deleted file mode 100644 index 1a88e9d07c6a0e4a1425d9725be9d1fc130058ee..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6456 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 A-2eap diff --git a/src/main/resources/edu/rpi/legup/images/starbattle/rules/ColumnsWithinRowsDirectRule.png b/src/main/resources/edu/rpi/legup/images/starbattle/rules/ColumnsWithinRowsDirectRule.png deleted file mode 100644 index 24fb0d48a84c46608fc3ab3335ab0df053898bba..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5331 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 diff --git a/src/main/resources/edu/rpi/legup/images/starbattle/rules/FinishWithStarDirectRule.png b/src/main/resources/edu/rpi/legup/images/starbattle/rules/FinishWithStarDirectRule.png deleted file mode 100644 index 11cfbf89965d94b114cf32be6944f2703f4ee90f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4326 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 E0_Y@20RR91 diff --git a/src/main/resources/edu/rpi/legup/images/starbattle/rules/RowsWithinColumnsDirectRule.png b/src/main/resources/edu/rpi/legup/images/starbattle/rules/RowsWithinColumnsDirectRule.png deleted file mode 100644 index bac64a87c9ae9df53b8be031c17306773ccfba7d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5117 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 diff --git a/src/main/resources/edu/rpi/legup/images/starbattle/rules/RowsWithinRegionsDirectRule.png b/src/main/resources/edu/rpi/legup/images/starbattle/rules/RowsWithinRegionsDirectRule.png deleted file mode 100644 index 8907e047521d5310676821ddb141672f2b5e4d7c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6477 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 F^k2&Gt=s?r diff --git a/src/main/resources/edu/rpi/legup/images/starbattle/rules/SurroundStar.png b/src/main/resources/edu/rpi/legup/images/starbattle/rules/SurroundStar.png deleted file mode 100644 index 13287f779e74d6c70489f32013ec3675b07dfe4c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5102 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 diff --git a/src/main/resources/edu/rpi/legup/images/starbattle/star.gif b/src/main/resources/edu/rpi/legup/images/starbattle/star.gif deleted file mode 100644 index e289b287ae12d06741cf5d97a0413691752c4f49..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 545 zcmV++0^a?JP)Px$+et)0R7gwB)k~;OQ4|O8-%S#Q6f(WuN(@LbxC6?>z|bQh@)#H)BSjf;3uWXn zP!c6GWTuoTBMJi~86e~tQXYG0-#TsIx!*bRl~udbx7OP0zy9m7zdk*dz8=T--vKPZ zNZe}5ye)&{8DLYd0Dk7cjT39^h^+_)Av2;~qv~I+oyO zH;_68qf-gSS5A~<6}DyFAzZ*gyu-&-wh#DP0#*UeVHPIj6985Df-zYUfr3d@-r_ah z<1to;v1D)nd-JVpIkQjs`y%Q0XIp&7Vq88Gu{7JF`N8ys&8EnBIreozzwXyvjSvlDruB;5x!$Xnyj1X!07h$Pn6jcYf6SBM5q!d&djqZoq_nZLnHO!*stxbz$k z^O6OVs+_<8W@9oUnLlJW2AgrJxN#Uiu)EO55S(udFjW7z7Y*E=w)sI0G84zJJpYbF zwzLI!nx2AqGGew**VH(+^=R_>j2PR-CF)OWzawq%uDa$G`gogyQMoI%|H<=lr(y6R jw|ThRX3<*4@9h2yt8`HryKo;Y00000NkvXXu0mjflb`cS diff --git a/src/main/resources/edu/rpi/legup/images/sudoku/AdvancedDeduction.png b/src/main/resources/edu/rpi/legup/images/sudoku/AdvancedDeduction.png deleted file mode 100644 index d51538baf164400e6c4cca37fa44f738b2d3c6c1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3351 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 diff --git a/src/main/resources/edu/rpi/legup/images/sudoku/rules/NoCellForNumberColumn.png b/src/main/resources/edu/rpi/legup/images/sudoku/rules/NoCellForNumberColumn.png new file mode 100644 index 0000000000000000000000000000000000000000..9dcade64b2fb79be751848670324692e7b464cce GIT binary patch literal 958 zcmV;v13~Px&cu7P-RCt{2oWE|{Fc62&MF))<`XUzK#XyG|=+Ni!%*l^cAWMOGFu=S>2M--I z6iA0!jigW#?|2fg((eO;1djX%`g}a{MBUEc{42Gn4i)*Er!iuVNjZMYeBeF-CwE>x zat^KzRp)mbNYa5N1Sfrd*h3bW7YH#1gcu{3LqbU#EJIMpD-pdYCGh>BqMgbsZG+&D z^>XvHSBR4Rp;8mO6$W!isuakOF`Cq+QXoUlkuw@xU5kk1@ z42hKf|F_I&QkO3JF#D1-C?vHUGA3o~Q7}eOh*oV1k-{gKLv}<&GoQ$*T(VVyLN1q! z>YF&{R9~;p{~$JYn9jN{3%TSyqH3>IEDGjEFLo{(144`eA;w4&GWYChi-?6l#yp6G zIOnJ=OYP4BC?P`5=d#AJ5s|J6k6Q zYtdl^baHsmEvKFI&$WY26S?GP}eopb)EZTEZ@n&YIIm((M}FAci_e_$FP!n zsA@nh%NU{vX%ADJAuHxC+^w^CCkF@^hb3gHlLJU6T1adshZqng!$b+;c5(o6CWS~l zIZS~l34=}!#u%LTYISlLdkyUxu5a?nJ-WHSNreC_+x(PW1HsiTu@5Q52ZgD#8|W{BrE3 z3A2IHi7_C=7!YC%2r))5sbeae4{UNU28JwSK!`CQ#264_3yOtH2F`>4l2P;C_ gZBv_{_TwO(KSVOPa4)&_O8@`>07*qoM6N<$g6E{9PXGV_ literal 0 HcmV?d00001 diff --git a/src/main/resources/edu/rpi/legup/images/sudoku/rules/NoCellForNumberRegion.png b/src/main/resources/edu/rpi/legup/images/sudoku/rules/NoCellForNumberRegion.png new file mode 100644 index 0000000000000000000000000000000000000000..000dc8b68935563c869c695b114190eac7499805 GIT binary patch literal 1077 zcmeAS@N?(olHy`uVBq!ia0vp^DImV1DoE;uumf z=k1)me$tKt$N&2Y6uk`p=oNk>s4K#2;`4rb9xS z7iK=SsK4{>OjTNb-K1^@iM$_o@6}b*3zKK1sW$F0Z5C)l(Hs9l}f z^X*5i;>;_WlV*kS)yv6u_uOaS6dL9gwERxwt;h4ZUT!j1TWNPPqraZ($?pkvo<~&{ z+x|10G;Qzij7e2dzxV#0Iz@H)w;$~Zf=qi&Qf>9PFDPYX7BX0`12JonP$_7uTOJjLr~g}(jhe518xwdlFc%4K$?H*eL33p@`}XsTDGHtIQ#o$WvU9?^ly7T&Zh6Mm?bEUQXXw%DVPic> zk~d;l5Z>R?_#QR`O`wi_4*YwV@p4f8L}zC^ID7 zQOWF=cb+uiXp&>8to(}Cv%V^v5AFN=D|tguP~r>$6trO~V`<=Z)1N_`SLbyV?YtAW zuSjodqmNV4^(V(O_7}SNUgteh7~HzSe$%U6$5MDJ6&= zvfa~o{rI%slb+jXx!XmmmuAiSc{nuBd}p!vrozK&OJ<(9Eo^l>_L`Wp?$dAIbsKDo zf&O3D{ao(TzXQkFlTLn|!KIm%ydsuuK@A^g;nc$wHpgDoxk_!%=0B>bxmsXa>@U`a zx3BlFOr4V~zo@DuBR;S+@QO?jlbVYJ1bMa=9ZT$bJ$>okciL?CiRK zjpD*(@z(+ZuIguVtav>=)Jp4j>Q>JF6PD9XeSTleaNyZ}wi}=1vNpZFa=0$|t$2Hn z8%rtgjX%d_PVZKoR_^_Sz5ipynO&M;clBRCd&YKPcF)`?@g_lO_tS3txx44L)Yodg z+>r05tM1vA*C%_6{IB${aRc&q{j21Cklf0B)#j1>pZ3UUzj@Yo)I~Dv?I~WkD?Uu4 zF+1oxzue~ao9}v;y6=?vyX=tQK~t-+@2l^2OK<(V=^X2KnM0cl-(1euD&>?B+gw<~ zrz&DF)8~eK?r|b literal 0 HcmV?d00001 diff --git a/src/main/resources/edu/rpi/legup/images/sudoku/rules/NoCellForNumberRow.png b/src/main/resources/edu/rpi/legup/images/sudoku/rules/NoCellForNumberRow.png new file mode 100644 index 0000000000000000000000000000000000000000..f984f836508fbc3d6f0dce4d9b749f5e53de8d87 GIT binary patch literal 916 zcmeAS@N?(olHy`uVBq!ia0vp^DImVD|HLaSW-L z^LFmWyxRsMuJgNjq)flK`#3oBl&omv`zv>T)}Kh$O)MSk%xC&bPOQ+K8F8a2*YnBZ zd#csv=l!sgw+mV%lJ@xgzhDlY`)imdWNWbSa4|MJ9atb>fW(}qV|S(W+@oaihv)A- zDZZ(gFr&odK$eKzpL-(rTv}e zMq{QoAme+oS|aR^Us%MYINiuA&fY~!P)H-T&BN8{*88=kETUcFn|^N;7M$3>U;db9 ziAGe%>p47!6?`v;7{+#r=&5}8_A5=+u~)0*ipxf)L$?B@k8%l4Ty?F_p>TG0W1_?w z<&=dl_*PC#vR<-nrPcvHOiuy*cUk&yRGiO+7Fnh?&-N?3-Y#Uc2Kirkwt(J^!j!iH zCYtMt3uYcGIK_k!B%3%K_g`~Y%Wf|aF0`Dp2^3(9=C>EjJ#kp=Ykk1cu9I8$E#VV+ zU8*1Hk?>A@W7t9OqY>R4D>ymt{8n1SHBYEnNoj$e3(Mz}){PQVVv;w-q_!qa?Amvx zX-c-wG(N?TIW8?u4HdJj7QPL3xi>Yc=CZW(p zor_s6c+mFH+uw12{p{HPJy}0*d)8XTll7O%EFT5A$48j!UFX+zoMp-U@5%qUInU3> zxq3~SP?(q))uCJV=jihZij(Gj7JAEUv3U8KYSzrRnwcBJ{4Q%|XO(339S|vc&Lebd zTj*`cIGvO{Mya5nWvfk#o>hF>k#QQ2@#E!F3`Y22N%uG!+zUgxUM2u-s3x+XM7 z(^B40(kq%sZU$yE22WQ%mvv4F FO#n+HlXCz7 literal 0 HcmV?d00001 diff --git a/src/main/resources/edu/rpi/legup/images/sudoku/NoSolution.png b/src/main/resources/edu/rpi/legup/images/sudoku/rules/NoSolution.png similarity index 100% rename from src/main/resources/edu/rpi/legup/images/sudoku/NoSolution.png rename to src/main/resources/edu/rpi/legup/images/sudoku/rules/NoSolution.png diff --git a/src/main/resources/edu/rpi/legup/images/sudoku/PossibleValues.png b/src/main/resources/edu/rpi/legup/images/sudoku/rules/PossibleValues.png similarity index 100% rename from src/main/resources/edu/rpi/legup/images/sudoku/PossibleValues.png rename to src/main/resources/edu/rpi/legup/images/sudoku/rules/PossibleValues.png diff --git a/src/main/resources/edu/rpi/legup/images/sudoku/RepeatedNumber.png b/src/main/resources/edu/rpi/legup/images/sudoku/rules/RepeatedNumber.png similarity index 100% rename from src/main/resources/edu/rpi/legup/images/sudoku/RepeatedNumber.png rename to src/main/resources/edu/rpi/legup/images/sudoku/rules/RepeatedNumber.png diff --git a/src/main/resources/edu/rpi/legup/images/sudoku/forcedByDeduction.png b/src/main/resources/edu/rpi/legup/images/sudoku/rules/forcedByDeduction.png similarity index 100% rename from src/main/resources/edu/rpi/legup/images/sudoku/forcedByDeduction.png rename to src/main/resources/edu/rpi/legup/images/sudoku/rules/forcedByDeduction.png diff --git a/src/main/resources/edu/rpi/legup/images/sudoku/forcedByElimination.png b/src/main/resources/edu/rpi/legup/images/sudoku/rules/forcedByElimination.png similarity index 100% rename from src/main/resources/edu/rpi/legup/images/sudoku/forcedByElimination.png rename to src/main/resources/edu/rpi/legup/images/sudoku/rules/forcedByElimination.png diff --git a/src/main/resources/edu/rpi/legup/images/sudoku/possible_cells_number.png b/src/main/resources/edu/rpi/legup/images/sudoku/rules/possible_cells_number.png similarity index 100% rename from src/main/resources/edu/rpi/legup/images/sudoku/possible_cells_number.png rename to src/main/resources/edu/rpi/legup/images/sudoku/rules/possible_cells_number.png diff --git a/src/main/resources/edu/rpi/legup/images/sudoku/rules/possible_cells_number_column.png b/src/main/resources/edu/rpi/legup/images/sudoku/rules/possible_cells_number_column.png new file mode 100644 index 0000000000000000000000000000000000000000..2ebdc582364e4afc93c26d2e41548abf30456ed8 GIT binary patch literal 3336 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 SmU`#_0000uJ@VVD_U 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/edu/rpi/legup/images/sudoku/rules/possible_cells_number_row.png b/src/main/resources/edu/rpi/legup/images/sudoku/rules/possible_cells_number_row.png new file mode 100644 index 0000000000000000000000000000000000000000..80476a42820b213907af74ce76c96424a103b862 GIT binary patch literal 803 zcmeAS@N?(olHy`uVBq!ia0vp^DImV7lw+;uumf z=j~kEJgGntH+%OuhDZmoi4$WaPKH{U2a1`9YM){XaxLQWP7#cBh~o10Yjx^4&V1(k zgF7F~r6xG|Pp|$`SMmATxvRel|E_6xcy}o?$A2M310@!>mIECE5`s+1P6;j?JsgdN zw%=OcEwgr)$?y95xaz~^K*eOs8M+I!;Hlq$@iDW2kKmOj`3V_dO{b+#AWK6n|M}E5P11zN!Ub1 zQDG(7`FFgGmNYpnIXpSWw=E>3!(`r@E~6!foR&OX5l0AR_{`y}D+-{TV;{Rs_-QDFn=lPnv+ACit z!nbeZxLN<9^S7hMx>wh9 zAAtmTB6ZEb%@OrHzlqUu({e(~Cm3Z<`mh=YLWD)Q!J) z)xH;a(o@{Mde_#{sZak*T)QfI`wPiQ>+9C1p2+&De0NLN<;c6cPW~6@toGdMI_KQ0 zYhsGeJ@zH<$P!J@+JAlqIK=yAIqMa&z7<(@>qN^^MF)8F(Ut f1vEJ2J?7VB=2_pOylEaV)iZdy`njxgN@xNAzyM-G literal 0 HcmV?d00001 diff --git a/src/main/resources/edu/rpi/legup/images/sudoku/tem.png b/src/main/resources/edu/rpi/legup/images/sudoku/rules/tem.png similarity index 100% rename from src/main/resources/edu/rpi/legup/images/sudoku/tem.png rename to src/main/resources/edu/rpi/legup/images/sudoku/rules/tem.png diff --git a/src/main/resources/edu/rpi/legup/images/starbattle/white.gif b/src/main/resources/edu/rpi/legup/images/sudoku/tiles/NumberTile.png similarity index 82% rename from src/main/resources/edu/rpi/legup/images/starbattle/white.gif rename to src/main/resources/edu/rpi/legup/images/sudoku/tiles/NumberTile.png index fc2c683eb7860f47d4322fe0e73b0508099a89de..5a8540d02b509f12c7f059648bbadf021efcedda 100644 GIT binary patch delta 1577 zcmV+^2G;rHOVdt}BYy-jdQ@0+Qek%>aB^>EX>4U6ba`-PAZ2)IW&i+q+O1bxlH)22 z{nsjH36=y1mcz5^?%*ze4%kUMnRIm?ZDIpL7DqY~u2BE~zd?U+iP%QYTMQ|L4VOzU zNyZ><`<2#{H@BYal4A+;8#!GU1R_PR`_%HGf06Umz}{ty{C~;NWpggK3-MTxcxUL? zNGGC+q8*0PWnK0Kc86De@5=>p{JPb44==iNPG^BLM5%dbsYqAW4NuXyZ=~}U&FBqJ zjG@QsFjkF(&cWge?3gIrzwx*a_;qv&INdDV1zg-A*Sk1{Yk!r~d4c`oz^>?>Qy^bA zmK#L5ZML1SQ-5H`XmKo`;YD@6V@>W4e+v--( zDkl~&G1zhA%!4~O!k}^mMkieiy+{>ZvZy9Ws_xvN@etFbO(Qs~U{oQM9SXS_$h2Br zyG88W7^=cB#*6YN8a=D{sEtu)h#1Z@9l-)Fnb`^$lYhDSgc=y(aRk+`0AJeu1w%+r zQ0P~fBOJ_I*-aGBU%91=Xoa3fzgGfVTZu7=a)iA-z_5aXEwFkHyctdyW&|>VpbY4u zP6`-c@1+5xIMo1dqRg%FiV-he@v_Tt9)St30reEYPzG7fdE}3|h#bmZz4P7&Z$A3u zbI{;|4}XDzg?X@LQ*-7mm|3)BIcjv##}F;Xm|{+n6z85#Az6wkrJS*6hUJWxbEFJO zk)p*FUqZ1GODee{eX6UzhH5p|RCAN24M#%@&01`!<<1?c)Lr*IbfX@7>Ukj7h7LFU z2*XAkY2+(w2dn?I7g*ziHCaqeJ-f07so7D`NPicaMkZ%qOdNx80|ktPmdV)`**Tfa zP0qF?s0uFt=_fahCu3mHbtdtH@#fCm7jrN3Mj?F5o4mptP3k^i?#df=J9vA*TASat zx)|H5aMs|as6MRsn5FbFpfe)AA~BCLh5PjV8U2o#QRsa$1qV3<%Riiud9ED3LPO%4 zJ%7FR;sSGviYBbzKt*r6bBBs9!TJ;x#ZQ8KLPci^KS4#GP<}>5_lflms=*Z{A`Zo0 zdbX9eQ8L4R%S$0`0V@!s)=NzxZaTM+g1u1e*ml{PJzWOh^jCbVG|q&tn)%YCZ%sUD zT1$aV7J_xdsDEPY9PB%wuj8a?yHzPwVSh*sW;?`N%fsZAET9L4d_X?Z;Ynk3lUsG* zOHsOWnBjmA?0~Ge@Pu>pKH;}LJqnzL+yEt(HSI0r?MGnrEYrvETZr_7`y=^T7`1kw zLfG=a-zsa4oyTwfA3A!v7yQ(FVDr|-Sc4_7(X7%jdd0+?S)B`~8Qo6rW^0e zke@|N&qwEJL!V)y&#^o(^a&>Vjrcq;^gX7P5p9+VGUUOWeo}aLPM;e11w_mHeLjGw zC7f=50bTn~%N}k&;Gh#V7HDhEgG-Eb6Ei__gWi4VhVKXgbF*!71GBRQ@ zH90bqU=SZ9W;io4H!wLhEj4ClHZ3$_I590aGB-IbGi5b0I5;vmG%+<}lcNwPBxN)) zFk)t9G%Yt}VP!2eI5ROVVPP{lEjD2|F*0E`V_`I7Vw3I=V+b-hI5s&qG&Pf15!EC$ zF)(B@GB;r@H)CRAEi`61HZ5W?F*YqRG&M73Gh;I|VPavEQW8}HG&r-V5@-kntGq6x zldA(CvosrA3V$#$K0^8c008qzL_t(o!|j(biiI!~MNi~|km{GNLTs$;(zpW)!7T_b z$Zgo^CftBvZ>tvaels&nH^dA-%#hoq2%J3beeXp9f=4|7MEo!)rHJsX01yBIz~2Mt z`yOKq&*u}ZHO3g$b#;Oe8$(;|mSquJeSeMtaTOp%QQW$xJ^-A1dK||b z$Kh`lBuU~Y1zpzx(6;S+O!!^XGzlPCmfiNwZGdqcC5j?R)6~hlw*ZD=5J2)gcTSHr zz&y_aIKA8{hFWXR^W?g&_pfACRk80oP1F3|UT9MRrPNPxvaZ0xGOuAA2Y>+Z{{WQl b@A(VSFcRW7YuzH900000NkvXXu0mjf3V+L@ delta 1257 zcmVaB^>EX>4U6ba`-PAZ2)IW&i+q+Pzk7vg0TW z{Ld-&2$lp$9ET56wKtgKZ-X5_CzIKFaq`Ag3z)P4{AzAQdv27t4KbDMI z@kSedBpz)MbF-q2*gjDB-}!hX{AisBcXtC1gtOo6^1xF(>cj5N0~DSUJJ~y@Kt2}c zJ4A@1%lSDG+kbnrKKG1WWFNs|+&6XG$!s||77!zIT0~L&0@^xDLa`+;6@s*-E(N7h zB8C#3JT=PHX{F}Ss8oT`^U8{vxw1@~iE`p9n>HxaStUsmgJuZ zdg}R5ZCCZT@`7r#tHx8Q;irdcu&V9{8tLLjkbj{W6k|_NTpv+W z?G%nPxCl-k##hT+*52XM4gVsRdl|;9d%fpA6Q&n;Jxswx4#V6ZZpb`F_PxS`?PBdN zO@EwV?oqh`>l3KlcMUl-locdz%{XTmVP{9m0ocMrJr@Nt;je-wg6aTzqaJF{K{kqmz`Ha220 zFl1#dF)(B~Ei`5@Vl852VPq{fGG;R|G%{f{W@Tm~3LqdLcx`Y^O*%<#b97;DV`WK1 zJtBB*a4uY(#Hkb#0Sw5f3CWH(@n0G-YBfW;rrBEi`2~GA&{^VKOaYHD)w9 zGdDRlGcaV6p%G&UF*7kZIW{;mlME8oBw{o;V`DiuW-VnjVPY*bF*0T?Ib>xpEi__d zVPQ39Wiw=BFp~unRRS|Jvs@Es2n44`A)Aw41Rt~K8(a!hAzO}O2mk;8H%UZ6R9M69 z*Fg~gFc5=4(mDT@QyKYyg8dSp3_E~!V@SedoB#m=1PBlyK!5-N0t5&UkoBH_h^qxZ T9iesj00000NkvXXu0mjfY5XLV diff --git a/src/main/resources/edu/rpi/legup/images/starbattle/UnknownTile.png b/src/main/resources/edu/rpi/legup/images/sudoku/tiles/UnknownTile.png similarity index 100% rename from src/main/resources/edu/rpi/legup/images/starbattle/UnknownTile.png rename to src/main/resources/edu/rpi/legup/images/sudoku/tiles/UnknownTile.png diff --git a/src/main/resources/edu/rpi/legup/legup/config b/src/main/resources/edu/rpi/legup/legup/config index 1ee9ed79c..e01767677 100644 --- a/src/main/resources/edu/rpi/legup/legup/config +++ b/src/main/resources/edu/rpi/legup/legup/config @@ -34,26 +34,22 @@ fileCreationDisabled="false"/> - + fileCreationDisabled="false"/> - - - + + + diff --git a/src/test/java/puzzles/nurikabe/rules/FinishRoomCaseRuleTest.java b/src/test/java/puzzles/nurikabe/rules/FinishRoomCaseRuleTest.java index 9ba7fb9f3..32a440d13 100644 --- a/src/test/java/puzzles/nurikabe/rules/FinishRoomCaseRuleTest.java +++ b/src/test/java/puzzles/nurikabe/rules/FinishRoomCaseRuleTest.java @@ -78,34 +78,6 @@ public void FinishRoomCaseRule_FinishRoomCaseRuleBaseTest() throws InvalidFileFo NurikabeCell cell2 = board.getCell(4, 2); ArrayList cases2 = RULE.getCases(board, cell2); - Assert.assertEquals(6, cases2.size()); // correctly stops generating possible cases after - // more than 5 (the max) is found. Would have generated 8 cases - // FinishRoomCaseRule finny = new FinishRoomCaseRule(); - // finny.checkRuleRaw(); - // "Invalid use of the case rule FinishRoom: This case rule must have 5 or less children." - - // getErrorString in auto case rule - // should display "The selection can produce a max of 5 cases." - // AutoCaseRuleCommand autoCaseRuleCommand = new AutoCaseRuleCommand(elementView, selection, - // caseBoard.getCaseRule(), caseBoard, e); - - // NurikabeBoard caseyBoard = (NurikabeBoard) cases2.get(0); - // NurikabeBoard caseyBoard2 = (NurikabeBoard) cases2.get(1); - // NurikabeBoard caseyBoard3 = (NurikabeBoard) cases2.get(2); - // NurikabeBoard caseyBoard4 = (NurikabeBoard) cases2.get(3); - // NurikabeBoard caseyBoard5 = (NurikabeBoard) cases2.get(4); - // NurikabeBoard caseyBoard6 = (NurikabeBoard) cases2.get(5); - // NurikabeBoard caseyBoard7 = (NurikabeBoard) cases2.get(6); - // NurikabeBoard caseyBoard8 = (NurikabeBoard) cases2.get(7); - // - // NurikabeType boardy1Type = caseyBoard.getCell(5,5).getType(); - // NurikabeType boardy2Type = caseyBoard2.getCell(6,6).getType(); - // NurikabeType boardy3Type = caseyBoard.getCell(5,5).getType(); - // NurikabeType boardy4Type = caseyBoard2.getCell(6,6).getType(); - // NurikabeType boardy5Type = caseyBoard.getCell(5,5).getType(); - // NurikabeType boardy6Type = caseyBoard2.getCell(6,6).getType(); - // NurikabeType boardy7Type = caseyBoard.getCell(5,5).getType(); - // NurikabeType boardy8Type = caseyBoard2.getCell(6,6).getType(); - + Assert.assertEquals(9, cases2.size()); } } diff --git a/src/test/java/puzzles/sudoku/rules/LastNumberForCellDirectRuleRegionTest.java b/src/test/java/puzzles/sudoku/rules/LastNumberForCellDirectRuleRegionTest.java new file mode 100644 index 000000000..f27f38d8a --- /dev/null +++ b/src/test/java/puzzles/sudoku/rules/LastNumberForCellDirectRuleRegionTest.java @@ -0,0 +1,100 @@ +package puzzles.sudoku.rules; + +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.sudoku.Sudoku; +import edu.rpi.legup.puzzle.sudoku.SudokuBoard; +import edu.rpi.legup.puzzle.sudoku.SudokuCell; +import edu.rpi.legup.puzzle.sudoku.rules.LastNumberForCellDirectRule; +import edu.rpi.legup.save.InvalidFileFormatException; +import legup.MockGameBoardFacade; +import legup.TestUtilities; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class LastNumberForCellDirectRuleRegionTest { + private static final LastNumberForCellDirectRule RULE = new LastNumberForCellDirectRule(); + private static Sudoku sudoku; + + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + sudoku = new Sudoku(); + } + + @Test + public void LastNumberForCellDirectRule_FullRegionTest() throws InvalidFileFormatException { + // Import board and create transition + TestUtilities.importTestBoard( + "puzzles/sudoku/rules/LastNumberForCellDirectRule/FullRegion", sudoku); + TreeNode rootNode = sudoku.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + // Loop all numbers at point + for (int i = 1; i < 10; i++) { + // Reset board + SudokuBoard board = (SudokuBoard) transition.getBoard(); + // Set cell + SudokuCell cell1 = board.getCell(2, 5); + cell1.setData(i); + board.addModifiedData(cell1); + + // Test the case + if (i == 9) { + Assert.assertNull(RULE.checkRuleAt(transition, cell1)); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, cell1)); + } + } + + // Import Board and create transition + TestUtilities.importTestBoard( + "puzzles/sudoku/rules/LastNumberForCellDirectRule/FullRow", sudoku); + rootNode = sudoku.getTree().getRootNode(); + transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + // Loop all numbers at point + for (int i = 1; i < 10; i++) { + // Reset board + SudokuBoard board = (SudokuBoard) transition.getBoard(); + // Set cell + SudokuCell cell = board.getCell(4, 4); + cell.setData(i); + board.addModifiedData(cell); + + // Test the case + if (i == 5) { + Assert.assertNull(RULE.checkRuleAt(transition, cell)); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, cell)); + } + } + + // Import Board and create transition + TestUtilities.importTestBoard( + "puzzles/sudoku/rules/LastNumberForCellDirectRule/FullMixed", sudoku); + rootNode = sudoku.getTree().getRootNode(); + transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + // Loop all numbers at point + for (int i = 1; i < 10; i++) { + // Reset board + SudokuBoard board = (SudokuBoard) transition.getBoard(); + // Set cell + SudokuCell cell = board.getCell(5, 3); + cell.setData(i); + board.addModifiedData(cell); + + // Test the case + if (i == 2) { + Assert.assertNull(RULE.checkRuleAt(transition, cell)); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, cell)); + } + } + } +} diff --git a/src/test/java/puzzles/sudoku/rules/RepeatedNumberContradictionRuleTest.java b/src/test/java/puzzles/sudoku/rules/RepeatedNumberContradictionRuleTest.java new file mode 100644 index 000000000..704167a29 --- /dev/null +++ b/src/test/java/puzzles/sudoku/rules/RepeatedNumberContradictionRuleTest.java @@ -0,0 +1,88 @@ +package puzzles.sudoku.rules; + +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.sudoku.Sudoku; +import edu.rpi.legup.puzzle.sudoku.SudokuBoard; +import edu.rpi.legup.puzzle.sudoku.SudokuCell; +import edu.rpi.legup.puzzle.sudoku.rules.RepeatedNumberContradictionRule; +import edu.rpi.legup.save.InvalidFileFormatException; +import legup.MockGameBoardFacade; +import legup.TestUtilities; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class RepeatedNumberContradictionRuleTest { + private static final RepeatedNumberContradictionRule RULE = + new RepeatedNumberContradictionRule(); + private static Sudoku sudoku; + + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + sudoku = new Sudoku(); + } + + @Test + public void RepeatedNumberContradictionRule_GlobalTest() throws InvalidFileFormatException { + // Import board and create transition + TestUtilities.importTestBoard( + "puzzles/sudoku/rules/RepeatedNumberContradictionRule/BlankBoard7", sudoku); + TreeNode rootNode = sudoku.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + // Loop through every cell + for (int i = 0; i < 81; i++) { + // Reset board + SudokuBoard board = (SudokuBoard) transition.getBoard(); + // Set cell + int x = i / 9; + int y = i % 9; + if (x == 0 && y == 0) { + continue; + } + SudokuCell cell = board.getCell(x, y); + cell.setData(7); + + // Test the case + if (x == 0 || y == 0 || (x < 3 && y < 3)) { + Assert.assertNull(RULE.checkRuleAt(transition, cell)); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, cell)); + } + cell.setData(0); + } + // Import board and create transition + TestUtilities.importTestBoard( + "puzzles/sudoku/rules/RepeatedNumberContradictionRule/BlankBoard4", sudoku); + rootNode = sudoku.getTree().getRootNode(); + transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + // Loop through every cell + for (int i = 0; i < 81; i++) { + // Reset board + SudokuBoard board = (SudokuBoard) transition.getBoard(); + // Set cell + int x = i / 9; + int y = i % 9; + if ((x == 3 && y == 0) || (x == 6 && y == 8)) { + continue; + } + SudokuCell cell = board.getCell(x, y); + cell.setData(4); + + // Test the case + if ((x == 3 || y == 0 || x == 6 || y == 8) + || (x > 2 && x < 6 && y < 3) + || (x > 5 && y > 5)) { + Assert.assertNull(RULE.checkRuleAt(transition, cell)); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, cell)); + } + cell.setData(0); + } + } +} diff --git a/src/test/resources/puzzles/binary/rules/SurroundPairDirectRule/SurroundTwoZerosWithTwoOnes b/src/test/resources/puzzles/binary/rules/SurroundPairDirectRule/SurroundTwoZerosWithTwoOnes new file mode 100644 index 000000000..026742fea --- /dev/null +++ b/src/test/resources/puzzles/binary/rules/SurroundPairDirectRule/SurroundTwoZerosWithTwoOnes @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/puzzles/binary/rules/SurroundPairDirectRule/test b/src/test/resources/puzzles/binary/rules/SurroundPairDirectRule/test new file mode 100644 index 000000000..e69de29bb diff --git a/src/test/resources/puzzles/nurikabe/rules/BlackBetweenRegionsDirectRule/SurroundTwoZerosWithTwoOnes b/src/test/resources/puzzles/nurikabe/rules/BlackBetweenRegionsDirectRule/SurroundTwoZerosWithTwoOnes new file mode 100644 index 000000000..026742fea --- /dev/null +++ b/src/test/resources/puzzles/nurikabe/rules/BlackBetweenRegionsDirectRule/SurroundTwoZerosWithTwoOnes @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle.rules/BlackoutDirectRule/ColumnBlackout b/src/test/resources/puzzles/starbattle.rules/BlackoutDirectRule/ColumnBlackout deleted file mode 100644 index ddcc4dc9a..000000000 --- a/src/test/resources/puzzles/starbattle.rules/BlackoutDirectRule/ColumnBlackout +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle.rules/BlackoutDirectRule/RegionBlackout b/src/test/resources/puzzles/starbattle.rules/BlackoutDirectRule/RegionBlackout deleted file mode 100644 index f2a5b42d9..000000000 --- a/src/test/resources/puzzles/starbattle.rules/BlackoutDirectRule/RegionBlackout +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/test/resources/puzzles/starbattle.rules/BlackoutDirectRule/RowBlackout b/src/test/resources/puzzles/starbattle.rules/BlackoutDirectRule/RowBlackout deleted file mode 100644 index f2a5b42d9..000000000 --- a/src/test/resources/puzzles/starbattle.rules/BlackoutDirectRule/RowBlackout +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/test/resources/puzzles/sudoku/rules/LastCellForNumberDirectRule/CorneredRegion b/src/test/resources/puzzles/sudoku/rules/LastCellForNumberDirectRule/CorneredRegion new file mode 100644 index 000000000..4d3c57225 --- /dev/null +++ b/src/test/resources/puzzles/sudoku/rules/LastCellForNumberDirectRule/CorneredRegion @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/sudoku/rules/LastNumberForCellDirectRule/FullMixed b/src/test/resources/puzzles/sudoku/rules/LastNumberForCellDirectRule/FullMixed new file mode 100644 index 000000000..55b501fec --- /dev/null +++ b/src/test/resources/puzzles/sudoku/rules/LastNumberForCellDirectRule/FullMixed @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/puzzles/sudoku/rules/LastNumberForCellDirectRule/FullRegion b/src/test/resources/puzzles/sudoku/rules/LastNumberForCellDirectRule/FullRegion new file mode 100644 index 000000000..58fd02162 --- /dev/null +++ b/src/test/resources/puzzles/sudoku/rules/LastNumberForCellDirectRule/FullRegion @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/sudoku/rules/LastNumberForCellDirectRule/FullRow b/src/test/resources/puzzles/sudoku/rules/LastNumberForCellDirectRule/FullRow new file mode 100644 index 000000000..07e502ed9 --- /dev/null +++ b/src/test/resources/puzzles/sudoku/rules/LastNumberForCellDirectRule/FullRow @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/sudoku/rules/RepeatedNumberContradictionRule/BlankBoard4 b/src/test/resources/puzzles/sudoku/rules/RepeatedNumberContradictionRule/BlankBoard4 new file mode 100644 index 000000000..abaa0ba6b --- /dev/null +++ b/src/test/resources/puzzles/sudoku/rules/RepeatedNumberContradictionRule/BlankBoard4 @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/sudoku/rules/RepeatedNumberContradictionRule/BlankBoard7 b/src/test/resources/puzzles/sudoku/rules/RepeatedNumberContradictionRule/BlankBoard7 new file mode 100644 index 000000000..5692dea64 --- /dev/null +++ b/src/test/resources/puzzles/sudoku/rules/RepeatedNumberContradictionRule/BlankBoard7 @@ -0,0 +1,11 @@ + + + + + + + + + + +