Java solving a maze with recursion problem - java

I have an assignment where I am supposed to be able to display the path of a maze from the entrance to the exit and I have gotten it to work to a degree but when the maze gets more complicated with dead ends and such the program goes into infinite recursion. If you could give me any help to point me in the right direction it would be much appreciated.
Mu current theory can be found in the Room class.
Here is the Room class where the references to each room connecting the maze are stored, kind of like a linked list linked in 6 directions, north, south, east, west, up, and down.
import java.util.ArrayList;
public class OurRoom
{
private OurRoom exits[];
private String name;
private static ArrayList<OurRoom> list;
public OurRoom()
{
this(null);
}
public OurRoom(String name)
{
this.name = name;
this.list = new ArrayList<OurRoom>();
exits = new OurRoom[Direction.values().length];
for(OurRoom exit : exits)
{
exit = null;
}
}
public void connectTo(OurRoom theOtherRoom, Direction direction)
{
exits[direction.ordinal()] = theOtherRoom;
theOtherRoom.exits[direction.getOpposite().ordinal()] = this;
}
public OurRoom getExit(Direction direction)
{
return exits[direction.ordinal()];
}
public boolean lookExit(Direction direction)
{
return exits[direction.ordinal()] != null;
}
public String getName() {
return name;
}
public OurRoom solveRecursively(OurRoom exit) {
list.add(this);
if(this == exit) {
return this;
}else {
OurRoom temp = null;
if(lookExit(Direction.east)) {
temp = exits[Direction.east.ordinal()].solveRecursively(exit);
}
else if(lookExit(Direction.up)) {
temp = exits[Direction.up.ordinal()].solveRecursively(exit);
}
else if(lookExit(Direction.south)) {
temp = exits[Direction.south.ordinal()].solveRecursively(exit);
}
else if(lookExit(Direction.down)) {
temp = exits[Direction.down.ordinal()].solveRecursively(exit);
}
else if(lookExit(Direction.west)) {
temp = exits[Direction.west.ordinal()].solveRecursively(exit);
}
else if(lookExit(Direction.north)) {
temp = exits[Direction.north.ordinal()].solveRecursively(exit);
}
return temp;
}
}
public ArrayList<OurRoom> getList() {
return list;
}
}
Here is the Direction enum
public enum Direction
{
north, south, east, west, up, down;
public Direction getOpposite()
{
switch(this)
{
case north:
return south;
case south:
return north;
case east:
return west;
case west:
return east;
case up:
return down;
case down:
return up;
default:
return this;
}
}
}
And here is an example of how the maze is built.
import java.util.ArrayList;
import java.util.Iterator;
public class OurMaze
{
private OurRoom entrance, exit;
public OurMaze()
{
this(1);
}
public OurMaze(int mazeNumber)
{
entrance = null;
exit = null;
switch(mazeNumber)
{
case 0:
break;
case 1:
this.buildMaze1();
break;
default:
}
}
public OurRoom getEntrance()
{
return entrance;
}
public OurRoom getExit()
{
return exit;
}
public Iterator<OurRoom> findPathRecursively() {
entrance.solveRecursively(exit);
ArrayList<OurRoom> list = entrance.getList();
return list.iterator();
}
private void buildMaze1()
{
OurRoom room1, room2;
room1 = new OurRoom("Room 1");
room2 = new OurRoom("Room 2");
room1.connectTo(room2, Direction.north);
entrance = room1;
exit = room2;
}
public static void main(String[] args) {
OurMaze maze = new OurMaze(1);
}
}

You just need to keep two-dimensional array with values indicating whether the cell was visited or not: you don't want to go through the same cell twice.
Apart from that, it's just breadth-first-search (depth-first-search is fine too, if you don't want shortest path).
Some links
http://en.wikipedia.org/wiki/Flood_fill
http://en.wikipedia.org/wiki/Breadth-first_search
http://en.wikipedia.org/wiki/Depth-first_search
Sample search routine.
void dfs(int i, int j) {
if cell(i, j) is outside of maze or blocked {
return
}
if visited[i][j] {
return
}
visited[i][j] = true;
dfs(i + 1, j);
dfs(i - 1, j);
dfs(i, j + 1);
dfs(i, j - 1);
}
Path itself can be found if, like with visited, for each cell you keep cell from which you came to it. So, printing would look like this (just a pseudocode).
var end = exit_point;
while (end != start_point) {
print end;
end = came_from[end];
}
edit
The code above is for two-dimensional maze and I just noticed that you have three-dimensional version. But it's easy to introduce third coordinate in the example above.
Let me know if there're any difficulties.

