216 lines
6.3 KiB
Java
216 lines
6.3 KiB
Java
package gui;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
|
|
import sudoku.structure.Block;
|
|
import sudoku.structure.Cell;
|
|
import sudoku.structure.Coordinate;
|
|
import sudoku.structure.MultiDoku;
|
|
import sudoku.structure.Sudoku;
|
|
|
|
public class RenderableMultidoku {
|
|
|
|
private final MultiDoku doku;
|
|
private final List<Cell> cells;
|
|
private final List<Block> blocks;
|
|
private final int width;
|
|
private final int height;
|
|
|
|
private RenderableMultidoku(MultiDoku doku, List<Block> blocks, List<Cell> cells, int width, int height) {
|
|
this.cells = cells;
|
|
this.blocks = blocks;
|
|
this.width = width;
|
|
this.height = height;
|
|
this.doku = doku;
|
|
}
|
|
|
|
public boolean isResolved() {
|
|
return this.doku.isValid();
|
|
}
|
|
|
|
public int getWidth() {
|
|
return width;
|
|
}
|
|
|
|
public int getHeight() {
|
|
return height;
|
|
}
|
|
|
|
public List<Block> getBlocks() {
|
|
return this.blocks;
|
|
}
|
|
|
|
public Cell getCell(int x, int y) {
|
|
return getCell(y * width + x);
|
|
}
|
|
|
|
public Cell getCell(int index) {
|
|
return cells.get(index);
|
|
}
|
|
|
|
public boolean setCellValue(Cell cell, int value) {
|
|
for (Sudoku s : doku.getSubGrids()) {
|
|
int cellIndex = s.getCells().indexOf(cell);
|
|
// la cellule existe
|
|
if (cellIndex != -1) {
|
|
int cellX = cellIndex % s.getSize();
|
|
int cellY = cellIndex / s.getSize();
|
|
if (!s.canBePlaced(cellX, cellY, value)) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
cell.setSymbolIndex(value);
|
|
return true;
|
|
}
|
|
|
|
private static record PositionConstraint(Sudoku sudoku1, Sudoku sudoku2, Coordinate offset) {
|
|
}
|
|
|
|
private static Coordinate getConstraint(Sudoku sudoku1, Sudoku sudoku2) {
|
|
int blockWidth = sudoku1.getBlockWidth();
|
|
int blockHeight = sudoku1.getSize() / blockWidth;
|
|
for (int i = 0; i < sudoku1.getSize(); i++) {
|
|
for (int j = 0; j < sudoku2.getSize(); j++) {
|
|
Block block1 = sudoku1.getBlocks().get(i);
|
|
Block block2 = sudoku2.getBlocks().get(j);
|
|
if (block1 == block2) {
|
|
int block1X = i % blockHeight;
|
|
int block1Y = i / blockHeight;
|
|
int block2X = j % blockHeight;
|
|
int block2Y = j / blockHeight;
|
|
return new Coordinate((block1X - block2X) * blockWidth, (block1Y - block2Y) * blockHeight);
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private static boolean hasContraint(Sudoku sudoku1, Sudoku sudoku2, List<PositionConstraint> positionConstraints) {
|
|
for (PositionConstraint constraint : positionConstraints) {
|
|
if ((constraint.sudoku1 == sudoku1 && constraint.sudoku2 == sudoku2)
|
|
|| (constraint.sudoku1 == sudoku2 && constraint.sudoku2 == sudoku1))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private static Coordinate getMinSudokuOffset(Map<Sudoku, Coordinate> sudokusOffset) {
|
|
Coordinate minCoordinate = null;
|
|
for (Coordinate coordinate : sudokusOffset.values()) {
|
|
if (minCoordinate == null)
|
|
minCoordinate = coordinate;
|
|
minCoordinate = new Coordinate(Math.min(minCoordinate.getX(), coordinate.getX()),
|
|
Math.min(minCoordinate.getY(), coordinate.getY()));
|
|
}
|
|
return minCoordinate;
|
|
}
|
|
|
|
private static Coordinate getMaxSudokuCoordinate(Map<Sudoku, Coordinate> sudokusOffset) {
|
|
Coordinate maxCoordinate = null;
|
|
Sudoku maxSudoku = null;
|
|
float maxDistanceSquared = 0;
|
|
for (var entry : sudokusOffset.entrySet()) {
|
|
Coordinate coordinate = entry.getValue();
|
|
float distanceSquared = coordinate.getX() * coordinate.getX() + coordinate.getY() * coordinate.getY();
|
|
if (maxCoordinate == null) {
|
|
maxCoordinate = coordinate;
|
|
maxDistanceSquared = distanceSquared;
|
|
maxSudoku = entry.getKey();
|
|
}
|
|
|
|
if (distanceSquared > maxDistanceSquared) {
|
|
maxDistanceSquared = distanceSquared;
|
|
maxSudoku = entry.getKey();
|
|
maxCoordinate = coordinate;
|
|
}
|
|
}
|
|
|
|
int blockWidth = maxSudoku.getBlockWidth();
|
|
int blockHeight = maxSudoku.getSize() / blockWidth;
|
|
|
|
return new Coordinate(maxCoordinate.getX() + maxSudoku.getSize(), maxCoordinate.getY() + maxSudoku.getSize());
|
|
}
|
|
|
|
public static RenderableMultidoku fromMultidoku(MultiDoku doku) {
|
|
if (doku.getNbSubGrids() == 1) {
|
|
Sudoku sudoku = doku.getSubGrid(0);
|
|
return new RenderableMultidoku(doku, sudoku.getBlocks(), sudoku.getCells(), sudoku.getSize(),
|
|
sudoku.getSize());
|
|
}
|
|
Map<Sudoku, Coordinate> sudokusOffset = new HashMap<>();
|
|
// coordinates in cell
|
|
List<PositionConstraint> positionConstraints = new ArrayList<>();
|
|
for (Sudoku sudoku1 : doku.getSubGrids()) {
|
|
for (Sudoku sudoku2 : doku.getSubGrids()) {
|
|
if (sudoku1 == sudoku2)
|
|
continue;
|
|
|
|
Coordinate constraint = getConstraint(sudoku1, sudoku2);
|
|
|
|
if (constraint != null && !hasContraint(sudoku1, sudoku2, positionConstraints)) {
|
|
positionConstraints.add(new PositionConstraint(sudoku1, sudoku2, constraint));
|
|
}
|
|
}
|
|
}
|
|
|
|
for (PositionConstraint constraint : positionConstraints) {
|
|
if (!sudokusOffset.containsKey(constraint.sudoku1) && !sudokusOffset.containsKey(constraint.sudoku2)) {
|
|
sudokusOffset.put(constraint.sudoku1, new Coordinate(0, 0));
|
|
sudokusOffset.put(constraint.sudoku2, constraint.offset());
|
|
}
|
|
|
|
if (sudokusOffset.containsKey(constraint.sudoku1)) {
|
|
sudokusOffset.put(constraint.sudoku2, constraint.offset.add(sudokusOffset.get(constraint.sudoku1)));
|
|
} else {
|
|
sudokusOffset.put(constraint.sudoku1, constraint.offset.add(sudokusOffset.get(constraint.sudoku2)));
|
|
}
|
|
|
|
}
|
|
|
|
Coordinate minCoordinate = getMinSudokuOffset(sudokusOffset);
|
|
|
|
for (var entry : sudokusOffset.entrySet()) {
|
|
entry.setValue(entry.getValue().sub(minCoordinate));
|
|
}
|
|
|
|
Coordinate maxCoordinate = getMaxSudokuCoordinate(sudokusOffset);
|
|
|
|
List<Block> blocks = new ArrayList<>();
|
|
List<Cell> cells = new ArrayList<>(maxCoordinate.getX() * maxCoordinate.getY());
|
|
for (int i = 0; i < maxCoordinate.getX() * maxCoordinate.getY(); i++) {
|
|
cells.add(null);
|
|
}
|
|
|
|
for (var entry : sudokusOffset.entrySet()) {
|
|
Sudoku sudoku = entry.getKey();
|
|
Coordinate offset = entry.getValue();
|
|
|
|
for (int x = 0; x < sudoku.getSize(); x++) {
|
|
for (int y = 0; y < sudoku.getSize(); y++) {
|
|
Cell cell = sudoku.getCell(x, y);
|
|
int absoluteX = x + offset.getX();
|
|
int absoluteY = y + offset.getY();
|
|
cells.set(absoluteY * maxCoordinate.getX() + absoluteX, cell);
|
|
}
|
|
}
|
|
|
|
for (Block block : sudoku.getBlocks()) {
|
|
if (!blocks.contains(block)) {
|
|
blocks.add(block);
|
|
}
|
|
}
|
|
}
|
|
|
|
return new RenderableMultidoku(doku, blocks, cells, maxCoordinate.getX(), maxCoordinate.getY());
|
|
}
|
|
|
|
public MultiDoku getDoku() {
|
|
return doku;
|
|
}
|
|
|
|
}
|