Skip to content

Commit

Permalink
Short Truth Table Puzzle Editor (#451)
Browse files Browse the repository at this point in the history
* Created files for STT elements

* Renamed Tiles classes to Elements to match package name

Also added an elements reference sheet and renamed rules reference sheet accordingly

* More progress made

This won't compile, just saving progress made

* More progress being made

* Fixed file name typo and added placeholder tiles

* Added image paths

* Created element classes and added placeholder tile images (#452)

* Renamed Tiles classes to Elements to match package name

Also added an elements reference sheet and renamed rules reference sheet accordingly

* More progress made

This won't compile, just saving progress made

* More progress being made

* Fixed file name typo and added placeholder tiles

* Added image paths

* Set the current board on boardView

* Fixed typo and turned on STT puzzle editor for testing

* Added preliminary valid dimensions checker

This will most definitely change in the future, hopefully can change to accept a number of statements

* Fixed image file paths

* Added ActionListener

Allows us to determine what puzzle is selected by the user

* Hide rows and columns input for Short Truth Table

* Added text area for Short Truth Table

* Added scrollbars to show up as needed

* Reformatted code

* More code reformatting

* Even more reformatting

* Separate the data from the TextArea into different lines

* Did some researching/testing

Tested certain variable values with a STT file with no true/false values

* Made more progress

Added new methods to handle creating Short Truth Table boards from an array of strings

* Added a bunch of TODOs

- Implemented a couple functions to be used later
- Added a bunch of TODO comments for future work

* Made some more progress

* Implemented abstract methods from PuzzleImporter

* Added abstract methods to Fillapix and added other exception reporting

* CheckStyle formatting

* Removed a TODO comment

* Statements show up in puzzle editor

Fixed a bug where the importer was not properly being initialized. Statements now show up in the puzzle editor.

* Removed empty statements

* Changed InvalidFormatException to IllegalArgumentException

* Remove argument that has already been caught

* Removed elements that will not be used

* Added puzzle editor cell clicking functionality

* Added ability to toggle certain logical elements

* New icons and more functionality implemented

* Fixed a bug where spacer rows could be modified

* Added statement error checking

* Fixed formatting

* Only one logic symbol element needed

* Changed InputMismatchException to UnsupportedOperationException

* Renamed variables to not be STT specific

* Finding initial issue and starting fix

* Issue is statement copying and modifying

* STT exporter now working. Overrode setCell for STTBoard.

* Added code documentation

* removed testing println()

* Gradle fixes

* Revert "Merge pull request #545 from MMosley502/puzzle_editor-short_truth_table-file_saving"

This reverts commit 2e82547, reversing
changes made to beb60a2.

* Saving files now works

* Fixed the blank element to be categorized as a placeable element

* Fixed a bug where file wouldn't save due to batch grader updates

* Reformatted code in STT

* Reformatted code again

* MORE REFORMATTING

Pls like my code CheckStyle

---------

Co-authored-by: Matthew Mosley <[email protected]>
Co-authored-by: MMosley502 <[email protected]>
  • Loading branch information
3 people authored Sep 29, 2023
1 parent 50ba53f commit f3dbafb
Show file tree
Hide file tree
Showing 39 changed files with 629 additions and 38 deletions.
2 changes: 1 addition & 1 deletion bin/main/edu/rpi/legup/legup/config
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
<puzzle name="ShortTruthTable"
qualifiedClassName="edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTable"
fileType=".xml"
fileCreationDisabled="true"/>
fileCreationDisabled="false"/>
<puzzle name="Sudoku" qualifiedClassName="edu.rpi.legup.puzzle.sudoku.Sudoku"
fileType=".xml"
fileCreationDisabled="true"/>
Expand Down
14 changes: 14 additions & 0 deletions puzzles files/shorttruthtable/empty_test.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<Legup version="2.0.0">
<puzzle name="ShortTruthTable">
<board>
<data>
<statement representation="A>(B^C)" row_index="0"/>
<statement representation="C-B" row_index="1"/>
<statement representation="~C" row_index="2"/>
<statement representation="~A" row_index="3"/>
</data>
</board>
</puzzle>
<Solved isSolved="false"/>
</Legup>
84 changes: 76 additions & 8 deletions src/main/java/edu/rpi/legup/app/GameBoardFacade.java
Original file line number Diff line number Diff line change
@@ -1,23 +1,22 @@
package edu.rpi.legup.app;

import edu.rpi.legup.history.History;
import edu.rpi.legup.history.IHistoryListener;
import edu.rpi.legup.history.IHistorySubject;
import edu.rpi.legup.model.Puzzle;
import edu.rpi.legup.model.PuzzleImporter;
import edu.rpi.legup.model.gameboard.Board;
import edu.rpi.legup.model.Puzzle;
import edu.rpi.legup.model.tree.Tree;
import edu.rpi.legup.save.InvalidFileFormatException;
import edu.rpi.legup.ui.LegupUI;
import edu.rpi.legup.ui.ProofEditorPanel;
import edu.rpi.legup.ui.PuzzleEditorPanel;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;
import edu.rpi.legup.save.InvalidFileFormatException;
import edu.rpi.legup.ui.LegupUI;
import edu.rpi.legup.history.History;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
Expand Down Expand Up @@ -144,6 +143,30 @@ public boolean validateDimensions(String game, int rows, int columns) throws Run
}
}

