StackOverflow error for maze solving program - java

Currently I am trying to solve a program that determines whether it is possible to solve a maze and if the maze is solvable it should print out the number of steps to go through the maze path. The starting position and the end position and the maze are given in a input file in the following format:
Line 1: test cases(N)
For each N lines the first line will contain size of the maze, the start position and the end exit location will be given. Then a visual depiction of the maze will also be present in the input file
For example the sample input for this challenge is:
3
6 7 0 0 5 6
1110111
1011101
1001001
1011101
1000001
1111110
3 3 2 0 0 2
111
110
111
5 5 1 0 3 1
01111
11001
01001
01001
01111
The excact rules of the maze are that the 0s are inpenetrable walls and the 1s are free walking space being able to move around. Also the end position is not marked by any special character but rather the location is given to us.
The following code is my approach to the challenge which is obviously not functional:
import java.io.*;
import java.util.*;
public class Maze
{
public static void main(String[] args) throws FileNotFoundException
{
Scanner sc = new Scanner(new File("maze.txt"));
int tc = sc.nextInt();
for(int p = 0; p < tc; p++ ) {
int rows = sc.nextInt();
int cols = sc.nextInt();
int startRow = sc.nextInt();
int startCol = sc.nextInt();
int endRow = sc.nextInt();
int endCol = sc.nextInt();
sc.nextLine();
char[][] maze = new char[rows][cols];
for(int i = 0; i < rows; i++) {
String s = sc.nextLine();
for(int j = 0; j < cols; j++) {
maze[i][j] = s.charAt(j);
}
}
if(solvable(maze,startRow,startCol,endCol,endRow)) {
int count = 0;
for(char[] arr : maze) {
for(char elem: arr) {
if(elem == 'x') count++;
}
}
System.out.println("It takes " + count + " steps to solve the maze");
}else {
System.out.println("Unsolvable");
}
}
}
public static boolean solvable(char[][] maze,int row, int col,int finishRow, int finishCol) {
if(row < 0 || col < 0 || row >maze.length - 1 || col > maze[0].length - 1) {
return false;
}
if(row == finishRow && col == finishCol) {
return true;
}
if(maze[row][col] == 0) {
return false;
}
char c = maze[row][col];
maze[row][col] = 'x';
if(solvable(maze,row + 1,col,finishRow,finishCol)) {
return true;
}
if(solvable(maze,row - 1,col,finishRow,finishCol)){
return true;
}
if(solvable(maze,row ,col + 1,finishRow,finishCol)) {
return true;
}
if(solvable(maze,row,col - 1,finishRow,finishCol)) {
return true;
}
maze[row][col] = c;
return false;
}
}
As seen by the title this program produces a stack overflow error. I am incorporating the general algorithm for solving a maze and not incorporating the flood fill alogorithm. I need to identify the flaw in my recursive method solvable. Please note that this is a competetive programming enviorment so coding from the object oriented side of java would be inconvinient.

The problem is the infinite recursion in solvable. Why is that?
Why it never terminates?
Let's take a closer look at how it works:
return false if the position is invalid
return true if the position is the target
return false if the position is the start
This is a bit strange thing to do, but whatever, let's move on
At this point we know the current position is valid
Save the old value of the current position, and mark it with 'x'
Try to move in all possible directions
Restore the original value of the current position
Where's the flaw in this logic?
When is the marking 'x' used? -> Ha!
If the marking 'x' is not used, what's going to happen? -> Ha!
Imagine this is the maze, and the algorithm always checks the path going down first before checking other directions:
#####
#S E#
# ###
# ###
#####
The algorithm will first go from S until the bottom.
At the bottom there is a way to go up,
so it goes one step up.
There, there is a way to go down, so it goes back down.
And it gets stuck going up and down forever.
So the solution is to use the 'x' markings to avoid exploring the same positions forever.

Related

Why do I get an "ArrayIndexOutOfBounds" error in this program?

