diff --git a/android/gradle.properties b/android/gradle.properties index 4878903faeac600353ec559be514de7d30376f55..9dfcc4273391875fdd4899077969cf717c1ace23 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 Binary files /dev/null and b/assets/icons/button_help.png differ 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 0000000000000000000000000000000000000000..7c583babdbf2e5327d4b790122da790bd4b5255a --- /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 0000000000000000000000000000000000000000..874c6fdc3d6e730fd0962c3587e36574c21380a5 --- /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 2cd7ac8ddbed3fb1264fef39799c25bc1e5355a7..e05eb18fade7b66ea649c7af44814ab099bef3c0 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 0000000000000000000000000000000000000000..f8a083b4bbb0dfd5922a603fc3637aa1909bebc5 --- /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 2cc23c8cfd0ec94a354bb27090837e7e24e688a1..8f7628616b2302ea6794d60372ccb74106994151 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 6a32e1c9d5fed908f4e9d20cdf13f0a3cb84a51e..ef43797429450735feda092bb168daf0481576c1 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); + } }