Sudoku Checker 2d array Java - java

So im having a bit of problem with my code.. It's suppose to cross check rows and columns for same integers.
this is what i have so far.. but when i run it, it only seems to check the first integer only. (for example the first line of the sudoku board reads. 1 2 2 2 2 2 2 2 2 2) it wont detect the obvious multiple 2's but if i change the input to 1 1 2 2 2 2 2 2 2 the error will come up of multiple 1's in this case. the multiple any suggestions to tweak my loops to make it go through the columns?
public static void validate(final int[][] sudokuBoard) {
int width = sudokuBoard[0].length;
int depth = sudokuBoard.length;
for (int i = 0; i < width; i++) {
int j = i;
int reference = sudokuBoard[i][j];
while (true) {
if ((j >= width) || (j >= depth)) {
break;
}
else if (i == j){
// do nothing
}
else if (j < width) {
int current = sudokuBoard[i][j];
if (current == reference) {
System.out.print("Invalid entry found (width)" + "\n");
System.out.print(current + "\n");
// invalid entry found do something
}
} else if (j < depth) {
// note reversed indexes
int current = sudokuBoard[j][i];
if (current == reference) {
System.out.print("Invalid entry found (depth)" + "\n");
System.out.print(current + "\n");
// invalid entry found do something
}
}
j++;
}

Your code is more complex than it should be. Why put everything in one single function when you could split in several different functions?
public static void Validate(final int[][] sudokuBoard)
{
int width = sudokuBoard[0].length;
int depth = sudokuBoard.length;
for(int i = 0; i < width; i++)
if(!IsValidRow(sudokuBoard, i, width))
{
//Do something - The row has repetitions
}
for(int j = 0; j < height; j++)
if(!IsValidColumn(sudokuBoard, j, width))
{
//Do something - The columns has repetitions
}
}
static bool IsValidRow(int[][] sudokuBoard, int referenceRow, int width)
{
//Compare each value in the row to each other
for(int i = 0; i < width; i++)
{
for(int j = i + 1; j < width; j++)
{
if(sudokuBoard[referenceRow][i] == sudokuBoard[referenceRow][j])
return false
}
}
return true;
}
static bool IsValidColumn(int[][] sudokuBoard, int referenceColumn, int height)
{
//Compare each value in the column to each other
for(int i = 0; i < height; i++)
{
for(int j = i + 1; j < height; j++)
{
if(sudokuBoard[i][referenceColumn] == sudokuBoard[j][referenceColumn])
return false
}
}
return true;
}
That way, your code is much more easily maintainable/readable. This code above hasn't been tested, but it should be about right.
I suggest debugging this code step by step to really understand what's going on, if that's not clear for you.

Given the constraints of sudoku (a row of n cells must contain the numbers 1-n only) you don't need an order n^2 search (per row or column), you can do it order n by keeping a bit array indicating which numbers you've seen. Here's the pseudo-code for checking rows, do the same for columns:
for i in 0 to depth-1 // rows
boolean seen[] = new seen[width];
for j in 0 to width-1 // columns
if seen[board[i][j]-1] == true
duplicate number
else
seen[board[i][j]-1] = true

I would break the functionality into smaller boolean checks. This way, you can validate row by row, column by column, and square by square. For instance
private boolean isValidRow(int[] row) {
// Code here to check for valid row (ie, check for duplicate numbers)
}
private boolean isValidColumn(int[] column) {
// Code here to check for valid column
}
private boolean isValidSquare(int[][] square) {
// Code here to check for valid square
}
Note that rows and columns only need to be passed a 1 dimensional array. Squares are a 2 dimensional array as you need to check a 3x3 area. You can also treat these methods as static as their functionality is independent of the Sudoku board instance.
Edit: A suggestion on row/column/square validation is to use a HashSet. Sets can only have 1 element of a certain value, so you can add elements and look for a failure. For example:
HashSet<Integer> hs = new HashSet<Integer>();
for(int i = 0; i < 9; i++) {
if(!hs.add(integerArray[i])) // HashSet.add returns 'false' if the add fails
// (ie, if the element exists)
return false;
}
return true;

Related

Is there something wrong with my Magic Square Code?

A brief explanation: With the code below it will make a randomly generated Square and some code below would make sure that it was a Magic Square, in which the sum of the elements in each row, column, and the two diagonals are the same value.
My teacher said at maximum it should take three minutes to generate a magic square. So all I ask is there anything that can be done to improve or fix this code, please?
import java.util.ArrayList;
import java.util.Random;
class Main {
public static void main(String[] args) {
int size = 9;
int N = 3;
boolean result = true;
ArrayList<Integer> list = new ArrayList<Integer>(size);
int[][] mat = new int[N][N];
while (result) {
for (int i = 1; i <= size; i++) {
list.add(i);
}
Random rand = new Random();
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
int index = rand.nextInt(list.size());
System.out.print(list.remove(index)+" ");
}
System.out.println();
}
System.out.println();
// Checking process
// sumd1 and sumd2 are the sum of the two diagonals
int sumd1 = 0, sumd2 = 0;
for (int i = 0; i < N; i++) {
// (i, i) is the diagonal from top-left -> bottom-right
// (i, N - i - 1) is the diagonal from top-right -> bottom-left
sumd1 += mat[i][i];
sumd2 += mat[i][N - 1 - i];
}
// if the two diagonal sums are unequal then it is not a magic square
if (sumd1 != sumd2)
result = false;
// calculating sums of Rows and columns and checking if they are equal to each other,as well as equal to diagonal sum or not
for (int i = 0; i < N; i++) {
int rowSum = 0, colSum = 0;
for (int j = 0; j < N; j++) {
rowSum += mat[i][j];
colSum += mat[j][i];
}
if (rowSum != colSum || colSum != sumd1)
result=false;
}
result = true;
}
}
}
Trying with random numbers to coincidentally find a solution is deadly slow.
If you have the numbers 1 to 9, its entire sum 1+2+3+...+8+9 is 9*(1+9)/2 = 45.
As you have 3 rows and 3 colums, a row and column must sum upto 45/3 = 15.
Now that should restrict the number of possibilities.
So you must build in some intelligence in the code. Avoid random numbers as they do not even guarantee you'll find a solution in hundred years.
If you already treated recursion, that would be the easiest way to try all possibly valid combinations.
If you already treated Set, a BitSet maybe might be useful for a row, column or diagonal.
If you find it hard to code walking through all possibilities, you might hold the 2 dimensional matrix in a 1 dimensional array int[N*N], and have N (rows) + N (columns) + 2 (diagonals) arrays of N indices.
And of course I will not spoil your fun and satisfaction finding a smart solution.
Work it out on paper first.