Others have described appropriate approaches to solving this problem, but I think it's worth pointing out exactly why your program won't scale to more complex mazes.
As duffymo hinted, the problem is that your algorithm doesn't do any backtracking correctly - when it takes a branch that turns out to be a dead end, and returns to a previous square, it doesn't remember this at all. And since it tries the exits in a fixed order, it will always retry that failed exit immediately.
Look at how the solveRecursively function is defined, and you'll see that from any given room, only one direction would ever be tried. If a room has an exit to the east, then it doesn't even matter if it has any other exits since the if-else block would never consider them.
So as it turns out, your solving logic will fail (i.e go into an infinite loop between two rooms) in any case where the correct solution isn't the "first" exit from each room in the order you've defined there.
(A quick fix would be to store a simple boolean flag against each room/direction. Set it before you call the recursive call, then if you end up back in that room again, you know that direction doesn't work out and can let the if block fall through to try one of the other exits. Refactoring this to use typical BFS logic, as Nikita suggests, would be better overall)

I'd bet you need a tree of some kind to keep track of where you've been.
When recursion fails, it usually means that the person writing the method didn't expression the stopping condition properly. What's yours?
I think this was the first game I ever encountered on a computer. It was an IBM mainframe at the school where I got my undergraduate degree. The I/O was on a paper teletype. Many salt tears were wept at the account dollars that were flushed away playing this maze game. Great fun.

When solving the maze, represent it as a 6-ary graph where each node is a room and each edge represents travel in one of the six directions. You can then apply some of the well known algorithms for finding shortest paths.
This page describes various solutions for finding paths through graphs that are structured as such. Your graph is easier than the ones that describe real-world maps, since the cost of traveling down any edge is equal to the cost of traveling down any other edge.
Be especially sure to look at Dijkstra's algorithm.

Related

MinMax - generating game tree

I try to write a MinMax program in Java for connect-four game, but this program should also be applicable to other games. But, I encountered a problem, which I cannot pass for few days. The values for nodes are not set properly. I am sharing my piece of code which is responsible for generating a tree.
Maybe you will notice where I made a mistake.
If anyone could help me with this, I will be very happy.
public Node generateTree(Board board, int depth) {
Node rootNode = new Node(board);
generateSubtree(rootNode, depth);
minMax(rootNode, depth);
return rootNode;
}
private void generateSubtree(Node subRootNode, int depth) {
Board board = subRootNode.getBoard();
if (depth == 0) {
subRootNode.setValue(board.evaluateBoard());
return;
}
for (Move move : board.generateMoves()) {
Board tempBoard = board.makeMove(move);
Node tempNode = new Node(tempBoard);
subRootNode.addChild(tempNode);
generateSubtree(tempNode, depth - 1);
}
}
public void minMax(Node rootNode, int depth) {
maxMove(rootNode, depth);
}
public int maxMove(Node node, int depth) {
if (depth == 0) {
return node.getValue();
}
int bestValue = Integer.MIN_VALUE;
for (Node childNode : node.getChildren()) {
int tempValue = minMove(childNode, depth - 1);
childNode.setValue(tempValue);
if (tempValue > bestValue) {
bestValue = tempValue;
}
}
return bestValue;
}
public int minMove(Node node, int depth) {
if (depth == 0) {
return node.getValue();
}
int bestValue = Integer.MAX_VALUE;
for (Node childNode : node.getChildren()) {
int tempValue = maxMove(childNode, depth - 1);
childNode.setValue(tempValue);
if (tempValue < bestValue) {
bestValue = tempValue;
}
}
return bestValue;
}
Board class is the representation of the board state.
Move class hold the move to perform (integer [0-8] for tic-tac-toe, [0-6] for Connect Four).
Node class holds the Move and value how good given move is. Also, holds all its children.
In the code I use this method like this:
Node newNode = minmax.generateTree(board, depth, board.getPlayer());
Move newMove = new TicTacToeMove(board.getPlayer(), newNode.getBestMove().getMove(), depth);
board = board.makeMove(newMove);
And when it's obvious that given move is a losing move (or winning), I do not receive this move.
Alright, you did make a couple of mistakes. About 3-4, depending on how you count ;) Took me a bit of debugging to figure it all out, but I finally got an answer for you :D
Mistake #1: All your parents always get twins (that poor mother)
This is only the case with the code you uploaded, not the code in your question, so maybe we count it as half a mistake?
Since your trees aren't that big yet and it won't destroy your algorithm, this was the least important one anyway. Still, it's something to watch out for.
In your uploaded code, you do this in your generateSubtree method:
Node tempNode = new Node(tempBoard, move, subRootNode);
subRootNode.addChild(tempNode);
As that constructor already adds the child to the subRootNode, the second line always adds it a second time.
Mistake #2: That darn depth
If you haven't reached your desired depth yet, but the game is already decided, you completely ignore that. So in your provided example that won't work, if - for example - you look at making move 7 instead of 3 (which would be the 'right' move) and then the opponent does move 3, you don't count it as -10 points because you haven't reached your depth yet. It still won't get any children, so even in your minmax, it will never realize it's a screwed up way to go.
Which is why every move is 'possible' in this scenario and you just get the first one returned.
In the previous moves, there was luckily always a way to reach a losing move with your opponents third move (aka move #5), which is why those were called correctly.
Alright, so how do we fix it?
private void generateSubtree(Node subRootNode, int depth, int player) {
Board board = subRootNode.getBoard();
List<Move> moveList = board.generateMoves();
if (depth == 0 || moveList.isEmpty()) {
subRootNode.setValue(board.evaluateBoard(player));
return;
}
for (Move move : moveList) {
Board tempBoard = board.makeMove(move);
Node tempNode = new Node(tempBoard, move, subRootNode);
generateSubtree(tempNode, depth - 1, player);
}
}
Just get the move list beforehand and then look if it's empty (your generateMoves() method of the Board class (thank god you provided that by the way ;)) already checks if the game is over, so if it is, there won't be any moves generated. Perfect time to check the score).
Mistake #3: That darn depth again
Didn't we just go over this?
Sadly, your Min Max algorithm itself has the same problem. It will only even look at your values if you have reached the desired depth. You need to change that.
However, this is a bit more complicated, since you don't have a nice little method that already checks if the game is finished for you.
You could check to see if your value was set, but here's the problem: It might be set to 0 and you need to take that into account as well (so you can't just do if (node.getValue() != 0)).
I just set the initial value of each node to -1 instead and did a check against -1. It's not... you know... pretty. But it works.
public class Node {
private Board board;
private Move move;
private Node parent;
private List<Node> children = new ArrayList<Node>();;
private boolean isRootNode = false;
private int value = -1;
...
And this in the maxMove:
public int maxMove(Node node, int depth) {
if (depth == 0 || node.getValue() != -1) {
return node.getValue();
}
int bestValue = Integer.MIN_VALUE;
for (Node childNode : node.getChildren()) {
int tempValue = minMove(childNode, depth - 1);
childNode.setValue(tempValue);
if (tempValue > bestValue) {
bestValue = tempValue;
}
}
return bestValue;
}
It works the same for minMove of course.
Mistake #4: The player is screwing with you
Once I changed all that, it took me a moment with the debugger to realize why it still wouldn't work.
This last mistake was not in the code you provided in the question btw. Shame on you! ;)
Turns out it was this wonderful piece of code in your TicTacToeBoard class:
#Override
public int getPlayer() {
// TODO Auto-generated method stub
return 0;
}
And since you called
MinMax minmax = new MinMax();
Node newNode = minmax.generateTree(board, (Integer) spinner.getValue(), board.getPlayer());
in your makeMove method of TicTacToeMainWindow, you would always start out with the wrong player.
As you can probably guess yourself, you just need to change it to:
public int getPlayer() {
return this.player;
}
And it should do the trick.
Also:
Just a couple of things I'd like to remark at this point:
Clean up your imports! Your TicTacToe actually still imports your ConnectFour classes! And for no reason.
Your board is rotated and mirrored in your board array. WHY? You know how annoying that is to debug? I mean, I guess you probably do :D Also, if you're having problems with your code and you need to debug it's extremely helpful to overwrite your boards toString() method, because that will give you a very nice and easy way to look at your board in the debugger. You can even use it to rotate it again, so you see don't have to look at it lying on the side ;)
While we're at the subject of the board... this is just me but... I always tried clicking on the painted surface first and then had to remember: Oh yeah, there were buttons :D I mean... why not just put the images on the buttons or implement a MouseListener so you can actually just click on the painted surface?
When providing code and/or example images, please take out your test outputs. I'm talking about the Player 1 won!s of course ;)
Please learn what a complete, verifiable and minimal example is for the next time you ask a question on StackOverflow. The one in your question wasn't complete or verifiable and the one you provided on github was... well... not complete (the images were missing), but complete enough. It was also verifiable, but it was NOT minimal. You will get answers a LOT sooner if you follow the guidelines.

