(2D array) Java error: constant expression required - java

I'm doing my homework for Data Structures and I'm having trouble with 2D Array. Here's what I have to do:
"Suppose you are designing a multiplayer game that has n≥1000 players,
numbered 1 to n, interacting in an enchanted forest. The winner of this
game is the first player who can meet all the other players at least
once (ties are allowed). Assuming that there is a method meet(i, j),
which is called each time a player i meets a player j (with i ̸= j),
describe a way to keep track of the pairs of meeting players and who is the winner."
I can't compile because of this error:
Multiplayer.java:51: error: constant expression required
for this line:
case meet: sb.append("1");
I'm a beginner so I really appreciate any help. Thank you in advance!
/* Suppose you are designing a multiplayer game that has n≥1000
players, numbered 1 to n, interacting in an enchanted forest. The winner
of this game is the first player who can meet all the other players at
least once (ties are allowed). Assuming that there is a method meet(i,
j), which is called each time a player i meets a player j (with i ̸=
j), describe a way to keep track of the pairs of meeting players and
who is the winner. */
public class Multiplayer {
int n; // number of players
int map[][] = new int[n][n]; // create a 2D array
int meet = 1;
int notMeet = 0;
int[] count; // an array to keep the count, player wins when it reaches n
public Multiplayer() {
clearMap();
} // initiate a new game
public void clearMap() { // clear the 2d array
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
map[i][j] = notMeet; // clearing the map
count[i] = 0; // turn every value of count[] into 0
if (i == j)
map[i][j] = map[j][i] = meet; // when i == j give the tile the value of 1
}
}
}
public void meet(int i, int j) {
// when player i meets player j, add 1 to the count[] of each player
count[i] = count[i] + 1;
count[j] = count[j] + 1;
}
public int isWin() {
for (int i = 0; i < n; i++) {
if (count[i] == n)
return i; // player at the index i wins
}
return -1; // no player won yet
}
public String toString() {
// display the map in string
StringBuilder sb = new StringBuilder();
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
switch (map[i][j]) {
case meet:
sb.append("1"); // if player i and j meets, put 1 in the map //this line causes error
default:
sb.append("0"); // if they haven't met, put the 0 as default
}
if (j < n - 1)
sb.append("|");
}
if (i < n - 1)
sb.append("\n-----\n");
}
return sb.toString();
}
}
class MultiplayerTest {
public static void main(String[] args) {
Multiplayer newGame = new Multiplayer();
newGame.n = 5; // test for a small number of players
// test for player 1 to meet all other players
for (int i = 2; i <= 5; i++) {
newGame.meet(1, i);
}
// print test to see if player 1 wins the game
System.out.println(newGame.toString());
System.out.println(newGame.isWin());
}
}