Cant get required output from loop

I am trying to get a certain output pattern from the array but can't seem to get what I'm looking for and now sure why. Link is the desired output. Sorry if formatting is not good. Array size is inputted by the user.
public class A3_Q2 {
int [][] pattern2 = new int[arraySize][arraySize];
number = 1;
int i;
int j;
int newNumber = arraySize-1;
for (i = 0; i < arraySize; i++)
{
if (i == 0)
{
for (j = 0; j < arraySize; j++)
{
pattern2[i][j] = number;
System.out.printf("%3d", pattern2[i][j]);
number++;
}
}
else
{
for(j = 0; j < i; j++)
{
pattern2[i][j] = number + newNumber;
System.out.printf("%3d", pattern2[i][j]);
newNumber++;
}
newNumber = arraySize-1;
while(j < arraySize)
{
pattern2[i][j] = number;
System.out.printf("%3d", pattern2[i][j]);
number++;
j++;
}
}
System.out.println("");
}
Desired Output:
1 2 3 4 5
10 6 7 8 9
14 15 11 12 13
18 19 20 16 17
22 23 24 25 21
This image shows the out-of-sequence cells highlighted:
There is no need to separately handle specific rows. Value should be calculated with formula that can be applied universally using modulo operator.
This should do the trick:
for (i = 0; i < arraySize; i++) {
for (j = 0; j < arraySize; j++) {
int value = i * arraySize + (j - i + arraySize + 1) % arraySize;
if (value % arraySize == 0) {
value += arraySize;
}
pattern2[i][j] = value;
System.out.printf("%3d", pattern2[i][j]);
}
System.out.println("");
}
As I suggested in my comment, you're trying to do too many things at once, and that makes the logic (and logic errors) very hard to see.
Breaking each part into its own method can make things much easier.
All those loops and conditionals hid that there were only three tasks required:
Create grid.
Fill grid.
Print grid.
public static void main(final String[] args) {
final int arraySize = 5;
int[][] pattern = new int[arraySize][arraySize];
fillPattern(pattern);
printPattern(pattern);
return;
}
That weird non-sequential output means that "fill the grid" is actually too big a task for one method.
Filling a grid normally requires filling each row.
This grid also requires rotating each row's values one to the right...
one more than the previous row, that is.
That has nothing to do with filling a grid with rows, so it's some other method's problem.
(I could have foisted rowStartValue off onto the other method too, come to think of it.)
private static void fillPattern(int[][] pattern) {
final int rowCount = pattern.length;
for (int rowOffset = 0; rowOffset < rowCount; rowOffset++) {
final int[] row = pattern[rowOffset];
// Numbers in grid start at 1, not 0.
final int rowStartValue = rowOffset * row.length + 1;
fillRow(row, rowOffset, rowStartValue);
}
return;
}
fillRow has to produce values and stuff them into row.
Producing the values is easy;
the only tricky part is deciding where to put them.
Picking the destination required only two operators, so I did it here.
Since no one wants to figure out what row[some / weird * math % here] means, I gave the calculation a name by saving it as the rowIndex variable.
If it had been any more complex, I would have moved the work to a rowIndex(...) method instead.
private static void fillRow(int[] row, final int offset, final int value) {
for (int addend = 0; addend < row.length; addend++) {
final int rowIndex = (offset + addend) % row.length;
row[rowIndex] = value + addend;
}
return;
}
Now that the grid is full, printing it is easy:
private static void printPattern(final int[][] pattern) {
for (final int[] row : pattern) {
for (final int element : row) {
System.out.printf("%3d", element);
}
System.out.println();
}
return;
}
Replacing variables like i and j with row and offset helped a lot, too.

how to check if a number I try to add already exist in the column and row?(2d arrays )

int [][]a=new int[9][9] //creates a "square" with 81 0's
How do I go about checking if a input (when filling out the array) already exist in the column or row?
For example, for the row 0, how can I make sure I don't get the number 9 two times (for instance, once on row 0, column 0 and second on row 0 column 1)? I can't seem to figure out how to go about this (all I know is that I'll probably need two for loops? and a if statement. I'm not sure how to go about the if statement tho).
public static void main(String[] args)
{
int[][] a = new int[9][9];
boolean areThereDuplicates;
int input = 9; // or any input of course
int row = 0; // or any row
int column = 0;// or any column
areThereDuplicates = checkDuplicates(input, row, column, a);
if (!areThereDuplicates) // if there are no duplicates, input value
a[row][column] = input;
}
public static boolean checkDuplicates(int numChecked, int row, int column, int[][] arr)
{
// checks row
for (int j = 0; j < arr[row].length; j++)
{
if (arr[row][j] == numChecked)
return true;
}
// checks column
for (int k = 0; k < arr.length; k++)
{
if (arr[k][column] == numChecked)
return true;
}
return false;
}
One important thing I wanted to point out is the for loop that checks the column. arr.length does not return 81; rather it returns 9. arr[row].length also returns how many columns there are in the specified row.
Quick draft, not tested but should work:
a[x][y] = newValue; // e.g. 9
return checkDuplicates(x, y, newValue); // returns true if a duplicate is found
public boolean checkDuplicates(int x, int y, int newValue) {
for (int i=0; i<9; i++) {
if (i!=x && a[i][y]==newValue)
return true;
}
for (int i=0; i<9; i++) {
if (i!=y && a[x][i]==newValue)
return true;
}
return false;
}

Randomize tictactoe

A while I did an assignment creating a tictactoe program through eclipse. It works well enough, with me clicking empty boxes to place O's, and the program inputting X's afterward. However, I was using a pretty simple code for the placement of X's:
public int putX(){
for(int i=0; i<3;i++)
for(int j = 0;j<3;j++) {
if(position[i][j]==' ') {
position[i][j]='X';
return 0;
}
}
return -1; //some error occurred. This is odd. No cells were free.
}
Because of this, the X's are just placed in the row of each column, going down until the next column. Can someone show me a simple way to randomize this program?
What we want to do is generate an array of all the possible points, and pick one of those points at random. We use a for loop to iterate through all points in the 3x3 array, and add the valid ones to our temporary array, and then we choose a random index, and place an X there.
String[] list = new String[9]; // maximum 9 points
int size = 0;
for(int i = 0; i < 3; i++) {
for(int j = 0; j < 3; j++) {
if(position[i][j] == ' ') {
list[size] = "" + i + j;
size++;
}
}
}
int index = (int) (Math.random() * (size+1));
position[Integer.parseInt(list[index].charAt(0))][Integer.parseInt(list[index].charAt(1))] = 'X';
Alternatively, instead of storing the x,y coordinates of the point in a String we could store them in a java.awt.Point like so:
Point[] list = new Point[9]; // maximum 9 points
int size = 0;
for(int i = 0; i < 3; i++) {
for(int j = 0; j < 3; j++) {
if(position[i][j] == ' ') {
list[size] = new Point(i, j);
size++;
}
}
}
int index = (int) (Math.random() * (size+1));
position[list[index].getX()][list[index].getY()] = 'X';
As you can see, the code for using a Point is practically the same, but instead of parsing the coordinates out of the String, we can just access them directly from the Class.
You should also check to make sure that there are some elements left, by checking if size is still 0 after the for loop. If so, you should probably return -1 (what your existing code does). Otherwise, at the end of the whole code return 0.

Insert number into ordered arrayList

I have an interesting problem on how to insert any number into an ordered ArrayList. Lets say the user enters [12,34,37,60,89]; the method addListElement() should traverse the array to find the index where the new element will go.
The user enters the number 50, the new array should be [12,34,37,50,60,89]. I used a for loop to traverse the ArrayList, but I'm not sure about my if() statement.
public void addListElement() {
System.out.println("Add number to arrayList");
Scanner scan = new Scanner(System.in);
int number = scan.nextInt();
int loc = 0;
for (int i = 0; i < aryList.size(); i++) {
if (number > 0 && i < loc) {
loc++;
}
}
aryList.add(loc, number);
System.out.println(aryList.toString());
}
Try this:
int position = Collections.binarySearch(aryList, number);
aryList.add(position < 0 ? -position - 1 : position, number);
Edit thanks for pointing out the old code crashes if the number is already present
You would want to make use of the List<E>.add(int idx, E element) method. The idea behind inserting the element in order is that, for some array a, element ai, and for some integer n:
ai <= n <= ai+1 , 0 < i < len(a)-1.
// edge case: Size one list, number coming in is smaller.
if(aryList.size() == 1 && aryList.get(0) >= number) {
aryList.add(0, number);
} else {
for(int i = 0; i < aryList.size()-1; i++) {
if(number >= aryList.get(i) && number <= aryList.get(i+1)) {
aryList.add(i, number);
}
}
// number is the largest seen; add it to the end.
aryList.add(number);
}
this should work too. Since the list is already in ascending order, when ever you find the number in list bigger than the current one, insert the new number one index before this number in arrayList..
for (int i = 0; i < aryList.size(); i++) {
if (aryList.get(i)>number) {
break;
}
loc++;
}
Increment the index as long as there are more elements and the number is less than the current element. You will also have to check that i != list.size() when finished for cases when the user gives a number that is larger than any number currently in the list.
while (number >= 0 && number <= list.get(i) && i < list.size()) {
i++;
}
list.add(i, number);
int loc = 0;
int prevNumber = aryList.get(0);
for(int i = 1; i<aryList.size(); i++){
if(number > prevNumber && number <= aryList.get(i)){
return i;
}
prevNumber = aryList.get(i);
}
I suppose your Elements are ordered by an ascendant order
public void insert(int x){
// loop through all elements
for (int i = 0; i < arrayList.size(); i++) {
// if the element you are looking at is smaller than x,
// go to the next element
if (arrayList.get(i) < x) continue;
// if the element equals x, return, because we don't add duplicates
if (arrayList.get(i) == x) return;
// otherwise, we have found the location to add x
arrayList.add(i, x);
return;
}
// we looked through all of the elements, and they were all
// smaller than x, so we add x to the end of the list
arrayList.add(x);
}
If you want to insert duplicates in your ArrayList just remove the line of code
if (arrayList.get(i) == x) return;

Categories