牧师与恶魔过河游戏——智能提示

前言

      这次实现一个含提示功能的牧师与恶魔过河小游戏,主要在上一个版本的牧师与恶魔小游戏上进行更改,通过增加一个状态计算和改版了得寻路算法,实现向玩家提示如何胜利完成游戏。游戏主体实现思路见上一篇博客——牧师与恶魔小游戏 动作分离版
      游戏效果图如下:
这里写图片描述

状态设置

      这里的状态是指右边岸上的牧师数目和恶魔数目,易知道牧师数目和恶魔数目的取值范围均是[0,3],即每个身份的数目取值可能个数为4,设P为牧师,D为恶魔,p为牧师数目,d为恶魔数目,则(p,d)的可能取值为4 * 4 = 16种,即(p,d)即为一个状态,例如(2,1)表示有两个牧师,一个魔鬼。而这个游戏,实质上是进行状态之间的转换,经过一系列的状态转换,使得状态最终从(3,3)变为(0,0)。
      接下来就是这些状态怎么表示的问题了。考虑到需要进行状态的转换,于是,用二维矩阵来表示,其中,每行的下标表示当前状态,列的取值表示能否转换至下一状态,上面已经说了有16中状态,所以,可用边长为16的二维矩阵表示。如下图:
这里写图片描述
在开始写代码之前,得明确以下两点:
二维矩阵下标和状态的转换关系: 已经确定状态表示为(p,d),其中,p和d的取值范围均为[0,3],在这里,用index代表数组下标,则,转换关系可为:

p = index / 4;
d = index % 4;

两个状态之间可转换的条件:
1. 由于船每次航行最多只能有两个人,最少必须有一个人,所以,船上人的状态可能为(1,1)、(1,0)、(0,1)、(2,0)、(0,2),而我们现在讨论的是右边岸上的状态,则根据船是离岸或上岸,右岸状态可能是加上或减去上述五个状态,而通过前面的式子,可以计算出,对应的下标变换为{ 5, 4, 1, 8, 2 }。
2. 两岸和船上牧师的总数必须为3;两岸和船上恶魔的总数必须为3。(这一点我一开始没有想到,花费了挺多时间来找bug。。。)
3. 下一状态中,当岸上有牧师时,岸上(含船)牧师的数目必须不少于恶魔的数目。在这里可以作个变换,当两边岸上都有牧师时,为了保持牧师的数目不少于恶魔的数目,则必须两岸上,牧师的数目等于恶魔的数目,而当其中一个岸边没有牧师时,则无需这个限制,所以,当pristNumber != 0 && pristNumber != 3 && pristNumber != devilNumber条件成立时,则不符合要求。
      根据上述的两个条件以及状态的表示方式,则可以将所有状态与其可转换的下一状态关联起来,形成一个二维关系矩阵,如下:
这里写图片描述
画成状态转换图,如下:
这里写图片描述
具体实现代码如下:

private bool[][] graph = new bool[16][];
//(P,D):(1,1)(1,0)(0,1)(2,0)(0,2)
    private int[] moveSteps = { 5, 4, 1, 8, 2 };
     //状态初始化
    public void init()
    {
        for(int i = 0; i < 16; i++)
        {
            graph[i] = new bool[16];
            for (int j = 0; j < 16; j++)
                graph[i][j] = false;
        }
        for(int i = 0; i < 16; i++)
        {
            for(int j = 0; j < 5; j++)
            {
                int opp = 15 - i;
                if (i + moveSteps[j] >= 0 && i + moveSteps[j] < 16)
                {
                    if ((((opp - moveSteps[j]) % 4 + i % 4 + moveSteps[j] % 4) == 3) && (((opp - moveSteps[j]) / 4 + i / 4 + moveSteps[j] / 4) == 3))
                        graph[i][i + moveSteps[j]] = true;
                }
                if (i - moveSteps[j] >= 0 && i - moveSteps[j] < 16)
                {
                    if ((opp % 4 + (i - moveSteps[j]) % 4 + moveSteps[j] % 4) == 3 && (opp / 4 + (i - moveSteps[j]) / 4 + moveSteps[j] / 4 == 3))
                        graph[i][i - moveSteps[j]] = true;
                }
            }
        }
        for(int i = 0; i < 16; i++)
        {
            //根据下一状态确定连线
            for(int j = 0; j < 16; j++)
            {
                int pristNumber = j / 4;
                int devilNumber = j % 4;
                if(pristNumber != 0 && pristNumber != 3 && pristNumber != devilNumber)
                {
                    graph[i][j] = false;
                }
            }
        }
    }

寻找路径

      在生成了状态转换图后,接下来的工作就是寻找从任意状态到终点状态的路径了,事实上,很多状态是不会发生的。本来以为寻找状态路径和寻找图的路径一样,后来才发现,由于船的位置,可能在右边ÿ

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
牧师和野人过河问题是一个经典的人工智能问题,其目标是将三个牧师和三个野人带到河对岸,但是船只只能搭载两个人,且野人的数量不能超过牧师的数量。为了解决这个问题,我们可以使用深度优先搜索算法来找到最优解。 以下是牧师和野人过河问题的流程图: ``` (3,3,1) / \ / \ / \ (2,2,0) (3,1,0) / \ / \ / \ / \ (1,2,0) (2,1,0) (3,0,0) (2,1,1) / \ / \ / \ / \ / \ / \ / \ / \ (0,2,1)(1,1,1)(1,1,0)(2,0,0)(1,0,1) | | | | | X X X X X ``` 其中,每个节点表示当前状态下的船和河岸上的人数,例如(3,3,1)表示在河岸上有3个牧师,3个野人,船在左岸。 从根节点(3,3,1)开始,我们可以采用深度优先搜索算法进行搜索。具体步骤如下: 1. 判断当前状态是否为目标状态(0,0,0),如果是,则搜索结束。 2. 如果不是目标状态,则在当前状态的基础上进行扩展。扩展操作包括将两个人(牧师或者野人)从一个岸上移到另一个岸上。注意,在每次扩展前需要判断当前状态是否合法,即船上的人数不能超过2个,且野人的数量不能超过牧师的数量。 3. 对于每个扩展出来的状态,递归进行搜索。 在实现时,可以使用一个队列来保存当前状态以及它的父节点。在搜索到目标状态后,可以根据队列中保存的父节点信息构造出完整的路径。 如果你想了解如何使用 C++ 实现该算法,请告诉我,我可以为你提供代码实现和更详细的解释。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值