You can't use variables as the labels in a switch statement.
If you want to have a constant value in your program, the usual method is to create a static final member:
public static final int MEET = 1;
However, in this case if you only have two values then you are better using a boolean array and just checking for true and false. There is no need for a switch statement.
boolean map[][] = new boolean[n][n];
...
if (map[i][j]) {
...
In this case, it is better to rename the array met, so you code reads like this:
if (met[i][j]) {
...

You need to initialize your count array, like
public void initializeArray(int n) {
this.n = n;
count = new int[n];
for (int i = 0; i < n; i++) count[i] = 0;
}
and then, instead of
newGame.n = 5;
you will need to do:
initializeArray(5);

I can't see where you actually create the array count.
Your code:
boolean met[][] = new boolean[n][n]; //edited
int[] count; // an array to keep the count, player wins when it reaches n
creates the array met (... = new boolean[n][n]), but there is no such statement for the array count. Hence, references to count[i] fail.

So I fixed the code like you guys suggested. Thank you all so much! This code below still has an error, but it's a lot better than my original one. Anyone knows about ArraysIndexOutOfBound error?
import java.util.Arrays;
public class Multiplayer {
int n; //number of players
boolean met[][] = new boolean [n][n];
int[] count; //an array to keep the count, player wins when it reaches n
public Multiplayer() {clearMap(); } //initiate a new game
public void clearMap() {
for (int i = 0; i < n; i ++) {
for (int j = 0; j < n; j++) {
met [i][j] = false; //clearing the map
count [i] = 0; //turn every value of count[] into 0
if (i == j)
met[i][j] = met[j][i] = true;
}
}
}
public int[] meet(int i, int j){
//when player i meets player j, add 1 to the count[] of each player
if (i != j) {
count [i] = count[i] + 1;
count [j] = count [j] + 1;
met [i][j] = met[j][i] = true;
}
//System.out.println(Arrays.toString(count));
return count;
}
public void initializeArray(int n) {
this.n = n;
count = new int[n];
for (int i = 0; i < n; i++) count[i] = 0;
}
public int isWin () {
for (int i = 0; i < n ; i++){
if (count[i] == n-1) //if player i meets all the other players
return i; //player at the index i wins
}
System.out.println(Arrays.toString(count));
return -1;
}
public String toString() {
//display the map
StringBuilder sb = new StringBuilder();
for (int i = 0; i < n; i++) {
for (int j = 0; j <n; j++) {
if (met [i][j]) {sb.append("true");} //this line causes error ArrayIndexOutofBound
else {sb.append("false");}
if (j<n-1) sb.append ("|");
}
if (i<n-1) sb.append("\n-----\n");
}
return sb.toString();
}
}
class MultiplayerTest {
public static void main (String[] args) {
Multiplayer newGame = new Multiplayer ();
newGame.initializeArray(5); //test for a small number of players
//test for player 1 to meet all other players
for (int k = 0; k < 5; k++) {newGame.meet (1,k); }
//print test to see if player 1 wins the game
System.out.println(newGame.isWin());
//System.out.println(newGame.toString()); I tried printing the 2D array output into String but encountered an error and don't know how to fix it, but the other methods are fine.
}
}

In the below snippet:
switch (map[i][j]) {
case meet:
sb.append("1"); // if player i and j meets, put 1 in the map //this line causes error
default:
sb.append("0"); // if they haven't met, put the 0 as default
}
Please note that there is no break; statement and hence, as per fall through logic, it will append 0 anyway.
If you just have one case, you should rather use if, e.g.:
if(map[i][j] == meet) {
sb.append("1");
}else {
sb.append("0");
}
update
Regarding the NullPointerException, you are getting that exception because count array is not initialised and you are trying to access the element.
Change the declaration to the following:
int[] count = new int[n];

The 'constant expression required' suggests that the labels in switch case requires a constant. And as suggested by other answers, its better to use if and use boolean 2d array.
ArraysIndexOutOfBound error is actually due to because you need to create an array using the new operator in the constructor method and then pass the reference to
map asmap = new boolean[n][n];
I've tried here:
public class Multiplayer {
int n; //number of players
boolean[][] map; //not initializing here but in constructor
int[] count; //an array to keep the count, player wins when it reaches n
public Multiplayer(int num){
n=num;
map = new boolean[n][n];
count = new int[n];
//No need to use clearMap as all instance variables are assigned the default value of 0 or false or null;
for(int i=0;i<n;i++){ //self-meeting
count[i]=1;
map[i][i]=true;
}
}
public void meet(int i,int j){
if(i==j) return;
//player number 1 is at index number 0
//Hence player i is at index number i-1
i--;j--;
count[i]+=1;
count[j]+=1;
map[i][j]=map[j][i]=true;
}
public int isWin(){
for(int i =0;i<n;i++)
if(count[i]==n)
return i; // player at the index i wins
return -1; // no player won yet
}
public String toString(){
String s = "";
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
if(map[i][j]) s+="1";
else s+="0";
if(j<n-1) s+="|";
}
s+="\n";
for(int k=0;k<n && i<n-1;k++)
s+="--";
s+="\n";
}
return s;
}
}
public class MultiplayerTest {
public static void main(String[] args) {
int numberOfPlayers = 5;
Multiplayer newGame = new Multiplayer(numberOfPlayers);
// test for player 1 to meet all other players
for (int i = 2; i <=5; i++) {
newGame.meet(1, i);
}
// print test to see if player 1 wins the game
System.out.println(newGame.toString());
System.out.println(newGame.isWin());
}
}

