Edge of undirected graph in Java - java

Suppose I am writing a Java class to represent an edge of undirected graph. This class Edge contains two vertices to and from.
class Edge<Vertex> {
private final Vertex to, from
public Edge(Vertex to, Vertex from) {
this.to = to;
this.from = from;
}
... // getters, equals, hashCode ...
}
Obviously e1 = new Edge(v1, v2) and e2 = new Edge(v2, v1) are actually the same in an undirected graph. Does it make sense? How would you implement class Edge to meet that requirement?

Perform a sort on the vertices in the constructor based on some unique identifier. This way they are stored consistently regardless of order.
I find this preferable to noMAD's solution because all code interacting with these objects will treat them identically, not just your implementation of equals.
Also, calling your class members to and from is confusing because it sounds like a directed graph. I would rename these to something more generic like vertex1 and vertex2.
public Edge(Vertex x, Vertex y) {
if (vertex2.getId() > vertex1.getId()) {
this.vertex1 = x;
this.vertex2 = y;
} else {
this.vertex1 = y;
this.vertex2 = x;
}
}

I actually wouldn't have this logic in my Edge class but rather some sort of over-seeing class such as a Graph class. The reason for this is because an Edge is just an object with 2 vertices. It doesn't know anything about the rest of the edges in the graph.
So, to expand on #noMad's answer, I would actually put his checkIfSameEdge method in my Graph class:
public class Graph {
private List<Edge> edges;
....
public void addEdge(Edge e) {
for (Edge edge : edges) {
if (isSameEdge(edge, e) {
return; // Edge already in Graph, nothing to do
}
edges.add(e);
}
private boolean isSameEdge(Edge edge1, Edge edge2) {
return ((edge1.to.equals(edge2.to) && edge1.from.equals(edge2.from))
|| (edge1.to.equals(edge2.from) && edge1.from.equals(edge2.to)))
}
}
BTW: I would rename to and from to vertex1 and vertex2 because it is an undirected graph and to and from indicate direction, but that's just my opion.

Well, of the top of my head, the naivest method would be:
protected boolean checkIfSameEdge(Vertex to, Vertex from) {
if(to.equals(this.from) && from.equals(this.to) || to.equals(this.to) && from.equals(this.from)) {
return true;
return false;
}
Obviously you would have to override equals and hashcode

Presumably the nodes contain some sort of scalar values - sort the parameters based on these values (using the compareTo method) and use a factory to create a new instance or return an existing instance.

Related

Bfs game Map implementation in java

I'm trying to implement a bfs algorithm in Java,but it doesn't work as it should be.
I've made a game map comprised of HexTile objects(custom objects,similar to matrix elements). Each HexTile includes one adjacency list containing references to the elements that it's connected to, one function that returns those elements and one function that computes the distance between two HexTiles. The bfs algorithm is excecuted in another class called unit(units are placed in HexTiles) and finds every unit available in a given range from the room(currentTile). It then creates an ArrayList with the given units.
class HexTile {
static final int MAX_NEIGHBOURS = 6;
private HexTile[] neighbours;
public HexTile[] getNeighbours() {
return this.neighbours;
}
public double distanceFromTarget(HexTile target) {
double distance = Math.sqrt(Math.pow((this.getRow() - target.getRow()), 2) + Math.pow((this.getCol() - target.getCol()), 2));
return distance;
}
}
class Unit {
private ArrayList<Unit> unitsWithinRange = new ArrayList<Unit>();
private void findUnitsWithinRange(HexTile currentTile, int attackRange) {
Queue<HexTile> queue = new LinkedList<>();
ArrayList<HexTile> visited = new ArrayList<HexTile>();
queue.add(currentTile);
visited.add(currentTile);
while (!queue.isEmpty()) {
HexTile aux = queue.poll();
for (HexTile auxNeigh : aux.getNeighbours()) {
if (auxNeigh != null && (!visited.contains(auxNeigh))) {
visited.add(auxNeigh);
queue.add(auxNeigh);
}
}
if (aux != null && (currentTile.distanceFromTarget(aux) <= attackRange)) {
Unit auxUnit = aux.getUnitOnTile();
this.unitsWithinRange.add(auxUnit);
}
}
queue.clear();
visited.clear();
}
}
What happens whenever findUnitsWithinRange is excecuted is that it return a list of units,but the units that are in range 1 are not included(direct neighbours to root).Sometimes the program crashes,because units need to be able to know if there are any nearby units,to excecute some other functions.Any advice would be appreciated!

Create a Connected Graph With Two Types Of Edges

I want to build a graph that is connected and can only have horizontal or vertical edges. Edges are tracks/track switches.
There are two types of tracks: NormalTrack and TrackSwitch.
NormalTrack: startPoint, endPoint.
TrackSwitch: startPoint, endPoint, secondEndPoint.
The first endPoint is the standard setting which is passable (there is a set switch command which can change the switch setting).
All tracks (switch is also a track) have a unique identifier starting at 1.
With the exception of the first track, a start or end point must always be connected to a start or end point of an existing track. Only one other track (normal track or track switch) can be connected to a point on a track.
Here is an example and how the graph would look like:
add track (1,1) -> (5,1)
ID -> 1
add switch (5,1) -> (8,1),(5,3)
ID -> 2
add track (1,1) -> (1,-3)
ID -> 3
add track (1,-3) -> (10,-3)
ID -> 4
add track (8,1) -> (10,1)
ID -> 5
add track (10,1) -> (10,-3)
ID -> 6
add track (5,3) -> (8,3)
ID -> 7
I have a class Point which represents a Cartesian Point and a class RailNetwork where I am going to implement the graph.
In my Register class I have a Map<Integer, Track> tracks; in which I save all tracks. In this class I also instantiated RailNetwork network = new RailNetwork();
I've already implemented the command interface. Now, I want to create the rail network.
Could someone show me how to implement this way?
EDIT
Here is my current implementation:
public class RailNetwork {
private Map<Point, List<Point>> edges = new HashMap<>();
// Add edge (two points)
public void addEdge(Point firstCoordinate, Point secondCoordinate) {
edges.computeIfAbsent(firstCoordinate, x -> new ArrayList<>()).add(secondCoordinate);
edges.computeIfAbsent(secondCoordinate, x -> new ArrayList<>()).add(firstCoordinate);
}
// Return all edges
public List<Point> getEdges(Point node) {
return Collections.unmodifiableList(edges.get(node));
}
// Check if a set of edges is still connected after removing them
public boolean isConnectedAfterRemoving(Set<Edge> toRemove) {
Set<Point> notVisited = edges.entrySet()
.stream()
.filter(e -> e.getValue().stream().anyMatch(d -> !toRemove.contains(new Edge(e, d)) &&
!toRemove.contains(new Edge(d, e))))
.map(Map.Entry::getKey).collect(java.util.stream.Collectors.toSet());
if (notVisited.isEmpty())
return true;
visit(notVisited.iterator().next(), notVisited, toRemove);
return notVisited.isEmpty();
}
private void visit(Point next, Set<Point> notVisited, Set<Edge> toRemove) {
if (!notVisited.remove(next))
return;
for (Point point : edges.get(next))
if (!toRemove.contains(new Edge(next, point)) &&
!toRemove.contains(new Edge(point, next)))
visit(point, notVisited, toRemove);
}
private void visitAndRemove(Set<Point> nodes, Point node) {
if (nodes.contains(node)) {
nodes.remove(node);
List<Point> nextNodes = getEdges(node);
for (Point next : nextNodes) {
visitAndRemove(nodes, next);
}
}
}
}
public class Edge {
private final Point source;
private final Point dest;
public Edge(Point source, Point dest) {
this.source = source;
this.dest = dest;
}
#Override
public boolean equals(Object o) {
if (o == this || !(o instanceof Edge)) {
return o == this;
}
Edge edge = (Edge) o;
return Objects.equals(source, edge.source) &&
Objects.equals(dest, edge.dest);
}
#Override
public int hashCode() {
return Objects.hash(source, dest);
}
}
I am not sure why my isConnectedAfterRemoving() method doesn't work. How can I fix this?
I also have a abstract class Track and two subclasses NormalTrack and TrackSwitch.
TrackSwitch(int id, Point startPoint, Point endPoint, Point secondEndPoint, int length, boolean switchEnabled)
NormalTrack(int id, Point startPoint, Point endPoint, int length)
How do I continue now..?
You can create two classes NormalTrack and TrackSwitch and represent each track by an instance of that class. The classes store the id, the starting point and the end point(s) of the track.
Then you probably want to store for each point the list of incoming tracks as well as the list of outgoing tracks. A switch is a bit complicated in this setup since it has two endpoints. You probably also need a flag in the switch that tells which endpoint is currently active. Then, when you iterate over the incoming/outgoing tracks of a point and hit a TrackSwitch then you must first check if the point you are iterating is currently active. If not, you have to skip that.

How to access a getter from an object of a LinkedList

Following Scenario:
Classes:
GamePlayScene (Game logic and collision detection)
Obstacle (has the Rect getObstacleBounds() method to return Bounds)
ObstacleManager (has the LinkedList of obstacle objects)
I want to access the Boundaries (an android.Rect) of an obstacle. All obstacles will be stored into a LinkedList.
Now in the running game I want to access the getObstacleBounds() method in my GameplayScene Class but the problem is that I can't access the obstacle object directly but I obviously have to cycle through all my Objects in the LinkedList in my ObstacleManager.
Due to that I thought I have to also implement a Rect getObstacleBounds() in my Obstacle Manager, from where I cycle through every obstacle in my List and return that Rect.
Is this the right way to do so? I am fairly new to accessing objects and their methods in a LinkedList
If not: How would I implement access to such methods?
Here is my idea what I thought cold work / be the right way.
(Not compilable, more or less pseudo code)
GameplayScene.java
private ObstacleManager obstacleManager;
public GameplayScene() {
obstacleManager = new ObstacleManager();
obstacleManager.addObstacle(new Obstacle(...));
}
public void hitDetection() {
//get the Boundaries of obstacle(s) for collision detection
}
Obstacle.java
//...
public Rect getObstacleBounds() {
return obstacleBounds;
}
ObstacleManager.java
LinkedList<Obstacle> obstacles = new LinkedList<>();
public void update() { //example method
for (Obstacle o : obstacles){
o.update();
}
}
public Rect getObjectBounds() {
return ...
//how do I cycle through my objects and return each Bounds Rect?
}
In the end, depends of what you want to do in hitDetection
If you just want to check if a hit happened
In this case, you can just receive the list of Rect and check if any hit happened
GameplayScene.java
public void hitDetection() {
ArrayList<Rect> listOfBounds = obstacleManager.getObstacleBounds();
for(Rect bound : listOfBounds) {
// Do you stuff
// Note the here, you are receiving a list of Rects only.
// So, you can only check if a hit happened.. but you can't update the Obstacles because here, you don't have access to them.
// Nothing stops you of receiving the whole list of items if you want to(like the reference of ObstacleManager.obstacles).
}
}
ObstacleManager.java
public ArrayList<Rect> getObjectBounds() {
// You can also return just an array.. like Rect[] listToReturn etc
ArrayList<Rect> listToReturn = new ArrayList(obstacles.size());
for (Obstacle item : obstacles) {
listToReturn.add(item.getObjectBounds);
}
return listToReturn;
}
If you need to update some info on the Obstacle that was hit
In this case, you can transfer the hitDetection logic to you ObstacleManager (I'm assuming you check coordinates X and Y to check if obstacle was hit):
GameplayScene.java
public void hitDetection(int touchX, int touchY) {
Obstacle objectHit = obstacleManager.getObstacleTouched(int touchX, int touchY);
if (objectHit != null) {
objectHit.doStuffAlpha();
objectHit.doStuffBeta();
} else {
// No obstacle was hit.. Nothing to do
}
}
ObstacleManager.java
public Obstacle getObstacleTouched(int touchX, int touchY) {
Obstacle obstacleToReturn = null;
for (Obstacle item : obstacles) {
if(item.wasHit(touchX, touchY) {
obstacleToReturn = item;
break;
}
}
return listToReturn;
}
There are several ways to achieve what you want. Some better than others etcIn the end, depends of what you want to do exactly.

A* pathfinding with Multiple Agents

I've currently been learning and programming pathfinding(in Java) using the A* algorithm. A problem I've run into is when multiple entities are trying to pathfind, they both alter the previousNode(the Node that the Node being calculated on came from), messing up the algorithm, and eventually Node A will point to Node B and Node B will point to Node A.
How can I change the algorithm to either
Not use this previousNode system that is littered throughout all of the A * algorithms(that I have seen, that is)
Alter this system to be used concurrently
I am trying to avoid having one entity finish pathfinding, then telling the next entity to pathfinding, and so on. Like doing a wait() - notify() pair in Java.
public Path findPath(int startX, int startY, int goalX, int goalY) {
//Path is basically just a class that contains an ArrayList,
//containing Nodes, which contains the steps to reach a goal.
if(map.getNode(goalX, goalY).isObstacle()) {
return null;
}
map.getNode(startX, startY).setDistanceFromStart(0);
closedList.clear();
openList.clear(); //A List with added getFirst() - gets the first Node in the list
openList.add(map.getNode(startX, startY));
while(openList.size() != 0) {
//Node contains a List that has all of the Nodes around this node, a
//F, G, and H value, and its row(y) and column(x)
Node current = openList.getFirst();
if(current.getX() == goalX && current.getY() == goalY) {
return backtrackPath(current);
}
openList.remove(current);
closedList.add(current);
for(Node neighbor : current.getNeighborList()) {
boolean neighborIsBetter;
//If I've already searched this neighbor/node, don't check it
if(closedList.contains(neighbor)) {
continue;
}
if(!neighbor.isObstacle()) {
float neighborDistanceFromStart = (current.getDistanceFromStart() + map.getDistanceBetween(current, neighbor));
if(!openList.contains(neighbor)) {
openList.add(neighbor);
neighborIsBetter = true;
} else if(neighborDistanceFromStart < current.getDistanceFromStart()) {
neighborIsBetter = true;
} else {
neighborIsBetter = false;
}
if(neighborIsBetter) {
neighbor.setPreviousNode(current);
neighbor.setDistanceFromStart(neighborDistanceFromStart);
neighbor.setHeuristic(getManhattanDistance(neighbor.getX(), neighbor.getY(), goalX, goalY));
}
}
}
}
return null;
}
public Path backtrackPath(Node fromNode) {
Path path = new Path();
while(fromNode.getPreviousNode() != null) {
path.prependWaypoint(fromNode);
fromNode = fromNode.getPreviousNode();
}
return path;
}
I am specifically talking about(within findPath())
if(neighborIsBetter) {
neighbor.setPreviousNode(current); //previousNode is a value in the Node class that points to the Node that it came from
neighbor.setDistanceFromStart(neighborDistanceFromStart);
neighbor.setHeuristic(getManhattanDistance(neighbor.getX(), neighbor.getY(), goalX, goalY));
}
I don't think you can do A* (or any pathfinding algorithm, for that matter) without somehow storing a backpointer for a given path. So that leaves you with two options
Require each agent (Thread, I assume) to create their own copy of the graph to work on. That way each A* call going on won't interfere with one another, as they are working with the fields of the same node on different graphs.
Change your A* code to be able to handle multiple concurrent calls.
Option 1 is fairly self-explanatory and probably the better option. If this is just for you, you should probably just go with that one (instead of trying to make A* fully concurrent on a single graph). This would entail adding map as an input parameter (and requiring that concurrent calls should use a different map instance, either throwing an exception or having unspecified behavior if that doesn't occur). Additionally, you should instantiate closedList and openList as new data structures in each call, rather than share a list.
If that's not to your liking - you really want to fully encapsulate the mutli-call usage into the method itself, I think the simplest way you could do this is require an additional parameter of an id - some unique string that is guaranteed not to be the same as the id of another concurrent call. So the header of A* now looks like:
public Path findPath(final String ID, int startX, int startY, int goalX, int goalY) {
From there, change all of the implementations of each of the settable pathfinding fields in Node to a HashMap with the id as the key. From your code, I'm going to guess that your Node class looks something like this:
public class Node{
//Fields used by the A* call - no problem here
private boolean obstacle;
//Fields *edited* by the A* call
private float distanceFromStart;
private Node previous;
private int heuristic;
//other fields and stuff
public boolean isObstacle(){
return obstacle;
}
public float getDistanceFromStart(){
return distanceFromStart;
}
public void setDistanceFromStart(float f){
distanceFromStart = f;
}
public Node getPrevious(){
return previous;
}
public void setPrevious(Node p){
previous = p;
}
public int getHeuristic(){
return heuristic;
}
public void setHeuristic(int h){
heuristic = h;
}
}
We can edit the edited fields to be able to store many values, by id, as such:
public class Node{
//Fields used by the A* call - no problem here
private boolean obstacle;
//Fields *edited* by the A* call
private HashMap<String,Float> distanceFromStart;
private HashMap<String,Node> previous;
private HashMap<String,Integer> heuristic;
//other fields and stuff
public boolean isObstacle(){
return obstacle;
}
public float getDistanceFromStart(String id){
return distanceFromStart.get(id);
}
public void setDistanceFromStart(String id, float f){
distanceFromStart.put(id, f);
}
public Node getPrevious(String id){
return previous.get(id);
}
public void setPrevious(String id, Node p){
previous.put(id,p);
}
public int getHeuristic(String id){
return heuristic.get(id);
}
public void setHeuristic(String id,int h){
heuristic.put(id,h);
}
}
From there, simply edit your A* method to give the id from the method call to the getters and setters when called for. So long as two concurrent method calls don't have the same id value, they won't interfere with each other. Three things to keep in mind for this to work correctly:
Make sure that every editable field gets this treatment. It won't work if you forget about one. Non-editable fields (fields that don't get altered as a byproduct of running A*) can stay singular.
If you use the the above, you should probably add to the cleanup stage a step of removing all the information for the given ID from the graph, or the nodes' hashmaps will grow larger with each call.
Either way, you still should make openList and closedList new local instances, no matter what concurrent approach you pick. There's nothing to gain from making openList and closedList shared instances, and only bugs can come of it.
List<Node> closedList = new LinkedList<Node>();
List<Node> openList = new LinkedList<Node>();
//Don't have to clear them anymore - they're new lists
openList.add(map.getNode(startX, startY));

Avoiding duplicate entries in an array

I am writing a method that adds Vertex objects to an array. I need to check if the vertex I am adding already exists in the array. I am not sure where I am going wrong. Here is my method:
public void addVertex(Vertex v) {
if (activeVertices >= maxVertices) {
System.out.println("Graph full");
return;
}
for(int i=1; i<vertices.length; i++) {
if(vertices[i] != vertices[i-1]){
vertices[activeVertices] = v; // add vertex to list of vertices
v.graphIndex = activeVertices; // record index of vertex in graph
activeVertices++; // increment vertex count
}
}
}
Vertex class:
public class Vertex {
public String name;
public int graphIndex; // index of adjacency matrix position of node in graph
public Vertex (String s) {
name = s;
graphIndex = -1; // invalid position by default
}
public String toString() {
return name;
}
}
The class that contains the addVertex() method:
public class Graph {
private int maxVertices;
private Vertex[] vertices; // array of nodes
private int[][] edges; // adjacency matrix
int activeVertices;
public Graph(int maxSize) {
maxVertices = maxSize;
vertices = new Vertex[maxVertices];
activeVertices = 0;
}
public void addVertex(Vertex v) {
if (activeVertices >= maxVertices) {
System.out.println("Graph full");
return;
}
for(int i=1; i<vertices.length; i++) {
if(vertices[i] != vertices[i-1]){
vertices[activeVertices] = v; // add vertex to list of vertices
v.graphIndex = activeVertices; // record index of vertex in graph
activeVertices++; // increment vertex count
}
}
}
public void addEdge(Vertex v1, Vertex v2, int w) {
edges[v1.graphIndex][v2.graphIndex] = w;
edges[v2.graphIndex][v1.graphIndex] = w;
}
public Graph minimumSpanningTree() {
Graph mst = new Graph(maxVertices); // create new graph
int[] set = new int[activeVertices];
for (int i=0; i<activeVertices; i++) { // copy nodes to graph
mst.addVertex(vertices[i]);
set[i]=i; // assign each node to its own set
}
PriorityQueue q = new PriorityQueue(maxVertices*maxVertices); // create priority queue
for (int i=0; i<activeVertices; i++) { // copy edges to queue
for (int j=0; j<activeVertices; j++) {
if (edges[i][j]!=0) {
q.enqueue(new Edge(vertices[i],vertices[j],edges[i][j]));
}
}
}
while (!q.isEmpty()) { // iterate over all edges in priority order
Edge e = q.dequeue(); // consider next edge
if (set[e.source.graphIndex]!=set[e.destination.graphIndex]) { // skip edges not connecting different sets
mst.addEdge(e.source, e.destination, e.weight); // add edge to MST
System.out.println("adding "+e);
int setToMerge=set[e.destination.graphIndex]; // rename nodes from "other" set
for (int i=0; i<activeVertices; i++) {
if (set[i]==setToMerge) { // find nodes from "other" set
set[i]=set[e.source.graphIndex]; // reassign nodes
}
}
}
}
return mst;
}
public void print() {
System.out.format(" ");
for (int i=0; i<activeVertices; i++) {
System.out.format("%3s ", vertices[i].name);
}
System.out.format("\n");
for (int j=0; j<activeVertices; j++) {
System.out.format("%3s ", vertices[j].name);
for (int i=0; i<activeVertices; i++) {
System.out.format("%3d ", edges[i][j]);
}
System.out.format("\n");
}
}
}
First, you should be using equals instead of ==. You should write a proper equals method in your Vertex class (use Google to find plenty of tutorials on how to do this).
For example, if you wanted two Vertex objects to be considered equal only when their names were the same, then your equals method would look something like this:
public boolean equals(Object obj) {
if(obj == null) {
return false;
}
if(obj instanceof Vertex) {
Vertex otherVertex = (Vertex) obj;
if(this.name.equals(otherVertex.name)) {
return true;
}
}
return false;
}
If you wanted to compare graphIndex as well, then you would need to check that in the equals method as well.
Assuming you have a proper equals method in your Vertex class, the simplest solution would be to use the ArrayUtils.contains method, from the Apache Commons library (Apache Commons has TONS of useful methods, which can save you a lot of time. You should check it out). This method takes in an array and an Object, and checks if the array contains the object or not.
You're always checking vertices[1] against vertices[0] and adding based on the result. You're not checking for v, and not actually looking in the whole array.
If an == check (identity, not equivalence) is really what you want, then:
public void addVertex(Vertex v) {
if (activeVertices >= maxVertices) {
System.out.println("Graph full");
return;
}
for(int i=0; i<vertices.length; i++) {
if(vertices[i] == v){
// Already have it
return;
}
}
vertices[activeVertices] = v; // add vertex to list of vertices
v.graphIndex = activeVertices; // record index of vertex in graph
activeVertices++; // increment vertex count
}
If you want equivalence instead, replace
if(vertices[i] == v){
with
if(v.equals(vertices[i])){
Side note: Based on your having an activeVertices variable, I suspect you may be better off with ArrayList<Vertex> rather than Vertex[]. That would also give you the contains method (which uses equals), which may be able to replace your loop (if you want an equals, not ==, check).
Whenever you write a value class, i.e. a class that represents a value or quantity of something, you should always override the following methods for your class:
equals(Object o);
hashCode();
Not all classes are value classes. Some represent system resources and others represent actions or processes, but whenever a class is written as an abstraction for a collection of data you should always consider writing the above methods.
The reason is straightforward. Whereas Java primitives have only value, Java reference types (which include all the instances of classes you write yourself) have both value and location. This confers the properties of both equality and identity to reference types and they are very different.
By default, the equals() method in the Object class performs an identity comparison and NOT an equality comparison ... and it's a good thing too. Because any subclass of Object can have vastly different notions of "how instances can be considered equal" there is no straightforward way that Object could have a superclass method that would test equality for any arbitrary Java object. In contrast, it is always straightforward to test for identity. If any two references indicate the same location, then their objects are identical. This exemplifies the different notions of equality and identity.
You need to be able to test whether your Vertex instances are equal and not whether they are identical. For this reason, you really do need to override the equals(Object o) method. If you also override hashCode() (which you should), then you may be able to store your vertices in a HashSet, which would guarantee that no two vertices would be equal.

Categories

Resources