From 829619c3a2b9e01aa3d8dcf60b8f0602e970d34a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Harrault?= <benoit@harrault.fr> Date: Wed, 14 Jul 2021 00:32:39 +0200 Subject: [PATCH] Add a tip button, show conflict to solve or next cell/value to fill --- android/gradle.properties | 4 +- assets/icons/button_help.png | Bin 0 -> 6037 bytes .../metadata/android/en-US/changelogs/33.txt | 1 + .../metadata/android/fr-FR/changelogs/33.txt | 1 + icons/build_game_icons.sh | 1 + icons/button_help.svg | 2 + lib/screens/home.dart | 17 ++++ lib/utils/game_utils.dart | 83 +++++++++++++++++- 8 files changed, 106 insertions(+), 3 deletions(-) create mode 100644 assets/icons/button_help.png create mode 100644 fastlane/metadata/android/en-US/changelogs/33.txt create mode 100644 fastlane/metadata/android/fr-FR/changelogs/33.txt create mode 100644 icons/button_help.svg diff --git a/android/gradle.properties b/android/gradle.properties index 4878903..9dfcc42 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.32 -app.versionCode=32 +app.versionName=0.0.33 +app.versionCode=33 diff --git a/assets/icons/button_help.png b/assets/icons/button_help.png new file mode 100644 index 0000000000000000000000000000000000000000..cd1bcd29a76f0624c9a6404f4b90bbde8f56ea3f GIT binary patch literal 6037 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 literal 0 HcmV?d00001 diff --git a/fastlane/metadata/android/en-US/changelogs/33.txt b/fastlane/metadata/android/en-US/changelogs/33.txt new file mode 100644 index 0000000..7c583ba --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/33.txt @@ -0,0 +1 @@ +Add a tip button, show conflict to solve or next cell/value to fill diff --git a/fastlane/metadata/android/fr-FR/changelogs/33.txt b/fastlane/metadata/android/fr-FR/changelogs/33.txt new file mode 100644 index 0000000..874c6fd --- /dev/null +++ b/fastlane/metadata/android/fr-FR/changelogs/33.txt @@ -0,0 +1 @@ +Ajout d'un bouton d'aide, montrant un conflit à régler ou la prochaine cellule à sélectionner/saisir. diff --git a/icons/build_game_icons.sh b/icons/build_game_icons.sh index 2cd7ac8..e05eb18 100755 --- a/icons/build_game_icons.sh +++ b/icons/build_game_icons.sh @@ -57,6 +57,7 @@ function build_icon_for_skin() { # Game icons build_icon ${CURRENT_DIR}/button_back.svg ${BASE_DIR}/assets/icons/button_back.png +build_icon ${CURRENT_DIR}/button_help.svg ${BASE_DIR}/assets/icons/button_help.png build_icon ${CURRENT_DIR}/button_show_conflicts.svg ${BASE_DIR}/assets/icons/button_show_conflicts.png build_icon ${CURRENT_DIR}/button_start.svg ${BASE_DIR}/assets/icons/button_start.png build_icon ${CURRENT_DIR}/difficulty_easy.svg ${BASE_DIR}/assets/icons/difficulty_easy.png diff --git a/icons/button_help.svg b/icons/button_help.svg new file mode 100644 index 0000000..f8a083b --- /dev/null +++ b/icons/button_help.svg @@ -0,0 +1,2 @@ +<?xml version="1.0" encoding="UTF-8"?> +<svg enable-background="new 0 0 100 100" version="1.1" viewBox="0 0 91.389 91.821" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect width="91.389" height="91.821" ry="10.769" fill="#dd00ec"/><circle cx="45.694" cy="45.91" r="33.217" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.885"/><g transform="matrix(.54508 0 0 .54508 20.441 -502.46)" fill="#db00eb" stroke="#00b244" stroke-width=".60926"><path d="m81.135 971.23c-1.1715-1.1715-3.0711-1.1715-4.2426 0l-5.6569 5.6569c-1.1716 1.1716-1.1715 3.0711 3e-6 4.2426 1.1716 1.1716 3.071 1.1716 4.2426 0l5.6568-5.6568c1.1715-1.1716 1.1716-3.071 1e-6 -4.2426zm-28.284-11.711c-0.54299-0.54299-1.2929-0.88389-2.1213-0.88388-1.6567-1e-5 -3.0053 1.3485-3.0052 3.0052l-3.5e-5 7.9991c1e-6 1.6569 1.3485 3.0052 3.0052 3.0052 1.6569 1e-5 3.0052-1.3483 3.0052-3.0052l3.5e-5 -7.9991c-7.1e-5 -0.82852-0.34104-1.5785-0.88388-2.1213zm39.996 39.996c-0.54284-0.54284-1.2928-0.88381-2.1213-0.88388l-7.9991 4e-5c-1.6569-1e-5 -3.0052 1.3483-3.0052 3.0052-1e-6 1.6568 1.3483 3.0053 3.0052 3.0053l7.9991-1e-4c1.6567 1e-4 3.0052-1.3484 3.0052-3.0052-3e-6 -0.8284-0.3409-1.5783-0.88389-2.1213zm-24.439-15.556c-9.7205-9.7205-26.656-11.528-37.366-0.8176-6.6684 6.6685-8.3484 13.631-9.325 19.313-0.97661 5.6818-1.386 9.783-4.9277 13.325l-8.4853 8.4853c-2.7878 2.7877-2.6328 7.2667 2.4e-5 9.8994l9.8995 9.8996c2.6328 2.6327 7.1117 2.7877 9.8995-2e-4l8.4853-8.4851c3.5418-3.5418 7.6429-3.9511 13.325-4.9278 5.6816-0.9764 12.644-2.6565 19.313-9.325 10.71-10.71 8.9029-27.646-0.81762-37.366zm-4.2426 4.2426c7.5261 7.5261 9.0328 20.666 0.81762 28.881-5.6097 5.6097-10.646 6.7364-16.065 7.6678-4.6199 0.794-9.7346 1.3621-14.275 4.6404l-11.667-11.667c3.2782-4.5401 3.8463-9.6548 4.6404-14.275 0.93136-5.4187 2.0581-10.455 7.6677-16.065 8.2152-8.2152 21.355-6.7085 28.881 0.8176zm-5.458-1.2154c-0.29098-0.31274-0.65457-0.5946-1.0606-0.83965-6.3377-2.8668-13.837-2.2586-19.666 1.812-1.2903 0.90814-1.6596 2.9083-0.75129 4.1984 0.90835 1.2902 2.9305 1.6378 4.2206 0.72917 4.084-2.8517 9.3179-3.2839 13.744-1.2816 1.2643 0.57898 2.9159 0.12349 3.7123-1.0164 0.93238-1.4424 0.67412-2.6636-0.19895-3.6019zm-34.14-15.755c-1.1715-1.1715-3.071-1.1716-4.2426 0-1.1715 1.1715-1.1715 3.0711 6e-6 4.2426l5.6569 5.6569c1.1716 1.1716 3.0711 1.1716 4.2426 0 1.1716-1.1716 1.1716-3.071-3e-6 -4.2426zm50.912 50.912c-1.1716-1.1716-3.0711-1.1715-4.2426 0-1.1716 1.1717-1.1716 3.071-1.9e-5 4.2427l5.6569 5.6568c1.1715 1.1716 3.0711 1.1716 4.2426 0 1.1715-1.1715 1.1715-3.071-2.8e-5 -4.2426zm-56.569 2e-4 11.314 11.314-1.4142 1.4141-11.314-11.314zm-5.6569 5.6568 11.314 11.314-0.70709 0.7071c-0.46222 0.4622-1.0623 0.3519-1.4142 0l-9.8995-9.8995c-0.35189-0.352-0.46222-0.952 7e-6 -1.4142z" color="#000000" enable-background="accumulate" fill="#db00eb" overflow="visible" stroke="none" stroke-width=".60926" style="text-indent:0;text-transform:none"/></g></svg> diff --git a/lib/screens/home.dart b/lib/screens/home.dart index 2cc23c8..8f76286 100644 --- a/lib/screens/home.dart +++ b/lib/screens/home.dart @@ -17,6 +17,23 @@ class Home extends StatelessWidget { if (myProvider.stateRunning) { menuActions = [ + FlatButton( + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(4), + border: Border.all( + color: Colors.blue, + width: 4, + ), + ), + margin: EdgeInsets.all(8), + child: Image( + image: AssetImage('assets/icons/button_help.png'), + fit: BoxFit.fill + ), + ), + onPressed: () => GameUtils.showTip(myProvider), + ), FlatButton( child: Container( decoration: BoxDecoration( diff --git a/lib/utils/game_utils.dart b/lib/utils/game_utils.dart index 6a32e1c..ef43797 100644 --- a/lib/utils/game_utils.dart +++ b/lib/utils/game_utils.dart @@ -1,5 +1,6 @@ import '../provider/data.dart'; import '../utils/board_utils.dart'; +import '../utils/game_utils.dart'; class GameUtils { @@ -8,10 +9,90 @@ class GameUtils { } static Future<void> startGame(Data myProvider) async { - print('Start new game: ' + myProvider.size); myProvider.updateSize = myProvider.size; myProvider.updateStateRunning = true; myProvider.updateCells = BoardUtils.createEmptyBoard(myProvider.blockSizeHorizontal * myProvider.blockSizeVertical); BoardUtils.pickGrid(myProvider); } + + static void showTip(Data myProvider) { + if (myProvider.currentCellCol == null || myProvider.currentCellRow == null) { + // no selected cell -> pick one + GameUtils.helpSelectCell(myProvider); + } else { + // currently selected cell -> set value + GameUtils.helpFillCell(myProvider); + } + } + + static void helpSelectCell(Data myProvider) { + List cells = myProvider.cells; + int boardSize = myProvider.blockSizeHorizontal * 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]); + } + } + } + } + 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]); + } + } + } + } + if (candidateCells.length != 0) { + GameUtils.pickRandomFromList(myProvider, candidateCells); + return; + } + } + + static void pickRandomFromList(Data myProvider, List cellsCoordinates) { + if (cellsCoordinates.length > 0) { + cellsCoordinates.shuffle(); + List cell = cellsCoordinates[0]; + myProvider.selectCell(cell[0], cell[1]); + } + } + + static void helpFillCell(Data myProvider) { + int boardSize = myProvider.blockSizeHorizontal * myProvider.blockSizeVertical; + + 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)) { + allowedValuesCount++; + eligibleValue = value; + } + } + + myProvider.updateCellValue(myProvider.currentCellCol, myProvider.currentCellRow, allowedValuesCount == 1 ? eligibleValue : 0); + myProvider.selectCell(null, null); + BoardUtils.computeConflictsInBoard(myProvider); + } } -- GitLab