Skip to content

Instantly share code, notes, and snippets.

@pigreco
Created May 6, 2025 15:52
Show Gist options
  • Save pigreco/d4909f7f2c942b87d4c08bf648815af9 to your computer and use it in GitHub Desktop.
Save pigreco/d4909f7f2c942b87d4c08bf648815af9 to your computer and use it in GitHub Desktop.
Sudoku
# === 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()
@pigreco
Copy link
Author

pigreco commented May 6, 2025

resolve

solve_and_apply()

Check

check_grid()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment