From 21849c65554568427e3304c3767b48c6a90641ea Mon Sep 17 00:00:00 2001 From: JBobda Date: Wed, 24 Oct 2018 20:49:29 -0500 Subject: [PATCH] I got rid of some of the unused imports, and I also added a selection sort method to the sort class to make the find lowest F cost method more efficient. I should have probably just fixed your quicksort method... but I didn't know that off the top of my head so I just went with selection sort. Lel. Also... 8 space tabs? --- .gitignore | 5 + src/APathfinding.java | 1120 ++++++++++++++++++++--------------------- src/Frame.java | 1059 +++++++++++++++++++------------------- src/Sort.java | 309 +++++++----- 4 files changed, 1274 insertions(+), 1219 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..21e74cb --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +/nbproject/ +/build/ +/build.xml +/manifest.mf + diff --git a/src/APathfinding.java b/src/APathfinding.java index efc50c0..5342179 100644 --- a/src/APathfinding.java +++ b/src/APathfinding.java @@ -1,560 +1,560 @@ -import java.util.ArrayList; - -public class APathfinding { - private int size, diagonalMoveCost; - private long runTime; - private double kValue; - private Frame frame; - private Node startNode, endNode, par; - private boolean diagonal, running, noPath, complete, trig; - private ArrayList borders, open, closed, path; - private Sort sort = new Sort(); - - public APathfinding(int size) { - this.size = size; - - diagonalMoveCost = (int) (Math.sqrt(2 * (Math.pow(size, 2)))); - kValue = Math.PI / 2; - diagonal = true; - trig = false; - running = false; - complete = false; - - borders = new ArrayList(); - open = new ArrayList(); - closed = new ArrayList(); - path = new ArrayList(); - } - - public APathfinding(Frame frame, int size) { - this.frame = frame; - this.size = size; - - diagonalMoveCost = (int) (Math.sqrt(2 * (Math.pow(size, 2)))); - kValue = Math.PI / 2; - diagonal = true; - trig = false; - running = false; - complete = false; - - borders = new ArrayList(); - open = new ArrayList(); - closed = new ArrayList(); - path = new ArrayList(); - } - - public APathfinding(Frame frame, int size, Node start, Node end) { - this.frame = frame; - this.size = size; - startNode = start; - endNode = end; - - diagonalMoveCost = (int) (Math.sqrt(2 * (Math.pow(size, 2)))); - diagonal = true; - trig = false; - running = false; - complete = false; - - borders = new ArrayList(); - open = new ArrayList(); - closed = new ArrayList(); - path = new ArrayList(); - } - - public void start(Node s, Node e) { - running = true; - startNode = s; - startNode.setG(0); - endNode = e; - - // Adding the starting node to the closed list - addClosed(startNode); - - long startTime = System.currentTimeMillis(); - - findPath(startNode); - - complete = true; - long endTime = System.currentTimeMillis(); - runTime = endTime - startTime; - System.out.println("Completed: " + runTime + "ms"); - } - - public void setup(Node s, Node e) { - running = true; - startNode = s; - startNode.setG(0); - par = startNode; - endNode = e; - - // Adding the starting node to the closed list - addClosed(startNode); - } - - public void setStart(Node s) { - startNode = s; - startNode.setG(0); - } - - public void setEnd(Node e) { - endNode = e; - } - - public boolean isRunning() { - return running; - } - - public boolean isComplete() { - return complete; - } - - public Node getStart() { - return startNode; - } - - public Node getEnd() { - return endNode; - } - - public Node getPar() { - return par; - } - - public boolean isNoPath() { - return noPath; - } - - public boolean isDiagonal() { - return diagonal; - } - - public boolean isTrig() { - return trig; - } - - public void setDiagonal(boolean d) { - diagonal = d; - } - - public void setTrig(boolean t) { - trig = t; - } - - public void setSize(int s) { - size = s; - diagonalMoveCost = (int) (Math.sqrt(2 * (Math.pow(size, 2)))); - } - - public void findPath(Node parent) { - Node openNode = null; - - if (diagonal) { - // Detects and adds one step of nodes to open list - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 3; j++) { - if (i == 1 && j == 1) { - continue; - } - int possibleX = (parent.getX() - size) + (size * i); - int possibleY = (parent.getY() - size) + (size * j); - - // Possible coordinates of borders - // Using (crossBorderX, parent.getY()) - // and (parent.getX(), crossBorderY()) - // To see if there are borders in the way - int crossBorderX = parent.getX() + (possibleX - parent.getX()); - int crossBorderY = parent.getY() + (possibleY - parent.getY()); - - // Disables ability to cut corners around borders - if (searchBorder(crossBorderX, parent.getY()) != -1 - | searchBorder(parent.getX(), crossBorderY) != -1 && ((j == 0 | j == 2) && i != 1)) { - continue; - } - - calculateNodeValues(possibleX, possibleY, openNode, parent); - } - } - } - else if (!trig) { - // Detects and adds one step of nodes to open list - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 3; j++) { - if((i == 0 && j == 0) || (i == 0 && j == 2) || - (i == 1 && j == 1) || (i == 2 && j == 0) || - (i == 2 && j == 2)) { - continue; - } - int possibleX = (parent.getX() - size) + (size * i); - int possibleY = (parent.getY() - size) + (size * j); - - calculateNodeValues(possibleX, possibleY, openNode, parent); - } - } - } - else { - for (int i = 0; i < 4; i++) { - // Uses cosine and sine functions to get circle of points - // around parent - int possibleX = (int) Math.round(parent.getX() + (-size * Math.cos(kValue * i))); - int possibleY = (int) Math.round(parent.getY() + (-size * Math.sin(kValue * i))); - - calculateNodeValues(possibleX, possibleY, openNode, parent); - } - } - // frame.repaint(); - - // Set the new parent node - parent = lowestFCost(); - - if (parent == null) { - System.out.println("END> NO PATH"); - noPath = true; - running = false; - frame.repaint(); - return; - } - - if (Node.isEqual(parent, endNode)) { - endNode.setParent(parent.getParent()); - - connectPath(); - running = false; - complete = true; - frame.repaint(); - return; - } - - // Remove parent node from open list - removeOpen(parent); - // Add parent node to closed list - addClosed(parent); - - // Allows correction for shortest path during runtime - // When new parent Node is selected.. Checks all adjacent open - // Nodes.. Then checks if the (G Score of parent + open Node - // distance from parent) is less than the current G score - // of the open node.. If true.. Sets parent of open Node - // as new parent.. and re-calculates G, and F values - if (diagonal) { - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 3; j++) { - if (i == 1 && j == 1) { - continue; - } - int possibleX = (parent.getX() - size) + (size * i); - int possibleY = (parent.getY() - size) + (size * j); - Node openCheck = getOpenNode(possibleX, possibleY); - - // If spot being looked at, is an open node - if (openCheck != null) { - int distanceX = parent.getX() - openCheck.getX(); - int distanceY = parent.getY() - openCheck.getY(); - int newG = parent.getG(); - - if (distanceX != 0 && distanceY != 0) { - newG += diagonalMoveCost; - } else { - newG += size; - } - - if (newG < openCheck.getG()) { - int s = searchOpen(possibleX, possibleY); - open.get(s).setParent(parent); - open.get(s).setG(newG); - open.get(s).setF(open.get(s).getG() + open.get(s).getH()); - } - } - } - } - } - if(!frame.showSteps()) { - findPath(parent); - } - else { - par = parent; - } - } - - public void calculateNodeValues(int possibleX, int possibleY, Node openNode, Node parent) { - // If the coordinates are outside of the borders - if (possibleX < 0 | possibleY < 0 | possibleX >= frame.getWidth() | possibleY >= frame.getHeight()) { - return; - } - - // If the node is already a border node or a closed node or an - // already open node, then don't make open node - if (searchBorder(possibleX, possibleY) != -1 | searchClosed(possibleX, possibleY) != -1 - | searchOpen(possibleX, possibleY) != -1) { - return; - } - // Create an open node with the available x and y - // coordinates - openNode = new Node(possibleX, possibleY); - - // Set the parent of the open node - openNode.setParent(parent); - - // Calculating G cost - // Cost to move from parent node to one open node (x - // and - // y - // separately) - int GxMoveCost = openNode.getX() - parent.getX(); - int GyMoveCost = openNode.getY() - parent.getY(); - int gCost = parent.getG(); - - if (GxMoveCost != 0 && GyMoveCost != 0) { - gCost += diagonalMoveCost; - } else { - gCost += size; - } - openNode.setG(gCost); - - // Calculating H Cost - int HxDiff = Math.abs(endNode.getX() - openNode.getX()); - int HyDiff = Math.abs(endNode.getY() - openNode.getY()); - int hCost = HxDiff + HyDiff; - openNode.setH(hCost); - - // Calculating F Cost - int fCost = gCost + hCost; - openNode.setF(fCost); - - addOpen(openNode); - } - - public void connectPath() { - if (getPathList().size() == 0) { - Node parentNode = endNode.getParent(); - - while (!Node.isEqual(parentNode, startNode)) { - addPath(parentNode); - - for (int i = 0; i < getClosedList().size(); i++) { - Node current = getClosedList().get(i); - - if (Node.isEqual(current, parentNode)) { - parentNode = current.getParent(); - break; - } - } - } - reverse(getPathList()); - } - - } - - public void addBorder(Node node) { - if (borders.size() == 0) { - borders.add(node); - } else if (!checkBorderDuplicate(node)) { - borders.add(node); - } - } - - public void addOpen(Node node) { - if (open.size() == 0) { - open.add(node); - } else if (!checkOpenDuplicate(node)) { - open.add(node); - } - } - - public void addClosed(Node node) { - if (closed.size() == 0) { - closed.add(node); - } else if (!checkClosedDuplicate(node)) { - closed.add(node); - } - } - - public void addPath(Node node) { - if (path.size() == 0) { - path.add(node); - } else { - path.add(node); - } - } - - public void removePath(int location) { - path.remove(location); - } - - public void removeBorder(int location) { - borders.remove(location); - } - - public void removeOpen(int location) { - open.remove(location); - } - - public void removeOpen(Node node) { - for (int i = 0; i < open.size(); i++) { - if (node.getX() == open.get(i).getX() && node.getY() == open.get(i).getY()) { - open.remove(i); - } - } - } - - public void removeClosed(int location) { - closed.remove(location); - } - - public boolean checkBorderDuplicate(Node node) { - for (int i = 0; i < borders.size(); i++) { - if (node.getX() == borders.get(i).getX() && node.getY() == borders.get(i).getY()) { - return true; - } - } - return false; - } - - public boolean checkOpenDuplicate(Node node) { - for (int i = 0; i < open.size(); i++) { - if (node.getX() == open.get(i).getX() && node.getY() == open.get(i).getY()) { - return true; - } - } - return false; - } - - public boolean checkClosedDuplicate(Node node) { - for (int i = 0; i < closed.size(); i++) { - if (node.getX() == closed.get(i).getX() && node.getY() == closed.get(i).getY()) { - return true; - } - } - return false; - } - - public int searchBorder(int xSearch, int ySearch) { - int Location = -1; - - for (int i = 0; i < borders.size(); i++) { - if (borders.get(i).getX() == xSearch && borders.get(i).getY() == ySearch) { - Location = i; - break; - } - } - return Location; - } - - public int searchClosed(int xSearch, int ySearch) { - int Location = -1; - - for (int i = 0; i < closed.size(); i++) { - if (closed.get(i).getX() == xSearch && closed.get(i).getY() == ySearch) { - Location = i; - break; - } - } - return Location; - } - - public int searchOpen(int xSearch, int ySearch) { - int Location = -1; - - for (int i = 0; i < open.size(); i++) { - if (open.get(i).getX() == xSearch && open.get(i).getY() == ySearch) { - Location = i; - break; - } - } - return Location; - } - - public void reverse(ArrayList list) { - int j = list.size() - 1; - - for (int i = 0; i < j; i++) { - Object temp = list.get(i); - list.remove(i); - list.add(i, list.get(j - 1)); - list.remove(j); - list.add(j, temp); - j--; - } - } - - public Node lowestFCost() { - if (open.size() > 0) { - sort.bubbleSort(open); - return open.get(0); - } - return null; - } - - public ArrayList getBorderList() { - return borders; - } - - public ArrayList getOpenList() { - return open; - } - - public Node getOpen(int location) { - return open.get(location); - } - - public ArrayList getClosedList() { - return closed; - } - - public ArrayList getPathList() { - return path; - } - - public long getRunTime() { - return runTime; - } - - public void reset() { - while(open.size() > 0) { - open.remove(0); - } - - while(closed.size() > 0) { - closed.remove(0); - } - - while(path.size() > 0) { - path.remove(0); - } - noPath = false; - running = false; - complete = false; - } - - public Node getOpenNode(int x, int y) { - for (int i = 0; i < open.size(); i++) { - if (open.get(i).getX() == x && open.get(i).getY() == y) { - return open.get(i); - } - } - return null; - } - - public void printBorderList() { - for (int i = 0; i < borders.size(); i++) { - System.out.print(borders.get(i).getX() + ", " + borders.get(i).getY()); - System.out.println(); - } - System.out.println("==============="); - } - - public void printOpenList() { - for (int i = 0; i < open.size(); i++) { - System.out.print(open.get(i).getX() + ", " + open.get(i).getY()); - System.out.println(); - } - System.out.println("==============="); - } - - public void printPathList() { - for (int i = 0; i < path.size(); i++) { - System.out.print(i + ": " + path.get(i).getX() + ", " + path.get(i).getY() + ": " + path.get(i).getF()); - System.out.println(); - } - System.out.println("==============="); - } -} +import java.util.ArrayList; + +public class APathfinding { + private int size, diagonalMoveCost; + private long runTime; + private double kValue; + private Frame frame; + private Node startNode, endNode, par; + private boolean diagonal, running, noPath, complete, trig; + private ArrayList borders, open, closed, path; + private Sort sort = new Sort(); + + public APathfinding(int size) { + this.size = size; + + diagonalMoveCost = (int) (Math.sqrt(2 * (Math.pow(size, 2)))); + kValue = Math.PI / 2; + diagonal = true; + trig = false; + running = false; + complete = false; + + borders = new ArrayList(); + open = new ArrayList(); + closed = new ArrayList(); + path = new ArrayList(); + } + + public APathfinding(Frame frame, int size) { + this.frame = frame; + this.size = size; + + diagonalMoveCost = (int) (Math.sqrt(2 * (Math.pow(size, 2)))); + kValue = Math.PI / 2; + diagonal = true; + trig = false; + running = false; + complete = false; + + borders = new ArrayList(); + open = new ArrayList(); + closed = new ArrayList(); + path = new ArrayList(); + } + + public APathfinding(Frame frame, int size, Node start, Node end) { + this.frame = frame; + this.size = size; + startNode = start; + endNode = end; + + diagonalMoveCost = (int) (Math.sqrt(2 * (Math.pow(size, 2)))); + diagonal = true; + trig = false; + running = false; + complete = false; + + borders = new ArrayList(); + open = new ArrayList(); + closed = new ArrayList(); + path = new ArrayList(); + } + + public void start(Node s, Node e) { + running = true; + startNode = s; + startNode.setG(0); + endNode = e; + + // Adding the starting node to the closed list + addClosed(startNode); + + long startTime = System.currentTimeMillis(); + + findPath(startNode); + + complete = true; + long endTime = System.currentTimeMillis(); + runTime = endTime - startTime; + System.out.println("Completed: " + runTime + "ms"); + } + + public void setup(Node s, Node e) { + running = true; + startNode = s; + startNode.setG(0); + par = startNode; + endNode = e; + + // Adding the starting node to the closed list + addClosed(startNode); + } + + public void setStart(Node s) { + startNode = s; + startNode.setG(0); + } + + public void setEnd(Node e) { + endNode = e; + } + + public boolean isRunning() { + return running; + } + + public boolean isComplete() { + return complete; + } + + public Node getStart() { + return startNode; + } + + public Node getEnd() { + return endNode; + } + + public Node getPar() { + return par; + } + + public boolean isNoPath() { + return noPath; + } + + public boolean isDiagonal() { + return diagonal; + } + + public boolean isTrig() { + return trig; + } + + public void setDiagonal(boolean d) { + diagonal = d; + } + + public void setTrig(boolean t) { + trig = t; + } + + public void setSize(int s) { + size = s; + diagonalMoveCost = (int) (Math.sqrt(2 * (Math.pow(size, 2)))); + } + + public void findPath(Node parent) { + Node openNode = null; + + if (diagonal) { + // Detects and adds one step of nodes to open list + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + if (i == 1 && j == 1) { + continue; + } + int possibleX = (parent.getX() - size) + (size * i); + int possibleY = (parent.getY() - size) + (size * j); + + // Possible coordinates of borders + // Using (crossBorderX, parent.getY()) + // and (parent.getX(), crossBorderY()) + // To see if there are borders in the way + int crossBorderX = parent.getX() + (possibleX - parent.getX()); + int crossBorderY = parent.getY() + (possibleY - parent.getY()); + + // Disables ability to cut corners around borders + if (searchBorder(crossBorderX, parent.getY()) != -1 + | searchBorder(parent.getX(), crossBorderY) != -1 && ((j == 0 | j == 2) && i != 1)) { + continue; + } + + calculateNodeValues(possibleX, possibleY, openNode, parent); + } + } + } + else if (!trig) { + // Detects and adds one step of nodes to open list + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + if((i == 0 && j == 0) || (i == 0 && j == 2) || + (i == 1 && j == 1) || (i == 2 && j == 0) || + (i == 2 && j == 2)) { + continue; + } + int possibleX = (parent.getX() - size) + (size * i); + int possibleY = (parent.getY() - size) + (size * j); + + calculateNodeValues(possibleX, possibleY, openNode, parent); + } + } + } + else { + for (int i = 0; i < 4; i++) { + // Uses cosine and sine functions to get circle of points + // around parent + int possibleX = (int) Math.round(parent.getX() + (-size * Math.cos(kValue * i))); + int possibleY = (int) Math.round(parent.getY() + (-size * Math.sin(kValue * i))); + + calculateNodeValues(possibleX, possibleY, openNode, parent); + } + } + // frame.repaint(); + + // Set the new parent node + parent = lowestFCost(); + + if (parent == null) { + System.out.println("END> NO PATH"); + noPath = true; + running = false; + frame.repaint(); + return; + } + + if (Node.isEqual(parent, endNode)) { + endNode.setParent(parent.getParent()); + + connectPath(); + running = false; + complete = true; + frame.repaint(); + return; + } + + // Remove parent node from open list + removeOpen(parent); + // Add parent node to closed list + addClosed(parent); + + // Allows correction for shortest path during runtime + // When new parent Node is selected.. Checks all adjacent open + // Nodes.. Then checks if the (G Score of parent + open Node + // distance from parent) is less than the current G score + // of the open node.. If true.. Sets parent of open Node + // as new parent.. and re-calculates G, and F values + if (diagonal) { + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + if (i == 1 && j == 1) { + continue; + } + int possibleX = (parent.getX() - size) + (size * i); + int possibleY = (parent.getY() - size) + (size * j); + Node openCheck = getOpenNode(possibleX, possibleY); + + // If spot being looked at, is an open node + if (openCheck != null) { + int distanceX = parent.getX() - openCheck.getX(); + int distanceY = parent.getY() - openCheck.getY(); + int newG = parent.getG(); + + if (distanceX != 0 && distanceY != 0) { + newG += diagonalMoveCost; + } else { + newG += size; + } + + if (newG < openCheck.getG()) { + int s = searchOpen(possibleX, possibleY); + open.get(s).setParent(parent); + open.get(s).setG(newG); + open.get(s).setF(open.get(s).getG() + open.get(s).getH()); + } + } + } + } + } + if(!frame.showSteps()) { + findPath(parent); + } + else { + par = parent; + } + } + + public void calculateNodeValues(int possibleX, int possibleY, Node openNode, Node parent) { + // If the coordinates are outside of the borders + if (possibleX < 0 | possibleY < 0 | possibleX >= frame.getWidth() | possibleY >= frame.getHeight()) { + return; + } + + // If the node is already a border node or a closed node or an + // already open node, then don't make open node + if (searchBorder(possibleX, possibleY) != -1 | searchClosed(possibleX, possibleY) != -1 + | searchOpen(possibleX, possibleY) != -1) { + return; + } + // Create an open node with the available x and y + // coordinates + openNode = new Node(possibleX, possibleY); + + // Set the parent of the open node + openNode.setParent(parent); + + // Calculating G cost + // Cost to move from parent node to one open node (x + // and + // y + // separately) + int GxMoveCost = openNode.getX() - parent.getX(); + int GyMoveCost = openNode.getY() - parent.getY(); + int gCost = parent.getG(); + + if (GxMoveCost != 0 && GyMoveCost != 0) { + gCost += diagonalMoveCost; + } else { + gCost += size; + } + openNode.setG(gCost); + + // Calculating H Cost + int HxDiff = Math.abs(endNode.getX() - openNode.getX()); + int HyDiff = Math.abs(endNode.getY() - openNode.getY()); + int hCost = HxDiff + HyDiff; + openNode.setH(hCost); + + // Calculating F Cost + int fCost = gCost + hCost; + openNode.setF(fCost); + + addOpen(openNode); + } + + public void connectPath() { + if (getPathList().size() == 0) { + Node parentNode = endNode.getParent(); + + while (!Node.isEqual(parentNode, startNode)) { + addPath(parentNode); + + for (int i = 0; i < getClosedList().size(); i++) { + Node current = getClosedList().get(i); + + if (Node.isEqual(current, parentNode)) { + parentNode = current.getParent(); + break; + } + } + } + reverse(getPathList()); + } + + } + + public void addBorder(Node node) { + if (borders.size() == 0) { + borders.add(node); + } else if (!checkBorderDuplicate(node)) { + borders.add(node); + } + } + + public void addOpen(Node node) { + if (open.size() == 0) { + open.add(node); + } else if (!checkOpenDuplicate(node)) { + open.add(node); + } + } + + public void addClosed(Node node) { + if (closed.size() == 0) { + closed.add(node); + } else if (!checkClosedDuplicate(node)) { + closed.add(node); + } + } + + public void addPath(Node node) { + if (path.size() == 0) { + path.add(node); + } else { + path.add(node); + } + } + + public void removePath(int location) { + path.remove(location); + } + + public void removeBorder(int location) { + borders.remove(location); + } + + public void removeOpen(int location) { + open.remove(location); + } + + public void removeOpen(Node node) { + for (int i = 0; i < open.size(); i++) { + if (node.getX() == open.get(i).getX() && node.getY() == open.get(i).getY()) { + open.remove(i); + } + } + } + + public void removeClosed(int location) { + closed.remove(location); + } + + public boolean checkBorderDuplicate(Node node) { + for (int i = 0; i < borders.size(); i++) { + if (node.getX() == borders.get(i).getX() && node.getY() == borders.get(i).getY()) { + return true; + } + } + return false; + } + + public boolean checkOpenDuplicate(Node node) { + for (int i = 0; i < open.size(); i++) { + if (node.getX() == open.get(i).getX() && node.getY() == open.get(i).getY()) { + return true; + } + } + return false; + } + + public boolean checkClosedDuplicate(Node node) { + for (int i = 0; i < closed.size(); i++) { + if (node.getX() == closed.get(i).getX() && node.getY() == closed.get(i).getY()) { + return true; + } + } + return false; + } + + public int searchBorder(int xSearch, int ySearch) { + int Location = -1; + + for (int i = 0; i < borders.size(); i++) { + if (borders.get(i).getX() == xSearch && borders.get(i).getY() == ySearch) { + Location = i; + break; + } + } + return Location; + } + + public int searchClosed(int xSearch, int ySearch) { + int Location = -1; + + for (int i = 0; i < closed.size(); i++) { + if (closed.get(i).getX() == xSearch && closed.get(i).getY() == ySearch) { + Location = i; + break; + } + } + return Location; + } + + public int searchOpen(int xSearch, int ySearch) { + int Location = -1; + + for (int i = 0; i < open.size(); i++) { + if (open.get(i).getX() == xSearch && open.get(i).getY() == ySearch) { + Location = i; + break; + } + } + return Location; + } + + public void reverse(ArrayList list) { + int j = list.size() - 1; + + for (int i = 0; i < j; i++) { + Object temp = list.get(i); + list.remove(i); + list.add(i, list.get(j - 1)); + list.remove(j); + list.add(j, temp); + j--; + } + } + + public Node lowestFCost() { + if (open.size() > 0) { + sort.selectionSort(open); + return open.get(0); + } + return null; + } + + public ArrayList getBorderList() { + return borders; + } + + public ArrayList getOpenList() { + return open; + } + + public Node getOpen(int location) { + return open.get(location); + } + + public ArrayList getClosedList() { + return closed; + } + + public ArrayList getPathList() { + return path; + } + + public long getRunTime() { + return runTime; + } + + public void reset() { + while(open.size() > 0) { + open.remove(0); + } + + while(closed.size() > 0) { + closed.remove(0); + } + + while(path.size() > 0) { + path.remove(0); + } + noPath = false; + running = false; + complete = false; + } + + public Node getOpenNode(int x, int y) { + for (int i = 0; i < open.size(); i++) { + if (open.get(i).getX() == x && open.get(i).getY() == y) { + return open.get(i); + } + } + return null; + } + + public void printBorderList() { + for (int i = 0; i < borders.size(); i++) { + System.out.print(borders.get(i).getX() + ", " + borders.get(i).getY()); + System.out.println(); + } + System.out.println("==============="); + } + + public void printOpenList() { + for (int i = 0; i < open.size(); i++) { + System.out.print(open.get(i).getX() + ", " + open.get(i).getY()); + System.out.println(); + } + System.out.println("==============="); + } + + public void printPathList() { + for (int i = 0; i < path.size(); i++) { + System.out.print(i + ": " + path.get(i).getX() + ", " + path.get(i).getY() + ": " + path.get(i).getF()); + System.out.println(); + } + System.out.println("==============="); + } +} diff --git a/src/Frame.java b/src/Frame.java index 4c4a2e6..a503a3f 100644 --- a/src/Frame.java +++ b/src/Frame.java @@ -1,533 +1,526 @@ -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Graphics; -import java.awt.Insets; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.KeyEvent; -import java.awt.event.KeyListener; -import java.awt.event.MouseEvent; -import java.awt.event.MouseListener; -import java.awt.event.MouseMotionListener; -import java.awt.event.MouseWheelEvent; -import java.awt.event.MouseWheelListener; - -import javax.swing.JButton; -import javax.swing.JCheckBox; -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.JSlider; -import javax.swing.SwingUtilities; -import javax.swing.Timer; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; - -/* The main graphics class for APathfinding. Controls the window, - * and all path finding node graphics. Need to work on zoom function, - * currently only zooms to top left corner rather than towards mouse - * by Devon Crawford - */ -public class Frame extends JPanel - implements ActionListener, MouseListener, MouseMotionListener, MouseWheelListener, KeyListener { - - ControlHandler ch; - JFrame window; - APathfinding pathfinding; - boolean showSteps, btnHover; - int size; - double a1, a2; - char currentKey = (char) 0; - Node startNode, endNode; - String mode; - - Timer timer = new Timer(100, this); - int r = randomWithRange(0, 255); - int G = randomWithRange(0, 255); - int b = randomWithRange(0, 255); - - public static void main(String[] args) { - new Frame(); - } - - public Frame() { - ch = new ControlHandler(this); - size = 25; - mode = "Map Creation"; - showSteps = true; - btnHover = false; - setLayout(null); - addMouseListener(this); - addMouseMotionListener(this); - addMouseWheelListener(this); - addKeyListener(this); - setFocusable(true); - setFocusTraversalKeysEnabled(false); - - // Set up pathfinding - pathfinding = new APathfinding(this, size); - pathfinding.setDiagonal(true); - - // Calculating value of a in speed function 1 - a1 = (5000.0000 / (Math.pow(25.0000/5000, 1/49))); - a2 = 625.0000; - - // Set up window - window = new JFrame(); - window.setContentPane(this); - window.setTitle("A* Pathfinding Visualization"); - window.getContentPane().setPreferredSize(new Dimension(700, 600)); - window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - window.pack(); - window.setLocationRelativeTo(null); - window.setVisible(true); - - // Add all controls - ch.addAll(); - - this.revalidate(); - this.repaint(); - } - - public void paintComponent(Graphics g) { - super.paintComponent(g); - - // Grab dimensions of panel - int height = getHeight(); - int width = getWidth(); - - // If no path is found - if (pathfinding.isNoPath()) { - // Set timer for animation - timer.setDelay(50); - timer.start(); - - // Set text of "run" button to "clear" - ch.getB("run").setText("clear"); - - // Set mode to "No Path" - mode = "No Path"; - - // Set up flicker animation - Color flicker = new Color(r, G, b); - g.setColor(flicker); - g.fillRect(0, 0, getWidth(), getHeight()); - - // Place "No Path" text on screen in center - ch.noPathTBounds(); - ch.getL("noPathT").setVisible(true); - this.add(ch.getL("noPathT")); - this.revalidate(); - } - - // If pathfinding is complete (found path) - if (pathfinding.isComplete()) { - // Set run button to clear - ch.getB("run").setText("clear"); - - // Set timer delay, start for background animation - timer.setDelay(50); - timer.start(); - - // Make the background flicker - Color flicker = new Color(r, G, b); - g.setColor(flicker); - g.fillRect(0, 0, getWidth(), getHeight()); - - // Set completed mode - if(showSteps) { - mode = "Completed"; - } - else { - mode = "Completed in " + pathfinding.getRunTime() + "ms"; - } - } - - // Draws grid - g.setColor(Color.lightGray); - for (int j = 0; j < this.getHeight(); j += size) { - for (int i = 0; i < this.getWidth(); i += size) { - g.drawRect(i, j, size, size); - } - } - - // Draws all borders - g.setColor(Color.black); - for (int i = 0; i < pathfinding.getBorderList().size(); i++) { - g.fillRect(pathfinding.getBorderList().get(i).getX() + 1, pathfinding.getBorderList().get(i).getY() + 1, - size - 1, size - 1); - } - - // Draws all open Nodes (path finding nodes) - for (int i = 0; i < pathfinding.getOpenList().size(); i++) { - Node current = pathfinding.getOpenList().get(i); - g.setColor(style.greenHighlight); - g.fillRect(current.getX() + 1, current.getY() + 1, size - 1, size - 1); - - drawInfo(current, g); - } - - // Draws all closed nodes - for (int i = 0; i < pathfinding.getClosedList().size(); i++) { - Node current = pathfinding.getClosedList().get(i); - - g.setColor(style.redHighlight); - g.fillRect(current.getX() + 1, current.getY() + 1, size - 1, size - 1); - - drawInfo(current, g); - } - - // Draw all final path nodes - for (int i = 0; i < pathfinding.getPathList().size(); i++) { - Node current = pathfinding.getPathList().get(i); - - g.setColor(style.blueHighlight); - g.fillRect(current.getX() + 1, current.getY() + 1, size - 1, size - 1); - - drawInfo(current, g); - } - - // Draws start of path - if (startNode != null) { - g.setColor(Color.blue); - g.fillRect(startNode.getX() + 1, startNode.getY() + 1, size - 1, size - 1); - } - // Draws end of path - if (endNode != null) { - g.setColor(Color.red); - g.fillRect(endNode.getX() + 1, endNode.getY() + 1, size - 1, size - 1); - } - - // If control panel is being hovered, change colours - if(btnHover) { - g.setColor(style.darkText); - ch.hoverColour(); - } - else { - g.setColor(style.btnPanel); - ch.nonHoverColour(); - } - // Drawing control panel rectangle - g.fillRect(10, height-96, 322, 90); - - // Setting mode text - ch.getL("modeText").setText("Mode: " + mode); - - // Position all controls - ch.position(); - - // Setting numbers in pathfinding lists - ch.getL("openC").setText(Integer.toString(pathfinding.getOpenList().size())); - ch.getL("closedC").setText(Integer.toString(pathfinding.getClosedList().size())); - ch.getL("pathC").setText(Integer.toString(pathfinding.getPathList().size())); - - // Setting speed number text in showSteps or !showSteps mode - if(showSteps) { - ch.getL("speedC").setText(Integer.toString(ch.getS("speed").getValue())); - } - else { - ch.getL("speedC").setText("N/A"); - } - - // Getting values from checkboxes - showSteps = ch.getC("showStepsCheck").isSelected(); - pathfinding.setDiagonal(ch.getC("diagonalCheck").isSelected()); - pathfinding.setTrig(ch.getC("trigCheck").isSelected()); - } - - // Draws info (f, g, h) on current node - public void drawInfo(Node current, Graphics g) { - if (size > 50) { - g.setFont(style.numbers); - g.setColor(Color.black); - g.drawString(Integer.toString(current.getF()), current.getX() + 4, current.getY() + 16); - g.setFont(style.smallNumbers); - g.drawString(Integer.toString(current.getG()), current.getX() + 4, current.getY() + size - 7); - g.drawString(Integer.toString(current.getH()), current.getX() + size - 26, current.getY() + size - 7); - } - } - - public void MapCalculations(MouseEvent e) { - // If left mouse button is clicked - if (SwingUtilities.isLeftMouseButton(e)) { - // If 's' is pressed create start node - if (currentKey == 's') { - int xRollover = e.getX() % size; - int yRollover = e.getY() % size; - - if (startNode == null) { - startNode = new Node(e.getX() - xRollover, e.getY() - yRollover); - } else { - startNode.setXY(e.getX() - xRollover, e.getY() - yRollover); - } - repaint(); - } - // If 'e' is pressed create end node - else if (currentKey == 'e') { - int xRollover = e.getX() % size; - int yRollover = e.getY() % size; - - if (endNode == null) { - endNode = new Node(e.getX() - xRollover, e.getY() - yRollover); - } else { - endNode.setXY(e.getX() - xRollover, e.getY() - yRollover); - } - repaint(); - } - // Otherwise, create a wall - else { - int xBorder = e.getX() - (e.getX() % size); - int yBorder = e.getY() - (e.getY() % size); - - Node newBorder = new Node(xBorder, yBorder); - pathfinding.addBorder(newBorder); - - repaint(); - } - } - // If right mouse button is clicked - else if (SwingUtilities.isRightMouseButton(e)) { - int mouseBoxX = e.getX() - (e.getX() % size); - int mouseBoxY = e.getY() - (e.getY() % size); - - // If 's' is pressed remove start node - if (currentKey == 's') { - if (startNode != null && mouseBoxX == startNode.getX() && startNode.getY() == mouseBoxY) { - startNode = null; - repaint(); - } - } - // If 'e' is pressed remove end node - else if (currentKey == 'e') { - if (endNode != null && mouseBoxX == endNode.getX() && endNode.getY() == mouseBoxY) { - endNode = null; - repaint(); - } - } - // Otherwise, remove wall - else { - int Location = pathfinding.searchBorder(mouseBoxX, mouseBoxY); - if (Location != -1) { - pathfinding.removeBorder(Location); - } - repaint(); - } - } - } - - @Override - public void mouseClicked(MouseEvent e) { - MapCalculations(e); - } - - @Override - public void mousePressed(MouseEvent e) {} - - @Override - public void mouseReleased(MouseEvent e) {} - - @Override - public void mouseEntered(MouseEvent e) {} - - @Override - public void mouseExited(MouseEvent e) {} - - @Override - public void mouseDragged(MouseEvent e) { - MapCalculations(e); - } - - @Override - // Track mouse on movement - public void mouseMoved(MouseEvent e) { - int x = e.getX(); - int y = e.getY(); - int height = this.getHeight(); - - // Detects if mouse is within button panel - if(x >= 10 && x <= 332 && y >= (height-96) && y <= (height-6)) { - btnHover = true; - } - else { - btnHover = false; - } - repaint(); - } - - @Override - public void keyTyped(KeyEvent e) {} - - @Override - public void keyPressed(KeyEvent e) { - char key = e.getKeyChar(); - currentKey = key; - - // Start if space is pressed - if (currentKey == KeyEvent.VK_SPACE) { - ch.getB("run").setText("stop"); - start(); - } - } - - @Override - public void keyReleased(KeyEvent e) { - currentKey = (char) 0; - } - - // Starts path finding - void start() { - if(startNode != null && endNode != null) { - if (!showSteps) { - pathfinding.start(startNode, endNode); - } else { - pathfinding.setup(startNode, endNode); - setSpeed(); - timer.start(); - } - } - else { - System.out.println("ERROR: Needs start and end points to run."); - } - } - - @Override - // Scales the map with mouse wheel scroll - public void mouseWheelMoved(MouseWheelEvent m) { - int rotation = m.getWheelRotation(); - double prevSize = size; - int scroll = 3; - - // Changes size of grid based on scroll - if (rotation == -1 && size + scroll < 200) { - size += scroll; - } else if (rotation == 1 && size - scroll > 2) { - size += -scroll; - } - pathfinding.setSize(size); - double ratio = size / prevSize; - - // new X and Y values for Start - if (startNode != null) { - int sX = (int) Math.round(startNode.getX() * ratio); - int sY = (int) Math.round(startNode.getY() * ratio); - startNode.setXY(sX, sY); - } - - // new X and Y values for End - if (endNode != null) { - int eX = (int) Math.round(endNode.getX() * ratio); - int eY = (int) Math.round(endNode.getY() * ratio); - endNode.setXY(eX, eY); - } - - // new X and Y values for borders - for (int i = 0; i < pathfinding.getBorderList().size(); i++) { - int newX = (int) Math.round((pathfinding.getBorderList().get(i).getX() * ratio)); - int newY = (int) Math.round((pathfinding.getBorderList().get(i).getY() * ratio)); - pathfinding.getBorderList().get(i).setXY(newX, newY); - } - - // New X and Y for Open nodes - for (int i = 0; i < pathfinding.getOpenList().size(); i++) { - int newX = (int) Math.round((pathfinding.getOpenList().get(i).getX() * ratio)); - int newY = (int) Math.round((pathfinding.getOpenList().get(i).getY() * ratio)); - pathfinding.getOpenList().get(i).setXY(newX, newY); - } - - // New X and Y for Closed Nodes - for (int i = 0; i < pathfinding.getClosedList().size(); i++) { - if (!Node.isEqual(pathfinding.getClosedList().get(i), startNode)) { - int newX = (int) Math.round((pathfinding.getClosedList().get(i).getX() * ratio)); - int newY = (int) Math.round((pathfinding.getClosedList().get(i).getY() * ratio)); - pathfinding.getClosedList().get(i).setXY(newX, newY); - } - } - repaint(); - } - - @Override - public void actionPerformed(ActionEvent e) { - // Moves one step ahead in path finding (called on timer) - if (pathfinding.isRunning() && showSteps) { - pathfinding.findPath(pathfinding.getPar()); - mode = "Running"; - } - // Finish pathfinding background flicker! - if (pathfinding.isComplete() || pathfinding.isNoPath()) { - r = (int) (Math.random() * ((r + 15) - (r - 15)) + (r - 15)); - G = (int) (Math.random() * ((G + 15) - (G - 15)) + (G - 15)); - b = (int) (Math.random() * ((b + 15) - (b - 15)) + (b - 15)); - - if (r >= 240 | r <= 15) { - r = randomWithRange(0, 255); - } - if (G >= 240 | G <= 15) { - G = randomWithRange(0, 255); - } - if (b >= 240 | b <= 15) { - b = randomWithRange(0, 255); - } - } - - // Actions of run/stop/clear button - if(e.getActionCommand() != null) { - if(e.getActionCommand().equals("run") && !pathfinding.isRunning()) { - ch.getB("run").setText("stop"); - start(); - } - else if(e.getActionCommand().equals("clear")) { - ch.getB("run").setText("run"); - mode = "Map Creation"; - ch.getL("noPathT").setVisible(false); - pathfinding.reset(); - } - else if(e.getActionCommand().equals("stop")) { - ch.getB("run").setText("start"); - timer.stop(); - } - else if(e.getActionCommand().equals("start")) { - ch.getB("run").setText("stop"); - timer.start(); - } - } - repaint(); - } - - // Returns random number between min and max - int randomWithRange(int min, int max) - { - int range = (max - min) + 1; - return (int)(Math.random() * range) + min; - } - - // Calculates delay with two exponential functions - void setSpeed() { - int delay = 0; - int value = ch.getS("speed").getValue(); - - if(value == 0) { - timer.stop(); - } - else if(value >= 1 && value < 50) { - if(!timer.isRunning()) { - timer.start(); - } - // Exponential function. value(1) == delay(5000). value (50) == delay(25) - delay = (int)(a1 * (Math.pow(25/5000.0000, value / 49.0000))); - } - else if(value >= 50 && value <= 100) { - if(!timer.isRunning()) { - timer.start(); - } - // Exponential function. value (50) == delay(25). value(100) == delay(1). - delay = (int)(a2 * (Math.pow(1/25.0000, value/50.0000))); - } - timer.setDelay(delay); - } - - boolean showSteps() { - return showSteps; - } -} - - +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; +import java.awt.event.MouseWheelEvent; +import java.awt.event.MouseWheelListener; + +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.SwingUtilities; +import javax.swing.Timer; + +/* The main graphics class for APathfinding. Controls the window, + * and all path finding node graphics. Need to work on zoom function, + * currently only zooms to top left corner rather than towards mouse + * by Devon Crawford + */ +public class Frame extends JPanel + implements ActionListener, MouseListener, MouseMotionListener, MouseWheelListener, KeyListener { + + ControlHandler ch; + JFrame window; + APathfinding pathfinding; + boolean showSteps, btnHover; + int size; + double a1, a2; + char currentKey = (char) 0; + Node startNode, endNode; + String mode; + + Timer timer = new Timer(100, this); + int r = randomWithRange(0, 255); + int G = randomWithRange(0, 255); + int b = randomWithRange(0, 255); + + public static void main(String[] args) { + new Frame(); + } + + public Frame() { + ch = new ControlHandler(this); + size = 25; + mode = "Map Creation"; + showSteps = true; + btnHover = false; + setLayout(null); + addMouseListener(this); + addMouseMotionListener(this); + addMouseWheelListener(this); + addKeyListener(this); + setFocusable(true); + setFocusTraversalKeysEnabled(false); + + // Set up pathfinding + pathfinding = new APathfinding(this, size); + pathfinding.setDiagonal(true); + + // Calculating value of a in speed function 1 + a1 = (5000.0000 / (Math.pow(25.0000/5000, 1/49))); + a2 = 625.0000; + + // Set up window + window = new JFrame(); + window.setContentPane(this); + window.setTitle("A* Pathfinding Visualization"); + window.getContentPane().setPreferredSize(new Dimension(700, 600)); + window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + window.pack(); + window.setLocationRelativeTo(null); + window.setVisible(true); + + // Add all controls + ch.addAll(); + + this.revalidate(); + this.repaint(); + } + + public void paintComponent(Graphics g) { + super.paintComponent(g); + + // Grab dimensions of panel + int height = getHeight(); + int width = getWidth(); + + // If no path is found + if (pathfinding.isNoPath()) { + // Set timer for animation + timer.setDelay(50); + timer.start(); + + // Set text of "run" button to "clear" + ch.getB("run").setText("clear"); + + // Set mode to "No Path" + mode = "No Path"; + + // Set up flicker animation + Color flicker = new Color(r, G, b); + g.setColor(flicker); + g.fillRect(0, 0, getWidth(), getHeight()); + + // Place "No Path" text on screen in center + ch.noPathTBounds(); + ch.getL("noPathT").setVisible(true); + this.add(ch.getL("noPathT")); + this.revalidate(); + } + + // If pathfinding is complete (found path) + if (pathfinding.isComplete()) { + // Set run button to clear + ch.getB("run").setText("clear"); + + // Set timer delay, start for background animation + timer.setDelay(50); + timer.start(); + + // Make the background flicker + Color flicker = new Color(r, G, b); + g.setColor(flicker); + g.fillRect(0, 0, getWidth(), getHeight()); + + // Set completed mode + if(showSteps) { + mode = "Completed"; + } + else { + mode = "Completed in " + pathfinding.getRunTime() + "ms"; + } + } + + // Draws grid + g.setColor(Color.lightGray); + for (int j = 0; j < this.getHeight(); j += size) { + for (int i = 0; i < this.getWidth(); i += size) { + g.drawRect(i, j, size, size); + } + } + + // Draws all borders + g.setColor(Color.black); + for (int i = 0; i < pathfinding.getBorderList().size(); i++) { + g.fillRect(pathfinding.getBorderList().get(i).getX() + 1, pathfinding.getBorderList().get(i).getY() + 1, + size - 1, size - 1); + } + + // Draws all open Nodes (path finding nodes) + for (int i = 0; i < pathfinding.getOpenList().size(); i++) { + Node current = pathfinding.getOpenList().get(i); + g.setColor(style.greenHighlight); + g.fillRect(current.getX() + 1, current.getY() + 1, size - 1, size - 1); + + drawInfo(current, g); + } + + // Draws all closed nodes + for (int i = 0; i < pathfinding.getClosedList().size(); i++) { + Node current = pathfinding.getClosedList().get(i); + + g.setColor(style.redHighlight); + g.fillRect(current.getX() + 1, current.getY() + 1, size - 1, size - 1); + + drawInfo(current, g); + } + + // Draw all final path nodes + for (int i = 0; i < pathfinding.getPathList().size(); i++) { + Node current = pathfinding.getPathList().get(i); + + g.setColor(style.blueHighlight); + g.fillRect(current.getX() + 1, current.getY() + 1, size - 1, size - 1); + + drawInfo(current, g); + } + + // Draws start of path + if (startNode != null) { + g.setColor(Color.blue); + g.fillRect(startNode.getX() + 1, startNode.getY() + 1, size - 1, size - 1); + } + // Draws end of path + if (endNode != null) { + g.setColor(Color.red); + g.fillRect(endNode.getX() + 1, endNode.getY() + 1, size - 1, size - 1); + } + + // If control panel is being hovered, change colours + if(btnHover) { + g.setColor(style.darkText); + ch.hoverColour(); + } + else { + g.setColor(style.btnPanel); + ch.nonHoverColour(); + } + // Drawing control panel rectangle + g.fillRect(10, height-96, 322, 90); + + // Setting mode text + ch.getL("modeText").setText("Mode: " + mode); + + // Position all controls + ch.position(); + + // Setting numbers in pathfinding lists + ch.getL("openC").setText(Integer.toString(pathfinding.getOpenList().size())); + ch.getL("closedC").setText(Integer.toString(pathfinding.getClosedList().size())); + ch.getL("pathC").setText(Integer.toString(pathfinding.getPathList().size())); + + // Setting speed number text in showSteps or !showSteps mode + if(showSteps) { + ch.getL("speedC").setText(Integer.toString(ch.getS("speed").getValue())); + } + else { + ch.getL("speedC").setText("N/A"); + } + + // Getting values from checkboxes + showSteps = ch.getC("showStepsCheck").isSelected(); + pathfinding.setDiagonal(ch.getC("diagonalCheck").isSelected()); + pathfinding.setTrig(ch.getC("trigCheck").isSelected()); + } + + // Draws info (f, g, h) on current node + public void drawInfo(Node current, Graphics g) { + if (size > 50) { + g.setFont(style.numbers); + g.setColor(Color.black); + g.drawString(Integer.toString(current.getF()), current.getX() + 4, current.getY() + 16); + g.setFont(style.smallNumbers); + g.drawString(Integer.toString(current.getG()), current.getX() + 4, current.getY() + size - 7); + g.drawString(Integer.toString(current.getH()), current.getX() + size - 26, current.getY() + size - 7); + } + } + + public void MapCalculations(MouseEvent e) { + // If left mouse button is clicked + if (SwingUtilities.isLeftMouseButton(e)) { + // If 's' is pressed create start node + if (currentKey == 's') { + int xRollover = e.getX() % size; + int yRollover = e.getY() % size; + + if (startNode == null) { + startNode = new Node(e.getX() - xRollover, e.getY() - yRollover); + } else { + startNode.setXY(e.getX() - xRollover, e.getY() - yRollover); + } + repaint(); + } + // If 'e' is pressed create end node + else if (currentKey == 'e') { + int xRollover = e.getX() % size; + int yRollover = e.getY() % size; + + if (endNode == null) { + endNode = new Node(e.getX() - xRollover, e.getY() - yRollover); + } else { + endNode.setXY(e.getX() - xRollover, e.getY() - yRollover); + } + repaint(); + } + // Otherwise, create a wall + else { + int xBorder = e.getX() - (e.getX() % size); + int yBorder = e.getY() - (e.getY() % size); + + Node newBorder = new Node(xBorder, yBorder); + pathfinding.addBorder(newBorder); + + repaint(); + } + } + // If right mouse button is clicked + else if (SwingUtilities.isRightMouseButton(e)) { + int mouseBoxX = e.getX() - (e.getX() % size); + int mouseBoxY = e.getY() - (e.getY() % size); + + // If 's' is pressed remove start node + if (currentKey == 's') { + if (startNode != null && mouseBoxX == startNode.getX() && startNode.getY() == mouseBoxY) { + startNode = null; + repaint(); + } + } + // If 'e' is pressed remove end node + else if (currentKey == 'e') { + if (endNode != null && mouseBoxX == endNode.getX() && endNode.getY() == mouseBoxY) { + endNode = null; + repaint(); + } + } + // Otherwise, remove wall + else { + int Location = pathfinding.searchBorder(mouseBoxX, mouseBoxY); + if (Location != -1) { + pathfinding.removeBorder(Location); + } + repaint(); + } + } + } + + @Override + public void mouseClicked(MouseEvent e) { + MapCalculations(e); + } + + @Override + public void mousePressed(MouseEvent e) {} + + @Override + public void mouseReleased(MouseEvent e) {} + + @Override + public void mouseEntered(MouseEvent e) {} + + @Override + public void mouseExited(MouseEvent e) {} + + @Override + public void mouseDragged(MouseEvent e) { + MapCalculations(e); + } + + @Override + // Track mouse on movement + public void mouseMoved(MouseEvent e) { + int x = e.getX(); + int y = e.getY(); + int height = this.getHeight(); + + // Detects if mouse is within button panel + if(x >= 10 && x <= 332 && y >= (height-96) && y <= (height-6)) { + btnHover = true; + } + else { + btnHover = false; + } + repaint(); + } + + @Override + public void keyTyped(KeyEvent e) {} + + @Override + public void keyPressed(KeyEvent e) { + char key = e.getKeyChar(); + currentKey = key; + + // Start if space is pressed + if (currentKey == KeyEvent.VK_SPACE) { + ch.getB("run").setText("stop"); + start(); + } + } + + @Override + public void keyReleased(KeyEvent e) { + currentKey = (char) 0; + } + + // Starts path finding + void start() { + if(startNode != null && endNode != null) { + if (!showSteps) { + pathfinding.start(startNode, endNode); + } else { + pathfinding.setup(startNode, endNode); + setSpeed(); + timer.start(); + } + } + else { + System.out.println("ERROR: Needs start and end points to run."); + } + } + + @Override + // Scales the map with mouse wheel scroll + public void mouseWheelMoved(MouseWheelEvent m) { + int rotation = m.getWheelRotation(); + double prevSize = size; + int scroll = 3; + + // Changes size of grid based on scroll + if (rotation == -1 && size + scroll < 200) { + size += scroll; + } else if (rotation == 1 && size - scroll > 2) { + size += -scroll; + } + pathfinding.setSize(size); + double ratio = size / prevSize; + + // new X and Y values for Start + if (startNode != null) { + int sX = (int) Math.round(startNode.getX() * ratio); + int sY = (int) Math.round(startNode.getY() * ratio); + startNode.setXY(sX, sY); + } + + // new X and Y values for End + if (endNode != null) { + int eX = (int) Math.round(endNode.getX() * ratio); + int eY = (int) Math.round(endNode.getY() * ratio); + endNode.setXY(eX, eY); + } + + // new X and Y values for borders + for (int i = 0; i < pathfinding.getBorderList().size(); i++) { + int newX = (int) Math.round((pathfinding.getBorderList().get(i).getX() * ratio)); + int newY = (int) Math.round((pathfinding.getBorderList().get(i).getY() * ratio)); + pathfinding.getBorderList().get(i).setXY(newX, newY); + } + + // New X and Y for Open nodes + for (int i = 0; i < pathfinding.getOpenList().size(); i++) { + int newX = (int) Math.round((pathfinding.getOpenList().get(i).getX() * ratio)); + int newY = (int) Math.round((pathfinding.getOpenList().get(i).getY() * ratio)); + pathfinding.getOpenList().get(i).setXY(newX, newY); + } + + // New X and Y for Closed Nodes + for (int i = 0; i < pathfinding.getClosedList().size(); i++) { + if (!Node.isEqual(pathfinding.getClosedList().get(i), startNode)) { + int newX = (int) Math.round((pathfinding.getClosedList().get(i).getX() * ratio)); + int newY = (int) Math.round((pathfinding.getClosedList().get(i).getY() * ratio)); + pathfinding.getClosedList().get(i).setXY(newX, newY); + } + } + repaint(); + } + + @Override + public void actionPerformed(ActionEvent e) { + // Moves one step ahead in path finding (called on timer) + if (pathfinding.isRunning() && showSteps) { + pathfinding.findPath(pathfinding.getPar()); + mode = "Running"; + } + // Finish pathfinding background flicker! + if (pathfinding.isComplete() || pathfinding.isNoPath()) { + r = (int) (Math.random() * ((r + 15) - (r - 15)) + (r - 15)); + G = (int) (Math.random() * ((G + 15) - (G - 15)) + (G - 15)); + b = (int) (Math.random() * ((b + 15) - (b - 15)) + (b - 15)); + + if (r >= 240 | r <= 15) { + r = randomWithRange(0, 255); + } + if (G >= 240 | G <= 15) { + G = randomWithRange(0, 255); + } + if (b >= 240 | b <= 15) { + b = randomWithRange(0, 255); + } + } + + // Actions of run/stop/clear button + if(e.getActionCommand() != null) { + if(e.getActionCommand().equals("run") && !pathfinding.isRunning()) { + ch.getB("run").setText("stop"); + start(); + } + else if(e.getActionCommand().equals("clear")) { + ch.getB("run").setText("run"); + mode = "Map Creation"; + ch.getL("noPathT").setVisible(false); + pathfinding.reset(); + } + else if(e.getActionCommand().equals("stop")) { + ch.getB("run").setText("start"); + timer.stop(); + } + else if(e.getActionCommand().equals("start")) { + ch.getB("run").setText("stop"); + timer.start(); + } + } + repaint(); + } + + // Returns random number between min and max + int randomWithRange(int min, int max) + { + int range = (max - min) + 1; + return (int)(Math.random() * range) + min; + } + + // Calculates delay with two exponential functions + void setSpeed() { + int delay = 0; + int value = ch.getS("speed").getValue(); + + if(value == 0) { + timer.stop(); + } + else if(value >= 1 && value < 50) { + if(!timer.isRunning()) { + timer.start(); + } + // Exponential function. value(1) == delay(5000). value (50) == delay(25) + delay = (int)(a1 * (Math.pow(25/5000.0000, value / 49.0000))); + } + else if(value >= 50 && value <= 100) { + if(!timer.isRunning()) { + timer.start(); + } + // Exponential function. value (50) == delay(25). value(100) == delay(1). + delay = (int)(a2 * (Math.pow(1/25.0000, value/50.0000))); + } + timer.setDelay(delay); + } + + boolean showSteps() { + return showSteps; + } +} + + diff --git a/src/Sort.java b/src/Sort.java index 1c78c31..d587b67 100644 --- a/src/Sort.java +++ b/src/Sort.java @@ -1,126 +1,183 @@ -import java.util.ArrayList; - -/* Sort functions used in path finding to - * determine lowest F cost Node. Bubble sort is mainly - * used, quick sort needs work. Currently not working - * by Devon Crawford - */ -public class Sort { - - private boolean lowToHigh, highToLow; - - public Sort() { - lowToHigh = true; - highToLow = false; - } - - public void bubbleSort(int[] data) { - int Switch = -1; - int temp; - - while (Switch != 0) { - Switch = 0; - - if (lowToHigh) { - for (int i = 0; i < data.length - 1; i++) { - if (data[i] > data[i + 1]) { - temp = data[i]; - data[i] = data[i + 1]; - data[i + 1] = temp; - Switch = 1; - } - } - } else if (highToLow) { - for (int i = 0; i < data.length - 1; i++) { - if (data[i] < data[i + 1]) { - temp = data[i]; - data[i] = data[i + 1]; - data[i + 1] = temp; - Switch = 1; - } - } - } - } - } - - public void bubbleSort(ArrayList list) { - int Switch = -1; - Node temp; - - while (Switch != 0) { - Switch = 0; - - if (lowToHigh) { - for (int i = 0; i < list.size() - 1; i++) { - if (list.get(i).getF() > list.get(i + 1).getF()) { - temp = list.get(i); - list.remove(i); - list.add(i + 1, temp); - Switch = 1; - } - } - } else if (highToLow) { - for (int i = 0; i < list.size() - 1; i++) { - if (list.get(i).getF() < list.get(i + 1).getF()) { - temp = list.get(i); - list.remove(i); - list.add(i + 1, temp); - Switch = 1; - } - } - } - } - } - - // low is 0, high is numbers.length - 1 - // TODO: FIX HIGH TO LOW QUICKSORT - public void quickSort(int[] numbers, int low, int high) { - int i = low, j = high; - - int pivot = numbers[low + (high - low) / 2]; - - while (i <= j) { - - if (lowToHigh) { - while (numbers[i] < pivot) { - i++; - } - - while (numbers[j] > pivot) { - j--; - } - } else if (highToLow) { - while (numbers[i] > pivot) { - i++; - } - - while (numbers[j] < pivot) { - j--; - } - } - - if (i <= j) { - int temp = numbers[i]; - numbers[i] = numbers[j]; - numbers[j] = temp; - i++; - j--; - } - } - - if (low < j) - quickSort(numbers, low, j); - if (i < high) - quickSort(numbers, i, high); - } // end of quick sort - - public void setLowToHigh() { - lowToHigh = true; - highToLow = false; - } - - public void setHighToLow() { - lowToHigh = false; - highToLow = true; - } -} +import java.util.ArrayList; + +/* Sort functions used in path finding to + * determine lowest F cost Node. Bubble sort is mainly + * used, quick sort needs work. Currently not working + * by Devon Crawford + */ +public class Sort { + + private boolean lowToHigh, highToLow; + + public Sort() { + lowToHigh = true; + highToLow = false; + } + + public void selectionSort(int[] data){ + if(lowToHigh){ + for(int i = 0; i < data.length; i++){ + int minIndex = i; + for (int j = i; j < data.length; j++) { + if(data[minIndex] > data[j]){ + minIndex = j; + } + } + int temp = data[i]; + data[i] = data[minIndex]; + data[minIndex] = temp; + } + }else if(highToLow){ + for(int i = 0; i < data.length; i++){ + int minIndex = i; + for (int j = i; j < data.length; j++) { + if(data[minIndex] < data[j]){ + minIndex = j; + } + } + int temp = data[i]; + data[i] = data[minIndex]; + data[minIndex] = temp; + } + } + + } + + public void selectionSort(ArrayList list){ + if(lowToHigh){ + for(int i = 0; i < list.size(); i++){ + int minIndex = i; + for (int j = i; j < list.size(); j++) { + if(list.get(minIndex).getF() > list.get(j).getF()){ + minIndex = j; + } + } + Node temp = list.get(i); + list.set(i, list.get(minIndex)); + list.set(minIndex, temp); + } + }else if(highToLow){ + for(int i = 0; i < list.size(); i++){ + int minIndex = i; + for (int j = i; j < list.size(); j++) { + if(list.get(minIndex).getF() < list.get(j).getF()){ + minIndex = j; + } + } + Node temp = list.get(i); + list.set(i, list.get(minIndex)); + list.set(minIndex, temp); + } + } + } + + public void bubbleSort(int[] data) { + int Switch = -1; + int temp; + + while (Switch != 0) { + Switch = 0; + + if (lowToHigh) { + for (int i = 0; i < data.length - 1; i++) { + if (data[i] > data[i + 1]) { + temp = data[i]; + data[i] = data[i + 1]; + data[i + 1] = temp; + Switch = 1; + } + } + } else if (highToLow) { + for (int i = 0; i < data.length - 1; i++) { + if (data[i] < data[i + 1]) { + temp = data[i]; + data[i] = data[i + 1]; + data[i + 1] = temp; + Switch = 1; + } + } + } + } + } + + public void bubbleSort(ArrayList list) { + int Switch = -1; + Node temp; + + while (Switch != 0) { + Switch = 0; + + if (lowToHigh) { + for (int i = 0; i < list.size() - 1; i++) { + if (list.get(i).getF() > list.get(i + 1).getF()) { + temp = list.get(i); + list.remove(i); + list.add(i + 1, temp); + Switch = 1; + } + } + } else if (highToLow) { + for (int i = 0; i < list.size() - 1; i++) { + if (list.get(i).getF() < list.get(i + 1).getF()) { + temp = list.get(i); + list.remove(i); + list.add(i + 1, temp); + Switch = 1; + } + } + } + } + } + + // low is 0, high is numbers.length - 1 + // TODO: FIX HIGH TO LOW QUICKSORT + public void quickSort(int[] numbers, int low, int high) { + int i = low, j = high; + + int pivot = numbers[low + (high - low) / 2]; + + while (i <= j) { + + if (lowToHigh) { + while (numbers[i] < pivot) { + i++; + } + + while (numbers[j] > pivot) { + j--; + } + } else if (highToLow) { + while (numbers[i] > pivot) { + i++; + } + + while (numbers[j] < pivot) { + j--; + } + } + + if (i <= j) { + int temp = numbers[i]; + numbers[i] = numbers[j]; + numbers[j] = temp; + i++; + j--; + } + } + + if (low < j) + quickSort(numbers, low, j); + if (i < high) + quickSort(numbers, i, high); + } // end of quick sort + + public void setLowToHigh() { + lowToHigh = true; + highToLow = false; + } + + public void setHighToLow() { + lowToHigh = false; + highToLow = true; + } +}