Knight's Tour recursive algorithm - java

Okay everybody, I know the knight's tour problem is popular for all cs students and I am having trouble getting mine to work. I use this recursive algorithm to progress through the moves, however, once I get to around move 50 I have to backtrack since no moves are available and I end up never completing the tour. I pass a ChessNode (holds things like if node has been visited, move it was visited, etc...), next row, next column, and previous node's move count.
private int moveRecur(ChessNode current, int row, int column, int moveV){
current.moveVisited = moveV+1;
if(current.moveVisited > 63){
return 0;
}
if(current.position==13 && aboard[row-1][column+2].visited != 1){
current.visited = 1;
moveRecur(aboard[row-1][column+2], row-1, column+2, current.moveVisited);
}
else if(current.position==22 && aboard[row-2][column+1].visited != 1){
current.visited = 1;
moveRecur(aboard[row-2][column+1], row-2, column+1, current.moveVisited);
}
else if(current.position == 50 && aboard[row+1][column-2].visited != 1){
current.visited = 1;
moveRecur(aboard[row+1][column-2], row+1, column-2, current.moveVisited);
}
else if(current.position == 41 && aboard[row+2][column-1].visited != 1){
current.visited =1;
moveRecur(aboard[row+2][column-1], row+2, column-1, current.moveVisited);
}
else if(current.position == 46 && aboard[row+2][column+1].visited != 1){
current.visited = 1;
moveRecur(aboard[row+2][column+1], row+2, column+1, current.moveVisited);
}
else if(current.position == 53 && aboard[row+1][column+2].visited != 1){
current.visited = 1;
moveRecur(aboard[row+1][column+2], row+1, column+2, current.moveVisited);
}
else if(current.position == 10 && aboard[row-1][column-2].visited != 1){
current.visited = 1;
moveRecur(aboard[row-1][column-2], row-1, column-2, current.moveVisited);
}
else if (current.position == 17 && aboard[row-2][column-1].visited != 1){
current.visited =1;
moveRecur(aboard[row-2][column-1], row-2, column-2, current.moveVisited);
}
if(row+1>=0 && row+1<8 && column+2>=0 && column+2<8){
if(aboard[row+1][column+2].visited != 1){
current.visited = 1;
moveRecur(aboard[row+1][column+2], row+1, column+2, current.moveVisited);
}
}
if(row+2>=0 && row+2<8 && column+1>=0 && column+1<8){
if(aboard[row+2][column+1].visited != 1){
current.visited = 1;
moveRecur(aboard[row+2][column+1], row+2, column+1, current.moveVisited);
}
}
if(row-1>=0 && row-1<8 && column-2>=0 && column-2<8){
if(aboard[row-1][column-2].visited != 1){
current.visited = 1;
moveRecur(aboard[row-1][column-2], row-1, column-2, current.moveVisited);
}
}
if(row-2>=0 && row-2<8 && column-1>=0 && column-1<8){
if(aboard[row-2][column-1].visited != 1){
current.visited = 1;
moveRecur(aboard[row-2][column-1], row-2, column-1, current.moveVisited);
}
}
if(row+1>=0 && row+1<8 && column-2>=0 && column-2<8){
if(aboard[row+1][column-2].visited != 1){
current.visited = 1;
moveRecur(aboard[row+1][column-2], row+1, column-2, current.moveVisited);
}
}
if(row+2>=0 && row+2<8 && column-1>=0 && column-1<8){
if(aboard[row+2][column-1].visited != 1){
current.visited = 1;
moveRecur(aboard[row+2][column-1], row+2, column-1, current.moveVisited);
}
}
if(row-1>=0 && row-1<8 && column+2>=0 && column+2<8){
if(aboard[row-1][column+2].visited != 1){
current.visited = 1;
moveRecur(aboard[row-1][column+2], row-1, column+2, current.moveVisited);
}
}
if(row-2>=0 && row-2<8 && column+1>=0 && column+1<8){
if(aboard[row-2][column+1].visited != 1){
current.visited = 1;
moveRecur(aboard[row-2][column+1], row-2, column+1, current.moveVisited);
}
}
//System.out.println(current.position + " "+current.moveVisited);
current.visited = 0;
return 0;
}
So, initially I check for the spots that can move to the corner board positions, and then I just make recursive calls based on available moves. So I guess my main question is am I doing something wrong? or is there another condition I can used to make the tour a little more intuitive?
Thanks in advance!

