// Alex Mikhaylov // May 5, 1999 // CS 627 - Artificial Intelligence #include #include enum op_code {two_m, two_c, one_m, one_c, one_m_one_c, any}; //list of possible operations enum boat_pos {left=0,right=1}; //list of possible boat positions class State { private: boat_pos Boat; //boat position int MisLeft; //how many missioners on the left bank int CanLeft; //how many cannibals on the left bank int MisRight; //how many missioners on the right bank int CanRight; //how many cannibals on the right bank op_code operation; //what operation has been performed to achieve this state. This helps //avoid cases when same operation gets performed twice in a row //(like when 2 miss. are moved left and then immediately right) State* next; public: State(); //constructor bool IsValid(); //Checks whether state is valid according to the given rules void PrintState(); //prints out state void Initialize(); //Makes state the initial one: MR=3;ML=0;CR=3;CL=0;B=right bool IsGoal(); //Checks whether it is the Goal state State* GetChildQueue(); //Returns a pointer to the head of the queue of children of this state State* GetTail();//Returns pointer to the tail of the queue of which this state is the head void SearchDeep();//performs depth-search algorithm on the tree the root of which is this state void SearchWide();//performs width-search algorithm on the tree the root of which is this state }; int NumStates=0; //keeps track of the # of states searched int Depth=0; //keeps track of depth level for deep-search algorithm bool Found=false; State::State() { //Default Constructor Boat=left; MisLeft=0; MisRight=0; CanLeft=0; next=NULL; CanRight=0; } void State::Initialize() { Boat=right; MisLeft=0; MisRight=3; CanLeft=0; CanRight=3; operation=any; next=NULL; } bool State::IsValid() { //Check if # of missioners>=0, number of cannibals>=0, //and missioners>=cannibals if (MisRight==0) { if ((MisLeft>=CanLeft) && (MisLeft>=0) && (CanRight>=0) && (CanLeft>=0)) return (true); else return (false); } else { if (MisLeft==0) { if ((MisRight>=CanRight) && (MisRight>=0) && (CanRight>=0) && (CanLeft>=0)) return (true); else return (false); } else { if ((MisRight>=CanRight) && (MisLeft>=CanLeft) && (MisRight>=0) && (MisLeft>=0) && (CanRight>=0) && (CanLeft>=0)) return (true); else return (false); } } } void State::PrintState() { //Print out this state cout<<"ML:"<Boat=left; TempChild_two_m->MisRight=MisRight-2; TempChild_two_m->MisLeft=MisLeft+2; TempChild_two_m->CanRight=CanRight; TempChild_two_m->CanLeft=CanLeft; if (TempChild_two_m->IsValid() && operation!=two_m) { //the generated child is valid and is not the result of the same operation as parent TempChild_two_m->next=NULL; TempChild_two_m->operation=two_m; if (Head==NULL) { //it is the first child in the queue, make it head Head=TempChild_two_m; temptr=Head; } else { //attach this child to the last child in the queue temptr->next=TempChild_two_m; temptr=TempChild_two_m; } } else { //the generated child is either not valid or is the result of the same operation //as parent TempChild_two_m=NULL; delete TempChild_two_m; } //try to transport 2 cannibals TempChild_two_c->Boat=left; TempChild_two_c->MisRight=MisRight; TempChild_two_c->MisLeft=MisLeft; TempChild_two_c->CanRight=CanRight-2; TempChild_two_c->CanLeft=CanLeft+2; if ((TempChild_two_c->IsValid()) && (operation!=two_c)) { TempChild_two_c->next=NULL; TempChild_two_c->operation=two_c; if (Head==NULL) { Head=TempChild_two_c; temptr=Head; } else { temptr->next=TempChild_two_c; temptr=TempChild_two_c; } } else { TempChild_two_c=NULL; delete TempChild_two_c; } //try to transport 1 missioner TempChild_one_m->Boat=left; TempChild_one_m->MisRight=MisRight-1; TempChild_one_m->MisLeft=MisLeft+1; TempChild_one_m->CanRight=CanRight; TempChild_one_m->CanLeft=CanLeft; if ((TempChild_one_m->IsValid()) && (operation!=one_m)) { TempChild_one_m->next=NULL; TempChild_one_m->operation=one_m; if (Head==NULL) { Head=TempChild_one_m; temptr=Head; } else { temptr->next=TempChild_one_m; temptr=TempChild_one_m; } } else { TempChild_one_m=NULL; delete TempChild_one_m; } //try to transport 1 cannibal TempChild_one_c->Boat=left; TempChild_one_c->MisRight=MisRight; TempChild_one_c->MisLeft=MisLeft; TempChild_one_c->CanRight=CanRight-1; TempChild_one_c->CanLeft=CanLeft+1; if ((TempChild_one_c->IsValid()) && (operation!=one_c)) { TempChild_one_c->next=NULL; TempChild_one_c->operation=one_c; if (Head==NULL) { Head=TempChild_one_c; temptr=Head; } else { temptr->next=TempChild_one_c; temptr=TempChild_one_c; } } else { TempChild_one_c=NULL; delete TempChild_one_c; } //try to transport 1 missioner and 1 cannibal TempChild_one_m_one_c->Boat=left; TempChild_one_m_one_c->MisRight=MisRight-1; TempChild_one_m_one_c->MisLeft=MisLeft+1; TempChild_one_m_one_c->CanRight=CanRight-1; TempChild_one_m_one_c->CanLeft=CanLeft+1; if ((TempChild_one_m_one_c->IsValid()) && (operation!=one_m_one_c)) { TempChild_one_m_one_c->next=NULL; TempChild_one_m_one_c->operation=one_m_one_c; if (Head==NULL) { Head=TempChild_one_m_one_c; temptr=Head; } else { temptr->next=TempChild_one_m_one_c; temptr=TempChild_one_m_one_c; } } else { TempChild_one_m_one_c=NULL; delete TempChild_one_m_one_c; } } else {//boat is on the left bank //try to transport 2 missioners TempChild_two_m->Boat=right; TempChild_two_m->MisRight=MisRight+2; TempChild_two_m->MisLeft=MisLeft-2; TempChild_two_m->CanRight=CanRight; TempChild_two_m->CanLeft=CanLeft; if ((TempChild_two_m->IsValid()) && (operation!=two_m)) { TempChild_two_m->next=NULL; TempChild_two_m->operation=two_m; if (Head==NULL) { Head=TempChild_two_m; temptr=Head; } else { temptr->next=TempChild_two_m; temptr=TempChild_two_m; } } else { TempChild_two_m=NULL; delete TempChild_two_m; } //try to transport 2 cannibals TempChild_two_c->Boat=right; TempChild_two_c->MisRight=MisRight; TempChild_two_c->MisLeft=MisLeft; TempChild_two_c->CanRight=CanRight+2; TempChild_two_c->CanLeft=CanLeft-2; if ((TempChild_two_c->IsValid()) && (operation!=two_c)) { TempChild_two_c->next=NULL; TempChild_two_c->operation=two_c; if (Head==NULL) { Head=TempChild_two_c; temptr=Head; } else { temptr->next=TempChild_two_c; temptr=TempChild_two_c; } } else { TempChild_two_c=NULL; delete TempChild_two_c; } //try to transport 1 missioner TempChild_one_m->Boat=right; TempChild_one_m->MisRight=MisRight+1; TempChild_one_m->MisLeft=MisLeft-1; TempChild_one_m->CanRight=CanRight; TempChild_one_m->CanLeft=CanLeft; if ((TempChild_one_m->IsValid()) && (operation!=one_m)) { TempChild_one_m->next=NULL; TempChild_one_m->operation=one_m; if (Head==NULL) { Head=TempChild_one_m; temptr=Head; } else { temptr->next=TempChild_one_m; temptr=TempChild_one_m; } } else { TempChild_one_m=NULL; delete TempChild_one_m; } //try to transport 1 cannibal TempChild_one_c->Boat=right; TempChild_one_c->MisRight=MisRight; TempChild_one_c->MisLeft=MisLeft; TempChild_one_c->CanRight=CanRight+1; TempChild_one_c->CanLeft=CanLeft-1; if ((TempChild_one_c->IsValid()) && (operation!=one_c)) { TempChild_one_c->next=NULL; TempChild_one_c->operation=one_c; if (Head==NULL) { Head=TempChild_one_c; temptr=Head; } else { temptr->next=TempChild_one_c; temptr=TempChild_one_c; } } else { TempChild_one_c=NULL; delete TempChild_one_c; } //try to transport 1 missioner and 1 cannibal TempChild_one_m_one_c->Boat=right; TempChild_one_m_one_c->MisRight=MisRight+1; TempChild_one_m_one_c->MisLeft=MisLeft-1; TempChild_one_m_one_c->CanRight=CanRight+1; TempChild_one_m_one_c->CanLeft=CanLeft-1; if ((TempChild_one_m_one_c->IsValid()) && (operation!=one_m_one_c)) { TempChild_one_m_one_c->next=NULL; TempChild_one_m_one_c->operation=one_m_one_c; if (Head==NULL) { Head=TempChild_one_m_one_c; temptr=Head; } else { temptr->next=TempChild_one_m_one_c; temptr=TempChild_one_m_one_c; } } else { TempChild_one_m_one_c=NULL; delete TempChild_one_m_one_c; } } //return pointer to the head of the child queue return (Head); } void State::SearchDeep() {//deep search algorithm State* ChildQueuePtr; ChildQueuePtr=new State; ChildQueuePtr=NULL; if (Found) //check whether recursion has to be stopped return; NumStates++; PrintState(); if (!IsGoal()) //if this is not goal state { ChildQueuePtr=GetChildQueue(); //get child queue for this state while (!ChildQueuePtr==NULL) { ChildQueuePtr->SearchDeep(); //perform recursive deep search on the head //of the child queue ChildQueuePtr=ChildQueuePtr->next; //move along child queue } return; } else { cout<<"FOUND!!!"<next==NULL) temptr=temptr->next; return (temptr); } void State::SearchWide() { /*wide search algorithm this function first checks all states at the certain depth, then, if it does not come across the goal state, gets children for all the states at that depth, links all the children into one queue and passes that queue back to this function for recursion*/ State* ChildQuePtr; State* temptr; State* ChildHead; State* NextChild; ChildQuePtr=new State; temptr=new State; ChildHead=new State; NextChild=new State; ChildQuePtr=NULL; ChildHead=NULL; NextChild=NULL; if(Found) //stop recursion if goal state is found return; temptr=this; Depth++; //go through all states at the same depth as the one for which the function is called //and check if one of them is goal state while (!temptr==NULL) { cout<<" Depth: "<IsGoal()) { cout<<"FOUND!!!"<next; } temptr=this; //find first available child of the states in the queue while((ChildHead==NULL) && (temptr!=NULL)) { ChildHead=temptr->GetChildQueue(); temptr=temptr->next; } if (ChildHead==NULL) return; //no children found at this depth else { //form a queue of all children at this depth ChildQuePtr=ChildHead; while (!temptr==NULL) { NextChild=temptr->GetChildQueue(); if (!NextChild==NULL) { ChildQuePtr->GetTail()->next=NextChild; } temptr=temptr->next; } //pass the head of the children's queue back for recursion ChildHead->SearchWide(); } } void main() { //create initial state State InitState; InitState.Initialize(); //initialize global variables Found=false; NumStates=0; cout<<"Searching Deep"<