/**
* Validates the given text input for the given puzzle
*
* @param game the name of the puzzle
* @param statements an array of statements
* @return true if it is possible to create a board for the given game with the given statements,
* false otherwise
* @throws RuntimeException if any of the input is invalid
*/
public boolean validateTextInput(String game, String[] statements) throws RuntimeException {
String qualifiedClassName = config.getPuzzleClassForName(game);
try {
Class<?> c = Class.forName(qualifiedClassName);
Constructor<?> constructor = c.getConstructor();
Puzzle puzzle = (Puzzle) constructor.newInstance();
return puzzle.isValidTextInput(statements);
}
catch (ClassNotFoundException | NoSuchMethodException | InvocationTargetException | IllegalAccessException |
InstantiationException e) {
LOGGER.error(e);
throw new RuntimeException("Error validating puzzle text input");
}
}

/**
* Loads an empty puzzle
*
Expand All @@ -159,14 +182,20 @@ public void loadPuzzle(String game, int rows, int columns) throws RuntimeExcepti
Class<?> c = Class.forName(qualifiedClassName);
Constructor<?> cons = c.getConstructor();
Puzzle puzzle = (Puzzle) cons.newInstance();
setWindowTitle(puzzle.getName(), "New " + puzzle.getName() + " Puzzle");

PuzzleImporter importer = puzzle.getImporter();
if (importer == null) {
LOGGER.error("Puzzle importer is null");
throw new RuntimeException("Puzzle importer null");
}

// Theoretically, this exception should never be thrown, since LEGUP should not be
// allowing the user to give row/column input for a puzzle that doesn't support it
if (!importer.acceptsRowsAndColumnsInput()) {
throw new IllegalArgumentException(puzzle.getName() + " does not accept rows and columns input");
}

setWindowTitle(puzzle.getName(), "New " + puzzle.getName() + " Puzzle");
importer.initializePuzzle(rows, columns);

puzzle.initializeView();
Expand All @@ -183,6 +212,45 @@ public void loadPuzzle(String game, int rows, int columns) throws RuntimeExcepti
}
}

public void loadPuzzle(String game, String[] statements) {
String qualifiedClassName = config.getPuzzleClassForName(game);
LOGGER.debug("Loading " + qualifiedClassName);

try {
Class<?> c = Class.forName(qualifiedClassName);
Constructor<?> cons = c.getConstructor();
Puzzle puzzle = (Puzzle) cons.newInstance();

PuzzleImporter importer = puzzle.getImporter();
if (importer == null) {
LOGGER.error("Puzzle importer is null");
throw new RuntimeException("Puzzle importer null");
}

// Theoretically, this exception should never be thrown, since LEGUP should not be
// allowing the user to give text input for a puzzle that doesn't support it
if (!importer.acceptsTextInput()) {
throw new IllegalArgumentException(puzzle.getName() + " does not accept text input");
}

setWindowTitle(puzzle.getName(), "New " + puzzle.getName() + " Puzzle");
importer.initializePuzzle(statements);

puzzle.initializeView();
// puzzle.getBoardView().onTreeElementChanged(puzzle.getTree().getRootNode());
setPuzzleEditor(puzzle);
}
catch (IllegalArgumentException exception) {
throw new IllegalArgumentException(exception.getMessage());
}
catch (ClassNotFoundException | NoSuchMethodException | InvocationTargetException |
IllegalAccessException | InstantiationException e) {
LOGGER.error(e);
throw new RuntimeException("Puzzle creation error");
}

}

/**
* Loads a puzzle file
*
Expand Down
14 changes: 14 additions & 0 deletions src/main/java/edu/rpi/legup/model/Puzzle.java
Original file line number Diff line number Diff line change
Expand Up @@ -204,12 +204,26 @@ public boolean isValidDimensions(int rows, int columns) {
return rows > 0 && columns > 0;
}

/**
* Checks if the given array of statements is valid text input for the given puzzle
*
* @param statements
* @return
*/
public boolean isValidTextInput(String[] statements) {
return statements.length > 0;
}

