恶魔与牧师V3

题目

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

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

实现

状态图

这里写图片描述

表示方法

该图在游戏中以矩阵的形式表示,使用数字编码对游戏数据进行设置,以3P3D为例,计算公式为:Pnum * 4 + Dnum。其中,P与D均为左岸数据。
而图书局的生成依靠如下代码:
遍历所有的点,如果该点是合法的,那么说明可以计算该点到其他点的关系。否则跳过。

            for (int i = 0; i < 32; i++)
            {
                int P = getP(i);
                int D = getD(i);
                bool side = getSide(i);
                if ((P < D && P != 0) || (P > D && P != MAXP) || (P == MAXP && D == MAXD && !side))
                {
                    continue;
                }
                else
                {
                    Stack<int> temp = getNextNum(i);
                    while (temp.Count != 0)
                    {
                        matrix[i, temp.Peek()] = 1;
                        temp.Pop();
                    }
                }
            }

计算时,使用函数来计算,分别模拟5种情况,判断是否能够完成该情况,如果能够,就将该操作的结果插入存储器,最终返回存储器。

生成矩阵

判断如下
这里写图片描述
判断的代码如下:

         public Stack<int> getNextNum(int now)
        {
            Stack<int> temp = new Stack<int>();
            int P = getP(now);
            int D = getD(now);
            // 1 
            if (getSide(now))
            {
                if ((D == 2 && P == 0) || (P == MAXP - 2 && D == MAXD - 2))
                {
                    temp.Push((P * 4 + D + 8));
                }
            }
            else
            {
                if ((P == 2 && D == 2) || (P == MAXP && D == MAXD - 2))
                {
                    temp.Push(P * 4 + D - 8 + 16);
                }
            }
            // 2
            if (getSide(now))
            {
                if (MAXD - D >= 2 && (P == 0 || P == MAXP))
                {
                    temp.Push(P * 4 + D + 2);
                }
            }
            else
            {
                if (D >= 2 && (P == 0 || P == MAXP))
                {
                    temp.Push(P * 4 + D - 2 + 16);
                }
            }
            // 3
            if (getSide(now))
            {
                if (P == D && MAXD > P)
                {
                    temp.Push(P * 4 + D + 5);
                }
            }
            else
            {
                if (P == D && P > 0)
                {
                    temp.Push(P * 4 + D - 5 + 16);
                }
            }
            // 4
            if (getSide(now))
            {
                if ((MAXP - P == 1 && MAXD - D == 1) || (D == 1 && P == 0))
                {
                    temp.Push(P * 4 + D + 4);
                }
            }
            else
            {
                if ((P == 1 && D == 1) || (MAXD - D == 1 && P == MAXP))
                {
                    temp.Push(P * 4 + D - 4 + 16);
                }
            }
            // 5
            if (getSide(now))
            {
                if (MAXD - D > 0 && (P == MAXP || P == 0))
                {
                    temp.Push(P * 4 + D + 1);
                }
            }
            else
            {
                if (D > 0 && (P == 0 || P == MAXP))
                {
                    temp.Push(P * 4 + D - 1 + 16);
                }
            }
            return temp;
        }

计算时,使用了DFS算法,递归实现,实现较为简单,其中设置终点。代码如下:

         public Stack<int> Tips(int start, int end)
        {
            Stack<int> temp = new Stack<int>();
            bool[] dfs = new bool[32];
            for (int i = 0; i < 32; i++)
            {
                dfs[i] = false;
            }
            bool flag = false;
            DFS(dfs, start, temp, end, flag);
            return temp;
        }
        public void DFS(bool[] dfs, int pos, Stack<int> temp, int end, bool flag)
        {
            dfs[pos] = true;
            for (int i = 0; i < 32; i++)
            {
                if (matrix[pos, i] != -1 && !dfs[i]) {
                    if (!flag)
                    {
                    temp.Push(i);
                    }
                    if (i != end)
                    {
                        DFS(dfs, i, temp, end, flag);
                    }
                    else
                    {
                        flag = true;
                    }
                }
            }
        }

## 其他实现:

使用了一个新的按钮,当点击这个按钮的时候,会进行计算,计算后返回存储了int的存储器,需要进行解析,并输出。

                    while (newStack.Count != 0)
                    {
                        int tempi = newStack.Peek();
                        newStack.Pop();
                        bool tempS = (tempi > 16) ? true : false;
                        int tempP = (tempi % 16) / 4;
                        int tempD = (tempi % 16) % 4;
                        if (tempS)
                        {
                            Debug.Log("前往右岸,使左岸有" + tempP + "牧师和" + tempD + "魔鬼\n");
                        }
                        else
                        {
                            Debug.Log("前往左岸,使左岸有" + tempP + "牧师和" + tempD + "魔鬼\n");
                        }
                    }

完整代码

其他代码与之前相同,只贴上新的控制类与计算路径类

