DFS solving sudoku - java

I'm working on 16*16 sudoku problem with DFS algorithm. Java code looks like:
public class dfs {
public boolean dfs(int[][] puzzle,int i,int j){
if(i==15&&j>=16) return true;
if(j==16){
//System.out.println(String.valueOf(i));
return dfs(puzzle,i+1,0); //{j=0; i++;
}
if(puzzle[i][j]!=-1){
return dfs(puzzle,i,j+1); //next cell in the same row
}
else{
for(int num=1;num<=16;num++){
//System.out.println("trying"+i+","+j+","+num);
if(valid(puzzle,i,j,num)){
//System.out.println(String.valueOf(num));
puzzle[i][j]=num;
if(dfs(puzzle,i,j+1)){
return true;
}
}
//else return false;
}
}
return false;
}
public boolean valid(int[][] puzzle,int x,int y,int num){
for(int i=0;i<16;i++){
if(puzzle[i][y]==num) {
//System.out.println("a");
return false;
}
}
for(int j=0;j<16;j++){
if(puzzle[x][j]==num){
//System.out.println("b");
return false;
}
}
int c=(x/4)*4;
int r=(y/4)*4;
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
if(puzzle[c+i][r+j]==num){
//System.out.println("c");
return false;
}
}
}
return true;
}
}
And the main method is:
public static void main(String[] args) {
sudoku sudokuPuzzleGenerator = new sudoku();
long start = System.currentTimeMillis();
int numOfSudokuMatrix = 1;
List<int[][]> sudoku = new ArrayList<int[][]>();
for (int count = 1; count <= numOfSudokuMatrix; count++) {
int[][] randomMatrix = sudokuPuzzleGenerator.generatePuzzleMatrix();
int hole = 81;
while (hole > 0) {
Random randomGenerator = new Random();
int x = randomGenerator.nextInt(16);
int y = randomGenerator.nextInt(16);
if (randomMatrix[x][y] != -1) {
randomMatrix[x][y] = -1;
hole--;
}
}
for(int i=0;i<16;i++){
for(int j=0;j<16;j++){
System.out.print(randomMatrix[i][j] + " ");
}
System.out.println();
}
sudoku.add(randomMatrix);
}
System.out.println();
long start2 = System.currentTimeMillis();
for (int[][] p:sudoku) {
dfs d=new dfs();
boolean b=d.dfs(p,0,0);
for (int rowNum = 0; rowNum < 16; rowNum++) {
for (int colNum = 0; colNum < 16; colNum++) {
System.out.print(p[rowNum][colNum] + " ");
}
System.out.println();
}
}
Long end2 = System.currentTimeMillis();
Long time2 = end2 - start2;
System.out.println("It took: " + time2 + " milliseconds.");
}
When I run the code, it often terminates before all blank spaces be filled, leaving many -1 in the puzzle. I'm not sure where the problem is. I will be really thankful for any help!

It doesn't matter, but this would probably be classified as a backtracking problem, not a search. Anyway, I think this is it, but it's hard to test without that generatePuzzleMatrix method. After you check every possible number at a given cell, if you don't find an answer (hit your base case), you need to set the cell back to -1.
for(int num=1;num<=16;num++){
if(valid(puzzle,i,j,num)){
puzzle[i][j]=num;
if(dfs(puzzle,i,j+1)){
return true;
}
}
}
puzzle[i][j] = -1;
Without setting this value back to -1, you are going to leave these values set as the highest valid value, even if you didn't find an answer. Future iterations of your recursive algorithm will skip that value because they assume it is correct. Thus, your loop will end without testing all possibilities and finding an answer. Hope this does it for ya.
Comment Response
Yes, I agree there is at least 1 solution. I believe the problem is that your loop is ending before you actually test all possibilities. Your recursive calls need to set the grid back once they have tested every possibility. At an arbitrary depth in the recursive stack, say you add a valid number to your grid. The number being valid at that stage does not imply it is in the right position. You could create a ripple effect. Though it is currently valid for that particular number, you have unintentionally elimanted the possibility of any solution based on the cells you have filled so far. Once you hit that scenario, you have a problem. Your grid will retain the most recently set value, and you will never try setting it to anything else (because you have a condition that ignores values != -1).

Related

Using array.clone() and changing values, affects the original array too [duplicate]

