I'm trying to write a backtracking code that will find the number of solutions in a NQueens problem. But I am getting stack overflows when I try to mark the diagonal grids where it is not safe to place a queen.
int dim;
private void recurseMark(int row, int col, boolean[][] board, boolean val) {
if(row >= dim || col >= dim || row < 0 || col < 0) return;
if(board[row][col]) return;
System.out.println("Row " + row + " Col " + col);
board[row][col] = val;
recurseMark(row+1, col-1, board, val);
recurseMark(row+1, col+1, board, val);
recurseMark(row-1, col+1, board, val);
recurseMark(row-1, col-1, board, val);
}
private void mark(int i, int k, boolean[][] board, boolean val) {
for(int j = 0; j < dim; j++) {
board[i][j] = val;
}
for(int j = 0; j < dim; j++) {
board[j][k] = val;
}
}
private int countQueens(int i, boolean[][] board) {
int count = 0;
if(i == dim) return 1;
for(int k = 0; k < dim; k++) {
if(!board[i][k]) {
board[i][k] = true;
mark(i, k, board, true);
System.out.println("Giving " + i + " " + k);
recurseMark(i, k, board, true);
count += countQueens(i+1, board);
recurseMark(i, k, board, false);
mark(i, k, board, false);
}
}
return count;
}
public int totalNQueens(int n) {
dim = n;
boolean[][] board = new boolean[n][n];
return countQueens(0, board);
}
public static void main(String[] args) {
NQueens nq = new NQueens();
System.out.println(nq.totalNQueens(2));
}
Any idea why it's overflowing for a small value of N?
Because your method recurses infinitely.
If the board is 8x8, then for example recurseMark(1, 1, board, false) calls recurseMark(2, 2, board, false) which calls recurseMark(1, 1, board, false) which calls recurseMark(2, 2, board, false) which calls recurseMark(1, 1, board, false) which ...
The problem is when recurseMark is called with false. Here is a correct recurseMark():
private void recurseMark(int row, int col, Boolean[][] board, Boolean val) {
if(row >= dim || col >= dim || row < 0 || col < 0) return;
if(board[row][col] != null) return;
System.out.println("Row " + row + " Col " + col);
board[row][col] = val;
recurseMark(row+1, col-1, board, val);
recurseMark(row+1, col+1, board, val);
recurseMark(row-1, col+1, board, val);
recurseMark(row-1, col-1, board, val);
}
What we have done here is to switch to a Boolean class rather than primitive boolean, and use the null case to represent "square not visited yet". As it was the "square not visited" state was "false".
Related
I am working on a Percolation java program. I have implemented the following Percolation.java file and am running into an error when testing it with certain input files, as described below.
import edu.princeton.cs.algs4.In;
import edu.princeton.cs.algs4.StdOut;
import edu.princeton.cs.algs4.WeightedQuickUnionUF;
public class Percolation {
private int n;
private WeightedQuickUnionUF verify;
private WeightedQuickUnionUF solution;
private int sink;
private int source = 0;
private boolean[][] grid;
private int openSites = 0;
private int length;
// creates n-by-n grid, with all sites initially blocked
public Percolation(int n) {
if (n <= 0) {
throw new IllegalArgumentException();
}
this.length = n;
this.grid = new boolean[length][length];
this.sink = (length * length) + 1;
verify = new WeightedQuickUnionUF(length * length + 2);
solution = new WeightedQuickUnionUF(length * length + 2);
for (int i = 0; i < length; i++) {
verify.union(encode(0, i), source);
solution.union(encode(0, i), source);
}
for (int j = 0; j < length; j++) {
verify.union(encode(n - 1, j), sink);
}
}
// opens the site (row, col) if it is not open already
public void open(int row, int col) {
grid[row][col] = true;
openSites++;
if ((row - 1) >= 0 && isOpen(row - 1, col)) {
verify.union(encode(row, col), encode(row - 1, col));
solution.union(encode(row, col), encode(row - 1, col));
}
if ((row + 1) < length && isOpen(row + 1, col)) {
verify.union(encode(row, col), encode(row + 1, col));
solution.union(encode(row, col), encode(row + 1, col));
}
if ((col - 1) >= 0 && isOpen(row, col - 1)) {
verify.union(encode(row, col), encode(row, col - 1));
solution.union(encode(row, col), encode(row, col - 1));
}
if ((col + 1) < length && isOpen(row, col + 1)) {
verify.union(encode(row, col), encode(row, col + 1));
solution.union(encode(row, col), encode(row, col + 1));
}
}
// is the site (row, col) open?
public boolean isOpen(int row, int col) {
return grid[row][col];
}
// is the site (row, col) full?
public boolean isFull(int row, int col) {
return solution.find(source) == solution.find(encode(row, col));
}
// returns the number of open sites
public int numberOfOpenSites() {
return openSites;
}
// does the system percolate?
public boolean percolates() {
return verify.find(0) == verify.find(sink);
}
// An integer ID (1...n) for site (i, j).
private int encode(int row, int col) {
int number = length * row + 1 + col;
return number;
}
// unit testing (required)
public static void main(String[] args) {
String filename = args[0];
In in = new In(filename);
int n = in.readInt();
Percolation perc = new Percolation(n);
while (!in.isEmpty()) {
int i = in.readInt();
int j = in.readInt();
perc.open(i, j);
}
StdOut.println(perc.numberOfOpenSites() + " open sites");
if (perc.percolates()) {
StdOut.println("percolates");
}
else {
StdOut.println("does not percolate");
}
// Check if site (i, j) optionally specified on the command line
// is full.
if (args.length == 3) {
int i = Integer.parseInt(args[1]);
int j = Integer.parseInt(args[2]);
StdOut.println(perc.isFull(i, j));
}
}
}
However, when I test the code using certain input files, I receive error messages such as the following:
java.lang.ArrayIndexOutOfBoundsException: Index 8 out of bounds for length 8
Percolation.isOpen(Percolation.java:63)
TestPercolation.checkIsOpen(TestPercolation.java:122)
TestPercolation.checkIsOpen(TestPercolation.java:105)
TestPercolation.check(TestPercolation.java:177)
TestPercolation.checkFile(TestPercolation.java:198)
TestPercolation.test1(TestPercolation.java:659)
TestPercolation.main(TestPercolation.java:963)
java.lang.ArrayIndexOutOfBoundsException: Index 25 out of bounds for length 25
java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
What in my code could be causing this? In other words, where is the issue and how can I fix it?
I have a question about my homework in scratching my head-on.
So I need to build a program that counts the number of areas of true value (near to each other) in the 2D array.
{0,1,0,0}
{1,0,0,1}
{1,1,0,1}
{1,0,0,1}
So the program needs to return 3 because there 3 places with trues.
If there are no true then to return 0.
The program needs to recursive and without loops.
Thanks in advance to the ones that will help me solve this one. I didn't even have any idea how to start it.
Ok, you do a dfs to record the cells you went and you can have a boolean[][] to record the cells you went. Then you just loop through the grid to see where you have not gone. If you did not go there yet, go there and also perform a dfs on nearby cells, but anyway, a code would be more clear.
public static int[][] grid;
public static boolean[][] went;
public static int r, c;
public static void dfs(int x, int y) {
if (x < 0 || x >= r || y < 0 || y >= c) {//out of the grid
return;
}
if (went[x][y]) {//I went here
return;
}
went[x][y] = true;
if (grid[x][y] == 0) {//It's false here so don't go
return;
}
dfs(x - 1, y);
dfs(x + 1, y);
dfs(x, y - 1);
dfs(x, y + 1);
}
public static void main(String[] args) throws IOException {
BufferedReader input =
new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(input.readLine());
//input reading
r = Integer.parseInt(st.nextToken());
c = Integer.parseInt(st.nextToken());
grid = new int[r][c];
went = new boolean[r][c];
for (int i = 0; i < r; i++) {
st = new StringTokenizer(input.readLine());
for (int j = 0; j < c; j++) {
grid[i][j] = Integer.parseInt(st.nextToken());
}
}
//end of input reading
int cnt = 0;//number of areas
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++) {
// If I have not went have and the value
// must be true so I would perform a dfs
// (since I only care about the value of 1s)
if (!went[i][j] && grid[i][j] == 1) {
cnt++;//add to our counter
dfs(i, j);//have not went here
}
}
}
System.out.println(cnt);
}
This solution uses the only recursion. No loops.
public static void main(String... args) {
System.out.println(countTrueAreas(new int[][] {
{ 0, 1, 0, 0 },
{ 1, 0, 0, 1 },
{ 1, 1, 0, 1 },
{ 1, 0, 0, 1 } })); // 3
}
public static int countTrueAreas(int[][] grid) {
return countTrueAreas(grid, 0, 0, 10) - 10;
}
private static int countTrueAreas(int[][] grid, int row, int col, int num) {
if (row == grid.length)
return num;
if (col == grid[row].length) {
if (++row == grid.length)
return num;
col = 0;
}
if (grid[row][col] == 1)
dfs(grid, row, col, num++);
return countTrueAreas(grid, row, col + 1, num);
}
private static void dfs(int[][] grid, int row, int col, int num) {
if (row < 0 || row >= grid.length)
return;
if (col < 0 || col >= grid[row].length)
return;
if (grid[row][col] != 1)
return;
grid[row][col] = num;
dfs(grid, row, col - 1, num);
dfs(grid, row, col + 1, num);
dfs(grid, row - 1, col, num);
dfs(grid, row + 1, col, num);
}
The program I have is supposed to divide the matrix into four quadrants continuously until it finds the given value. With the current program it runs forever. How do I get it to post the number I search for?
public static void DivideAndConquerSearch(int target, int fromRow, int toRow, int fromCol, int toCol, int[][] matrix, int comparison_counter) {
boolean found = false;
while (!found) {
int i = fromRow + (toRow - fromRow) / 2;
int j = fromCol + (toCol - fromCol) / 2;
if (matrix[i][j] == target) {
found = true;
} else if (matrix[i][j] < target) {
if (i + 1 <= toRow) {
found = false;
DivideAndConquerSearch(target, i + 1, toRow, fromCol, toCol, matrix, comparison_counter);
} else if (j - 1 >= fromCol) {
found = false;
DivideAndConquerSearch(target, fromRow, toRow, fromCol, j - 1, matrix, comparison_counter);
}
}
comparison_counter++;
}
if (found == true) {
System.out.println(target + " found in " + comparison_counter + " comparisons using recursive search");
} else {
System.out.println(target + " NOT found in " + comparison_counter + " comparisons using recursive search");
}
}
I wrote up something that simply searches all over the array (brute-force kinds) using a recursive approach. It splits the 2D array into 4 quadrants and search NW, NE, SW, SE. I used an OR condition to check if it is found in any of the quadrants. So, if number is found in NW, it won't search the rest (yay!). Let me know if you have any questions. The code isn't the prettiest or the most optimized, and I have kinda chosen to leave it that way so that you can understand what I am doing a little better. The full class, including a (very basic) test...
public class Divide_Conquer_2dArr {
private static boolean divideAndConquer(int[][] arr, int target) {
/* IDEA */
// NORTH_WEST [Kanye West joke(?)]
// need to search row-wise from [0,row-1], col-wise from [0, col-1]
// NORTH_EAST
// need to search row-wise from [0,row-1], col-wise from [col, maxCol]
// SOUTH_WEST
// need to search row-wise from [row, maxRow], col-wise from [0, col-1]
// SOUTH_EAST
// need to search row-wise from [row, maxRow], col-wise from [col, maxCol]
return divideAndConquerHelper(arr, target, 0, arr[0].length-1, 0, arr.length-1);
}
private static boolean divideAndConquerHelper(int[][] arr, int target, int minCol,
int maxCol, int minRow, int maxRow) {
// print relevant stuff
printArr(arr, minCol, maxCol, minRow, maxRow);
if(minCol == maxCol || minRow == maxRow) {
if(minCol == maxCol) {
for(int i = minRow ; i <= maxRow ; i++)
if(arr[i][minCol] == target) {
System.out.println("Found!");
return true;
}
}
else if(minRow == maxRow) {
for(int i = minCol ; i <= maxCol ; i++)
if(arr[minRow][i] == target) {
System.out.println("Found!");
return true;
}
}
return false;
}
int midRow = (maxRow + minRow)/2;
int midCol = (maxCol + minCol)/2;
return
// north-west quadrant
divideAndConquerHelper(arr, target, minCol, midCol, minRow, midRow)
||
// north-east quadrant
divideAndConquerHelper(arr, target, midCol+1, maxCol, minRow, midRow)
||
// south-west quadrant
divideAndConquerHelper(arr, target, minCol, midCol, midRow+1, maxRow)
||
// south-east quadrant
divideAndConquerHelper(arr, target, midCol+1, maxCol, midRow+1, maxRow);
}
// prints arr[minRow..maxRow][minCol..maxCol] inclusive
private static void printArr(int[][] arr, int minCol,
int maxCol, int minRow, int maxRow) {
for(int i = minRow ; i <= maxRow ; i++ ) {
for(int j = minCol ; j <= maxCol ; j++) {
System.out.print(arr[i][j] + "\t");
}
System.out.println();
}
System.out.println("==================================");
}
public static void main(String[] args) {
int[][] arr = new int[][]
{
{1,2,3,4},
{6,7,8,9},
{11,12,13,14},
{16,17,18,19},
{21,22,23,24}
};
boolean retVal = divideAndConquer(arr, 12);
if(!retVal)
System.out.println("Not found :(");
}
}
I'm trying to create a strategy that will play against human or another strategy for the game Gomoku. I already have some kind of minimax function, although i don't quite understand how does it work and i also have a getscore function, which should send back the best score to minimax ? But the problem is that my getScore function does not recognize if there are 4 or 5 circles in a row/col/diagonally.
Here is my code:
public class JarmoStrategyV1 implements ComputerStrategy {
public static int Lrow = 0;
public static int Lcol = 0;
public static int Drow = 0;
public static int Dcol = 0;
public static final int E = 0;
public static final int X = 1; // black
public static final int O = -1; // white
public static final int WINSCORE = 100;
private static final int WINCOUNT = 5;
public Location getMove(SimpleBoard board, int player) {
// let's operate on 2-d array
int[][] b = board.getBoard();
System.out.println(getScore(b, player));
for (int row = 0; row < b.length; row++) {
for (int col = 0; col < b[0].length; col++) {
if (b[row][col] == SimpleBoard.EMPTY) {
// first empty location
return new Location(row, col);
}
}
}
return null;
}
#Override
public String getName() {
return "Student name";
}
public static int minimax(int[][] board, int player, int depth) {
if (getScore(board, player) == WINSCORE) {
//
return WINSCORE;
}
if (depth == 2) {
return getScore(board, player);
}
int max = Integer.MIN_VALUE;
if (player == -1){
max = Integer.MAX_VALUE;
}
System.out.println(max);
List<Location> possibleMoves = getPossibleMoves(board);
for (Location loc : possibleMoves) {
board[loc.getRow()][loc.getColumn()] = player;
int newplayer = 0 - player;
if(newplayer == 1){
int value = minimax(board, newplayer,depth + 1);
if(value < max) {
max = value;
}
}
if (newplayer == -1){
int value = minimax(board, newplayer, depth + 1);
if (value > max) {
max = value;
}
}
board[loc.getRow()][loc.getColumn()] = E;
}
return max;
}
public static int getScore(int[][] board, int muutuja) {
//int yks = 0;
for (int row = 0; row < board.length; row++) {
for (int col = 0; col < board[row].length; col++) {
if (board[row][col] == muutuja) {
if (row <= (board.length - 5)) {
if (col <= board.length && getCount(board, row, col, 0, 1, muutuja, WINCOUNT) >= (WINCOUNT - 1) && getCount(board, row, (col + 4), 0, 1, E, 1 ) >= 1) return 1; // - 4 in a row
if (row >= 1 && getCount(board, row, col, 1, 0, muutuja, WINCOUNT) >= (WINCOUNT -1) && getCount(board, (row - 1), col, 1, 0, E, 1) == 1) return 1;
if (getCount(board, row, col, 1, 0, muutuja, WINCOUNT) >= WINCOUNT) return 100; // | 5 in a row
if (col <= WINCOUNT && getCount(board, row, col, 1, 1, muutuja, WINCOUNT) >= WINCOUNT) return 100; // \
if (col >= WINCOUNT && getCount(board, row, col, 1, -1, muutuja, WINCOUNT) >= WINCOUNT) return 100; // /
}
if (col <= WINCOUNT && getCount(board, row, col, 0, 1, muutuja, WINCOUNT) >= WINCOUNT) return 100; // -
}
}
}
return 0;
}
public static int getCount(int[][] board, int row, int col, int rowd, int cold, int player, int test) {
int count = 0;
for (int i = 0; i < test; i++) {
if (board[row + i * rowd][col + i * cold] == player) count++;
else break;
}
return count;
}
public static ArrayList<Location> getPossibleMoves(int[][] board) {
ArrayList<Location> availableMoves = new ArrayList<Location>();
for (int row = 0; row < board.length; row++) {
for (int col = 0; col < board[row].length; col++) {
if (board[row][col] == E) {
availableMoves.add(new Location(row, col));
}
}
}
return availableMoves;
}
}
There seems to be some kind of a problem with getScore, when i run this code then i can only play for a while until my Gomoku app crashes.
If you want to try this out yourself then you can open this via Eclipse.
Download the project file: http://www68.zippyshare.com/v/feWl2QwC/file.html
Import it to eclipse projects/workspace.
And you also have to build path to those 2 jar files in lib folder.
NOTE: I can only edit files in gomoku.strategies package.
the stacktrace shows an exception. add debug print or run with debugger
java.lang.IllegalArgumentException: It's computer's turn, pass the player to makeMove()
at gomoku.Game.makeMove(Game.java:476)
i'm a bit stuck with the Sudoku algorithm, i coded it using backtrack, and following the theorical steps this should work, and i tried to debuge it, but is too hard (and yes, it solve some numbers and does things)
i paste the code, i hope that you can help me, i really can't see where the problem is...
public void backtracking(int row,int col){
if(row > 8){
System.out.println("Solution Found!!");
printSudoku();
}
if (m[row][col] != 0){
next(row, col);
}
else {
for(int i =1; i < n;i++)
if(row(row, i) && col(col, i)) {
m[row][col] =i;
next(row, col);
}
m[row][col] = 0;
}
}
public void next( int row, int col ) {
if( col < 8)
backtracking( row, col + 1 ) ;
else
backtracking( row+ 1, 0 ) ;
}
public boolean region(int x, int y, int numReg) {
x = (x / 3) * 3 ;
y = (y / 3) * 3 ;
for( int r = 0; r < 3; r++ )
for( int c = 0; c < 3; c++ )
if( m[x+r][y+c] == numReg )
return false ;
return true ;
}
public boolean row(int x, int k){
for(int i =0; i < 9; i++)
if(m[x][i] == k)
return false;
return true;
}
public boolean col(int x, int k){
for(int i =0; i < 9; i++)
if(m[i][x] == k)
return false;
return true;
}
I ommited the "printSudoku" method, is just a double for and you know.
The code seems almost right.
As far as i can see you just forgot to call the region method. And I can't see where the variable n is coming from.
Try it with this slightly modified backtracking method:
public static void backtracking(int row, int col) {
if (row > 8) {
System.out.println("Solution Found!!");
printSudoku();
System.exit(0); //exiting after solution is found
}
if (m[row][col] != 0) {
next(row, col);
} else {
for (int i = 1; i <= 9; i++) //replaced i < n with i<=9
if (row(row, i) && col(col, i) && region(row, col, i)) { //calling region method too
m[row][col] = i;
next(row, col);
}
m[row][col] = 0;
}
}