graph

    public class Graph
    {
        public int MAXP = 3;
        public int MAXD = 3;
        public int priestNum;
        public int demonNum;
        public bool boatSide;
        int[,] matrix = new int[32, 32];
        public Graph()
        {
            priestNum = 0;
            demonNum = 0;
            boatSide = false;
            for (int i = 0; i < 32; i++)
            {
                for (int j = 0; j < 32; j++)
                {
                    matrix[i, j] = -1;
                }
            }
            for (int i = 0; i < 32; i++)
            {
                int P = getP(i);
                int D = getD(i);
                bool side = getSide(i);
                if ((P < D && P != 0) || (P > D && P != MAXP) || (P == MAXP && D == MAXD && !side))
                {
                    continue;
                }
                else
                {
                    Stack<int> temp = getNextNum(i);
                    while (temp.Count != 0)
                    {
                        matrix[i, temp.Peek()] = 1;
                        temp.Pop();
                    }
                }
            }
        }
        public Stack<int> Tips(int start, int end)
        {
            Stack<int> temp = new Stack<int>();
            bool[] dfs = new bool[32];
            for (int i = 0; i < 32; i++)
            {
                dfs[i] = false;
            }
            bool flag = false;
            DFS(dfs, start, temp, end, flag);
            return temp;
        }
        public void DFS(bool[] dfs, int pos, Stack<int> temp, int end, bool flag)
        {
            dfs[pos] = true;
            for (int i = 0; i < 32; i++)
            {
                if (matrix[pos, i] != -1 && !dfs[i]) {
                    if (!flag)
                    {
                    temp.Push(i);
                    }
                    if (i != end)
                    {
                        DFS(dfs, i, temp, end, flag);
                    }
                    else
                    {
                        flag = true;
                    }
                }
            }
        }
        public int getP(int num)
        {
            num = num % 16;
            return num / 4;
        }
        public int getD(int num)
        {
            num = num % 16;
            return num % 4;
        }
        public bool getSide(int num)
        {
            if (num >= 16)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        //1 = 2P; 2 = 2D; 3 = 1P1D; 4 = 1P; 5 = 1D 
        public Stack<int> getNextNum(int now)
        {
            Stack<int> temp = new Stack<int>();
            int P = getP(now);
            int D = getD(now);
            // 1 
            if (getSide(now))
            {
                if ((D == 2 && P == 0) || (P == MAXP - 2 && D == MAXD - 2))
                {
                    temp.Push((P * 4 + D + 8));
                }
            }
            else
            {
                if ((P == 2 && D == 2) || (P == MAXP && D == MAXD - 2))
                {
                    temp.Push(P * 4 + D - 8 + 16);
                }
            }
            // 2
            if (getSide(now))
            {
                if (MAXD - D >= 2 && (P == 0 || P == MAXP))
                {
                    temp.Push(P * 4 + D + 2);
                }
            }
            else
            {
                if (D >= 2 && (P == 0 || P == MAXP))
                {
                    temp.Push(P * 4 + D - 2 + 16);
                }
            }
            // 3
            if (getSide(now))
            {
                if (P == D && MAXD > P)
                {
                    temp.Push(P * 4 + D + 5);
                }
            }
            else
            {
                if (P == D && P > 0)
                {
                    temp.Push(P * 4 + D - 5 + 16);
                }
            }
            // 4
            if (getSide(now))
            {
                if ((MAXP - P == 1 && MAXD - D == 1) || (D == 1 && P == 0))
                {
                    temp.Push(P * 4 + D + 4);
                }
            }
            else
            {
                if ((P == 1 && D == 1) || (MAXD - D == 1 && P == MAXP))
                {
                    temp.Push(P * 4 + D - 4 + 16);
                }
            }
            // 5
            if (getSide(now))
            {
                if (MAXD - D > 0 && (P == MAXP || P == 0))
                {
                    temp.Push(P * 4 + D + 1);
                }
            }
            else
            {
                if (D > 0 && (P == 0 || P == MAXP))
                {
                    temp.Push(P * 4 + D - 1 + 16);
                }
            }
            return temp;
        }
    }

controller

public class Controller : MonoBehaviour
{


    Data instance;          //数据块
    GameState states;       //当前游戏状态
    DemonAndPriest.Action act;             //动作管理器
    bool toBoat;            //判断上船动作是否完成,若完成则改变Data中的状态,下同
    bool turnBack;          //是否船已到达对岸,需要掉头
    bool toShore;           //是否需要对象上岸
    Graph graph;


    //初始化
    public void Start()
    {
        instance = gameObject.AddComponent<Data>() as Data;
        act = gameObject.AddComponent<DemonAndPriest.Action>() as DemonAndPriest.Action;
        graph = new Graph();
        states = GameState.Waiting;
        toBoat = false;
        turnBack = false;
        toShore = false;
    }

    //交互
    public void OnGUI()
    {
        //显示界面
        instance.SetView();
        //调整当前状态,查看是否有已完成动作但未和Data同步
        if (!act.Run())
        {
            states = GameState.Waiting;
            if (toBoat)
            {
                instance.MoveToBoat();
                toBoat = false;
            } else if(toShore)
            {
                instance.MoveToShore();
                toShore = false;
            } else if (turnBack)
            {
                instance.SetPosition();
                turnBack = false;
            }
        }
        //判断当前游戏是否结束
        if (states == GameState.Waiting)
        {
            states = instance.Charge();
        }
        //游戏进行中
        if (states == GameState.Waiting || states == GameState.Moving)
        {
            if (states == GameState.Waiting)
            {
                if (GUI.Button(new Rect(Screen.width / 2 - 50, Screen.height / 10 * 2f, 100, 30), "提示"))
                {
                    int now = 0;
                    if (instance.getBoatPosition())
                    {
                        now = (3 - instance.GetPriestCount()) * 4 + (3 - instance.GetDemonCount()) + 16;
                    }
                    else
                    {
                        now = instance.GetPriestCount() * 4 + instance.GetDemonCount();
                    }
                    Debug.Log(now);
                    Stack<int> next = graph.Tips(now , 15);
                    Stack<int> newStack = new Stack<int>();
                    while (next.Peek() != 15)
                    {
                        next.Pop();
                    }
                    while (next.Count != 0)
                    {
                        int tempi = next.Peek();
                        newStack.Push(tempi);
                        next.Pop();
                    }
                    while (newStack.Count != 0)
                    {
                        int tempi = newStack.Peek();
                        newStack.Pop();
                        bool tempS = (tempi > 16) ? true : false;
                        int tempP = (tempi % 16) / 4;
                        int tempD = (tempi % 16) % 4;
                        if (tempS)
                        {
                            Debug.Log("前往右岸,使其有" + tempP + "牧师和" + tempD + "魔鬼\n");
                        }
                        else
                        {
                            Debug.Log("前往左岸,使其有" + tempP + "牧师和" + tempD + "魔鬼\n");
                        }
                    }
                }
            }
            if (GUI.Button(new Rect (Screen.width / 10 * 3.4f, Screen.height / 10 * 2f, 100, 30), "牧师上船"))
            {
                if (states == GameState.Waiting)
                {
                    if (instance.BoatCount() == 2 || instance.GetPriestCount() == 0)
                    {
                        return;
                    }
                    instance.PriestOnBoat();
                    act.Act(instance.getMoving(), instance.getBoatPosition(), instance.BoatCount(), false);
                    states = GameState.Moving;
                    toBoat = true;
                }
            }
            if (GUI.Button(new Rect(Screen.width / 10 * 6, Screen.height / 10 * 2f, 100, 30), "恶魔上船"))
            {
                if (states == GameState.Waiting)
                {
                    if (instance.BoatCount() == 2 || instance.GetDemonCount() == 0)
                    {
                        return;
                    }
                    instance.DemonOnBoat();
                    act.Act(instance.getMoving(), instance.getBoatPosition(), instance.BoatCount(), false);
                    states = GameState.Moving;
                    toBoat = true;
                }
            }
            if (GUI.Button(new Rect(Screen.width / 2 - 50, Screen.height / 10 * 3.5f, 100, 30), "启程"))
            {
                if (states == GameState.Moving || instance.BoatCount() == 0)
                {
                    return;
                }
                act.Act(instance.GetBoat(), instance.getBoatPosition(), instance.BoatCount(), true);
                states = GameState.Moving;
                turnBack = true;
            }
            if (GUI.Button(new Rect (Screen.width / 2 - 50, Screen.height / 10 * 4.5f, 100, 30), "下船"))
            {
                if(states != GameState.Waiting)
                {
                    return;
                }
                if (instance.BoatCount() != 0)
                {
                    instance.DownBoat();
                    act.Act(instance.getMoving(), instance.getBoatPosition(), instance.BoatCount(), true);
                    states = GameState.Moving;
                    toShore = true;
                }
            }
            if (GUI.Button(new Rect(Screen.width / 4 * 3, Screen.height / 10 * 8f, 100, 30), "重新开始"))
            {
                instance.Reload();
                states = GameState.Waiting;
            }
        }
        //胜利
        else if (states == GameState.Win)
        {
            GUI.Label(new Rect(Screen.width / 2 - 50, Screen.height / 10 * 3f, 100, 30), "胜利");
            if (GUI.Button(new Rect(Screen.width / 4 * 3, Screen.height / 10 * 8f, 100, 30), "重新开始")) {
                states = GameState.Waiting;
                instance.Reload();
            }
        }
        //游戏结束
        else if (states == GameState.GameOver)
        {
            GUI.Label(new Rect(Screen.width / 2 - 50, Screen.height / 10 * 3f, 100, 30), "牧师死亡");
            if (GUI.Button(new Rect(Screen.width / 4 * 3, Screen.height / 10 * 8f, 100, 30), "重新开始"))
            {
                states = GameState.Waiting;
                instance.Reload();
            }
        }
    }
}

演示视频

视频

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值