I have written a program in which the user inputs the dimensions of a two-dimensional array, then the computer prints out the table with those dimensions and fills it with random integers from 0 to 9. Then, if there are four consecutive equal integers that appear anywhere in the table, the computer would return "True". If there are no consecutive equal integers in the table, it would return "False". For instance:
2 5 8 7 1
3 2 9 4 7
5 1 2 0 3
8 0 1 2 7
In that table, two appear consecutively, diagonally from the first spot. It can also be like this:
9 5 3 7 0
2 5 7 3 1
8 5 0 2 9
4 5 1 7 5
In this table, five appear vertically down from the second spot.
This is the code of the program:
/*MyName*/
package fourconsecutivenumbers;
import java.util.Random;
import java.util.Scanner;
public class FourConsecutiveNumbers {
public static void main(String[] args) {
Scanner rowDimension = new Scanner(System.in);
System.out.print("Enter the number of rows: ");
int firstInput = rowDimension.nextInt();
Scanner columnDimension = new Scanner(System.in);
System.out.print("Enter the number of columns: ");
int secondInput = columnDimension.nextInt();
int[][] randomTable = new int[firstInput][secondInput];
for (int row = 0; row < firstInput; row++) {
for (int column = 0; column < secondInput; column++) {
randomTable[row][column] = (int)(Math.random() * 10 + 0);
System.out.print(randomTable[row][column] + " ");
}
System.out.println();
}
if(check_horizontal(randomTable) || check_vertical(randomTable) || check_diagonal(randomTable)){
System.out.println("True");
}
else {
System.out.println("False");
}
}
public static boolean check_vertical(int[][] randomTable) {
for (int i = 0; i<randomTable.length; i++){
for(int t=0; t<randomTable[0].length-3;t++){
if (randomTable[i][t]==randomTable[i][t+1] && randomTable[i][t+1]==randomTable[i][t+2] && randomTable[i][t+2]==randomTable[i][t+3]){
return true;
}
}
}
return false;
}
public static boolean check_horizontal(int[][] randomTable){
for (int i = 0; i<randomTable.length; i++){
for(int t=0; t<randomTable[0].length-3;t++){
if (randomTable[t][i]==randomTable[t+1][i] && randomTable[t+1][i]==randomTable[t+2][i] && randomTable[t+2][i]==randomTable[t+3][i]){
return true;
}
}
}
return false;
}
public static boolean check_diagonal(int[][] randomTable){
//check down
for (int t =0; t<randomTable.length-3; t++){
for(int i=0; i<randomTable[0].length-3;i++){
if (randomTable[i][t]==randomTable[i+1][t+1] && randomTable[i+1][t+1]==randomTable[i+2][t+2] && randomTable[i+2][t+2]==randomTable[i+3][t+3]){
return true;
}
}
}
//check up
for (int t =0; t<randomTable.length-3; t--){
for(int i=0; i<randomTable[0].length-3;i++){
if (randomTable[t][i]==randomTable[t-1][i+1] && randomTable[t-1][i+1]==randomTable[t-2][i+2] && randomTable[t-2][i+2]==randomTable[t-3][i+3]){
return true;
}
}
}
return false;
}
}
Now the error I get is:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -1
at fourconsecutivenumbers.FourConsecutiveNumbers.check_diagonal(FourConsecutiveNumbers.java:70)
at fourconsecutivenumbers.FourConsecutiveNumbers.main(FourConsecutiveNumbers.java:25)
Java Result: 1
I know that it says the error is at line 70 and then at line 25, but I don't know what I did wrong. I am fairly new to programming so I was hoping that a more experienced program can see what I did wrong. Help is much appreciated!
This is the problem:
randomTable[t-1][i+1]
When t is 0, that will be accessing randomTable[-1][i + 1] - which can never be valid. Likewise you later go on to t - 3.
Additionally, your loop is starting at 0 but then going backwards... so even if the first iteration completed, you'd end up with t=-1 for the second iteration.
You probably want the loop declaration to be:
for (int t = randomTable.length; t >= 3; t--)
Or just:
for (int t = 3; t < randomTable.length; t++)
depending on whether you really need t to decrease or not.
Additionally, I'd recommend that you follow Java naming conventions - checkHorizontal instead of check_horizontal etc.

I need to make a triforce containing 3 lines of number for each triangle