This question already has answers here:
How do I do a deep copy of a 2d array in Java?
(7 answers)
Closed 2 years ago.
I have written a program for an exercise that generates numOfValidBoardsToCreate Sudoku boards with emptyCellsPerBoard cells with 0s (fills the rest with random numbers) and then solves them. If a generated board isn't valid or solvable it tries to create another one until it gets it. Now let's say we request just one board with 75 empty cells and its solution for the sake of simplicity.
The solve() method checks if a board is solvable and if so it solves it and returns true. Now, since when i check for each board's validity in the if statement of the for loop using isSolvableBoard() which in turn calls solve(), i don't want to solve the original board since i'm going to need to display the original unsolved one and then the solution. So i decided to use sudokuBoard.clone() to make a copy of the original one and use that for the check and disregard it since it's going to be solved after the condition is evaluated. I'd expect that the original sudokuBoard inside the if() statement wouldn't be solved when i print it the first time but the output is the solved version. What am i missing here?
public static void main(String[] args) {
BacktrackingAlgorithm solver = new BacktrackingAlgorithm();
// Get the required input from the user
Scanner scanner = new Scanner(System.in);
System.out.println("Enter the number of empty cells that the board should have:");
int emptyCellsPerBoard = scanner.nextInt();
System.out.println("Enter how many boards the app should create and solve:");
int numOfValidBoardsToCreate = scanner.nextInt();
// extra data to keep track of for printing purposes
int numOfInvalidBoards = 0;
int numOfUnsolvableBoards = 0;
// finding the time before the operation is executed
long start = System.currentTimeMillis();
int[][] sudokuBoard;
int[][] copyOfBoard;
for (int i = 1; i <= numOfValidBoardsToCreate; i++) {
sudokuBoard = solver.generateSudokuBoard(emptyCellsPerBoard);
// Create a copy of the board to pass to isSolvableBoard to test the condition without altering the board
copyOfBoard = sudokuBoard.clone();
if (solver.isSolvableBoard(copyOfBoard)) {
System.out.println("Board #"+i);
solver.printBoard(sudokuBoard);
System.out.println("Solution of board #"+i);
solver.solve(sudokuBoard);
solver.printBoard(sudokuBoard);
} else {
numOfUnsolvableBoards++;
numOfInvalidBoards++;
i--; // run the loop again if we haven't reached the end
}
}
// finding the time after the operation is executed
long end = System.currentTimeMillis();
//finding the time difference and converting it into seconds
float sec = (end - start) / 1000F;
// Print final message
System.out.println("Empty Cells per board: " + emptyCellsPerBoard + "\nValid boards created: " + numOfValidBoardsToCreate + "\nInvalid boards created: "
+ numOfInvalidBoards + "\nUnsolvable boards created: " + numOfUnsolvableBoards + "\nElapsed time: " + sec + " seconds");
}
}
boolean solve(int[][] board) {
for (int row = BOARD_START_INDEX; row < BOARD_SIZE; row++) {
for (int column = BOARD_START_INDEX; column < BOARD_SIZE; column++) {
if (board[row][column] == NO_VALUE) {
for (int k = MIN_VALUE; k <= MAX_VALUE; k++) {
board[row][column] = k;
if (isValid(board, row, column) && solve(board)) {
return true;
}
board[row][column] = NO_VALUE;
}
return false;
}
}
}
return true;
}
/**
* Checks if a Sudoku board is valid and solvable.
*
* #param board The given board
* #return True if it is or false otherwise.
*/
boolean isSolvableBoard(int[][] board) {
return isValidBoard(board) && solve(board);
}
/**
* Checks if the given sudoku board is valid.
*
* #param brd The 9x9 board
* #return True if it's valid or false otherwise.
*/
private boolean isValidBoard(int[][] brd) {
for (int i = BOARD_START_INDEX; i < BOARD_SIZE; i++) {
for (int j = BOARD_START_INDEX; j < BOARD_SIZE; j++) {
try {
if (!isValid(brd, i, j)) return false;
} catch (ArrayIndexOutOfBoundsException e) { // if a given cell has a value > 9, an exception is thrown, so handle it
return false;
}
}
}
return true;
}
Turns out a good solution is the following:
for(int j=0; j <9; j++) {
copyOfBoard[j] = Arrays.copyOf(sudokuBoard[j], sudokuBoard.length); // deep copy of the subarray
}
Which basically performs a deep copy of each subarray of the 2D array.

Java: Optimize two searches and two lists to one

