From a024002321724498b4b64065f015e7f3d2c243e0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Beno=C3=AEt=20Harrault?= <benoit@harrault.fr>
Date: Sun, 25 Jul 2021 18:58:02 +0200
Subject: [PATCH] Improve tip on grid if cell with wrong value, compute solved
 grid on new game

---
 android/gradle.properties                     |   4 +-
 .../metadata/android/en-US/changelogs/39.txt  |   1 +
 .../metadata/android/fr-FR/changelogs/39.txt  |   1 +
 lib/entities/cell.dart                        |   6 +-
 lib/provider/data.dart                        |   6 +
 lib/utils/board_utils.dart                    | 112 +++++++++++++++---
 lib/utils/game_utils.dart                     |  49 +++-----
 7 files changed, 132 insertions(+), 47 deletions(-)
 create mode 100644 fastlane/metadata/android/en-US/changelogs/39.txt
 create mode 100644 fastlane/metadata/android/fr-FR/changelogs/39.txt

diff --git a/android/gradle.properties b/android/gradle.properties
index 604fc08..c8bbff9 100644
--- a/android/gradle.properties
+++ b/android/gradle.properties
@@ -1,5 +1,5 @@
 org.gradle.jvmargs=-Xmx1536M
 android.useAndroidX=true
 android.enableJetifier=true