Each line is the same number and in all three triangles the number is the same.
Input:
The first line contains an integer n that represents the number of data sets to follow.
Each data set will consist of 1 integer m that represents the number that the Triforce of Courage contains throughout.
Output:
Print out a triforce, using this template (replacing 0 with the integer specified):
0
000
00000
0 0
000 000
00000 00000
Assumptions: The number to be replaced will be:0<=m<=9
Sample Input:
1
2
Sample Output:
2
222
22222
2 2
222 222
22222 22222
The following is my code thus far:
import java.lang.Math;
import java.util.Scanner;
import java.io.*;
import java.util.*;
import java.io.FileNotFoundException;
public class TriforceOfCourage {
public static void main(String[] args) throws FileNotFoundException {
Scanner scan=new Scanner(new File("num.dat"));
int n = scan.nextInt();
int count = 0;
while(count<n) {
for (int i=0; i<3; i++) {
for (int k=0; k<3-i; k++) {
System.out.print(" ");
}
for (int j=0; j<i*2+1; j++) {
System.out.print(n);
}
System.out.println("");
}
break;
}
}
}
There are many possible solutions to this problem. In general, there are many good strategies you would typically use to solve this:
Look for a pattern. Can you find a pattern that can be easily expressed through logic and algebraic operations?
Can the problem be broken down into smaller, more manageable parts? Sometimes what appears to be a complex problem can be separated into smaller, very simple problems.
When in doubt, work things out on paper.
Let's take your example. At a glance, personally, I would divide the output into two halves; the top, consisting of a single triangle, and the bottom, consisting of a two triangles side by side. Further, let's focus on just being able to draw a triangle at all. Let's say we want to produce this, a triangle at an arbitrary location:
11
012345678901
0 x
1 xxx
2 xxxxx
We notice the triangle is centered on column 7, and we suspect it will help us if we can draw a triangle in any column, so let's let center be the center column of our triangle. A lot of these types of strategies involve coming up with a way to parameterize the problem. For this approach we want to find the answer to this question:
Given row, column, and center, should we draw a character at that location?
Let's take a simple algebraic approach first, one row at a time, and see if we notice any patterns:
row == 0: Here we output only when column == center.
row == 1: Here we output when column >= center - 1 && column <= center + 1.
row == 2: Here we output when column >= center - 2 && column <= center + 2.
Notice a pattern? Think about it for a second. Recognizing that row == 0 isn't actually a special case, the pattern is:
Output when column >= center - row && column <= center + row.
Great! Now we can output a triangle very easily:
int center = 7; // From our example.
for (int row = 0; row < 3; ++ row) {
for (int column = 0; column < 11; ++ column) {
if (column >= center - row && column <= center + row)
System.out.print("x"); // Replace with whatever character to print.
else
System.out.print(" ");
}
System.out.println(); // Line break after each row, of course.
}
But what about two triangles, for the bottom half? The simplest of course would be to do the exact same as above, but since we have two triangles, we have two centers (say, centerL and centerR), and can simply add a second if block in our bottom-half loop -- same logic for both centers, all in one loop. I'll leave this as an exercise to you.
Now, like I said, there are many possible solutions. Choose the one that makes the most sense for you and is easiest for you to get your head around. In fact, as a learning exercise, I would suggest trying to implement this program with at least three different algorithms. For example:
Loop over all 6 rows (instead of top and bottom half) and put all 3 triangles in the same loop.
Create a 2D array and draw the triangles into it, then output the contents.
Try to implement the above without using if at all (e.g. loops to output from center - row to center + row, and separate loops for the borders) - this is similar to your current approach.
Try to create a method that can draw triangles of any height, not just 3.
Try to create a method that can draw any "triangle of triangles", e.g. 3, 4, 5 rows of triangles.
And of course,
As promised, i will be posting my solution. Thanks to MR. Jason i was able to solve this problem and now i need to make some slight modifications to where it reads in the numbers from a file but that i can comprehend with easily.
// By Rexhep Rexhepi
// 11/12/14
// BIG THANKS TO MR. Jason!
import java.lang.Math;
import java.util.Scanner;
import java.io.*;
import java.util.*;
import java.io.FileNotFoundException;
public class TriforceOfCourage
{
public static void main(String[] args) throws FileNotFoundException
{
Scanner scan=new Scanner(new File("num.dat"));
int n = scan.nextInt();
int count = 0;
int center = 5;
int centerL = 2;
int centerR = 8;
for (int row = 0; row < 3; ++ row)
{
for (int column = 0; column < 11; ++ column)
{
if (column >= center - row && column <= center + row)
System.out.print("x"); // Replace with whatever character to print.
else
System.out.print(" ");
}
System.out.println(); // Line break after each row, of course.
}
for(int rowB = 0; rowB < 3; rowB++)
{
for (int columnL= 0;columnL < 5; columnL++)
{
if (columnL>= centerL - rowB && columnL <= centerL + rowB)
System.out.print("x");
else
System.out.print(" ");
}
for (int columnR = 5; columnR<11; columnR++)
{
if (columnR>= centerR-rowB && columnR <= centerR+rowB)
System.out.print("x");
else
System.out.print(" ");
}
System.out.println();
}
}
}
In the below code triforce(...) will print the required output.
public void triforce(int n, int m) {
triangleWithSpaces(2, 1, n, m);
triangleWithSpaces(2, 2, n, m);
}
public void triangleWithSpaces(int s, int t, int n, int m) {
for (int i = 0; i <= n; i++) {
for (int k = 0; k < t; k++) {
for (int j = 0; j < ((n * 2 + 1) / 2 + 1) * (s - t); j++) {
System.out.print(" ");
}
for (int j = n - i; j > 0; j--) {
System.out.print(" ");
}
for (int j = 0; j < i * 2 + 1; j++) {
System.out.print(m);
}
for (int j = n - i; j > 0; j--) {
System.out.print(" ");
}
System.out.print(" ");
}
System.out.println();
}
}
Sample run :
triforce(2, 0);
0
000
00000
0 0
000 000
00000 00000
triforce(3, 9);
9
999
99999
9999999
9 9
999 999
99999 99999
9999999 9999999