This is the Knight's tour code in java and has a brilliant layout. I did this using backtracking using recursion. This was my class assignment. Do contact me if you have any problem understanding or running this code.
package knights.tour;
import java.awt.*;
import java.awt.event.*;
import java.util.logging.*;
import javax.swing.*;
public class KnightsTour extends JFrame implements ActionListener{
//All the static variables used between action listeners and functions.
public static String path;
public static int btnPressed = 0;
public static int rowSelected;
public static String[] pathArray;
public static int[][] coordinatesArray;
public static int columnSelected;
public static int flag =0;
public static int increment = 0;
public static JPanel panel1 = new JPanel();
public static JPanel panel3 ;
public static JButton btnStart = new JButton("Start Animation");
public static JButton btnClear = new JButton("Clear");
public static JTextArea lblPath = new JTextArea();
public static JLabel lblStartRow = new JLabel();
public static JLabel lblStartColumn = new JLabel();
public static JButton[][] button;
public static int variableForIncrement=0;
static int row ;
static int column ;
static int[][] array = new int[row][column];
public static int count = 1;
KnightsTour(){
//Setting layout of the frame in the constructor and adding buttons to the panel and the frame.
getContentPane().setLayout(new GridLayout(2,1));
lblPath.setLineWrap(true);
lblPath.setColumns(10);
lblPath.setSize(700, 100);
lblPath.setEditable(false);
panel1.add(btnStart);
panel1.add(btnClear);
panel1.add(lblStartRow);
panel1.add(lblStartColumn);
panel1.add(lblPath);
panel3 = new JPanel(new GridLayout(row,column));
// Initializing Array of buttons for the user to click on the chess board.
button= new JButton[row][column];
array = new int[row][column];
coordinatesArray = new int[row*column][2]; // This array stores the coordinates as the Knight
for(int i=0;i<row;i++){
for(int j=0;j<column;j++){
button[i][j] = new JButton();
}
}
//Setting background of the buttons to black and white for chessboard layout.
for(int i=0;i<row;i++){
for(int j=0;j<column;j++){
if(i%2 ==j%2){
button[i][j].setBackground(Color.BLACK);
button[i][j].setForeground(Color.WHITE);
}
else{
button[i][j].setBackground(Color.WHITE);
}
panel3.add(button[i][j]);
button[i][j].addActionListener(this);
}
}
btnClear.addActionListener(this);
btnStart.addActionListener(this);
add(panel3);
add(panel1);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public static void main(String[] args) {
// TODO code application logic here
String input =JOptionPane.showInputDialog("Enter the rows and columns in the format (row,column)");
String[] ar = input.split(",");
row = Integer.parseInt(ar[0]); // Finding out row and column from the user input.
column = Integer.parseInt(ar[1]);
pathArray = new String[row*column]; // This array is kept to store the path of the knight.
JFrame frame = new KnightsTour();
frame.setVisible(true);
frame.setSize(700,700);
}
//All the computation takes place in this function. It checks the neighbour and recursively calls itself.
public static void neighbourRecursion(int a,int b){
pathArray[increment] = Integer.toString(a) + "," + Integer.toString(b); // Storing the path of the Knight
increment++;
array[a][b] = count; //Stroing value of count.
button[a][b].setText(String.valueOf(count));
coordinatesArray[variableForIncrement][0] = button[a][b].getX(); //Finding coordinates of buttons to show animation
coordinatesArray[variableForIncrement][1] = button[a][b].getY();
count++;
variableForIncrement++;
//Checking for valid neighbours and calling itself recursively.
if(a <= row-3 && b<=column-2){
if(alreadyVisited(a+2,b+1)){
neighbourRecursion(a+2,b+1);
}
}
if(a<=row-3 && b>=1){
if(alreadyVisited(a+2,b-1)){
neighbourRecursion(a+2,b-1);
}
}
if(a>=2 && b<=column-2){
if(alreadyVisited(a-2,b+1)){
neighbourRecursion(a-2,b+1);
}
}
if(a>=2 && b>=1){
if(alreadyVisited(a-2,b-1)){
neighbourRecursion(a-2,b-1);
}
}
if(a<=row-2 && b>=2){
if(alreadyVisited(a+1,b-2)){
neighbourRecursion(a+1,b-2);
}
}
if(a<=row-2 && b<=column-3){
if(alreadyVisited(a+1,b+2)){
neighbourRecursion(a+1,b+2);
}
}
if(a>=1 && b>=2){
if(alreadyVisited(a-1,b-2)){
neighbourRecursion(a-1,b-2);
}
}
if(a>=1 && b <=column-3){
if(alreadyVisited(a-1,b+2)){
neighbourRecursion(a-1,b+2);
}
}
//Breaking condition of the function.
if(count == (row*column)+1){
}
// Backtracking condition if there is no neighbour.
else{
button[a][b].setText("");
array[a][b]=0;
count--;
variableForIncrement--;
if(increment >0){
increment--;
}
return ;
}
}
//This function checks if the neighbour is already visited.
public static boolean alreadyVisited(int a,int b){
if(array[a][b] != 0){
return false;
}
else{
return true;
}
}
#Override
public void actionPerformed(ActionEvent e) {
//when clear is pressed all arrays and global variables are set to initial conditon.
if(e.getSource() == btnClear){
for(int i =0;i<row;i++){
for(int j=0;j<column;j++){
array[i][j] = 0;
button[i][j].setText("");
count = 1;
lblPath.setText("");
lblStartRow.setText("");
lblStartColumn.setText("");
flag =0;
variableForIncrement=0;
increment =0;
path =" ";
}
}
}
//If start animation button is pressed animation is started.
else if(e.getSource() == btnStart){
animate();
}
// When the button is pressed.
else{
for(int i=0;i<row;i++){
for(int j=0;j<column;j++){
if(e.getSource() == button[i][j]){
if(flag == 1){
lblPath.setText(" Please press clear before clicking again"); // Button pressed twice without reset.
}
else{
rowSelected = i;
columnSelected =j;
// If odd * odd board and selected postion is odd then No path is possible.
if(row%2 ==1 && column%2 == 1 && rowSelected%2 ==0 && columnSelected%2 == 1 || row%2 ==1 && column%2 == 1 && rowSelected%2 ==1 && columnSelected%2 == 0){
lblPath.setText(" Path not possible from this point");
}
else{
int count;
lblStartRow.setText("Starting Row : "+String.valueOf(rowSelected + 1));
lblStartColumn.setText("Starting Column : "+String.valueOf(columnSelected + 1));
count = 1;
flag = 1;
startTour(); //Start tour function called.
for(int q=0;q<row;q++){
for(int w=0;w<column;w++){
if(array[i][j] == 0){
count++;
}
}
}
if(count > 2){
lblPath.setText(" No Path found");
}
//Printing path of the knight here.
else{
for(int k=0;k<pathArray.length;k++){
path = path+"->"+ pathArray[k];
}
lblPath.setText(" Path : \n"+ path.substring(5));
}
btnPressed = 1;
break;
}
}
}
}
}
} }
//Function for the animation.
void animate(){
if(btnPressed == 1){
btnPressed =0;
Graphics g = getGraphics();
for(int i=0;i<(row*column)-1;i++){
try {
Thread.sleep(600); // this function slows down drawing of lines.
} catch (InterruptedException ex) {
}
g.setColor(Color.RED); // setting colour or line to red.
g.drawLine((coordinatesArray[i][0]+65),(coordinatesArray[i][1]+50),(coordinatesArray[i+1] [0]+65),(coordinatesArray[i+1][1]+50));
}
}
else{
lblPath.setText(" Please clear, select a button to see the animation again"); //Animate button pressed twice without clear.
}
}
//This function calls the neighbour function with the selected row and column by the user.
static void startTour(){
neighbourRecursion(rowSelected,columnSelected);
for(int i=0;i<row;i++){
for(int j=0;j<column;j++){
System.out.print(array[i][j]+" ");
}
System.out.println();
}
}
}

I have an implementation of this program in C#. You can find it here:
http://github.com/danieltian/KnightBoard
It will only find the first solution though. I'm not saying to copy it, but you can take a look at it and see if it helps.

Related

How to switch between 2 colors in Java Jbuttons after every click

I have been making a color-based Tic Tac Toe game using Java Swing and Java AWT and have more or less finished the project, however there is still one problem that needs to be fixed in order to be a proper Tic Tac Toe game. The colors that are supposed to be used is Orange (X) and blue (O), however for some reason even when checking each turn iteration it refuses to switch colors after every click and at this point I am lost. Any help is appreciated
Board.java:
public class Board extends JPanel {
boolean gameRunning = true;
private final JButton[][] grid = new JButton[3][3];
JFrame board;
JPanel panel;
public Board() {
initBoard();
}
private void makePanel() {
panel = new JPanel();
panel.setBackground(Color.lightGray);
panel.setLayout(new GridLayout(3, 3));
setBoard();
board.add(panel);
}
private void initBoard() {
int BOARD_WIDTH = 800;
int BOARD_HEIGHT = 600;
board = new JFrame();
board.setTitle("JTicTacToe");
board.setSize(BOARD_WIDTH, BOARD_HEIGHT);
board.setResizable(false);
board.setLocationRelativeTo(null);
board.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
makePanel();
board.setVisible(true);
}
private void setBoard() {
//Loop through 2D array
for (int row = 0; row < grid.length; row++) {
for (int col = 0; col < grid[row].length; col++) {
grid[row][col] = new JButton();
grid[row][col].setOpaque(true);
grid[row][col].setBorderPainted(false);
grid[row][col].addActionListener(new ButtonListener());
panel.add(grid[row][col]);
}
}
validate();
}
protected class ButtonListener implements ActionListener {
Color defaultColor = new Color(238,238,238);
protected void check(int moves) {
//Rows
for (int c = 0; c < 3; c++) {
if (!defaultColor.equals(grid[c][0].getBackground()) && grid[c][0].getBackground() == grid[c][1].getBackground() && grid[c][0].getBackground() == grid[c][2].getBackground()) {
gameRunning = false;
JOptionPane.showMessageDialog(null, "Game Over!");
}
}
//Verticals
for (int c = 0; c < 3; c++) {
if (!defaultColor.equals(grid[0][c].getBackground()) && grid[0][c].getBackground() == grid[1][c].getBackground() && grid[0][c].getBackground() == grid[2][c].getBackground()) {
gameRunning = false;
JOptionPane.showMessageDialog(null, "Game Over!");
}
}
//Check diagonals
if (!defaultColor.equals(grid[0][0].getBackground()) && grid[0][0].getBackground() == grid[1][1].getBackground() && grid[0][0].getBackground() == grid[2][2].getBackground()) {
gameRunning = false;
JOptionPane.showMessageDialog(null, "Game Over!");}
if (!defaultColor.equals(grid[0][2].getBackground()) && grid[0][2].getBackground() == grid[1][1].getBackground() && grid[0][2].getBackground() == grid[2][0].getBackground()) {
gameRunning = false;
JOptionPane.showMessageDialog(null, "Game Over!");
}
//Check draw if game goes to 9 moves
if(moves == 9) {
gameRunning = false;
JOptionPane.showMessageDialog(null, "Draw!");
}
}
#Override
public void actionPerformed(ActionEvent e) {
int turns = 0;
if (e.getSource() == grid[0][0]) {
turns++;
if (turns % 2 == 0) {
grid[0][0].setBackground(Color.orange);
check(turns);
} else {
grid[0][0].setBackground(Color.blue);
check(turns);
}
} else if (e.getSource() == grid[0][1]) {
turns++;
if (turns % 2 == 0) {
grid[0][1].setBackground(Color.orange);
check(turns);
} else {
grid[0][1].setBackground(Color.blue);
check(turns);
}
} else if (e.getSource() == grid[0][2]) {
turns++;
if (turns % 2 == 0) {
grid[0][2].setBackground(Color.orange);
check(turns);
} else {
grid[0][2].setBackground(Color.blue);
check(turns);
}
} else if (e.getSource() == grid[1][0]) {
turns++;
if (turns % 2 == 0) {
grid[1][0].setBackground(Color.orange);
check(turns);
} else {
grid[1][0].setBackground(Color.blue);
check(turns);
}
} else if (e.getSource() == grid[1][1]) {
turns++;
if (turns % 2 == 0) {
grid[1][1].setBackground(Color.orange);
check(turns);
} else {
grid[1][1].setBackground(Color.blue);
check(turns);
}
} else if (e.getSource() == grid[1][2]) {
turns++;
if (turns % 2 == 0) {
grid[1][2].setBackground(Color.orange);
check(turns);
} else {
grid[1][2].setBackground(Color.blue);
check(turns);
}
} else if (e.getSource() == grid[2][0]) {
turns++;
if (turns % 2 == 0) {
grid[2][0].setBackground(Color.orange);
check(turns);
} else {
grid[2][0].setBackground(Color.blue);
check(turns);
}
} else if (e.getSource() == grid[2][1]) {
turns++;
if (turns % 2 == 0) {
grid[2][1].setBackground(Color.orange);
check(turns);
} else {
grid[2][1].setBackground(Color.blue);
check(turns);
}
} else if (e.getSource() == grid[2][2]) {
turns++;
if (turns % 2 == 0) {
grid[2][2].setBackground(Color.orange);
check(turns);
} else {
grid[2][2].setBackground(Color.blue);
check(turns);
}
} else {
JOptionPane.showMessageDialog(null, "Invalid");
}
System.out.println(turns);
}
}
}
If you want to make the code prettier:
The variable gameRunning is set but it is never used. You can remove it and the program will still behave the same. Or you can start using it. But just giving it values without using those values is unnecessary work.
The variables at the top should be private (grid is private, but eg board is not)
You can use a loop to shorten the actionPerformed method (note that I added a return;):
#Override
public void actionPerformed(ActionEvent e) {
for (int col = 0; col < 3; col++) {
for (int row = 0; row < 3; row++) {
if (e.getSource() == grid[col][row]) {
turns++;
if (turns % 2 == 0) {
grid[col][row].setBackground(Color.orange);
check(turns);
} else {
grid[col][row].setBackground(Color.blue);
check(turns);
}
System.out.println(turns);
return;
}
}
}
JOptionPane.showMessageDialog(null, "Invalid");
}
You set the variable turns to 0 every time a button is clicked (ie every time actionPerformed is called). You need to make turns global (same as eg grid).

Peg solitaire solution change destination

I wrote a program that solves a peg solitaire in java.
My program gets a starting board and a destination board and try to finish the game.
I have a sort of counter that count my turn because I have a destination with more the 1 peg rest and as assume that if I have to remove only 2 pegs so I can solve it in only 2 moves.
I have an board class that I create:
public class Board {
private int board[][] = new int[7][7];
public Board(String place)
{
board[0][0]=2;
board[1][0]=2;
board[5][0]=2;
board[6][0]=2;
board[0][1]=2;
board[1][1]=2;
board[5][1]=2;
board[6][1]=2;
board[0][5]=2;
board[1][5]=2;
board[5][5]=2;
board[6][5]=2;
board[0][6]=2;
board[1][6]=2;
board[5][6]=2;
board[6][6]=2;
int loca=0;//location on the string of place
for(int i=0;i<7;i++){
for(int j=0;j<7;j++){
if(board[i][j]!=2) {
if (place.charAt(loca) == 'O') {
loca++;
board[i][j] = 1;
} else if (place.charAt(loca) == '.') {
loca++;
board[i][j] = 0;
}
}
System.out.print(board[i][j]);//print for test
}
System.out.println();//print for test
}
System.out.println();
}
public Board(Board copy){
for(int i=0;i<7;i++)
{
for(int j=0;j<7;j++)
{
board[i][j]=copy.getValue(i,j);
}
}
}
public int getValue(int x, int y)
{
return board[x][y];
}
public boolean isFinished(Board destination)
{
for(int i=0;i<7;i++)
{
for(int j=0;j<7;j++)
{
if(this.getValue(i,j)!=destination.getValue(i,j))
{
return false;
}
}
}
return true;
}
public Board turn(Board board,String direction,int x,int y)
{
if(direction.equals("right"))
{
board.setValue(x,y,0);
board.setValue(x+1,y,0);
board.setValue(x+2,y,1);
return board;
}
else if(direction.equals("left"))
{
board.setValue(x,y,0);
board.setValue(x-1,y,0);
board.setValue(x-2,y,1);
return board;
}
else if(direction.equals("up"))
{
board.setValue(x,y,0);
board.setValue(x,y-1,0);
board.setValue(x,y-2,1);
return board;
}
else if(direction.equals("down"))
{
board.setValue(x,y,0);
board.setValue(x,y+1,0);
board.setValue(x,y+2,1);
return board;
}
else{
System.out.println("there is not such direction, method turn on board class");
return null;//just for caution
}
}
public boolean isLegal(int x, int y){
if(board[x][y]==2)
{
return false;
}
else{
return true;
}
}
public boolean canTurn(String direction,int x,int y){
if(direction.equals("right"))
{
if(x<5) {
if (board[x][y] == 1 && board[x + 1][y] == 1 && board[x + 2][y] == 0) {
return true;
}
}
}
else if(direction.equals("left"))
{
if(x>1) {
if (board[x][y] == 1 && board[x - 1][y] == 1 && board[x - 2][y] == 0) {
return true;
}
}
}
else if(direction.equals("up"))
{
if(y>1) {
if (board[x][y] == 1 && board[x][y - 1] == 1 && board[x][y - 2] == 0) {
return true;
}
}
}
else if(direction.equals("down"))
{
if(y<5) {
if (board[x][y] == 1 && board[x][y + 1] == 1 && board[x][y + 2] == 0) {
return true;
}
}
}
else{
System.out.println("there is not such direction, method canTurn on board class");
return false;//just for caution
}
return false;
}
public void setValue(int x, int y, int value)
{
board[x][y]=value;
}
}
and I wrote my "solver" class.
public class PegSolver {
public int peg =1;
Board destinationBoard = new Board("OOOOOOOOOOOOOOOOO..OOOOOOOOOOOOOO");
Board board = new Board("OOOOOOOOOOOOOOOO.OOOOOOOOOOOOOOOO");
public void start(){
solve(0,board);
}
public boolean solve(int turn, Board board){
Board temp = new Board(board);
if(turn>peg)
{
return false;
}
else if(turn==peg){
//todo:check if solve
if(temp.isFinished(destinationBoard))
{
System.out.println("solution");
return true;
}
else
{
return false;
}
}
else//lower then 8
{
for(int i=0;i<7;i++){
for (int j=0;j<7;j++)
{
if(board.isLegal(i,j)) {
if(board.canTurn("right",i,j) && solve(turn++, temp.turn(temp, "right", i, j)))
{
return true;
}
else if(board.canTurn("left",i,j) && solve(turn++, temp.turn(temp, "left", i, j)))
{
return true;
}
else if(board.canTurn("up",i,j) && solve(turn++, temp.turn(temp, "up", i, j)))
{
return true;
}
else if(board.canTurn("down",i,j) && solve(turn++, temp.turn(temp, "down", i, j)))
{
return true;
}
}
}
}
}
return false;
}
}
When the program finds a solution, it needs to print "solution" but for some reason my program can't find a solution even when it's a basic destination with one move.
Can someone help me please?
Please review the modified code.
Many of the changes are related to indices and directions inconsistency across the code: where x represents horizontal index and y represents vertical index: array index should be board[y][x] (and not board[x][y]).
Many "magic numbers" were changed to constants for better readability of the code.
A toString method was added to the Boardclass to print out a board state. It uses special characters to make a nice printout :
This is helpful when debugging.
public class PegSolver {
private final Board startBoard, destinationBoard;
public PegSolver(Board startBoard, Board destinationBoard) {
super();
this.startBoard = startBoard;
this.destinationBoard = destinationBoard;
}
public void start(){
solve(0,startBoard);
}
private boolean solve(int turn, Board board){
//check if solve
if(board.isFinished(destinationBoard))
{
System.out.println("solved after "+ turn +" turns");
return true;
}
for(int x=0;x<board.boardSize();x++){
for (int y=0;y<board.boardSize();y++)
{
if(board.isLegal(x,y)) {
if(board.canTurn("right",x,y)
//turn++ changed to turn+1 so turn is incremented before invoking next solve
//and avoid changing the value of turn
&& solve(turn+1, board.turn(new Board(board), "right", x, y)))
return true;
else if(board.canTurn("left",x,y)
&& solve(turn+1, board.turn(new Board(board), "left", x, y)))
return true;
else if(board.canTurn("up",x,y)
&& solve(turn+1, board.turn(new Board(board), "up", x, y)))
return true;
else if(board.canTurn("down",x,y)
&& solve(turn+1, board.turn(new Board(board), "down", x, y)))
return true;
}
}
}
return false;
}
public static void main(String[] args) {
Board[] destinationBoards = {
//by order of number of turns
new Board("OOOOOOOOOOOOOO..OOOOOOOOOOOOOOOOO"), //one right turn
new Board("OOO.OOOO.OOOOO.OOOOOOOOOOOOOOOOOO"), //right, down
new Board("OOO.OO..OOOOOO.OOOOOOOOOOOOOOOOOO"), //right, down,right
new Board("OOO.OOO.OOOOO..OOOOO.OOOOOOOOOOOO"), //right, down,right,up
new Board("OOOOOOO..OOOO...OOOO.OOOOOOOOOOOO"), //right, down,right,up,up
new Board(".OO.OOO.OOOOO...OOOO.OOOOOOOOOOOO"), //right, down,right,up,up,down
new Board(".OO.OOO.OOOOO...OOOOO..OOOOOOOOOO"), //right, down,right,up,up,down, left
new Board(".OO.OOO.OOOOO...OOOOO.OOOOO.OO.OO"), //right, down,right,up,up,down,left,up
new Board(".OO.OO..O.OOO...OOOOO.OOOOO.OO.OO"), //10 turns
new Board("..O..O.O..OOO...OOOO..OOOOO..O..O"), //15 turns
new Board(".........O................O......"), //30 turns
new Board("...................O............."), //31 turns
};
Board startBoard = new Board("OOOOOOOOOOOOOOOO.OOOOOOOOOOOOOOOO");
for(Board destinationBoard : destinationBoards ){
new PegSolver(startBoard, destinationBoard).start();
}
}
}
class Board {
//int representation of the three states of a board cell
private final static int EMPTY = 0, PEG = 1, BORDER = 2;
/*cahr representation of the three states of a board cell
special chars are used to get nice printout
todo: change board to char[][] to avoid the need for two
representations (int and char)
*/
private final static char[] CHAR_REPRESENTATION = {9898,9899,10062};
private final static char ERROR = '?';
private final int BOARD_SIZE=7, CORNER_SIZE=2;
private final int board[][] = new int[BOARD_SIZE][BOARD_SIZE];
public Board(String place) {
int loca=0;
for(int y=0;y<BOARD_SIZE;y++){
for(int x=0;x<BOARD_SIZE;x++){
if(isWithinBoard(x,y)) {
if (place.charAt(loca) == 'O') {
loca++;
board[y][x] = PEG;
} else if (place.charAt(loca) == '.') {
loca++;
board[y][x] = EMPTY;
}
}else{
board[y][x] = BORDER;
}
}
}
//for testing
//System.out.println(this);
}
//copy constructor
public Board(Board copy){
for(int x=0;x<BOARD_SIZE;x++)
{
for(int y=0;y<BOARD_SIZE;y++)
{
board[y][x]=copy.getValue(x,y);
}
}
}
public int getValue(int x, int y)
{
return board[y][x]; //and not return board[x][y];
}
public boolean isFinished(Board destination)
{
for(int i=0;i<BOARD_SIZE;i++)
{
for(int j=0;j<BOARD_SIZE;j++)
{
if(this.getValue(i,j)!=destination.getValue(i,j))
return false;
}
}
return true;
}
public Board turn(Board board,String direction,int x,int y)
{
if(direction.equals("right"))
{
board.setValue(x,y,EMPTY);
board.setValue(x+1,y,EMPTY);
board.setValue(x+2,y,PEG);
return board;
}
else if(direction.equals("left"))
{
board.setValue(x,y,EMPTY);
board.setValue(x-1,y,EMPTY);
board.setValue(x-2,y,PEG);
return board;
}
else if(direction.equals("up"))
{
board.setValue(x,y,EMPTY);
board.setValue(x,y-1,EMPTY);
board.setValue(x,y-2,PEG);
return board;
}
else if(direction.equals("down"))
{
board.setValue(x,y,EMPTY);
board.setValue(x,y+1,EMPTY);
board.setValue(x,y+2,PEG);
return board;
}
System.out.println("there is not such direction, method turn on startBoard class");
return null;
}
public boolean isLegal(int x, int y){
if(board[y][x]==BORDER) //and not if(board[x][y]==BORDER)
return false;
return true;
}
public boolean canTurn(String direction,int x,int y){
if(direction.equals("right") && x < BOARD_SIZE - 2)
{
if (board[y][x] == PEG && board[y][x + 1] == PEG && board[y][x + 2] == EMPTY)
return true;
}
else if(direction.equals("left") && x > 1)
{
if (board[y][x] == PEG && board[y][x - 1] == PEG && board[y][x - 2] == EMPTY)
return true;
}
else if(direction.equals("up") && y > 1)
{
if (board[y][x] == PEG && board[y - 1][x] == PEG && board[y - 2][x] == EMPTY)
return true;
}
else if(direction.equals("down") && y < BOARD_SIZE - 2)
{
if (board[y][x] == PEG && board[y + 1][x] == PEG && board[y + 2][x] == EMPTY)
return true;
}
return false;
}
public void setValue(int x, int y, int value)
{
board[y][x]=value; //and not board[x][y]=value;
}
//for square nxn board
public int boardSize(){
return board.length;
}
public boolean isWithinBoard(int x, int y){
//check bounds
if (x < 0 || y < 0 || x >= BOARD_SIZE || y >= BOARD_SIZE) return false;
//left top corner
if (x < CORNER_SIZE && y < CORNER_SIZE) return false;
//right top corner
if(x >= BOARD_SIZE - CORNER_SIZE && y < CORNER_SIZE) return false;
//left bottom corner
if(x < CORNER_SIZE && y >= BOARD_SIZE - CORNER_SIZE) return false;
//right bottom corner
if(x >= BOARD_SIZE - CORNER_SIZE && y >= BOARD_SIZE - CORNER_SIZE) return false;
return true;
}
#Override
public String toString() {
StringBuilder sb = new StringBuilder();
for (int[] row : board) {
for(int cell : row){
if(cell<CHAR_REPRESENTATION.length && cell >= 0) {
sb.append(CHAR_REPRESENTATION[cell]);
}else{
sb.append(ERROR);
}
}
sb.append("\n"); //new line
}
return sb.toString();
}
}
Todo:
The code is working but it needs further in-depth testing and debugging.
If something is not clear, don't hesitate to ask.

Is there a solution to prevent this recursion?

In this program, a randomly generated 2D array is populated with 1's or 0's and I attempt to find a path of 1's (no diagonal movement). I have got the program to work for smaller dimensions of the 2D array, but when the dimensions are too large, the error Exception in thread "main" java.lang.StackOverflowError occurs.
import java.util.Scanner;
import java.util.Random;
public class Daft {
private int counter = 0;
public static void main(String[] args) {
Daft punk = new Daft();
punk.run();
}
public void run() {
int ans;
int[][] array;
int[][] solvedPath;
do {
counter = 1;
array = populate(defineArray(firstDimension(),secondDimension()));
solvedPath = findPath(array);
System.out.println("Times before solvable: " + counter);
print(solvedPath);
ans = continuity();
}while(ans != 0);
}
public int[][] findPath(int[][] array) {
int r = 0, c = 0;
while(true) {
array[0][0] = 7;
if(c == 0 && r == array.length-1) { //reached the bottom left, checks right
if(array[r][c+1] == 1) {
array[r][c+1] = 7;
c+=1;
} else {
array[r][c] = 7;
break;
}
} else if(c == array[0].length-1 && r == array.length-1) { //reached the bottom right, checks left
if(array[r][c-1] == 1) {
array[r][c-1] = 7;
} else {
array[r][c] = 7;
break;
}
} else if(r == array.length-1) { //reached the bottom, checks left/right
if(array[r][c+1] == 1 && array[r][c-1] == 1) {
counter++;
newPath(array);
break;
} else if(array[r][c+1] == 1) { //checks right
array[r][c+1] = 7;
c+=1;
} else if(array[r][c-1] == 1) { //checks left
array[r][c-1] = 7;
c-=1;
} else { //end of path
array[r][c] = 7;
break;
}
} else if(c == 0) { //reached the left, checks right/bottom
if(array[r][c+1] == 1 && array[r+1][c] == 1) { //checks if path is unique
counter++;
newPath(array);
break;
} else if(array[r][c+1] == 1) {
array[r][c+1] = 7;
c+=1;
} else if(array[r+1][c] == 1) {
array[r+1][c] = 7;
r+=1;
} else {
counter++; //path has ended, not solvable
newPath(array);
break;
}
} else if(c == array[0].length-1) { //reached the right, checks left/bottom
if(array[r+1][c] == 1 && array[r][c-1] == 1) { //checks if path is unique
counter++;
newPath(array);
break;
} else if(array[r+1][c] == 1) {
array[r+1][c] = 7;
r+=1;
} else if(array[r][c-1] == 1) {
array[r][c-1] = 7;
c-=1;
} else {
counter++; //path has ended, not solvable
newPath(array);
break;
}
} else if(array[r][c+1] == 1 && array[r+1][c] == 1) { //checks if path is unique
counter++;
newPath(array);
break;
} else if(array[r][c-1] == 1 && array[r+1][c] == 1) { //checks if path is unique
counter++;
newPath(array);
break;
} else if(array[r][c+1] == 1) { //checks right
array[r][c+1] = 7;
c+=1;
} else if(array[r+1][c] == 1) { //checks bottom
array[r+1][c] = 7;
r+=1;
} else if(array[r][c-1] == 1) { //checks left
array[r][c-1] = 7;
c-=1;
} else {
counter++;
newPath(array);
break;
}
}
return array;
}
public int firstDimension() {
Scanner in = new Scanner(System.in);
System.out.println("Size of the first dimension:");
return in.nextInt();
}
public int secondDimension() {
Scanner in = new Scanner(System.in);
System.out.println("Size of the second dimension:");
return in.nextInt();
}
public int[][] defineArray(int firstDimension, int secondDimension) {
return new int[firstDimension][secondDimension];
}
public int[][] populate(int[][] array) {
Random rand = new Random();
for(int i = 0; i < array.length; i++) {
for(int j = 0; j < array[i].length; j++) {
array[i][j] = rand.nextInt(2);
}
}
return array;
}
public int continuity() {
Scanner in = new Scanner(System.in);
System.out.println("Enter a number to continue (0 to quit):");
return in.nextInt();
}
public void print(int[][] array) {
for(int[] ints : array) {
for(int anInt : ints) {
System.out.print(anInt + " ");
}
System.out.println();
}
System.out.println();
}
public void newPath(int[][] array) {
findPath(populate(array));
}
}

Java maze won't print

I have to make a maze for a java assignment, and I was able to finish most of it. I was provided with an outline of the code that had all the methods. Can someone help me? My issue is that the maze wont print out, and I can't figure out why.
package maze;
public class Maze {
private char direction;
private int r; // x position of the mouse
private int c; //y position of the mouse
private boolean exitFound = false;
public Maze(int[][] arrMaze) {
this.r = arrMaze.length - 1;
this.c = 0;
}
//Prints out the maze without solution
public void displayMaze(int[][] arrMaze)
{
//display the maze putting blank spaces where there are 1's in the array and putting
//another symbol where there are 0's to show the maze without the solution
for(int i=0; i<arrMaze.length; i++){
System.out.println(" ");
for(int j=0; j<arrMaze[i].length; j++){
if(arrMaze[i][j] == 0){
System.out.print("#");
} if(arrMaze[i][j] == 1) {
System.out.print(" ");
} if(arrMaze[i][j] == 2){
System.out.print("#");
} if(arrMaze[i][j] == 3){
System.out.println("~");
}
}
}
}
//displays the Maze with the path taken
public void displayPath(int[][] arrMaze)
{
//show the user how far the mouse has gone since the start.
//The path the mouse has gone will be filled in but the path ahead will not.
for (int i = 0; i < arrMaze.length; i++) {
System.out.println(" ");
for (int j = 0; j < arrMaze[i].length; j++) {
if (arrMaze[i][j] == 3) {
System.out.print("#");
} else if (arrMaze[i][j] == 2) {
System.out.print("~");
} else if (arrMaze[i][j] == 0) {
System.out.print("#");
} else {
}
}
}
}
public boolean takeStep(int[][] newMaze) {
// moveNorth(newMaze)
for (int i = 0; i < newMaze.length; i++) {
System.out.println(" ");
for (int j = 0; j < newMaze[i].length; j++) {
if (newMaze[r][c] == 3) {
moveNorth(newMaze);
System.out.print("~");
} else if (newMaze[r][c] == 2) {
System.out.print("#");
} else {
}
}
}
return isAnExit(newMaze);
}
public void moveNorth(int[][] arrMaze) {
//complete the code here
/*method will check for a 0 or a 1 in the position above the current position
* and then if not a 0 will change the current position to the row above it, but in the same column.
*/
if (arrMaze[r][c - 1] != 0) {
arrMaze[r][c - 1] = 3;
arrMaze[r][c + 1] = 2;
} else {
moveSouth(arrMaze);
}
displayPath(arrMaze);
}
public void moveSouth(int[][] arrMaze)
{
//method will check for a 0 or a 1 in the position below the current position and then if not a 0
//it will change the current position to the row below it, but in the same column.
if (arrMaze[r][c + 1] != 0) {
arrMaze[r][c + 1] = 3;
arrMaze[r][c + 1] = 2;
} else {
moveNorth(arrMaze);
}
displayPath(arrMaze);
}
public void moveEast(int[][] arrMaze) {
//method will check for a 0 or a 1 in the position to the right of  the current position and then if
//not a 0 will change the current position to the column to the right but the same row.
if (arrMaze[r + 1][c] != 0) {
arrMaze[r + 1][c] = 3;
arrMaze[r - 1][c] = 2;
} else {
moveWest(arrMaze);
}
displayPath(arrMaze);
}
public void moveWest(int[][] arrMaze) {
//method will check for a 0 or a 1 in the position to the left of  the current position and then if
//not a 0 will change the current position to the column to the left but the same row.
if (arrMaze[r - 1][c] != 0) {
arrMaze[r - 1][c] = 3;
arrMaze[r + 1][c] = 2;
} else {
}
displayPath(arrMaze);
}
private boolean isAnExit(int[][] arrMaze) {
//method will return true if the user arrives into the last column of the array because there is only one
//location in the last column that is a 1, so if the user reaches the array[i].length then that means that it found an exit.
if (arrMaze[r][c] > arrMaze.length) {
exitFound = true;
} else {
exitFound = false;
}
return exitFound;
}
//finds the path without stopping at every step
//method will show the complete path from start to finish of the maze and the suggested route to the end.
public void findExit(int[][] arrMaze) {
if (arrMaze[r][c] > arrMaze.length) {
for (int i = 0; i < arrMaze.length; i++) {
takeStep(arrMaze);
}
}
}
}
This is the test code. I was provided the test code, and I haven't changed it.
package maze;
import java.util.Scanner;
public class TestMaze
{
public static void main(String[] args)
{
int[][] mazeArray = {
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0},
{0,0,0,1,1,1,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,1,1,1,1},
{0,0,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0},
{0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0},
{1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
Maze myMaze = new Maze(mazeArray);
boolean keepAsking = true;
Scanner scan = new Scanner(System.in);
String input = "";
myMaze.displayPath(mazeArray);
System.out.println("Maze");
do {
System.out.println("T = Take a step | S = Show path | Q = Quit");
System.out.print("Enter command: ");
input = scan.nextLine();
input.trim();
input.toLowerCase();
if(input.equals("t")) {
keepAsking = !myMaze.takeStep(mazeArray);
System.out.println("Which direction would you like to go? N, S, E, W?");
String direction = scan.nextLine();
if(direction.equalsIgnoreCase("n"))
myMaze.moveNorth(mazeArray);
if(direction.equalsIgnoreCase("s"))
myMaze.moveSouth(mazeArray);
if(direction.equalsIgnoreCase("e"))
myMaze.moveEast(mazeArray);
if(direction.equalsIgnoreCase("w"))
myMaze.moveWest(mazeArray);
}
else if(input.equals("s")) {
myMaze.findExit(mazeArray);
keepAsking = false;
}
else if(input.equals("q")) {
keepAsking = false;
}
else {
System.out.println("ERR: Invalid input");
}
} while(keepAsking);
System.out.println("Quitting program...");
scan.close();
}
}
You need to call displayMaze() (in displayPath()) to print it.
Currently, you're not calling the method, meaning that your code will never print the maze as it's no being instructed to.
Also, where are you assigning values to r and c? I think you meant to use i and j in your displayPath() method ([i][j] instead of [r][c]).
I imagine you're throwing an error somewhere because your r and c values are undefined everywhere they are used. Try adding code to initialize and update these values, then you should see your maze print.

To test, using a backtracking algorithm, if a mouse can escape from a rectangular maze

This program has is meant to create and solve a mouse escape route from a maze, by reading from a text file.There is a Maze class which is basically a 2D array of MazeElements, the MazeElements contains a char variable and a position object; the Position holds the co-ordinates of each element on the 2D-array.
So far, the program effectively reads in and creates the 2D array. The problem lies in the backTracking algorithm. I am using a stack to implement the back track but the backtrack seems to only loop once from the output. I don't know if you can notice something from the code below:
import java.io.;
import java.util.;
public class MazeSolver
{
public static void main (String [] parms)
{
Maze maze = new Maze();
maze.displayMaze();
maze.backTracking();
maze.displayMaze();
}
}
//**********************************
//*******Position class*************
//**********************************
class Position
{
private int row;
private int col;
public Position()
{
row =0;
col =0;
}
public Position (int x, int y)
{
row = x;
col = y;
}
public void setRow(int x)
{
row = x;
}
public void setCol(int y)
{
col = y;
}
public int getRow()
{
return row;
}
public int getCol()
{
return col;
}
//NOTE: wrote for testing purposes, to see the mouse and exit positions
public String getPosition()
{
return row + ", " + col;
}
}//end Position
//**********************************
//*******Maze element class*********
//**********************************
class MazeElement
{
private char letter;
private Position prevPosition;
public MazeElement(char c, Position p)
{
this.letter = c;
this.prevPosition = p;
}
public char getLetter()
{
return letter;
}
public Position getPosition()
{
return prevPosition;
}
public void setPosition(Position p)
{
this.prevPosition = p;
}
public void setLetter(char c)
{
this.letter = c;
}
public void printElement()
{
System.out.print(letter + " ");
}
}//end MazeElement
//**********************************
//*******Maze class*****************
//**********************************
class Maze
{
private MazeElement [][] maze;
private int numRows;
private int numCols;
private Position start;
private Position exit;
BufferedReader inFile;
Scanner kbd = new Scanner(System.in);
String inLine;
String fileName;
String [] tokens;
public Maze()
{
try
{
System.out.println("Input file name");
fileName = kbd.next();
inFile = new BufferedReader(new FileReader(fileName));
inLine = inFile.readLine();
tokens = inLine.trim().split("\\s+");
numRows = Integer.parseInt(tokens[0]);
numCols = Integer.parseInt(tokens[1]);
maze = new MazeElement[numRows][numCols];
for(int row = 0; inLine != null && row < numRows; row++)
{
inLine = inFile.readLine();
tokens = inLine.trim().split("\\s+");
for(int col = 0; col < numCols; col++)
{
maze[row][col] = new MazeElement(tokens[col].charAt(0),null);
}
}
inFile.close();
//finding m and e from the maze
for (int i = 0; i < maze.length; i++)
{
for (int j = 0; j < maze[i].length; j++)
{
char letter = maze[i][j].getLetter();
if(letter == 'm')
{
start = new Position(i,j);
}
if(letter == 'e')
{
exit = new Position(i,j);
}
}
}
}//end try block
catch (IOException ioe)
{
System.out.println(ioe.getMessage());
}
}//end public Maze()
public void backTracking()
{
Stack<Position> theStack = new Stack<Position>();//initialise stack
Position goal = exit;
Position curr;
MazeElement north, south, east, west;
int currRow, currCol;
curr = null;
boolean foundGoal = false;
theStack.push(start);
while((!foundGoal) && (!theStack.isEmpty()))
{
curr = theStack.pop();
currRow = curr.getRow();
currCol = curr.getCol();
//check neighbouring positions
east = maze[currRow][currCol+1];
south = maze[currRow+1][currCol];
west = maze[currRow][currCol-1];
north = maze[currRow-1][currCol];
//searching clockwise
//setting visited positions to '.', open = '0', wall = '1', exit==goal = 'e'
if(isValidPosition(east))
{
if(east.getLetter() == 'e')
{
east.setPosition(curr);
theStack.push(east.getPosition());
foundGoal = true;
}
else if((!foundGoal)&&(east.getLetter() == '0')&& (east.getLetter() != '.'))
{
east.setLetter('.');
east.setPosition(curr);
theStack.push(east.getPosition());
}
}
else if(isValidPosition(south))
{
if(south.getLetter() == 'e')
{
south.setPosition(curr);
theStack.push(south.getPosition());
foundGoal = true;
}
else if((!foundGoal)&&(south.getLetter() == '0')&& (south.getLetter() != '.'))
{
south.setLetter('.');
south.setPosition(curr);
theStack.push(south.getPosition());
}
}
else if(isValidPosition(west))
{
if(west.getLetter() == 'e')
{
west.setPosition(curr);
theStack.push(west.getPosition());
foundGoal = true;
}
else if((!foundGoal)&&(west.getLetter() == '0')&& (west.getLetter() != '.'))
{
west.setLetter('.');
west.setPosition(curr);
theStack.push(west.getPosition());
}
}
else if(isValidPosition(north))
{
if(north.getLetter() == 'e')
{
north.setPosition(curr);
theStack.push(north.getPosition());
foundGoal = true;
}
else if((!foundGoal)&&(north.getLetter() == '0')&& (north.getLetter() != '.'))
{
north.setLetter('.');
north.setPosition(curr);
theStack.push(north.getPosition());
}
}
}//end while
}
public void displayMaze()
{
for (int i = 0; i < maze.length; i++)
{
for (int j = 0; j < maze[i].length; j++)
{
maze[i][j].printElement();
}
System.out.println();
}
System.out.println("start is at " + start.getPosition());
System.out.println("exit is at " + exit.getPosition());
}//displayMaze()
public boolean isValidPosition(MazeElement element)
{
char wall = '1';
return (element.getLetter() != wall);
}
}
//**********************************
//*******Stack<E> class*************
//**********************************
class Stack<E>
{
protected Node<E> head;
public Stack()
{
head = null;
}
public boolean isEmpty()
{
return (head == null);
}
public void push(E item)
{
head = new Node<E>(item, head);
}
public E top()
{
E topItem = null;
if (head != null) topItem = head.getData();
return topItem;
}
public E pop()
{
E topItem = top();
if (head != null) head = head.getNext();
return topItem;
}
}
//**********************************
//*******Node class*****************
//**********************************
class Node <E>
{
private E data;
private Node<E> next;
public Node ()
{
//initializing everything to null at first
next = null;
data = null;
}
public Node(E data, Node <E> n)
{
this.data = data;
this.next = n;
}
public E getData()
{
return data;
}
public Node <E> getNext()
{
return next;
}
public void setNext(Node <E> next)
{
this.next = next;
}
}
My input file is the following:
6 5
1 1 1 1 1
1 0 0 e 1
1 1 1 0 1
1 m 1 0 1
1 0 0 0 1
1 1 1 1 1
When I print the maze after I call the backTrack() method, my Maze(with m and e positions) becomes:
1 1 1 1 1
1 0 0 e 1
1 1 1 0 1
1 m 1 0 1
1 . 0 0 1
1 1 1 1 1
start is at 3, 1
exit is at 1, 3
The issue is that I do not understand why my curr doesn't move beyond the point '.' in the output. Please help?
Here:
if(isValidPosition(east))
{
if(east.getLetter() == 'e')
{
east.setPosition(curr);
theStack.push(east.getPosition());
foundGoal = true;
}
else if((!foundGoal)&&(east.getLetter() == '0')&& (east.getLetter() != '.'))
{
east.setLetter('.');
theStack.push(east.getPosition());
}
}
Original :
From what I can tell, the only thing that has been pushed into theStack is start. So, curr == start. Then, in your conditions, if it meets the directions you do:
east.setPosition(curr);
theStack.push(east.getPosition());
(Or whichever direction it tests on, in this case it's actually south).
Remember, the first time curr == start, so you're setting east.setPosition == curr == start, which means you push back to the stack start.
Now, the code runs again with only 1 thing in the theStack and it's the same as it was before, EXCEPT, the character below start is now a '.', so there are no valid directions and your while loop breaks.
To fix the code, you'll have to push to theStack a Position whose values are the direction's and not update the direction position.
I made a few changes to your code, first to the map loading function, so that every element had a position. You can get rid of this and use rheStack.push(new Position(row,col)); but i was too lazy.
for(int row = 0; inLine != null && row < numRows; row++)
{
inLine = inFile.readLine();
tokens = inLine.trim().split("\\s+");
for(int col = 0; col < numCols; col++)
{
maze[row][col] = new MazeElement(tokens[col].charAt(0),new Position(row,col));
}
}
The next change is to the backtracking code. Now in essence you can backtrack using only a stack, however it is not enough to just store the places you have been. For example, after if you first went east and then west, then you need to store that on the stack as well. This makes backtracking more complicated, however programming languages gives us a much easier way of dealing with stacks - recursion.
All the parameters passed to a function, and all the temporaries it creates, are stored on a special stack - the program stack. This is the same stack referenced in StackOverflow. Therefore recursive functions have all the same strucutre as a backtracking alogorithm.
So I broke you backtracking algorithm to make it recursive
public void backTracking()
{
Stack<Position> theStack = new Stack<Position>();//initialise stack
theStack.push(start);
//pass it the stack and the goal
backTrackingRecursive(theStack, exit);
}
public boolean backTrackingRecursive(Stack<Position> theStack, Position goal)
{
//displayMaze();
Position curr = theStack.top();
int currRow = curr.getRow();
int currCol = curr.getCol();
//setting visited positions to '.', open = '0', wall = '1', exit==goal = 'e'
for(int i = 0; i != 4; i++)
{
//forget this code, it is only to avoid writing out north, south, etc
int col = currCol;
int row = currRow;
if(i%2 == 1)
col += ((i==1)?1:-1);
else
row += ((i==2)?1:-1);
//check it is a valid position, if not continue
if(row < 0 || row >= numRows || col < 0 || col >= numCols) continue;
MazeElement next = maze[row][col];
if(next.getLetter() == 'e')
{
theStack.push(next.getPosition());
return true;
}
else if(next.getLetter() == '0')
{
theStack.push(next.getPosition());
next.setLetter('.');
if(backTrackingRecursive(theStack,goal))
{
//success!
return true;
} else {
//try a different path
next.setLetter('0');
theStack.pop();
}
}
}
return false;
}
The backTrackingRecursive function does all the work, and we simply push the next position on to the stack before continuing. We don't even need to have the stack at all but I kept it for simplicity.
Output:
1 1 1 1 1
1 0 0 e 1
1 1 1 0 1
1 m 1 0 1
1 0 0 0 1
1 1 1 1 1
start is at 3, 1
exit is at 1, 3
1 1 1 1 1
1 0 0 e 1
1 1 1 . 1
1 m 1 . 1
1 . . . 1
1 1 1 1 1
start is at 3, 1
exit is at 1, 3
this works perfectly!!!! i followed the comments from the first answer and found this solution! thank you #CreationEdge
if(isValidPosition(east))
{
if(east.getLetter() == 'e')
{
foundGoal = true;
}
if((!foundGoal)&&(east.getLetter() == '0')&& (east.getLetter() != '.'))
{
east.setLetter('.');
east.setPosition(curr);
theStack.push(new Position(curr.getRow(), curr.getCol()+1));
}
}
if(isValidPosition(south))
{
if(south.getLetter() == 'e')
{
System.out.println(south.getLetter());
foundGoal = true;
}
if((!foundGoal)&&(south.getLetter() == '0')&& (south.getLetter() != '.'))
{
south.setLetter('.');
south.setPosition(curr);
theStack.push(new Position(curr.getRow() + 1, curr.getCol()));
}
}
if(isValidPosition(west))
{
if(west.getLetter() == 'e')
{
foundGoal = true;
}
if((!foundGoal)&&(west.getLetter() == '0')&& (west.getLetter() != '.'))
{
west.setLetter('.');
west.setPosition(curr);
theStack.push(new Position(curr.getRow(), curr.getCol()-1));
}
}
if(isValidPosition(north))
{
if(north.getLetter() == 'e')
{
foundGoal = true;
}
if((!foundGoal)&&(north.getLetter() == '0')&& (north.getLetter() != '.'))
{
north.setLetter('.');
north.setPosition(curr);
theStack.push(new Position(curr.getRow() - 1, curr.getCol()));
}
}

Categories

Resources