código escrito · artículos digitales de informática
 
Baile de sudokus
11.03.2006 :: Jaime Irurzun

El cuatrimestre pasado se organizó un concurso de C/C++ en mi universidad. Se retaba a los alumnos de mi curso (2º) que quisieran paticipar a escribir el programa que resolviera cierto número de sudokus (leídos de un .txt y resueltos sobre otro .txt) en el menor tiempo posible. Lo organizaron los profesores de la asignatura de C++ que teníamos en ese momento, así que los premios eran muy tentadores: una matrícula de honor directa para quien consiguiera el programa más rápido, hasta 3 puntos más sobre la nota final para quien quedara segundo, y hasta 1 punto más para el que quedara tercero. Supongo que montaron el concurso pensando en despertar el interés de los frikis de la uni que tenemos el código fuente casi como un objeto fetiche. En mi caso lo consiguieron porque no dudé en presentarme.

En la fase de documentación descubrí que el método más rápido que existe consiste en implementar el algoritmo Dancing Links sobre una matriz de unos y ceros que describa las restricciones que debe cumplir una solución correcta del Sudoku. Es el mismo método que se aplica a otros problemas de tipo exact-cover, como el N-Reinas. Es muy difícil de explicar (bastante me costó a mi entenderlo), así que pienso que si alguien tiene interés en saber en qué consiste lo mejor que puede hacer es bajarse el PDF de Donald Knuth, su inventor.

Después de encontrar la técnica vino lo más difícil: aplicarlo a C++. No recuerdo unas Navidades con tanta presión encima ni otras 2 semanas en las que estuviera tan obsesionado con algún tema. Dormía pensando en punteros, me despertaba pensando en punteros y vivía imaginando la maldita matriz de 729x324 estructuras que no conseguía enlazar correctamente. Sabía que si conseguía que funcionara tendría muchas opciones de ganar (a menos que otro hubiera implementado Dancing Links y hubiera aplicado más optimizaciones que yo); pero si no lo conseguía me quedaría sin nada y habría perdido dos semanas de estudio para otras asignaturas. Una pesadilla.

Afortunadamente, el nuevo año me iluminó y a falta de 1 día para que se acabara el plazo de entrega conseguí que funcionara. Hubo suerte y quedé primero, pero sobre todo conseguí asentar un lenguaje de programación al que tenía ganas desde hacía tiempo. Aunque sigo siendo un novato en C++, creo que aquellas dos terribles semanas me ayudaron mucho a coger soltura en el lenguaje de propósito general más extendido (hablando de C/C++). Ahora creo estar preparado para abordar pequeños proyectos, y este cuatrimestre tendré la oportunidad de comprobarlo porque voy a tener que programar un videojuego con dos amigos para otra asignatura ;)

Cuando terminó el concurso se publicó en una lista de distribución el código de los dos primeros clasificados, pero no se colgó en ninguna web. Para los interesados en el tema, libero aquí el mío bajo licencia GPL:

comentarios (42) |


Comentarios del artículo
1 · xalernita · 12.03.2006

estás realmente loco ;)

siendo sincero yo la verdad es que empecé a leerme la documentación hacerca de los "dancing links" durante un par de días, pero nu fui capaz de pasar del #include jijijiji

enhorabuena por el éxito porque realmente el ser capaz de implementar este atentado a la sociabilidad de un ser es digno de mención

un saludo

2 · José F. Giménez · 12.03.2006

Jaime,

ENHORABUENA!!!

No hay nada como meterse de lleno en un reto difícil, lidiar con él y salir victorioso ;-)

Un saludo.

3 · marcgenou · 13.03.2006

me lo he bajado para echarle un ojo, y ahora que lo veo me pregunto si podrias aclararme el formato del fichero de entrada?

4 · Jaime Irurzun · 13.03.2006

Gracias a los dos, Jose y xalernita :) Os aseguro que la suerte me ha acompañado, y mucho.

marcgenou: La primera línea del ENTRADA.txt indica el nº de sudokus que hay en el fichero. Después viene un sudoku en cada línea (en cada línea hay 81 caracteres). Los símbolos '+' corresponden a espacios, que son los que hay que rellenar. Los números que aparecen son los números que vienen en el enunciado del sudoku. Aparecen las 81 casillas de golpe, pero el programa las lee entendiendo que los 9 primeros caracteres son la primera fila del sudoku, los 9 siguientes la segunda fila, etc. Si colocas cada fragmento de 9 caracteres, uno debajo del otro, te saldrá el tablero entero.

