Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • 23-add-timer
  • 65-update-icons
  • 82-fix-colors
  • 84-improve-app-metadata
  • master
  • Release_0.0.16_16
  • Release_0.0.17_17
  • Release_0.0.18_18
  • Release_0.0.19_19
  • Release_0.0.20_20
  • Release_0.0.21_21
  • Release_0.0.22_22
  • Release_0.0.23_23
  • Release_0.0.24_24
  • Release_0.0.25_25
  • Release_0.0.26_26
  • Release_0.0.27_27
  • Release_0.0.28_28
  • Release_0.0.29_29
  • Release_0.0.30_30
  • Release_0.0.31_31
  • Release_0.0.32_32
  • Release_0.0.33_33
  • Release_0.0.34_34
  • Release_0.0.35_35
  • Release_0.0.36_36
  • Release_0.0.37_37
  • Release_0.0.38_38
  • Release_0.0.39_39
  • Release_0.0.40_40
  • Release_0.0.41_41
  • Release_0.0.42_42
  • Release_0.0.43_43
  • Release_0.0.44_44
  • Release_0.0.45_45
  • Release_0.0.46_46
  • Release_0.0.47_47
  • Release_0.0.48_48
  • Release_0.1.0_49
  • Release_0.1.10_59
  • Release_0.1.11_60
  • Release_0.1.12_61
  • Release_0.1.13_62
  • Release_0.1.14_63
  • Release_0.1.15_64
  • Release_0.1.16_65
  • Release_0.1.17_66
  • Release_0.1.18_67
  • Release_0.1.19_68
  • Release_0.1.1_50
  • Release_0.1.20_69
  • Release_0.1.21_70
  • Release_0.1.22_71
  • Release_0.1.2_51
  • Release_0.1.3_52
  • Release_0.1.4_53
  • Release_0.1.5_54
  • Release_0.1.6_55
  • Release_0.1.7_56
  • Release_0.1.8_57
  • Release_0.1.9_58
  • Release_0.10.0_87
  • Release_0.2.0_72
  • Release_0.2.1_73
  • Release_0.3.0_74
  • Release_0.3.1_75
  • Release_0.4.0_76
  • Release_0.4.1_77
  • Release_0.5.0_78
  • Release_0.5.1_79
  • Release_0.5.2_80
  • Release_0.6.0_81
  • Release_0.7.0_82
  • Release_0.8.0_83
  • Release_0.9.0_84
  • Release_0.9.1_85
  • Release_0.9.2_86
77 results

Target

Select target project
  • android/org.benoitharrault.sudoku
1 result
Select Git revision
  • 23-add-timer
  • 65-update-icons
  • 82-fix-colors
  • 84-improve-app-metadata
  • master
  • Release_0.0.16_16
  • Release_0.0.17_17
  • Release_0.0.18_18
  • Release_0.0.19_19
  • Release_0.0.20_20
  • Release_0.0.21_21
  • Release_0.0.22_22
  • Release_0.0.23_23
  • Release_0.0.24_24
  • Release_0.0.25_25
  • Release_0.0.26_26
  • Release_0.0.27_27
  • Release_0.0.28_28
  • Release_0.0.29_29
  • Release_0.0.30_30
  • Release_0.0.31_31
  • Release_0.0.32_32
  • Release_0.0.33_33
  • Release_0.0.34_34
  • Release_0.0.35_35
  • Release_0.0.36_36
  • Release_0.0.37_37
  • Release_0.0.38_38
  • Release_0.0.39_39
  • Release_0.0.40_40
  • Release_0.0.41_41
  • Release_0.0.42_42
  • Release_0.0.43_43
  • Release_0.0.44_44
  • Release_0.0.45_45
  • Release_0.0.46_46
  • Release_0.0.47_47
  • Release_0.0.48_48
  • Release_0.1.0_49
  • Release_0.1.10_59
  • Release_0.1.11_60
  • Release_0.1.12_61
  • Release_0.1.13_62
  • Release_0.1.14_63
  • Release_0.1.15_64
  • Release_0.1.16_65
  • Release_0.1.17_66
  • Release_0.1.18_67
  • Release_0.1.19_68
  • Release_0.1.1_50
  • Release_0.1.20_69
  • Release_0.1.21_70
  • Release_0.1.22_71
  • Release_0.1.2_51
  • Release_0.1.3_52
  • Release_0.1.4_53
  • Release_0.1.5_54
  • Release_0.1.6_55
  • Release_0.1.7_56
  • Release_0.1.8_57
  • Release_0.1.9_58
  • Release_0.10.0_87
  • Release_0.2.0_72
  • Release_0.2.1_73
  • Release_0.3.0_74
  • Release_0.3.1_75
  • Release_0.4.0_76
  • Release_0.4.1_77
  • Release_0.5.0_78
  • Release_0.5.1_79
  • Release_0.5.2_80
  • Release_0.6.0_81
  • Release_0.7.0_82
  • Release_0.8.0_83
  • Release_0.9.0_84
  • Release_0.9.1_85
  • Release_0.9.2_86
