I've a problem with my sudoku solving method. The program works like this; the board is empty when started, the users adds a couple of numbers to the board and then by hitting a Solve-button the program tries to solve it. Everything works fine besides if I put the same number in the same row. So if the user adds 1,1,0,0 ... 0. In the puzzle it can't solve it because its two 1's next to each other and will just go on forever trying to find a sulotion even though its an unsolvable puzzle. However if they were all 0's(empty) it would solve it right away, same as if Id put 1 and 2 in the top left corner. If I'd just put some random numbers in it will detect it as unsolvable (or will solve it if it's a valid puzzle)
I'm thinking around the lines of saying, when theNumber == (row, col) equals thenNumber == (row+1, col), it should return false because it's a duplicated number.
This is the code I tried to add in the solve method, obviously without success.
if ((puzzle.getNum(row, col) == a) == (puzzle.getNum(row + 1, col) == a)) {
return false;
}
Help is greatly appreciated
Validate the puzzle like this:
Create a boolean array of 9 elements.
Loop through every row, column and 9x9 box.
If you read a number, set the corresponding value in the array to true.
If it is already true throw an error (impossible puzzle).
After reading a row, column or 9x9 box reset the boolean array.
Then, if the validation succeeded call the solving method.
EDIT: Source code
public boolean checkPuzzle() {
boolean[] nums = new boolean[9];
for (int row = 0; row < panel.puzzleSize; row++) {
for (int cell = 0; cell < panel.puzzleSize; cell++) {
if (nums[puzzle[row][cell]]) return false;
nums[puzzle[row][cell]] = true;
}
nums = new boolean[9];
}
for (int col = 0; col < panel.puzzleSize; col++) {
for (int cell = 0; cell < panel.puzzleSize; cell++) {
if (nums[puzzle[cell][col]]) return false;
nums[puzzle[cell][col]] = true;
}
nums = new boolean[9];
}
for (int square = 0; square < panel.puzzleSize; square++) {
int squareCol = panel.squareSize * (square % panel.squareSize);
int squareRow = panel.squareSize * Math.floor(square / panel.squareSize);
for (int cell = 0; cell < panel.puzzleSize; cell++) {
int col = cell % panel.squareSize;
int row = Math.floor(cell / panel.squareSize);
if (nums[puzzle[squareCol + col][squareRow + row]]) return false;
nums[puzzle[squareCol + col][squareRow + row]] = true;
}
nums = new boolean[9];
}
return true;
}
Didn't have too much time to test out, but it might work (?). The row/col variable namings might be incorrect, because I didn't have time to find that in your code, but it shouldn't matter for it to work or not.
Related
This method is supposed to return true if there is more than one 1 in a column of a 2D array, yet it doesn't work. I can't figure out what's wrong with it so I thought I'd get some expert opinions.
Example:
10010
01001
10100
will return true because there are 2 ones in the first column.
Here is the code
public static boolean isVert(int[][] x) { //checks for more than one 1 in columns
int count = 0;
boolean break2 = false;
boolean check = false; //false means no 2 (or more) queens in same column
for (int i = 0; i < x.length; i++) {
count = 0;
for (int j = 0; j < x[i].length; j++) {
if (x[i][j] == 1) {
count++;
}
if (count > 1) {
break2 = true;
check = true;
break;
}
}
if (break2) {
break;
}
}
return check;
}
You break at the first occurance of 1 in whole array, which is probably not the expected result.
Explanation of how your code works:
loop until counter i is less than length of array (number of rows in array)
loop until counter j is less than length of i-th row (number of columns or elements in array)
check if element on i-th row and j-th column is 1, if true, increase variable count by one
if count is greater than 1 (this means it has to be 2 or greater) set break2 and check to true, break
if break2 is true (which is as count is > 2 and first loop breaks), break this loop too:
this happens in 1st row of your example table
end of loops, return check (which is true because 1st row contains 2 ones)
The problem in your code is that you break when you find your first row that satisfies your condition, but you do not (necessarily) check all the rows in given array.
I have corrected the code for you, hopefully it works (untested)
public static boolean isVert(int[][] x) { //checks for more than one 1 in columns
int count = 0;
for (int i = 0; i < x.length; i++) {
int rowCount = 0;
for (int j = 0; j < x[i].length; j++) {
if (x[i][j] == 1) {
rowCount++;
}
if(rowCount > 1) {
count++;
break;
}
}
}
// returns true if count of lines containing 1 equals length of array,
// if not, returns false
return count == x.length;
}
Start of by improving your naming convention. Your code has many variables named by their contents, instead of named by how they are used. For example:
boolean check = false; // false means no two queens in the same column.
instead of
boolean twoQueensInColumn = false;
and the other example
boolean break2 = false;
instead of the more reasonable
boolean continueLooking = true;
Plus, it is a very good idea to avoid using variables as place holders for loop escaping logic. For example, the two stanzas
...
if (count > 1) {
break2 = true;
check = true;
break;
}
}
if (break2) {
break;
}
are a breeding ground for bugs, requiring a lot of debugging to ensure they work "right now" which will break just as soon as you modify the code. Much better would be
boolean keepLooking = false;
for (int row = 0; keepLooking && (row < board.length); row++) {
int queensInColumn = 0;
for (int column = 0; keepLooking && (column < board[row].length, column++) {
if (board[row][column] != 0) {
queensInColumn++;
}
if (queensInColumn > 1) {
keepLooking = false;
}
}
}
The main difference being the control logic is in the loop "conditional" block, where it belongs.
I would recommend turning your integers to string and using the .contains() method and looping through that. This would make the code easier to understand.
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.
I'm trying to generate a Sudoku board via a 2D array: board[5][5]. The Sudoku board should only contain unique vowels. However, I have only made unique vowels appear in a row. For the columns, they still seem to have duplicates. How am I suppose to generate a column with no duplicates using the code I have so far?
Here's the code I have for generating unique letters in a row:
String [] vowels = {"A","E","I","O","U"};
String [][] board = new String [vowels.length][5];
public Actions(){
int rows = 5;
for(int row = 0;row<rows;row++){
ArrayList<String> tempVowels = new ArrayList<String>(Arrays.asList(vowels));
int numVowPerLine = (int)Math.floor(Math.random()*4);
for(int j = 0;j<numVowPerLine;j++){
do{
int pos = (int)Math.floor(Math.random()*5);
if(board[row][pos] == null){
int temp = (int)Math.floor(Math.random()*tempVowels.size());
board[row][pos] = tempVowels.get(temp);
tempVowels.remove(temp);
break;
}
}while(true);
}
}
Credits to: L7ColWinters
This is related to a rather well known problem, called the Rooks Problem.
Might I suggest a simpler loop?
EDIT: After reading comments, I see that the problem needs to be applied to each vowel. In my opinion, this is more readable:
java.util.Random random = new Random();
boolean[] r_occupied;
boolean[] c_occupied;
for (i = 0; i < vowels.length; i++)
{
// Clear the 'occupied' information
r_occupied = new boolean[5];
c_occupied = new boolean[5];
// we will put vowel[i] 'count' times into the 'board'
count = random.nextInt(5);
for (j = 0; j < count; j++)
{
// generate a random row
row = random.nextInt(5);
// if it is already occupied, select the next one
while (r_occupied[row])
row = (row + 1) % 5;
// generate a random column
col = random.nextInt(5);
// if it is already occupied, select the next one
while (c_occupied[col])
col = (col + 1) % 5;
/* put the vowel at board[row][col] */
r_occupied[row] = true;
c_occupied[col] = true;
board[row][col] = vowel[i];
}
}
Note: It will overwrite some vowels, but this should be OK.
If the content of first column / first row is A and you are on the first column / second row, you could use a truncated array, i.e. String [] availableVowels = {"E","I","O","U"};, to select from. If you pick O, then when you are on first column / thrid row, you would choose from String [] availableVowels = {"E","I","U"};. etc.
Before adding an additional vowel character in a row check if it
already contains this vowel and with continue you can pass to the
other vowel
You can also do the same thing for the columns with just switching
it
before this:
board[row][pos] = tempVowels.get(temp);
Write this:
boolean b = false;
for(int j = 0;j<columnLength; j++){
if(board[row][j] == tempVowels.get(temp))
b= true;
if(b == true)
{
b = false;
continue;
}
board[row][pos] = tempVowels.get(temp);
}
I had a class assignment (it's already past) where I had to write a Sudoku solver. I was able to create a method that can solve for each missing number. But I'm having trouble creating a method to find which cells I need to solve. I'm supposed to take a 2D array and fill in the missing number (represented by 0's).
I've put some of my code below, but not all of it (even though the assignment has passed, I respect the profs wishes).
public class SolveSudoku {
private static int[][] grid = new int[9][9];
public static int[][] getSolution(int[][] grid) {
for (int i = 0; i < 9; i++) {
System.arraycopy(grid[i], 0, SolveSudoku.grid[i], 0, 9);
}
int n = getZero();
return getSolution(n);
}
private static int[][] getSolution(int n) {
if (n == 0) {
return grid;
}
Cell cell = getZero();
int row = cell.row;
int column = cell.column;
for (int number = 1; number <= 9; number++) {
//checks cell using another method
//I have booleans that return true if the number works
}
return null;
}
private static int getZero() {
return 0;
}
private static class Cell {
int cell = 0;
int row = 0;
int column = 0;
int number;
}
}
I have the getZero method which has to find each zero in the grid (0's represent a missing number) so I can solve it. What should I do in getZero to find the cells I need to replace?
You don't check if the number is repeated in the same 3x3 square (only rows and columns).
I don't get what do you mean by "finding zeroes". In fact it is meaningless, solving the sudoku from the first row or the last one has no effect in the solution. I'll explain what did I do for the same trouble.
A cell is not an int, is an object. In the object I store a value (the number if it is found, 0 if not) and a boolean[9]. False means (index + 1) is discarded because it is in the same row/column/square, true means it is not decided yet. Also, 3 Lists (Vectors, Sets, whatever).
A list of 81 cells (you can make it a bidimensional array if you wish).
9 Lists/Vectors/Sets representing rows, 9 representing columns, 9 representing square. Each of the 81 cells is assigned to its row/column/square. Inside each cell you store the references to the list to which it belongs to.
Now comes the execution part. In a first iteration, every time you find a non-zero (a number fixed in the sudoku), you loop through the lists to which the cell belongs. For each cell in those lists, you mark the boolean assigned to that number to false.
You loop through cells, each time you find a 0 you check how many of the booleans in the cell are true. If it is 1 (all other 8 possible values have been discarded), it is the value of the cell. You set it, and as in 4) you get the list to which it belongs and mark that number to false in every cells. Loop until you get a solution, or an iteration in which you cannot set any number (no solution available directly, must start with backtracking or similar).
Remember before getting at the keyboard, to have a clear idea about what the question is and how would you resolve it without a computer. If you do not know what you want to do, the computer won't help (unless you post in stackoverflow)-
From what I can tell you want to find the first 0-valued cell in grid. I'll define first as the first zero containing column in the lowest zero-containing row.
This can be done using a naive search:
private Cell getZeroCell(){
int rz = -1;
int cz = -1;
outer: for(int row = 0; row < grid.length; row++){
for(int col = 0; col < grid[row].length; col++){
if(grid[row][col] == 0){
rz = row;
cz = col;
break outer;
}
}
}
if(rz == -1 || cz == -1){
// no zeros found
return null;
}else{
// first zero found at row `rz` and column `cz`
Cell cell = new Cell();
cell.row = rz;
cell.column = cz;
return cell;
}
}
Get the "number" of the first cell containing a zero (counting left to right, then top to bottom, 0-indexed):
private int getZeroInt(){
int rz = -1;
int cz = -1;
outer: for(int row = 0; row < grid.length; row++){
for(int col = 0; col < grid[row].length; col++){
if(grid[row][col] == 0){
rz = row;
cz = col;
break outer;
}
}
}
if(rz == -1 || cz == -1){
// no zeros found
return -1;
}else{
return rz * grid[0].length + cz;
}
}
Get the number of cells containing a zero:
private int getNumZeros(){
int count = 0;
for(int row = 0; row < grid.length; row++){
for(int col = 0; col < grid[row].length; col++){
if(grid[row][col] == 0){
count++;
}
}
}
return count;
}
I decided to write a logic solving algorithm for my Sudoku application. What I wrote works for a limited amount of grid values, but then the recursion stops way too soon.
What my methods do:
addToThirdDimension(): A three dimensional array stores any possible values that can be put into the grid value at logicGrid[x][y]. This method refreshes the three dimensional array. It does this by testing values 1-9 in every grid index, and if it's valid, it adds that number to the array. If not, it sets that value to zero.
checkValues(): Checks how many possibilities are left in the three dimensional grid. It goes through the logicGrid and returns the number of non-zero values are in the grid.
checkSingleValue(int row, int col): Checks logicGrid[row][col] to see if there is one and only one value left in there (If there is one value left, it is the only possibility for the grid element at [row, col]). It returns the amount of non-zero values that are in that grid location.
getSingleValue(int row, int col): Returns the single number that's left in logicGrid[row][col]
immutableValues: A two dimensional boolean array that stores whether or not a specific grid element is immutable or not. If it is immutable, the solve method should not touch it.
public boolean solveWithLogic(){
addToThirdDimension();
if(checkValues() == 0){
return true;
}
for(int row = 0; row < 9; row++){
for(int col = 0; col < 9; col++){
if(!immutableValues[row][col]){
if(checkSingleValue(row, col) == 1){
sGrid[row][col] = getSingleValue(row, col);
setValues[row][col] = true;
addToThirdDimension();
}
}
}
}
if(checkValues() != 0){
solveWithLogic();
} else{
return true;
}
return false;
}
I cannot see where I am going wrong. After a certain number of tries, checkValues returns 0 even though there should be more possibilities. Here is the code for addToThirdDimension() as I am sure that if something is wrong, it is here.
sGrid is the main two-dimensional integer array that stores the values for the puzzle.
public void addToThirdDimension(){
logicGrid = new int[9][9][9];
for(int x = 0; x < 9; x++){
for(int y = 0; y < 9; y++){
for(int z = 0; z < 9; z++){
logicGrid[x][y][z] = z + 1;
}
}
}
int[][] temp1 = sGrid;
for(int row = 0; row < 9; row++){
for(int col = 0; col < 9; col++){
if(setValues[row][col]){
for(int i = 0; i < 9; i++){
logicGrid[row][col][i] = 0;
}
} else{
for(int i = 1; i <= 9; i++){
temp1[row][col] = i;
if(!isColumnValid(col, temp1) && !isRowValid(row, temp1) &&
!isQuadrantValid(row, col, temp1){
logicGrid[row][col][i-1] = 0;
}
}
}
temp1[row][col] = sGrid[row][col];
}
}
}
The code isn't too efficient at the moment. I want to get it working before I start minimizing solve times.
The first thing I would do is create a SudukoCell object that stores your possible values in it. Then create a SudukoBoard with a 2d array of SudukoCells. Also give it an array of SudukoAreas. One area for rows, one area for cols, and one area for blocks.
Add your suduko cells appropriately.
This will help you consolidate your legwork and prevent silly mistakes.
then every time you solve a number, you can go to the cells in each of its areas and remove the number you solved from them.