-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMonster.java
More file actions
250 lines (209 loc) · 8.81 KB
/
Monster.java
File metadata and controls
250 lines (209 loc) · 8.81 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
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
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
import java.util.*;
import java.util.Queue;
import java.util.LinkedList;
import java.util.stream.Collectors;
/**
* Class representing the Monster character in the game.
*/
public class Monster extends Player implements MoveStrategy, Graph {
/**
* Constructor for Monster class.
* @param game The instance of the game.
* @param startSite The starting position of the monster.
*/
public Monster(Game game, Site startSite) {
super(game, startSite);
}
@Override
public Site move(Site current, Site target) {
return current;
}
@Override
public Site move() {
Site monster = game.getMonsterSite();
Site rogue = game.getRogueSite();
// Get all possible shortest paths
List<List<Site>> paths = calculateBFSDistanceToRogue(monster, rogue);
if (!paths.isEmpty()) {
// If there are multiple paths, choose the best path based on Priority
return paths.size() > 1 ? chooseBestPathBasedOnPriority(paths) : paths.get(0).get(1);
} else {
System.out.println("No path to Rogue, Rogue wins the game.");
System.exit(0);
return null;
}
}
/**
* Implements the Breadth-First Search algorithm to find the shortest paths from the monster to the rogue.
* @param start The starting position.
* @param end The target position.
* @return List of shortest paths from start to end.
*/
private List<List<Site>> calculateBFSDistanceToRogue(Site start, Site end) {
Map<Site, List<List<Site>>> allPaths = new HashMap<>();
Queue<Site> queue = new LinkedList<>();
Map<Site, Integer> distance = new HashMap<>();
int shortestDistance = Integer.MAX_VALUE;
queue.offer(start);
allPaths.put(start, Arrays.asList(Arrays.asList(start)));
distance.put(start, 0);
while (!queue.isEmpty()) {
Site current = queue.poll();
int Distance = distance.get(current);
if (Distance > shortestDistance) {
continue;
}
for (Site neighbor : game.getDungeon().getNeighbors(current)) {
if (!game.getDungeon().isLegalMove(current, neighbor)) {
continue;
}
int newDistance = Distance + 1;
if (newDistance > shortestDistance) {
continue;
}
if (!distance.containsKey(neighbor) || newDistance == distance.get(neighbor)) {
if (!distance.containsKey(neighbor)) {
distance.put(neighbor, newDistance);
queue.offer(neighbor);
}
List<List<Site>> newPaths = new ArrayList<>();
for (List<Site> path : allPaths.get(current)) {
List<Site> newPath = new ArrayList<>(path);
newPath.add(neighbor);
newPaths.add(newPath);
}
allPaths.computeIfAbsent(neighbor, k -> new ArrayList<>()).addAll(newPaths);
if (neighbor.equals(end) && newDistance < shortestDistance) {
shortestDistance = newDistance;
}
}
}
}
List<List<Site>> shortestPath = allPaths.getOrDefault(end, new ArrayList<>());
int finalShortestDistanceToRogue = shortestDistance;
return shortestPath.stream()
.filter(path -> path.size() == finalShortestDistanceToRogue + 1)
.collect(Collectors.toList());
}
/**
* Chooses the best path based on priority to the rogue, integrating all related decisions within a single method.
* @param paths List of paths.
* @return The best move based on priority.
*/
private Site chooseBestPathBasedOnPriority(List<List<Site>> paths) {
Site rogueSite = game.getRogueSite();
List<Site> adjacentStarSites = game.getDungeon().getAdjacentToStarsSites();
if (adjacentStarSites.isEmpty()) {
// Logic from chooseClosestStepToRogue directly included here when no star sites are adjacent
Site bestMove = null;
int manhattanDistance = Integer.MAX_VALUE;
for (List<Site> path : paths) {
Site nextStep = path.get(1);
int distanceToRogue = computeManhattanDistance(nextStep, rogueSite);
if (distanceToRogue < manhattanDistance) {
bestMove = nextStep;
manhattanDistance = distanceToRogue;
}
}
return bestMove;
}
// Computes the distances from the rogue site to all adjacent star sites
Map<Site, Integer> distancesFromRogue = new HashMap<>();
Map<Site, Integer> fullDistances = game.getDungeon().bfsDistance(rogueSite);
for (Site target : adjacentStarSites) {
distancesFromRogue.put(target, fullDistances.getOrDefault(target, Integer.MAX_VALUE));
}
Site nearestStar = findNearestCorridor(distancesFromRogue, adjacentStarSites);
// Check if there's a single corridor leading to the nearest star
if (isSingleCorridor(distancesFromRogue, adjacentStarSites, nearestStar)) {
return findBestMoveToNearestCorridor(paths, nearestStar);
} else {
// Reusing the logic for finding the closest step to the rogue when there's no single corridor
Site bestMove = null;
int manhattanDistance = Integer.MAX_VALUE;
for (List<Site> path : paths) {
Site nextStep = path.get(1);
int distanceToRogue = computeManhattanDistance(nextStep, rogueSite);
if (distanceToRogue < manhattanDistance) {
bestMove = nextStep;
manhattanDistance = distanceToRogue;
}
}
return bestMove;
}
}
/**
* Checks if there is only one nearest star site to the rogue.
* @param distancesFromRogue Map containing distances from the rogue to adjacent star sites.
* @param starSites List of adjacent star sites.
* @param nearestCorridor The nearest star site.
* @return True if there is only one nearest star site, false otherwise.
*/
private boolean isSingleCorridor(Map<Site, Integer> distancesFromRogue, List<Site> starSites, Site nearestCorridor) {
int minDistance = distancesFromRogue.get(nearestCorridor);
return starSites.stream()
.mapToInt(star -> distancesFromRogue.getOrDefault(star, Integer.MAX_VALUE))
.filter(dist -> dist == minDistance)
.count() == 1;
}
/**
* Finds the nearest star site to the rogue.
* @param distancesFromRogue Map containing distances from the rogue to adjacent star sites.
* @param corridorSites List of adjacent corridor sites.
* @return The nearest star site.
*/
private Site findNearestCorridor(Map<Site, Integer> distancesFromRogue, List<Site> corridorSites) {
Site nearestStar = null;
int nearestDistance = Integer.MAX_VALUE;
for (Site corridorSite : corridorSites) {
int distance = distancesFromRogue.getOrDefault(corridorSite, Integer.MAX_VALUE);
if (distance < nearestDistance) {
nearestDistance = distance;
nearestStar = corridorSite;
}
}
return nearestStar;
}
/**
* Finds the best move to the nearest star site.
* @param paths List of paths.
* @param nearestCorridor The nearest star site.
* @return The best move to the nearest star.
*/
private Site findBestMoveToNearestCorridor(List<List<Site>> paths, Site nearestCorridor) {
Site bestMove = null;
int minDistanceToCorridor = Integer.MAX_VALUE;
for (List<Site> path : paths) {
Site nextStep = path.get(1);
int distanceToNearestCorridor = computeManhattanDistance(nextStep, nearestCorridor);
if (distanceToNearestCorridor < minDistanceToCorridor) {
bestMove = nextStep;
minDistanceToCorridor = distanceToNearestCorridor;
}
}
return bestMove;
}
@Override
public Map bfsDistance(Object start) {
return null;
}
@Override
public List getNeighbors(Object vertex) {
return null;
}
@Override
public List findAccessibleCorridors(Object vertex) {
return null;
}
@Override
public void findImmediateCorridors(Object vertex) {
}
@Override
public List findShortestPathToStart(Object vertex, List point) {
return null;
}
@Override
public List calculateBFSDistanceToRogue(Object vertex, List point) {
return null;
}
}