-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSearch.java
More file actions
125 lines (100 loc) · 4.92 KB
/
Search.java
File metadata and controls
125 lines (100 loc) · 4.92 KB
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
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.PriorityQueue;
/* The Search class implements the A* and Uniform Cost Search search algorithms to search through the state space
* of the game. */
class Search {
/* Search from the agents state to one of the provided targets, using the A* algorithm */
static LinkedList<Character> AStar(Agent agent, LinkedList<Tile> targets, SearchMode mode) throws NoPathFoundException {
// If no targets where provided, don't try to search, simply return
if (targets == null || targets.isEmpty()) {
throw new NoPathFoundException("No targets provided");
}
return findPath(agent, targets, "AStar", mode);
}
/* Perform uniform cost search from the agents state. Considers any tile with unseen tiles around it a target */
static LinkedList<Character> UCS(Agent agent, SearchMode mode) throws NoPathFoundException {
/* Pass in an empty linked list as target. This makes SearchState set the heuristic to zero, which makes
* A* search the same as UCS */
return findPath(agent, new LinkedList<Tile>(), "UCS", mode);
}
/* Perform A* or UCS search, depending on the inputs, and return the path to the target */
private static LinkedList<Character> findPath(Agent agent, LinkedList<Tile> targets, String algorithm, SearchMode mode) throws NoPathFoundException {
SearchState current;
LinkedList<SearchState> newStates;
PriorityQueue<SearchState> open = new PriorityQueue<>();
HashMap<Integer, SearchState> openH = new HashMap<>();
HashSet<SearchState> closed = new HashSet<>();
// Add the starting state to the set of open states
SearchState firstState = new SearchState(agent, targets, mode);
open.add(firstState);
openH.put(firstState.hashCode(), firstState);
// Search as long as there are open states, i.e. states that haven't been expanded
while (!open.isEmpty()) {
// Get the open state with lowest fCost
current = open.poll();
openH.remove(current.hashCode());
closed.add(current);
/* If we have reached a goal, return the path to it. */
switch (algorithm) {
/* For A* the we have reached the goal if the current position is the same as the position of a target */
case "AStar":
for (Tile target : targets) {
if (target.getX() == current.posX && target.getY() == current.posY) {
return current.getPathHere();
}
}
break;
/* For UCS we have reached a goal if the current position has unseen tiles around it */
case "UCS":
if (current.numUnseenTiles() > 0) {
return current.getPathHere();
}
break;
default:
throw new RuntimeException("Unknown search algorithm type");
}
// Expand the current state, and add / update the new states to open
newStates = current.expandState();
for (SearchState newState : newStates) {
// The state already been searched, and is no longer of interest
if (closed.contains(newState)) { // Works because SearchState overrides the equals method.
continue;
}
int hashCode = newState.hashCode();
/* Check if the new state is in the open hash map, so that the costly iteration through the open
* priority queue only needs to be done when we know there is something that needs to be removed */
if (openH.containsKey(hashCode)) {
if (newState.getFCost() < openH.get(hashCode).getFCost()) {
openH.remove(hashCode);
openH.put(hashCode, newState);
Iterator<SearchState> it = open.iterator();
while (it.hasNext()) {
SearchState state = it.next();
if (state.sameState(newState)) {
it.remove();
open.add(newState);
break;
}
}
}
} else if (!openH.containsKey(hashCode)) {
open.add(newState);
openH.put(hashCode, newState);
}
}
}
throw new
NoPathFoundException("Exhausted all possibilities");
}
}
class NoPathFoundException extends RuntimeException {
NoPathFoundException() {
super();
}
NoPathFoundException(String message) {
super(message);
}
}