Your HashSet approach looks quite good, but needs a little tweaking...
The assumption is: when the first block is duplication free and the same position in all blocks is duplication free too, then the sudoku is solved.
In you outer loop you should go trough the values of the first block only.
You should add the current value to the "first block check set" and check, that the all the blocks have a different number at the same position by an inner loop with its own "check set":
First iteration
1## 2## 3##
### ### ###
### ### ###
4## 5## 5##
### ### ###
### ### ###
7## 8## 9##
### ### ###
### ### ###
firstBlock: [1]
second iteration
#2# #3# #4#
### ### ###
### ### ###
#5# #6# #7#
### ### ###
### ### ###
#8# #9# #1#
### ### ###
### ### ###
firstBlock: [1,2]
The big trick is to avoid separate loops for x and y coordinates.
Since Java is an object oriented programming language I suggest to use objects to determine the coordinates. We could hold them in an Array (set a bookmark,I usually say "Collection" instead...) and iterate ofer it with a simple forech loop...
Also we have to deal with a fix number of objects we know in advance (there a 9 blocks with 9 positions in each...)
so I suggest using Java enums like this:
so you logic should look like this:
public class SudokuCheck {
enum SudokuPosition {
p11(0, 0), p12(0, 1), p13(0, 2),
p21(1, 0), p22(1, 1), p23(1, 2),
p31(2, 0), p32(2, 1), p33(2, 2);
private final int x;
private final int y;
SudokuPosition(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {return x;}
public int getY() {return y;}
}
boolean check(int[][] sudoku) {
Set<Integer> firstBlockUniqueNumbers = new HashSet<>();
for (SudokuPosition inBlock : SudokuPosition.values()) {
firstBlockUniqueNumbers.add(sudoku[inBlock.x][inBlock.y]);
Set<Integer> samePosInOtherBlocksUniqueNumbers = new HashSet<>();
for (SudokuPosition ofBlock : SudokuPosition.values()) {
int sameXinAll = inBlock.x + offset(ofBlock.x);
int sameYinAll = inBlock.y + offset(ofBlock.y);
samePosInOtherBlocksUniqueNumbers.add(sudoku[sameXinAll][sameYinAll]);
}
if (9 > samePosInOtherBlocksUniqueNumbers.size())
// numbers where not unique at current block position
// through all the blocks
return false;
}
return 9 == firstBlockUniqueNumbers.size();
}
private int offset(int xOrY) {
return xOrY * 3;
}
}
I hopefully demonstrated the usefulness of Java enums and how important good identifier names are.
I think this approach could be improved in 2 ways:
- using the Java 8 Stream API may replace the forech loops
- the names of the position elements somehow repeat their constructor values which may lead to nasty mistakes. The latter may be replaces by some clever calculation on the constant name which is available via
name(), but for this demonstration it might be good enough as it is...