5 · alx · 13.03.2006

Eres el puto amo colega!!

ENHORABUENA

6 · ++h · 14.03.2006

Estás enfermo, jaja

Pero te lo merecias, vaya que si:)

7 · SQuaVeR · 14.03.2006

Wenaz! La verdad es que si parece que te lo has currao. De que universidad soys? En la mía no hacen esas cosas... Por curiosidad? Cuanto tiempo tarda en resolverte 1 sudoku? Yo hice un programa para resolver sudokus en C# para unas practicas de inteligencia artificial hace unos meses. No es gran cosa pq además está hecho en 2 ratos, pero si alguien quiere echarle un vistazo está en:
http://www.movileswindows.es/modules/mydownloads/viewcat.php?cid=13
Esta hecho para funcionar en un movil con Windows Mobile, aunque también funciona en una PDA o un PC con el .NET Framework :)

Un saludo!

8 · Makinolo · 14.03.2006

Ahora entiendo el por qué de la avalancha de visitas de mi post sobre el algoritmo de resolver sudokus :D (el mio era por fuerza bruta, recursividad con backtracking de la de toda la vida :)

Enhorabuena por haber sobrevivido a los punteros!!! jejeje

9 · Jaime Irurzun · 15.03.2006

SQuaVeR,

Voy a la universidad de Deusto (Bilbao). Ahora me tengo que ir pero a ver si mañana en un rato me bajo el código que escribiste tú (que sepas que me supondrá un esfuerzo después de esta pesadilla :P)

Sobre el tiempo, recuerdo que en las pruebas me salió que de media resolvía cada sudoku en unos 50-70 milisegundos. Eso no lo recuerdo muy exacto, pero lo que sí se me quedó grabado es que resolvía 100.000 sudokus en menos de 30 segundos :) En este caso hice la prueba desde fuera del programa, así que este tiempo incluye la carga del ejecutable y es menos objetivo. A ver si me pongo a hacer las pruebas rigurosamente y apunto los resultados ;)

Gracias al resto!

10 · marcgenou · 15.03.2006

gracias por la aclaracion y felicidades por haber vencido en tu lucha contra los sudokus :D

11 · José Luis · 15.03.2006

No quiero quitar méritos a tu código, pero el uso que haces de C++ en tu programa es mínimo (la declaración de variables sin tener que ser al comienzo de un bloque y el uso de cout y fstream en lugar de printf y fprintf).

Lo que has hecho es convertible en C con mínimos cambios. No has aprovechado el auténtico potencial de C++, que es la orientación a objetos.

Como programa en C (sin los mínimos usos de C++) es bueno. Como programa óptimo para resolver Sudokus es muy bueno. Como programa en C++ no lo es.

De todos modos el programa que tu has hecho no lo haría prácticamente ninguno de los alumnos de primer o segundo curso de informática. Así que ánimo.

Saludos.

12 · José Luis · 15.03.2006

Te puedo hacer, si no te parece mal, algún comentario sobre tu código:
a) desde el establecimiento del estándar de C++ en 1997, los ficheros de cabecera estándar de C++, como por ejemplo "iostream" (no así los de C), no llevan extensión .h. Si tu compilador lo admite es porque, o bien es muy antiguo (que lo dudo) o bien está en modo compatible pre-estándar.
b) Utilizas demasiados "números mágicos". Deberías utilizar defines o constantes.
c) Realizar operaciones restando/sumando 48 cuando quieres convertir un carácter que es un dígito en un número no es claro. Mejor restar o sumar directamente el carácter '0'.
d) Utilizas un operador ? como si fuera una sentencia, no aprovechándose de que es una expresión. El operador ? que invocas en la función ConvertirSudokus estaría mejor así:
*pSudokus = (*pSudokus == '+')? 0 : (*pSudokus - '0');
e) La gestión de errores mejor con excepciones que con códigos de retorno.

De todos modos, es código muy bueno para el poco tiempo que llevas en esto. Mucha gente con más experiencia lo hace igual o peor.

Saludos.

13 · José Luis · 16.03.2006

Por cierto, la memoria que reservas con new[] debes liberarla con delete[].

Saludos.

