summaryrefslogtreecommitdiff
path: root/Pathfinding Visualizer/Assets/Scripts/PathNode.cs
diff options
context:
space:
mode:
authorSimon O'Shea <osheas1@wit.edu>2023-08-08 13:10:51 -0400
committerSimon O'Shea <osheas1@wit.edu>2023-08-08 13:10:51 -0400
commitf825ec9c278af326bde56524a08888d067b2a68f (patch)
treecbd098364eacb500a22168268a4d87c17ddb57a2 /Pathfinding Visualizer/Assets/Scripts/PathNode.cs
parent219d21173eca4d9ddb033d12555a160a6021d89c (diff)
slop of code
intermediate push so logan can have access to reset function
Diffstat (limited to 'Pathfinding Visualizer/Assets/Scripts/PathNode.cs')
-rw-r--r--Pathfinding Visualizer/Assets/Scripts/PathNode.cs261
1 files changed, 261 insertions, 0 deletions
diff --git a/Pathfinding Visualizer/Assets/Scripts/PathNode.cs b/Pathfinding Visualizer/Assets/Scripts/PathNode.cs
new file mode 100644
index 0000000..0f607cd
--- /dev/null
+++ b/Pathfinding Visualizer/Assets/Scripts/PathNode.cs
@@ -0,0 +1,261 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+
+ class Node : IComparable<Node>
+ {
+ // helper variables just to make indexing arrays easier to read
+ public static int row = 0;
+ public static int col = 1;
+
+ Node parent;
+ int[] agent;
+ List<int[]> samples;
+ char lastMove; // for output/animation
+ int distanceTraveled; // for calculating f(n) value
+ double heuristic;
+ double fn; // distance traveled + heuristic value
+ bool canSample; // for expansion
+
+ // construct node :)
+ public Node(Node parent, int[] agent, List<int[]> samples, char lastMove, int distanceTraveled, double heuristic)
+ {
+ this.parent = parent;
+ this.agent = agent;
+ this.samples = new ArrayList<int[]>(samples);
+ this.lastMove = lastMove;
+ this.distanceTraveled = distanceTraveled;
+ this.heuristic = heuristic;
+ this.fn = distanceTraveled + heuristic;
+ }
+
+ // determine valid moves and collect children to be sent back to search
+ public List<Node> expand(int depth)
+ {
+ List<Node> children = new ArrayList<Node>();
+ if (this.distanceTraveled >= depth && depth != -1)
+ return children;
+
+ // document expansion of node and get ready to collect this node's children
+ SampleWorld.expansions++;
+ int[] onSample = new int[2];
+
+ // since this state is being currently visited (expanded), put in closed list
+ SampleWorld.closed.add(this.getState());
+
+ ////////////////////////////////////
+ // BEGIN CHECKING FOR VALID MOVES //
+ ////////////////////////////////////
+
+ // store coordinates for all potential moves to be checked
+ int[] up = { this.agent[row] - 1, this.agent[col] };
+ int[] down = { this.agent[row] + 1, this.agent[col] };
+ int[] left = { this.agent[row], this.agent[col] - 1 };
+ int[] right = { this.agent[row], this.agent[col] + 1 };
+
+ // make sure going up doesn't go outside world-bounds or into obstacle
+ if (isOpen(up))
+ {
+ // if move is valid, create that new node/state and document
+ Node child = new Node(this, up, this.samples, 'U', this.distanceTraveled + 1, this.heuristic);
+ SampleWorld.nodesGenerated++;
+
+ // make sure that we have not already made that move
+ if (!child.getState().inClosed())
+ children.add(child);
+ }
+
+ // same idea but for the different potential moves
+ if (isOpen(down))
+ {
+ Node child = new Node(this, down, this.samples, 'D', this.distanceTraveled + 1, this.heuristic);
+ SampleWorld.nodesGenerated++;
+
+ if (!child.getState().inClosed())
+ children.add(child);
+ }
+
+ if (isOpen(left))
+ {
+ Node child = new Node(this, left, this.samples, 'L', this.distanceTraveled + 1, this.heuristic);
+ SampleWorld.nodesGenerated++;
+
+ if (!child.getState().inClosed())
+ children.add(child);
+ }
+
+ if (isOpen(right))
+ {
+ Node child = new Node(this, right, this.samples, 'R', this.distanceTraveled + 1, this.heuristic);
+ SampleWorld.nodesGenerated++;
+
+ if (!child.getState().inClosed())
+ children.add(child);
+ }
+
+ // CHECK IF CAN SAMPLE
+ onSample = canSample();
+ if (onSample[0] == 1)
+ {
+ Node child = new Node(this, this.agent, this.samples, 'S', this.distanceTraveled + 1, this.heuristic);
+ child.samples.remove(onSample[1]);
+
+ SampleWorld.nodesGenerated++;
+ children.add(child);
+ }
+
+ return children;
+ }
+
+ // helper for expand, verifies whether potential move is legal
+ public boolean isOpen(int[] position)
+ {
+ // check that agent is not trying to move into an obstacle
+ for (int i = 0; i < SampleWorld.obstacles.size(); i++)
+ {
+ if (Arrays.compare(SampleWorld.obstacles.get(i), position) == 0)
+ return false;
+ }
+
+ // check that agent is not stepping out of the world
+ if (!((position[row] >= 0) && (position[row] <= SampleWorld.worldRows - 1) && (position[col] >= 0) && (position[col] <= SampleWorld.worldCols - 1)))
+ return false;
+
+ return true;
+ }
+
+ // returns the coordinates of the sample closest to the agent's current location
+ public int[] nearestSample()
+ {
+ if (samples.size() == 0)
+ return agent;
+
+ int[] s = samples.get(0);
+ double lowest = distance(agent, samples.get(0));
+ double distance;
+
+ for (int i = 1; i < samples.size(); i++)
+ {
+ distance = distance(agent, samples.get(i));
+ if (distance < lowest)
+ {
+ lowest = distance;
+ s = samples.get(i);
+ }
+ }
+ return s;
+ }
+ // helper function for nearestSample()
+ public static double distance(int[] a, int[] b)
+ { // _________________________
+ // distance between 2D points = √(y2 - y1)^2 + (x2 - x1)^2
+ double total = (((b[row] - a[row]) * (b[row] - a[row])) + ((b[col] - a[col]) * (b[col] - a[col])));
+ total = Math.sqrt(total);
+
+ return total;
+ }
+
+ // helper function for h2
+ /////////////////////////////
+ // returns two pieces of information if true:
+ // [0] is 1 to indicate agent can sample
+ // [1] is the index of the valid sample in the list
+ public int[] canSample()
+ {
+ // default to false
+ int[] result = new int[2];
+ result[0] = 0;
+ result[1] = -1;
+
+ for (int i = 0; i < this.samples.size(); i++)
+ {
+ if ((this.agent[row] == samples.get(i)[row]) && (this.agent[col] == samples.get(i)[col]))
+ {
+ result[0] = 1;
+ result[1] = i;
+ return result;
+ }
+ }
+ return result;
+ }
+
+ // returns only the dynamic information directly related to the Node's state.
+ // we need a way to extract just this information for the sake of our closed list
+ public State getState()
+ {
+ return new State(this.agent, this.samples);
+ }
+
+ // we use to override comparisons for priorityQueues so that our heuristic calculations are actually used
+ @Override
+ public int compareTo(Node other)
+ {
+ if (this.fn > other.fn)
+ return 1;
+ else
+ return -1;
+ }
+
+ }
+
+ // helper class for Node
+ class NodeComparator implements Comparator<Node>
+ {
+ // used to sort nodes based on sum of distance traveled + heuristic estimation of work left
+ @Override
+ public int compare(Node a, Node b)
+ {
+ if (a.fn > b.fn)
+ return 1;
+ else
+ return -1;
+ }
+ }
+ // helper class for Node
+ class State
+ {
+ int[] agent;
+ int[][] samples;
+
+ public State(int[] agent, List<int[]> samples)
+ {
+ this.agent = agent;
+ this.samples = new int[samples.size()][];
+
+ // convert List<int[]> into 2D array of ints [][]
+ for (int i = 0; i < samples.size(); i++)
+ {
+ this.samples[i] = samples.get(i).clone();
+ }
+ }
+
+ public boolean inClosed()
+ {
+ for (int i = 0; i < SampleWorld.closed.size(); i++)
+ {
+ if (this.equals(SampleWorld.closed.get(i)))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public boolean equals(State other)
+ {
+ if (this.samples.length != other.samples.length)
+ return false;
+
+ if (Arrays.compare(this.agent, other.agent) != 0)
+ return false;
+
+ for (int i = 0; i < this.samples.length; i++)
+ {
+ if (Arrays.compare(this.samples[i], other.samples[i]) != 0)
+ return false;
+ }
+
+ return true;
+ }
+ }