Skip to content

Commit

Permalink
Some changes
Browse files Browse the repository at this point in the history
  • Loading branch information
Zomis committed Jul 11, 2014
1 parent 64ff65a commit ca592a2
Show file tree
Hide file tree
Showing 6 changed files with 256 additions and 189 deletions.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -4,3 +4,4 @@
*.jar
*.war
*.ear
/bin
266 changes: 150 additions & 116 deletions src/net/zomis/sudoku/SudokuBoard.java
Expand Up @@ -5,6 +5,7 @@
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
Expand All @@ -13,6 +14,30 @@

public class SudokuBoard {

private int mMaxValue;
private int rowAddIndex;

private Set<SudokuRule> rules = new HashSet<SudokuRule>();


private SudokuTile[][] tiles;

public SudokuBoard(int width, int height) {
this(width, height, Math.max(width, height));
}

public SudokuBoard(int width, int height, int maxValue) {
mMaxValue = maxValue;
tiles = new SudokuTile[width][height];
createTiles();
// If maxValue is not width or height, then adding line rules would be stupid
if (mMaxValue == width || mMaxValue == height) {
IntStream.range(0, getWidth ()).forEach(x -> rules.add(new SudokuRule(getColumn(x), "Row " + x)));
IntStream.range(0, getHeight()).forEach(y -> rules.add(new SudokuRule(getRow(y), "Col " + y)));
}
}


public SudokuBoard(SudokuBoard copy) {
mMaxValue = copy.mMaxValue;
tiles = new SudokuTile[copy.getWidth()][copy.getHeight()];
Expand All @@ -35,186 +60,195 @@ public SudokuBoard(SudokuBoard copy) {
}
}

public SudokuBoard(int width, int height, int maxValue) {
mMaxValue = maxValue;
tiles = new SudokuTile[width][height];
createTiles();
// If maxValue is not width or height, then adding line rules would be stupid
if (mMaxValue == width || mMaxValue == height) {
IntStream.range(0, getWidth ()).forEach(x -> rules.add(new SudokuRule(GetCol(x), "Row " + x)));
IntStream.range(0, getHeight()).forEach(y -> rules.add(new SudokuRule(GetRow(y), "Col " + y)));
void addBoxesCount(int boxesX, int boxesY) {
int sizeX = getWidth() / boxesX;
int sizeY = getHeight() / boxesY;

Collection<ImmutablePoint> boxes = SudokuFactory.box(sizeX, sizeY);
for (ImmutablePoint pos : boxes) {
Collection<SudokuTile> boxTiles = TileBox(pos.getX() * sizeX,
pos.getY() * sizeY, sizeX, sizeY);
createRule("Box at (" + pos.getX() + ", " + pos.getY() + ")",
boxTiles);
}
}

public SudokuBoard(int width, int height) {
this(width, height, Math.max(width, height));
public SudokuBoard addRow(String s) {
// Method for initializing a board from string
for (int i = 0; i < s.length(); i++) {
SudokuTile tile = tiles[i][rowAddIndex];
if (s.charAt(i) == '/') {
tile.block();
continue;
}
int value = s.charAt(i) == '.' ? 0 : Character.digit(s.charAt(i),
10);
tile.setValue(value);
}
rowAddIndex++;
return this;
}

private int mMaxValue;
public boolean checkValid() {
return rules.stream().allMatch(rule -> rule.checkValid());
}

public void createRule(String description, Collection<SudokuTile> tiles) {
if (tiles.stream().anyMatch(tile -> tile.IsBlocked()))
throw new IllegalArgumentException("Unable to create rule since a tile in it is blocked: " + tiles);
rules.add(new SudokuRule(tiles, description));
}

public void createRule(String description, Stream<SudokuTile> tiles) {
createRule(description, tiles.collect(Collectors.toList()));
}

private void createTiles() {
SudokuFactory.box(getWidth(), getHeight())
.stream().forEach(pos -> tiles[pos.getX()][pos.getY()] = new SudokuTile(pos.getX(), pos.getY(), mMaxValue));
}

Collection<SudokuTile> TileBox(int startX, int startY, int sizeX, int sizeY) {
Collection<ImmutablePoint> positions = SudokuFactory.box(sizeX, sizeY);
return positions.stream()
.map(pos -> tiles[startX + pos.getX()][startY + pos.getY()])
.collect(Collectors.toList());
private Stream<SudokuTile> getColumn(int col) {
return IntStream.range(0, getHeight()).mapToObj(i -> tiles[col][i]);
}
public int getHeight() {
return tiles[0].length;
}

private Collection<SudokuTile> GetRow(int row) {
private Collection<SudokuTile> getRow(int row) {
return IntStream.range(0, getWidth()).mapToObj(i -> tiles[i][row])
.collect(Collectors.toList());
}

private Stream<SudokuTile> GetCol(int col) {
return IntStream.range(0, getHeight()).mapToObj(i -> tiles[col][i]);
}

private Set<SudokuRule> rules = new HashSet<SudokuRule>();
private SudokuTile[][] tiles;

public int getWidth() {
return tiles.length;
}

public int getHeight() {
return tiles[0].length;
public void output() {
for (int y = 0; y < getHeight(); y++) {
for (int x = 0; x < getWidth(); x++) {
System.out.print(tiles[x][y].toStringSimple());
}
System.out.println();
}
}

public void createRule(String description, Stream<SudokuTile> tiles) {
createRule(description, tiles.collect(Collectors.toList()));
}
public void CreateRule(String description, SudokuTile... tiles) {
rules.add(new SudokuRule(Arrays.asList(tiles), description));
void outputRules() {
// rules.stream().forEach(System.out::println);
for (SudokuRule rule : rules) {
System.out.println(String.join(",", rule.getTiles().toString()) + " - " + rule);
}
}

public void createRule(String description, Collection<SudokuTile> tiles) {
rules.add(new SudokuRule(tiles, description));
void resetSolutions() {
Arrays.stream(tiles).forEach(
arr -> Arrays.stream(arr)
.forEach(tile -> tile.resetPossibles()));
}

public boolean CheckValid() {
return rules.stream().allMatch(rule -> rule.checkValid());
SudokuProgress simplify() {
SudokuProgress result = SudokuProgress.NO_PROGRESS;
if (!checkValid())
return SudokuProgress.FAILED;

for (SudokuRule rule : rules)
result = result.combineWith(rule.solve());

return result;
}

public Collection<SudokuBoard> Solve() {
Collection<SudokuBoard> results = new ArrayList<SudokuBoard>();
ResetSolutions();
public Collection<SudokuBoard> solve() {
resetSolutions();
SudokuProgress simplify = SudokuProgress.PROGRESS;
while (simplify == SudokuProgress.PROGRESS)
simplify = Simplify();
simplify = simplify();

if (simplify == SudokuProgress.FAILED)
return results;
return new ArrayList<>();

// Find one of the values with the least number of alternatives, but
// that still has at least 2 alternatives

// var query = from rule in rules
// from tile in rule
// where tile.PossibleCount > 1
// orderby tile.PossibleCount ascending
// select tile;
// Find one of the values with the least number of alternatives,
// but that still has at least 2 alternatives

Stream<SudokuTile> query = rules
.stream()
.flatMap(
rule -> rule.getTiles().stream()
.filter(tile -> (tile.getPossibleCount() > 1)))
.sorted((a, b) -> Integer.compare(a.getPossibleCount(),
b.getPossibleCount()));
.sorted((tileA, tileB) -> Integer.compare(tileA.getPossibleCount(),
tileB.getPossibleCount()));

Optional<SudokuTile> chosen = query.findFirst();
if (!chosen.isPresent()) {
// The board has been completed, we're done!
Collection<SudokuBoard> results = new ArrayList<SudokuBoard>();
results.add(this);
return results;
}

System.out.println("SudokuTile: " + chosen.toString());

for (int value = 1; value <= mMaxValue; value++) {
// Iterate through all the valid possibles on the chosen square and
// pick a number for it
SudokuTile tile = chosen.get();
if (!tile.isPossibleValue(value))
continue;
SudokuBoard copy = new SudokuBoard(this);
copy.Tile(tile.getX(), tile.getY()).fix(value, "Trial and error");
for (SudokuBoard innerSolution : copy.Solve())
results.add(innerSolution);
}
// System.out.println("SudokuTile: " + chosen.toString());

SudokuTile tile = chosen.get();

Collection<SudokuBoard> results = new ArrayList<>();

results = IntStream
.rangeClosed(1, mMaxValue)
// .parallel()
.filter(value -> tile.isPossibleValue(value))
.mapToObj(value -> fixTile(tile, value))
.flatMap(board -> board.solve().stream())
.collect(Collectors.toList());


// for (int value = 1; value <= mMaxValue; value++) {
// // Iterate through all the valid possibles on the chosen square and pick a number for it
// if (!tile.isPossibleValue(value))
// continue;
// SudokuBoard newBoard = fixTile(tile, value);
// results.addAll(newBoard.solve());
// }
return results;
}

public void Output() {
for (int y = 0; y < getHeight(); y++) {
for (int x = 0; x < getWidth(); x++) {
System.out.print(tiles[x][y].toStringSimple());
}
System.out.println();
}
private SudokuBoard fixTile(SudokuTile tile, int value) {
SudokuBoard newBoard = new SudokuBoard(this);
newBoard.tile(tile.getX(), tile.getY()).fix(value, "Trial and error");
return newBoard;
}

public SudokuTile Tile(int x, int y) {
public SudokuTile tile(int x, int y) {
return tiles[x][y];
}

private int _rowAddIndex;

public SudokuBoard addRow(String s) {
// Method for initializing a board from string
for (int i = 0; i < s.length(); i++) {
SudokuTile tile = tiles[i][_rowAddIndex];
if (s.charAt(i) == '/') {
tile.block();
continue;
}
int value = s.charAt(i) == '.' ? 0 : Character.digit(s.charAt(i),
10);
tile.setValue(value);
}
_rowAddIndex++;
return this;
Collection<SudokuTile> TileBox(int startX, int startY, int sizeX, int sizeY) {
Collection<ImmutablePoint> positions = SudokuFactory.box(sizeX, sizeY);
return positions.stream()
.map(pos -> tiles[startX + pos.getX()][startY + pos.getY()])
.collect(Collectors.toList());
}

void ResetSolutions() {
Arrays.stream(tiles).forEach(
arr -> Arrays.stream(arr)
.forEach(tile -> tile.resetPossibles()));
public boolean isComplete() {
return this.rules.stream().allMatch(rule -> rule.checkComplete());
}

SudokuProgress Simplify() {
SudokuProgress result = SudokuProgress.NO_PROGRESS;
boolean valid = CheckValid();
if (!valid)
return SudokuProgress.FAILED;

for (SudokuRule rule : rules)
result = result.combineWith(rule.solve());

return result;
public boolean isRulesValid() {
Predicate<SudokuTile> tileInRule = tile -> rules.stream().anyMatch(rule -> rule.getTiles().contains(tile));
return Arrays.stream(tiles).flatMap(arr -> Arrays.stream(arr)).filter(tile -> !tile.IsBlocked())
.allMatch(tile -> tileInRule.test(tile));
}

void AddBoxesCount(int boxesX, int boxesY) {
int sizeX = getWidth() / boxesX;
int sizeY = getHeight() / boxesY;

Collection<ImmutablePoint> boxes = SudokuFactory.box(sizeX, sizeY);
for (ImmutablePoint pos : boxes) {
Collection<SudokuTile> boxTiles = TileBox(pos.getX() * sizeX,
pos.getY() * sizeY, sizeX, sizeY);
createRule("Box at (" + pos.getX() + ", " + pos.getY() + ")",
boxTiles);
}
public Set<SudokuRule> getRules() {
return new HashSet<>(this.rules);
}

void outputRules() {
// rules.stream().forEach(System.out::println);
for (SudokuRule rule : rules) {
System.out.println(String.join(",", rule.getTiles().toString()) + " - " + rule);
public void highlightRule(SudokuRule rule) {
for (int y = 0; y < getHeight(); y++) {
for (int x = 0; x < getWidth(); x++) {
if (rule.getTiles().contains(tile(x, y)))
System.out.print(" ");
else System.out.print(tiles[x][y].toStringSimple());
}
System.out.println();
}
}
}

0 comments on commit ca592a2

Please sign in to comment.