Ver Mensaje Individual
  #13 (permalink)  
Antiguo 12/10/2015, 21:16
Avatar de NSD
NSD
Colaborador
 
Fecha de Ingreso: mayo-2012
Ubicación: Somewhere
Mensajes: 1.332
Antigüedad: 11 años, 11 meses
Puntos: 320
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
  1. % Tipos de (magia, daño) en el orden de preferencia.
  2. magic(hielo, 500).
  3. magic(fuego, 250).
  4. magic(rayo,  125).
  5.  
  6. % Realizar ataques.
  7. destroy(HP, Previous, Attacks) :- HP > 0,  % Mientras este vivo.
  8.                                   magic(Type, Damage),  % Seleccionar una magia para usar.
  9.                                   NewHP is HP - Damage,  % Computar daño.
  10.                                   destroy(NewHP, [Type|Previous], Attacks).  % Seguir peleando.
  11.                                  
  12. % Hasta derrotar al objetivo.
  13. destroy(HP, Previous, Previous) :- 0 >= HP.
  14.  
  15. % Sugar.
  16. 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
  1. % Cambiar esto:
  2. % destroy(HP, Previous, Previous) :- 0 >= HP.
  3. % Por esto:
  4. destroy(0, Previous, Previous).
  5. % Que es lo mismo que esto:
  6. % 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
  1. % Tipos de (magia, daño) en el orden de preferencia.
  2. magic(hielo, 500).
  3. magic(fuego, 250).
  4. magic(rayo,  125).
  5.  
  6. % Realizar ataques.
  7. destroy(HP, Number, Previous, Attacks) :- HP > 0,                           % Mientras este vivo.
  8.                                   length(Previous, Length),                 % Contar ataques realizados.
  9.                                   Length < Number,                          % Hay ataques disponibles.
  10.                                   magic(Type, Damage),                      % Seleccionar una magia para usar.
  11.                                   NewHP is HP - Damage,                     % Computar daño.
  12.                                   destroy(NewHP, Number, [Type|Previous], Attacks). % Seguir peleando.
  13.                                  
  14. % Hasta derrotar al objetivo.
  15. destroy(HP, Number, Previous, Previous) :- 0 >= HP.
  16.  
  17. % Sugar.
  18. 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
  1. % Cambiar esto:
  2. % destroy(HP, Number, Previous, Previous) :- 0 >= HP.
  3. % Por esto:
  4. 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