文章目录

  • P&D 过河游戏智能帮助
    • 状态图
    • 实现方法
      • 图的表示方法
      • 广度优先搜索
    • P&D 过河游戏拓展
    • 结果展示

P&D 过河游戏智能帮助

本次作业基本要求是三选一,我选择了P&D 过河游戏智能帮助实现

3、P&D 过河游戏智能帮助实现,程序具体要求:

  • 实现状态图的自动生成
  • 讲解图数据在程序中的表示方法
  • 利用算法实现下一步的计算
  • 参考:P&D 过河游戏智能帮助实现

状态图

以下状态图摘自上面的参考博客,主要表示了3个牧师与3个魔鬼的游戏所有可能出现的状况。而如果要实现智能游戏帮助,则需要用代码的形式自动生成以下状态图。

实现方法

刚好在结束的实训中学习到了两大类搜索算法(盲目式搜索与启发式搜索),这两大搜索方法都能以较快的速率遍历状态图的所有状态,这样就可以找到一条通往游戏结束状态的路径。由于此游戏状态比较少,经过测试速度也还可以,所以我就使用了广度优先搜索的方法寻找路径(使用启发式搜索的A*算法会更加趋向于终点)。

图的表示方法

要实现路径的搜索,首先要将状态图抽象为一个数据结构。我选择使用邻接表表示图,所以每个状态就用一个自定义节点PAndDNode来表示。

以下是实现这个状态节点的PAndDNode类,首先需要解释一下PAndDNode的一些属性:

  1. priestsNum:用于记录还未转移到目的地的牧师个数
  2. devilsNum:用于记录还未转移到目的地的魔鬼的个数
  3. parent:相当于指针,指向发展到这个状态的状态父节点

除了上面的属性,我还未这个状态节点定义了一些行为,以方便后面BFS算法的实现:

  1. public bool IsValid():判断该状态是否合法,也就是判断此状态是否导致游戏失败
  2. public bool Move(int path):将此状态转移到下一状态,在图论中就是访问邻接点。这里每种状态都会有5个邻接状态可以转移(当然实际种不是每个状态都能有5个,所以会在实现的5个Move函数中判断是否能够执行该转移),所以根据输入的int数来指引到相应的Move函数中。
  3. 其他的还有构造函数以及属性的get函数,还有需要重写节点的比较函数Equals及其绑定在一起的函数。
public class PAndDNode
{private const int maxPriests = 3;private const int maxDevils = 3;int priestsNum;int devilsNum;private PAndDNode parent;public PAndDNode(int priestsNum, int devilsNum){if (priestsNum <= maxPriests && devilsNum <= maxDevils){this.priestsNum = priestsNum;this.devilsNum = devilsNum;this.parent = null;}else{Debug.Log("传参错误");}}public PAndDNode(PAndDNode node){this.priestsNum = node.priestsNum;this.devilsNum = node.devilsNum;this.parent = node.parent;}public int GetPriestsNum(){return priestsNum;}public int GetDevilsNum(){return devilsNum;}public PAndDNode GetParent(){return parent;}public override bool Equals(object obj){if (obj == null || obj.GetType().Equals(this.GetType()) == false){return false;}PAndDNode node = (PAndDNode)obj;if (node.priestsNum == this.priestsNum && node.devilsNum == this.devilsNum){return true;}return false;}public override int GetHashCode(){return this.priestsNum.GetHashCode() + this.devilsNum.GetHashCode();}public bool IsValid(){return ((priestsNum >= devilsNum || priestsNum  == 0) && (priestsNum <= devilsNum || priestsNum == maxPriests));}public bool MoveDD(){if (devilsNum >= 2){this.parent = new PAndDNode(this);devilsNum -= 2;return true;}return false;}public bool MoveDP(){if (priestsNum > 0 && devilsNum > 0){this.parent = new PAndDNode(this);devilsNum--;priestsNum--;return true;}return false;}public bool MovePP(){if (priestsNum >= 2){this.parent = new PAndDNode(this);priestsNum -= 2;return true;}return false;}public bool MoveD(){if (devilsNum > 0){this.parent = new PAndDNode(this);devilsNum--;return true;}return false;}public bool MoveP(){if (priestsNum > 0){this.parent = new PAndDNode(this);priestsNum--;return true;}return false;}public bool Move(int path){switch (path) {case 0:return MoveDP();case 1:return MovePP();case 2:return MoveDD();case 3:return MoveP();case 4:return MoveD();default:return false;}}
}

广度优先搜索

广度优先搜索算法在PAndD类中实现,代码如下。