Related

Why are my arrays returned blank from a method but the code works fine when running in the main-Method?

I'm having following problem with my program.
It's a "connect four" Java console application.
When starting my program, I reset 3 things.
A multi-dimensional char array
public final int rows = 8, columns = 8;
public char[][] board = new char[rows][columns];
I reset it with a for-loop, overwriting every array field with the character '.', which is my default board texture.
public char[][] resetBoard() {
// for loops cycle through every array field
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
board[i][j] = '.';
}
}
return board;
}
An integer-array
public int[] nums = new int[columns];
I reset it with a for-loop using the variable i, since I just need an array with the length of columns, which just counts up from 1. It is used so the user know which column he's choosing. Like in chess "A6" e.g., except without letters.
public int[] resetNums() {
for (int i = 0; i < nums.length; i++) {
nums[i] = i + 1;
}
return nums;
}
An integer
public int roundCounter = 0;
The integers keeps track of how many rounds there have been in the current game. I want it to be printed while playing.
public int resetRoundCounter() {
// Resetting Round Counter, by initializing it to 0
return roundCounter = 0;
}
I reset these looking like this:
gameMain main = new gameMain();
gameMode mode = new gameMode();
gameCheck check = new gameCheck();
main.board = main.resetBoard();
main.nums = main.resetNums();
check.roundCounter = check.resetRoundCounter();
My problem is when printing the game board, the nums-array and the round counter none seem to work.
The game board is just completely blank. The nums-array is only 0's and the round counter stays at 0.
When running the code in the main-method it worked better than running it through classes etc.
My print method:
public void printBoard() {
gameMain main = new gameMain();
gameCheck check = new gameCheck();
// Printing number array with space in between the elements
for (int i = 0; i < main.nums.length; i++) {
System.out.print(main.nums[i] + " ");
}
// Printing the round count next to the number array
System.out.println(" Round " + check.getRoundCounter());
for (int i = 0; i < main.rows; i++) {
for (int j = 0; j < main.columns; j++) {
System.out.print(main.board[i][j] + " ");
}
System.out.println();
}
for (int i = 0; i < main.nums.length; i++) {
System.out.print(main.nums[i] + " ");
}
System.out.println("\n");
}
I could really use some help, since I've been up all night. Originally due to how much fun I was having programming this, now it has become frustrating.
Thanks for reading and thanks in advance!
I think what is happening to you is related to the references of the objects you are using. You are mixing two different ways of working, I give you an example:
You can use the reference of 'roundCounter' and work on it:
public void resetRoundCounter() {
// Resetting Round Counter, by initializing it to 0
roundCounter = 0;
}
or you can return it, like this:
public int resetRoundCounter() {
// Resetting Round Counter, by initializing it to 0
return 0;
}
In the first case, you will have to call the function like this:
resetRoundCounter(); //this function changes the value of your variable.
In the second case, you will have to call the function like this:
roundCounter = resetRoundCounter();
You can choose the way you like to work but I recomend you not working with global variables especially working with methods. I hope it helps you.
Do it as
public void resetBoard() {
// for loops cycle through every array field
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
board[i][j] = '.';
}
}
}
public void resetNums() {
for (int i = 0; i < nums.length; i++) {
nums[i] = i + 1;
}
}
public void resetRoundCounter() {
// Resetting Round Counter, by initializing it to 0
roundCounter = 0;
}
Finally, call them as follows:
gameMain main = new gameMain();
gameCheck check = new gameCheck();
main.resetBoard();
main.resetNums();
check.resetRoundCounter();
I also recommend you follow Java Naming Convention e.g. gameMain should be GameMain and gameCheck should be GameCheck.

