You are on page 1of 3

EL PROBLEMA DE LOS MISIONEROS Y CANIBALES

Autor: Javier Navarrete T. (jnavarrete@softein.com)

Tres misioneros y tres canbales estn en una de las mrgenes de un ro junto a un bote en la que slo cabe 1 o 2 personas. Hay que encontrar la manera de pasarlos al otro lado del ro pero teniendo cuidado que en ningn momento quede un grupo de misioneros junto con un grupo de canbales, siendo la cantidad de misioneros menor a la de canbales. DEFINICION DEL PROBLEMA Se debe considerar una secuencia ordenada de 3 nmeros que representarn: la cantidad de misioneros, canbales y en que orilla del ro se encuentran. Por lo tanto, el estado inicial ser: 3,3,1. El estado objetivo ser: 0,0,0 en la orilla izquierda y 3,3,1 en la orilla derecha. Operadores posibles: Pueden ser que un bote: No lleva ningn misionero y lleva un canbal. Lleva 2 misioneros y ningn canbal. Lleva 2 canbales y ningn misionero. Lleva 1 canbal y un misionero. No lleva ningn canbal y lleva un misionero. Solo est permitido si hay igual o ms misioneros que canbales en una orilla o no hay misioneros que afectar en una orilla. Se utilizar la bsqueda preferente por profundidad o depth search first.

En la bsqueda preferente por profundidad siempre se expande uno de los nodos que se encuentre en los ms profundo de rbol, por lo tanto los nodos sucesores estarn a profundidades cada vez mayores. DESARROLLO EN PROLOG:
/* Problema de los Canbales y Misioneros usando bsqueda Depth First Desarrollado en : Visual Prolog v. 5.1 (versin gratuita de Prolog (VIP.exe) bajada de : www.visual-prolog.com ). Autor : Javier Navarrete T. ******************************************************************************************** */ domains orilla=orilla(byte,byte,byte) bote=bote(byte,byte) hecho=hecho(orilla,orilla) database - canymis hecho(orilla,orilla) predicates ejecutar. profundidad(orilla,orilla). ejecutar_movimiento(orilla,orilla,orilla,orilla). movimiento(orilla,orilla,orilla,orilla). imprime_estado(orilla,orilla). invertir_orillaOproceder(orilla,orilla,orilla,orilla). mostrar_movimiento(bote). movimiento(bote).

permitido(orilla). adicionar(orilla, bote, orilla). quitar(orilla, bote, orilla). aplicable(orilla,bote). mostrar_bote(byte). clauses ejecutar :/* llama a ejecutar para resolver */ assert(hecho(orilla(3,3,1), orilla(0,0,0))), /* estado inicial */ /* Estado INICIAL = 3 misioneros, 3 canbales y 1 bote en la orilla izquierda y nada en la orilla derecha */ profundidad(orilla(3,3,1),orilla(0,0,0)). /* busca a partir de este estado */ /* 5 posibles movimientos - no necesariamente permitidos */ movimiento(bote(0,1)). /* No lleva ningn misionero y lleva un canbal */ movimiento(bote(2,0)). /* Lleva 2 misioneros y ningn canbal */ movimiento(bote(0,2)). /* Lleva 2 canbales y ningn misionero */ movimiento(bote(1,1)). /* Lleva 1 canbal y un misionero (se supone que hay un barquero que los cuida)*/ movimiento(bote(1,0)). /* No lleva ningn canbal y lleva un misionero */ /* si la situacin es permitida */ permitido(orilla(0,_,_)) :- !. /* corte continua donde qued */ permitido(orilla(M,C,_)) :- M >= C. /* si hay igual o ms misioneros que canibales para que no se los coman */ profundidad(orilla(0,0,0),orilla(3,3,1)) :/* si se encuentra el estado objetivo */ /* Estado OBJETIVO = 3 misioneros, 3 canbales y 1 bote en la orilla derecha y nada en la orilla izquierda */ nl,write(" >> Objetivo encontrado << "), nl, nl. profundidad(Izq,Der) :/* Si no es el ESTADO OBJETIVO efecta la bsqueda */ ejecutar_movimiento(Izq,Der,SgteIzq,SgteDer), /* ejecutar movimiento desde el estado actual */ imprime_estado(SgteIzq,SgteDer), profundidad(SgteIzq,SgteDer). /* y llamarse recursivamente */ ejecutar_movimiento(Izq,Der,SgteIzq,SgteDer) :write("Toma la primera movida permitida que encuentre\n"), movimiento(Izq,Der,SgteIzq,SgteDer), /* ver movimiento */ /* si no est el mov sgte. para no repetir situacin */ not(hecho(SgteIzq,SgteDer)), /* para obtener un nuevo estado */ /* grabar el mov */ assert(hecho(SgteIzq,SgteDer)), permitido(SgteIzq), permitido(SgteDer). /* ver si es permitido */ movimiento(orilla(MI,CI,1),Der,PSgteIzq,PSgteDer) :/* si el bote est en la orilla izquierda */ /* Inicialmente recibir : en MI - misioneros a la izquierda 3 en CI - canbales a la izquierda 3 y el 1 representa que el bote est en la orilla derecha */ invertir_orillaOproceder(orilla(MI,CI,1),Der,PSgteIzq,PSgteDer). /* entonces el movimiento ser de izquierda a derecha */ movimiento(orilla(ML,CL,0),Der,PSgteIzq,PSgteDer) :/* si el bote est en la orilla derecha */ write("\n <--> origen y destino \n"), invertir_orillaOproceder(Der,orilla(ML,CL,0),PSgteDer,PSgteIzq). /* entonces el movimiento ser de derecha a izquierda */ invertir_orillaOproceder(Origen,Destino,SgteO,SgteD) :/* desde un origen a un destino */ /* Inicialmente recibir : en Origen - 3,3,1. en Destino- 0,0,0. */ movimiento(BoteObtenido), /* obtener movimiento de de 5 posibles */ /* Pj si obtiene bote(0,1) */ /* verificar si orilla(3,3,1) el bote(0,1) es aplicable */ aplicable(Origen,BoteObtenido), /* si opcin es aplicable */ quitar(Origen,BoteObtenido,SgteO), /* tomar bote del origen */ /* 3,2,0 inicialmente adicionar un canbal a la orilla derecha */ adicionar(Destino,BoteObtenido,SgteD), /* y adicionar al destino donde destino 0,0,0 inic */