Shortest path in Rat in a Maze with option to remove one wall

This is the problem:
You have maps of parts of the space station, each starting at a prison exit and ending at the door to an escape pod. The map is represented as a matrix of 0s and 1s, where 0s are passable space and 1s are impassable walls. The door out of the prison is at the top left (0,0) and the door into an escape pod is at the bottom right (w-1,h-1).
Write a function answer(map) that generates the length of the shortest path from the prison door to the escape pod, where you are allowed to remove one wall as part of your remodeling plans. The path length is the total number of nodes you pass through, counting both the entrance and exit nodes. The starting and ending positions are always passable (0). The map will always be solvable, though you may or may not need to remove a wall. The height and width of the map can be from 2 to 20. Moves can only be made in cardinal directions; no diagonal moves are allowed.
To Summarize the problem: It is a simple rat in a maze problem with rat starting at (0,0) in matrix and should reach (w-1,h-1). Maze is a matrix of 0s and 1s. 0 means path and 1 means wall.You have the ability to remove one wall(change it from 0 to 1). Find the shortest path.
I've solved the problem but 3 of 5 testcases fail and I don't know what those test cases are. and I'm unable to figure out why. Any help would be greatly appreciated.Thanks in Advance. Here is my code:
import java.util.*;
class Maze{//Each cell in matrix will be this object
Maze(int i,int j){
this.flag=false;
this.distance=0;
this.x=i;
this.y=j;
}
boolean flag;
int distance;
int x;
int y;
}
class Google4_v2{
public static boolean isPresent(int x,int y,int r,int c)
{
if((x>=0&&x<r)&&(y>=0&&y<c))
return true;
else
return false;
}
public static int solveMaze(int[][] m,int x,int y,int loop)
{
int r=m.length;
int c=m[0].length;
int result=r*c;
int min=r*c;
Maze[][] maze=new Maze[r][c];//Array of objects
for(int i=0;i<r;i++)
{
for(int j=0;j<c;j++)
{
maze[i][j]=new Maze(i,j);
}
}
Queue<Maze> q=new LinkedList<Maze>();
Maze start=maze[x][y];
Maze[][] spare=new Maze[r][c];
q.add(start);//Adding source to queue
int i=start.x,j=start.y;
while(!q.isEmpty())
{
Maze temp=q.remove();
i=temp.x;j=temp.y;
int d=temp.distance;//distance of a cell from source
if(i==r-1 &&j==c-1)
{
result=maze[i][j].distance+1;
break;
}
maze[i][j].flag=true;
if(isPresent(i+1,j,r,c)&&maze[i+1][j].flag!=true)//check down of current cell
{
if(m[i+1][j]==0)//if there is path, add it to queue
{
maze[i+1][j].distance+=1+d;
q.add(maze[i+1][j]);
}
if(m[i+1][j]==1 && maze[i+1][j].flag==false && loop==0)//if there is no path, see if breaking the wall gives a path.
{
int test=solveMaze(m,i+1,j,1);
if(test>0)
{
test+=d+1;
min=(test<min)?test:min;
}
maze[i+1][j].flag=true;
}
}
if(isPresent(i,j+1,r,c)&&maze[i][j+1].flag!=true)//check right of current cell
{
if(m[i][j+1]==0)
{
maze[i][j+1].distance+=1+d;
q.add(maze[i][j+1]);
}
if(m[i][j+1]==1 && maze[i][j+1].flag==false && loop==0)
{
int test=solveMaze(m,i,j+1,1);
if(test>0)
{
test+=d+1;
min=(test<min)?test:min;
}
maze[i][j+1].flag=true;
}
}
if(isPresent(i-1,j,r,c)&&maze[i-1][j].flag!=true)//check up of current cell
{
if(m[i-1][j]==0)
{
maze[i-1][j].distance+=1+d;
q.add(maze[i-1][j]);
}
if(m[i-1][j]==1 && maze[i-1][j].flag==false && loop==0)
{
int test=solveMaze(m,i-1,j,1);
if(test>0)
{
test+=d+1;
min=(test<min)?test:min;
}
maze[i-1][j].flag=true;
}
}
if(isPresent(i,j-1,r,c)&&maze[i][j-1].flag!=true)//check left of current cell
{
if(m[i][j-1]==0)
{
maze[i][j-1].distance+=1+d;
q.add(maze[i][j-1]);
}
if(m[i][j-1]==1 && maze[i][j-1].flag==false && loop==0)
{
int test=solveMaze(m,i,j-1,1);
if(test>0)
{
test+=d+1;
min=(test<min)?test:min;
}
maze[i][j-1].flag=true;
}
}
}
return ((result<min)?result:min);
}
public static int answer(int[][] m)
{
int count;
int r=m.length;
int c=m[0].length;
count=solveMaze(m,0,0,0);
return count;
}
public static void main(String[] args)
{
Scanner sc=new Scanner(System.in);
System.out.println("enter row size ");
int m=sc.nextInt();
System.out.println("enter column size ");
int n=sc.nextInt();
int[][] maze=new int[m][n];
System.out.println("Please enter values for maze");
for(int i=0;i<m;i++)
{
for(int j=0;j<n;j++)
{
maze[i][j]=sc.nextInt();
}
}
int d=answer(maze);
System.out.println("The maze can be solved in "+d+" steps");
}
}
Found the problem. maze[i][j].flag=true; needs to be put as soon as the cell is visited, inside the if(m[i+1][j]==0) condition. Otherwise, the distance for same cell can be added by more than one cells
Unfortunately it's quite hard to help you because your code is very difficult to read. The variables are generally single characters which makes it impossible to know what they are supposed to represent. Debugging it would be more help than most of us are willing to give :-)
I suggest you go about debugging your code as follows:
Split your solveMaze method into a number of smaller methods that each perform much simpler functions. For example, you have very similar code repeated 4 times for each direction. Work to get that code in a single method which can be called 4 times. Move your code to create the array into a new method. Basically each method should do one simple thing. This approach makes it much easier to find problems when they arise.
Write unit tests to ensure each of those methods do exactly what you expect before attempting to calculate the answer for entire mazes.
Once all the methods are working correctly, generate some mazes starting from very simple cases to very complex cases.
When a case fails, use an interactive debugger to walk through your code and see where it is going wrong.
Good luck.

