简单人工智能原理实验/猴子摘香蕉

广州大学 人工智能原理 实验一

猴子摘香蕉问题

背景介绍:利用一阶谓词逻辑求解猴子摘香蕉问题:房内有一个猴子,一个箱子,天花板上挂了一串香蕉,其位置如图1所示,猴子为了拿到香蕉,它必须把箱子搬到香蕉下面,然后再爬到箱子上。请定义必要的谓词,列出问题的初始化状态(即下图所示状态),目标状态(猴子拿到了香蕉,站在箱子上,箱子位于位置b)

分析

从初始状态到目标状态的转化,猴子需要完成一系列操作

首先,分析,这里有三个物体,猴子(Monkey),香蕉(banana),箱子(box),那么猴子要怎么移动才可以到达b处的香蕉呢,也就是分为4步,移动到C处,搬箱子到B处,爬箱子,拿到香蕉。那么就是对每一种可能出现的情况进行分析,然后判断下一步需要做什么做什么,一步一步进行。

在这之中所有所有的状态一共有四个动作。因为最后还需要将移动步骤一点点输出,就用一个数组来进行存储

string routesave[150];//用来记录每一次路线的变化
主要函数

猴子移动

void monkeymove(int b,int i) //第i步,移动到b处
{
    int a;
    a = b;
    if (a == -1)
    {
        routesave[i] = "Monkey move to A";
        States[i + 1] = States[i]; //结合下一句,其他状态不变,但猴子位置发生改变 
        States[i + 1].monkey = -1;
    }
    else if (a == 0)
    {
        routesave[i] = "Monkey move to B";
        States[i + 1] = States[i];
        States[i + 1].monkey = 0;
    }
    else if (a == 1)
    {
        routesave[i] = "Monkey move to C";
        States[i + 1] = States[i];
        States[i + 1].monkey = 1;
    }
    else
    {
        //猴子不在指定位置,出错
        cout << "Parameter is wrong" << endl;
    }
}

猴子搬箱子,箱子移动函数

void movebox(int a, int i) //第i步,把箱子搬到a处
{
    int B;
    B = a;
    if (B == -1)
    {
        routesave[i] = "Monkey move box to A";
        States[i + 1] = States[i];
        States[i + 1].monkey = -1;
        States[i + 1].box = -1;
    }
    else if (B == 0)
    {
        routesave[i] = "Monkey move box to B";
        States[i + 1] = States[i];
        States[i + 1].monkey = 0;
        States[i + 1].box = 0;
    }
    else if (B == 1)
    {
        routesave[i] = "Monkey move box to C";
        States[i + 1] = States[i];
        States[i + 1].monkey = 1;
        States[i + 1].box = 1;
    }
    else 
    {
        cout << "Parameter is wrong" << endl;
    }
}

猴子爬箱子/爬上/爬下

void climbonto(int i) //爬上箱子
{
    routesave[i] = "Monkey climb onto the box";
    States[i + 1] = States[i];
    States[i + 1].monbox = 1;
}

void climbdown(int i) //爬下箱子
{
    routesave[i] = "Monkey climb down from the box";
    States[i + 1] = States[i];
    States[i + 1].monbox = -1;
}

拿到香蕉并进行打印输出

void reach(int i)
{
    routesave[i] = "Monkey reach the banana"; //得到香蕉
    int c;
    cout << "Result to problem" << endl;
    for (c = 0; c < i + 1; c++)
    {
        cout << "Step" << c + 1 << "  " << routesave[c] << endl;
    }
    cout << "解决问题" << endl;
}

OK

到这里,我们完成了主要的函数部分,后面就是一步一步的逻辑判断了

每一步都要向着最终状态前进,如果猴子和箱子不在一起,那就猴子移动到箱子,在满足前提条件下,猴子搬箱子到香蕉下,无论怎么样,一步步向最终状态,也就是猴子,箱子,香蕉都在同一个点位的状态改变。