使用BFS寻找路径主要在public bool BFSearch(PAndDNode begin, PAndDNode end)函数中,函数接受起始节点,以及目标节点(这里目标节点固定为牧师数和恶魔数都是0,而起始节点则根据游戏当时状态决定)。当到达目标终点后,会调用setNextToMove()回溯这条路径找到此时状态应该转移的合法状态,然后返回true。所以调用者如果判断返回值为true就可以调用GetNextToMove()获取下一转移状态。

BFS实现中主要要注意的点是,什么才算访问邻接点,不仅要判断其是否能由该节点转移得到(也就是是否为邻接点)和其是否访问过,还有调用节点提供的方法IsValid()来判断这个状态是否会导致玩家游戏失败。

BFS是实时进行的,当然搜索的速度也非常喜人,能够很好地作为智能帮助的底层算法。

public class PAndD
{private const int pathNum = 5;private PAndDNode beginNode;private PAndDNode endNode;private PAndDNode nextNode;private PAndDNode currentNode;public bool BFSearch(PAndDNode begin, PAndDNode end){Queue<PAndDNode> openList = new Queue<PAndDNode>();List<PAndDNode> closeList = new List<PAndDNode>();openList.Enqueue(begin);this.beginNode = begin;this.endNode = end;while (openList.Count > 0){this.currentNode = openList.Peek();if (this.currentNode.Equals(end)){setNextToMove();return true;}openList.Dequeue();closeList.Add(this.currentNode);for (int i = 0; i < pathNum; i++){PAndDNode newNode = new PAndDNode(this.currentNode);if (newNode.Move(i) && !closeList.Contains(newNode) && newNode.IsValid()){openList.Enqueue(newNode);}}}return false;}private void setNextToMove(){nextNode = this.currentNode;while (!nextNode.GetParent().Equals(beginNode)){nextNode = nextNode.GetParent();}}public PAndDNode GetNextToMove(){return nextNode;}
}

P&D 过河游戏拓展

实现了游戏帮助的底层算法,接下来就要将该算法植入到原来的游戏当中,并扩展一个提示功能。首先我先在interface IUserAction增加一个需要实现的功能函数bool Tips()。然后扩展用户GUI,增加一个Tips按钮,当被点击时调用该Tips()函数。最后在FirstController中实现该函数,实现如下:

流程为首先获取当前出发Land上的牧师与魔鬼的个数(当然还有包含船上的个数,因为节点保存的是未到达终点的个数)。然后以此调用PAndDBFSearch函数,找到一条可以通往节点的路径,并获取下一步需要转移的状态(主要是下一状态岸上还剩的牧师魔鬼数)。如果能够找到这样一条路径,那么就进行自动移动。

自动移动实现为自动将要转移的牧师和魔鬼放上船上(这里是根据下一状态节点的剩下牧师魔鬼数与当前牧师魔鬼数对比获取要转移的牧师魔鬼数),还能矫正玩家行为,也就是如果已在船上但又不该转移的牧师或魔鬼移动回岸上,再把需要转移的牧师或魔鬼转移到船上。

