惡魔與牧師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();
            }
        }
    }
}

演示視頻

視頻

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章