-app.versionName=0.0.38
-app.versionCode=38
+app.versionName=0.0.39
+app.versionCode=39
diff --git a/fastlane/metadata/android/en-US/changelogs/39.txt b/fastlane/metadata/android/en-US/changelogs/39.txt
new file mode 100644
index 0000000..54a876f
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/39.txt
@@ -0,0 +1 @@
+Improve tip on grid if cell with wrong value, compute solved grid on new game
diff --git a/fastlane/metadata/android/fr-FR/changelogs/39.txt b/fastlane/metadata/android/fr-FR/changelogs/39.txt
new file mode 100644
index 0000000..2c378dc
--- /dev/null
+++ b/fastlane/metadata/android/fr-FR/changelogs/39.txt
@@ -0,0 +1 @@
+Amélioration du coup de pouce en cas de cellule avec une valeur fausse, calcul de la grille résolue au début de la partie
diff --git a/lib/entities/cell.dart b/lib/entities/cell.dart
index 4cb5fdd..a42ad6f 100644
--- a/lib/entities/cell.dart
+++ b/lib/entities/cell.dart
@@ -91,12 +91,16 @@ class Cell {
 
     Color backgroundColor = Colors.grey[200];
 
+    List cells = myProvider.cells;
+    int blockSizeHorizontal = myProvider.blockSizeHorizontal;
+    int blockSizeVertical = myProvider.blockSizeVertical;
+
     if (
       myProvider.showConflicts
       && myProvider.currentCellCol != null
       && myProvider.currentCellRow != null
     ) {
-      if (!BoardUtils.isValueAllowed(myProvider, myProvider.currentCellCol, myProvider.currentCellRow, this.value)) {
+      if (!BoardUtils.isValueAllowed(cells, blockSizeHorizontal, blockSizeVertical, myProvider.currentCellCol, myProvider.currentCellRow, this.value)) {
         backgroundColor = Colors.pink[100];
       }
     }
diff --git a/lib/provider/data.dart b/lib/provider/data.dart
index e2881e9..8162bc6 100644
--- a/lib/provider/data.dart
+++ b/lib/provider/data.dart
@@ -22,6 +22,7 @@ class Data extends ChangeNotifier {
   int _blockSizeVertical = null;
   int _blockSizeHorizontal = null;
   List _cells = [];
+  List _cellsSolved = [];
   int _currentCellCol = null;
   int _currentCellRow = null;
   int _currentCellValue = null;
@@ -94,6 +95,11 @@ class Data extends ChangeNotifier {
     notifyListeners();
   }
 
+  List get cellsSolved => _cellsSolved;
+  set updateCellsSolved(List cells) {
+    _cellsSolved = cells;
+  }
+
   int get currentCellCol => _currentCellCol;
   set updateCurrentCellCol(int currentCellCol) {
     _currentCellCol = currentCellCol;
diff --git a/lib/utils/board_utils.dart b/lib/utils/board_utils.dart
index baa0527..bc5f4f0 100644
--- a/lib/utils/board_utils.dart
+++ b/lib/utils/board_utils.dart
@@ -6,16 +6,18 @@ import '../provider/data.dart';
 
 class BoardUtils {
 
-  static printGrid(List cells) {
+  static printGrid(List cells, List solvedCells) {
     String stringValues = '0123456789ABCDEFG';
     print('');
     print('-------');
     for (var rowIndex = 0; rowIndex < cells.length; rowIndex++) {
       String row = '';
+      String rowSolved = '';
       for (var colIndex = 0; colIndex < cells[rowIndex].length; colIndex++) {
         row += stringValues[cells[rowIndex][colIndex].value];
+        rowSolved += stringValues[solvedCells[rowIndex][colIndex].value];
       }
-      print(row);
+      print(row + ' | ' + rowSolved);
     }
     print('-------');
     print('');
@@ -40,13 +42,14 @@ class BoardUtils {
       print('Picked grid from template: ' + grid);
       bool isSymetric = (blockSizeHorizontal == blockSizeVertical);
       myProvider.updateCells = BoardUtils.createBoardFromTemplate(grid, isSymetric);
+      myProvider.updateCellsSolved = BoardUtils.getSolvedGrid(myProvider);
       myProvider.selectCell(null, null);
+
+      printGrid(myProvider.cells, myProvider.cellsSolved);
     }
   }
 
-
   static List createEmptyBoard(int boardSize) {
-    int index = 0;
     List cells = [];
     for (var rowIndex = 0; rowIndex < boardSize; rowIndex++) {
       List row = [];
@@ -59,6 +62,18 @@ class BoardUtils {
     return cells;
   }
 
+  static List copyBoard(List cells) {
+    List copiedGrid = [];
+    for (var rowIndex = 0; rowIndex < cells.length; rowIndex++) {
+      List row = [];
+      for (var colIndex = 0; colIndex < cells[rowIndex].length; colIndex++) {
+        row.add(Cell(cells[rowIndex][colIndex].value, false));
+      }
+      copiedGrid.add(row);
+    }
+
+    return copiedGrid;
+  }
 
   static List createBoardFromTemplate(String grid, bool isSymetric) {
     List cells = [];
@@ -145,12 +160,9 @@ class BoardUtils {
       }
     }
 
-    printGrid(cells);
-
     return cells;
   }
 
-
   static bool checkBoardIsSolved(Data myProvider) {
     List cells = myProvider.cells;
 
@@ -178,16 +190,11 @@ class BoardUtils {
     return true;
   }
 
-  static bool isValueAllowed(Data myProvider, int candidateCol, int candidateRow, int candidateValue) {
+  static bool isValueAllowed(List cells, int blockSizeHorizontal, int blockSizeVertical, int candidateCol, int candidateRow, int candidateValue) {
     if (candidateValue == 0) {
       return true;
     }
 
-    List cells = myProvider.cells;
-
-    int blockSizeHorizontal = myProvider.blockSizeHorizontal;
-    int blockSizeVertical = myProvider.blockSizeVertical;
-
     int boardSize = blockSizeHorizontal * blockSizeVertical;
 
     // check lines does not contains a value twice
@@ -257,7 +264,6 @@ class BoardUtils {
     return true;
   }
 
-
   static void computeConflictsInBoard(Data myProvider) {
     List cells = myProvider.cells;
 
@@ -345,4 +351,82 @@ class BoardUtils {
     }
   }
 
+  static List getCellsWithWrongValue(List cells, List cellsSolved, int blockSizeHorizontal, int blockSizeVertical) {
+    List cellsWithWrongValue = [];
+    int boardSize = blockSizeHorizontal * blockSizeVertical;
+
+    for (var row = 0; row < boardSize; row++) {
+      for (var col = 0; col < boardSize; col++) {
+        if (cells[row][col].value != 0 && cells[row][col].value != cellsSolved[row][col].value) {
+          cellsWithWrongValue.add([col, row]);
+        }
+      }
+    }
+
+    return cellsWithWrongValue;
+  }
+
+  static List getConflictingCells(List cells, int blockSizeHorizontal, int blockSizeVertical) {
+    List conflictingCells = [];
+    int boardSize = blockSizeHorizontal * blockSizeVertical;
+
+    for (var row = 0; row < boardSize; row++) {
+      for (var col = 0; col < boardSize; col++) {
+        if (!cells[row][col].isFixed && cells[row][col].value != 0) {
+          if (cells[row][col].conflictsCount != 0 && !BoardUtils.isValueAllowed(cells, blockSizeHorizontal, blockSizeVertical, col, row, cells[row][col].value)) {
+            conflictingCells.add([col, row]);
+          }
+        }
+      }
+    }
+
+    return conflictingCells;
+  }
+
+  static List getCellsWithUniqueAvailableValue(List cells, int blockSizeHorizontal, int blockSizeVertical) {
+    List candidateCells = [];
+    int boardSize = blockSizeHorizontal * blockSizeVertical;
+
+    for (var row = 0; row < boardSize; row++) {
+      for (var col = 0; col < boardSize; col++) {
+        if (cells[row][col].value == 0) {
+          int allowedValuesCount = 0;
+          int candidateValue = 0;
+          for (var value = 1; value <= boardSize; value++) {
+            if (BoardUtils.isValueAllowed(cells, blockSizeHorizontal, blockSizeVertical, col, row, value)) {
+              candidateValue = value;
+              allowedValuesCount++;
+            }
+          }
+          if (allowedValuesCount == 1) {
+            candidateCells.add([col, row, candidateValue]);
+          }
+        }
+      }
+    }
+
+    return candidateCells;
+  }
+
+  static List getSolvedGrid(Data myProvider) {
+    List cells = copyBoard(myProvider.cells);
+    int blockSizeHorizontal = myProvider.blockSizeHorizontal;
+    int blockSizeVertical = myProvider.blockSizeVertical;
+
+    do {
+      List cellsWithUniqueAvailableValue = BoardUtils.getCellsWithUniqueAvailableValue(cells, blockSizeHorizontal, blockSizeVertical);
+      if (cellsWithUniqueAvailableValue.length == 0) {
+        break;
+      }
+      for (var i = 0; i < cellsWithUniqueAvailableValue.length; i++) {
+        int col = cellsWithUniqueAvailableValue[i][0];
+        int row = cellsWithUniqueAvailableValue[i][1];
+        int value = cellsWithUniqueAvailableValue[i][2];
+        cells[row][col].value = value;
+      }
+    } while (true);
+
+    return cells;
+  }
+
 }
diff --git a/lib/utils/game_utils.dart b/lib/utils/game_utils.dart
index 335258b..5b703a3 100644
--- a/lib/utils/game_utils.dart
+++ b/lib/utils/game_utils.dart
@@ -29,42 +29,25 @@ class GameUtils {
 
   static void helpSelectCell(Data myProvider) {
     List cells = myProvider.cells;
-    int boardSize = myProvider.blockSizeHorizontal * myProvider.blockSizeVertical;
+    int blockSizeHorizontal = myProvider.blockSizeHorizontal;
+    int blockSizeVertical = myProvider.blockSizeVertical;
 
-    // pick one of conflicting cells, if found
-    List conflictingCells = [];
-    for (var row = 0; row < boardSize; row++) {
-      for (var col = 0; col < boardSize; col++) {
-        if (!cells[row][col].isFixed && cells[row][col].value != 0) {
-
-          if (cells[row][col].conflictsCount != 0 && !BoardUtils.isValueAllowed(myProvider, col, row, cells[row][col].value)) {
-            conflictingCells.add([col, row]);
-          }
-        }
-      }
+    // pick one of wrong value cells, if found
+    List wrongValueCells = BoardUtils.getCellsWithWrongValue(cells, myProvider.cellsSolved, blockSizeHorizontal, blockSizeVertical);
+    if (wrongValueCells.length != 0) {
+      GameUtils.pickRandomFromList(myProvider, wrongValueCells);
+      return;
     }
+
+    // pick one of conflicting cells, if found
+    List conflictingCells = BoardUtils.getCellsWithUniqueAvailableValue(cells, blockSizeHorizontal, blockSizeVertical);
     if (conflictingCells.length != 0) {
       GameUtils.pickRandomFromList(myProvider, conflictingCells);
       return;
     }
 
     //  pick one form cells with unique non-conflicting candidate value
-    List candidateCells = [];
-    for (var row = 0; row < boardSize; row++) {
-      for (var col = 0; col < boardSize; col++) {
-        if (cells[row][col].value == 0) {
-          int allowedValuesCount = 0;
-          for (var value = 1; value <= boardSize; value++) {
-            if (BoardUtils.isValueAllowed(myProvider, col, row, value)) {
-              allowedValuesCount++;
-            }
-          }
-          if (allowedValuesCount == 1) {
-            candidateCells.add([col, row]);
-          }
-        }
-      }
-    }
+    List candidateCells = BoardUtils.getCellsWithUniqueAvailableValue(cells, blockSizeHorizontal, blockSizeVertical);
     if (candidateCells.length != 0) {
       GameUtils.pickRandomFromList(myProvider, candidateCells);
       return;
@@ -80,14 +63,19 @@ class GameUtils {
   }
 
   static void helpFillCell(Data myProvider) {
-    int boardSize = myProvider.blockSizeHorizontal * myProvider.blockSizeVertical;
+    List cells = myProvider.cells;
+    int blockSizeHorizontal = myProvider.blockSizeHorizontal;
+    int blockSizeVertical = myProvider.blockSizeVertical;
 
+    int boardSize = blockSizeHorizontal * blockSizeVertical;
+
+    // Will clean cell if no eligible value found
     int eligibleValue = 0;
 
     // ensure there is only one eligible value for this cell
     int allowedValuesCount = 0;
     for (var value = 1; value <= boardSize; value++) {
-      if (BoardUtils.isValueAllowed(myProvider, myProvider.currentCellCol, myProvider.currentCellRow, value)) {
+      if (BoardUtils.isValueAllowed(cells, blockSizeHorizontal, blockSizeVertical, myProvider.currentCellCol, myProvider.currentCellRow, value)) {
         allowedValuesCount++;
         eligibleValue = value;
       }
@@ -97,4 +85,5 @@ class GameUtils {
     myProvider.selectCell(null, null);
     BoardUtils.computeConflictsInBoard(myProvider);
   }
+
 }
-- 
GitLab