I'm trying to optimize my program by getting rid of duplicate searches or just by generally make things optimized throughout my program and I came across a method in which I can't find any "better" solution what so ever and would love to know if anyone could point me in a direction for refineing it.
First off here is my code that I'm trying to optimize:
public Player spaceBattle(Player player1, Player player2) {
ArrayList<Ship> listOfShipsPlayer1 = this.getShipsOfPlayer(player1);
ArrayList<Ship> listOfShipsPlayer2 = this.getShipsOfPlayer(player2);
Random random = new Random();
int player1hits = 0, player2hits = 0, rolledDie;
for (Ship aShip : listOfShipsPlayer1) {
rolledDie = random.nextInt(10) + 1;
if (rolledDie >= aShip.getShipType().getCombatValue()) {
player1hits += 1;
}
}
for (Ship aShip : listOfShipsPlayer2) {
rolledDie = random.nextInt(10) + 1;
if (rolledDie >= aShip.getShipType().getCombatValue()) {
player2hits += 1;
}
}
for (int i = 0; i < player1hits; ++i) {
if (this.getShipsOfPlayer(player2).size() > 0) {
this.listOfShips.remove(listOfShipsPlayer2.get(i));
} else {
break;
}
}
for (int i = 0; i < player2hits; ++i) {
if (this.getShipsOfPlayer(player1).size() > 0) {
this.listOfShips.remove(listOfShipsPlayer1.get(i));
} else {
break;
}
}
As you can see here I run the same algorithm twice in order to check for first Player1 and then Player2 and add update their respective hits. And then for the amount of hits for each player I then remove a ship.
What I would like to know if its possible to change this bit of code to be able to not have the duplicate code for each player but that it automatically can go through player1 first and then player2 in one loop.
Looking forward to hear from you
You can just create methods.
private int hitShips(List<Ship> ships) {
int result = 0;
for (Ship ship : ships) {
rolledDie = random.nextInt(10) + 1;
if (rolledDie >= ship.getShipType().getCombatValue()) {
result++;
}
}
return result;
}
which makes your code
int player1hits = hitShips(listOfShipsPlayer1);
int player2hits = hitShips(listOfShipsPlayer2);
and similar for the removal of the ships from the list.
void removeShips(List<Ship> ships, int remove) {
int removeCount = Math.max(ships.size(), remove);
Iterator<Ship> it = ships.iterator();
for (int i = 0; i < removeCount; i++) {
it.remove();
}
}
with
removeShips(getShipsOfPlayer(player2), player1hits);
removeShips(getShipsOfPlayer(player1), player2hits);
I'm not sure why you always remove ships from the head of the lists, since combat values seems to be a thing, but that's just a side note.
I wouldn't call this "optimization" so much, but the removal of duplicate code is always good.
You could optimize removeShips as:
void removeShips(List<Ship> ships, int numHits) {
int numToRemove = Math.min(ships.size(), numHits);
if (numToRemove > 0) {
ships.subList(0, numToRemove).clear();
}
}
This method call will result in only one System.arraycopy call, which will shift all remaining elements to the left.
https://docs.oracle.com/javase/8/docs/api/java/util/ArrayList.html#subList-int-int-

How do you return a zero if there is nothing in the grid where you checked?

To start things off, I am making a game. You fight on a 3x3 Grid (using a 2 Dimensional-Array), and if the "Lane#" (Lane# = Row + Col) ahead of you is blank then you get a -15% Damage Reduction, and this stacks for every blank lane.
This means if you are on [0][0] then you are in Lane# 0, and therefore, cannot possibly have anyone ahead of you, and you will always take 100% of Damage (this is of course without defense and yadda yadda else that modifies)
And if you are on [2][2] then you are in Lane# 4, and if every lane ahead of you has atleast one space in it taken, then you will take 15*4 = 60, 100-60 = 40% of actual damage.
Now that that is out of the way. I am having difficulty returning 0... I keep getting an Error that says that you cannot return a Void value...
'cannot return a value from method whose result type is void'
public Blanks(int l) { //l = Lane
int x = 0; //The Return
for (int i = 0; i < 6; i++) //The loop
if (l=0){ //Here I keep getting an error saying 'incompatible types'
x = 0;
return x; //Here is the 'cannot return a void value' error
break;
}
if (l>=1){
x++;
}
if (l>=2){
x++;
}
if (l>=3){
x++;
}
if (l>=4){
x++;
}
return x; //for some odd reason, this is also a void value
}
}
I still have yet to add the Checking the Array / Grid part as I am stumped about that one as well.. but another problem, another question.. the actual array itself..
you should modify the method header to public int Blanks(int l) {
and you should remove break; keyword because you return method value before it and will be unreached statement.
In order to return an integer value you have to mention a return type in the method. Also, in the first if statement you have used assignment operator instead of comparing.
Also why you have used break after return. I think you have to do first break and then return in the end.
One more thing to add. Your for loop should contain braces. Only the first if statement will get executed according to your code.
public int Blanks(int l) { //l = Lane
int x = 0; //The Return
for (int i = 0; i < 6; i++) //The loop
if (l==0){ //Here I keep getting an error saying 'incompatible types'
x = 0;
break;
}
if (l>=1){
x++;
}
if (l>=2){
x++;
}
if (l>=3){
x++;
}
if (l>=4){
x++;
}
return x; //for some odd reason, this is also a void value
}
}
I haven't stepped into your logic. Comment if you face any problem after this.
I don't understand why you are using the for loop here, but this is a way to do it:
public int Blanks(int l) {
int x = 0;
for (int i = 0; i < 6; i++)
if (l==0){
x = 0;
}else {
x++;
}
return x;
}
But in case that l==0 your method will return 5;
If you want to return 0 or 1 then you need to remove the for loop
public int Blanks(int l) {
if (l==0) return 0;
else return 1;
}
And the method with true-false:
public boolean Blanks(int l) {
if (l==0) return false;
else return true;
}

Binary Search w/o Library Methods

I am trying to construct a binarySearch method that goes through a sorted array, and evaluates whether a given element, given as int target, is present. It will do so by evaluating whether the mean value is greater or less than the target value, and will loop through the first or second half of the array accordingly.
I think I have the basic code down, but I am running into some problems:
int target = 0; (returns true) => correct
int target = (3, 6, 9); (returns false) => should return true
int target = (15, 19, 21, 90); returns "java.lang.ArrayIndexOutOfBoundsException: 15" => should be true
I imagine it has to do with my for statements in the respective if cases, but I have tried to debug and cannot. Also, I not permitted to use library methods.
Hopefully this question is helpful for other beginners like me. I would think it explores some java concepts like syntax, logic, and basic use Thanks for the help.
public class ArrayUtilities
{
public static void main(String[] args)
{
int[] arrayBeingSearched = {0, 3, 6, 9, 12, 15, 19, 21, 90};
int target = 90;
System.out.println("linear: " + linearSearch(arrayBeingSearched, target));
System.out.println("binary: " + binarySearch(arrayBeingSearched, target));
}
public static boolean binarySearch(int[] arrayBeingSearched, int target)
{
boolean binarySearch = false;
for (int i = 0; i < arrayBeingSearched.length; i++){
int left = 0; //array lower bound
int right = arrayBeingSearched.length - 1; //array upper bound
int middle = ((right - left) / (2)); //array mean
if(arrayBeingSearched[middle] == target){
binarySearch = true;
}
else if(arrayBeingSearched[middle] < target){
for(int j = middle + 1; j < arrayBeingSearched.length - 1; j ++){
int newLeft = arrayBeingSearched[j ++];
if(arrayBeingSearched[newLeft] == target){
binarySearch = true;
break;
}
else{
binarySearch = false;
}
}
}
else if(arrayBeingSearched[middle] > target)
for(int l = 0; l < middle - 1; l ++){
int newRight = arrayBeingSearched[l ++];
if(arrayBeingSearched[newRight] == target){
binarySearch = true;
break;
}
else{
binarySearch = false;
}
}
else{
binarySearch = false;
}
}
return binarySearch;
}
}
Okay, based on the comments, would this be a better representation? The first comment answered my question mostly but I just wanted to follow up:
public static boolean binarySearch(int[] array, int target)
{
int start = 0;
int end = array.length - 1;
while (start <= end)
{
int middle = start + (end - start)/2;
if (array[middle] == target) {
return true;
}
else if (array[middle] > target)
{
end = middle - 1;
}
else start = middle + 1;
}
return false;
}
}
This is a bad start:
for (int i = 0; i < arrayBeingSearched.length; i++)
That's a linear search, with something else within it. I haven't followed exactly what you're doing, but I think you should probably start again... with a description of binary search in front of you.
Typically a binary search loop looks something like:
int left = 0; // Inclusive lower bound
int right = arrayBeingSearch.length; // Exclusive upper bound
while (left < right) {
// Either change left, change right, or return success
// based on what you find
}
When your middle element is smaller than the target, you do this
int newLeft = arrayBeingSearched[j ++];
if(arrayBeingSearched[newLeft] == target) //...
And the equivalent when it's larger.
That is, you are taking an element of the array and using it as an index. Your array could contain only one element with a value of 1000, which is why you're running into an ArrayIndexOutOfBoundsException.
I'm sure there are other problems (see Jon's answer), but I wanted to mention that code like this:
for(int j = middle + 1; j < arrayBeingSearched.length - 1; j ++){
int newLeft = arrayBeingSearched[j ++];
will not do what you want. The for statement says that each time the program goes through the loop, it will add 1 to j (at the end of the loop code). But the next statement will use j as an index and then add 1 to it. The result is that each time you go through the loop, 1 will be added to j twice, so you're basically looking only at every other element. If this were otherwise correct (which I don't think it is), I'd say you definitely need to remove the ++ from the second line.

