I am doing my homework right now and have a question about refactoring my code in Java.
I am working on a Sudoku right now and I need to check if the 3x3 boxes are valid or not. To do that I create a one dimensional array with all the numbers of the boxes and later I compare the value of them. It is working right now but it really isn't refactored at all. I would really like to know if there is any way to reduce all this copy paste.
public static boolean validFieldParts() {
int counter = 0;
boolean isValid = false;
int[] copyArray1 = new int[field.length];
int[] copyArray2 = new int[field.length];
int[] copyArray3 = new int[field.length];
int[] copyArray4 = new int[field.length];
int[] copyArray5 = new int[field.length];
int[] copyArray6 = new int[field.length];
int[] copyArray7 = new int[field.length];
int[] copyArray8 = new int[field.length];
int[] copyArray9 = new int[field.length];
// copy the array
// 1 große Feld
for (int i = 0; i < field.length / 3; i++) {
for (int j = 0; j < field[i].length / 3; j++) {
copyArray1[i * 3 + j] = field[i][j];
}
}
// 2 große Feld
for (int i = 0; i < field.length / 3; i++) {
for (int j = 3; j < 6; j++) {
copyArray2[i * 3 + j - 3] = field[i][j];
}
}
// 3 große Feld
for (int i = 0; i < field.length / 3; i++) {
for (int j = 6; j < 9; j++) {
copyArray3[i * 3 + j - 6] = field[i][j];
}
}
// 4 große Feld
for (int i = 3; i < 6; i++) {
for (int j = 0; j < field[i].length / 3; j++) {
copyArray4[(i - 3) * 3 + j] = field[i][j];
}
}
// 5 große Feld
for (int i = 3; i < 6; i++) {
for (int j = 3; j < 6; j++) {
copyArray5[(i - 3) * 3 + j - 3] = field[i][j];
}
}
// 6 große Feld
for (int i = 3; i < 6; i++) {
for (int j = 6; j < 9; j++) {
copyArray6[(i - 3) * 3 + j - 6] = field[i][j];
}
}
// 7 große Feld
for (int i = 6; i < 9; i++) {
for (int j = 0; j < field[i].length / 3; j++) {
copyArray7[(i - 6) * 3 + j] = field[i][j];
}
}
// 8 große Feld
for (int i = 6; i < 9; i++) {
for (int j = 3; j < 6; j++) {
copyArray8[(i - 6) * 3 + j - 3] = field[i][j];
}
}
// 9 große Feld
for (int i = 6; i < 9; i++) {
for (int j = 6; j < 9; j++) {
copyArray9[(i - 6) * 3 + j - 6] = field[i][j];
}
}
Arrays.sort(copyArray1);
Arrays.sort(copyArray2);
Arrays.sort(copyArray3);
Arrays.sort(copyArray4);
Arrays.sort(copyArray5);
Arrays.sort(copyArray6);
Arrays.sort(copyArray7);
Arrays.sort(copyArray8);
Arrays.sort(copyArray9);
for (int i = 1; i < copyArray1.length; i++) {
if (copyArray1[i] == copyArray1[i - 1])
counter++;
else
continue;
}
for (int i = 1; i < copyArray2.length; i++) {
if (copyArray2[i] == copyArray2[i - 1])
counter++;
else
continue;
}
for (int i = 1; i < copyArray3.length; i++) {
if (copyArray3[i] == copyArray3[i - 1])
counter++;
else
continue;
}
for (int i = 1; i < copyArray4.length; i++) {
if (copyArray4[i] == copyArray4[i - 1])
counter++;
else
continue;
}
for (int i = 1; i < copyArray5.length; i++) {
if (copyArray5[i] == copyArray5[i - 1])
counter++;
else
continue;
}
for (int i = 1; i < copyArray6.length; i++) {
if (copyArray6[i] == copyArray6[i - 1])
counter++;
else
continue;
}
for (int i = 1; i < copyArray7.length; i++) {
if (copyArray7[i] == copyArray7[i - 1])
counter++;
else
continue;
}
for (int i = 1; i < copyArray8.length; i++) {
if (copyArray8[i] == copyArray8[i - 1])
counter++;
else
continue;
}
for (int i = 1; i < copyArray9.length; i++) {
if (copyArray9[i] == copyArray9[i - 1])
counter++;
else
continue;
}
if (counter > 0)
isValid = false;
else
isValid = true;
return isValid;
}
Instead of using 9 different arrays and 9 different loops to represent each section of 9, I would have another nested for loop that iterates over each cluster using the same array.
//Iterate over each 'block'
for (int row = 0; row < 3; row++) {
for (int col = 0; col < 3; col++) {
//Iterate over each cell in the block
for (int i = row*3; i < (row+1)*3; i++) {
for (int j = col*3; j < (col+1)*3; j++) {
copyArray[(i - 3) * 3 + j - 3] = field[i][j];
}
}
//Sort array and do duplication check here - return false if dupe found
}
}
return true
This would cut down on the length of your code, although it may not be more efficient.
Instead of using a counter flag, it would be much faster to instead return false whenever you would have incremented the counter, and to return true at the end. This would prevent unnecessary code from running
Here a complete refactoring. Here the improuvements:
Created two new methods: createCopy and isValid
Deleted unused variables counter and isValid
Substituted 9 arrays with one two size array.
The code as not been tested, please take a bit careful attention on method createCopy in particular.
// Creates each block of 9 digits copying digits from field
// row, col are the block position, starting from upper left 0, 0 to
// last block 2, 2
public static int[] createCopy(int[] field, int row, int col) {
int[] copy = new int[9];
for (int i = 3 * row; i < 3 * row + 3; i++) {
for (int j = 3 * col; j < 3 * col + 3; j++) {
copy[(i - 3 * row) * 3 + j - 3 * col] = field[i][j];
}
}
return copy;
}
// Check if one block is valid
private static boolean isValid(int[] copyArray) {
Arrays.sort(copyArray);
for (int i = 1; i < copyArray.length; i++) {
if (copyArray[i] == copyArray[i - 1]) {
// Exit immediately if not valid
return false;
}
}
return true;
}
// Create blocks, then validate them
// At first not valid block return false
public static boolean validFieldParts() {
int[][] copyArrays = new int[3][3];
for (int row = 0; row < 3; row++) {
for (int col = 0; col < 3; col++) {
copyArrays[row][col] = createCopy(field, row, col);
}
}
for (int[] copyArray : copyArrays) {
if (!isValid(copyArray)) {
// Exit immediately if not valid
return false;
}
}
return true;
}
Related
for the given input I need to print the pattern. For example for input = 6 I have to print:
MMMMMMSDDDDDD
MMMMMSSSDDDDD
MMMMSSSSSDDDD
MMMSSSSSSSDDD
MMSSSSSSSSSDD
MSSSSSSSSSSSD
CSSSSSSSSSSSK
CCSSSSSSSSSKK
CCCSSSSSSSKKK
CCCCSSSSSKKKK
CCCCCSSSKKKKK
CCCCCCSKKKKKK
I have tried but couldn't go further than this could anyone help
public class tgk {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int size = sc.nextInt();
int half = ((2*size)+1)/2;
for (int i = 0; i < size ; i++)
{
for (int j = size; j > i; j--)
{
System.out.print("M");
}
for (int k = half+1 ; k > half - i; k--)
{
System.out.print("S");
}
System.out.println();
}
for(int i = size; i > 0; i--)
{
for (int j = size; j >= i; j--) {
System.out.print("C");
}
for (int k = 0; k < (i * 2 - 1); k++) {
System.out.print("S");
}
System.out.println();
}
}
}
if input = 3 it should be
MMMSDDD
MMSSSDD
MSSSSSD
CSSSSSK
CCSSSKK
CCCSKKK
You can use two sets of for loops to print each half of the pattern. Assuming input variable holds the size of the problem
int input = 3;
for (int i = 0; i < input; i++) {
for (int j = 0; j < input - i; j++) {
System.out.print('M');
}
for (int j = 0; j < 2 * i + 1; j++) {
System.out.print('S');
}
for (int j = 0; j < input - i; j++) {
System.out.print('D');
}
System.out.println();
}
for (int i = input - 1; i >= 0; i--) {
for (int j = 0; j < input - i; j++) {
System.out.print('C');
}
for (int j = 0; j < 2 * i + 1; j++) {
System.out.print('S');
}
for (int j = 0; j < input - i; j++) {
System.out.print('K');
}
System.out.println();
}
will print for input = 3:
MMMSDDD
MMSSSDD
MSSSSSD
CSSSSSK
CCSSSKK
CCCSKKK
and for input = 6:
MMMMMMSDDDDDD
MMMMMSSSDDDDD
MMMMSSSSSDDDD
MMMSSSSSSSDDD
MMSSSSSSSSSDD
MSSSSSSSSSSSD
CSSSSSSSSSSSK
CCSSSSSSSSSKK
CCCSSSSSSSKKK
CCCCSSSSSKKKK
CCCCCSSSKKKKK
CCCCCCSKKKKKK
I don't know why, but I really wanted it to work with only one set of for-loops:
int number = 8;
for (int i = 0; i < number * 2; i++) {
for (int j = 0; j < (number * 2) + 1; j++) {
System.out.print(
i < number && j+i < number ? 'M' :
i < number && j-i > number ? 'D' :
i < number ? 'S' :
i >= number && i-j >= number ? 'C' :
i >= number && j+i >= number*3 ? 'K' :
'S'
);
}
System.out.println();
}
So for 8 (like in the code) it prints:
MMMMMMMMSDDDDDDDD
MMMMMMMSSSDDDDDDD
MMMMMMSSSSSDDDDDD
MMMMMSSSSSSSDDDDD
MMMMSSSSSSSSSDDDD
MMMSSSSSSSSSSSDDD
MMSSSSSSSSSSSSSDD
MSSSSSSSSSSSSSSSD
CSSSSSSSSSSSSSSSK
CCSSSSSSSSSSSSSKK
CCCSSSSSSSSSSSKKK
CCCCSSSSSSSSSKKKK
CCCCCSSSSSSSKKKKK
CCCCCCSSSSSKKKKKK
CCCCCCCSSSKKKKKKK
CCCCCCCCSKKKKKKKK
...or for 3:
MMMSDDD
MMSSSDD
MSSSSSD
CSSSSSK
CCSSSKK
CCCSKKK
public static void main(String[] args) {
// TODO code application logic here
int numRows = 5;
int numCols = numRows;
int[][] twoDimArray = new int[numRows][numCols];
Random randGen = new Random();
for (int i = 0; i < numRows; i++) {
for (int j = 0; j < numCols; j++) {
int randIndex = randGen.nextInt(4);
int value = randGen.nextInt(100);
twoDimArray[i][j] = value;
}
}
System.out.println("\nThe two-dimensional array: ");
for (int i = 0; i < numRows; i++) {
for (int j = 0; j < numCols; j++) {
System.out.print(twoDimArray[i][j] + " ");
}
System.out.println();
}
}
}
I want to find a local minimum using a "brute force" approach. I know with a one dimensional array I would use a for-loop to compare all the elements in the array until I found a local minimum, but I don't know how to do that here.
Edit: Could I use binary search instead? Find the middle row and search there and if one isn't found, I search one of the halves.
The brute force method would be very similar to that of a 1D array, just with an extra loop, and a few more checks:
public int[] findLocalMinimum(int[][] arr) {
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr[i].length; j++) {
int current = arr[i][j];
if (i + 1 < arr.length && current >= arr[i + 1][j] ||
i - 1 >= 0 && current >= arr[i - 1][j] ||
j + 1 < arr[i].length && current >= arr[i][j + 1] ||
j - 1 >= 0 && current >= arr[i][j - 1]) {
continue;
} else {
return new int[] { i, j };
}
}
}
return new int[] { -1, -1 };
}
I'm using a four dimensional array write a Sudoku solver in Java, where the dimensions describe the location of the cell on the board and the values assigned to them are the possible numbers that the cell can be. Sudoku Wikipedia, for reference
I have written methods for printing a Unicode art representation of the board for clarity, as well as a method to print all of the choices for each cell on the board. These methods work. However, my method to eliminate singletons from other cells in the single's row, column, and box does not work as intended (removing from unknown cells all known cells in the same row/column/box). Note that the top left cell (choiceArray[0][0][0][0]) should be the string 467 but is instead 23478. Here is the code I wrote. Sudoku boards are entered as 81-character strings, where 0's represent empty cells in the initial board.
(In addition to answering this question, stylistic/procedural advice from more experienced programmers than myself would be appreciated, as I'm very much a beginner)
public class SudokuSolver {
public static void main(String[] args) {
String initialBoard = "020501090800203006030060070001000600540000019002000700090030080200804007010907060";
//Parsing the input to make sure that it is valid
if (!(initialBoard.matches("[0-9]+") && initialBoard.length() == 81)) {
System.err.println("Input board was not valid.");
System.exit(0);
}
//Generating the sudoku board
printBoard(initialBoard);
//Generating an array for the given information
String[][][][] choiceArray = new String[3][3][3][3];
for(int i = 0; i < 3; i++) { //row of box
for(int j = 0; j < 3; j++) { //column of box
for(int k = 0; k < 3; k++) { //row in box
for(int l = 0; l < 3; l++) { //column in box
int cellNumber = 27 * i + 3 * j + 9 * k + l;
char cellContents = initialBoard.charAt(cellNumber);
if(cellContents == '0') {
choiceArray[i][j][k][l] = "123456789";
}
else {
choiceArray[i][j][k][l] = Character.toString(cellContents);
}
}
}
}
}
//Removing singletons
while(!(puzzleIsSolved(choiceArray))) {
boolean boardChanges = false;
for(int i = 0; i < 3; i++) { //row of box
for(int j = 0; j < 3; j++) { //column of box
for(int k = 0; k < 3; k++) { //row in box
for(int l = 0; l < 3; l++) { //column in box
if(choiceArray[i][j][k][l].length() == 1) {
String solvedCell = choiceArray[i][j][k][l];
//Removing choice from row (i, k constant)
for(int a = 0; a < 3; a++) {
for(int b = 0; b < 3; b++) {
if(a != j && b != l) {
if(choiceArray[i][a][k][b].contains(solvedCell)) {
choiceArray[i][a][k][b] = removeChoice(choiceArray[i][a][k][b], solvedCell);
boardChanges = true;
}
}
}
}
//Removing choice from column (j, l constant)
for(int a = 0; a < 3; a++) {
for(int b = 0; b < 3; b++) {
if(a != i && b != k) {
if(choiceArray[a][j][b][l].contains(solvedCell)) {
choiceArray[a][j][b][l] = removeChoice(choiceArray[a][j][b][l], solvedCell);
boardChanges = true;
}
}
}
}
//Removing choice from box (i, j constant)
for(int a = 0; a < 3; a++) {
for(int b = 0; b < 3; b++) {
if(a != i && b != j) {
if(choiceArray[a][b][k][l].contains(solvedCell)) {
choiceArray[a][b][k][l] = removeChoice(choiceArray[a][b][k][l], solvedCell);
boardChanges = true;
}
}
}
}
}
}
}
}
}
if(!boardChanges) {
break;
}
}
System.out.println(choiceArray[0][0][0][0]);
//expected: 467
//actual: 23478
}
//Printing the current state of the sudoku
public static void printBoard(String input) {
String rowA = "╔═══╤═══╤═══╦═══╤═══╤═══╦═══╤═══╤═══╗";
String rowB = "╟───┼───┼───╫───┼───┼───╫───┼───┼───╢";
String rowC = "╠═══╪═══╪═══╬═══╪═══╪═══╬═══╪═══╪═══╣";
String rowD = "╚═══╧═══╧═══╩═══╧═══╧═══╩═══╧═══╧═══╝";
input = input.replaceAll("0", " ");
System.out.println(rowA);
for(int row = 0; row < 9; row++) {
for(int box = 0; box < 3; box++) {
System.out.print("║");
for(int cell = 0; cell < 3; cell++) {
System.out.print(" " + input.charAt(9 * row + 3 * box + cell) + " ");
if(cell != 2) {
System.out.print("│");
}
}
}
System.out.println("║");
if(row % 3 == 2 && row != 8) {
System.out.println(rowC);
}
else if(row != 8){
System.out.println(rowB);
}
else {
System.out.println(rowD);
}
}
}
//Print all possible choices in all cells in sudoku (good for debugging)
public static void printAllChoices(String[][][][] choiceArray) {
for(int i = 0; i < 3; i++) { //row of box
for(int k = 0; k < 3; k++) { //row in box
for(int j = 0; j < 3; j++) { //column of box
for(int l = 0; l < 3; l++) { //column in box
int cellNumber = 27 * i + 3 * j + 9 * k + l + 1;
System.out.println(cellNumber + ": " + choiceArray[i][j][k][l]);
}
}
}
}
}
//Check if all cells only have one choice left
public static boolean puzzleIsSolved(String[][][][] choiceArray) {
for(int i = 0; i < 3; i++) {
for(int j = 0; j < 3; j++) {
for(int k = 0; k < 3; k++) {
for(int l = 0; l < 3; l++) {
if(choiceArray[i][j][k][l].length() > 1) {
return false;
}
}
}
}
}
return true;
}
//Removing choice from cell
public static String removeChoice(String initialChoices, String choiceToRemove) {
String finalChoices = "";
for(int i = 0; i < initialChoices.length(); i++) {
if(initialChoices.charAt(i) != choiceToRemove.charAt(0)) {
finalChoices += initialChoices.charAt(i);
}
}
return finalChoices;
}
}
I am currently working on a SudokuChecker I want to check the subfields [3x3] of the sudoku. The following code does this:
int[][] field = new field[9][9];
int wrongNumbers = 0;
for (int i = 0; i < 9; i += 3) {
for (int j = 0; j < 9; j += 3) {
// Check subfield by using an array
int arr[] = new int[10];
for (int k = 0; k < 3; k++) {
for (int l = 0; l < 3; l++) {
arr[field[i + k][j + l]]++;
}
}
for (int k = 1; k < arr.length; k++) {
wrongNumbers += arr[k] > 1 ? arr[k] - 1 : 0;
}
}
}
I want to know are there any improvements for the given code?
(I am not talking about making the 3, 9, etc. constant)
I found a very good answer in Codefights from thucnguyen:
boolean sudoku(int[][] grid) {
for (int i = 0; i <9; i++) {
int row = 0, col = 0, group = 0;
for (int j = 0; j <9; j++) {
// check for row i
row += grid[i][j];
// check for col i
col += grid[j][i];
// check for sub-grid i
group += grid[i / 3 * 3 + j / 3][i % 3 * 3 + j % 3];
}
if (row != 45 || col != 45 || group != 45) return false;
}
return true;
}
Where is the logic error?.. Sometimes the solution is correct and sometimes it is not. The program is suppose to calculate the row with the greatest sum and column with the greatest sum. For example:
1 1 1 1
0 0 1 0
0 0 1 0
0 0 1 0
Then the output would be:
largest row = 0
largest column = 2 //since count starts at 0
This is what I have:
import java.util.Random;
public class LargestRowAndColumn {
public static void main(String[] args) {
Random f = new Random();
int[][] m = new int[4][4];
for (int i = 0; i < m.length; i++) {
for (int j = 0;j < m[0].length; j++) {
m[i][j] = f.nextInt(2);
}
}
for (int i = 0; i < m.length; i++) {
for (int j = 0;j < m[0].length; j++) {
System.out.print(m[i][j] + " ");
}
System.out.println();
}
System.out.println("The largest row is index: " + computeRow(m));
System.out.println("The largest column is index: " + computeColumn(m));
}
public static int computeRow(int[][] m) {
int[] count = new int[m.length];
int sum;
for (int i = 0; i < 4; i++) {
sum = 0;
for (int j = 0; j < 4; j++) {
sum = sum + m[i][j];
}
count[i] = sum;
}
int maxIndex = 0;
for (int i = 0; i < i + 1; i++) {
for (int j = count.length - 1; j >= i; j--) {
if (count[i] < count[j]) {
maxIndex = j;
break;
}
}
}
return maxIndex;
}
public static int computeColumn(int[][] m) {
int[] count = new int[m.length];
int sum = 0;
for (int i = 0; i < 4; i++) {
sum = 0;
for (int j = 0; j < 4; j++) {
sum = sum + m[j][i];
}
count[i] = sum;
}
int maxIndex = 0;
for (int i = 0; i < i + 1; i++) {
for (int j = count.length - 1; j >= i; j--) {
if (count[i] < count[j]) {
maxIndex = j;
break;
}
}
}
return maxIndex;
}
}
Your maxIndex nested loop is too complex. It should be a single loop, checking the current max value seen so far with the current item in the loop. Something like this:
int maxIndex = 0;
for (int i = 1; i < count.length; i++) {
if (count[i] > count[maxIndex]) {
maxIndex = i;
}
}
return maxIndex;
Your code is correct , but
for (int i = 0; i < m.length; i++) {
for (int j = 0;j < m[0].length; j++) {
m[i][j] = f.nextInt(2);
}
}
for (int i = 0; i < m.length; i++) {
for (int j = 0;j < m[0].length; j++) {
System.out.print(m[i][j] + " ");
}
Because of the two loops:
You are creating two random 2-dimensional array instead of one.
There is one which is being printed and the other one which is not being printed but being used for index values you require so do :
System.out.print("Index" + "\t0"+"\t1"+"\t2"+"\t3" +"\n");
System.out.print("--------------------------------------------\n");
for (int i = 0; i < m.length; i++) {
System.out.print(i+ "|\t");
for (int j = 0;j < m[0].length; j++) {
m[i][j] = f.nextInt(101);
System.out.print(m[i][j] + " \t");
}
System.out.println();
}
This will also print the index, which may assist you
Why you made your job difficult. Make 2 loops, 1 for calculating the row with biggest sum, 1 for calculating the line with the bigger sum.
You don't need an int array count[i]. In your example you calculate the row with the greatest sum, you don't need to know the sum of every row after the for loop finished, so you can use a simple int bigRow.
int bigRow = 1, sumRow = 0;
// We assume that 1st row is the biggest
// Calculate the sumRow
for (int j=0;j<n;j++)
sumRow = sumRow + m[i][j] ;
// At this moment our maximum is row 1 with its sum.
// Now we compare it with the rest of the rows
// If another row is bigger, we set him as the biggest row
for ( int i=1;i<n;i++) // We start with row 2 as we calculated the 1st row
{ int auxRow = 0;
for (int j=0;j<m;j++)
{ auxRow = auxRow + m[i][j] ; }
if (auxRow > sumRow ) { auxRow=sumRow ; bigRow = i;}
}
Do the same with lines.
int bigLine = 1, sumLine = 0 ;
Let me know if you have another problem.