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.
Related
In my program in certain function i have to fill 3x3 square of 9x9 array. At first glance it seems to be as trivial as it sounds but somehow one for() loop is not working properly. I asked two friends of mine and checked the code several times but still cant find any mistake everything seems to be working just fine if we do not count one for function. I tried to change it to other loop and it also didnt work. Below i give you my code and the outcome.I tried to serch the web for similar problem but also couldnt find one. Thank you in advance!
Code:
import java.util.Random;
public class ttabela
{
public static void main(String[] args) {
boolean bylo[] = new boolean[10];
int tabela[][] = new int[9][9];
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
tabela[i][j] = 0;
}
}
wypelnianiePrzekatnych(bylo, tabela,0,2);
clear(bylo);
System.out.println("");
for(int i=0;i<3;i++) {
for (int j = 0; j < 3; j++) {
System.out.print(tabela[i][j]+" ");
}
System.out.println();
}
System.out.println("");
for(int x=0;x<9;x++)
System.out.print(tabela[0][x]+" ");
}
static int RandomBeetween ( int min, int max)
{
Random random = new Random();
int a1 = random.nextInt(max - min);
int a2 = a1 + min;
return a2;
}
static void wypelnianiePrzekatnych(boolean[] bylo, int[][] tabela,int i,int j){//i=0 j=2
int a = i,b=i ;
for (;a < (j+1);a++) { //This one doesnt make any difference
for (;b < (j+1); b++) {
System.out.println("p "+a+" "+b+" k");
tabela[a][b] = RandomBeetween(1, 10);
System.out.println(tabela[a][b]);
if (bylo[tabela[a][b]] == true) {
do {
tabela[a][b] = RandomBeetween(1, 10);
}while (bylo[tabela[a][b]] == true);
bylo[tabela[a][b]] = true;
System.out.println(tabela[a][b]);
}
else {
if (bylo[tabela[a][b]] == false)
bylo[tabela[a][b]] = true;
System.out.println(tabela[a][b]);
}
}
}
}
static void clear(boolean[] bylo)
{
for(int h=0;h<10;h++)
bylo[h]=false;
}
/*public static void wypelnianieReszty()
{
}*/
}
Outcome:
p 0 0 k
7
7
p 0 1 k
8
8
p 0 2 k
3
3
7 8 3
0 0 0
0 0 0
7 8 3 0 0 0 0 0 0
The problem is that your inner for loop will only execute once, so the outer loop has nothing to run after the first iteration.
I'll explain in more detail.
You start with:
int a = i,b=i ;
Let's say we passed in (..., 0, 2) as you have done. So a = 0, b = 0.
The outer for loop will run just fine exactly as expected - the code will run until a > (j+1) and there's nothing wrong here.
The problem is actually with your second for loop:
for (;b < (j+1); b++) {
For the first iteration, this will run as expected. But any time after that, it will never run - because you have already incremented b, such that b == (j+1).
I believe there is a fairly simple solution, assuming I've interpreted your requirements correctly:
int a = i;
int b;
for (;a < (j+1);a++) { //This one doesnt make any difference
b = i
for (;b < (j+1); b++) {
This works because it resets the value of b before each iteration of the for loop, so it won't halt immediately.
I hope this helps! Feel free to ask any questions in the comments.
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.
I am tasked to make a program which returns true if in a 2D array 1-s encircle 0-s.
I tried something like this, but i cant find the right solution.
public boolean checkGameState(){
for(int i=0;i<fields.length;i++){
for(int j=0;j<fields.length;j++){
if(fields[i][j]!=0){
if(row(i,j){
return true;
}
}
}
}
return false;
}
private boolean row(int a, int b){
int checkI=a;
int checkJ=b;
while(fields[checkI][checkJ]==1){
checkJ++;
}
while(fields[checkI][checkJ]==1){
checkI++;
}
while(fields[checkI][checkJ]==1){
checkJ--;
}
while(fields[checkI][checkJ]==1){
checkI--;
}
return a==checkI && b==checkJ;
}
The 2D array looks something like this:
111100
100100
100101
111100
001100
For this array the method should return true.
The easiest way might be to use a flood fill algorithm to eliminate all the zeros that are not encircled by ones, and then checking whether there are any left.
First, put all the zeros directly on the "fringe" of the 2D array into a queue. Then, use the flood fill algorithm to turn all of those into a different number (e.g., 2), and add the nodes next to them to the fringe set (either diagonally or only direct neighbours). Repeat until there are no more nodes in the fringe. Finally, check whether there are any more zeros in the array. If so, those were not connected to the fringe region and thus had to be "encircled" by ones.
// test data set up
int[][] data = {{1,1,1,1,0,0},
{1,0,0,1,0,0},
{1,0,0,1,0,1},
{1,1,1,1,0,0},
{0,0,1,1,0,0}};
int N = data.length, M = data[0].length;
// create queue of zeros on the "fringe"
Queue<int[]> fringe = new LinkedList<>();
for (int i = 0; i < N; i++) {
if (data[i][0 ] == 0) fringe.add(new int[]{i,0 });
if (data[i][M-1] == 0) fringe.add(new int[]{i,M-1});
}
for (int j = 0; j < M; j++) {
if (data[0 ][j] == 0) fringe.add(new int[]{0 ,j});
if (data[N-1][j] == 0) fringe.add(new int[]{N-1,j});
}
// do flood fill until no more zeros reachable
while (! fringe.isEmpty()) {
int[] next = fringe.poll();
int i = next[0], j = next[1];
data[i][j] = 2;
for (int di = -1; di <= 1; di++) {
for (int dj = -1; dj <= 1; dj++) {
try {
if (data[i+di][j+dj] == 0) fringe.add(new int[]{i+di, j+dj});
} catch (ArrayIndexOutOfBoundsException e) {}
}
}
}
// check for remaining zeros
boolean encircled = false;
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
System.out.print(data[i][j]);
encircled |= data[i][j] == 0;
}
System.out.println();
}
System.out.println(encircled);
Example output:
111122
100122
100121
111122
221122
true
The complexity should be on the order of O(NxM), since each of the NxM nodes can only appear once in the queue (plus a bit of overhead for constructing the queue and finding remaining zeros).
Please note that I have assumed that you need rectangle shape surrounding
You need to find sequences for 3 or more 1 in one row.
xx1111xx // x means any number
For each sequence check if there is sequence of the same length 2 or more rows lower.
xx1111xx
xxxxxxxx
xx1111xx
For each "pair" of sequences check if they are connected with 1 on the edges.
xx1111xx
xx1xx1xx
xx1111xx
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.
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.