I am in the process of writing a sudoku solver (still need to write the box check and actually complete the program) but I'm testing it as I know. The puzzle I'm testing right now is "very easy" as in there is only one empty cell in any row/column. THe puzzle starts with "empty" cells as zeros. My issues is that when I run the program and print out the puzzle after solve() is called, the zeros aren't changing and the original puzzle is just printed out. Not sure what my issue is, would appreciate some direction!
public ArrayList<Integer> create(){
ArrayList<Integer> possible = new ArrayList<Integer>();
for(int i=1; i<10; i++){
possible.add(i);
}
return possible;
}
public sudoku( int size )
{
SIZE = size;
N = size*size;
Grid = new int[N][N];
for( int i = 0; i < N; i++ )
for( int j = 0; j < N; j++ )
Grid[i][j] = 0;
}
public void solve()
{
int a, b, c, d, i, j, k, l;
int count = 0;
int value= 0;
for(i=0; i<N;i++){
for(j=0; j<N;j++){
if(Grid[i][j]==0){
ArrayList<Integer> possible = create();
//check row
for(a=0; a<N;a++){
for(b=0; b<N; b++){
if(Grid[a][0]==possible.get(a)){
possible.set(a, 0);
}
}
}
//check column
for(c=0; c<N;c++){
for(d=0; d<N;d++){
if(Grid[0][d]==possible.get(d)){
possible.set(d,0);
}
}
}
for(k=0; k<9; k++){
if(possible.get(k)!=0){
count++;
}
}
if(count==1){
for(l=0; l<9; l++){
if(possible.get(l)!=0){
value=possible.get(l);
}
}
}
Grid[i][j]=value;
}
}
}
}
Look at your line if(Grid[a][0]==possible.get(a)) (and similar spots). What is it doing there vs what do you actually want?
Your possible array looks something like this:
[1,2,3,4,5,6,7,8,9]
and your grid (just the first row, since you're only checking Grid[a][0]) might look something like this:
[3,7,8,1,2,9,5,0,4]
Your loop is looking at each element stepwise individually and seeing if they're equal, like this:
if(1 == 3) ... it's not
if(2 == 7) ... it's not
if(3 == 8) ... it's not
... etc
So, as you can see, when you do your
for(k=0; k<9; k++){
if(possible.get(k)!=0){
count++;
}
}
Your possible array is still going to be full of options most of the time, unless your first row happens to be some variation on [1,2,3,4,5,6,7,8,9] with a 0 in one of the spaces... so count is definitely going to be > 1
So, your next loop (for(l=0; l<9; l++)) next gets executed, so value is still (as you initialized it) 0.
Try stepping through a debugger on these points and seeing how the arrays are interacting.
if(Grid[a][0]==possible.get(a))
if(Grid[0][d]==possible.get(d))
You don't use b or c in these lines. You probably want:
if(Grid[a][i]==possible.get(b))
if(Grid[j][d]==possible.get(c))
Also, the Grid[i][j]=value check should be inside the if block.
You might want to use a Set for the possible values instead of an ArrayList.
You are always checking only the first row and first column and the way you check for the possible numbers is also not doing what you want.
A few tips first:
First of all, it is not necessary to always define a new variable for the loops, you can reuse them and then you won't have too many of them and you won't get so easily confused in them.
Secondly, if you name all the variables a, b, c, d, etc. you can also easily get confused. While it is ok to name variables in loops as i, j, if you have too many loops, it may be better to think of better names. In this case row and column for example.
Why don't you remove the numbers from the possible list? Something like:
int index = possible.indexOf(a);
if (index != -1) possible.remove(index);
Then it would be easier to determine how many values you still have left. You can simply do:
if (possible.size()==1) value = possible.get(0);
And one last note, to obey the convention for variable names, you should probably use grid instead of Grid.
And now the code:
public void solve() {
int row, column, i;
int count = 0;
int value= 0;
int index = 0;
for(row=0; row<N; row++){
for(column=0; column<N; column++){
if(Grid[row][column]==0){
ArrayList<Integer> possible = create();
//check row
for(i=0; i<N; i++){
index = possible.indexOf(Grid[row][i]);
if (index != -1) possible.remove(index);
}
//check column
for(i=0; i<N; i++){
index = possible.indexOf(Grid[i][column]);
if (index != -1) possible.remove(index);
}
if (possible.size()==1) value = possible.get(0);
Grid[row][column]=value;
}
}
}
}
EDIT: Rewritten the whole answer into a better form.
Related
I want to write a methode which will return the 1st position of a certain value in an 2D int array. If the value is not in the array, then the posistion will be an array with values [-1, -1]
My code is:
public static int[] findItemIn2DArray(int[][] A, int value)
{
int position[] = new int [] {-1, -1} ;
for (int i=0; i < A.length; i++)
{
for (int j=0; j < (A[i].length/2)+1; j++)
{
if ( A[i][j] == value )
{
position [0] = i;
position [1] = j;
}
break;
}
break;
}
return position;
}
I give the array
int numbers[][] =
{
{2,3,5} ,
{4,1,0,10} ,
{3,9,10} ,
{5,9,10,1,12}
};
and I'm searching for the value 10.
It was supposed to return [1,3], but instead I get [-1,-1]. I think that it does not go through all the row, but only checks out the first value.
Can you help me? Thank you.
First of all, you need to iterate through the whole column, not only half of it (in your second for-loop).
Second, your first break statement should be INSIDE the if statement, since the way you have your code now, your program will always break out of the code without getting to all the elements.
Third, Why do you have a second break? That causes your code to break every time you only get through the first row. You don't need it there.
Your code should look like:
public static int[] findItemIn2DArray(int[][] A, int value)
{
int position[] = new int [] {-1, -1} ;
boolean found = false;
for (int i=0; i < A.length; i++)
{
for (int j=0; j < (A[i].length); j++)
{
if ( A[i][j] == value )
{
position [0] = i;
position [1] = j;
found = true;
break;
}
}
if(found)
break;
}
return position;
}
if the first occurrence isnt equal to the value, it breaks the loop straight away. Try moving the break statement inside the 'if' statement
it's because you break the outer for loop after the inner for loop
The (A[i].length/2)+1 was a typo, it sould be A[i].length instead (that's what happens when you use CNTL+C without checking!)
The comments about the break command were very usefull, thank you all!
For example, if I have:
int Myarray[][] = new int[][] {{1,2}, {3,4}};
for (int line=0; line < Myarray.length; line++) {
for (int column = 0; column < Myarray[0].length; column++) {
// do something ...
}
}
How could I go through the entire array without the two loops?
Well you could use just a single loop:
for (int i = 0; i < Myarray.length*Myarray.length; i++) {
int row = i / Myarray.length;
int col = i % Myarray.length;
System.out.println(Myarray[row][col]);
}
But this assumes that your 2D array is square, i.e. its width and length are the same everywhere. Another way of saying this is that the 2D array is not jagged.
Demo
Note: As #Thilo mentioned above, this won't make things run faster. If you need to touch every element in your array, then my suggested code and your current double loop basically have the same complexity.
If you don’t need to know the line or column in the “do something” code (not stated in question), you could:
Arrays.stream(Myarray).flatMap(Arrays:stream)
.forEach(n -> /* do something with “n”, the cell value */);
You can iterate without any loops:
void recursive(int[][] array, int r, int c) {
if (r >= array.length) return;
if (c >= array[r].length) {
recursive(array, r+1, 0);
} else {
System.out.println(array[r][c]);
recursive(array, r, c+1);
}
}
Then invoke with recursive(array, 0, 0) to get started.
But there is no practical benefit in doing so. This would perform poorly, because of all the extra effort involved in calling a method vs just incrementing an int. (Plus, depending upon the size of the array, you could end up with a stack overflow).
Please bear within as it might be difficult to understand
I have an array of jbuttons 50 size big, for this example ill use 7 I have jbutton object within 1 2 3 4 6 7 but not 5. These are printed on the screen. I want to remove these jbuttons however all buttons up to 5 are removed while the last two are not.
for(int i = 1; i < 51; i++){
if(seat.buttonArray[i] == null){
remove(seat.buttonArray[i]);
seat.buttonArray[i] = null;}
}
There is no way to remove element from array, assuming you want latter indexes changed after remove. For this purpose, you should use List:
Iterator buttonIterator = seat.buttonList.iterator();
while (buttonIterator.hasNext()) {
Object button = buttonIterator.next(); //or more specific type, if your list was generified
if (button == null) { //or some other criteria, wrote this just as an example
buttonIterator.remove();
}
}
If using array is mandatory, you have two options:
Set seat.buttonArray[i] to null value, indicating it has been removed;
Recreate array each time you deleted something. See System.arraycopy javadoc for details, although I do not recommend this approach because of performance considerations.
You could store the values in a temp array and then copy what you want back into your original array. Somewhat similar to this:
int myArray[50];
int temp[50];
int good;
for (int i = 0; i < 50; i++) {
myArray[i] = i;
}
for (int i = 0; i < 50; i++) {
temp[i] = myArray[i];
}
good = 0;
for (int i = 0; i < 50; i++) {
if (i < 10) {
} else {
myArray[good] = temp[i];
good += 1;
}
}
Looks messier than I first thought... But it essentially does what you're wanting.
This is a method for a Sudoku game.
Could someone explain their thought processes for this? :( I'm having a lot of difficulty figuring this out. I know for the first method, we're supposed to use a for loop or something.
I know my iteration for my method is wrong...Sorry :(
private int countOccurrencesInCol(int col, int d){
for (int i = 0; i < grid.length; i++;){
for(int j = col; j = col; j++;){
if (grid[i][j] == d){
count++;
}
}
}
return count;
}
This method returns the number of times a digit occurs in a given column in a 9 X 9 matrix.
private int countPossiblePlacementsInCol (int col, int d){
This method is supposed to determine the number of spots in a given column where a given digit can be placed, and returns the number of spots where a digit can be placed in a spot for a given column. If the digit already occurs, then the method returns 0.
Here is some code with explainations to help you understand the approach required:
private int countOccurrencesInCol(int col, int d) {
// counter variable to count the number of occurrences
int counter = 0;
// matrix is the 2D array, the first index is the row, second is the column
// loop through each index of the given column, checking for the digit, d
for(int row = 0; row < matrix.length; row++) {
// if a match is found...
if(matrix[row][col] == d) {
// increment the counter by one
counter++;
}
}
// return the final count
return counter;
}
The next method is a bit trickier, because I am not clear on what is required. Is this method supposed to just return the number of empty cells in the given column? Or should it take into account all the rules of sudoku and check if those empty cells are valid moves for that digit? If it is the former, then the solution is simple:
private int countPossiblePlacementsInCol(int col, int d) {
// I am assuming an empty cell is indicated by 0. In that case,
// we can reuse the previous method to find the number of occurrences of d,
// and the occurences of 0
// first, find out if the digit already occurs in the row, return 0
// if it does:
if(countOccurrencesInCol(col, d) > 0) {
return 0;
}
// next, return the number of times 0 occurs (the number of empty cells):
return countOccurrencesInCol(col, 0);
}
However, if you must count only VALID moves, this gets a lot trickier. The last line in the previous method would turn into something more like this:
private int countPossiblePlacementsInCol(int col, int d) {
//start the same as the previous method:
if(countOccurrencesInCol(col, d) > 0) {
return 0;
}
int counter = 0;
// this time, for each cell in the column, you must check that it is a valid move:
for(int row = 0; row < matrix.length; row++) {
if(countOccurrencesInRow(row, d) == 0 &&
countOccurencesInSquare(row, col, d) == 0) {
counter++
}
}
}
The two methods I used this time, countOccurrencesInRow and countOccurencesInSquare are going to do something similar to countOccurrencesInCol. The Row one is basically the same as the Col one, but it checks a row instead of a column. The Square one is a bit trickier. Assuming you know the rules of sudoku, you should know that a square is a 3x3 section of the 9x9 game board (in which there are 9 3x3 sections). The Square method will use the row and col to figure out which square the given cell is in, and then loop through the rows and columns of just that square, counting occurrences of the given digit. For this, you will need to use two for loops, one nested inside the other. If you have trouble understanding how to properly use for loops, and loop through arrays, then I suggest you talk to your teacher/professor for additional help on the topic.
I hope these explanations and examples help. Good luck.
You do not need a second for loop.
Count of occurrence of number in a column can be found by
private int countOccurrencesInCol(int col, int d){
for (int i = 0; i < grid.length; i++){
if (grid[i][col] == d){
count++;
}
}
return count;
}
Hope this helps!
Good luck!
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.