Adding 2 differently sized 2d arrays together - java

I am trying to add two differently sized matrices together. For example, the resultant matrix should be matOne[0][0]+matTwo[0][0]; however, I am having trouble taking into account their different sizes (if there's a missing value, it should be assumed it's a 0).
Here's my code:
int[][] go(int[][] matOne, int[][] matTwo)
{
int size= Math.max(matOne.length, matTwo.length);
int[][] matThree= new int [size][];
int c;
for (int i=0; i<size; i++) {
c= Math.max(matOne[i].length, matTwo[i].length);
for (int j = 0; j < c; j++) {
if (matOne[j].length > i) {
matThree[i][j] += matOne[i][j];
}
if (matTwo[j].length > i) {
matThree[i][j] += matTwo[i][j];
}
}
}
return matOne;
}

I see the following bugs in the code:
You never allocate the inner arrays. After you get size, you correctly create the outer array. After you get c, you forget to create the inner array for that row.
Right inside the i loop, one of matOne[i] and matTwo[i] is likely to fail eventually, whichever one is shorter.
Variable i iterates over rows, and variable j iterates over columns in a row, which means that the [i][j] in the += statements are correct, but that the matOne[j].length > i should have been matOne[i].length > j. Same for matTwo.
You return the wrong array.
Here is the fixed code, using better variable names:
static int[][] go(int[][] matOne, int[][] matTwo) {
int rows = Math.max(matOne.length, matTwo.length);
int[][] matThree = new int [rows][];
for (int r = 0; r < rows; r++) {
int cells = Math.max((matOne.length > r ? matOne[r].length : 0),
(matTwo.length > r ? matTwo[r].length : 0));
matThree[r] = new int[cells];
for (int c = 0; c < cells; c++) {
if (matOne.length > r && matOne[r].length > c) {
matThree[r][c] += matOne[r][c];
}
if (matTwo.length > r && matTwo[r].length > c) {
matThree[r][c] += matTwo[r][c];
}
}
}
return matThree;
}
Test
public static void main(String[] args) {
int[][] matOne = { { 1, 2, 3 }, { 4, 5, 6 } };
int[][] matTwo = { { 7, 8 }, { 9, 10 }, { 11, 12 } };
int[][] matThree = go(matOne, matTwo);
print(matOne);
System.out.println("+");
print(matTwo);
System.out.println("=");
print(matThree);
}
static void print(int[][] mat) {
for (int[] row : mat) {
for (int cell : row)
System.out.printf(" %2d", cell);
System.out.println();
}
}
Output
1 2 3
4 5 6
+
7 8
9 10
11 12
=
8 10 3
13 15 6
11 12
If you don't want the result to be a jagged array, i.e. you want the result to be a 2D rectangular matrix, change the code as follows:
static int[][] go(int[][] matOne, int[][] matTwo) {
int rows = Math.max(matOne.length, matTwo.length);
int cols = 0;
for (int[] row : matOne)
cols = Math.max(cols, row.length);
for (int[] row : matTwo)
cols = Math.max(cols, row.length);
int[][] matThree = new int [rows][cols];
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
if (matOne.length > r && matOne[r].length > c) {
matThree[r][c] += matOne[r][c];
}
if (matTwo.length > r && matTwo[r].length > c) {
matThree[r][c] += matTwo[r][c];
}
}
}
return matThree;
}
Output
1 2 3
4 5 6
+
7 8
9 10
11 12
=
8 10 3
13 15 6
11 12 0

Just before the inner loop; replace current calculation of 'c' and allocate a row for matThree.
c = 0;
if (i < matOne.length)
c = matOne[i].length;
if (i < matTwo.length && matTwo[i].length > c)
c = matTwo[i].length;
matThree[i] = new int[c];
The code inside the inner loop should be:
int elem1 = 0, elem2 = 0;
if (i < matOne.length && j < matOne[i].length)
elem1 = matOne[i][j];
if (i < matTwo.length && j < matTwo[i].length)
elem2 = matTwo[i][j];
matThree[i][j] = elem1 + elem2;
Firstly, it's necessary to allocate storage for the current row of matThree.
Secondly, you need to check that both row and column are within bounds for each matrix. For my taste it's clearest to explicitly extract the values, defaulting to zero, thus the variables elem1 and elem2.

Related

Print Pascal's Triangle using recursion