核心函数
void nextStep(int i)
{
    int c;
    int j;
    if (i >= 150)
    {
        cout << "超过150,出现问题" << endl;
        return;
    }
    for (c = 0; c < i; c++)
    {
        if (States[c].monkey == States[i].monkey && States[c].box == States[i].box && States[c].banana == States[i].banana && States[c].monbox == States[i].monbox)
        {
            return;//出现相同状态,陷入循环,退出
        }
    }
     j = i + 1;
    if (States[i].monkey == 0)
    {
        if (States[i].box == 0)
        {
            if (States[i].monbox == 0) //猴子箱子都在B位置且猴子没爬上箱子
            {
                climbonto(i);
                reach(i + 1);
                return;
            }
            else               //猴子已经爬上了箱子
            {
                reach(i + 1);
                return;

            }
        }
        else if (States[i].box == 1)   
        {
            monkeymove(1, i);  //将猴子移动到箱子的位置
            nextStep(j);
            return;
            
        }
        else
        {
            monkeymove(-1, i);  
            nextStep(j);
            return;
        }
    }
    if (States[i].monkey == -1)
    {
        if (States[i].box == -1)  //猴子箱子都在A位置
        {
            if (States[i].monbox == -1)
            {
                movebox(0, i);    //
                nextStep(j);
                return;
            }
            else
            {
                climbdown(i);
                nextStep(j);
                return;
            }

        }
        else if (States[i].box == 0)
        {
            monkeymove(0, i);
            nextStep(j);
            return;
        }
        else
        {
            monkeymove(1, i);
            nextStep(j);
            return;
        }
    }
    if (States[i].monkey == 1)
    {
        if (States[i].box == 1)
        {
            if (States[i].monbox == 0)
            {
                movebox(0, i);
                nextStep(j);
                return;
            }
            else
            {
                climbdown(i);
                nextStep(j);
                return;
            }
        }
        else if (States[i].banana == -1)
        {
            monkeymove(-1, i);
            nextStep(j);
            return;
        }
        else
        {
            monkeymove(0, i);
            nextStep(j);
            return;
        }
    }
    return;
}

需要注意一下实验指导书上的代码

大概都是这样子的,但这样子会有问题,会重复输出,也就是当你执行nextstep函数的时候一步步进行下去,然后最后拿到香蕉了,这样子就可以了,但它会重新跳转到这里的if语句中,继续movebox,继续nextstep,就会继续输出残缺的结果。

但在nextstep的核心中,其实就是根据每一个状态来判断下一步应该干嘛,然后嵌套循环进行下去

完整的代码
#include <iostream>
#include <string>
using namespace std;

struct State    //每一个状态的记录
{
    int monkey; // -1: Monkey at A; 0: Monkey at B; 1: Monkey at C;
    int box;    // -1: Box at A; 0: Box at B; 1: Box at C;
    int banana; // Banana at B, Banana=0
    int monbox; // -1: Monkey on the box; 1: Monkey off the box;
};

State States[150]; //提供一个最大数组来存储
string routesave[150];//用来记录每一次路线的变化

//猴子的目标状态是b,想要前往b地点
void monkeymove(int b,int i)
{
    int a;
    a = b;
    if (a == -1)
    {
        routesave[i] = "Monkey move to A";
        States[i + 1] = States[i]; //结合下一句,其他状态不变,但猴子位置发生改变 
        States[i + 1].monkey = -1;
    }
    else if (a == 0)
    {
        routesave[i] = "Monkey move to B";
        States[i + 1] = States[i];
        States[i + 1].monkey = 0;
    }
    else if (a == 1)
    {
        routesave[i] = "Monkey move to C";
        States[i + 1] = States[i];
        States[i + 1].monkey = 1;
    }
    else
    {
        //猴子不在指定位置,出错
        cout << "Parameter is wrong" << endl;
    }
}

void movebox(int a, int i)
{
    int B;
    B = a;
    if (B == -1)
    {
        routesave[i] = "Monkey move box to A";
        States[i + 1] = States[i];
        States[i + 1].monkey = -1;
        States[i + 1].box = -1;
    }
    else if (B == 0)
    {
        routesave[i] = "Monkey move box to B";
        States[i + 1] = States[i];
        States[i + 1].monkey = 0;
        States[i + 1].box = 0;
    }
    else if (B == 1)
    {
        routesave[i] = "Monkey move box to C";
        States[i + 1] = States[i];
        States[i + 1].monkey = 1;
        States[i + 1].box = 1;
    }
    else 
    {
        cout << "Parameter is wrong" << endl;
    }
}