mostrar_movimiento(BoteObtenido). /* El movimiento es aplicable al estado */ aplicable(orilla(M,C,1), bote(Mbote,Cbote)) :/* inicialmente ver si orilla(3,3,1) y bote(0,1) es aplicable si M(Cantidad de misioneros (3)) en mayor o igual la cantidad de misioneros en bote permitido (0), como esto se cumple, ve si C(Cantidad de canbales (3)) en mayor o igual que la cantidad de canbales permitidos en el bote segn la combinacin bote(0,1) permitida, como se cumple devuelve un si. */ M >= Mbote, C >= Cbote. /* en otras palabras, hay suficiente de cada uno para llenar el bote? */ /* Quitar del origen */ quitar(orilla(MO,CO,1), bote(MB,CB), orilla(MCanti,CCanti,0)) :/* inicialmente recibir orilla(3,3,1), bote(0,1) y un nuevo origen donde : MCanti = la cantidad de misioneros que habia en la orilla origen (en este caso izq MO) menos la cantidad de misioneros que suben al bote MB, cual dar 3 CCanti = igual para la cantidad de canbales (3-1)=2 0 = indica la orilla izquierda Quiere decir que la orilla izquierda quedar con 3,2,0 (3 mis y 2 cani) */ MCanti = MO-MB, CCanti = CO-CB. /* Adicionar al destino */ adicionar(orilla(MD,CD,0), bote(MB,CB), orilla(MR,CR,1)) :/* Pj si el destino inicial es 0,0,0 y el bote (0,1) entonces : MR = 0+0 = 0 misioneros a la orilla derecha por que no se transport ninguno CR = 0+1 = 1 canbal a la orilla derecha por se transport 1, el resultado ser que la orilla derecha tendr 0 misioneros y 1 canbal */ MR = MD+MB, CR = CD+CB. imprime_estado(orilla(MIzq,CIzq,BoteI), orilla(MDer,CDer,_)) :- write("\nLa orilla izquierda tiene : "), write(MIzq), write(" misioneros y "), write(CIzq), write(" canbales\n"), write("La orilla derecha tiene : "), write(MDer), write(" misioneros y "), write(CDer), write(" canbales\n"), mostrar_bote(BoteI), write("\n>>>>>>>>>>>>>>>>>>Presione una continuar<<<<<<<<<<<<<<<<<<<<\n"), readchar(_). mostrar_movimiento(bote(M,C)) :- write("Movida : "), write(C), write(" canbal(es) y "), write(M), write(" misionero(s)\n"). mostrar_bote(1) :- write("El bote est en la orilla izquierda\n"). mostrar_bote(0) :- write("El bote est en la orilla derecha\n"). goal ejecutar.

tecla

para