I'm trying to develop a program that prints out Pascal's Triangle using recursion. Here are my codes:
public class PascalTriangle {
public static int[] computePT(int k) {
int[] pt = new int[k + 1];
if (k == 0) {
pt[0] = 1;
return pt;
} else {
int[] ppt = computePT(k - 1);
pt[0] = pt[k] = 1;
for (int i = 1; i < ppt.length; i++) {
pt[i] = ppt[i - 1] + ppt[i];
}
}
return pt;
}
}
public class PascalTriangleDriver {
public static void main(String args[]) {
int k = 10;
int arr[] = PascalTriangle.computePT(k);
for (int i = 0; i < arr.length; i++)
System.out.print(arr[i] + " ");
System.out.println();
}
}
The code runs perfectly, however my issue is that I want to modify my PascalTriangle code (not the PascalTriangleDriver code) such that when k=10, for example, it prints out:
1 9 36 84 126 126 84 36 9 1
instead of:
1 10 45 120 210 252 210 120 45 10 1
You seem to have made an off-by-1 error. One simple way to solve this is to write another method that calls your original method with k-1:
// this is your original method, just renamed:
private static int[] computePTImpl(int k) {
int[] pt = new int[k + 1];
if (k == 0) {
pt[0] = 1;
return pt;
} else {
int[] ppt = computePT(k - 1);
pt[0] = pt[k] = 1;
for (int i = 1; i < ppt.length; i++) {
pt[i] = ppt[i - 1] + ppt[i];
}
}
return pt;
}
// you will call this method:
public static int[] computePT(int k) {
return computePT(k - 1);
}
Alternatively, you can actually fix your code by replacing ks with k-1s:
public static int[] computePT(int k) {
int[] pt = new int[k]; // note the change
if (k == 1) { // note the change
pt[0] = 1;
return pt;
} else {
int[] ppt = computePT(k - 1);
pt[0] = pt[k - 1] = 1; // note the change
for (int i = 1; i < ppt.length; i++) {
pt[i] = ppt[i - 1] + ppt[i];
}
}
return pt;
}
Note that we don't change the recursive call because if we did, we would be saying that the k-th row of Pascal's triangle depends on the k-2-th row, which is not true.
You can iteratively populate an array of binomial coefficients as follows: the first row and column are filled with ones, and all other elements are equal to the sum of the previous element in the row and column.
T[i][j] = T[i][j-1] + T[i-1][j];
You can create two methods: one returns a 2d array containing a triangle, and the second returns the base of that triangle. It is more useful for clarity.
Output:
Triangle:
1 1 1 1 1 1 1 1 1 1
1 2 3 4 5 6 7 8 9
1 3 6 10 15 21 28 36
1 4 10 20 35 56 84
1 5 15 35 70 126
1 6 21 56 126
1 7 28 84
1 8 36
1 9
1
Base:
[1, 9, 36, 84, 126, 126, 84, 36, 9, 1]
Code:
public static void main(String[] args) {
int n = 10;
System.out.println("Triangle:");
int[][] arr = binomialTriangle(n);
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr[i].length; j++)
if (arr[i][j] > 0)
System.out.printf("%2d ", arr[i][j]);
System.out.println();
}
int[] base = binomial(arr);
System.out.println("Base:");
System.out.println(Arrays.toString(base));
}
public static int[][] binomialTriangle(int n) {
// an array of 'n' rows
int[][] arr = new int[n][];
// iterate over the rows of the array
for (int i = 0; i < n; i++) {
// a row of 'n-i' elements
arr[i] = new int[n - i];
// iterate over the elements of the row
for (int j = 0; j < n - i; j++) {
if (i == 0 || j == 0) {
// elements of the first row
// and column are equal to one
arr[i][j] = 1;
} else {
// all other elements are the sum of the
// previous element in the row and column
arr[i][j] = arr[i][j - 1] + arr[i - 1][j];
}
}
}
return arr;
}
public static int[] binomial(int[][] arr) {
int[] base = new int[arr.length];
for (int i = 0; i < arr.length; i++) {
// the last element in the row
base[i] = arr[i][arr[i].length - 1];
}
return base;
}
See also: Finding trinomial coefficients using dynamic programming

Fill a Matrix with Random Number with no repeat vertically or horizontally

