93 lines
2.9 KiB
Python
93 lines
2.9 KiB
Python
|
|
||
|
|
||
|
def encuentra_prox_vacio(puzzle):
|
||
|
"""
|
||
|
Encuentra la próxima fila, columna del puzzle sin llenar
|
||
|
(están representadas como -1)
|
||
|
retorna tupla (indice fila, indice columna) o (None, None)
|
||
|
en caso de no existir.
|
||
|
"""
|
||
|
for f in range(9):
|
||
|
for c in range(9):
|
||
|
if puzzle[f][c] == -1:
|
||
|
return f, c
|
||
|
return None, None
|
||
|
|
||
|
def es_valida(puzzle, intento, fil, col):
|
||
|
"""
|
||
|
Valida el intento en fila/columna
|
||
|
retorna True si es valida, Falso si no.
|
||
|
"""
|
||
|
# comenzar con los valores de fila:
|
||
|
fil_vals = puzzle[fil]
|
||
|
if intento in fil_vals:
|
||
|
return False
|
||
|
|
||
|
# ahora los valores de columna
|
||
|
#col_vals = []
|
||
|
#for i in range(9):
|
||
|
# col_vals.append(puzzle[i][col])
|
||
|
col_vals = [puzzle[i][col] for i in range(9)]
|
||
|
if intento in col_vals:
|
||
|
return False
|
||
|
|
||
|
# ahora el bloque 3x3
|
||
|
# encontrar donde empieza cada bloque, e iterar sobre
|
||
|
# los 3 valores de fila/columna
|
||
|
fil_start = (fil // 3) * 3
|
||
|
col_start = (col // 3) * 3
|
||
|
for f in range(fil_start, fil_start + 3):
|
||
|
for c in range(col_start, col_start +3):
|
||
|
if puzzle[f][c] == intento:
|
||
|
return False
|
||
|
|
||
|
# Al llegar aquí el intento es válido
|
||
|
return True
|
||
|
|
||
|
def resolver_sodoku(puzzle):
|
||
|
"""
|
||
|
Resuelve sodoku usando 'backtracking'.
|
||
|
El puzzle es una lista de listas, donde cada
|
||
|
lista interna es una fila en el puzzle.
|
||
|
retorna exista solución o no.
|
||
|
"""
|
||
|
# paso 1: Escoger un lugar en el puzzle para intetar solución
|
||
|
fil, col = encuentra_prox_vacio(puzzle)
|
||
|
|
||
|
# paso 1.1: Validación
|
||
|
if fil is None:
|
||
|
return True
|
||
|
|
||
|
# paso 2: Si hay lugar para poner un número, entonces hace un intento (1-9)
|
||
|
for intento in range(1, 10):
|
||
|
# paso 3: validar posición
|
||
|
if es_valida(puzzle, intento, fil, col):
|
||
|
# paso 3.1: intento validado, proceder con la jugada
|
||
|
puzzle[fil][col] = intento
|
||
|
# paso 4: llamado recursivo a funcion resolver_sodoku()
|
||
|
if resolver_sodoku(puzzle):
|
||
|
return True
|
||
|
# paso 5: si el intento no es válido o no resuelve el puzzle
|
||
|
# entoncens retroceder un paso y haver nuevo intento
|
||
|
puzzle[fil][col] = -1 # resetea el intento
|
||
|
# paso 6: si ningún intento funcion entonves el puzzle no tiene solución
|
||
|
return False
|
||
|
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
tablero_ejemplo = [
|
||
|
[3, 9, -1, -1, 5, -1, -1, -1, -1],
|
||
|
[-1, -1, -1, 2, -1, -1, -1, -1, 5],
|
||
|
[-1, -1, -1, 7, 1, 9, -1, 8, -1],
|
||
|
|
||
|
[-1, 5, -1, -1, 6, 8, -1, -1, -1],
|
||
|
[2, -1, 6, -1, -1, 3, -1, -1, -1],
|
||
|
[-1, -1, -1, -1, -1, -1, -1, -1, 4],
|
||
|
|
||
|
[5, -1, -1, -1, -1, -1, -1, -1, -1],
|
||
|
[6, 7, -1, 1, -1, 5, -1, 4, -1],
|
||
|
[1, -1, 9, -1, -1, -1, 2, -1, -1]
|
||
|
]
|
||
|
print(resolver_sodoku(tablero_ejemplo))
|
||
|
print(tablero_ejemplo)
|