JAVA Need help involving matrices and arrays

I'm working on a test prep program. Its not homework or for a grade, I just need help finishing and fixing it so I can study and better understand how it works. The directions are "Write a program named Matrix1.java that randonly fills in 0s and 1s into an n-by-n matrix, prints the matrix." I'm still pretty new to coding so any help would be greatly appreciated. This is the code I have so far:
public class Matrix1{
public static void main(String[] args){
Matrix1 matrix=new Matrix1(5);
matrix.fill();
matrix.print();
}
public Matrix1(int n){
int[][] matrix = new int[n][n];
}
public void fill(int n){ // randomly fill in 0s and 1s
Random rand = new Random();
for(int i = 0; i < n; i++){
for(int j = 0; j < n; j++){
Integer r = rand.nextInt;
matrix[i][j] = Math.abs(r);
}
}
}
public void print(int[][]matrix, int n){ //print the matrix, each row is printed in a separate line
for(int i = 0; i< n; i++){
for(int j = 0; j<n; j++){
System.out.println(array[i][j]);
}
}
}
}
I ended up confusing myself and I'm not sure how to fix it or continue. I think I'm partially on the right track though.
Your code after fixes.
import java.util.Random;
public class Matrix1 {
private final int[][] matrix;
private final int n;
public Matrix1(int n) {
this.n = n;
this.matrix = new int[n][n];
}
/**
* randomly fill in 0s and 1s
*/
public void fill() {
Random rand = new Random();
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
matrix[i][j] = rand.nextInt(2);
}
}
}
/**
* print the matrix, each row is printed in a separate line
*/
public void print() {
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
System.out.print(matrix[i][j]);
}
System.out.println();
}
}
public static void main(String[] args) {
Matrix1 matrix = new Matrix1(5);
matrix.fill();
matrix.print();
}
}
So changes I've made:
I've changed "matrix" and "n" variables into class fields, so you don't have to pass them through class methods
filling array - it should be just 0/1 not any integer so you can use rand.nextInt(2) with bounds - it gives values less then 2
printing array - you have to print row in one line, then change line
It looks like the right direction, check your main method to set the necessary parameters (size, array and size).
Also set the Random object to only be 0 or 1 (Check the Java class libraries for the answer) I believe you can set a parameter inside the Random.nextInt method.
Also if its required to print it like a double array, change up your printing logic since you are always writing to a new line
Well, I see a few problems, which if fixed might help get you on the right track.
First of all, for the random integer, you'll probably want to use the method from this answer:
import java.util.concurrent.ThreadLocalRandom;
// nextInt is normally exclusive of the top value,
// so add 1 to make it inclusive
ThreadLocalRandom.current().nextInt(min, max + 1);
I don't think you need to use Math.abs in this case, as long as you call ThreadLocalRandom.current().nextInt(0, 2).
Second, there are a couple of problems with your printing code. First of all, you should be using matrix[i][j] instead of array[i][j]. Second, you'll want to use System.out.print instead of System.out.println.
It should be something like this:
for(int i = 0; i< n; i++){
for(int j = 0; j<n; j++){
System.out.print(matrix[i][j]);
}
System.out.println();
}
public class Matrix1{
public static void main(String[] args){
Matrix1 matrix = new Matrix1(5);
matrix.fill();
matrix.print();
}
private int[][] m; //it is easier use a global variable
public Matrix1(int n){
m = new int[n][n];
}
public void fill(){ // randomly fill in 0s and 1s
for(int i = 0; i < m.length; i++){
for(int j = 0; j < m.length; j++){
if (Math.random() > 0.5) {
m[i][j] = 1;
} else {
m[i][j] = 0;
}
}
}
}
public void print(){ //print the matrix, each row is printed in a separate line
for(int i = 0; i< m.length; i++){
for(int j = 0; j<m.length; j++){
System.out.print(m[i][j]); //only use print() for the same row
}
System.out.println("");
}
}
}

