Respuesta: Reto/favor: Plantead problemas sencillos que no pueda resolver. Cita: Como se ve, el que haya números o textos sólo importa si el problema requiere más de una acción para resolverse. ¿Qué significa eso?
Ejemplo de problema solucionable en 1 acción:
Tu rival tiene 500 HP, debes reducirlos a 0 o menos y dispones de 3 ataques:
1- Magia de fuego, que le quita 250
2- Magia de rayo, que le quita 125
3- Magia de hielo, que le quita 500
Podría agregar posibles ataques pero está claro que el problema puede solucionarse en 1 acción, 1 ataque.
Para estos problemas hice este diagrama:
...pero fue antes de haber hecho el "algoritmo" de arriba, es decir, este tipo de problemas se dividen en 2 y quizá otros (debo ver el algoritmo, no lo sé de memoria): Los que requieren definir situación y acciones y los que sólo una de ellas. En estos casos, en vez de romperse la cabeza pensando algoritmos complicados, es mejor cambiar de enfoque y dividir al problema en dos partes: "QUE tiene que resolver" y "COMO tiene que resolverlo", en el paradigma funcional y lógico, el "COMO" lo resuelve la herramienta, mientras que tu solo tienes que definirle "QUE" es lo que hay que hacer.
Ej:
Código Prolog:
Ver original% Tipos de (magia, daño) en el orden de preferencia. magic(hielo, 500). magic(fuego, 250). magic(rayo, 125). % Realizar ataques. destroy(HP, Previous, Attacks) :- HP > 0, % Mientras este vivo. magic(Type, Damage), % Seleccionar una magia para usar. NewHP is HP - Damage , % Computar daño. destroy(NewHP, [Type|Previous], Attacks). % Seguir peleando. % Hasta derrotar al objetivo. destroy(HP, Previous, Previous) :- 0 >= HP. % Sugar. destroy(HP, Attacks) :- destroy(HP, [], Attacks).
Eso genera todas y cada una de las soluciones posibles al problema: Cita: ?- destroy(500, Attacks).
Attacks = [hielo] ;
Attacks = [hielo, fuego] ;
Attacks = [fuego, fuego] ;
Attacks = [hielo, rayo, fuego] ;
Attacks = [fuego, rayo, fuego] ;
Attacks = [rayo, rayo, fuego] ;
Attacks = [hielo, rayo] ;
Attacks = [hielo, fuego, rayo] ;
Attacks = [fuego, fuego, rayo] ;
Attacks = [rayo, fuego, rayo] ;
Attacks = [hielo, rayo, rayo] ;
Attacks = [fuego, rayo, rayo] ;
Attacks = [hielo, rayo, rayo, rayo] ;
Attacks = [fuego, rayo, rayo, rayo] ;
Attacks = [rayo, rayo, rayo, rayo] ; Definir que solo quieres las soluciones que derroten con exactitud a tu adversario (que dejen sus HP en 0 pero no en negativo) es tan simple como:
Código Prolog:
Ver original% Cambiar esto: % destroy(HP, Previous, Previous) :- 0 >= HP. % Por esto: destroy(0, Previous, Previous). % Que es lo mismo que esto: % destroy(HP, Previous, Previous) :- 0 = HP.
En ese caso las soluciones cambian: Cita: ?- destroy(500, Attacks).
Attacks = [hielo] ;
Attacks = [fuego, fuego] ;
Attacks = [rayo, rayo, fuego] ;
Attacks = [rayo, fuego, rayo] ;
Attacks = [fuego, rayo, rayo] ;
Attacks = [rayo, rayo, rayo, rayo] ; Si la consiga es destruirlo en hasta N ataques, donde N > 0, entonces podemos definir la logica de esta forma:
Código Prolog:
Ver original% Tipos de (magia, daño) en el orden de preferencia. magic(hielo, 500). magic(fuego, 250). magic(rayo, 125). % Realizar ataques. destroy (HP , Number, Previous , Attacks ) :- HP > 0, % Mientras este vivo. length(Previous, Length), % Contar ataques realizados. Length < Number, % Hay ataques disponibles. magic(Type, Damage), % Seleccionar una magia para usar. NewHP is HP - Damage , % Computar daño. destroy (NewHP , Number, [Type |Previous ], Attacks ). % Seguir peleando. % Hasta derrotar al objetivo. destroy (HP , Number, Previous , Previous ) :- 0 >= HP . % Sugar. destroy (HP , Number, Attacks ) :- destroy (HP , Number, [], Attacks ).
Podemos ver que: Cita: ?- destroy(500, 1, Attacks).
Attacks = [hielo] ;
?- destroy(500, 2, Attacks).
Attacks = [hielo] ;
Attacks = [hielo, fuego] ;
Attacks = [fuego, fuego] ;
Attacks = [hielo, rayo] ;
?- destroy(500, 3, Attacks).
Attacks = [hielo] ;
Attacks = [hielo, fuego] ;
Attacks = [fuego, fuego] ;
Attacks = [hielo, rayo, fuego] ;
Attacks = [fuego, rayo, fuego] ;
Attacks = [rayo, rayo, fuego] ;
Attacks = [hielo, rayo] ;
Attacks = [hielo, fuego, rayo] ;
Attacks = [fuego, fuego, rayo] ;
Attacks = [rayo, fuego, rayo] ;
Attacks = [hielo, rayo, rayo] ;
Attacks = [fuego, rayo, rayo] ;
?- destroy(500, 4, Attacks).
Attacks = [hielo] ;
Attacks = [hielo, fuego] ;
Attacks = [fuego, fuego] ;
Attacks = [hielo, rayo, fuego] ;
Attacks = [fuego, rayo, fuego] ;
Attacks = [rayo, rayo, fuego] ;
Attacks = [hielo, rayo] ;
Attacks = [hielo, fuego, rayo] ;
Attacks = [fuego, fuego, rayo] ;
Attacks = [rayo, fuego, rayo] ;
Attacks = [hielo, rayo, rayo] ;
Attacks = [fuego, rayo, rayo] ;
Attacks = [hielo, rayo, rayo, rayo] ;
Attacks = [fuego, rayo, rayo, rayo] ;
Attacks = [rayo, rayo, rayo, rayo] ; Si lo que queremos es derrotarlo exactamente en N ataques, con N > 0, entonces lo que debemos modificar es:
Código Prolog:
Ver original% Cambiar esto: % destroy(HP, Number, Previous, Previous) :- 0 >= HP. % Por esto: destroy (HP , Number, Previous , Previous ) :- 0 >= HP , length (Previous , Length ), Length = Number.
Obteniendo así: Cita: ?- destroy(500, 1, Attacks).
Attacks = [hielo] ;
?- destroy(500, 2, Attacks).
Attacks = [hielo, fuego] ;
Attacks = [fuego, fuego] ;
Attacks = [hielo, rayo] ;
?- destroy(500, 3, Attacks).
Attacks = [hielo, rayo, fuego] ;
Attacks = [fuego, rayo, fuego] ;
Attacks = [rayo, rayo, fuego] ;
Attacks = [hielo, fuego, rayo] ;
Attacks = [fuego, fuego, rayo] ;
Attacks = [rayo, fuego, rayo] ;
Attacks = [hielo, rayo, rayo] ;
Attacks = [fuego, rayo, rayo] ;
?- destroy(500, 4, Attacks).
Attacks = [hielo, rayo, rayo, rayo] ;
Attacks = [fuego, rayo, rayo, rayo] ;
Attacks = [rayo, rayo, rayo, rayo] ;
?- destroy(500, 5, Attacks).
false. Como veras, viendo el mismo problema desde diferentes ángulos hay diferentes soluciones.
__________________ Maratón de desafíos PHP Junio - Agosto 2015 en FDW | Reglamento - Desafios |