14 · Verónica · 29.03.2006

Makinolo,donde es donde tienes publicado el tuyo resuelto mediante fuerza bruta,necesito resolverlo en CAML y creo q el tuyo es el q mas me podría ayudar. Gracias.

15 · Pedro Amaro · 01.04.2006

Felicidades Jaime!!

Yo llevo algun tiempo con un problema que podria talvez resolverse con la misma idea del sudoku, voy ha estudiar tu codigo haber si entiendo algo.

Sigue con ese empeño..

16 · rcarlos · 03.04.2006

tuve un problema al hacer correr el programa me sale el error que el tamaño de la matriz es demasiado grande

17 · rcarlos · 03.04.2006

Por cierto me intereso mucho tu trabajo y lo estoy analizando para hacerlo yo pero en lenguaje java felicidades por haber triunfado en el reto que te impusiste espero hacer lo mismo

18 · Jaime Irurzun · 04.04.2006

José Luis,
Perdona por el retraso en contestarte. He estado muy metido en el proyecto del videojuego y no he pasado por el blog en días. Te agradezco tus consejos. En estos momentos no voy a meterme otra vez con el código, pero sí tengo pensado mejorarlo más adelante y seguramente aplicarlo a un jueguecillo que proponga sudokus con soluciones únicas :) Cuando me meta con ello miraré más en detalle lo que me dices. Gracias otra vez, y al resto también!

19 · Susana · 05.04.2006

Hola necesito hacer el sudoku en caml alguien tiene el algoritmo en pseudocodigo, me seria de gran ayuda muchas gracias.Veronica si lo consigues echame un cable porfavor.

20 · rcarlos · 07.04.2006

el algoritmo de dancing links para resolver sudokus esta en el PDF de Donal Knuth te lo puedes bajar del articulo Baile de sudokus de jaime, esta ingles yo lo tengo mas o menos codificado en java lo puedes examinar tambien en el programa de jaime el hipervinculo esta en el mismo articulo

21 · Raul · 11.04.2006

Hola. Yo estoy en la misma situación de Veronica y susana. NEcesito hacer un sudoku en Caml con listas y utilizando backtracking. Si alguien me puede echar una manilla se lo agradeceria. Un saludo

22 · Raul · 11.04.2006

Makinolo si me puedes pasar el pseudocódigo de tu sudoku te lo agradeceria mucho. Un saludo

23 · VERÓNICA · 12.04.2006

Os propongo a los q stamos liados con el sudoku en caml q en cuanto tengamos lo mas mínimo lo pongamos en común para poder ayudarnos entre nosotros.q os parece? mi email es verosb82@hotmail.com para si quereis comentarme algo,gracias.

24 · miki · 14.04.2006

hola. veo q hay gente q tiene el dixoso ejercicio resulto del sudoku. me ayudarian muxo si me pasaran el ejercicio resulto ya q me toy volviendo loco, lo necesito para ya.

25 · miki · 14.04.2006

por cierto manadarmelos a pablo1986_69@hotmail.com

26 · Verónica · 15.04.2006

Asi stamos todos MIKI,lo necesitamos para ya pero ninguno sabemos como hacerlo.

27 · susana · 17.04.2006

Hola sigo buscando algo para poder hacer el sudoku en caml raul y veronica os dejo mi direccion por si encontrais algo vale?muchas gracias. susana_martinezj@yahoo.es

28 · Chan · 19.04.2006

Hola yo también he estado buscando un algoritmo para poder resolver sudokus en caml, lo único que he encontrado es el algoritmo en Ocaml. Si encontrais algo o quereis el algoritmo en Ocaml decidmelo, os dejo el mail: remerchan@yahoo.es

29 · Luis · 19.04.2006

Buenas!!
Necesito el código xa resolver sudokus en caml. Enhorabuena a los q lo habeis logrado y si haceis el favor os agradecería que me lo enviarais a mi mail: que_tal_estamos@hotmail.com

Mil Gracias

30 · angel · 20.04.2006

Hola a todos y a todas, yo tb necesito hacer el sudoku en caml,llevo unos dias dandole vueltas y estoy un poco atascado,si alguien me puede echar una mano se lo agradeceria.

31 · angel · 20.04.2006

Por cierto mi correo es: angelgpri@hotmail.com

32 · medulla · 23.04.2006