Confused about writing a program for placing some modified queen-type pieces on an 8 x 8 board

To this question:
The superqueen is a chess piece that can move like a queen, but also like a knight. What is the maximal number of superqueens on an 8X8 chessboard such that no one can capture an other?
I want to write a brute force algorithm to find the maximum. Here's what I wrote:
public class Main {
public static boolean chess[][];
public static void main(String[] args) throws java.lang.Exception {
chess = new boolean[8][8];
chess[0][0] = true;
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
/*Loop to check various possibilities*/
if (!checkrow(i) && !checkcolumn(j) && !checkdiagonals(i, j) && !checkknight(i, j)) {
if (i != 0 || j != 0) {
chess[i][j] = true;
}
}
}
}/*printing the array*/
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
System.out.print(((chess[i][j]) ? "T" : "x") + "|");
}
System.out.println();
}
}
/*All working fine here*/
public static boolean checkrow(int a) {
for (int i = 0; i < 8; i++) {
if (chess[a][i]) {
return true;
}
}
return false;
}
/*All working fine here*/
public static boolean checkcolumn(int a) {
for (int i = 0; i < 8; i++) {
if (chess[i][a]) {
return true;
}
}
return false;
}
/*All working fine here*/
public static boolean checkdiagonals(int pi, int pj) {
int i = pi - Math.min(pi, pj);
int j = pj - Math.min(pi, pj);
for (int k = i, l = j; k < 8 && l < 8; k++, l++) {
if (chess[k][l]) {
return true;
}
}
int i_2 = pi - Math.min(pi, pj);
int j_2 = pj + Math.min(pi, pj);
for (int k = i_2, l = j_2; k < 8 && l > 1; k++, l--) {
if (chess[k][l]) {
return true;
}
}
return false;
}
/*Not All working fine here try commenting out this method above so that that it doesn't run during the check*/
public static boolean checkknight(int pi, int pj) {
for (int i = -1; i <= 1; i++) {
for (int j = -1; j <= 1; j++) {
if (0 <= pi + 2 * i && pi + 2 * i <= 8 && 0 <= pj + j && pj + j <= 8) {
if (chess[pi + 2 * i][pj + j]) {
return true;
}
}
if (0 <= pi + i && pi + i <= 8 && 0 <= pj + 2 * j && pj + 2 * j <= 8) {
if (chess[pi + i][pj + 2 * i]) {
return true;
}
}
}
}
return false;
}
}
I have two questions:
My algorithm for checkknight looks for all knight positions, is it wrong? or there is some coding error.Everything is working fine when I comment out it and I get a nice solution.
Secondly it'll result only in one solution.For other solutions I have to offset(or change position) of other pieces bit by bit after each mega-loop of this, I am confused about implementing it. My instincts guide me that I need to change whole of the code. Is there a modification or a way to do it?
Additional Thoughts: I think we would add to a counter each time we place a piece and add to a long array and output the maximum and array after storing the relevant data.
Code Location: You may view/edit/fork/download it at http://ideone.com/gChD8a
This a rough brute-force method starting from the opposite direction, i.e. from the solved eight-queens puzzle. This will allow us to find a bunch of viable solutions.
The brute-force technique for going from a single superqueen to potentially 8 seems to be especially complex due to the knight's traversal. Based on the runs, about 60% of the viable paths for normal queens are invalid with superqueens. So if we were to instead brute force normal queens, and then work backwards, that is potential time saved for finding a solution, and we can better determine the run-time. Because we know normal queens is easier.
We start off with the 12 fundamental solutions, we would then use these as inputs. Solving normal queens is outside this, but the wiki page has a fantastic article describing everything.
In my case, I stored them as Strings representing the coordinate of the queen (the rows are indices).
So: "17468253" = A1, B7, C4, D6, E8, F2, G5, H3
By brute-forcing the opposite direction from solved queens, we only have to test at most 12 x 8! possible solutions. Because order doesn't matter, additional optimization could occur by eliminating duplicate boards and solutions for processing.
First up, checkKnight, which appears to be your source of confusion. Using absolute values, you can reasonably determine whether or not a piece is within knight's range by checking whether the X offset is 2 and Y offset is 1, or vice versa. You've made a complex checkKnight function to check each individual location and whether or not a piece is on the border. Working the other way by hitscanning each queen to each other queen is logically simpler and less of a nightmare to debug.
Queen class
public class Queen {
int i, j;
public Queen(int i, int j) {
this.i = i;
this.j = j;
}
public boolean checkKnight(Queen queen) { // if any queen meets another
// queen at 2 and 1 offset, we
// eliminate it.
return (Math.abs(i - queen.i) == 2 && Math.abs(j - queen.j) == 1)
|| (Math.abs(i - queen.i) == 1 && Math.abs(j - queen.j) == 2);
}
}
This board has been modified since I originally posted. It takes a String input and converts it to a full chessboard. It has some minor work towards the potential any-size board, but right now it handles child board creation. When a child board is created, the queens are passed by reference rather than making a whole new set of queens. A total of 96 queens are stored in memory, 1 for each one on the original 12-board solution. Not perfectly optimized, but better than 96 -> 672 -> 4032 -> ...
Board class
public class Board {
static int boardSize = 8;
ArrayList<Queen> queens = new ArrayList<Queen>();
public Board(String s) {
for (int i = 0; i < s.length(); i++) {
queens.add(new Queen(i, s.charAt(i) - 49)); // you could implement
// base 16 here, for
// example, for a 15x15
// board
}
}
public Board(Board b) { // duplicates the board, but keeps references to
// queens to conserve memory, only 96 total queens
// in existence through search!
for (Queen q : b.queens) {
queens.add(q);
}
}
public boolean checkForImpact() {
for (int i = 0; i < queens.size(); i++) {
for (int j = i + 1; j < queens.size(); j++) {
if (queens.get(i).checkKnight(queens.get(j))) { // just check
// for any
// queens
// intersecting,
// one hit is
// enough
return true;
}
}
}
return false;
}
public ArrayList<Board> getChildBoards() { // create child boards with a
// single queen removed
ArrayList<Board> boards = new ArrayList<Board>();
for (int i = 0; i < queens.size(); i++) {
boards.add(new Board(this));
}
int i = 0;
for (Board b : boards) {
b.queens.remove(i);
i++;
}
return boards;
}
public String drawBoard() {
String s = "";
char[][] printableBoard = new char[boardSize][boardSize];
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
printableBoard[i][j] = '_';
}
}
for (Queen q : queens) {
printableBoard[q.i][q.j] = 'Q';
}
s += " A B C D E F G H\n";
for (int i = 0; i < 8; i++) {
s += (8 - i) + "|";
for (int j = 0; j < boardSize; j++) {
s += printableBoard[i][j];
s += "|";
}
s += "\n";
}
return s;
}
}
Test class
import java.util.ArrayList;
public class Test {
static String[] boards = { "24683175", "17468253", "17582463", "41582736",
"51842736", "31758246", "51468273", "71386425", "51863724",
"57142863", "63184275", "53172864" }; // all 12 solutions for the 8
// queens problem
static ArrayList<Board> boardObjects = new ArrayList<Board>();
public static void main(String[] args) {
for (String queens : boards) { // create starter boards
boardObjects.add(new Board(queens));
}
int i;
ArrayList<Board> foundBoards = null;
for (i = 8; i > 0; i--) {
ArrayList<Board> newBoards = new ArrayList<Board>();
foundBoards = new ArrayList<Board>();
for (Board b : boardObjects) {
if (b.checkForImpact()) { // if any queen intercepts we get
// children
ArrayList<Board> boardsToBeAdded = b.getChildBoards(); // pass
// all
// permutations
// of
// queens
// once
// removed
for (Board bo : boardsToBeAdded) {
newBoards.add(bo); // add it in to the next list
}
} else {
foundBoards.add(b); // if we have no impact, we have a
// solution
}
}
if (!foundBoards.isEmpty())
break;
boardObjects.clear();
boardObjects = newBoards;
}
System.out.println("The maximum number of super-queens is: " + i);
ArrayList<String> winningCombinations = new ArrayList<String>();
for (Board board : foundBoards) {
String createdBoard = board.drawBoard();
boolean found = false;
for (String storedBoard : winningCombinations) {
if (storedBoard.equals(createdBoard))
found = true;
}
if (!found)
winningCombinations.add(createdBoard);
}
for (String board : winningCombinations) {
System.out.println(board);
}
}
}
The end output is:
The maximum number of super-queens is: 6
A B C D E F G H
8|Q|_|_|_|_|_|_|_|
7|_|_|_|_|_|_|Q|_|
6|_|_|_|Q|_|_|_|_|
5|_|_|_|_|_|_|_|_|
4|_|_|_|_|_|_|_|Q|
3|_|Q|_|_|_|_|_|_|
2|_|_|_|_|Q|_|_|_|
1|_|_|_|_|_|_|_|_|
A B C D E F G H
8|Q|_|_|_|_|_|_|_|
7|_|_|_|_|_|_|_|_|
6|_|_|_|_|Q|_|_|_|
5|_|_|_|_|_|_|_|Q|
4|_|Q|_|_|_|_|_|_|
3|_|_|_|_|_|_|_|_|
2|_|_|_|_|_|Q|_|_|
1|_|_|Q|_|_|_|_|_|
A B C D E F G H
8|_|_|_|_|Q|_|_|_|
7|Q|_|_|_|_|_|_|_|
6|_|_|_|_|_|_|_|Q|
5|_|_|_|Q|_|_|_|_|
4|_|_|_|_|_|_|_|_|
3|_|_|_|_|_|_|_|_|
2|_|_|Q|_|_|_|_|_|
1|_|_|_|_|_|Q|_|_|
A B C D E F G H
8|_|_|_|_|Q|_|_|_|
7|Q|_|_|_|_|_|_|_|
6|_|_|_|_|_|_|_|Q|
5|_|_|_|Q|_|_|_|_|
4|_|_|_|_|_|_|_|_|
3|_|_|_|_|_|_|Q|_|
2|_|_|Q|_|_|_|_|_|
1|_|_|_|_|_|_|_|_|
A B C D E F G H
8|_|_|_|_|Q|_|_|_|
7|Q|_|_|_|_|_|_|_|
6|_|_|_|_|_|_|_|Q|
5|_|_|_|_|_|_|_|_|
4|_|_|Q|_|_|_|_|_|
3|_|_|_|_|_|_|Q|_|
2|_|_|_|_|_|_|_|_|
1|_|_|_|Q|_|_|_|_|
I've removed the duplicates and made a nice board printing method. don't remember the exact math, but this highlights 40 possible locations. There are others, just by looking, but we've found a fair chunk of them already! From here, we can gently shift individual queens around. From a cursory look, each board has a single piece that can be moved to 3 additional spaces, so now we know there are probably about 160 solutions.
Conclusions
With this application, the run-time on my machine was less than a second, meaning that if we attached this to a standard queens application, the additional knight's brute-forcing would have no impact on that process and have almost the same run-time. In addition, because only 6-piece puzzles are possible, we know that your eventual application run will finish its finding at the 6th piece being placed, as no more solutions are possible, since there are no viable 7-piece and 8-piece solutions.
In other words, finding the maximum super-queen layout is likely actually shorter than the maximum queen layout due to the additional restrictions!
Trying to brute-force such a question is a good way to get a feel for it. So I won't suggest looking up pre-cooked solutions at first.
One little remark though: I don't see the reason for the condition if (i != 0 || j != 0) { that you have there. You are working on Java arrays. Instead of 1 through 8, they go 0 through 7, but the 0 is the first column, you should not eliminate it, otherwise it's only a 7x7 board.
First, let me address your technical question: how to calculate the knight positions.
Take a sheet of quad paper, put a queen somewhere not less than two squares away from the edge. Then mark the end positions of a knight-move from it.
You'll end up with just 8 squares that need to be considered. There is no point in doing a 3x3 loop to find them. A better idea would be to prepare a static array with the relative coordinates of the knight moves - an array of 8 pairs of numbers - and loop on that. So you have only an 8-step loop. In each step of the loop, check for bounds (0 ≤ X + Xoffset < 8, 0 ≤ Y + Yoffset < 8 ), and you have the knight coordinates.
Second, there is no point checking the part of the board that's ahead of you. Since you have not covered the next row and those below it, there is no point in looking for queens there. The implications of this:
You'll never put another queen in the same row where you have just marked a queen position (because you threaten it horizontally). This means that if you mark a queen, you should use continue to break out of the inner loop to the next row.
You don't need checkrow(). When you start a row, there is no queen ahead of you. And if you followed the above bullet point, there is no queen on your back, either.
When you use checkcolumn, you start at row 0, but you can finish at the row before the one you are on (i-1). There are still no queens in the rows below you! The same is true for the diagonal checks.
Earlier I said that you need to prepare and check 8 knight positions. But now you know there is no queen at the knight positions ahead of you. So you only need to prepare an array with four knight positions - the ones above your position.
But most importantly... once you have finished and you have your queens in positions and print the board: you have a single solved board. You have proved that this number of queens is possible. But is it the highest number possible? You have not checked what happens if you don't put a queen on the first square of the first row, but on the second. Perhaps this will allow you to put in an extra queen later. And what about the queen in the second row? Maybe if you moved that, you would be able to put a queen somewhere below where you couldn't before?
So, now you have to actually do the same thing over again, changing one decision every time and working from there. In effect, you have many potential boards. Why? Because there may be more than one valid position on each row where you put that row's queen. So you have decided to put it in the first valid position. But what if you decide to put it in the second valid position? Or leave that row empty? Each such decision is followed by another set of decisions on the next row.
The different boards created by different decisions form a decision tree. The problem for you to consider, therefore, is how to work such a tree out. How to write your decision trail and then backtrack, change, fill another board and count the queens at each level. People here suggested recursion, because it lends itself nicely to such problems. Or you can keep a stack of decisions if you want. You can eliminate some of the potential boards based on symmetries.
I suggest you first make sure you understand your single board well, and then consider how to represent your decision tree and how to traverse it.
There are several questions here.
The first is: how many knight-queens can be placed on an nxn chessboard? Since a k-piece solution can trivially be reduced to a k-1 piece solution, it makes sense to start from the upper bound. That is, look for an n-piece solution, if that fails look for an n-1 piece solution, and so forth.
The second question is: how should I look for a k-piece solution? There are two classic strategies: depth-first and breadth-first. In the former, you consider one vertex of the search tree at a time and use backtracking on failure. In the latter, you consider one complete level of the search tree at a time.
Something that can make a great deal of difference to your search is to account for symmetry (in this case, rotations and reflections).
The third (implicit) question is: what is a good representation here? If your chess-boards are less than 8x8 in size then a 64-bit bit-pattern will do very nicely!
In practical terms, try to separate the three levels of your problem as far as you can. If you don't, you'll find that a choice in one level will severely limit your options at another level.

