Created
May 6, 2025 15:52
-
-
Save pigreco/d4909f7f2c942b87d4c08bf648815af9 to your computer and use it in GitHub Desktop.
Sudoku
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# === IMPORT NECESSARI === | |
from qgis.core import ( | |
QgsProject, QgsVectorLayer, QgsField, QgsFeature, | |
QgsGeometry, QgsPointXY, QgsRectangle, QgsFillSymbol, | |
QgsRuleBasedRenderer, QgsPalLayerSettings, | |
QgsTextFormat, QgsVectorLayerSimpleLabeling | |
) | |
from PyQt5.QtCore import QVariant | |
from PyQt5.QtGui import QColor | |
# === PARAMETRI DI BASE === | |
CELL_SIZE = 1 | |
ROWS, COLS = 9, 9 | |
# === PUZZLE INIZIALE === | |
initial_puzzle = [ | |
[5, 3, 0, 0, 7, 0, 0, 0, 0], | |
[6, 0, 0, 1, 9, 5, 0, 0, 0], | |
[0, 9, 8, 0, 0, 0, 0, 6, 0], | |
[8, 0, 0, 0, 6, 0, 0, 0, 3], | |
[4, 0, 0, 8, 0, 3, 0, 0, 1], | |
[7, 0, 0, 0, 2, 0, 0, 0, 6], | |
[0, 6, 0, 0, 0, 0, 2, 8, 0], | |
[0, 0, 0, 4, 1, 9, 0, 0, 5], | |
[0, 0, 0, 0, 8, 0, 0, 7, 9] | |
] | |
# === CREA LAYER VETTORIALE === | |
layer = QgsVectorLayer("Polygon?crs=EPSG:4326", "Sudoku", "memory") | |
provider = layer.dataProvider() | |
provider.addAttributes([ | |
QgsField("row", QVariant.Int), | |
QgsField("col", QVariant.Int), | |
QgsField("valore", QVariant.Int), | |
]) | |
layer.updateFields() | |
features = [] | |
for row in range(ROWS): | |
for col in range(COLS): | |
x_min = col * CELL_SIZE | |
y_min = -row * CELL_SIZE | |
x_max = x_min + CELL_SIZE | |
y_max = y_min - CELL_SIZE | |
rect = QgsRectangle(x_min, y_max, x_max, y_min) | |
points = [ | |
QgsPointXY(rect.xMinimum(), rect.yMinimum()), | |
QgsPointXY(rect.xMaximum(), rect.yMinimum()), | |
QgsPointXY(rect.xMaximum(), rect.yMaximum()), | |
QgsPointXY(rect.xMinimum(), rect.yMaximum()), | |
QgsPointXY(rect.xMinimum(), rect.yMinimum()) | |
] | |
geom = QgsGeometry.fromPolygonXY([points]) | |
feat = QgsFeature() | |
feat.setGeometry(geom) | |
valore = initial_puzzle[row][col] | |
feat.setAttributes([row, col, valore]) | |
features.append(feat) | |
provider.addFeatures(features) | |
layer.updateExtents() | |
QgsProject.instance().addMapLayer(layer) | |
print("β Griglia Sudoku creata.") | |
# === FUNZIONI LOGICHE === | |
def get_grid(): | |
grid = [[0]*9 for _ in range(9)] | |
for feat in layer.getFeatures(): | |
r = feat["row"] | |
c = feat["col"] | |
v = feat["valore"] | |
grid[r][c] = v | |
return grid | |
def is_valid(grid, r, c, val): | |
for i in range(9): | |
if grid[r][i] == val or grid[i][c] == val: | |
return False | |
box_r, box_c = 3*(r//3), 3*(c//3) | |
for i in range(3): | |
for j in range(3): | |
if grid[box_r+i][box_c+j] == val: | |
return False | |
return True | |
def check_grid(): | |
grid = get_grid() | |
for r in range(9): | |
for c in range(9): | |
val = grid[r][c] | |
if val == 0: | |
print(f"π‘ Casella vuota in ({r+1},{c+1})") | |
return False | |
grid[r][c] = 0 | |
if not is_valid(grid, r, c, val): | |
print(f"β Valore {val} non valido in ({r+1},{c+1})") | |
return False | |
grid[r][c] = val | |
print("β La griglia Γ¨ completa e corretta!") | |
return True | |
def solve_sudoku(grid): | |
for r in range(9): | |
for c in range(9): | |
if grid[r][c] == 0: | |
for val in range(1, 10): | |
if is_valid(grid, r, c, val): | |
grid[r][c] = val | |
if solve_sudoku(grid): | |
return True | |
grid[r][c] = 0 | |
return False | |
return True | |
def apply_solution_to_layer(grid): | |
layer.startEditing() | |
for feat in layer.getFeatures(): | |
r = feat["row"] | |
c = feat["col"] | |
fid = feat.id() | |
layer.changeAttributeValue(fid, layer.fields().indexFromName("valore"), grid[r][c]) | |
layer.commitChanges() | |
print("β Soluzione applicata al layer.") | |
def solve_and_apply(): | |
grid = get_grid() | |
if solve_sudoku(grid): | |
apply_solution_to_layer(grid) | |
else: | |
print("β Nessuna soluzione trovata.") | |
# === STILE E ETICHETTE === | |
def style_and_label_layer(): | |
symbol_default = QgsFillSymbol.createSimple({'color': 'white', 'outline_color': 'black'}) | |
symbol_fixed = QgsFillSymbol.createSimple({'color': '#cccccc', 'outline_color': 'black'}) | |
root_rule = QgsRuleBasedRenderer.Rule(None) | |
rule_fixed = QgsRuleBasedRenderer.Rule(symbol_fixed) | |
rule_fixed.setFilterExpression('"valore" > 0') | |
rule_fixed.setLabel("Valori iniziali") | |
rule_empty = QgsRuleBasedRenderer.Rule(symbol_default) | |
rule_empty.setFilterExpression('"valore" = 0') | |
rule_empty.setLabel("Vuote o modificabili") | |
root_rule.appendChild(rule_fixed) | |
root_rule.appendChild(rule_empty) | |
renderer = QgsRuleBasedRenderer(root_rule) | |
layer.setRenderer(renderer) | |
layer.triggerRepaint() | |
settings = QgsPalLayerSettings() | |
settings.fieldName = 'valore' | |
settings.placement = QgsPalLayerSettings.Placement.OverPoint | |
settings.enabled = True | |
text_format = QgsTextFormat() | |
text_format.setSize(10) | |
text_format.setColor(QColor('black')) | |
settings.setFormat(text_format) | |
labeling = QgsVectorLayerSimpleLabeling(settings) | |
layer.setLabelsEnabled(True) | |
layer.setLabeling(labeling) | |
layer.triggerRepaint() | |
print("π¨ Etichette e stile applicati.") | |
# === APPLICA STILE === | |
style_and_label_layer() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
resolve
solve_and_apply()
Check
check_grid()