public bool Tips()
{int[] fromCount = fromLand.GetCharacterNum();int[] boatCount = boat.GetCharacterNum();PAndD solution = new PAndD();if (solution.BFSearch(new PAndDNode(fromCount[0] + boatCount[0], fromCount[1] + boatCount[1]), new PAndDNode(0, 0))) {// 船在左边if (fromLand.GetToOrFrom() != boat.GetToOrFrom()){return false;}PAndDNode nextToMove = solution.GetNextToMove();CharacterModel[] fromCharacters = fromLand.GetCharacters();int pNum = fromCount[0] - nextToMove.GetPriestsNum();int dNum = fromCount[1] - nextToMove.GetDevilsNum();foreach (CharacterModel character in boat.GetCharacters()){if (pNum >= 0)break;if (character != null && character.GetType() == 0){MoveCharacter(character);pNum++;}}foreach (CharacterModel character in boat.GetCharacters()){if (dNum >= 0)break;if (character != null && character.GetType() == 1){MoveCharacter(character);dNum++;}}for (int i = 0; i < pNum; i++){foreach (CharacterModel character in fromCharacters){if (character != null && character.GetType() == 0){MoveCharacter(character);break;}}}for (int i = 0; i < dNum; i++){foreach (CharacterModel character in fromCharacters){if (character != null && character.GetType() == 1){MoveCharacter(character);break;}}}return true;}return false;
}

结果展示

演示视频:https://v.youku.com/v_show/id_XNDQ1Njg4ODI3Ng==.html?spm=a2hzp.8244740.0.0

完整代码:Github

Unity3d入门之路-PD 过河游戏智能帮助相关推荐

  1. Unity学习之PD 过河游戏智能帮助实现

    Unity学习之P&D 过河游戏智能帮助实现 根据之前设计好的动作分离版过河游戏,我们进行一个简单的状态图AI实现. 转移状态图 状态图老师已经给出: 该状态图只记录了游戏过程中左岸的情况.P ...

  2. 【Unity 3D学习笔记】PD 过河游戏智能实现

    P&D 过河游戏智能帮助实现 实现状态图的自动生成 讲解图数据在程序中的表示方法 利用算法实现下一步的计算 对于过河游戏,首先需要知道其中各个状态之间的转换关系,绘制状态转移图如下: 其中,P ...

  3. unity:PD 过河游戏智能帮助实现

    P&D 过河游戏智能帮助实现 github传送门 状态图 状态图课件有 状态图(Statechart Diagram)是描述一个实体基于事件反应的动态行为,显示了该实体如何根据当前所处的状态对 ...

  4. 3D游戏编程实践——PD 过河游戏智能帮助实现

    P&D 过河游戏智能帮助实现 需求 实现状态图的自动生成 讲解图数据在程序中的表示方法 利用算法实现下一步的计算 实现过程 实现状态图的自动生成&讲解图数据在程序中的表示方法 牧师与魔 ...

  5. PD 过河游戏智能帮助实现

    github传送门 https://github.com/ddghost/unity3d_n/tree/R%26D%E6%99%BA%E8%83%BD%E5%B8%AE%E5%8A%A9%E6%8F% ...

  6. 3D游戏编程与设计 PD(牧师与恶魔)过河游戏智能帮助实现

    3D游戏编程与设计 P&D(牧师与恶魔) 过河游戏智能帮助实现 文章目录 3D游戏编程与设计 P&D(牧师与恶魔) 过河游戏智能帮助实现 一.作业与练习 二.设计简述 1. 状态图基础 ...

  7. 【Unity3d学习】魔鬼与牧师过河游戏智能帮助

    文章目录 写在前面 实验内容 状态图自动生成(使用DFS) 1. 状态表示 2.DFS算法实现 3.DFS生成结果 更改Controller 效果展示 写在前面 本次项目Github地址:传送门 本次 ...

  8. Unity3d入门之路-从设计元素浅析一款游戏的成功因素

    什么造就了<明日方舟>的成功? 目录 什么造就了<明日方舟>的成功? 前言 游戏设计元素 玩家(players) 目标(objectives) 游戏过程(procedure) ...

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

    前言 这次实现一个含提示功能的牧师与恶魔过河小游戏,主要在上一个版本的牧师与恶魔小游戏上进行更改,通过增加一个状态计算和改版了得寻路算法,实现向玩家提示如何胜利完成游戏.游戏主体实现思路见上一篇博客- ...

最新文章

  1. yum 快速搭建lnmp环境
  2. linux igmp v3 过滤ip,网络 – Linux和IGMPv3上的多播加入
  3. UA OPTI570 量子力学30 Degenerate Stationary Perturbation Theory简介
  4. HDU - 4856 Tunnels(哈密顿路径+状压dp)
  5. 超线程cpu的寄存器_一文总结 CPU 基本知识
  6. PCM接口详细介绍--TDM方式
  7. sql组合键设置外键_学习SQL:外键
  8. linux用openssl制作自签名数字证书
  9. 计算机组成原理定点源码一位乘,计算机组成原理课程设计-定点原码一位乘法器的设计.doc...
  10. 城市矢量边界数据下载
  11. java单线程刷功德程序
  12. jquery手写table行列自动计算(自动计算小计和合计)
  13. 数据挖掘-python数据分析与挖掘实战
  14. 华三交换机模拟器搭建和使用
  15. yum命令详解和报错 Cannot find a valid baseurl for repo: base
  16. IDEA新建项目卡在下载Resolving dependencies of xxx
  17. 关于attach和detach的疑问
  18. 27、*(类和对象)现有电视商品价格竞猜活动。 项目需求:随机出现一个商品名,用户猜测它的价值 规定次数4次,猜对便可获得此商品。
  19. dbc:oracle:thin,没安装EBS能自己写个.dbc文件么?
  20. ni visa pci_希捷酷玩固态520系列1TB评测:PCI-E 4.0让游戏进一步加速

热门文章

  1. 尚硅谷_springcloud(2020新版 思维导图_2020年新版KET官方真题解析 Reading Part 4
  2. 闲来无聊,养狗养猫养乌龟
  3. 数据中心机房综合布线技巧大放送!
  4. 洛谷P2839 [国家集训队]middle(主席树)
  5. ACM/ICPC 2018亚洲区预选赛北京赛站网络赛 80 Days ——尺取
  6. 【知识图谱实战学习--[3]】
  7. 一款不错的java web网络相册管理系统
  8. 东北石油大学计算机科学与技术排名,东北石油大学优势专业排名,2021年东北石油大学最好的专业排名...
  9. python调用海康工业相机并用opencv显示(整体实现)
  10. knowledge tracing baseline解读-注释版本