Knights tour backtracking Java

I am trying to solve the Knights tour problem on a 4x4 board with backtracking and recursion in java, and on the output I get this step sequence:
1 13 16 15
10 7 4 14
5 2 11 8
12 9 6 3
in the right upper corner, the 14, 15 and 16 neighbour with each other, which is impossible, because the knight moves on the chessboard into an L-shape. I would be thankful if someone could help me solve this.
the code:
public class KnightsTour {
private static int board[][] = new int[4][4];
private static int stepCounter = 1;
public Test() {
initBoard(board);
tour(0,0);
printSol(board);
}
public static void printSol(int[][] a) {
for (int i = 0; i < a.length; i++) {
for (int j = 0; j < a[i].length; j++) {
if(a[i][j]>9){
System.out.print(a[i][j] + " ");
}else{
System.out.print(a[i][j] + " ");
}
}
System.out.println();
}
System.out.println();
}
public static void initBoard(int[][] a) {
for (int i = 0; i < a.length; i++) {
for (int j = 0; j < a[i].length; j++) {
a[i][j] = -1;
}
}
}
public void tour(int x, int y) {
if (((x < 0) || (x >= 4) || (y < 0) || (y >= 4)) || (board[x][y] != -1)) {
return;
}else{
board[x][y] = stepCounter++;
tour(x+2, y+1);
tour(x+1, y-2);
tour(x+1, y+2);
tour(x-1, y+2);
tour(x-2, y-1);
tour(x-2, y+1);
tour(x-1, y-2);
tour(x+2, y-1);
}
}
public static void main(String[] args){
new KnightsTour();
}
}
You need to make the function return a boolean so it can tell the calling function whether or not it succeeded. Otherwise you just carry on until you've tried every possible combination, even after you've found a solution.
Then, at each call of the function, you need to check the return value and return true if it succeeded.
Then you also obviously need to return true when done.
I suggest something like:
if (stepCounter == 1 + board.length * board[0].length)
return true;
Right after board[x][y] = stepCounter++;.
You need to revert any changes made at the end of the function call, i.e. stepCounter needs to decrease and board[x][y] needs to be set to -1.
After you've successfully made these changes, you should actually see a result of all -1's, because it's not possible on a 4x4 board, but changing it to 8x8 should succeed.
Note that I didn't use 17 above - it's good practice to not use hard-coded values (in, for example, x >= 4). Use either the size of the array, or final values, instead.
Your tour() function appears to set the value of a square to the step-counter of the order it's visited for the first time. But you're trying multiple options. Your first tour dead ends when you get to 12 - one of the subsequent attempts touches each of the 13-16 squares.
You need to store the state of the current tour, rather than the order in which you visited. E.g. if you backtrack, the current square is no longer part of the tour. If you find a tour, you should stop, because you're done.