/**
* Determines if the edu.rpi.legup.puzzle was solves correctly
*
* @return true if the board was solved correctly, false otherwise
*/
public boolean isPuzzleComplete() {
if (tree == null) {
return false;
}

boolean isComplete = tree.isValid();
if (isComplete) {
for (TreeElement leaf : tree.getLeafTreeElements()) {
Expand Down
1 change: 1 addition & 0 deletions src/main/java/edu/rpi/legup/model/PuzzleExporter.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ public abstract class PuzzleExporter {

/**
* PuzzleExporter Constructor exports the puzzle object to a file
*
* @param puzzle puzzle that is to be exported
*/
public PuzzleExporter(Puzzle puzzle) {
Expand Down
19 changes: 15 additions & 4 deletions src/main/java/edu/rpi/legup/model/PuzzleImporter.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,7 @@
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;

public abstract class PuzzleImporter {
private static final Logger LOGGER = LogManager.getLogger(PuzzleImporter.class.getName());
Expand All @@ -24,12 +21,17 @@ public abstract class PuzzleImporter {

/**
* PuzzleImporter Constructor creates the puzzle object
*
* @param puzzle puzzle that is imported
*/
public PuzzleImporter(Puzzle puzzle) {
this.puzzle = puzzle;
}

public abstract boolean acceptsRowsAndColumnsInput();

public abstract boolean acceptsTextInput();

/**
* Initializes an empty puzzle
*
Expand All @@ -46,6 +48,13 @@ public void initializePuzzle(int rows, int columns) throws RuntimeException {
}
}

public void initializePuzzle(String[] statements) throws InputMismatchException, IllegalArgumentException {
// Note: Error checking for the statements will be left up to the puzzles that support
// text input. For example, some puzzles may be okay with "blank" statements (Strings with
// length = 0) while others may not.
initializeBoard(statements);
}

/**
* Initializes the puzzle attributes
*
Expand Down Expand Up @@ -116,6 +125,8 @@ public void initializePuzzle(Node node) throws InvalidFileFormatException {
*/
public abstract void initializeBoard(Node node) throws InvalidFileFormatException;

public abstract void initializeBoard(String[] statements) throws UnsupportedOperationException, IllegalArgumentException;

/**
* Creates the proof for building
*
Expand Down
1 change: 1 addition & 0 deletions src/main/java/edu/rpi/legup/model/tree/Tree.java
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ public Set<TreeElement> getLeafTreeElements() {

/**
* Gets a Set of TreeNodes that are leaf nodes from the sub tree rooted at the specified node
*
* @param node node that is input
* @return Set of TreeNodes that are leaf nodes from the sub tree
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,16 @@ public BattleshipImporter(Battleship battleShip) {
super(battleShip);
}

@Override
public boolean acceptsRowsAndColumnsInput() {
return true;
}

@Override
public boolean acceptsTextInput() {
return false;
}

/**
* Creates an empty board for building
*
Expand Down Expand Up @@ -177,4 +187,9 @@ public void initializeBoard(Node node) throws InvalidFileFormatException {
"unknown value where integer expected");
}
}

@Override
public void initializeBoard(String[] statements) throws UnsupportedOperationException {
throw new UnsupportedOperationException("Battleship cannot accept text input");
}
}
15 changes: 15 additions & 0 deletions src/main/java/edu/rpi/legup/puzzle/fillapix/FillapixImporter.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,16 @@ public FillapixImporter(Fillapix fillapix) {
super(fillapix);
}

@Override
public boolean acceptsRowsAndColumnsInput() {
return true;
}

@Override
public boolean acceptsTextInput() {
return false;
}

/**
* Creates an empty board for building
*
Expand Down Expand Up @@ -88,4 +98,9 @@ public void initializeBoard(Node node) throws InvalidFileFormatException {
throw new InvalidFileFormatException("Fillapix Importer: unknown value where integer expected");
}
}

@Override
public void initializeBoard(String[] statements) throws UnsupportedOperationException {
throw new UnsupportedOperationException("Fillapix cannot accept text input");
}
}
15 changes: 15 additions & 0 deletions src/main/java/edu/rpi/legup/puzzle/heyawake/HeyawakeImporter.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,16 @@ public HeyawakeImporter(Heyawake heyawake) {
super(heyawake);
}

@Override
public boolean acceptsRowsAndColumnsInput() {
return true;
}

@Override
public boolean acceptsTextInput() {
return false;
}

/**
* Creates an empty board for building
*
Expand Down Expand Up @@ -91,4 +101,9 @@ public void initializeBoard(Node node) throws InvalidFileFormatException {
throw new InvalidFileFormatException("Heyawake Importer: unknown value where integer expected");
}
}

@Override
public void initializeBoard(String[] statements) throws UnsupportedOperationException {
throw new UnsupportedOperationException("Hey Awake cannot accept text input");
}
}
15 changes: 15 additions & 0 deletions src/main/java/edu/rpi/legup/puzzle/lightup/LightUpImporter.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,16 @@ public LightUpImporter(LightUp lightUp) {
super(lightUp);
}

@Override
public boolean acceptsRowsAndColumnsInput() {
return true;
}

@Override
public boolean acceptsTextInput() {
return false;
}

/**
* Creates an empty board for building
*
Expand Down Expand Up @@ -102,4 +112,9 @@ public void initializeBoard(Node node) throws InvalidFileFormatException {
throw new InvalidFileFormatException("lightup Importer: unknown value where integer expected");
}
}

@Override
public void initializeBoard(String[] statements) throws UnsupportedOperationException {
throw new UnsupportedOperationException("Light Up cannot accept text input");
}
}
15 changes: 15 additions & 0 deletions src/main/java/edu/rpi/legup/puzzle/masyu/MasyuImporter.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,16 @@ public MasyuImporter(Masyu masyu) {
super(masyu);
}

@Override
public boolean acceptsRowsAndColumnsInput() {
return true;
}

@Override
public boolean acceptsTextInput() {
return false;
}

/**
* Creates an empty board for building
*
Expand Down Expand Up @@ -90,4 +100,9 @@ public void initializeBoard(Node node) throws InvalidFileFormatException {
throw new InvalidFileFormatException("Masyu Importer: unknown value where integer expected");
}
}

@Override
public void initializeBoard(String[] statements) throws UnsupportedOperationException {
throw new UnsupportedOperationException("Masyu cannot accept text input");
}
}
Loading

0 comments on commit f3dbafb

Please sign in to comment.