void climbonto(int i)
{
    routesave[i] = "Monkey climb onto the box";
    States[i + 1] = States[i];
    States[i + 1].monbox = 1;
}

void climbdown(int i)
{
    routesave[i] = "Monkey climb down from the box";
    States[i + 1] = States[i];
    States[i + 1].monbox = -1;
}

void reach(int i)
{
    routesave[i] = "Monkey reach the banana"; //得到香蕉
    int c;
    cout << "Result to problem" << endl;
    for (c = 0; c < i + 1; c++)
    {
        cout << "Step" << c + 1 << "  " << routesave[c] << endl;
    }
    cout << "解决问题" << endl;
}

void nextStep(int i)
{
    int c;
    int j;
    if (i >= 150)
    {
        cout << "超过150,出现问题" << endl;
        return;
    }
    for (c = 0; c < i; c++)
    {
        if (States[c].monkey == States[i].monkey && States[c].box == States[i].box && States[c].banana == States[i].banana && States[c].monbox == States[i].monbox)
        {
            return;//出现相同状态,陷入循环,退出
        }
    }
     j = i + 1;
    if (States[i].monkey == 0)
    {
        if (States[i].box == 0)
        {
            if (States[i].monbox == 0) //猴子箱子都在B位置且猴子没爬上箱子
            {
                climbonto(i);
                reach(i + 1);
                return;
            }
            else               //猴子已经爬上了箱子
            {
                reach(i + 1);
                return;

            }
        }
        else if (States[i].box == 1)   
        {
            monkeymove(1, i);  //将猴子移动到箱子的位置
            nextStep(j);
            return;
            
        }
        else
        {
            monkeymove(-1, i);  
            nextStep(j);
            return;
        }
    }
    if (States[i].monkey == -1)
    {
        if (States[i].box == -1)  //猴子箱子都在A位置
        {
            if (States[i].monbox == -1)
            {
                movebox(0, i);    //
                nextStep(j);
                return;
            }
            else
            {
                climbdown(i);
                nextStep(j);
                return;
            }

        }
        else if (States[i].box == 0)
        {
            monkeymove(0, i);
            nextStep(j);
            return;
        }
        else
        {
            monkeymove(1, i);
            nextStep(j);
            return;
        }
    }
    if (States[i].monkey == 1)
    {
        if (States[i].box == 1)
        {
            if (States[i].monbox == 0)
            {
                movebox(0, i);
                nextStep(j);
                return;
            }
            else
            {
                climbdown(i);
                nextStep(j);
                return;
            }
        }
        else if (States[i].banana == -1)
        {
            monkeymove(-1, i);
            nextStep(j);
            return;
        }
        else
        {
            monkeymove(0, i);
            nextStep(j);
            return;
        }
    }
    return;
}

int main()
{
    States[0].monkey = -1;
    States[0].box = 1;
    States[0].banana = 0;
    States[0].monbox = 0;
    nextStep(0);

}

需要注意,因为我们的核心函数nextstep是根据猴子箱子香蕉的初始状态来写的,就可能你改变猴子,箱子的位置最后结果可能就会出现错误,所以如果说,代码哪里还可以再优化,应该就是把函数里面的-1,0,1改的更详细一点,States[i].monkey这样子的。

输出结果

进行改进

前面提到如果初始状态进行改变,那么就不能用上原先的代码了,而且经过前面的分析,其实就是猴子箱子先在一起,然后猴子箱子香蕉在同一个位置。那么改变nextStep函数中的数值,都改成States[i].  的形式,这是进行优化后可以改变初始状态的代码

#include <iostream>
#include <string>
using namespace std;

struct State    //每一个状态的记录
{
    int monkey; // -1: Monkey at A; 0: Monkey at B; 1: Monkey at C;
    int box;    // -1: Box at A; 0: Box at B; 1: Box at C;
    int banana; // Banana at B, Banana=0
    int monbox; // -1: Monkey on the box; 1: Monkey off the box;
};

