(defstruct estado
ml cl ; misioneros y caníbales en la izquierda
mr cr ; misioneros y caníbales en la derecha
side ; 0 = bote a la izquierda, 1 = derecha
camino) ; lista de pasos previos
(defun estado-valido-p (st)
(let ((ml (estado-ml st))
(cl (estado-cl st))
(mr (estado-mr st))
(cr (estado-cr st)))
(and (>= ml 0) (<= ml 3)
(>= cl 0) (<= cl 3)
(>= mr 0) (<= mr 3)
(>= cr 0) (<= cr 3)
(or (= ml 0) (>= ml cl))
(or (= mr 0) (>= mr cr)))))
(defun mover (st m c)
(let* ((ml (estado-ml st))
(cl (estado-cl st))
(mr (estado-mr st))
(cr (estado-cr st))
(side (estado-side st)))
(if (= side 0)
;; Mover de izquierda a derecha
(make-estado :ml (- ml m) :cl (- cl c)
:mr (+ mr m) :cr (+ cr c)
:side 1
:camino (append (estado-camino st) (list (format nil "~dM~dC ->" m c))))
;; Mover de derecha a izquierda
(make-estado :ml (+ ml m) :cl (+ cl c)
:mr (- mr m) :cr (- cr c)
:side 0
:camino (append (estado-camino st) (list (format nil "~dM~dC <-" m c)))))))
(defun iguales (a b)
(and (= (estado-ml a) (estado-ml b))
(= (estado-cl a) (estado-cl b))
(= (estado-mr a) (estado-mr b))
(= (estado-cr a) (estado-cr b))
(= (estado-side a) (estado-side b))))
(defun repetido-p (nuevo historial)
(some (lambda (e) (iguales e nuevo)) historial))
(defparameter *viajes* '((2 0) (0 2) (1 1) (1 0) (0 1)))
(defun resolver (estado final historial)
(when (iguales estado final)
(mostrar-solucion (reverse (cons estado historial)))
(return-from resolver t))
(dolist (v *viajes*)
(let ((m (first v))
(c (second v)))
(let ((nuevo (mover estado m c)))
(when (and (estado-valido-p nuevo)
(not (repetido-p nuevo historial)))
(when (resolver nuevo final (cons estado historial))
(return-from resolver t)))))))
(defun personas (m c)
(concatenate 'string
(make-string m :initial-element #\M)
(make-string c :initial-element #\C)))
(defun lado-a-string (m c)
(format nil "[~3a]" (personas m c)))
;; FUNCIÓN CORREGIDA: Ahora siempre muestra ambos lados
(defun mostrar-paso (anterior actual)
(let ((side (estado-side anterior))
(ml (estado-ml anterior))
(cl (estado-cl anterior))
(mr (estado-mr anterior))
(cr (estado-cr anterior))
(movimiento (car (last (estado-camino actual)))))
(format t "~%Estado actual: ~a ~a ~a"
(lado-a-string ml cl)
(if (= side 0) " B ~~~~ " " ~~~~ B ")
(lado-a-string mr cr))
(format t "~%Acción: ~a" movimiento)))
(defun mostrar-solucion (camino)
(format t "~%====================================")
(format t "~%SOLUCIÓN ENCONTRADA")
(loop for (a b) on camino while b do
(mostrar-paso a b))
;; Mostrar el estado final alcanzado
(let ((ultimo (car (last camino))))
(format t "~%Estado Final: ~a ~a ~a"
(lado-a-string (estado-ml ultimo) (estado-cl ultimo))
" ~~~~ B "
(lado-a-string (estado-mr ultimo) (estado-cr ultimo))))
(format t "~%====================================~%"))
(defun main ()
(let ((inicio (make-estado :ml 3 :cl 3 :mr 0 :cr 0 :side 0 :camino '()))
(fin (make-estado :ml 0 :cl 0 :mr 3 :cr 3 :side 1 :camino '())))
(resolver inicio fin '())))
(main)