que bueno tengo una entrega el 5 de mayo ...es un sudoku en caml con backtracking..no sabia q tanta gente estaba en la misma situacion..animo espero que alguno lo consiga...habra q hecharle horas..yo solo tengo una idea sobre la q trabajare pero si queresi todos los q esten interesados podriamos hacer un intercambio de ideas para intentar resolverlo entre todos y encontrar la solucion. una reunion en el mesenger :.susana, vero..y otros que veo por alli,,

33 · Verónica · 23.04.2006

Q idea tiens? mandame un email y lo compartimos si kieres lo qtengamos las dos.Yo tb tengo q entregarlo el 5 de mayo. Mi email es verosb82@hotmail.com. Agregame si kieres y hablamos.chao!

34 · Chan · 24.04.2006

Aquí va el código en Ocaml, si alguno sabe como trasladarlo a caml o simplemente entender cada una de las lineas que lo ponga, yo he estado intentandolo pero no es fácil.Si quereis poneros en contacto mi correo es remerchan@yahoo.es

open Array

let bits = init 9 (fun b -> b, 1 lsl b)
let group = init 81 (fun i -> [| i/9; 9 + i mod 9; 18 + (i/27)*3 + (i mod 9) / 3 |])
let card = init 512 (fun i -> fold_left (fun a (b,s) -> if i land s > 0 then a+1 else a) 0 bits)

let rec solve grid =
let free = make 27 511 in
iteri (fun i v -> iter (fun g -> free.(g) let poss = mapi (fun i v -> (i,v), fold_left (fun a g -> a land free.(g)) 511 group.(i)) grid in
let m,c = fold_left (fun (m,c) ((i,v),p) -> if v = 0 && card.(p) let subsolve value = let grid2 = copy grid in grid2.(c) if m = 10 then (iteri (fun i v -> print_int v; if i mod 9 = 8 then print_char '\n') grid; print_char '\n')
else if m > 0 then iter (fun (b,s) -> if (snd poss.(c)) land s > 0 then (subsolve (b+1))) bits

let _ =
let inp() = int_of_char (input_char stdin) - 48 in
solve (init 81 (fun i -> (if i > 0 && i mod 9 = 0 then ignore (inp())); inp()))

35 · Popi · 24.04.2006

Vaya, veo mucho alcalaíno por aquí jejeje.

Estamos todos igual de jodidos. :(

36 · SuperIndio · 26.04.2006

Che Chango vos sabes que existe un deporte llamado football ? Sabes que ya se invento el Televisor ?
Sabes que culearte una tia distinta todas las noche hace bien para la salud ?
Estas de la nuca man... Soy programador, hice algun juego aplicando matrices en pero si hubiera que tenido que hacer esto en aquellas epocas de facultad no solo habria terminado loco sino ademas seguro huviera renunciado y me habria notado en otra carrera como Nutricion Odontologia jejejeej

37 · David · 26.04.2006

Me uno al club, yo también tengo que resolver un Sudoku en Caml, cómo lo lleváis??????? Por desgracia yo también necesito ayuda. Muchas gracias. Mi e-mail es dsanchez75@gmail.com

38 · antipolako · 27.04.2006

polakoooooooooooooooooooo, ke frikazo ke eres tio... solo alguien como tu podia presentarse a eso y encima... CONTARLO !!! 2 PUTAS SEMANAS Y PICO !!! ERES UN ENFERMO !!!

...eso es no tener infancia... y lo demas son tonterias.
saludos
fdo:antiTU
p.d.: SIN ACRITUD

39 · Julius · 30.04.2006

Vaya, q de alcalainos. Weno, pos yo me disponia a empezar ahora...:P(entrega el 5 de mayo...) No parece tan dificil. Bueno, si consigo algo os lo hago saber. Vero, a ti te he agregado x si tenías alguna idea. Suerte a todos y ánimo.

40 · yaigjtech · 22.05.2006

wiimaeivhq sodkfi ytrwdajdne

41 · jean carlos tirado · 26.05.2006

de verdad q eres un sadico t felicito yo estoy estudiando informatica tenemos un programa q nos tiene loco sera q m puedes ayudar a realizar o m lo pueds explicar?ante mano muchas gracias....

42 · jean carlos tirado · 26.05.2006

Mi msn JEANC24@HOTMAIL.COM














































Creative Commons - Jaime Irurzun y Aitor Martin