I'm trying out this code for a project where we do the fill grid and evaluate methods for a given sudoku grid via three urls that we can interchange within the code. I'm not interested in efficiency at this point because I'm still trying to get a handle on Java. So far this is the code I have for the evaluate method
I understand the logic behind the first two for loops for the box but I'm trying to understand the second two
EDIT: I'm asking if I what I wrote for the box checker is correct because it still returns false even though the written grids are all correct sudoku boards
public boolean evaluate() {
// check row
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
for (int k = j + 1; k < 9; k++) {
if (gridButton[i][j].getText().equals(gridButton[i][k].getText())) return false;
}
}
}
// check box
for (int i = 0; i < 9; i += 3) {
for (int j = 0; j < 9; j += 3) {
for (int k = 0; k < 3; k++) {
for (int l = 0; l < 3; l++) {
if (gridButton[i][j].getText().equals(gridButton[k][l].getText())) return false;
k += 1;
}
}
}
}
// check col
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
for (int k = i + 1; k < 9; k++) {
if (gridButton[i][j].getText().equals(gridButton[k][j].getText())) return false;
}
}
}
return false;
}
I worked with my professor for a viable row checker and I adapted it myself for the col checker but I'm still not totally sure about how to write the box checker.
The Box algorithm in your code does 9x9x3x3 == 729 comparisons.
Perhaps a better approach would be to use a HashSet across each row, column, or box. Once a duplicate value is found in the set, it can bail out.
With using a Set, there's 9x3x3 == 81 looksup and insertions to be made. Assumption is that Set insertion and lookup are both O(1)
// check box
HashSet<String> set = new HashSet<String>();
for (int i = 0; i < 9; i++) { // for each major 3x3 box
set.clear(); // start with an empty "set"
// examine each cell in the box. If the cell's value is already in
// "set", then we have a duplicate and should exit. Otherwise, add
// the cell's value to the set
for (int r = 0; r < 3; r++) {
for (int c = 0; c < 3; c++) {
int row = (i / 3) + r;
int column = 3*(i%3) + c;
String val = gridButton[row][column].getText();
if (set.contains(val) {
return false; // the value of the cell was already found, bail
}
set.add(val); // not found, add it to the set
}
}
}
You can apply the same technique to the "check row" and "check column" algorithm and have less comparisons to make as well. That's an exercise I'll leave up to you to solve.
And if we were comparing integers instead of text strings, we could use a simple Boolean array instead of a HashSet instance. :)
Related
I'm trying to evaluate a hand to see if they have a pair and I feel like this is right but i keep getting errors. Any idea on what im doing wrong?
public boolean isPair() {
String[] values = new String[5];
int counter = 0;
//Put each cards numeric value into array
for(int i = 0; i < cards.length; i++){
values[i] = cards[i].toString();
}
//Loop through the values. Compare each value to all values
//If exactly two matches are made - return true
for(int j = 0; j < values.length; j++){
for(int k = 0; k < cards.length; k++){
if(values[j].equals(cards[k].toString()))
counter++;
if(counter == 2)
return true;
}
counter = 0;
}
return false;
}
The first obvious error I can see, is that you re comparing the first card with itself here :
for(int j = 0; j < values.length; j++){
for(int k = 0; k < cards.length; k++){
Your index k should not be verified if it equals j.
Secondly, why are you using a your variable "hand" in the comparison when you bothered to create a array of String containing your hand ?
values[j].equals(cards[k].toString())
You can write :
values[j].equals(values[k])
I dont think it is responsible for any errors, but it s much easier to understand.
And finally, your counter is false. A pair, is by definition two cards of the same value. So, you have to check if a value is present only two times(that means 1 equality) in your hand.
So you'll have :
for(int j = 0; j < values.length; j++){
for(int k = 0; k < cards.length; k++){
if(k!=j){
if(values[j].equals(values[k]))
counter ++;
}
}
if (counter ==1 ) //Counter==1 means the a value matched with an other value in your hand only once, involving one pair.
return true;
else counter = 0;
}
return false;
String[] values = new String[5];
should be
String[] values = new String[cards.length];
However, even better would be to not use values anyway, since it's almost a copy of cards.
In an ordinary nested for-loop, is it possible to put a condition to determine whether to run a specific for loop in a nested loop?
For example, in a code like below, is it possible to skip second for-statement(int j) when int i of the first loop is < 3?
for(int i = 0; i < 5; i++) {
for(int j = 0; j < 3; j++) {
for(int k = 0; k < 9; k++) {
//hell a lot of codes
}
}
}
so that only when i < 3, the actual executed code looks like this?
for(int i = 0; i < 5; i++) {
for(int k = 0; k < 9; k++) {
//hell a lot of codes
}
}
The reason why I want to do this is that the inner-most codes are quite long as well as the number of the for loops (about 10 nested), and really don't want to repeat them again. I can think of doing this with methods, but I am not quite familiar with methods and OO programming.
Much appreciated,
Generally, I'd probably extract the code to a separate method. But here's a workaround if you don't want to do that:
for(int i = 0; i < 5; i++) {
for(int j = 0; j < (i < 3 ? 1 : 3); j++) {
for(int k = 0; k < 9; k++) {
//hell a lot of codes
}
}
}
This way, if i < 3, the j loop will only execute once.
The method approach would roughly look something like this:
void outer() {
for(int i = 0; i < 5; i++) {
if(i < 3) {
inner(i, 0);
} else {
for(int j = 0; j < 3; j++) {
inner(i, j);
}
}
}
}
void inner(int i, int j) {
for(int k = 0; k < 9; k++) {
//hell a lot of codes
}
}
You may want to make the methods static, or private, or remove the parameter(s), or add a return type, etc. It's hard to say with just the code in your question.
This question already has answers here:
How to count distinct values in a list in linear time?
(3 answers)
Closed 7 years ago.
For this Algorithm assignment in class I have to find all the unique values in a 1000x250 2D array.
The data is between 2000000 to 2200000. All the data is stored in a 2D int array called data.
The problem I am having is that it takes a bit of time to run this and my prof said we can't use other data sets and also we need to optimize our code so it runs at a good speed.
int[] uniqueValues = new int[200000];
boolean isUnique = true;
int uniqueCounter = 0;
for (int i = 0; i < data.length; i++) {
for (int j = 0; j < data[i].length; j++) {
for (int x = 0; x < uniqueCounter; x++) {
if (data[i][j] != uniqueValues[x]) {
isUnique = true;
} else {
isUnique = false;
break;
}
}
if (isUnique) {
uniqueValues[uniqueCounter] = data[i][j];
uniqueCounter++;
}
}
}
Well if you allocate 200000 ints for the result anyway, you can use them as counters for each value, then collect the ones that only occur once:
for (int i = 0; i < data.length; i++) {
for (int j = 0; j < data[i].length; j++) {
uniqueValues[data[i][j] - 2000000]++;
}
}
int uniqueCounter = 0;
for (int i = 0; i < uniqueValue.length; i++) {
if (uniqueValues[i] == 1) {
uniqueValues[uniqueCounter++] = i + 2000000;
}
}
I have four almost same loops in Java with different methods:
int Point;
for (int i = 0; i < 10; i++)
{
if (isLeft())
Point = i;
}
for (int i = 0; i < 10; i++)
{
if (isRight())
Point = i;
}
for (int i = 0; i < 10; i++)
{
if (isAbove())
Point = i;
}
for (int i = 0; i < 10; i++)
{
if (isUnder())
Point = i;
}
Can I merge all loops to one?
You could chain the conditions with the || operator:
for (int i = 0; i < 10; i++) {
if (isLeft() || isRight() || isAbove() ||isUnder()) {
Point = i;
}
}
You can't merge the loops if you want the current control flow to be retained.
Currently:
All four functions run 10 times each
isRight will not be called until isLeft will no longer be called, etc.
Point is a stronger function of the result of isUnder than isAbove, etc.
You could consider using || within an if statement, but I think you are likely to introduce bugs, assuming of course that the code currently runs as intended.
Not too sure what you are trying to do because all the conditions seem to change the value of point to the last value of the iterator that is 9.
but the snippet bellow can allow you to do so.
for (int i = 0; i < 10; i++){
if (isLeft())
int Point = i;
if (isRight())
int Point = i;
if (isAbove())
int Point = i;
if (isUnder())
int Point = i;
}
another version of this will joint all the conditions
for (int i = 0; i < 10; i++) {
if (isLeft() || isRight() || isAbove() ||isUnder()) {
Point = i;
}
}
So here's my problem. I have to write a program that will fill array with random numbers(and it's ok), then it's necessary to print only even index numbers or only odd value numbers(j). Tried like this but when i put if statement and it shows every even number (index and value-the second in array) so it wrong. What should i do so?
import java.util.Random;
public class Array {
public static void main(String[] args)
{
int rows = 5;
int colu = 2;
Random r = new Random();
int [][] array = new int [rows][colu];
for(int row = 0; row < array.length; row++)
{
for(int col = 0; col < array[row].length; col++)
{
array[row][col] = r.nextInt(10);
}
}
for(int i = 0; i < array.length; i++)
{
for(int j = 0; j < array[i].length; j++)
{
if(array[i][j]%2 == 0){
System.out.print(array[i][j] + " ");
}
}
}
System.out.println();
}
}
Thanks
I'm going to take a stab at this but I'm not sure if I quite understand yet.
int array[][] = new int[row][col];
// ... populate the array with random numbers, works fine...
// Let's traverse the first column.
for (int i = 0; i < row; i++) {
int value = array[i][0]; // col 0 means first column
if (value % 2 == 0) {
// ...
}
}
// Let's traverse the second column.
for (int i = 0; i < row; i++) {
int value = array[i][1]; // col 1 means second column
// ...
}
Is this what you mean? If it is, do you see the pattern and how you could generalize this and make the code a bit smaller?
Just implement this formula in your "if" statement :
(Number × 2 )/4 ==0. You will always get even numbers. You can handle the rest :D