Simulating archers hitting a target monte carlo method

3 archers are shooting at a target with probabilities p1, p2, p3. With a Monte Carlo simulation I am supposed to find an approximation of the probabilities of the following events:
randomly chosen archer hits the target // already solved
the target will be hit if all three shoot at it with a single bullet. // no idea how to approach
This is the first problem of this type that I am approaching. I can solve it easily using probabilities formulas, but I have no idea how to approach the problem using a simulation.
I would do something like this:
public class Archer {
private Random random = new Random();
public final double chance;
public Archer(double chance) {
this.chance = chance;
}
public boolean shoot() {
return random.nextDouble() < chance;
}
}
// ...
public boolean sample_problem2() {
for (Archer archer : archers) {
if (archer.shoot()) return true;
}
return false;
}
public double estimate_sample2(long count) {
long positive = 0;
for (long i = 0; i < count; i++) {
if (sample_problem2()) positive++;
}
return (double)positive / (double)count;
}
Here, the archer objects shoot method will return true or false with their respective probabilities. sample_problem2 will simulate an event you need. The latter method will take count samples, and will estimate the probability of the simulated event.
If you have some example code, we can help you develop a solution which fits better to what you already have.

To find adjacent sides of cube

I m trying to do a online problem about finding adjacent sides of a cube .The full question is at http://www.codechef.com/JULY15/problems/CHCUBE.
it gives correct answer to me, but when i submit it will get wrong answer.
heres my java code
import java.util.*;
class Cube {
public static void main(String[] args)
{
long T;
int blue = 0,black = 0,red=0,green=0,orange=0,yellow=0;
Scanner input=new Scanner(System.in);
T=input.nextLong();
int pos=0,checked=0,answer=0;
String colors[]=new String[6];
while(T>0){
for(int temp=0;temp<6;temp++)
{
colors[temp]=input.next();
if(colors[temp].equals("blue"))
{
blue++;
if(blue>2)
pos=temp;
}
else if(colors[temp].equals("black"))
{black++;
if(black>2)
pos=temp;
}
else if(colors[temp].equals("yellow"))
{yellow++;
if(yellow>2)
pos=temp;
}
else if(colors[temp].equals("orange"))
{orange++;
if(orange>2)
pos=temp;
}
else if(colors[temp].equals("green"))
{green++;
if(green>2)
pos=temp;
}
else if(colors[temp].equals("red"))
{red++;
if(red>2)
pos=temp;
}
}
if(blue>2||black>2||green>2||yellow>2||red>2||orange>2)
{ if(pos%2==0)
{
checked=(pos+2)%6;
}
else{
checked=(pos+1)%6;
}
if(colors[pos].equals(colors[checked] )||colors[pos].equals(colors[(checked+1)%6]) )
{
if(colors[pos].equals(colors[(checked+3)%6]) ||colors[pos].equals(colors[(checked+2)%6]) )
{
answer++;
}
}
}
if(answer==1)
System.out.println("YES");
else
System.out.println("NO");
T--;
}
}
}
I suggest you to model the whole thing as a graph.
A graph is a really flexible data structure, in this case
you can also use all algorithms, because the problem size
is so little.
The nodes of your graph are the sides, each node has to have
an attribute color which is representing its color.
Each node also has a list of the adjacent sides( so we are
implementing a graph with adjacent lists, not an adjacent matrix).
If you have built the graph you can begin to count adjacent sides with the same color. There are many different approaches, I think in your case it could be
good to delete all nodes between not equally colored sides.
After that, you can count all the edges that are left in your graph.
Since the graph is an undirected one, you have to divide the
result by 2.
Note that this approach will not lead to huge main methods - you can solve and debug the problem much faster.

