-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathAStar.java
156 lines (139 loc) · 5.06 KB
/
AStar.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
import java.util.ArrayList;
import java.util.Comparator;
import java.util.PriorityQueue;
public class AStar extends SearchAlg implements Searchable<AStar.Node> {
private Node root;
private static int lengthAcross;
private static int area;
private static PriorityQueue<Node> openList;
private static boolean isSolution;
protected class Node extends BasicNode {
private int moveCost;
private int manhattan;
public Node() {
towerBlocks = new ArrayList<>();
}
private int getWeight() {
return moveCost + manhattan;
}
}
//class to help with prioritising promising nodes
private class WeightComparator implements Comparator<Node> {
@Override
public int compare(Node x, Node y) {
return Integer.compare(x.getWeight(), y.getWeight());
}
}
public AStar(PuzzleBoard newBoard) {
super(newBoard.getObstacles());
root = new Node();
root.agent = newBoard.getAgent();
root.towerBlocks = newBoard.getBlocks();
lengthAcross = newBoard.getLengthAcross();
area = lengthAcross * lengthAcross;
openList = new PriorityQueue<>(new WeightComparator());
nodesPassed = 0;
isSolution = false;
}
//adds nodes to pen list and expands to most promising one of them
//when solution found calls printing function
public void startSearch() {
root.moveCost = 0;
root.manhattan = heuristicSum(root.towerBlocks);
openList.add(root);
while (!openList.isEmpty() && !isSolution) {
doAStar(openList.poll());
}
//when solution is found get the final node and trace it back to the start
BasicNode goal = null;
for (Node i : openList) {
if (i.manhattan == 0) {
goal = i;
break;
}
}
traceRouteFrom(goal);
}
//checks possible Adjacent movements from current position of agent
private void doAStar(Node current) {
nodesPassed++;
int agentPos = current.agent.getCurrPos();
//checks for when agent is next to borders
//prevents moving out of the bounds of the board or into obstacles
//up
if (agentPos > (lengthAcross - 1) && noObstacle(agentPos - lengthAcross)) {
makeSwitches(new Node(), current, agentPos - lengthAcross, agentPos);
}
//left
if (agentPos % lengthAcross != 0 && noObstacle(agentPos - 1)) {
makeSwitches(new Node(), current, agentPos - 1, agentPos);
}
//down
if (agentPos < (area - lengthAcross) && noObstacle(agentPos + lengthAcross)) {
makeSwitches(new Node(), current, agentPos + lengthAcross, agentPos);
}
//right
if (agentPos % lengthAcross != (lengthAcross - 1) && noObstacle(agentPos + 1)) {
makeSwitches(new Node(), current, agentPos + 1, agentPos);
}
}
//manhattan distance for all movable Blocks
private int heuristicSum(ArrayList<Block> blocks) {
int sum = 0;
for (Block i : blocks)
sum += calcManhattan(i.getCurrPos(), i.getGoalPos());
return sum;
}
//returns manhattan distance of one block
private int calcManhattan(int current, int goal) {
if (current == goal) {
return 0;
} else {
int steps = 0;
//row alignment
while (current / lengthAcross != goal / lengthAcross) {
if (current < goal) {
current += lengthAcross;
} else {
current -= lengthAcross;
}
steps++;
}
//column align and return
return steps + Math.abs(current - goal);
}
}
//of manhattan distance for all movable blocks is 0 then they are at their goal positions
public boolean checkSolution(Node current) {
return current.manhattan == 0;
}
//handles scenario when agent swaps with a block
//only recalculates Manhattan distance when a block has been moved
public void makeSwitches(Node child, Node parent, int futureAgentPos, int currentAgentPos) {
if (isSolution)
return;
boolean recalculate = false;
child.agent = new Block(futureAgentPos);
child.parent = parent;
child.moveCost = parent.moveCost + 1;
for (Block i : parent.towerBlocks) {
if (i.getCurrPos() == futureAgentPos) {
recalculate = true;
child.towerBlocks.add(new Block(currentAgentPos, i.getGoalPos()));
} else {
child.towerBlocks.add(new Block(i.getCurrPos(), i.getGoalPos()));
}
}
if (recalculate) {
child.manhattan = heuristicSum(child.towerBlocks);
} else {
child.manhattan = parent.manhattan;
}
if (checkSolution(child)) {
isSolution = true;
openList.add(child);
return;
}
openList.add(child);
}
}