-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathEx2.java
200 lines (167 loc) · 5.74 KB
/
Ex2.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
/* Ex2
*
* I use a linked list to store the initial direction.
* Nodes in the linked list are removed once the junction is fully traversed.
* This approach minimizes memory usage and eliminates the need to store the x and y coordinates of the junctions.
* This program will fail to complete the Loopy Generator maze because it removes nodes, which can lead to an out-of-bounds error.
*/
import java.util.LinkedList;
import uk.ac.warwick.dcs.maze.logic.IRobot;
public class Ex2 {
private int pollRum = 0; // Number of step
private boolean backtrackMode = false;
LinkedList<Integer> backtrackDirection = new LinkedList<>();
/**
* Logic Controller
*
* @param robot IRobot object
*/
public void controlRobot(IRobot robot) {
int exits = nonwallExits(robot); // Number of nonwall Exits
int direction = IRobot.AHEAD;
if ((robot.getRuns() == 0)&&(pollRum == 0)) // Initialize junction data
backtrackDirection.removeAll(backtrackDirection);
pollRum++; // Number of step += 1
switch (exits) {
case 1 -> direction = deadEnd(robot);
case 2 -> direction = corridor(robot);
case 3, 4 -> direction = junctionAndCrossroad(robot);
default -> System.err.println("Invalid exits value");
}
robot.face(direction);
}
/**
* Call when arrived target
*/
public void reset() {
/*
for (int juction : backtrackDirection) {
System.out.println(juction);
}
System.out.println(backtrackDirection.size());
*/
}
/**
* Find the number of nonwall exits at current location
*
* @param robot IRobot object
* @return nonwall exits
*/
private int nonwallExits(IRobot robot) {
int numOfExits = 0;
for (int i = IRobot.AHEAD; i <= IRobot.LEFT; i++)
if (robot.look(i) != IRobot.WALL)
numOfExits++;
return numOfExits;
}
/**
* Find the number of passage exits at current location
*
* @param robot IRobot object
* @return passage exits
*/
private int passageExits(IRobot robot) {
int numOfPassage = 0;
for (int i = IRobot.AHEAD; i <= IRobot.LEFT; i++)
if (robot.look(i) == IRobot.PASSAGE)
numOfPassage++;
return numOfPassage;
}
/**
* Handle the situation where a dead end is encountered
*
* @param robot IRobot object
* @return The direction the robot should be face to
*/
private int deadEnd(IRobot robot) {
int direction = IRobot.BEHIND;
backtrackMode = true;
if (robot.look(direction) == IRobot.WALL) // Dealing with the opening wall
for (int i = IRobot.AHEAD; i <= IRobot.LEFT; i++)
if (robot.look(i) != IRobot.WALL)
direction = i;
return direction;
}
/**
* Handle the situation where a corridor is encountered
*
* @param robot IRobot object
* @return The direction the robot should be face to
*/
private int corridor(IRobot robot) {
int direction = IRobot.AHEAD;
if (robot.look(direction) == IRobot.WALL) // If the robot is in a cornor
if (robot.look(((direction + 1)%4) + IRobot.AHEAD) != IRobot.WALL) // Turn Right
direction = ((direction + 1)%4) + IRobot.AHEAD;
else
direction = ((direction - 1)%4) + IRobot.AHEAD; // Turn Left
return direction;
}
/**
* Handle the situation where a junction and crossroad is encountered
*
* @param robot IRobot object
* @return The direction the robot should be face to
*/
private int junctionAndCrossroad(IRobot robot) {
if ((backtrackMode)&&(passageExits(robot) == 0)) { // If this junction fully traversed
int direction = backtrackDirection.getLast();
backtrackDirection.removeLast(); // Remove this node
return switch (robot.getHeading() - direction) { // Convert absolute directions to relative directions
case 1, -3 -> IRobot.LEFT;
case 2, -2 -> IRobot.BEHIND;
case 3, -1 -> IRobot.RIGHT;
default -> IRobot.AHEAD;
};
}
else if (backtrackMode) { // If this junction is not a new one
int directions[] = new int[]{IRobot.AHEAD, IRobot.RIGHT, IRobot.BEHIND, IRobot.LEFT};
for (int i = IRobot.AHEAD; i <= IRobot.LEFT; i++) // Remove unconsidered directions
if (robot.look(i) != IRobot.PASSAGE)
directions[i-IRobot.AHEAD] = 0;
backtrackMode = false;
return randomDirection(directions);
}
else { // If this junction is a new one
int directions[] = new int[]{IRobot.AHEAD, IRobot.RIGHT, IRobot.BEHIND, IRobot.LEFT};
for (int i = IRobot.AHEAD; i <= IRobot.LEFT; i++) // Remove unconsidered directions
if (robot.look(i) != IRobot.PASSAGE)
directions[i-IRobot.AHEAD] = 0;
backtrackDirection.add(oppositeDirection(robot.getHeading())); // Add new node
return randomDirection(directions);
}
}
/**
* Get a opposite absolute direction
*
* @param direction Initial absolute directions
* @return Opposite absolute direction
*/
private int oppositeDirection(int direction) {
return switch(direction) {
case IRobot.NORTH -> IRobot.SOUTH;
case IRobot.EAST -> IRobot.WEST;
case IRobot.SOUTH -> IRobot.NORTH;
case IRobot.WEST -> IRobot.EAST;
default -> -1;
};
}
/**
* Get a random direction from given directions
*
* @param ways[] Optional directions
* @return Ramdom direction
*/
private int randomDirection(int ways[]) {
int availableCount = 0;
for (int i : ways) // Count how many direction that can choose
if (i > 0)
availableCount++;
int direction[] = new int[availableCount];
for (int i : ways)
if (i > 0) {
direction[--availableCount] = i; // Copy the avaliable direction
}
return direction[(int)(Math.random()*direction.length)]; // return the random direction
}
}