Complexity and Efficiency in Algorithm for: a[j]-a[i] i>=j

I'm looking to make this much quicker. I've contemplated using a tree, but I'm not sure if that would actually help much.
I feel like the problem is for most cases you don't need to calculate all the possible maximums only a hand full, but I'm not sure where to draw the line
Thanks so much for the input,
Jasper
public class SpecialMax {
//initialized to the lowest possible value of j;
public static int jdex = 0;
//initialized to the highest possible value of i;
public static int idex;
//will hold possible maximums
public static Stack<Integer> possibleMaxs = new Stack<Integer> ();
public static int calculate (int[] a){
if (isPositive(a)){
int size = a.length;
int counterJ;
counterJ = size-1;
//find and return an ordered version of a
int [] ordered = orderBySize (a);
while (counterJ>0){
/* The first time this function is called, the Jvalue will be
* the largest it can be, similarly, the Ivalue that is found
* is the smallest
*/
int jVal = ordered[counterJ];
int iVal = test (a, jVal);
possibleMaxs.push(jVal-iVal);
counterJ--;
}
int answer = possibleMaxs.pop();
while (!possibleMaxs.empty()){
if (answer<possibleMaxs.peek()){
answer = possibleMaxs.pop();
} else {
possibleMaxs.pop();
}
}
System.out.println("The maximum of a[j]-a[i] with j>=i is: ");
return answer;
} else {
System.out.println ("Invalid input, array must be positive");
return 0; //error
}
}
//Check to make sure the array contains positive numbers
public static boolean isPositive(int[] a){
boolean positive = true;
int size = a.length;
for (int i=0; i<size; i++){
if (a[i]<0){
positive = false;
break;
}
}
return positive;
}
public static int[] orderBySize (int[] a){
//orders the array into ascending order
int [] answer = a.clone();
Arrays.sort(answer);
return answer;
}
/*Test returns an Ival to match the input Jval it accounts for
* the fact that jdex<idex.
*/
public static int test (int[] a, int jVal){
int size = a.length;
//initialized to highest possible value
int tempMin = jVal;
//keeps a running tally
Stack<Integer> mIndices = new Stack<Integer> ();
//finds the index of the jVal being tested
for (int i=0; i<size; i++) {
if (jVal==a[i]){
//finds the highest index for instance
if (jdex<i){
jdex = i;
}
}
}
//look for the optimal minimal below jdex;
for (int i=0; i<jdex; i++){
if (a[i]<tempMin){
tempMin = a[i];
mIndices.push(i);
}
}
//returns the index of the last min
if (!mIndices.empty()){
idex = mIndices.pop();
}
return tempMin;
}
}
It can be done in linear time and linear memory. The idea is: find the minimum over each suffix of the array and maximum over each prefix, then find the point where the difference between the two is the highest. You'll also have to store the index on which the maximum/minimum for each prefix is reached if you need the indices, rather than just the difference value.
Pre-sorting a[] makes the procedure complicated and impairs performance. It is not necessary, so we leave a[] unsorted.
Then (EDITED, because I had read j>=i in the body of your code, rather than i>=j in the problem description/title, which I now assume is what is required (I didn't go over your coding details); The two varieties can easily be derived from each other anyway.)
// initialize result(indices)
int iFound = 0;
int jFound = 0;
// initialize a candidate that MAY replace jFound
int jAlternative = -1; // -1 signals: no candidate currently available
// process the (remaining) elements of the array - skip #0: we've already handled that one at the initialization
for (int i=1; i<size; i++)
{
// if we have an alternative, see if that combines with the current element to a higher "max".
if ((jAlternative != -1) && (a[jAlternative]-a[i] > a[jFound]-a[iFound]))
{
jFound = jAlternative;
iFound = i;
jAlternative = -1;
}
else if (a[i] < a[iFound]) // then we can set a[iFound] lower, thereby increasing "max"
{
iFound = i;
}
else if (a[i] > a[jFound])
{ // we cannot directly replace jFound, because of the condition iFound>=jFound,
// but when we later may find a lower a[i], then it can jump in:
// set it as a waiting candidate (replacing an existing one if the new one is more promising).
if ((jAlternative = -1) || (a[i] > a[jAlternative]))
{
jAlternative = i;
}
}
}
double result = a[jFound] - a[iFound];

Categories

Resources