La primera resolución que vi
La escena que describo en la página [Acerca de](/es/about/) es este modelo. La IA que resolvía sudokus iba rellenando las respuestas una a una, fila por fila, desde la primera casilla. Parecía un niño pequeño que ya se sabía las respuestas.
Datos de entrenamiento hechos con la hoja de soluciones
Los primeros datos de entrenamiento se hicieron con dataset_sudoku.py. El motor genera el puzzle junto con su solución, y escribir el número correcto en la primera casilla vacía del tablero (fila por fila desde arriba a la izquierda) se guarda como un problema. Se rellena esa casilla, se pasa a la siguiente casilla vacía y se repite hasta llenar el tablero.
De 300 tableros fáciles, medios y difíciles salieron 13.497 problemas, con los que se entrenó Qwen3-VL-2B-Instruct mediante LoRA (lora_stoku).
En el prompt también se incluía la lista de jugadas posibles. Pero la respuesta correcta era siempre la primera casilla vacía. Aunque en (0,3) cupieran tanto el 5 como el 9, si la hoja de soluciones decía 9, la respuesta era 9. Por qué era 9 no aparecía en ninguna parte de los datos.

¿Se podía resolver esa casilla en ese momento?
Revisé las casillas de respuesta de los 13.497 problemas usando solo el tablero de ese momento.
- Casillas con un solo número candidato: 9.502 (70%)
- Casillas que eran el único sitio para ese número dentro de su fila, columna o caja: 2.127 (16%)
- Casillas que ninguno de los dos métodos podía decidir y que necesitaban la hoja de soluciones: 1.868 (14%)
Las casillas que necesitaban la hoja de soluciones eran alrededor del 21% en difícil, el 12% en medio y el 5% en fácil. Una persona se saltaría esas casillas y rellenaría primero las seguras. El modelo aprendió a escribir en la misma posición el número de la hoja de soluciones.

El código real de este paso
Esta es la función que genera los primeros datos de entrenamiento. empties[0] es la primera casilla vacía contando desde arriba a la izquierda, y el valor se toma de engine.solution.
dataset_sudoku.py
def generate_game_samples(
engine: SudokuEngine,
difficulty: str,
game_id: int,
image_dir: Path,
) -> list[dict]:
engine.new_game(difficulty)
board = [row[:] for row in engine.puzzle]
given_mask = [[engine.is_given(r, c) for c in range(9)] for r in range(9)]
samples: list[dict] = []
step = 0
while True:
empties = [(r, c) for r in range(9) for c in range(9) if board[r][c] == 0]
if not empties:
break
r, c = empties[0]
value = engine.solution[r][c]
img = board_to_image(board, given_mask)
img_name = f"g{game_id:05d}_s{step:02d}.png"
img_path = image_dir / img_name
img.save(img_path)
answer = json.dumps({"row": r, "col": c, "value": value}, ensure_ascii=False)
prompt = build_sudoku_prompt(board, given_mask)
samples.append(
{
"id": f"g{game_id:05d}_s{step:02d}",
"image_path": str(img_path.resolve()),
"prompt": prompt,
"answer": answer,
"difficulty": difficulty,
}
)
board[r][c] = value
step += 1
return samplesLa siguiente entrada es "2. No pudo aprender por ensayo y error".
COMMENTS · CHAPTER 01
Una IA que resuelve como un niño que ya sabe las respuestas 0 comentarios
Todavía no hay comentarios. Deja una pregunta o algo que quieras añadir.
Para publicar un comentario, empieza con Google y registra un apodo y un correo.
Empezar con Google