diff --git a/diuf/sudoku/Settings.java b/diuf/sudoku/Settings.java index 284db06..fcc692b 100644 --- a/diuf/sudoku/Settings.java +++ b/diuf/sudoku/Settings.java @@ -18,8 +18,8 @@ public class Settings { public final static int VERSION = 1; public final static int REVISION = 15; - public final static String SUBREV = ".5"; - public final static String releaseDate = "2019-12-30"; + public final static String SUBREV = ".6"; + public final static String releaseDate = "2019-12-31"; public final static String releaseYear = "2019"; public final static String releaseLicence = "Lesser General Public License"; public final static String releaseLicenceMini = "LGPL"; @@ -52,6 +52,7 @@ public class Settings { private boolean isAntiKnight = false;//(1,2) cells that are a knight chess move away private boolean isVanilla = true;//Check to see if we are using variants (to minimize extra code calls use in Vanilla sudoku) private boolean isForbiddenPairs = false;//Check to see if we are using Forbidden pairs (NC or cNC, ...) but doeasn't apply to Antichess + private int variantCount = 0;//Number of variants used private int whichNC = 0;//0: disabled (default) 1:NC 1-9 but excludes (9,1) 2:cNC which include (1,9) private boolean isVLatin = true;//Check to see if we are using variants with Latin Square(to minimize extra code calls use in Latin square) public String variantString = ""; @@ -172,6 +173,9 @@ public PrintWriter getLogWriter() { private Settings() { init(); load(); + Settings_Variants(); + if (isBringBackSE121()) + Settings_BBSE121(); } public void Settings_BBSE121() { @@ -201,6 +205,7 @@ public boolean islkSudokuURUL() { } public void setRevisedRating(int revisedRating) { this.revisedRating = revisedRating; + save(); } public int revisedRating() { return revisedRating; @@ -276,46 +281,80 @@ public boolean isVLatin() { public void toggleVariants() { this.isVanilla = true; this.isVLatin = true; + int variantsCount = 0; String temp = ""; if (!isBlocks()) { temp += "Latin Square "; this.isVanilla = false; } - if (isDG()) + if (isDG()) { temp += "Disjoint Groups "; - if (isWindows()) + variantsCount++; + } + if (isWindows()){ temp += "Windows "; - if (isAsterisk()) + variantsCount++; + } + if (isAsterisk()){ temp += "Asterisk "; - if (isCD()) + variantsCount++; + } + if (isCD()){ temp += "Center Dot "; - if (isGirandola()) + variantsCount++; + } + if (isGirandola()){ temp += "Girandola "; - if (isX()) + variantsCount++; + } + if (isX()){ temp += "X "; - if (isToroidal()) + variantsCount++; + } + if (isToroidal()){ temp += "Toroidal "; - if (isAntiFerz()) + variantsCount++; + } + if (isAntiFerz()){ temp += "Anti-King "; - if (isAntiKnight()) + variantsCount++; + } + if (isAntiKnight()){ temp += "Anti-kNight "; + variantsCount++; + } if (isForbiddenPairs()) - if (whichNC == 1) + if (whichNC == 1){ temp += "NC "; + variantsCount++; + } else - if (whichNC == 2) + if (whichNC == 2){ temp += "NC+ "; + variantsCount++; + } if (isDG() || isWindows() || isX() || isGirandola() || isCD() || isAsterisk() || isAntiFerz() || isAntiKnight()/* || isForbiddenPairs()*/) { this.isVLatin = false; this.isVanilla = false; } + if (!isVLatin) + setBringBackSE121(false); this.variantString = temp; + setVariantsCount(variantsCount); Grid.changeVisibleCells(); } + public void setVariantsCount(int value){ + this.variantCount = value; + } + + public int variantCount() { + return this.variantCount; + } + public void setBlocks(boolean isBlocks) { this.isBlocks = isBlocks; - toggleVariants();; + toggleVariants(); save(); } @@ -325,7 +364,7 @@ public boolean isBlocks() { public void setDG(boolean value) { this.isDG = value; - toggleVariants();; + toggleVariants(); save(); } @@ -345,7 +384,7 @@ public boolean isX() { public void setWindows(boolean value) { this.isWindows = value; - toggleVariants();; + toggleVariants(); save(); } @@ -355,7 +394,7 @@ public boolean isWindows() { public void setGirandola(boolean value) { this.isGirandola = value; - toggleVariants();; + toggleVariants(); save(); } @@ -365,7 +404,7 @@ public boolean isGirandola() { public void setCD(boolean value) { this.isCD = value; - toggleVariants();; + toggleVariants(); save(); } @@ -426,7 +465,7 @@ public boolean isForbiddenPairs() { public void setNC(int value) { this.whichNC = value; if (value > 0) - setForbiddenPairs(true); + getInstance().setForbiddenPairs(true); toggleVariants(); save(); } @@ -511,6 +550,10 @@ private void init() { techniques.remove(SolvingTechnique.NakedTripletGen); techniques.remove(SolvingTechnique.NakedQuadGen); techniques.remove(SolvingTechnique.NakedQuintGen); + if (isForbiddenPairs()) { + techniques.remove(SolvingTechnique.UniqueLoop); + techniques.remove(SolvingTechnique.BivalueUniversalGrave); + } } private void initVariants() { @@ -532,8 +575,14 @@ private void initVariants() { techniques.remove(SolvingTechnique.BivalueUniversalGrave); } if (isVLatin()) - init(); + if (isBringBackSE121()) + init121(); + else + init(); + else + setBringBackSE121(false); } + private void init121() { techniques = EnumSet.allOf(SolvingTechnique.class); //The following techniques are not part of SE121 @@ -560,7 +609,8 @@ public void load() { isAntialiasing = prefs.getBoolean("isAntialiasing", isAntialiasing); isShowingCandidates = prefs.getBoolean("isShowingCandidates", isShowingCandidates); isShowingCandidateMasks = prefs.getBoolean("isShowingCandidateMasks", isShowingCandidateMasks); - isBringBackSE121 = prefs.getBoolean("BringBackSE121", isBringBackSE121); + isBringBackSE121 = prefs.getBoolean("BringBackSE121", isBringBackSE121); + revisedRating = prefs.getInt("RevisedRatings", revisedRating); lookAndFeelClassName = prefs.get("lookAndFeelClassName", lookAndFeelClassName); } catch (SecurityException ex) { // Maybe we are running from an applet. Do nothing @@ -584,8 +634,11 @@ public void save() { prefs.putBoolean("isCD", isCD); prefs.putBoolean("isGirandola", isGirandola); prefs.putBoolean("isForbiddenPairs", isForbiddenPairs); + prefs.putInt("whichNC", whichNC); prefs.putBoolean("isAntiFerz", isAntiFerz); - prefs.putBoolean("isAntiKnight", isAntiKnight); + prefs.putBoolean("isAntiKnight", isAntiKnight); + prefs.putBoolean("BringBackSE121", isBringBackSE121); + prefs.putInt("RevisedRatings", revisedRating); if (lookAndFeelClassName != null) prefs.put("lookAndFeelClassName", lookAndFeelClassName); try { diff --git a/diuf/sudoku/generator/Generator.java b/diuf/sudoku/generator/Generator.java index 58e73ad..69e5276 100644 --- a/diuf/sudoku/generator/Generator.java +++ b/diuf/sudoku/generator/Generator.java @@ -68,6 +68,8 @@ public Grid generate(Random rnd, Symmetry symmetry) { // Build the solution Grid grid = new Grid(); + Solver solver = new Solver(grid); + solver.want = 0; boolean result = analyser.solveRandom(grid, rnd); assert result; Grid solution = new Grid(); @@ -111,7 +113,6 @@ public Grid generate(Random rnd, Symmetry symmetry) { if (grid.getCellValue(p.x, p.y) != 0) { //cell.setValue(0); grid.setCellValue(p.x, p.y, 0); - cellRemoved = true; } } @@ -122,6 +123,17 @@ public Grid generate(Random rnd, Symmetry symmetry) { // Cells successfully removed: still a unique solution isSuccess = true; //successes += 1; + //Following code is to handle Naturally difficult variants: 1to9only + if (Settings.getInstance().isAntiFerz() || Settings.getInstance().isAntiKnight() || Settings.getInstance().whichNC() > 0 || Settings.getInstance().variantCount() > 1) { + try { solver.getDifficulty(); } catch (UnsupportedOperationException ex) { solver.difficulty = solver.pearl = solver.diamond = 20.0; } + if ( solver.difficulty == 20.0 ) { + for (Point p : points){ + grid.setGiven(y * 9 + x); + grid.setCellValue(p.x, p.y, solution.getCellValue(p.x, p.y)); + } + return grid; + } + } } else if (state == 0) { assert false : "Invalid grid"; } else { diff --git a/diuf/sudoku/gui/SudokuFrame.java b/diuf/sudoku/gui/SudokuFrame.java index df6ed29..bf57cd8 100644 --- a/diuf/sudoku/gui/SudokuFrame.java +++ b/diuf/sudoku/gui/SudokuFrame.java @@ -1507,8 +1507,10 @@ private JCheckBoxMenuItem getMitRegularNC() { mitRegularNC.setToolTipText("Adjacent cells can't have consecutive numbers (Excludes 1,9)"); mitRegularNC.addItemListener(new java.awt.event.ItemListener() { public void itemStateChanged(java.awt.event.ItemEvent e) { - if (mitRegularNC.isSelected()) + if (mitRegularNC.isSelected()) { mitCyclicNC.setSelected(false); + mitBringBackSE121.setSelected(false); + } Settings.getInstance().setNC(mitCyclicNC.isSelected() ? 2 : 0); Settings.getInstance().setNC(mitRegularNC.isSelected() ? 1 : 0); Settings.getInstance().toggleVariants(); @@ -1532,8 +1534,10 @@ private JCheckBoxMenuItem getMitCyclicNC() { mitCyclicNC.setToolTipText("Adjacent cells can't have consecutive numbers (Includes 1,9)"); mitCyclicNC.addItemListener(new java.awt.event.ItemListener() { public void itemStateChanged(java.awt.event.ItemEvent e) { - if (mitCyclicNC.isSelected()) + if (mitCyclicNC.isSelected()) { mitRegularNC.setSelected(false); + mitBringBackSE121.setSelected(false); + } Settings.getInstance().setNC(mitRegularNC.isSelected() ? 1 : 0); Settings.getInstance().setNC(mitCyclicNC.isSelected() ? 2 : 0); Settings.getInstance().toggleVariants(); @@ -1589,6 +1593,9 @@ private JCheckBoxMenuItem getMitAntiFerz() { mitAntiFerz.addItemListener(new java.awt.event.ItemListener() { public void itemStateChanged(java.awt.event.ItemEvent e) { Settings.getInstance().setAntiFerz(mitAntiFerz.isSelected()); + if (Settings.getInstance().isAntiFerz()) { + mitBringBackSE121.setSelected(false); + } Settings.getInstance().toggleVariants(); engine.clearGrid(); initialize(false); @@ -1610,6 +1617,9 @@ private JCheckBoxMenuItem getMitAntiKnight() { mitAntiKnight.addItemListener(new java.awt.event.ItemListener() { public void itemStateChanged(java.awt.event.ItemEvent e) { Settings.getInstance().setAntiKnight(mitAntiKnight.isSelected()); + if (Settings.getInstance().isAntiKnight()) { + mitBringBackSE121.setSelected(false); + } Settings.getInstance().toggleVariants(); engine.clearGrid(); initialize(false); @@ -1669,6 +1679,9 @@ private JCheckBoxMenuItem getMitX() { mitX.addItemListener(new java.awt.event.ItemListener() { public void itemStateChanged(java.awt.event.ItemEvent e) { Settings.getInstance().setX(mitX.isSelected()); + if (Settings.getInstance().isX()) { + mitBringBackSE121.setSelected(false); + } Settings.getInstance().toggleVariants(); engine.clearGrid(); initialize(false); @@ -1690,6 +1703,9 @@ private JCheckBoxMenuItem getMitDG() { mitDG.addItemListener(new java.awt.event.ItemListener() { public void itemStateChanged(java.awt.event.ItemEvent e) { Settings.getInstance().setDG(mitDG.isSelected()); + if (Settings.getInstance().isDG()) { + mitBringBackSE121.setSelected(false); + } Settings.getInstance().toggleVariants(); engine.clearGrid(); initialize(false); @@ -1711,6 +1727,9 @@ private JCheckBoxMenuItem getMitWindows() { mitWindows.addItemListener(new java.awt.event.ItemListener() { public void itemStateChanged(java.awt.event.ItemEvent e) { Settings.getInstance().setWindows(mitWindows.isSelected()); + if (Settings.getInstance().isWindows()) { + mitBringBackSE121.setSelected(false); + } Settings.getInstance().toggleVariants(); engine.clearGrid(); initialize(false); @@ -1737,6 +1756,7 @@ public void itemStateChanged(java.awt.event.ItemEvent e) { Settings.getInstance().setGirandola(false); mitCD.setSelected(false); mitGirandola.setSelected(false); + mitBringBackSE121.setSelected(false); } Settings.getInstance().toggleVariants(); engine.clearGrid(); @@ -1764,6 +1784,7 @@ public void itemStateChanged(java.awt.event.ItemEvent e) { Settings.getInstance().setGirandola(false); mitAsterisk.setSelected(false); mitGirandola.setSelected(false); + mitBringBackSE121.setSelected(false); } Settings.getInstance().toggleVariants(); engine.clearGrid(); @@ -1791,6 +1812,7 @@ public void itemStateChanged(java.awt.event.ItemEvent e) { Settings.getInstance().setCD(false); mitAsterisk.setSelected(false); mitCD.setSelected(false); + mitBringBackSE121.setSelected(false); } Settings.getInstance().toggleVariants(); engine.clearGrid(); @@ -1994,7 +2016,8 @@ private JCheckBoxMenuItem getMitBringBackSE121() { mitBringBackSE121.setSelected(Settings.getInstance().isBringBackSE121()); mitBringBackSE121.addItemListener(new java.awt.event.ItemListener() { public void itemStateChanged(java.awt.event.ItemEvent e) { - Settings.getInstance().setBringBackSE121(mitBringBackSE121.isSelected()); + Settings.getInstance().setBringBackSE121(mitBringBackSE121.isSelected() && Settings.getInstance().isVLatin()); + mitBringBackSE121.setSelected(Settings.getInstance().isBringBackSE121()); if (Settings.getInstance().isBringBackSE121()) { //uniquess fix false //BUG fix false diff --git a/diuf/sudoku/solver/Solver.java b/diuf/sudoku/solver/Solver.java index 1aed726..d5edbe5 100644 --- a/diuf/sudoku/solver/Solver.java +++ b/diuf/sudoku/solver/Solver.java @@ -626,6 +626,7 @@ private Hint getSingleHint() { } catch (InterruptedException willHappen) {} return accu.getHint(); } + public void getDifficulty(serate.Formatter formatter) { Grid backup = new Grid(); grid.copyTo(backup); @@ -711,6 +712,87 @@ else if (want != 0 && difficulty > pearl) { } } + public void getDifficulty() { + Grid backup = new Grid(); + grid.copyTo(backup); + boolean logStep = Settings.getInstance().isLog(); + PrintWriter logWriter = Settings.getInstance().getLogWriter(); + int stepCount = 0; + try { + difficulty = 0; + pearl = 0.0; + diamond = 0.0; + ERtN ="No solution"; + EPtN ="No solution"; + EDtN ="No solution"; + shortERtN ="O"; + shortEPtN ="O"; + shortEDtN ="O"; + while (!grid.isSolved()) { + Hint hint = null; + try { + hint = getSingleHint(); + if(hint != null) { + assert hint instanceof Rule; + Rule rule = (Rule)hint; + double ruleDiff = rule.getDifficulty(); + String ruleName = rule.getName(); + String ruleNameShort = rule.getShortName(); + //lksudoku, log steps + if (logStep) { + ++stepCount; + logWriter.println("Step "+stepCount+": rate "+ruleDiff); + logWriter.println(rule.toString()); + } + if (ruleDiff > difficulty) { + difficulty = ruleDiff; + ERtN = ruleName; + shortERtN = ruleNameShort; + } + } + } + catch (UnsupportedOperationException ex) { + difficulty = pearl = diamond = 0.0; + ERtN = EPtN = EDtN = "No solution"; + shortERtN = shortEPtN = shortEDtN = "O"; + } + if (hint == null) { + difficulty = 20.0; + ERtN = "Beyond solver"; + shortERtN = "xx"; + break; + } + hint.apply(grid); + if (pearl == 0.0) { + if (diamond == 0.0){ + diamond = difficulty; + EDtN = ERtN; + shortEDtN = shortERtN; + } + if (hint.getCell() != null) { + if (want == 'd' && difficulty > diamond) { + difficulty = 20.0; + ERtN = "Beyond solver"; + shortERtN = "xx"; + break; + } + pearl = difficulty; + EPtN = ERtN; + shortEPtN = shortERtN; + } + } + else if (want != 0 && difficulty > pearl) { + difficulty = 20.0; + ERtN = "Beyond solver"; + shortERtN = "xx"; + break; + } + } + } finally { + backup.copyTo(grid); + } + } + public void getHintsHint() { Grid backup = new Grid(); grid.copyTo(backup); diff --git a/diuf/sudoku/solver/rules/lockedNC.html b/diuf/sudoku/solver/rules/lockedNC.html index 0cdf45f..7b90f47 100644 --- a/diuf/sudoku/solver/rules/lockedNC.html +++ b/diuf/sudoku/solver/rules/lockedNC.html @@ -3,7 +3,7 @@
In {4} (outlined), all the cells with value