(defstruct estado
ml cl mr cr side camino)
(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 ((side (estado-side st)))
(if (= side 0)
(make-estado :ml (- (estado-ml st) m) :cl (- (estado-cl st) c)
:mr (+ (estado-mr st) m) :cr (+ (estado-cr st) c)
:side 1
:camino (append (estado-camino st) (list (format nil "~dM~dC ->" m c))))
(make-estado :ml (+ (estado-ml st) m) :cl (+ (estado-cl st) c)
:mr (- (estado-mr st) m) :cr (- (estado-cr st) 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)))
;; Contador global para identificar las soluciones
(defparameter *contador-soluciones* 0)
(defun resolver (estado final historial)
(when (iguales estado final)
(incf *contador-soluciones*)
(mostrar-solucion (reverse (cons estado historial)) *contador-soluciones*)
;; NO ponemos return-from para que siga buscando más caminos
(return-from resolver nil))
(dolist (v *viajes*)
(let* ((m (first v))
(c (second v))
(nuevo (mover estado m c)))
(when (and (estado-valido-p nuevo)
(not (repetido-p nuevo historial)))
(resolver nuevo final (cons estado historial))))))
(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)))
(defun mostrar-paso (anterior actual)
(let ((side (estado-side anterior))
(movimiento (car (last (estado-camino actual)))))
(format t "~%~a ~a ~a | Acción: ~a"
(lado-a-string (estado-ml anterior) (estado-cl anterior))
(if (= side 0) " B ~~~~ " " ~~~~ B ")
(lado-a-string (estado-mr anterior) (estado-cr anterior))
movimiento)))
(defun mostrar-solucion (camino n)
(format t "~%~%====================================")
(format t "~%SOLUCIÓN NÚMERO ~d" n)
(format t "~%====================================")
(loop for (a b) on camino while b do (mostrar-paso a b))
(let ((u (car (last camino))))
(format t "~%~a ~~~~ B ~a | ¡Llegaron!"
(lado-a-string (estado-ml u) (estado-cl u))
(lado-a-string (estado-mr u) (estado-cr u)))))
(defun main ()
(setf *contador-soluciones* 0) ; Reiniciar contador
(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 '())
(format t "~%~%Búsqueda finalizada. Se encontraron ~d soluciones.~%" *contador-soluciones*)))
(main)