Recursion with maze solver - java

The project is to code a maze solver in Java using recursion and a tree (I'm using my own linked list, not exactly sure if it's a tree but I don't mind that).
The lecturer never explains anything, so I get all my knowledge online. I'm having trouble with my recursive method, I'm not sure what to do since I can't find an example that can relate to my project
In my linked list, I have links to the node on the right, left, bottom and top. If there is for example a wall on your right, the link would be null. I also have booleans in the linked list wallRight, wallLeft, wallBottom and wallTop to see if there is for example a wall to the right. So if there was a wall to the right, the "Right" link would be null and wallRight would be true.
I also use Labels which are images, so if I landed on a spot, an image shows. I made a method that if I'm on position 1, it makes label 1 display, so in the recursive methods I use the int pos to know which label to display.
Now comes the trouble with my recursive method. I have tried it two ways, but neither work. Here is both of them:
public boolean move(Maze rigting,int pos) // Righting = direction
{
if(rigting.goal == true)
return true; //BASE CASE - tests if it is on the goal node
else if(rigting.wallR != true) //checks if there is a wall on the right
{
pos += 1;
move(rigting.right, pos); //moves right
showLabel(pos);
return true;
}
else if(rigting.wallD != true) //checks if there is a wall below
{
pos += 10;
move(rigting.down, pos); //moves down
showLabel(pos);
return true;
}
else if(rigting.wallL != true) //checks if there is a wall on the left
{
pos -= 1;
move(rigting.left, pos); //moves left
showLabel(pos);
return true;
}
else if(rigting.wallU != true) //checks if there is a wall above
{
pos -= 10;
move(rigting.up, pos); //moves up
showLabel(pos);
return true;
}
return false; //I know this return is incorrect, but it won't run without one
}
public boolean move(Maze rigting,int pos) //Righting = direction
{
if(rigting.goal == true)
return true;
return (rigting.wallR != true) ? move(rigting.right, pos += 1) : false ||
(rigting.wallD != true) ? move(rigting.down, pos += 10) : false ||
(rigting.wallL != true) ? move(rigting.left, pos -= 1) : false ||
(rigting.wallU != true) ? move(rigting.up, pos -= 10) : false;
}
Both of these give stackoverflow exceptions...
I think my error is that, if there is a wall on the right, then the link Right is null. If I could somehow make it that none of the links are null, then I wouldn't need the booleans wallRight etc, but I have no idea how to implement that.
I would really appreciate it if you could send me in the right direction! I only need to hand in the project on 10 October, so if I'm doing it completely wrong, I don't mind starting over!

Since this is your homework, I won't give you a solution here, but some hints.
Your first solution does not consider the result of subsequent calls to move(), therefore the recursion only ends, if you reached the goal (accidentially).
In your second solution you consider the result, but are not prepared for a case, where you are moving in a loop. You need to mark the nodes you already visited and break there (with return value false).
For recursion it's best to start with the break-condition (as you did), and then implement one simple case (e.g. always go right). After managed the simple case you can add others (branches)

Related

How to get the predicted move sequence that a negamax algorithm is basing its evaluation upon?

My chess algorithm is based on negamax. The relevant part is:
private double deepEvaluateBoard(Board board, int currentDepth, double alpha, double beta, Move initialMove) {
if (board.isCheckmate() || board.isDraw() || currentDepth <= 0) {
this.moveHistorys.put(initialMove, board.getMoveHistory()); // this is not working
return evaluateBoard(board); // evaluateBoard evaluates from the perspective of color whose turn it is.
} else {
double totalPositionValue = -1e40;
List<Move> allPossibleMoves = board.getAllPossibleMoves();
for (Move move : allPossibleMoves) {
board.makeMove(move);
totalPositionValue = max(-deepEvaluateBoard(board, currentDepth - 1, -beta, -alpha, initialMove), value);
board.unMakeMove(1);
alpha = max(alpha, totalPositionValue);
if (alpha >= beta) {
break;
}
}
return totalPositionValue;
}
}
It would greatly help debugging if I was be able to access the move sequence that the negamax algorithm bases its evaluation on (where on the decision tree the evaluated value is found).
Currently I am trying to save the move history of the board into a hashmap that is a field of the enclosing class. However, it is not working for some reason, as the produced move sequences are not optimal.
Since developing an intuition for negamax is not very easy, I have ended up on banging my head against the wall on this one for quite some time now. I would much appreciate if someone could point me in the right direction!

Your are given the root nodes of two binary search trees. Determine if both trees store the same numbers

The answer needs to be iterative, not recursive and the trees don't have to have the same structure, only the same numbers. I think I need to use a vertex traversal, but I am not sure how to implement that without using recursion.
This is what I had, but it doesn't pass the given tests. Also, I can't use any helper functions.
Node leftTree = t1;
Node rightTree = t2;
if(t1 == null && t2 == null)
return true;
else if (t1 != null && t2 == null)
return false;
else if (t1 == null && t2 != null)
return false;
else
{
if(leftTree.key == rightTree.key && problem1(leftTree.left, rightTree.left) == true
&& problem1(leftTree.right, rightTree.right) == true)
return true;
}
return false;
The recursion, where you compare left with left and right with right, will not work, because you can have the same keys but in a different topology. You need to visit the nodes in-order in the two trees in parallel.
One way of going through a tree without using recursion or extra memory is via a Morris traversal, where you temporarily put a tree in the rightmost position of its left subtree, and "return" from the recursion by following the right pointer there.
Here is an implementation in C, because I have one lying around. In Java it won't be that different. The rightmost_to() function returns the rightmost node in the left child of the current node, or the current node itself. You use it put the current node in the right child there, so when you get down to that point, going right emulates returning from the recursion.
void morris(stree *t)
{
struct node *curr = *t;
while (curr) {
if (!curr->left) {
printf("%d\n", curr->value);
curr = curr->right;
} else {
stree pred = *rightmost_to(&curr->left, curr);
assert(pred->right == 0 || pred->right == curr);
if (pred->right == 0) {
pred->right = curr;
curr = curr->left;
} else {
printf("%d\n", curr->value);
pred->right = 0;
curr = curr->right;
}
}
}
}
You will visit each node in order, without recursion, and without using extra memory. Whenever you recurse, you put the node you are in at the rightmost position, so you automatically come back to it. You can recognise that you are seeing the node for the second time because you find it when searching for the rightmost. Then you restore the tree instead of going left once more.
If you need to compare two trees, have two current nodes, and you should be fine. It does use an extra function, rightmost_to(), but it is a simple loop that you can easily embed without any issues. It is a line or two if you do that.
If you are allowed to put a parent pointer in the nodes, I think you can also traverse the trees without using extra memory doing something like this:
#define left_child(t) \
((t)->parent && (t)->parent->left == (t))
void parent_traverse(stree t)
{
enum { DOWN, UP } state = DOWN;
while (t) {
switch (state) {
case DOWN:
// Recurse as far left as we can...
while (t->left) { t = t->left; }
// Emit the leaf we find there
printf("(,%d,", t->value); // VISIT
// Then go right, if we can, or up if we can't.
if (t->right) { t = t->right; }
else { state = UP; }
break;
case UP:
if (!t->parent) return; // we have returned to the root...
if (left_child(t)) {
// Returning from a left child, we emit the parent
t = t->parent;
printf(",%d,", t->value); // VISIT
// Then we go right if we can't, or continue up
// (t is already the parent) if we cannot.
if (t->right) { t = t->right; state = DOWN; }
} else {
// Returning from a right child just means going up
t = t->parent;
}
break;
}
}
}
Sorry, it is C again, but just look at how t is updated to its left, right or parent node as we run through the tree. I cut that out of some code I have, and I might have copied it wrong, but you should get the idea. You can keep track of which direction you are moving, and essentially move along the "edge" of the tree, down left edges, under them and up, then down to the right, turn, and move up, and so on. If you have the state for both trees, you should be able to do that traversal in parallel in the two. Everwhere the code "visits" a node, you will compare the two nodes.
I don't know how useful this is, but it is at least a couple of ways that you can compare two trees with only constant extra memory usage and no recursion.
Of course, if it is a simple assignment and the time complexity doesn't matter, run through one tree and look up in the other in O(n log n) (balanced) or O(n^2). :)

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.

Minimax value issue - Java

I have looked everywhere for answers for fixing my code but after long hours spent trying to debug it I find myself hopelessly stuck. The problem is that my minimax function will not return the correct values for the best possible move, I even attempted to fix it by storing the best first moves (when depth = 0), but if the solution is not obvious, then the algorithm fails horribly. I also tried modifying the return values from the base cases in order to prioritize earlier wins, but this didn't solve the problem.
Currently I am testing the function on a TicTacToe board and the helper classes (Eg getMoves() or getWinner are working properly), I know my style is not the most efficient but I needed the code to be fairly explicit.
By adding a bunch of print statements I realized that under some circumstances my bestFinalMoves ArrayList was not modified, so this may be related to the issue. Another related problem is that unless the algorithm finds a direct win (in the next move), then instead of choosing a move that may lead to a future win or tie by blocking a square that leads to an immediate block, it just yields the space for the minimizing player to win.
For example on the board:
aBoard= new int[][] {
{0,1,0}, // 1 is MAX (AI), -1 is MIN (Human)
{-1,0,0},
{-1,0,0}
};
Yields the incorrect result of 2,0, where it is obvious that it should be 0,0, so that it blocks the win for the minimizing player, and the bestFinalMoves ArrayList is empty.
private result miniMaxEnd2(Board tmpGame, int depth){
String winner = tmpGame.whoWon();
ArrayList<Move> myMoves = tmpGame.getMoves();
if (winner == 'computer'){ //Base Cases
return new result(1000);
}else if (winner == 'human'){
return new result(-1000);
}
else if (winner == 'tie'){
return new result(0);
}
if (tmpGame.ComputerTurn) {//MAX
bestScore = -99999;
for (Move m : tmpGame.getMoves()){
Board newGame = new Board(tmpGame,!tmpGame.ComputerTurn, m);
result aScore = miniMaxEnd2(newGame, depth+1);
if (aScore.score > bestScore) {
bestScore = aScore.score;
bestMove = m;
if (depth == 0) {
bestFinalMoves.add(m);
}
}
}
return new result(bestScore, bestMove);
} else {//MIN
bestScore = 99999;
for (Move m : tmpGame.getMoves()) {
Board newGame = new Board(tmpGame,!tmpGame.ComputerTurn, m);
result aScore = miniMaxEnd2(newGame, depth + 1);
if (aScore.score < bestScore) {
bestScore = aScore.score;
bestMove = m;
}
}
return new result(bestScore,bestMove);
}
}
I know this was a long post, but I really appreciate your help. The full code can be accessed at https://github.com/serch037/UTC_Connect
The bestScore and bestMove variables must be declared as local variables inside the miniMaxEnd2 method for this logic to work properly.
Those variables' values are being replaced by the recursive call.

Flawed logic in A* implementation

I've been using examples of others' implementations of the A* pathfinding algorithm as a crutch to help me write my first implementation. I'm having some trouble with the logic in one of the more readable examples I've found.
I'm not here to pick apart this code, really, I'm trying to figure out if I am right or if I am misunderstanding the mechanics here. If I need to review how A* works I will but if this code is incorrect I need to find other sources to learn from.
It appears to me that the logic found here is flawed in two places both contained here:
for(Node neighbor : current.getNeighborList()) {
neighborIsBetter;
//if we have already searched this Node, don't bother and continue to the next
if (closedList.contains(neighbor))
continue;
//also just continue if the neighbor is an obstacle
if (!neighbor.isObstacle) {
// calculate how long the path is if we choose this neighbor as the next step in the path
float neighborDistanceFromStart = (current.getDistanceFromStart() + map.getDistanceBetween(current, neighbor));
//add neighbor to the open list if it is not there
if(!openList.contains(neighbor)) {
--> openList.add(neighbor);
neighborIsBetter = true;
//if neighbor is closer to start it could also be better
--> } else if(neighborDistanceFromStart < current.getDistanceFromStart()) {
neighborIsBetter = true;
} else {
neighborIsBetter = false;
}
// set neighbors parameters if it is better
if (neighborIsBetter) {
neighbor.setPreviousNode(current);
neighbor.setDistanceFromStart(neighborDistanceFromStart);
neighbor.setHeuristicDistanceFromGoal(heuristic.getEstimatedDistanceToGoal(neighbor.getX(), neighbor.getY(), map.getGoalLocationX(), map.getGoalLocationY()));
}
}
}
source
The first line I marked (-->), seems incorrect to me. If you look at the implementation of the list being used(below) it sorts based on heuristicDistanceFromGoal which is set several lines below the .add.
public int compareTo(Node otherNode) {
float thisTotalDistanceFromGoal = heuristicDistanceFromGoal + distanceFromStart;
float otherTotalDistanceFromGoal = otherNode.getHeuristicDistanceFromGoal() + otherNode.getDistanceFromStart();
if (thisTotalDistanceFromGoal < otherTotalDistanceFromGoal) {
return -1;
} else if (thisTotalDistanceFromGoal > otherTotalDistanceFromGoal) {
return 1;
} else {
return 0;
}
}
The second line I marked should always evaluate to false. It reads:
} else if(neighborDistanceFromStart < current.getDistanceFromStart()) {
Which can be simplified to:
if((current.getDistanceFromStart() + map.getDistanceBetween(current, neighbor)) < current.getDistanceFromStart())
And again to:
if(map.getDistanceBetween(current, neighbor) < 0)
Which would be fine except getDistanceBetween() should always return a positive value (see here).
Am I on or off track?
First of all, you are mostly on track. I strongly suspect the code you posted is still under development and has some problems. But, still your assumption of distance is positive is not correct in general. A* is a graph search algorithm and edges can have negative weights as well in general. Hence, I assume they tried to implement the most general case. The openList.add seems totally fine to me though. Your queue should be sorted with heuristic distance. Just check the wiki page https://en.wikipedia.org/wiki/A_star, the related line is f_score[neighbor] := g_score[neighbor] + heuristic_cost_estimate(neighbor, goal). And, main idea behind this is, you always underestimate the distance (admissible heuristic); hence, if the goal is found, none of the not-explored nodes can be optimal. You can read more at http://en.wikipedia.org/wiki/Admissible_heuristic
Second of all, If you want a stable AI code base, You can simply use http://code.google.com/p/aima-java/. It is the implementation of the algorithms in AIMA (Artificial Intelligence A Modern Approach)

Categories

Resources