What is wrong with my backtracking algorithm? [closed]

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 9 years ago.
I am working on a program that generates sudoku puzzles. I was trying to use a backtracking algorithm to do this but my program is not working. The program just runs infinitely and never returns a solution. I don't know if its just a minor problem or I misunderstand how to write a backtracking algorithm.
package sudoku;
import java.util.Random;
public class Puzzle {
// 9x9 puzzle
private int puzzle[][] = new int[9][9];
// generate a completely solved sudoku board
public int[][] generate() {
Random gen = new Random();
// add each number to the board square by square
for (int y = 0; y < 9; y++) {
for (int x = 0; x < 9; x++) {
// generate random number 1-9
int num = gen.nextInt(9) + 1;
int count = 0;
boolean valid = false;
while (valid == false) {
// check if number is valid
if (checkRow(num, x) && checkCol(num, y)
&& checkSection(num, x, y)) {
// add number to the board
puzzle[x][y] = num;
// exit loop, move on to next square
valid = true;
} else {
// try next number
if (num == 9) {
num = 1;
} else {
num++;
}
// increase counter.
count++;
// if counter reached 9, then all numbers were tried and
// none were valid, begin backtracking
if (count == 9) {
// go back 1 square
if (x == 0) {
x = 8;
y--;
} else {
x--;
}
// empty square
puzzle[x][y] = 0;
//reset count
count = 0;
}
}
}
}
}
return puzzle;
}
// check each element of the row for num, if num is found return false
private boolean checkRow(int num, int row) {
for (int i = 0; i < 9; i++) {
if (puzzle[row][i] == num) {
return false;
}
}
return true;
}
// check each element of the column for num, if num is found return false
private boolean checkCol(int num, int col) {
for (int i = 0; i < 9; i++) {
if (puzzle[i][col] == num) {
return false;
}
}
return true;
}
// check each element of the section for num, if num is found return false
private boolean checkSection(int num, int xPos, int yPos) {
int[][] section = new int[3][3];
section = getSection(xPos, yPos);
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (section[i][j] == num)
return false;
}
}
return true;
}
// return the 3x3 section the given coordinates are in
private int[][] getSection(int xPos, int yPos) {
int[][] section = new int[3][3];
int xIndex = 3 * (xPos / 3);
int yIndex = 3 * (yPos / 3);
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
section[i][j] = puzzle[xIndex + i][yIndex + j];
}
}
return section;
}
}
There are a number of issues that may happen. I will just put an example.
The principal reason backtracking is not working is because you are not doing backtracking. You only go back one state in the tree, backtracking means that you check all possibilities of a subtree and then (if none is valid) you ignore that subtree, no matter how high is it.
Let's see. Your approach is "put all the numbers in a line and hope that the square gets completed. In case there is an error dealing with the current square, clear the previous one".
At the beginning no problem, getting the first lines will cause no error. But think of the possibility that you have completed the first 8 lines, with something like that:
1
2
3
----
4
5
6
---
79
832|179|456
x
There is no valid value for x. What does your algorithm do? Go back and try to change the 6! Unsurprisingly, that will end with replacing the 6 with a 6, and trying again to set a value to x.
Sudokus generators that I found in the internet have no backtracking, just take a valid solution and perform a series of changes to it, in a way that all the changes bring valid solutions (for more details, ask google).
If you wanted to use backtracking, at each step you should scan if the sudoku is still solvable (or at least, that is not "broken"). And have a way of not repeating the non-solvable combinations.
Additionally, trying to put the numbers in order seems (that is an opinion) to add a constraint too strong at the beginning. Filling the first two lines is easy, but it will condition the entire solution (note that filling the first line does not affect it! :-D).
I don't think that this is a good way to approach the problem; unfortunately, I don't have a solution for you, but I do see that once count == 9, you change x and y, which isn't something that's necessarily good to do. Nonetheless, you do not provide a way to terminate the while(!valid) loop. You need to change valid to true to actually backtrack; however, this won't make the method work.

Categories