Object Oriented Programming Involving Arrays

I'm so lost with this problem and I don't even know how to get to the end point. I can't even get my array to work. Can someone help me out?
Problem #73-Write a method with a void return value that sets to 0 all
the elements of the even numbered rows and sets to 1 all the elements
in the odd numbered rows of a 2-dimensional array of ints. Include
the code to test your method.
public class EvenOdd
{
/*public EvenOdd(int numberOfRows, int numberOfColumns)
{
oddOrEven = new int [numberOfRows][numberOfColumns];
}//end arrayEvenOdd
*/
public static void main (String []args)
{
int [][] oddOrEven = { {1,2,3} , {1,3,5} };
for (int i = 0; i < oddOrEven.length; i++)
{
if (oddOrEven[i] % 2 == 0)
{
for(int j = 0; j < oddOrEven[i].length; j++)
{
oddOrEven[i][j] = 0;
}//end loop
System.out.print(oddOrEven[i]);
}//end set loop
else
{
for(int j = 0; j < oddOrEven[i].length; j++)
{
oddOrEven[i][j] = 1;
}
System.out.print(oddOrEven[i]);
}
}
}
}//end class
Try to replace
if (oddOrEven[i] % 2 == 0)
with
if (i % 2 == 0)

Solve sudoku by backtracking (java)