77 results
Show changes
Commits on Source (8)
Showing
with 565 additions and 177 deletions
org.gradle.jvmargs=-Xmx1536M
android.useAndroidX=true
android.enableJetifier=true
app.versionName=0.0.32
app.versionCode=32
app.versionName=0.0.36
app.versionCode=36
This diff is collapsed.
assets/icons/button_help.png

5.9 KiB

Add a tip button, show conflict to solve or next cell/value to fill
Ensure each grid template can be resolved, update templates, add solve script
Fix grid templates files format
Fix f-droid package metadata
......@@ -4,11 +4,15 @@ This simple sudoku game is aimed for kids (but not only).
You can play and have fun even if you can't read!
With a deliberately limited game options, everyone can understand how to play
and how to adapt this game to his needs.
With a deliberately limited number of game options, everyone can understand how to play and how to adapt this game to his needs.
You can choose:
# difficulty: easy, medium, hard, nightmare
# size: 2x2 (very easy, for kids), 3x2 (easy), 3x3 (standard), 4x4 (why?)
# tiles theme: digits (standard), pictures (for kids, several themes available)
- difficulty: easy, medium, hard
- size: 2x2 (very easy, for kids), 3x2 (easy), 3x3 (standard)
- tiles theme: digits (standard), pictures (for kids)
Some help can be provided with two buttons:
# "tip": will select next fillable cell on first tap, will fill this cell whith right value on second tap
# "conflicts": will show conflicting cells
Every grid has one unique solution. No assumption or guessing is needed to solve grids.
Simple Sudoku Game. Easy to play, easy to enjoy.
Icon based interface, ready to use, with deliberately limited options (difficulty, grid size, theme).
Ajout d'un bouton d'aide, montrant un conflit à régler ou la prochaine cellule à sélectionner/saisir.
Vérification que chaque modèle peut être résolu, mise à jour des modèles, ajout d'un script (naïf) de résolution
Correction du format du fichier des modèles de grilles
Correction des metadonnées du package f-droid
......@@ -7,7 +7,12 @@ Il est possible d'y jouer et de s'amuser même sans savoir lire.
Avec un choix volontairement limité dans les options, chacun peut découvrir et apprendre comment jouer et comment adapter le jeu à ses envies.
Il est possible de choisir :
# la difficulté du jeu : facile, moyen, difficile (nombre de cases vides au début de la partie)
# le taille de la grille : 2x2 (très facile, pour petits débutants), 3x2 (facile), 3x3 (classique), 4x4 (mais pourquoi ?)
# le style : chiffres (classique), dessins (pour enfants, plusieurs thèmes disponibles)
- la difficulté du jeu : facile, moyen, difficile (nombre de cases vides au début de la partie)
- le taille de la grille: 2x2 (très facile, pour grands débutants), 3x2 (facile), 3x3 (classique)
- le style: chiffres (classique), dessins (pour enfants)
Un coup de pouce peut être donné grâce à deux boutons :
# "conseil" : sélectionne la prochaine case à remplir au premier appui, renseigne la bonne valeur dans cette case au second appui
# "conflits" : affiche les cases en conflit
Chaque grille a une solution unique. Aucune hypothèse ou supposition n'est nécessaire pour résoudre les grilles.
Jeu de Sudoku simple, facile à jouer, facile à apprécier.
Interface à base d'icônes, facile à prendre en main et volontairement peu de choix dans les options (difficulté, taille de la grille et thème du jeu).
......@@ -7,11 +7,18 @@ ALLOWED_DIFFICULTY_VALUES="easy medium hard nightmare"
GRIDS_COUNT=10
for BLOCK_SIZE in ${ALLOWED_BLOCK_SIZE_VALUES}; do
echo "Block size: ${BLOCK_SIZE}"
for DIFFICULTY in ${ALLOWED_DIFFICULTY_VALUES}; do
echo "Difficulty: ${DIFFICULTY}"
echo "Block size: ${BLOCK_SIZE} / Difficulty: ${DIFFICULTY}"
for i in $(seq ${GRIDS_COUNT}); do
python ${CURRENT_DIR}/generate.py ${BLOCK_SIZE} ${DIFFICULTY} | tail -n 1
# Generate grid candidate
GRID="$(python ${CURRENT_DIR}/generate.py ${BLOCK_SIZE} ${DIFFICULTY} | tail -n 1)"
# Ensure grid can be resolve without any assumption
CAN_BE_SOLVED="$(python ${CURRENT_DIR}/solve.py ${BLOCK_SIZE} ${GRID} | tail -n 1)"
if [ "${CAN_BE_SOLVED}" == "Ok" ]; then
echo "${BLOCK_SIZE} ${DIFFICULTY} ${GRID}"
else
echo "FAILED: ${BLOCK_SIZE} ${DIFFICULTY} ${GRID}"
fi
done
done
done
#!/usr/bin/python
# -*- coding: iso-8859-15 -*-
#
# Naive sudoku grid solver
#
# Will try to solve sudoku grid without making any assumption
# -> pick and fill first cell where only one value is allowed
# and loop until grid is filled
#
# Will fail if solution needs any assumption on a cell value
#
import sys
import math
if (len(sys.argv) != 3):
print('Usage: solve.py block-size grid')
print('block-size: [2x2|3x2|3x3|4x4]')
exit()
blocksize, gridTemplate = sys.argv[1], sys.argv[2]
if not blocksize in ['2x2', '3x2', '3x3', '4x4']:
print('wrong size given')
exit()
splitted_blocksize = blocksize.split('x')
size_horizontal = int(splitted_blocksize[0])
size_vertical = int(splitted_blocksize[1])
boardSize = size_horizontal * size_vertical
if (len(gridTemplate) != boardSize * boardSize):
print('wrong grid length (should be '+str(boardSize * boardSize)+')')
exit()
debugSolveGrid = False
############################################################################
sys.stdout.write('Will solve grid: ['+str(size_horizontal)+'x'+str(size_vertical)+'] // '+gridTemplate+'\n')
stringValues = '0123456789ABCDEFG'
# draw grid (array style)
def drawGrid(grid):
gridVerticalSize = len(grid)
gridHorizontalSize = len(grid[0])
horizontalLineLength = ((size_horizontal + 1) * size_vertical) + 1
for row in range(gridHorizontalSize):
if ((row % size_vertical) == 0):
sys.stdout.write(('' * horizontalLineLength) + '\n')
for col in range(gridVerticalSize):
if ((col % size_horizontal) == 0):
sys.stdout.write('')
if grid[row][col] != 0:
sys.stdout.write(stringValues[grid[row][col]])
else:
sys.stdout.write(' ')
sys.stdout.write('\n')
sys.stdout.write(('' * horizontalLineLength) + '\n')
sys.stdout.write('\n')
# (deep) copy of grid
def copyGrid(grid):
copiedGrid = []
for row in range(len(grid)):
copiedGrid.append([])
for col in range(len(grid[row])):
copiedGrid[row].append(grid[row][col])
return copiedGrid
# Init grid from given template
def initGrid(boardSize, gridTemplate):
grid = []
index = 0
for row in range(boardSize):
grid.append([])
for col in range(boardSize):
grid[row].append(stringValues.index(gridTemplate[index]))
index += 1
return grid
# Check if grid is fully completed, without any empty cell
def isFullyCompleted(grid):
for row in range(len(grid)):
for col in range(len(grid[row])):
if grid[row][col] == 0:
return False
return True
# Check if a list contains duplicates (conflicts)
def containsDuplicates(list):
tmp_set = set(list)
return (len(list) != len(tmp_set))
# Check if given grid contains conflicts
def hasConflict(grid, size_horizontal, size_vertical):
# Check horizontal conflicts
for row in range(len(grid)):
values = []
for col in range(len(grid[row])):
value = grid[row][col]
if value != 0:
values.append(value)
if containsDuplicates(values):
# print('Horizontal conflict found')
return True
# Check vertical conflicts
for col in range(len(grid[0])):
values = []
for row in range(len(grid)):
value = grid[row][col]
if value != 0:
values.append(value)
if containsDuplicates(values):
# print('Vertical conflict found')
return True
# Check sub-blocks conflicts
for blockRow in range(size_horizontal):
for blockCol in range(size_vertical):
# Get sub-square
blockColFrom = size_horizontal * int(col / size_horizontal)
blockRowFrom = size_vertical * int(row / size_vertical)
values = []
for rowInBlock in range(size_vertical):
for colInBlock in range(size_horizontal):
row = (blockRow * size_vertical) + rowInBlock;
col = (blockCol * size_horizontal) + colInBlock;
value = grid[row][col]
if value != 0:
values.append(value)
if containsDuplicates(values):
# print('Sub-block conflict found')
return True
return False
# Check if a value is allowed in a cell (without conflicting)
def isValueAllowed(grid, size_horizontal, size_vertical, row, col, candidateValue):
testGrid = copyGrid(grid)
testGrid[row][col] = candidateValue
if not hasConflict(testGrid, size_horizontal, size_vertical):
return True
return False
# Get allowed values in a cell (witjout conflicting)
def findAllowedValuesForCell(grid, size_horizontal, size_vertical, row, col):
allowedValues = []
if not hasConflict(grid, size_horizontal, size_vertical):
for candidateValue in range(1, size_horizontal * size_vertical + 1):
if isValueAllowed(grid, size_horizontal, size_vertical, row, col, candidateValue):
allowedValues.append(candidateValue)
return allowedValues
# Globally solve grid
def solve(grid, size_horizontal, size_vertical):
iterations = 0
maxIterations = 500
boardSize = size_horizontal * size_vertical
# Loop until grid is fully completed
while True:
iterations += 1
if isFullyCompleted(grid) or (iterations > maxIterations):
break
if debugSolveGrid:
print('===================================')
print('Iteration: '+str(iterations))
# Get first/next cell with only one allowed value
candidates = []
if debugSolveGrid:
print('Searching for empty cells...')
for row in range(len(grid)):
for col in range(len(grid[row])):
if grid[row][col] == 0:
if debugSolveGrid:
print('Found empty cell ['+str(col)+','+str(row)+']')
candidates.append([row,col])
if len(candidates):
for candidate in candidates:
candidateRow = candidate[0]
candidateCol = candidate[1]
allowedValues = findAllowedValuesForCell(grid, size_horizontal, size_vertical, candidateRow, candidateCol)
if debugSolveGrid:
print('Allowed values for cell ['+str(candidateCol)+','+str(candidateRow)+']: '+str(allowedValues))
if len(allowedValues) != 1:
if debugSolveGrid:
print(' Non unique allowed value for cell. Skip to next cell')
else:
value = allowedValues[0]
grid[candidateRow][candidateCol] = value
if debugSolveGrid:
print(' Found unique allowed value for cell ['+str(candidateCol)+','+str(candidateRow)+']: '+str(value))
drawGrid(grid)
#########################
sys.stdout.write('Building start grid:\n')
grid = initGrid(boardSize, gridTemplate)
drawGrid(grid)
sys.stdout.write('Checking grid:\n')
if hasConflict(grid, size_horizontal, size_vertical):
sys.stdout.write(' - oups, initial conflict found.\n')
else:
sys.stdout.write(' - ok, no initial conflict found.\n')
sys.stdout.write('\n')
sys.stdout.write('Solving grid...\n')
solve(grid, size_horizontal, size_vertical)
if isFullyCompleted(grid):
sys.stdout.write('Ok, solved grid:\n')
drawGrid(grid)
sys.stdout.write('Ok\n')
else:
sys.stdout.write('Failed to solve grid\n')
#!/usr/bin/env bash
CURRENT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
# Fetch grid from game templates
GRIDS="$(cat "${CURRENT_DIR}/../assets/files/templates.json" | grep "0" | sed 's/"//g' | sed 's/,//g')"
function get_block_size() {
BLOCK_SIZE=""
GRID_LENGTH="$(echo -n "${GRID}" | wc -c)"
if [ "${GRID_LENGTH}" == "16" ]; then
BLOCK_SIZE="2x2"
fi
if [ "${GRID_LENGTH}" == "36" ]; then
BLOCK_SIZE="3x2"
fi
if [ "${GRID_LENGTH}" == "81" ]; then
BLOCK_SIZE="3x3"
fi
if [ "${GRID_LENGTH}" == "256" ]; then
BLOCK_SIZE="4x4"
fi
echo "${BLOCK_SIZE}"
}
for GRID in ${GRIDS}; do
BLOCK_SIZE="$(get_block_size "${GRID}")"
echo "GRID: ${BLOCK_SIZE} / ${GRID}"
python ${CURRENT_DIR}/solve.py ${BLOCK_SIZE} ${GRID} | tail -n 1
done
......@@ -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
......
<?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>