package sudoku.solver; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Random; import sudoku.structure.Cell; import sudoku.structure.MultiDoku; public class HintHelper { public record Hint(Cell cell, int newValue) {} /** * Si possible, donne un indice sur la résolution du doku passé en paramètre, * selon la méthode de résolution rensaignée. * @param doku MultiDoku, multidoku pour lequel on veut un indice * @param solver Solver, méthode de résolution souhaitée * @return Hint, indice sur une case à remplir, valant null si le doku n'a pas de solution. */ public static Hint getHint(MultiDoku doku, Solver solver) { doku.getStateManager().pushState(); doku.clearMutableCells(); if (!solver.solve(doku)) return null; var stateSolved = doku.getStateManager().popAndGetState(); // find differences Map newValues = new HashMap<>(); for (var entry : stateSolved.entrySet()) { Cell cell = entry.getKey(); // we only want the cells that can be filled if (!cell.isMutable()) continue; int oldValue = cell.getSymbolIndex(); int newValue = stateSolved.get(cell); if (oldValue == newValue) continue; // we have to clear the cell if (newValue == Cell.NOSYMBOL) return new Hint(cell, newValue); // we have to change the cell value if (oldValue != Cell.NOSYMBOL) return new Hint(cell, newValue); // there is a valid move newValues.put(cell, newValue); } // this is too complex just for fetching a random entry, but whatever ... Random r = new Random(); List cells = new ArrayList<>(newValues.keySet()); Cell randomCell = cells.get(r.nextInt(cells.size())); int randomCellValue = newValues.get(randomCell); return new Hint(randomCell, randomCellValue); } }