3D_HW10

3D游戏编程与设计

HW 10

P&D 过河游戏智能帮助实现

  • 实现状态图的自动生成
  • 讲解图数据在程序中的表示方法
  • 利用算法实现下一步的计算

演示视频

http://www.iqiyi.com/w_19sb4adyrd.html
在这里插入图片描述

状态图与图数据

状态图可通过枚举列出

左岸恶魔左岸牧师右岸恶魔右岸牧师船只
0033右岸
1122左岸
3300左岸
2211右岸

枚举出所有状态然后化为状态转换图如下
在这里插入图片描述

有了上面的状态转换图, 就只需要实现相应的代码, 这里将以前的代码重新改写一下, 将一个状态改写为一个具体的class, 其中包括两岸的恶魔与牧师数量, 船的数量, 父节点等, 加入父节点是为了构建具体的图. 接下来我们需要根据状态实现BFS, 根据相应的游戏规则可知搜索的情况包括以下几种, 包括船只的位置, 船只上的空闲位置, 伪代码如下

初始化队列Q;
访问顶点v; visited [v]=1; 顶点v入队Q;
while (队列Q非空) 
    v=队列Q的队头元素出队;
    w=顶点v的第一个邻接点;
    while (w存在) 
        如果w 未被访问,则
        访问顶点w; 
        visited[w]=true; 顶点w入队列Q;
        w=顶点v的下一个邻接点;

参考师兄博客实现实际的BFS算法如下

public static PristsAndDevilsState BFS(PristsAndDevilsState start, PristsAndDevilsState end)
{
    Queue<PristsAndDevilsState> found = new Queue<PristsAndDevilsState>();
    PristsAndDevilsState temp = new PristsAndDevilsState(start.leftPriests, start.leftDevils, start.rightPriests, start.rightDevils, start.boat_pos, null);
    found.Enqueue(temp);
    while (found.Count > 0){
        temp = found.Peek();
        if (temp == end){
            while (temp.parent_state != start){
                temp = temp.parent_state;
            }
            return temp;
        }
        found.Dequeue();

        if (temp.boat_pos){
            if (temp.leftPriests > 0){
                PristsAndDevilsState next = new PristsAndDevilsState(temp);
                next.parent_state = new PristsAndDevilsState(temp);
                next.boat_pos = false;
                next.leftPriests--;
                next.rightPriests++;
                if (next.isValid() && !found.Contains(next)){
                    found.Enqueue(next);
                }
            }if (temp.leftDevils > 0){
                PristsAndDevilsState next = new PristsAndDevilsState(temp);
                next.parent_state = new PristsAndDevilsState(temp);
                next.boat_pos = false;
                next.leftDevils--;
                next.rightDevils++;
                if (next.isValid() && !found.Contains(next)){
                    found.Enqueue(next);
                }
            }if (temp.leftDevils > 0 && temp.leftPriests > 0){
                PristsAndDevilsState next = new PristsAndDevilsState(temp);
                next.parent_state = new PristsAndDevilsState(temp);
                next.boat_pos = false;
                next.leftDevils--;
                next.rightDevils++;
                next.leftPriests--;
                next.rightPriests++;
                if (next.isValid() && !found.Contains(next)){
                    found.Enqueue(next);
                }
            }if (temp.leftPriests > 1){
                PristsAndDevilsState next = new PristsAndDevilsState(temp);
                next.parent_state = new PristsAndDevilsState(temp);
                next.boat_pos = false;
                next.leftPriests -= 2;
                next.rightPriests += 2;
                if (next.isValid() && !found.Contains(next)){
                    found.Enqueue(next);
                }
            }if (temp.leftDevils > 1){
                PristsAndDevilsState next = new PristsAndDevilsState(temp);
                next.parent_state = new PristsAndDevilsState(temp);
                next.boat_pos = false;
                next.leftDevils -= 2;
                next.rightDevils += 2;
                if (next.isValid() && !found.Contains(next)){
                    found.Enqueue(next);
                }
            }
        }else{
            if (temp.rightPriests > 0){
                PristsAndDevilsState next = new PristsAndDevilsState(temp);
                next.parent_state = new PristsAndDevilsState(temp);
                next.boat_pos = true;
                next.rightPriests--;
                next.leftPriests++;
                if (next.isValid() && !found.Contains(next)){
                    found.Enqueue(next);
                }
            }if (temp.rightDevils > 0){
                PristsAndDevilsState next = new PristsAndDevilsState(temp);
                next.parent_state = new PristsAndDevilsState(temp);
                next.boat_pos = true;
                next.rightDevils--;
                next.leftDevils++;
                if (next.isValid() && !found.Contains(next)){
                    found.Enqueue(next);
                }
            }if (temp.rightDevils > 0 && temp.rightPriests > 0){
                PristsAndDevilsState next = new PristsAndDevilsState(temp);
                next.parent_state = new PristsAndDevilsState(temp);
                next.boat_pos = true;
                next.rightDevils--;
                next.leftDevils++;
                next.rightPriests--;
                next.leftPriests++;
                if (next.isValid() && !found.Contains(next)){
                    found.Enqueue(next);
                }
            }if (temp.rightDevils > 1) {
                PristsAndDevilsState next = new PristsAndDevilsState(temp);
                next.parent_state = new PristsAndDevilsState(temp);
                next.boat_pos = true;
                next.rightDevils -= 2;
                next.leftDevils += 2;
                if (next.isValid() && !found.Contains(next)){
                    found.Enqueue(next);
                }
            }if (temp.rightPriests > 1){
                PristsAndDevilsState next = new PristsAndDevilsState(temp);
                next.parent_state = new PristsAndDevilsState(temp);
                next.boat_pos = true;
                next.rightPriests -= 2;
                next.leftPriests += 2;
                if (next.isValid() && !found.Contains(next)){
                    found.Enqueue(next);
                }
            }
        }
    }
    return null;
}

