我正在制造机器人迷宫,机器人自动到达目标而不会撞到墙壁。我希望机器人做一次迷宫,学习正确的路线,然后第二次能够直接到达那里,而不需要任何延迟。我想我可以通过制作三个arraylists来做到这一点。
一个用于机器人访问的所有方块。
两个导致deadend的所有正方形。
三个用于机器人的所有方向。
如果在第一个arraylist中找到导致死胡同的方块,那么我可以删除第三个arraylist中的相同索引。这样,第二次,我可以迭代第三个Arraylist。
我的完整代码如下:
import java.util.ArrayList;
import java.util.*;
import java.util.Iterator;
import java.util.stream.IntStream;
public class Explorer {
private int pollRun = 0; // Incremented after each pass.
private RobotData robotData; // Data store for junctions.
private ArrayList<Integer> nonWallDirections;
private ArrayList<Integer> passageDirections;
private ArrayList<Integer> beenbeforeDirections;
private Random random = new Random();
int [] directions = {IRobot.AHEAD, IRobot.LEFT, IRobot.RIGHT, IRobot.BEHIND};
private ArrayList<Square> correctSquares;
private ArrayList<Square> wrongSquares;
private ArrayList<Integer> correctDirections;
public void controlRobot (IRobot robot) {
// On the first move of the first run of a new maze.
if ((robot.getRuns() == 0) && (pollRun ==0))
robotData = new RobotData();
pollRun++; /* Increment poll run so that the data is not reset
each time the robot moves. */
int exits = nonwallExits(robot);
int direction;
if ((robot.getRuns() != 0))
direction = grandfinale(robot);
nonWallDirections = new ArrayList<Integer>();
passageDirections = new ArrayList<Integer>();
beenbeforeDirections = new ArrayList<Integer>();
correctSquares = new ArrayList<Square>();
correctDirections = new ArrayList<Integer>();
// Adding each direction to the appropriate state ArrayList.
for(int item : directions) {
if(robot.look(item) != IRobot.WALL) {
nonWallDirections.add(item);
}
}
for(int item : directions) {
if(robot.look(item) == IRobot.PASSAGE) {
passageDirections.add(item);
}
}
for(int item : directions) {
if(robot.look(item) == IRobot.BEENBEFORE) {
beenbeforeDirections.add(item);
}
}
// Calling the appropriate method depending on the number of exits.
if (exits < 2) {
direction = deadEnd(robot);
} else if (exits == 2) {
direction = corridor(robot);
} else {
direction = junction(robot);
robotData.addJunction(robot);
robotData.printJunction(robot);
}
robot.face(direction);
addcorrectSquares(robot);
correctDirections.add(direction);
}
/* The specification advised to have to seperate controls: Explorer and Backtrack
and a variable explorerMode to switch between them.
Instead, whenever needed I shall call this backtrack method.
If at a junction, the robot will head back the junction as to when it first approached it.
When at a deadend or corridor, it will follow the beenbefore squares until it
reaches an unexplored path. */
public int backtrack (IRobot robot) {
if (nonwallExits(robot) > 2) {
addwrongSquares(robot);
return robotData.reverseHeading(robot);
} else {
do {
addwrongSquares(robot);
return nonWallDirections.get(0);
} while (nonwallExits(robot) == 1);
}
}
// Deadend method makes the robot follow the only nonwall exit.
public int deadEnd (IRobot robot) {
return backtrack(robot);
}
/* Corridor method will make the robot follow the one and only passage.
The exception is at the start. Sometimes, the robot will start with
two passages available to it in which case it will choose one randomly.
If there is no passage, it will follow the beenbefore squares
until it reaches an unexplored path.*/
public int corridor (IRobot robot) {
if (passageExits(robot) == 1) {
return passageDirections.get(0);
} else if (passageExits(robot) == 2) {
int randomPassage = random.nextInt(passageDirections.size());
return passageDirections.get(randomPassage);
} else {
return backtrack(robot);
}
}
/* Junction method states if there is more than one passage, it will randomly select one.
This applies to crossroads as well as essentially they are the same.
If there is no passage, it will follow the beenbefore squares until it reaches an unexplored
path. */
public int junction(IRobot robot) {
if (passageExits(robot) == 1) {
return passageDirections.get(0);
} else if (passageExits(robot) > 1) {
int randomPassage = random.nextInt(passageDirections.size());
return passageDirections.get(randomPassage);
} else {
return backtrack(robot);
}
}
// Calculates number of exits.
private int nonwallExits (IRobot robot) {
int nonwallExits = 0;
for(int item : directions) {
if(robot.look(item) != IRobot.WALL) {
nonwallExits++;
}
}
return nonwallExits;
}
// Calculates number of passages.
private int passageExits (IRobot robot) {
int passageExits = 0;
for(int item : directions) {
if(robot.look(item) == IRobot.PASSAGE) {
passageExits++;
}
}
return passageExits;
}
// Calculates number of beenbefores.
private int beenbeforeExits (IRobot robot) {
int beenbeforeExits = 0;
for(int item : directions) {
if(robot.look(item) == IRobot.PASSAGE) {
beenbeforeExits++;
}
}
return beenbeforeExits;
}
// Resets Junction Counter in RobotData class.
public int reset() {
return robotData.resetJunctionCounter();
}
public void addcorrectSquares(IRobot robot) {
Square newSquare = new Square(robot.getLocation().x, robot.getLocation().y);
correctSquares.add(newSquare);
}
public void addwrongSquares(IRobot robot) {
Square badSquare = new Square(robot.getLocation().x, robot.getLocation().y);
wrongSquares.add(badSquare);
}
public int grandfinale (IRobot robot) {
IntStream.range(0, correctSquares.size())
.map(index -> correctSquares.size() - index - 1)
.filter(index -> (((wrongSquares.x).contains(correctSquares.x)) && ((wrongSquares.y).contains(correctSquares.y))).get(index))
.forEach(index -> correctDirections.remove(index));
Iterator<Integer> routeIterator = correctDirections.iterator();
while (routeIterator.hasNext()) {
break;
}
return (routeIterator.next());
}
}
class RobotData {
/* It was advised in the specification to include the variable:
private static int maxJunctions = 10000;
However, as I am not using arrays, but ArrayLists, I do not
need this. */
private static int junctionCounter = 0;
private ArrayList<Junction> junctionList = new ArrayList<Junction>();
// Resets the Junction counter.
public int resetJunctionCounter() {
return junctionCounter = 0;
}
// Adds the current junction to the list of arrays.
public void addJunction(IRobot robot) {
Junction newJunction = new Junction(robot.getLocation().x, robot.getLocation().y, robot.getHeading());
junctionList.add(newJunction);
junctionCounter++;
}
// Gets the junction counter for Junction info method in Junction class.
public int getJunctionCounter (IRobot robot) {
return junctionCounter;
}
// Prints Junction info.
public void printJunction(IRobot robot) {
String course = "";
switch (robot.getHeading()) {
case IRobot.NORTH:
course = "NORTH";
break;
case IRobot.EAST:
course = "EAST";
break;
case IRobot.SOUTH:
course = "SOUTH";
break;
case IRobot.WEST:
course = "WEST";
break;
}
System.out.println("Junction " + junctionCounter + " (x=" + robot.getLocation().x + ", y=" + robot.getLocation().y +") heading " + course);
}
/* Iterates through the junction arrayList to find the
heading of the robot when it first approached the junction.
It does this by finding the first junction in the ArrayList
that has the same x and y coordinates as the robot.*/
public int searchJunction(IRobot robot) {
Junction currentJunction = null;
Iterator<Junction> junctionIterator = junctionList.iterator();
while (junctionIterator.hasNext()) {
currentJunction = junctionIterator.next();
if ((((currentJunction.x)==(robot.getLocation().x))) && ((currentJunction.y)==(robot.getLocation().y)))
break;
}
return currentJunction.arrived;
}
// Returns the reverse of the heading the robot had when first approaching the junction.
public int reverseHeading(IRobot robot) {
int firstHeading = searchJunction(robot);
int reverseHeading = 1; // Random integer to Iniitalise variable.
switch (firstHeading) {
case IRobot.NORTH:
if (robot.getHeading() == IRobot.NORTH)
reverseHeading = IRobot.BEHIND;
else if (robot.getHeading() == IRobot.EAST)
reverseHeading = IRobot.RIGHT;
else if (robot.getHeading() == IRobot.SOUTH)
reverseHeading = IRobot.AHEAD;
else
reverseHeading = IRobot.LEFT;
break;
case IRobot.EAST:
if (robot.getHeading() == IRobot.NORTH)
reverseHeading = IRobot.LEFT;
else if (robot.getHeading() == IRobot.EAST)
reverseHeading = IRobot.BEHIND;
else if (robot.getHeading() == IRobot.SOUTH)
reverseHeading = IRobot.RIGHT;
else
reverseHeading = IRobot.AHEAD;
break;
case IRobot.SOUTH:
if (robot.getHeading() == IRobot.NORTH)
reverseHeading = IRobot.AHEAD;
else if (robot.getHeading() == IRobot.EAST)
reverseHeading = IRobot.LEFT;
else if (robot.getHeading() == IRobot.SOUTH)
reverseHeading = IRobot.BEHIND;
else
reverseHeading = IRobot.RIGHT;
break;
case IRobot.WEST:
if (robot.getHeading() == IRobot.NORTH)
reverseHeading = IRobot.RIGHT;
else if (robot.getHeading() == IRobot.EAST)
reverseHeading = IRobot.AHEAD;
else if (robot.getHeading() == IRobot.SOUTH)
reverseHeading = IRobot.LEFT;
else
reverseHeading = IRobot.BEHIND;
break;
}
return reverseHeading;
}
}
class Junction {
int x;
int y;
int arrived;
public Junction(int xcoord, int ycoord, int course) {
x = xcoord;
y = ycoord;
arrived = course;
}
}
class Square {
int x;
int y;
public Square(int cordx, int cordy){
x = cordx;
y = cordy;
}
}
答案 0 :(得分:1)
IntStream.range(0, al1.length)
.filter(index -> al2.contains(al1.get(index)))
.forEach(index -> al3.remove(index));
稍微复杂一点如果从al3中删除元素会将它们向左移动但在这种情况下只是在.filter之前反转流 - 然后它将从末尾删除。最简单的方法是:
.map(index -> al1.length - index - 1)
没有Streams,等价物将是
for (int i = 0; i < al1.length; i++) {
if (al2.contains(al1.get(i))) {
al3.remove(i);
}
}
同样,如果你需要从右边删除那么for循环需要倒计时而不是up。
如果没有关于arraylist结构的更多细节,很难再提供任何提示。