Compare commits

..

5 Commits

Author SHA1 Message Date
Jonathan Turner
97ccd4d66b Finished commenting. 2024-02-11 22:00:07 -05:00
Jonathan Turner
22ffd96380 Implemented functionality to record number of nodes used. 2024-02-11 21:58:12 -05:00
Jonathan Turner
4753ba5aa9 Documented and Organized Code. 2024-02-11 21:57:52 -05:00
Jonathan Turner
76c66440d6 Added iteration counter to Solver.java 2024-02-11 21:34:34 -05:00
Jonathan Turner
29328c2288 Removed Files. 2024-02-11 21:32:51 -05:00
11 changed files with 231 additions and 116 deletions

View File

@ -1,7 +1,17 @@
package Assignments.A1; package Assignments.A1;
/**
* Launches the MainScene
*
* @author Jonathan Turner
* @version Spring 2024
*/
public class GUILauncher { public class GUILauncher {
/**
* Is used to prevent the issue of "missing javafx toolkit"
* @param args - the program args.
*/
public static void main(final String[] args) { public static void main(final String[] args) {
MainScene.main(args); MainScene.main(args);
} }

View File

@ -6,6 +6,12 @@ import javafx.scene.Parent;
import javafx.scene.Scene; import javafx.scene.Scene;
import javafx.stage.Stage; import javafx.stage.Stage;
/**
* The main Scene that is ran by GUILauncher to fix VM argument requirements.
*
* @author Jonathan Turner
* @version Spring 2024
*/
public class MainScene extends Application { public class MainScene extends Application {
@Override @Override

View File

@ -11,6 +11,16 @@ import Assignments.A1.models.BoardNode;
*/ */
public interface Solver { public interface Solver {
/**
* Returns the number of nodes from the previous iterations.
*
* @precondition none
* @postcondition none
*
* @return the number of nodes from the interation.
*/
int getNumOfNodes();
/** /**
* Solves for, finds and creates a spanning representing the solving pattern. * Solves for, finds and creates a spanning representing the solving pattern.
* *

View File

@ -17,6 +17,7 @@ public class DFS implements Solver {
/* Private Fields for Searching */ /* Private Fields for Searching */
private final Board solved = new Board(); private final Board solved = new Board();
private final List<String> tried = new ArrayList<>(); private final List<String> tried = new ArrayList<>();
private int numOfNodes = 1;
/** /**
* Traverses through a Board using a Stack, allowing for DFS LIFO. * Traverses through a Board using a Stack, allowing for DFS LIFO.
@ -33,7 +34,7 @@ public class DFS implements Solver {
BoardNode rootNode = new BoardNode(root, null); BoardNode rootNode = new BoardNode(root, null);
rootNode.depth = 0; rootNode.depth = 0;
stack.push(rootNode); stack.push(rootNode);
numOfNodes = 1;
while (!stack.isEmpty()) { while (!stack.isEmpty()) {
BoardNode current = stack.pop(); BoardNode current = stack.pop();
@ -54,8 +55,21 @@ public class DFS implements Solver {
childNode.depth = current.depth+1; childNode.depth = current.depth+1;
stack.push(childNode); stack.push(childNode);
current.addChild(childNode); current.addChild(childNode);
numOfNodes++;
} }
} }
return null; return null;
} }
/**
* Returns the number of nodes from the previous iterations.
*
* @precondition none
* @postcondition none
*
* @return the number of nodes from the interations.
*/
public int getNumOfNodes() {
return numOfNodes;
}
} }

View File

@ -10,23 +10,39 @@ import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.PriorityQueue; import java.util.PriorityQueue;
/**
* Used to traverse a Spanning Tree of 8 Puzzle using a provided comparitor for a Priority Queue.
*
* @author Jonathan Turner
* @version Spring 2024
*/
public class PriorityTraversal implements Solver { public class PriorityTraversal implements Solver {
private final Board solved = new Board(); private final Board solved = new Board();
private final HashSet<Board> visited = new HashSet<>(); private final HashSet<Board> visited = new HashSet<>();
private final Comparator<BoardNode> comparator; private final Comparator<BoardNode> comparator;
private int numOfNodes = 1;
public PriorityTraversal(Comparator<BoardNode> type) { public PriorityTraversal(Comparator<BoardNode> type) {
this.comparator = type; this.comparator = type;
} }
/**
* Traverses through the list using a priority queue which is specified by the comparitor at constructor.
*
* @precondition root != null
* @postcondition a spanning tree is created.
*
* @param root the first node/initial start.
* @return the solved leaf node.
*/
public BoardNode traverse(Board root) { public BoardNode traverse(Board root) {
visited.clear(); visited.clear();
PriorityQueue<BoardNode> boards = new PriorityQueue<>(comparator); PriorityQueue<BoardNode> boards = new PriorityQueue<>(comparator);
boards.add(new BoardNode(root, null)); boards.add(new BoardNode(root, null));
BoardNode node = null; BoardNode node = null;
Board current = new Board(root); Board current = new Board(root);
numOfNodes = 1;
while (!current.equals(solved) && !boards.isEmpty()) { while (!current.equals(solved) && !boards.isEmpty()) {
node = boards.poll(); node = boards.poll();
current = node.board; current = node.board;
@ -41,8 +57,22 @@ public class PriorityTraversal implements Solver {
BoardNode childNode = new BoardNode(child, node); BoardNode childNode = new BoardNode(child, node);
boards.add(childNode); boards.add(childNode);
node.addChild(childNode); node.addChild(childNode);
numOfNodes++;
} }
} }
return node; return node;
} }
/**
* Returns the number of nodes from the previous iterations.
*
* @precondition none
* @postcondition none
*
* @return the number of nodes from the interation.
*/
@Override
public int getNumOfNodes() {
return this.numOfNodes;
}
} }

View File

@ -6,6 +6,12 @@ import javafx.event.ActionEvent;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.scene.control.*; import javafx.scene.control.*;
/**
* Code Behind file for MainView.fxml
*
* @author Jonathan Turner
* @version Spring 2024
*/
public class BoardViewCodeBehind { public class BoardViewCodeBehind {
@FXML @FXML
@ -89,6 +95,11 @@ public class BoardViewCodeBehind {
this.viewModel.runPerformanceCheck(); this.viewModel.runPerformanceCheck();
} }
@FXML
void openPerformance(ActionEvent event) {
this.viewModel.openPerf();
}
public void onGenerateBoard(ActionEvent actionEvent) { public void onGenerateBoard(ActionEvent actionEvent) {
this.viewModel.generateBoard(); this.viewModel.generateBoard();
} }
@ -111,11 +122,6 @@ public class BoardViewCodeBehind {
} }
@FXML
void openPerformance(ActionEvent event) {
this.viewModel.openPerf();
}
public void onDFS(ActionEvent actionEvent) { public void onDFS(ActionEvent actionEvent) {
viewModel.setSelectedAlg("DFS"); viewModel.setSelectedAlg("DFS");
this.menu_alg.textProperty().set(this.menu_alg.getItems().get(0).textProperty().get()); this.menu_alg.textProperty().set(this.menu_alg.getItems().get(0).textProperty().get());

View File

@ -19,15 +19,14 @@ import java.util.Stack;
public class MainViewModel { public class MainViewModel {
/* Private Fields used to bind */ /* Private Fields used to bind */
private StringProperty currentBoardProperty, algSpeedProperty; private final StringProperty currentBoardProperty, algSpeedProperty, iterationCounter;
private StringProperty iterationCounter; private final BooleanProperty expanded, DFS, UCS, BFS, AStar, solvingAlgErr, genBoardErr, disclaimer, openPerf, runPerf;
private BooleanProperty expanded, DFS, UCS, BFS, AStar, solvingAlgErr, genBoardErr, disclaimer, openPerf, runPerf;
private BoardNode current = new BoardNode(new Board(), null); private BoardNode current = new BoardNode(new Board(), null);
private TreeItem<BoardNode> solvedRootNode = null; private TreeItem<BoardNode> solvedRootNode = null;
/* Private Fields used for traversing/creating nodes. */ /* Private Fields used for traversing/creating nodes. */
private BoardNode solvedRootBoardNode = null; private BoardNode solvedRootBoardNode = null;
private long[][] hasRanPerformance; private final long[][] hasRanPerformance;
private String selectedAlg; private String selectedAlg;
/** /**
@ -57,85 +56,24 @@ public class MainViewModel {
this.hasRanPerformance = new long[4][102]; this.hasRanPerformance = new long[4][102];
} }
/** /**
* Generates the board and sets the board on view to new board.
* *
* @precondition none
* @postcondition none
*/ */
public void runPerformanceCheck() {
Solver solver = null;
int alg = -1;
if (this.selectedAlg.equals("DFS") && this.hasRanPerformance[0][0] == 0) {
solver = new DFS();
alg = 0;
} else if (this.selectedAlg.equals("UCS") && this.hasRanPerformance[1][0] == 0) {
solver = new PriorityTraversal(new UCS());
alg = 1;
} else if (this.selectedAlg.equals("BFS") && this.hasRanPerformance[2][0] == 0) {
solver = new PriorityTraversal(new BFS());
alg = 2;
} else if (this.selectedAlg.equals("AStar") && this.hasRanPerformance[3][0] == 0) {
solver = new PriorityTraversal(new AStar());
alg = 3;
}
if (solver != null) {
for (int i = 0; i < 100; i++) {
Board board = BoardGenerator.generateBoard();
System.out.println(board);
long start = new Date().getTime();
BoardNode node = solver.traverse(board);
long end = new Date().getTime();
System.out.println(node.board + "\n");
if (node != null) {
this.hasRanPerformance[alg][i + 2] = end - start;
this.currentBoardProperty.setValue(node.board.toString());
} else {
this.hasRanPerformance[alg][i+2] = -1;
}
iterationCounter.setValue("Performing Analysis Iteration: " + (i+1) + "/100");
}
this.hasRanPerformance[alg][0] = 1;
this.runPerf.setValue(false);
this.openPerf.setValue(true);
}
for (int i = 1; i < this.hasRanPerformance[alg].length; i++) {
System.out.println(this.hasRanPerformance[alg][i]);
}
}
public void setSelectedAlg(String value) {
this.selectedAlg = value;
this.DFS.set(value.equals("DFS"));
this.UCS.set(value.equals("UCS"));
this.BFS.set(value.equals("BFS"));
this.AStar.set(value.equals("AStar"));
this.disclaimer.setValue(value.equals("DFS"));
this.openPerf.setValue(this.hasRanPerformance[convertValueToInt(value)][0] == 1);
this.runPerf.setValue(this.hasRanPerformance[convertValueToInt(value)][0] == 0);
if (this.hasRanPerformance[convertValueToInt(value)][0] == 0) {
this.iterationCounter.set("");
}
}
private int convertValueToInt(String value) {
if (value.equals("DFS")) return 0;
if (value.equals("UCS")) return 1;
if (value.equals("BFS")) return 2;
return 3;
}
public StringProperty getCurrentBoardProperty() {
return this.currentBoardProperty;
}
public void generateBoard() { public void generateBoard() {
this.current = new BoardNode(BoardGenerator.generateBoard(), null); this.current = new BoardNode(BoardGenerator.generateBoard(), null);
currentBoardProperty.set(this.current.board.toString()); currentBoardProperty.set(this.current.board.toString());
} }
/**
* Solves the current board by checking for which alg is selected, then will solve that board
* with the given alg that implements the Solver interface.
*
* @precondition menuItem != null && (board != solver || board != null)
* @postcondition the board is solved.
*/
public void solveBoard() { public void solveBoard() {
if (selectedAlg == null || selectedAlg.isEmpty()) { if (selectedAlg == null || selectedAlg.isEmpty()) {
this.solvingAlgErr.setValue(true); this.solvingAlgErr.setValue(true);
@ -175,6 +113,88 @@ public class MainViewModel {
this.current = solved; this.current = solved;
} }
/**
* Sets the values of the data using the View's Property files and Bindings.
*
* @precondition none
* @postcondition none
*
* @param value the menu item value.
*/
public void setSelectedAlg(String value) {
this.selectedAlg = value;
this.DFS.set(value.equals("DFS"));
this.UCS.set(value.equals("UCS"));
this.BFS.set(value.equals("BFS"));
this.AStar.set(value.equals("AStar"));
this.disclaimer.setValue(value.equals("DFS"));
this.openPerf.setValue(this.hasRanPerformance[convertValueToInt(value)][0] == 1);
this.runPerf.setValue(this.hasRanPerformance[convertValueToInt(value)][0] == 0);
if (this.hasRanPerformance[convertValueToInt(value)][0] == 0) {
this.iterationCounter.set("");
}
}
/**
* Runs through the selected algorithm and will run it 100 times. It will collect data from these runs
* and store them. It will then allow you to view the data in a new windows and the button will appear.
*
* @precondition none
* @postcondition the performance is taken.
*/
public void runPerformanceCheck() {
Solver solver = null;
int alg = -1;
if (this.selectedAlg.equals("DFS") && this.hasRanPerformance[0][0] == 0) {
solver = new DFS();
alg = 0;
} else if (this.selectedAlg.equals("UCS") && this.hasRanPerformance[1][0] == 0) {
solver = new PriorityTraversal(new UCS());
alg = 1;
} else if (this.selectedAlg.equals("BFS") && this.hasRanPerformance[2][0] == 0) {
solver = new PriorityTraversal(new BFS());
alg = 2;
} else if (this.selectedAlg.equals("AStar") && this.hasRanPerformance[3][0] == 0) {
solver = new PriorityTraversal(new AStar());
alg = 3;
}
int averageNodes = 0;
if (solver != null) {
for (int i = 0; i < 100; i++) {
Board board = BoardGenerator.generateBoard();
System.out.println(board);
long start = new Date().getTime();
BoardNode node = solver.traverse(board);
long end = new Date().getTime();
System.out.println(node.board + "\n");
if (node != null) {
this.hasRanPerformance[alg][i + 2] = end - start;
this.currentBoardProperty.setValue(node.board.toString());
averageNodes += solver.getNumOfNodes();
updateDisplay();
} else {
this.hasRanPerformance[alg][i+2] = -1;
}
iterationCounter.setValue("Performing Analysis Iteration: " + (i+1) + "/100");
}
this.hasRanPerformance[alg][0] = 1;
this.hasRanPerformance[alg][1] = averageNodes;
this.runPerf.setValue(false);
this.openPerf.setValue(true);
}
for (int i = 1; i < this.hasRanPerformance[alg].length; i++) {
System.out.println(this.hasRanPerformance[alg][i]);
}
}
/**
* Opens the performance files that were previously generated. Is only visible when performance is already generated.
*
* @precondition performance == generated
* @postcondition performance is displayed in Alert.
*/
public void openPerf() { public void openPerf() {
long totalTime = 0; long totalTime = 0;
int success = 0; int success = 0;
@ -201,52 +221,26 @@ public class MainViewModel {
perf.setHeaderText(success + "/" + 100 + " Succeeded."); perf.setHeaderText(success + "/" + 100 + " Succeeded.");
String results = "Shortest Run: " + shortest + "ms\n" + String results = "Shortest Run: " + shortest + "ms\n" +
"Longest Run: " + longest + "ms\n" + "Longest Run: " + longest + "ms\n" +
"Average Time: " + average + "ms"; "Average Time: " + average + "ms" + "\n" +
"Average Nodes: " + (this.hasRanPerformance[convertValueToInt(this.selectedAlg)][1]/success);
perf.setContentText(results); perf.setContentText(results);
perf.show(); perf.show();
} }
/**
* Is used to update the display with the current board.
*
* @precondition none
* @postcondition the dispaly is updated.
*/
public void updateDisplay() { public void updateDisplay() {
TreeItem<BoardNode> newRoot = null; TreeItem<BoardNode> newRoot = null;
newRoot = this.rebuildTree(this.solvedRootBoardNode, this.expanded.getValue()); newRoot = this.rebuildTree(this.solvedRootBoardNode, this.expanded.getValue());
this.solvedRootNode = newRoot; this.solvedRootNode = newRoot;
} }
private TreeItem<BoardNode> rebuildTree(BoardNode root, boolean expanded) {
if (this.selectedAlg != null) {
if (this.selectedAlg.equals("DFS")) {
Stack<BoardNode> generations = new Stack<>();
BoardNode temp = this.current;
while (temp != null) {
generations.push(temp);
temp = temp.parent;
}
TreeItem<BoardNode> rootItem = new TreeItem<>(root);
TreeItem<BoardNode> currItem = rootItem;
while (!generations.isEmpty()) {
TreeItem<BoardNode> child = new TreeItem<>(generations.pop());
currItem.getChildren().add(child);
currItem.setExpanded(expanded);
currItem = child;
}
return rootItem;
} else {
TreeItem<BoardNode> treeItem = new TreeItem<>(root);
for (BoardNode child : root.children) {
TreeItem<BoardNode> childItem = rebuildTree(child, expanded);
treeItem.getChildren().add(childItem);
}
treeItem.setExpanded(expanded);
return treeItem;
}
}
return new TreeItem<>();
}
/* Getters for bindings */ /* Getters for bindings */
public TreeItem<BoardNode> getSolvedRootNode() { public TreeItem<BoardNode> getSolvedRootNode() {
return solvedRootNode; return solvedRootNode;
} }
@ -306,4 +300,49 @@ public class MainViewModel {
public BooleanProperty runPerfProperty() { public BooleanProperty runPerfProperty() {
return runPerf; return runPerf;
} }
public StringProperty getCurrentBoardProperty() {
return this.currentBoardProperty;
}
/* End of Public Methods. Private Fields Only */
private TreeItem<BoardNode> rebuildTree(BoardNode root, boolean expanded) {
if (this.selectedAlg != null) {
if (this.selectedAlg.equals("DFS")) {
Stack<BoardNode> generations = new Stack<>();
BoardNode temp = this.current;
while (temp != null) {
generations.push(temp);
temp = temp.parent;
}
TreeItem<BoardNode> rootItem = new TreeItem<>(root);
TreeItem<BoardNode> currItem = rootItem;
while (!generations.isEmpty()) {
TreeItem<BoardNode> child = new TreeItem<>(generations.pop());
currItem.getChildren().add(child);
currItem.setExpanded(expanded);
currItem = child;
}
return rootItem;
} else {
TreeItem<BoardNode> treeItem = new TreeItem<>(root);
for (BoardNode child : root.children) {
TreeItem<BoardNode> childItem = rebuildTree(child, expanded);
treeItem.getChildren().add(childItem);
}
treeItem.setExpanded(expanded);
return treeItem;
}
}
return new TreeItem<>();
}
private int convertValueToInt(String value) {
if (value.equals("DFS")) return 0;
if (value.equals("UCS")) return 1;
if (value.equals("BFS")) return 2;
return 3;
}
} }