State States[150]; //提供一个最大数组来存储
string routesave[150];//用来记录每一次路线的变化

void monkeymove(int b, int i)
{
    if (b < -1 || b > 1)
    {
        cout << "Parameter is wrong" << endl;
        return;
    }

    if (b == States[i].monkey)
    {
        routesave[i] = "Monkey stay at current position";
    }
    else if (b == -1)
    {
        routesave[i] = "Monkey move to A";
        States[i + 1] = States[i]; //结合下一句,其他状态不变,但猴子位置发生改变 
        States[i + 1].monkey = -1;
    }
    else if (b == 0)
    {
        routesave[i] = "Monkey move to B";
        States[i + 1] = States[i];
        States[i + 1].monkey = 0;
    }
    else if (b == 1)
    {
        routesave[i] = "Monkey move to C";
        States[i + 1] = States[i];
        States[i + 1].monkey = 1;
    }
}

void movebox(int a, int i)
{
    if (a < -1 || a > 1)
    {
        cout << "Parameter is wrong" << endl;
        return;
    }

    if (States[i].monbox == -1)
    {
        routesave[i] = "Monkey cannot move box when it is on the box";
    }
    else if (a == States[i].box)
    {
        routesave[i] = "Box stay at current position";
    }
    else if (a == -1)
    {
        routesave[i] = "Monkey move box to A";
        States[i + 1] = States[i];
        States[i + 1].monkey = -1;
        States[i + 1].box = -1;
    }
    else if (a == 0)
    {
        routesave[i] = "Monkey move box to B";
        States[i + 1] = States[i];
        States[i + 1].monkey = 0;
        States[i + 1].box = 0;
    }
    else if (a == 1)
    {
        routesave[i] = "Monkey move box to C";
        States[i + 1] = States[i];
        States[i + 1].monkey = 1;
        States[i + 1].box = 1;
    }
}

void climbonto(int i)
{
    routesave[i] = "Monkey climb onto the box";
    States[i + 1] = States[i];
    States[i + 1].monbox = -1;
}

void climbdown(int i)
{
    routesave[i] = "Monkey climb down from the box";
    States[i + 1] = States[i];
    States[i + 1].monbox = 1;
}

void reach(int i)
{
    routesave[i] = "Monkey reach the banana"; //得到香蕉
    cout << "Result to problem" << endl;
    for (int c = 0; c < i + 1; c++)
    {
        cout << "Step" << c + 1 << "  " << routesave[c] << endl;
    }
    cout << "解决问题" << endl;
}

void nextStep(int i, int n)
{
    if (i >= 150)
    {
        cout << "超过150,出现问题" << endl;
        return;
    }

    if (States[i].box ==States[i].monkey && States[i].monkey == States[i].banana  && States[i].monbox==-1) // 猴子、箱子和香蕉都在B位置且猴子在箱子上
    {
        reach(i);
        return;
    }

    for (int c = 0; c < i; c++)
    {
        if (States[c].monkey == States[i].monkey && States[c].box == States[i].box && States[c].banana == States[i].banana && States[c].monbox == States[i].monbox)
        {
            return;//出现相同状态,陷入循环,退出
        }
    }

    int j = i + 1;

    if (States[i].box == States[i].monkey) //箱子和猴子在相同位置
    {
        if (States[i].banana == States[i].monkey) //猴子箱子香蕉都在相同位置且猴子没爬上箱子
        {
            if (States[i].monbox == 1)
            {
                climbonto(i);
                nextStep(i + 1, n);
                return;
            }
            else           //猴子已经爬上了箱子
            {
                nextStep(i + 1, n);
                return;
            }
        }
        else //猴子箱子在相同位置,但不和香蕉在同一个位置
        {
            movebox(States[i].banana, i); //把箱子搬到香蕉的相同位置
            nextStep(i + 1, n);
            return;
        }
    }
    else //将猴子移动到箱子的位置
    {
        monkeymove(States[i].box, i);
        nextStep(j, n);
        return;
    }
}

int main()
{
    States[0].monkey = -1;
    States[0].banana = 0;
    States[0].box = 1;

    States[0].monbox = 1;
    nextStep(0, 10); // 查找第10步的状态
}

应该是对的 

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值