public static int[][] solve(int[][] input){
for (int i = 0; i < 9*9; i++){
if(input[i / 9][i % 9] != 0){
continue;
}
for (int j = 1; j <= 9; j++){
if(validNumber(input, i / 9, i % 9, j)){
input[i / 9][i % 9] = j;
solve(input);
}
}
}
return input;
}
This method should solve a (solvable) sudoku puzzle via backtracking regardless of the initial situation. It works like this:
Given a sudoku puzzle it iterates from the upper left corner over each row to the lower right corner of the 2D array. When there is already a number, it gets skipped. When there is a zero (empty field) it calculates possible values via the validNumber method. The first valid number (from 1 to 9) is put in the field and the method goes to the next field.
In this algorithm the method does not now whether or not a valid number will eventually render the puzzle unsolvable.
I want to alter it like this:
At the end, when the method finishes iterating through the whole 2d array, every entry of the array gets tested if it is a zero or not.
If there is even one zero the whole algorithm must go to the place where the very first "valid" number was put in. Now, the next "valid" number is put in and so on until there are no zeroes at the end of the algorithm.
I have some troubles implementing this thought. It seems to me there must be an other for loop somewhere, or something like a goto statement, but I don't know where to put it.
Any advice?
I implemented a Sudoku solver once before. It was a bit more complicated than what you had, but solved the game in a blink. :)
What you are attempting to do is solve Sudoku by "Brute Force" and using (tail) recursion. That means you are attempting to solve the board by iterating over all 981 possible combinations. 9 to the power of 81 is... well it's a big number. And so your approach will take eternity, but you'll run out of stack space from the tail recursion much sooner.
When I implemented Sudoko, it was more straight up. It kept a 9x9 array of "items", where each item was the value in the square, and an array of 9 booleans representing candidates (true == viable, false == eliminated). And then it just did a non-recursive loop of solving the board.
The main loop would start with the simple process of finding squares with only 1 remaining candidate. Then the next step would do simple candidate elimination based on values already assigned. Then it would work its way into more complicated elimination techniques such as X-Wing.
Your algorithm does not actually backtrack. It moves forward if it can, but it never moves backwards when it realizes it's stuck in a corner. This is because it never returns any knowledge up the stack, and it never resets squares. Unless you get really lucky, your code will get the game board into a cornered state, and then print out that cornered state. To backtrack, you need to reset the last square you set (the one that got you cornered) to zero, so your algorithm will know to keep trying other things.
For understanding backtracking, I highly recommend a book called The Algorithm Design Manual by Steven Skiena. I read it when I was preparing for SWE interviews, and it really improved my knowledge of backtracking, complexity, and graph search. The second half of the book is a catalog of 75 classic algorithmic problems, and Sudoku is one of them! He has an interesting analysis of optimizations you can make to prune the search tree and solve very hard puzzle boards. Below is some code I wrote a long time ago after reading this chapter (probably not that high quality by my current standards, but it works). I just read through it really quickly and added the solveSmart boolean in the solve method which allows you to turn one of those optimizations on or off, which results in a pretty big time savings when solving a "hard" class Sudoku board (one with only 17 squares filled in to start with).
public class Sudoku {
static class RowCol {
int row;
int col;
RowCol(int r, int c) {
row = r;
col = c;
}
}
static int numSquaresFilled;
static int[][] board = new int[9][9];
static void printBoard() {
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
System.out.print(" " + (board[i][j] == 0 ? " " : board[i][j]) + " ");
if (j % 3 == 2 && j < 8)
System.out.print("|");
}
System.out.println();
if (i % 3 == 2 && i < 8)
System.out.println("---------|---------|---------");
}
System.out.println();
}
static boolean isEntireBoardValid() {
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
if (!isBoardValid(i, j)) {
return false;
}
}
}
return true;
}
static boolean isRowValid(int row) {
int[] count = new int[9];
for (int col = 0; col < 9; col++) {
int n = board[row][col] - 1;
if (n == -1)
continue;
count[n]++;
if (count[n] > 1)
return false;
}
return true;
}
static boolean isColValid(int col) {
int[] count = new int[9];
for (int row = 0; row < 9; row++) {
int n = board[row][col] - 1;
if (n == -1)
continue;
count[n]++;
if (count[n] > 1)
return false;
}
return true;
}
static boolean isSquareValid(int row, int col) {
int r = (row / 3) * 3;
int c = (col / 3) * 3;
int[] count = new int[9];
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
int n = board[r + i][c + j] - 1;
if (n == -1)
continue;
count[n]++;
if (count[n] > 1)
return false;
}
}
return true;
}
static boolean isBoardValid(int row, int col) {
return (isRowValid(row) && isColValid(col) && isSquareValid(row, col));
}
static RowCol getOpenSpaceFirstFound() {
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
if (board[i][j] == 0) {
return new RowCol(i, j);
}
}
}
return new RowCol(0, 0);
}
static RowCol getOpenSpaceMostConstrained() {
int r = 0, c = 0, max = 0;
int[] rowCounts = new int[9];
int[] colCounts = new int[9];
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
if (board[i][j] != 0)
rowCounts[i]++;
if (board[j][i] != 0)
colCounts[i]++;
}
}
int[][] squareCounts = new int[3][3];
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
int count = 0;
for (int m = 0; m < 3; m++) {
for (int n = 0; n < 3; n++) {
if (board[(i * 3) + m][(j * 3) + n] != 0)
count++;
}
}
squareCounts[i][j] = count;
}
}
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
if (board[i][j] == 0) {
if (rowCounts[i] > max) {
max = rowCounts[i];
r = i;
c = j;
}
if (colCounts[j] > max) {
max = rowCounts[j];
r = i;
c = j;
}
}
}
}
return new RowCol(r, c);
}
static boolean solve() {
if (81 == numSquaresFilled) {
return true;
}
boolean solveSmart = true;
RowCol rc = solveSmart ? getOpenSpaceMostConstrained() : getOpenSpaceFirstFound();
int r = rc.row;
int c = rc.col;
for (int i = 1; i <= 9; i++) {
numSquaresFilled++;
board[r][c] = i;
if (isBoardValid(r, c)) {
if (solve()) {
return true;
}
}
board[r][c] = 0;
numSquaresFilled--;
}
return false;
}
public static void main(String[] args) {
// initialize board to a HARD puzzle
board[0][7] = 1;
board[0][8] = 2;
board[1][4] = 3;
board[1][5] = 5;
board[2][3] = 6;
board[2][7] = 7;
board[3][0] = 7;
board[3][6] = 3;
board[4][3] = 4;
board[4][6] = 8;
board[5][0] = 1;
board[6][3] = 1;
board[6][4] = 2;
board[7][1] = 8;
board[7][7] = 4;
board[8][1] = 5;
board[8][6] = 6;
numSquaresFilled = 17;
printBoard();
long start = System.currentTimeMillis();
solve();
long end = System.currentTimeMillis();
System.out.println("Solving took " + (end - start) + "ms.\n");
printBoard();
}
}
Eventually validNumber() method will not return any number because there is no possibilities left that means one of the previous choices was incorrect. Just imagine that the algorithm is started with the empty grid (obviously this puzzle is solvable1).
The solution is to keep tree of possible choices and if some choices are incorrect, then just remove them from the tree and use the next available choice (or step back on a higher level of the tree, if there is no choice left in this branch). This method should find a solution if any. (Actually this is how I implemented my sudoku solver some time ago.)
1 IMHO there are 3 different kinds of sudoku:
"true" correct sudoku that has a single unique complete solution;
ambiguous sudoku that has multiple distinct complete solutions, e.g. a puzzle with only 7 different numbers, so it has at least two distinct solutions that differ by swapping 8th and 9th numbers;
incorrect sudoku that has no complete solution, e.g. with a row with two or more occurrences of the same number.
With this definition, a solver algorithm should either:
prove that there is no solution;
return complete solution that satisfies the initial grid.
In the case of a "true" sudoku the result is a "true" solution by definition. In the case of an ambiguous sudoku the result can be different depending on the algorithm. An empty grid is the ultimate example of ambiguous sudoku.