最后只需要实现UI部分即可.

void initializePD() {
    for (int i = 0; i < 3; ++i) {
        vec[i].x = begin_len + i * space;
        vec[i].y = 1;
        vec[i].z = 0;
    }
    for (int i = 3; i < 6; ++i) {
        vec[i].x = begin_len + 2 * space + (i - 2) * space;
        vec[i].y = 1;
        vec[i].z = 0;
    }
    for (int i = 0; i < 3; ++i) {
        priests[i] = GameObject.Instantiate(Resources.Load("Prefabs/Priest", typeof(GameObject)), vec[i], Quaternion.identity, null) as GameObject;
        priests[i].name = "priest" + i.ToString();
        priests[i].AddComponent<SSActionManager>();
        devils[i] = GameObject.Instantiate(Resources.Load("Prefabs/Devil", typeof(GameObject)), vec[i + 3], Quaternion.identity, null) as GameObject;
        devils[i].name = "devils" + i.ToString();
        devils[i].AddComponent<SSActionManager>();
    }
}

void OnGUI() {
    if(GUI.Button(new Rect(Screen.width / 2 - 50, Screen.height / 2 + 200, 100, 100), "Go!")) {
        if (BoatController.count >= 1) {
            BoatController.if_move = true;
            run = false;
            int count = BoatController.boat.transform.childCount;
            if (BoatController.direction_left) {
                for (int i = 0; i < count; ++i) {
                    Click.decCount(BoatController.boat.transform.GetChild(i).name, 0);
                    Click.insCount(BoatController.boat.transform.GetChild(i).name, 1);
                }
            } else {
                for (int i = 0; i < count; ++i) {
                    Click.decCount(BoatController.boat.transform.GetChild(i).name, 1);
                    Click.insCount(BoatController.boat.transform.GetChild(i).name, 0);
                }
            }
            ++step;
        }
    }

    // success or lose or normal condition
    if (Judge.judgeEnd() == 2 || Judge.judgeEnd() == 1) { // lose
        GUI.Label(new Rect(Screen.width / 2 - 100, Screen.height / 2 - 200, 200, 200), "Failed, reload after 2s", mstyle);
        Invoke("reset", Time.time + 2);
    } else if (Judge.judgeEnd() == 0) { // success
        GUI.Label(new Rect(Screen.width / 2 - 100, Screen.height / 2 - 200, 200, 200), "Success! reload after 2s", mstyle);
        Invoke("reset", Time.time + 2);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值