fork download
  1. ;;; ==========================================
  2. ;;; SISTEMA EXPERTO DE IDENTIFICACIÓN ANIMAL
  3. ;;; ==========================================
  4.  
  5. (defvar *rules* nil) ; Nuestra base de conocimientos (reglas)
  6. (defvar *known-facts* nil) ; Lo que vamos aprendiendo del animal actual
  7. (defvar *asked-questions* nil)
  8.  
  9. (defun init-rules ()
  10. "Definimos las reglas de lógica. El símbolo -> separa premisas de la conclusión."
  11. (setf *rules*
  12. '(
  13. ;; Reglas de clasificación base (Categorías)
  14. (has-hair -> mammal)
  15. (gives-milk -> mammal)
  16. (has-feathers -> bird)
  17. (mammal eats-meat -> carnivore)
  18. (mammal has-pointed-teeth has-claws forward-eyes -> carnivore)
  19. (mammal has-hooves -> ungulate)
  20. (bird flies -> bird-prey)
  21. (bird-ungulate black-white (not flies) -> ostrich)
  22.  
  23. ;; Identificación de animales específicos
  24. (carnivore tawny dark-spots -> cheetah)
  25. (carnivore tawny black-stripes -> tiger)
  26. (ungulate long-neck dark-spots (not carnivore) -> giraffe)
  27. (ungulate black-stripes -> zebra)
  28. (bird swims (not flies) black-white -> penguin)
  29. (bird-prey large -> albatross)
  30.  
  31. ;; --- NUEVOS ANIMALES ---
  32. ;; Un zorro: es un carnívoro, pequeño y tiene una cola peluda
  33. (carnivore small bushy-tail -> fox)
  34. ;; Un pollo: es un ave, vive en granja y (generalmente) no vuela
  35. (bird farm-animal (not flies) -> chicken)
  36. ))
  37. )
  38.  
  39. ;; --- FUNCIONES DE APOYO ---
  40.  
  41. (defun split-rule (rule)
  42. "Corta la regla para saber qué necesitamos (condiciones) y qué obtenemos (conclusión)."
  43. (let ((arrow-pos (position '-> rule)))
  44. (if arrow-pos
  45. (values (subseq rule 0 arrow-pos) (nth (+ arrow-pos 1) rule))
  46. (error "La regla no tiene flecha '->': ~A" rule))))
  47.  
  48. (defun get-user-input (question)
  49. "Le pregunta al usuario. 'Is it true?' significa '¿Es cierto?'."
  50. (let ((fact-true (member question *known-facts* :test #'equal))
  51. (fact-false (member `(not ,question) *known-facts* :test #'equal)))
  52. (cond
  53. (fact-true t)
  54. (fact-false nil)
  55. (t
  56. ;; Usamos ~A para insertar la pregunta en el texto
  57. (format t "~%* Is it true that it ~A? (y/n) > " question)
  58. (finish-output)
  59. (let ((ans (read)))
  60. (cond
  61. ((member ans '(y Y yes YES))
  62. (push question *known-facts*)
  63. t)
  64. ((member ans '(n N no NO))
  65. (push `(not ,question) *known-facts*)
  66. nil)
  67. (t (format t "Please answer 'y' or 'n'.~%")
  68. (get-user-input question))))))))
  69.  
  70. (defun check-condition (condition)
  71. "Analiza si una condición se cumple, manejando el caso de las negaciones (not X)."
  72. (if (and (listp condition) (eq (car condition) 'not))
  73. (not (check-condition (cadr condition)))
  74. (get-user-input condition)))
  75.  
  76. ;; --- EL MOTOR LÓGICO ---
  77.  
  78. (defun prove-goal (goal)
  79. "Intenta demostrar una meta buscando reglas que la respalden."
  80. (if (member goal *known-facts* :test #'equal)
  81. t
  82. (loop for rule in *rules* do
  83. (multiple-value-bind (conditions conclusion) (split-rule rule)
  84. (when (equal goal conclusion)
  85. (format t "~%Checking if it is a ~A..." goal)
  86. ;; Si todas las condiciones de la regla son ciertas, ¡lo encontramos!
  87. (if (every #'check-condition conditions)
  88. (progn
  89. (push goal *known-facts*)
  90. (return-from prove-goal t))))))
  91. nil))
  92.  
  93. ;; --- INTERACCIÓN PRINCIPAL ---
  94.  
  95. (defun identify-animal ()
  96. "Función principal: limpia la memoria y recorre la lista de posibles animales."
  97. (setf *known-facts* nil)
  98. (init-rules)
  99. (format t "--- System Ready! Let's find the animal ---~%")
  100.  
  101. ;; Añadimos fox y chicken a la lista de búsqueda
  102. (let ((animals '(cheetah tiger giraffe zebra penguin albatross ostrich fox chicken))
  103. (found nil))
  104.  
  105. (dolist (animal animals)
  106. (when (prove-goal animal)
  107. (setf found animal)
  108. (return)))
  109.  
  110. (format t "~%========================================")
  111. (if found
  112. (format t "~%*** RESULT: It is a ~A! ***" found)
  113. (format t "~%*** RESULT: I don't know this animal. ***"))
  114. (format t "~%========================================~%"))
  115. )
  116.  
  117. ;; Para iniciar el sistema: (identify-animal)
Success #stdin #stdout #stderr 0.02s 9504KB
stdin
Standard input is empty
stdout
Standard output is empty
stderr
Warning: reserving address range 0x80000c0000...0x1fffffffffff that contains memory mappings. clisp might crash later!
Memory dump:
  0x8000000000 - 0x80000bffff
  0x149574e00000 - 0x1495750e4fff
  0x149575215000 - 0x149575239fff
  0x14957523a000 - 0x1495753acfff
  0x1495753ad000 - 0x1495753f5fff
  0x1495753f6000 - 0x1495753f8fff
  0x1495753f9000 - 0x1495753fbfff
  0x1495753fc000 - 0x1495753fffff
  0x149575400000 - 0x149575402fff
  0x149575403000 - 0x149575601fff
  0x149575602000 - 0x149575602fff
  0x149575603000 - 0x149575603fff
  0x149575680000 - 0x14957568ffff
  0x149575690000 - 0x1495756c3fff
  0x1495756c4000 - 0x1495757fafff
  0x1495757fb000 - 0x1495757fbfff
  0x1495757fc000 - 0x1495757fefff
  0x1495757ff000 - 0x1495757fffff
  0x149575800000 - 0x149575803fff
  0x149575804000 - 0x149575a03fff
  0x149575a04000 - 0x149575a04fff
  0x149575a05000 - 0x149575a05fff
  0x149575a72000 - 0x149575a75fff
  0x149575a76000 - 0x149575a76fff
  0x149575a77000 - 0x149575a78fff
  0x149575a79000 - 0x149575a79fff
  0x149575a7a000 - 0x149575a7afff
  0x149575a7b000 - 0x149575a7bfff
  0x149575a7c000 - 0x149575a89fff
  0x149575a8a000 - 0x149575a97fff
  0x149575a98000 - 0x149575aa4fff
  0x149575aa5000 - 0x149575aa8fff
  0x149575aa9000 - 0x149575aa9fff
  0x149575aaa000 - 0x149575aaafff
  0x149575aab000 - 0x149575ab0fff
  0x149575ab1000 - 0x149575ab2fff
  0x149575ab3000 - 0x149575ab3fff
  0x149575ab4000 - 0x149575ab4fff
  0x149575ab5000 - 0x149575ab5fff
  0x149575ab6000 - 0x149575ae3fff
  0x149575ae4000 - 0x149575af2fff
  0x149575af3000 - 0x149575b98fff
  0x149575b99000 - 0x149575c2ffff
  0x149575c30000 - 0x149575c30fff
  0x149575c31000 - 0x149575c31fff
  0x149575c32000 - 0x149575c45fff
  0x149575c46000 - 0x149575c6dfff
  0x149575c6e000 - 0x149575c77fff
  0x149575c78000 - 0x149575c79fff
  0x149575c7a000 - 0x149575c7ffff
  0x149575c80000 - 0x149575c82fff
  0x149575c85000 - 0x149575c85fff
  0x149575c86000 - 0x149575c86fff
  0x149575c87000 - 0x149575c87fff
  0x149575c88000 - 0x149575c88fff
  0x149575c89000 - 0x149575c89fff
  0x149575c8a000 - 0x149575c90fff
  0x149575c91000 - 0x149575c93fff
  0x149575c94000 - 0x149575c94fff
  0x149575c95000 - 0x149575cb5fff
  0x149575cb6000 - 0x149575cbdfff
  0x149575cbe000 - 0x149575cbefff
  0x149575cbf000 - 0x149575cbffff
  0x149575cc0000 - 0x149575cc0fff
  0x55d67d3bb000 - 0x55d67d4abfff
  0x55d67d4ac000 - 0x55d67d5b5fff
  0x55d67d5b6000 - 0x55d67d615fff
  0x55d67d617000 - 0x55d67d645fff
  0x55d67d646000 - 0x55d67d676fff
  0x55d67d677000 - 0x55d67d67afff
  0x55d67ed1b000 - 0x55d67ed3bfff
  0x7ffe87c7f000 - 0x7ffe87c9ffff
  0x7ffe87df4000 - 0x7ffe87df7fff
  0x7ffe87df8000 - 0x7ffe87df9fff