Sudoku debugging issue

I'm working on a program that is supposed to take as input a solved Sudoku Puzzle and return if it is a valid solution or not (true or false).
My code is written and running with a few helper methods.
The isSolution method runs through 4 different things to check if the solution is valid or not.
I've written a valid solution as input that should return true.
When I check each of these 4 elements separately, they return true, when I check them together, they return false (which is wrong)
I've spent hours testing them separately, together and in different combinations.
I've tried with different inputs.
I can't figure out why it's returning false when it should be returning true.
Any help would be amazingly appreciated! Thanks
public static void main(String[] args){
int [][] solvedPuzzle = {
{8,3,5,4,1,6,9,2,7},
{2,9,6,8,5,7,4,3,1},
{4,1,7,2,9,3,6,5,8},
{5,6,9,1,3,4,7,8,2},
{1,2,3,6,7,8,5,4,9},
{7,4,8,5,2,9,1,6,3},
{6,5,2,7,8,1,3,9,4},
{9,8,1,3,4,5,2,7,6},
{3,7,4,9,6,2,8,1,5}
};
System.out.println(isSolution(solvedPuzzle));
}
////// Checks if the input is a valid sudoku solution
/* The solvedPuzzle input is a valid solution, so this method should return true.
* Each of the elements in this method return true when tested individually, but for some reason,
* when I run them all together, the method returns false
*/
public static boolean isSolution(int [][] solvedPuzzle){
//Checks if the rows and columns have 9 ints
if (solvedPuzzle.length != 9 || solvedPuzzle[0].length !=9){
return false;
}
//Checks if every column is made up of unique entries
for (int j = 0; j < 9; j++){
if (uniqueEntries(getColumn(solvedPuzzle, j)) !=true){
System.out.println("HERE!"); //these are just here to try to figure out WHERE I've gone wrong
return false;
}
}
//Checks if every row is made up of unique entries
for (int i = 0; i < 9; i++){
if (uniqueEntries(solvedPuzzle[i]) !=true){
System.out.println("HERE!!!");
return false;
}
}
//Checks if every sub 3x3 grid is made up of unique entries
for (int x = 0; x < 9; x = x+3){
for (int y = 0; y < 9; y = y+3){
if (uniqueEntries(flatten(subGrid(solvedPuzzle, x,y,3))) != true){
System.out.println("HERE22");
return false;
}
}
}
return true;
}
///Below are the helper methods
////// Creates a smaller grid of size m starting at indexI,indexJ (x,y).
public static int [][] subGrid(int [][] original, int indexI, int indexJ, int m){
int [][] subGrid = new int [m][m];
for (int i = indexI; i < indexI+m ; i++){
for (int j = indexJ; j < indexJ+m ; j++){
subGrid [i - indexI][j - indexJ] = original[i][j];
}
}
return subGrid;
}
////// Sorts the intergers in a 1D array in asceding order
public static int [] sort(int [] originalArray){
int temp;
for(int i = 0; i < originalArray.length - 1; i++){
for(int j = 0; j < originalArray.length - 1; j++){
if(originalArray[j] > originalArray[j+1]){
temp = originalArray[j];
originalArray[j] = originalArray[j+1];
originalArray[j+1] = temp;
}
}
}
return(originalArray);
}
////// Checks if the intergers in a 1D array are all unique by first using the sort method
public static boolean uniqueEntries(int [] original){
int [] sorted = sort(original);
for (int i = 0; i < original.length-1; i++){
if (sorted[i+1] == sorted[i]) {
return false;
}
}
return true;
}
////// Takes a 2D array where each subarray is of the same size and creates a 1D array made up of the i-th element of each sub array
public static int [] getColumn(int [][] original, int indexJ){
int [] column = new int[original[0].length];
for (int i = 0; i < original[0].length; i++){
column[i] = original[i][indexJ];
}
return column;
}
////// takes a 2D array and flattens it into a 1D array
public static int [] flatten(int [][] original){
int [] flattenedArray = new int[original.length*original[0].length];
int counter = 0;
for (int i = 0; i < original.length; i++){
for(int j = 0; j < original.length; j++) {
flattenedArray[counter] = original[i][j];
counter++;
}
}
return flattenedArray;
}
if you check your puzzle before and after running //Checks if every row is made up of unique entries you will see that you are actually changing the original format of your puzzle. So the next test is not going to run over the original puzzle but a sorted one! If you add a simple loop before and after the second test you will understand what I am talking about
for (int i = 0; i < 9; i++){ //ADD THAT LOOP BEFORE AND AFTER THE TEST
for (int j = 0; j<9; j++) {
System.out.print(solvedPuzzle[i][j]);
}
System.out.println();
}
System.out.println('\n');
//Checks if every row is made up of unique entries
for (int i = 0; i < 9; i++){
if (uniqueEntries(solvedPuzzle[i]) !=true){
System.out.println("HERE!!!");
return false;
}
}
for (int i = 0; i < 9; i++){
for (int j = 0; j<9; j++) {
System.out.print(solvedPuzzle[i][j]);
}
System.out.println();
}
the code above will help you visualise what the puzzle looks before and after the test. A test should never change the format/contents/attributes of anything tested. The results of the above will be:
835416927
296857431
417293658
569134782
123678549
748529163
652781394
981345276
374962815
123456789
123456789
123456789
123456789
123456789
123456789
123456789
123456789
123456789
As you can see the original puzzle is not "original" anymore.
So as I told you on my comment, flipping the tests around will NOT actually fix the problem. Instead the bug will still be produced; but without any tests to run after it is not going to affect the CURRENT code.
Hope that helps
EDIT: I don't know if I will be online later on; so in the case that even that hint didn't help you find the bug so I am also going to give you the solution :p
The issue is that you are using the sort() method that doesn't ONLY return the array sorted BUT ALSO actually sorts the input array! SO in order to avoid that you simply need to pass in a copy of the array instead of the array itself whenever you are calling the sort method:
////// Checks if the intergers in a 1D array are all unique by first using the sort method
public static boolean uniqueEntries(int [] original){
int [] sorted = sort(original.clone()); //pass in a copy of the array
for (int i = 0; i < original.length-1; i++){
if (sorted[i+1] == sorted[i]) {
return false;
}
}
return true;
}

Categories

Resources