Java: ArrayList not compiling [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I am working on a Robot Maze where the robot finds the target without crashing into walls. I know I've missed something or done something incorrectly (most likely a couple of things haha) but I've been racking my brain over it for a couple of hours now and tried several alternatives. I’m pretty sure my error is either where and how I declared the ArrayList.
It cannot find the symbol for the passageDirections and nonwallDirections.
Any help is appreciated :)
PS: I am a beginner programmer, still learning so explain your answer as if you were to explain it to a three year old :)
Your problem is in the nonwallExits method - you cannot have any code after a return statement, as this statement terminates the method. Just move return nonwallExits; to be the last line of the method and you should be fine.
I for example see a problem here in this method:
/* Junction method states if there is more than one passage, it will randomly select one.
If there is no passage, it will randomly select a nonwall/BeenBefore direction. */
public int junction(IRobot robot) {
if (passageExits(robot) >= 1) {
int randomPassage = ((Math.random())*(passageDirections.length()));
passageDirections.get(randomPassage);
} else {
int randomNonwall = ((Math.random())*(nonwallDirections.length()));
nonwallDirections.get(randomNonwall);
}
}
Here you are using the lists 'passageDirections' and 'nonwallDirections' without declaring them first. I see that you have declared those lists in other functions as local variables, which means that they exist as long as the function is executing which they are declared in. So if you want to use them in other functions, you shouldn make them somehow global or pass them around as parameters...
Without fully understanding your code, I would suggest try to do something like this to make the code "compileable":
import uk.ac.warwick.dcs.maze.logic.IRobot;
import java.util.ArrayList;
import java.util.*;
public class Explorer2 {
private ArrayList<Integer> passageDirections = new ArrayList<Integer>();
private ArrayList<Integer> nonWallDirections = new ArrayList<Integer>();
private Random random = new Random();
public void controlRobot (IRobot robot) {
int exits = nonwallExits(robot);
int direction;
if (exits < 2) {
direction = deadEnd(robot);
} else if (exits == 2) {
direction = corridor(robot);
} else if (exits == 3) {
direction = junction(robot);
} else {
direction = crossroads(robot);
}
robot.face(direction);
}
/* Deadend method will make the robot turn around except from the beginning.
Because the robot can face any direction at the start, it will follow
the one and only passage it will detect. */
public int deadEnd (IRobot robot) {
if (passageExits(robot) == 0)
return IRobot.BEHIND;
else
return -1; //FIXME: return correct direction!!!
}
/* Corridor method will make the robot follow the one and only passage. */
public int corridor (IRobot robot) {
return -1; //FIXME: return correct direction!!!
}
/* Junction method states if there is more than one passage, it will randomly select one.
If there is no passage, it will randomly select a nonwall/BeenBefore direction. */
public int junction(IRobot robot) {
if (passageExits(robot) >= 1) {
int randomPassage = random.nextInt(passageDirections.size());
return passageDirections.get(randomPassage);
} else {
int randomNonwall = random.nextInt(nonWallDirections.size());
return nonWallDirections.get(randomNonwall);
}
}
/* Crossroads method states if there is more than one passage, it will randomly select one.
If there is no passage, it will randomly select a nonwall/BeenBefore direction. */
public int crossroads (IRobot robot) {
if (passageExits(robot) >= 1) {
int randomPassage = random.nextInt(passageDirections.size());
return passageDirections.get(randomPassage);
} else {
int randomNonwall = random.nextInt(nonWallDirections.size());
return nonWallDirections.get(randomNonwall);
}
}
//Calculates number of exits and stores the direction of the exits in an ArrayList
private int nonwallExits (IRobot robot) {
int nonwallExits = 4;
if(robot.look(IRobot.AHEAD) == IRobot.WALL)
nonwallExits--;
if(robot.look(IRobot.LEFT) == IRobot.WALL)
nonwallExits--;
if(robot.look(IRobot.RIGHT) == IRobot.WALL)
nonwallExits--;
if(robot.look(IRobot.BEHIND) == IRobot.WALL)
nonwallExits--;
for(int direction = IRobot.AHEAD; direction < IRobot.LEFT; direction++) {
if(robot.look(direction) != IRobot.PASSAGE)
nonWallDirections.add(direction);
}
return nonwallExits;
}
//Calculates number of passages and stores the direction of the passages in an ArrayList
private int passageExits (IRobot robot) {
int passageExits = 0;
if(robot.look(IRobot.AHEAD) == IRobot.PASSAGE)
passageExits++;
if(robot.look(IRobot.LEFT) == IRobot.PASSAGE)
passageExits++;
if(robot.look(IRobot.RIGHT) == IRobot.PASSAGE)
passageExits++;
for(int direction = IRobot.AHEAD; direction < IRobot.LEFT; direction++) {
if(robot.look(direction) == IRobot.PASSAGE)
passageDirections.add(direction);
}
return passageExits;
}
}
This way you declare the lists to be instance variables, meaning that they represent the state of an Explorer2 object. Now all the instance methods operating on the Explorer2 objects can access these variables as this.passageDirections and this.nonWallDirections, where this refers to the object you are currently "working on". (and if there are no ambiguities you can skip the this. part).

Categories

Resources