-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathReroute.java
222 lines (196 loc) · 7.6 KB
/
Reroute.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
/**
* The following code implements a manner of fast reroute in a simulated network.
* Djistra's gives the shortest path initially but after a node breaks, it gives
* a local optimum between then the node preceding and succeeding the broken node.
* This may result in a less than optimal path between the final source and destination
* but takes less time to calculate and hence is faster. This has the final result of
* the network connecting back as soon as possible using the fast reroute method.
*
*/
import java.awt.Color;
import java.awt.Graphics;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import javax.swing.JFrame;
public class Reroute extends JFrame{
final int WIDTH = 1080; // width of window
final int HEIGHT = 720; // height of window
final int TOTAL_NODES = 30; // total number of network nodes
final int TOT_NEIGHBORS = 4; // approximate number of neighbor nodes connected to each node.
final int RADIUS = 8; // radius of each node circle on window
String BROKEN_NODE = "";
Map<String, ArrayList<String>> neighbours; // maps each node to it's list of neighbors
Map<String, int[]> allNodes; // maps each node to it's coordinates
ArrayList<String> path = null; // stores final path to be displayed
public static void main(String[] args) throws IOException {
// generates the random nodes and calculates it's neighbors and draws map
Reroute reroute = new Reroute();
reroute.allNodes = new HashMap<String, int[]>();
reroute.neighbours = new HashMap<String, ArrayList<String>>();
reroute.generatesNodes();
reroute.drawMap();
// takes in source and destination and draws map with shortest route
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.println("Enter source: ");
String src = br.readLine();
System.out.println("Enter destination: ");
String dst = br.readLine();
reroute.path = reroute.djikstra(src, dst);
reroute.drawMap();
// takes in broken node and calculates shortest route between
// the nodes preceding and succeeding the broken node
System.out.println("Enter Broken Node: ");
reroute.BROKEN_NODE = br.readLine();
int broken = reroute.path.indexOf(reroute.BROKEN_NODE);
ArrayList<String> newPath = reroute.djikstra(reroute.path.get(broken - 1), reroute.path.get(broken + 1));
newPath.remove(newPath.size() - 1); // remove dst because it is already in path
reroute.path.remove(broken);
// add newly calculated path to original path, taking care of trace back path
while(newPath.size() > 0){ //reverse traversal
String node = newPath.remove(newPath.size() - 1);
if(! reroute.path.contains(node))
reroute.path.add(broken, node);
else{
int tracebackNode = reroute.path.indexOf(node);
if(tracebackNode > broken) // means nodes around dst of newPath should be skipped
reroute.path.remove(broken);
else{
for(int i=1; i < broken-tracebackNode; i++)
reroute.path.remove(tracebackNode+1); // skips nodes around src of newPath
break;
}
}
}
// draw fast reroute map
reroute.drawMap();
}
// Djikstra's algorithm gives shortest path between src and dst
private ArrayList<String> djikstra(String src, String dst){
Map<String, Integer> minDist = new HashMap<String, Integer>(); //seen but not visited
Map<String, String> visitedFrom = new HashMap<String, String>(); //key visited from value
String currentNode = src;
int totCost = 0;
while(true){
if(currentNode.equals(dst))
break;
double min = WIDTH*HEIGHT; //initially assign a large value to min
for(String key:neighbours.get(currentNode)){
if(key.equals(src) || key.equals(BROKEN_NODE) || (visitedFrom.containsKey(key) && !minDist.containsKey(key)))
continue;
int dist =(int) getDistance(currentNode, key, allNodes);
if(!( minDist.containsKey(key) && (totCost+dist > minDist.get(key)))){
minDist.put(key, totCost+dist);
//key is visited from current node
visitedFrom.put(key, currentNode);
}
}
for(String key:minDist.keySet()){
if(minDist.get(key) < min){
min = totCost = minDist.get(key);
currentNode = key;
}
}
minDist.remove(currentNode);
}
return calcPath(src, dst, visitedFrom);
}
// gives final path between src and dst. Method called by Djikstra's
private ArrayList<String> calcPath(String src, String dst, Map<String, String> visitedFrom){
String currentNode = dst;
ArrayList<String> path = new ArrayList<String>();
while(true){
path.add(currentNode);
if(currentNode.equals(src))
break;
currentNode = visitedFrom.get(currentNode);
}
Collections.reverse(path);
return path;
}
// get euclidean distance between loc1 and loc2 based on the coordinates
private double getDistance(String loc1, String loc2, Map<String, int[]> nodes){
return Math.sqrt(Math.pow(nodes.get(loc2)[1] - nodes.get(loc1)[1], 2)
+ Math.pow(nodes.get(loc2)[0] - nodes.get(loc1)[0], 2));
}
// generate random nodes
private void generatesNodes(){
Random rand = new Random();
for(int i=0; i<=TOTAL_NODES; i++){
String nodeName = "Node"+i;
allNodes.put(nodeName, new int[]{rand.nextInt(WIDTH *9/10)+4*RADIUS, rand.nextInt(HEIGHT *9/10)+4*RADIUS});
neighbours.put(nodeName, new ArrayList<String>());
}
//Compute neighbors
if(TOTAL_NODES <= TOT_NEIGHBORS){
System.err.println("Insufficient nodes");
System.exit(ERROR);
}
for(String currentNode: allNodes.keySet()){
ArrayList<String> connections = new ArrayList<String>(); //list of potential neighbors
ArrayList<Integer> distances = new ArrayList<Integer>(); //and their distances
for(String aNode: allNodes.keySet()){
if(currentNode.equals(aNode))
continue;
int dist = (int) getDistance(currentNode, aNode, allNodes);
int start=0, end = connections.size();
// add aNode in sorted order
while(start <= end){
int mid = start + (end - start)/2;
if(start == end){
connections.add(start, aNode);
distances.add(start, dist);
break;
}
else if(distances.get(mid) < dist)
start = mid+1;
else
end = mid;
}
}
for(int i=0; i<TOT_NEIGHBORS; i++){
String aNode = connections.get(i);
if(!neighbours.get(currentNode).contains(aNode))
neighbours.get(currentNode).add(aNode);
if(!neighbours.get(aNode).contains(currentNode))
neighbours.get(aNode).add(currentNode);
}
}
}
// draws window
public void paint(Graphics g){
//getContentPane().setBackground(Color.YELLOW);
for(String key: allNodes.keySet()){
int x = allNodes.get(key)[0];// - radius;
int y = allNodes.get(key)[1];// - radius;
g.setColor(Color.BLUE);
if(BROKEN_NODE.equals(key))
g.setColor(Color.RED);
if(path != null && path.contains(key))
g.setColor(Color.GREEN);
g.fillOval(x - RADIUS, y - RADIUS, RADIUS*2, RADIUS*2);
g.setColor(Color.DARK_GRAY);
g.drawString(key, x + RADIUS, y + RADIUS);
for(String neighbor: neighbours.get(key)){
g.setColor(Color.BLACK);
if(path != null && path.contains(key) && path.contains(neighbor)
&& Math.abs(path.indexOf(key) - path.indexOf(neighbor)) == 1)
g.setColor(Color.GREEN);
g.drawLine(x, y, allNodes.get(neighbor)[0], allNodes.get(neighbor)[1]);
}
}
}
// helper method for paint
private void drawMap(){
setSize(WIDTH, HEIGHT);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setResizable(false);
setVisible(true);
//repaint();
}
}