This is more of a logical question . Problem IS:
I need to fill a Matrix with number (1-9) In such a way so that :
No number should repeat in row
No number should repeat in column
Matrix can be from 3X3 to 8X8
Matrix should contain Random numbers not in some particular order
I am not good at putting logic what i have tried is below :
public class RandMatrix {
static int max=8;
static ArrayList<Integer> numbers=new ArrayList<>();
static int[][] arr=new int[max][max];
public static void main(String[] a){
// To fill number
for (int i = 1; i <=9; i++) {
numbers.add(i);
}
// Shuffle number
Collections.shuffle(numbers);
call();
}
public static void call(){
for (int i = 0; i < max; i++) {
for (int j = 0; j <max ; j++) {
for (int k = 0; k <max ; k++) {
int num=numbers.get(k);
if(!isExist(num,i,j)){
arr[i][j]=num;
break;
}
}
}
Collections.shuffle(numbers);
}
}
private static boolean isExist(int num,int row, int col){
for (int i = row; i >=0; i--) {
if(arr[i][col]==num){
return true;
}
}
for (int j = col; j >=0; j--) {
if(arr[row][j]==num){
return true;
}
}
return false;
}
}
When i print the 2-d array i see in some places there is still 0 as value . Seems like my code breaks. at some point there is no random number left which can be filled. Output is something like :
I know my algo is not right i just can not find a way to make it done .
Can i get some help on this.
I've saved and modified some the code a while ago so as to use if I need another time. I think it's for you ;)
import java.util.Arrays;
import java.util.Random;
class Test {
public static void main(String[] args){
int size = 9;
int[][] matrix= new int[size][];
matrix[0] = MatrixOps.createOrderedArray(size, 1);
for(int x=0; x < size; x++) {
matrix[x] = MatrixOps.createOrderedArray(size, 1);
do {
MatrixOps.shuffle(matrix[x]);
} while(! MatrixOps.compare2DArray(matrix[x], matrix, 0, x));
}
MatrixOps.print(matrix);
}
}
class MatrixOps {
public static void shuffle(int[] arr){
Random random = new Random();
for(int x = 0; x < arr.length; x++)
swap(arr, x, random.nextInt(arr.length));
}
public static int[] createOrderedArray(int size, int startValue) {
int[] num = new int[size];
for (int x = 0; x < num.length; x++)
num[x] = x + startValue;
return num;
}
public static boolean compare2DArray(int[] arr1, int[][] arr2, int begin, int end) {
for (int x = begin; x < end; x++)
if (!compareArray(arr1, arr2[x]))
return false;
return true;
}
// https://stackoverflow.com/questions/19648240/java-best-way-to-print-2d-array/41533179#41533179
public static void print(int[][] array) {
for (int[] x: array) {
for (int y: x) {
System.out.print(y + " ");
}
System.out.println();
}
}
private static boolean compareArray(int[] arr1, int[] arr2){
if(arr1.length != arr2.length)
return false;
for(int x=0; x<arr1.length; x++)
if(arr1[x] == arr2[x])
return false;
return true;
}
private static void swap(int[] arr, int a, int b){
int temp = arr[a];
arr[a] = arr[b];
arr[b] = temp;
}
}
Example output:
5 1 7 2 3 8 9 4 6
4 3 1 5 7 9 2 6 8
9 7 3 8 6 2 4 5 1
6 8 4 3 5 7 1 9 2
1 5 8 9 2 6 7 3 4
7 9 2 6 4 1 5 8 3
8 6 9 4 1 5 3 2 7
3 2 6 7 9 4 8 1 5
2 4 5 1 8 3 6 7 9
Define the following matrix during startup:
1 2 3 4 5 6 7 8 9
2 3 4 5 6 7 8 9 1
3 4 5 6 7 8 9 1 2
4 5 6 7 8 9 1 2 3
5 6 7 8 9 1 2 3 4
6 7 8 9 1 2 3 4 5
7 8 9 1 2 3 4 5 6
8 9 1 2 3 4 5 6 7
9 1 2 3 4 5 6 7 8
When you need to create a n X n matrix do the following:
Randomly pick N numbers between 0-8 (without repeats) for row numbers ->R
Randomly pick N numbers between 0-8 (without repeats) for column numbers ->C
The elements of the final matrix will be M[x][y] = O[R[x]][C[y]]
The only problem is that the result is still not totally random. (It cannot generate ALL of the possible solutions.) Although the randomness is mentioned only in the title but not in the 3 requirements...
I think the best approach is to use a randomized backtracking algorithm.
The elements of the matrix are filled, one after the other. For each matrix element, we first enumerate all the remaining integers which can be used (based on the previous elements). Then each of them is tried in a random order untill the first solution is found.
public static void main(String[] args) {
int[][] matrix = getMatrix(7, 0L);
if (matrix != null) {
for (int row = 0; row < 7; ++row) {
for (int column = 0; column < 7; ++column) {
System.out.print(matrix[row][column]);
}
System.out.println();
}
}
}
public static int[][] getMatrix(int size, long seed) {
int[][] matrix = new int[size][size];
Random random = new Random(seed);
if (!backtrack(matrix, size, 0, random))
return null;
return matrix;
}
// returns true when the backtracking could succesfully fill the matrix
private static boolean backtrack(int[][] matrix, int size, int index, Random random) {
if (index == size * size) {
// all elements are filled without conflict
return true;
} else {
// find the row and column of the next element which need to be filled
int column = index % size;
int row = index / size;
// an array which indicates whether the numbers in range [1 - 9] can be used
// canUse[x] encodes whether number (x+1) can be used
boolean[] canUse = new boolean[9];
Arrays.fill(canUse, true);
// check the previous rows and column elements
for (int c = 0; c < column; ++c)
canUse[matrix[row][c] - 1] = false;
for (int r = 0; r < row; ++r)
canUse[matrix[r][column] - 1] = false;
// generate the list of possible entries
List<Integer> possibilities = new ArrayList<Integer>();
for (int i = 1; i <= 9; ++i)
if (canUse[i - 1])
possibilities.add(i);
// backtrack if there are no possible entries
if (possibilities.isEmpty())
return false;
// shuffle the list (to randomly fill the matrix)
Collections.shuffle(possibilities, random);
// enter the number
for (int possiblity : possibilities) {
matrix[row][column] = possiblity;
if (backtrack(matrix, size, index + 1, random))
return true;
}
return false;
}
}
Output:
4139562
1896375
2613857
9357124
6245931
3482619
8761493
Giving it a wild shot, not writing code. But thinking out:
How about start filling numbers column-wise, such that
mat[0][0]=1
mat[1][0]=2
...
mat[8][0]=9
Then when you starting filling the next column, do like:
mat[1][1]=1
mat[2][1]=2
...
mat[8][1]=8
mat[0][1]=9
and so on.
So its precisely filling the numbers sequentially and diagonally.
Using purely randomization to fill the matrix you will need to redo the last part of the result if you reach a dead end.
public static void call(){
int repeats = 0;
for (int i = 0; i < max; i++) {
for (int j = 0; j <max ; j++) {
for (int k = 0; k <max ; k++) {
int num=numbers.get(k);
if(!isExist(num,i,j)){
arr[i][j]=num;
break;
}
}
}
if(containsZero(arr[i]){
i--;
repeats++;
if(repeats > 1000){
i = 0;
repeats = 0;
}
}
Collections.shuffle(numbers);
}
}
private static boolean containsZero(int[] array){
for(int i = 0; i < array.length; i++){
if(array[i] == 0){
return true;
}
}
return false;
}
In some cases changing the last row isn't enough to guarantee that the matrix will be filled. That is why I added a counter which will reset the whole matrix if no solution can be found by changing the last row.

Java- Addition of two valus of a 2d Array

I do a matrix and I want to change the values of the original value, by adding the value of the position where you are and the value of the right sight of it. For example the new value of the position [0][0] should be [0][0](original value)+[0][1]. And when there is no value it should be just added 0. But when I do this I get this error ArrayIndexOutOfBoundsException. So does anybody know how to fix this problem? That's my code:
public class Matrix {
public static void main(String[] args) {
int[][] matrix = { { 1, 8, 1 }, { 4, 2, 4 }, { 1, 8, 1 } };
print(matrix);
System.out.println("\n");
int[][] blur = blurMatrix(matrix);
print(blur);
}
public static int[][] blurMatrix(int[][] matrix) {
if (matrix == null)
return null;
if (matrix.length <= 0)
return null;
int[][] blur = new int[matrix.length][];
for (int row = 0; row < blur.length; row++) {
blur[row] = new int[matrix[row].length];
for (int col = 0; col < blur[row].length; col++) {
blur[row][col] = (matrix[row][col] + matrix[row][col + col]);
if (blur[row] == null)
return null;
// if(blur[col]==null)return null;
}
}
return blur;
}
public static void print(int[][] m) {
if (m == null) {
System.out.print(" no matrix to print!");
return;
}
for (int row = 0; row < m.length; row++) {
for (int col = 0; col < m[row].length; col++) {
System.out.print(m[row][col] + " ");
}
System.out.println("");
}
}
}
When you do matrix[row][col + col], you are trying to read out of the matrix. Also it should be matrix[row][col + 1].
You need to do the blur on all columns except the last one which should remain unchanged.
This should fix your problem:
public static int[][] blurMatrix(int[][] matrix){
if(matrix == null || matrix.length <= 0)
return null;
int[][] blur = new int[matrix.length][];
for(int row =0; row < blur.length; row++) {
blur[row]= new int[matrix[row].length];
// for all cols except the last one (we do not modify the last row)
for(int col=0; col<blur[row].length-1; col++) {
int cellValue = matrix[row][col];
int nextCellValue = matrix[row][col+1];
blur[row][col] = cellValue + nextCellValue;
}
// for the last column
int lastColumnIndex = blur[row].length-1;
blur[row][lastColumnIndex]= matrix[row][lastColumnIndex];
}
return blur;
}
EDIT: To do it in the other direction
public static int[][] blurMatrix(int[][] matrix){
if(matrix == null || matrix.length <= 0)
return null;
int[][] blur = new int[matrix.length][];
for(int row =0; row < blur.length; row++) {
blur[row]= new int[matrix[row].length];
// for all cols except the first one (we do not modify the first row)
for(int col=blur[row].length-1; col>0; col--) {
int cellValue = matrix[row][col];
int previousCellValue = matrix[row][col-1];
blur[row][col] = cellValue + previousCellValue;
}
// for the first column
blur[row][0] = matrix[row][0];
}
return blur;
}
EDIT Applying the 2 blur methods to the original matrix
I think what you are doing is applying the 2 blur methods sequentially
int[][] blur = blurMatrix1(matrix);
print(blur);
System.out.println("");
blur = blurMatrix2(blur);
print(blur);
which results in
after first pass
9 9 1
6 6 4
9 9 1
after second pass
9 18 10
6 12 10
9 18 10
What you seem to want to do is apply the 2 methods on the original one and then sum them
int[][] blur1 = blurMatrix1(matrix);
print(blur1);
System.out.println("");
int[][] blur2 = blurMatrix2(matrix);
print(blur2);
System.out.println("");
which result in
first blur
9 9 1
6 6 4
9 9 1
second blur
1 9 9
4 6 6
1 9 9
now if you add them you get
10 18 10
10 12 10
10 18 10

how to get specific column in 2D array using java

when searched value exist in array, I choose the column and save them.
for example
1 2 3 4 5 6
A B C D E F
G H I J K L
I want to make a column including x==1||x==4
below column will be result of what i want
1 4
A D
G J
below code is my 2D array code. I make 1D array from csv file and 2D array. when searched value exist, I choose the column and save them.
String str = readCSV(new File("D:/sample_folder/sample1.csv"));
String[] strArr = parse(str); // It comes out in a row in an String array.
int varNumber = 45;
int rowNumber = strArr.length/varNumber;
String[][] Array2D = new String[varNumber][rowNumber];
for(int j=0;j<varNumber;j++)
{
for(int i=0; i<rowNumber;i++)
{
String k = strArr[i*varNumber+j];
Array2D[j][i]= k;
}
} //make 2D array
You can through rows of 2D array and pick the column you want.
for(int j=0;j<rowNumber;j++)
{
// index starts from 0
yourArray[j][0] = array2D[j][0];
yourArray[j][1] = array2D[j][3];
}
Or more dynamically you could write:
int[] columnsYouWant = {0, 3};
for(int j=0;j<rowNumber;j++)
{
for(int c=0;c<columnsYouWant.length;c++)
{
yourArray[j][c] = array2D[j][columnsYouWant[c]];
}
}
If you want to use if (x == 1 || x == 4) :
for(int j=0;j<rowNumber;j++)
{
column = 0;
for(int c=0;c<columnNumber;c++)
{
x = c + 1;
if (x == 1 || x == 4)
yourArray[j][column++] = array2D[j][c];
}
}
I might get it wrong. It also seems you may want to have columns starting with 1 or 4. In that case, if your first row has numbers and rest are alphabetical. You should find the column starting with either 1 or 4.
for(int j=0;j<colNumber;j++)
{
x = array2d[0][j];
if ( x == 1 || x == 4 ) {
// add you j to an array
}
}
In the case you will know which columns you want, and you can use the second piece of code in my answer to create 2D array with columns you want.
Try this simulation, I populate this in your 2DArray:
1 2 3 4 5 6
A B C D E F
G H I J K L
after that, I made a code to print only the columns 1 and 4.
public static void main(String[] args) {
String[][] twoDArray = populateArray();
int x = 0;
for (int i = 0; i < twoDArray.length; i++) {
for (int j = 0; j < twoDArray[0].length; j++) {
x = j + 1;
if(x == 1 || x == 4) {
System.out.print(twoDArray[i][j]);
}
}
System.out.println();
}
}
public static String[][] populateArray() {
String[][] twoDArray = new String[3][6];
for (int i = 0; i < twoDArray[0].length; i++) {
twoDArray[0][i] = (i + 1) + "";
}
char alphaChar = 'A';
for (int i = 1; i < twoDArray.length; i++) {
for (int j = 0; j < twoDArray[0].length; j++) {
twoDArray[i][j] = String.valueOf(alphaChar);
alphaChar++;
}
}
return twoDArray;
}
the output of the code is:
14
AD
GJ
if you comment the if(x == 1 || x == 4) { that I used, it will print like this:
123456
ABCDEF
GHIJKL

Filling array with random digits in range

I am writing a sudoku board game generator. My code looks like this:
/**
* Created by szubansky on 3/9/16.
*/
public class SudokuBoard {
static int N = 9;
static int[][] grid = new int[N][N];
static void printGrid()
{
for (int row = 0; row < N; row++)
{
for (int col = 0; col < N; col++) {
System.out.printf("%5d", grid[row][col]);
}
System.out.println("\n");
}
}
private static boolean checkRow(int row, int num)
{
for( int col = 0; col < 9; col++ )
if(grid[row][col] == num)
return false;
return true;
}
private static boolean checkCol(int col, int num)
{
for( int row = 0; row < 9; row++ )
if(grid[row][col] == num)
return false;
return true;
}
private static boolean checkBox(int row, int col, int num)
{
row = (row / 3) * 3;
col = (col / 3) * 3;
for(int r = 0; r < 3; r++)
for(int c = 0; c < 3; c++)
if(grid[row+r][col+c] == num)
return false;
return true;
}
public static boolean fillBoard(int row, int col, int[][] grid)
{
if(row==9) {
row = 0;
if (++col == 9)
return true;
}
if(grid[row][col] != 0)
return fillBoard(row+1, col, grid);
for(int num=1 + (int)(Math.random() * ((9 - 1) + 1)); num<=9; num++)
{
if(checkRow(row,num) && checkCol(col,num) && checkBox(row,col,num)){
grid[row][col] = num;
if(fillBoard(row+1, col, grid))
return true;
}
}
grid[row][col] = 0;
return false;
}
static public void main(String[] args){
fillBoard(0, 0, grid);
printGrid();
}
}
the problem is with generating numbers in fillBoard backtrack algorithm
it basically puts 0 everywhere
when I change the num range in for loop to 10 it goes smoothly but my numbers need to be lower than 9
i can also change the beginning of backtrack fillBoard to row==8 and col==8 and it fills it correctly with random numbers leaving last row and last column with "0".
how to generate random numbers from 1 to 9 and fill all my grid?
Try this :
public static void main(String[] args) {
int[][] grid = new int[9][9];
randomFillGrid(grid, 1, 10);
for (int[] row : grid) {
System.out.println(Arrays.toString(row));
}
}
static void randomFillGrid(int[][] grid, int randomNumberOrigin, int randomNumberBound) {
PrimitiveIterator.OfInt iterator = ThreadLocalRandom.current()
.ints(randomNumberOrigin, randomNumberBound)
.iterator();
for (int[] row : grid) {
for (int i = 0; i < row.length; i++) {
row[i] = iterator.nextInt();
}
}
}
EDIT :
if you want to generate a sudoku grid i.e.
the same single integer may not appear twice in the same row, column or in any of the nine 3×3 subregions of the 9x9 playing board.
import java.util.Arrays;
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;
/**
* #author FaNaJ
*/
public class SudokuGenerator {
private static final int N = 9;
private static final int S_N = 3;
public static int[][] generateSudokuGrid() {
int[][] grid = new int[N][N];
int[] row = {1, 2, 3, 4, 5, 6, 7, 8, 9};
for (int y = 0; y < N; y++) {
int attempts = 0;
do {
if (++attempts > 1000000) { // Oops! I know (sometimes :) it's not a good algorithm...
return generateSudokuGrid();
}
shuffleArray(row);
} while (!isAllowed(grid, y, row));
System.arraycopy(row, 0, grid[y], 0, N);
}
return grid;
}
static boolean isAllowed(int[][] grid, int y, int[] row) {
// check columns
for (int i = 0; i < y; i++) {
for (int j = 0; j < N; j++) {
if (grid[i][j] == row[j]) {
return false;
}
}
}
// check sub grids
int startY = (y / S_N) * S_N;
for (int x = 0; x < N; x++) {
int startX = (x / S_N) * S_N;
for (int j = startX; j < startX + S_N; j++) {
if (j != x) {
for (int i = startY; i < y; i++) {
if (grid[i][j] == row[x]) {
return false;
}
}
}
}
}
return true;
}
static void shuffleArray(int[] array) {
Random random = ThreadLocalRandom.current();
for (int i = N; i > 1; i--) {
swap(array, i - 1, random.nextInt(i));
}
}
static void swap(int[] array, int i, int j) {
int tmp = array[i];
array[i] = array[j];
array[j] = tmp;
}
public static void main(String[] args) {
int[][] grid = generateSudokuGrid();
for (int[] row : grid) {
System.out.println(Arrays.toString(row));
}
}
}
output :
[3, 4, 6, 9, 1, 2, 7, 8, 5]
[9, 7, 2, 3, 8, 5, 4, 1, 6]
[5, 8, 1, 6, 7, 4, 3, 2, 9]
[7, 6, 3, 8, 2, 9, 1, 5, 4]
[4, 9, 5, 1, 6, 7, 2, 3, 8]
[2, 1, 8, 4, 5, 3, 6, 9, 7]
[6, 2, 4, 5, 9, 1, 8, 7, 3]
[8, 5, 7, 2, 3, 6, 9, 4, 1]
[1, 3, 9, 7, 4, 8, 5, 6, 2]
You can use Random class of java.utilpackage to generate random numbers. Below is an example that generates random numbers between 1 to 9:
Random rn = new Random();
int answer = rn.nextInt(9) + 1;
Before I start let me say that this while I'm not going tell you outright what all of your errors are, I will help you narrow your search and suggest a method to further debug your code.
Now to your problem: your array populated only with zero.
Only two lines can populate your array.
The first sets a spot in the array to have a random int value between 1 and 9 inclusive. If this random number doesn't pass a series of tests then that spot in the array is set to zero.
If one of these testers never returns true, the array will be populated with only zeros.
This leaves 4 functions that could be bugged.
-checkRow
-checkCol
-checkBox
-fillBoard
The first 2 functions are relatively simple so I can say with certainty that those work fine.
This leads only the checkBox and fillBoard functions under suspicion as causes of your bug.
At this point, this is where the debugging comes in.
Both of these functions contain loops.
One method to see if your loop is working is to compare a set of expected changes/return values to those which are actually gotten from the program.
To do this, either use a debugger
(assert statement + java -ea program.java and or other debugger methods)
Or, you could add print statements within your loop which print your gotten values for various variables/functions.
In any case, welcome to Stacks Overflow.
You mention that you are using a backtrack algorithm so I thought this would be fun to use a backtrack algorithm and try to demonstrate what it is. Below is a mash-up of your code and mine. I tried to stick to what you were doing and only add/change what I felt like I needed to.
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* SudokuBoard.
*/
public class SudokuBoard {
// Dimension size of everything
static int N = 9;
// Sudoku grid
static int[][] grid = new int[N][N];
// Values that are potentially valid at each position in the sudoku grid
static int[][][] values = new int[N][N][N];
// Current index into the values
static int[][] index = new int[N][N];
/**
* Return a shuffled list of values from 1 - 9 with each value
* appearing only once.
*/
private static List<Integer> getValidValues(){
List<Integer> validValues = new ArrayList<>();
for(int i = 1; i < 10; i++){
validValues.add(i);
}
Collections.shuffle(validValues);
return validValues;
}
/**
* Populate the values array with shuffled values to choose from.
*/
private static void initValues()
{
for(int i = 0; i < values.length; i++){
for(int j = 0; j < values[i].length; j++){
List<Integer> validValues = getValidValues();
for(int k = 0; k < values[j].length; k++){
values[i][j][k] = validValues.get(k);
}
}
}
}
/**
* print the 2D sudoku grid.
*/
public static void printGrid()
{
for (int row = 0; row < N; row++)
{
for (int col = 0; col < N; col++) {
System.out.printf("%5d", grid[row][col]);
}
System.out.println("\n");
}
}
/**
* Check the row for validity.
*/
private static boolean checkRow(int row, int num)
{
for( int col = 0; col < 9; col++ )
if(grid[row][col] == num)
return false;
return true;
}
/**
* Check the col for validity.
*/
private static boolean checkCol(int col, int num)
{
for( int row = 0; row < 9; row++ )
if(grid[row][col] == num)
return false;
return true;
}
/**
* Check the box for validity.
*/
private static boolean checkBox(int row, int col,
int num, boolean testRowCol)
{
int theR = row;
int theC = col;
row = (row / 3) * 3;
col = (col / 3) * 3;
for(int r = 0; r < 3; r++) {
for (int c = 0; c < 3; c++) {
if (testRowCol) {
if (theR == row + r && theC == col + c){
continue;
}
}
if (grid[row + r][col + c] == num) {
return false;
}
}
}
return true;
}
/**
* Build the sudoku board.
*/
public static boolean fillBoard(int row, int col)
{
// if we are back at the beginning then success!
// but just for sanity we will check that its right.
if(row != 0 && col != 0){
if(row % 9 == 0 && col % 9 == 0){
return checkBoard();
}
}
// don't go out of range in the grid.
int r = row % 9;
int c = col % 9;
// get the index in the values array that we care about
int indexIntoValues = index[r][c];
// if the index is out of range then we have domain wipe out!
// lets reset the index and try to back up a step. Backtrack!
if(indexIntoValues > 8){
index[r][c] = 0;
// there are a few cases to cover
// if we are at the beginning and the index is out
// of range then failure. We should never get here.
if(row == 0 && col == 0) {
return false;
}
grid[r][c] = 0;
// if the row is at 0 then back the row up to row - 1 and
// the col - 1
if(r == 0 && c > 0) {
return fillBoard(row - 1, col - 1);
}
// if the row is greater than 0 then just back it up by 1
if(r > 0){
return fillBoard(row - 1, col);
}
}
index[r][c] += 1;
// get the value that we care about
int gridValue = values[r][c][indexIntoValues];
// is this value valid
if(checkRow(r,gridValue) && checkCol(c,gridValue) &&
checkBox(r,c,gridValue,false)){
// assign it and move on to the next one
grid[r][c] = gridValue;
return fillBoard(row+1, r == 8 ? col + 1 : col);
}
// the value is not valid so recurse and try the next value
return fillBoard(row, col);
}
/**
* This is a sanity check that the board is correct.
* Only run it after a solution is returned.
*/
private static boolean checkBoard(){
//the grid is N X N so just use N as the condition.
//check rows are ok.
for(int i = 0; i < N; i++){
for(int j = 0; j < N; j++){
//for each of the elements in the row compare against
//every other one except its self.
int toTest = grid[i][j];
//check that the digits in the elements are in the valid range.
if(toTest > 9 || toTest < 1)
return false;
for(int k = 0; k < N; k++){
//don't test me against myself
if(k == j)
continue;
//if i am equal to another in the row there is an error.
if(toTest == grid[i][k])
return false;
}
}
}
//check the cols are ok.
for(int i = 0; i < N; i++){
for(int j = 0; j < N; j++){
//flip i and j to go for cols.
int toTest = grid[j][i];
for(int k = 0; k < N; k++){
if(k == j)
continue;
if(toTest == grid[k][i])
return false;
}
}
}
//check blocks are ok
for(int i = 0; i < N; i++){
for(int j = 0; j < N; j++){
int toTest = grid[i][j];
if(!checkBox(i, j, toTest, true))
return false;
}
}
return true;
}
static public void main(String[] args){
initValues();
if(fillBoard(0, 0))
printGrid();
else
System.out.println("Something is broken");
}
}
So the main things that I added were two multidimensional arrays one is a values list, and the other is a current index into that values list. So the values array keeps a list of all of the valid values that each cell can have. I shuffled the values to give the random feel that you were looking for. We don't really care about value ordering here for any performance reasons, but we want it to be "random" in order to get a different board from run to run. Next the index array keeps track of where you are in the values array. At any point that your index in the index array goes out of bounds, that means that none of the values will work. This is the point that you need reset the index to zero and go back to the cell you came from to try a new value there. That is the backtracking step. I kept moving through the array sequential as you did but its not necessary. I think you could actually go to the variable that has the least amount of valid values, so the highest index in this case, and the search should be faster, but who cares right now, it's a small search, the depth is 81 and you win! I also included a sanity check that the board is valid.
Here is an output:
1 3 2 5 7 6 4 9 8
7 5 8 1 9 4 3 2 6
6 4 9 8 2 3 1 7 5
8 6 3 2 5 9 7 1 4
5 7 4 6 3 1 9 8 2
9 2 1 4 8 7 5 6 3
4 9 7 3 6 8 2 5 1
3 8 5 7 1 2 6 4 9
2 1 6 9 4 5 8 3 7
I hope this helps you in some way, this was a fun one.

Categories

Resources