1. 程式人生 > >c#實現迷宮尋路演算法

c#實現迷宮尋路演算法

一、解決問題:

在Unity3d的一些2d遊戲製作上,有時需要敵人在眾多箱子(障礙物)中向主角移動,如果是簡單的移動ai程式碼實現,敵人有可能陷入死衚衕然後左右移動,卡死在衚衕上,為了一個智慧的ai實現,比較常用的是A*演算法,但這裡為了簡便,我們使用了深度搜索的方式進行判斷。所謂深度搜索,一位博主總結得很好,就是“不見棺材不回頭。演算法會朝一個方向進發,直到遇到邊界或者障礙物,才回溯。一般在實現的時候,我們採用遞迴的方式來進行,也可以採用模擬壓棧的方式來實現。

在這裡的程式碼中,是利用c#的棧,儲存了名為Cell的宮格類,Cell類中包含了周圍四個方向是否有路的資訊,Maze迷宮類中將對每個能走的方向都進行嘗試行走,將能走的路一直走下去,直到走不通為止,此時開始回溯,即使用stack.Pop(),一直退回分支,走下一條路線。舉個例子:當前宮格的北方向【有路】,那麼嘗試向北走一步,走完後把設定此宮格的北方向為【無路】,並把走到的那個宮格的南方向設定為【無路】(都是相對的),就這樣一直走下去,當發現無法到達終點時,開始退回,再次判斷當前宮格的四個方向是否有路,直到退回到最後的分支上,進行下一條路的嘗試行走。

該演算法雖然簡單,但卻在不少地方都需要用到,比如遊戲按鍵刷圖指令碼的地圖判斷的處理部分:例如找色判斷dnf、手遊《永遠的7日之都》的萬神殿地圖部分,只要能直到當前揭示的地圖,就可以算出一條通向boss的道路,然後自動刷圖就完成了一個核心功能。

二、演示效果:

控制檯程式程式碼Program.cs中輸入:

 int[,] maps = new int[,] {
                { 0, 0, 0, 0, 0 },
                { 1, 0, 0, 1, 1 },
                { 0, 0, 0, 1, 0 },
                { 0, 1, 1, 1, 1 },

                { 0, 0, 0, 0, 0 } };

註釋:0代表可通過,1代表不可通過。

執行程式,輸出如下:

2 2 2 0 0
1 2 2 1 1
2 2 2 1 0
2 1 1 1 1
2 2 2 2 2

註釋:2代表為走出的路徑

三、上程式碼:

建立控制檯程式:

Program.cs:

using System;

namespace MazePath
{
    class Program
    {
        static void Main(string[] args)
        {
            //0表示可走,1表示不可走
            int[,] maps = new int[,] {
                { 0, 0, 0, 0, 0 },
                { 1, 0, 0, 1, 1 },
                { 0, 0, 0, 1, 0 },
                { 0, 1, 1, 1, 1 },
                { 0, 0, 0, 0, 0 } };


            Maze maze = new Maze(maps);           
            Console.ReadLine();
        }
    }
}

Maze.cs:

using System;
using System.Collections.Generic;


namespace MazePath
{
    class Maze
    {
        Cell[,] cells;
        Stack<Cell> cellStack = new Stack<Cell>();
        int[,] maps;
        int rows;
        int length;

        public Maze(int[,] maps)
        {
            this.maps = maps;
            length = maps.GetLength(1);
            rows = maps.GetLength(0);
            cells = new Cell[rows, length];
            InitCells();
            GetValidPath();
            ConsoleResult();
        }

        public void InitCells()
        {
            for (int i = 0; i < rows; i++)
            {
                for (int j = 0; j < length; j++)
                {
                    //設定每個格子自身的位置屬性
                    Cell cell = new Cell();
                    cell.SetPos(i, j);

                    cells[i, j] = cell;

                    //-----設定格子的周圍方向屬性---------------
                    //西
                    if ((j - 1) >= 0)
                    {
                        if (maps[i, j - 1] == 0)
                            cells[i, j].SetDirection(Const.WEST, Const.ENABLE);
                        else
                            cells[i, j].SetDirection(Const.WEST, Const.DISABLE);
                    }

                    //東
                    if ((j + 1) < length)
                    {
                        if (maps[i, j + 1] == 0)
                            cells[i, j].SetDirection(Const.EAST, Const.ENABLE);
                        else
                            cells[i, j].SetDirection(Const.EAST, Const.DISABLE);
                    }

                    //北
                    if ((i - 1) >= 0)
                    {
                        if (maps[i - 1, j] == 0)
                            cells[i, j].SetDirection(Const.NORTH, Const.ENABLE);
                        else
                            cells[i, j].SetDirection(Const.NORTH, Const.DISABLE);
                    }

                    //南
                    if ((i + 1) < rows)
                    {
                        if (maps[i + 1, j] == 0)
                            cells[i, j].SetDirection(Const.SOUTH, Const.ENABLE);
                        else
                            cells[i, j].SetDirection(Const.SOUTH, Const.DISABLE);
                    }

                }
            }
        }

        public void GetValidPath()
        {
            int i = 0;int j = 0;
            cellStack.Push(cells[i, j]);
            while (true)
            {
                i = cellStack.Peek().x; j = cellStack.Peek().y;
                if (i == (rows - 1) && j == (length - 1))
                {
                    return;
                }

                //東
                if (cellStack.Peek().GetDirection(Const.EAST)==Const.ENABLE)
                {
                    cells[i, j].SetDirection(Const.EAST, Const.DISABLE);
                    cells[i, j+1].SetDirection(Const.WEST, Const.DISABLE);
                    cellStack.Push(cells[i, j + 1]);
                    continue;
                }
                //西
                if (cellStack.Peek().GetDirection(Const.WEST) == Const.ENABLE)
                {
                    cells[i, j].SetDirection(Const.WEST, Const.DISABLE);
                    cells[i, j + 1].SetDirection(Const.EAST, Const.DISABLE);
                    cellStack.Push(cells[i, j - 1]);
                    continue;
                }
                //北
                if (cellStack.Peek().GetDirection(Const.NORTH) == Const.ENABLE)
                {
                    cells[i, j].SetDirection(Const.NORTH, Const.DISABLE);
                    cells[i - 1, j].SetDirection(Const.SOUTH, Const.DISABLE);
                    cellStack.Push(cells[i-1, j]);
                    continue;
                }
                //南
                if (cellStack.Peek().GetDirection(Const.SOUTH) == Const.ENABLE)
                {
                    cells[i, j].SetDirection(Const.SOUTH, Const.DISABLE);
                    cells[i + 1, j].SetDirection(Const.NORTH, Const.DISABLE);
                    cellStack.Push(cells[i+1, j]);
                    continue;
                }

                cellStack.Pop();

                if (cellStack.Count == 0)
                {
                    Console.WriteLine("根本沒有這個路徑");
                    return;
                }
            }
        }

        public void ConsoleResult()
        {
            while (cellStack.Count != 0)
            {
                int i = cellStack.Peek().x;
                int j = cellStack.Peek().y;
                cellStack.Pop();
                maps[i, j] = 2;
            }

            string s = "";
            for(int i = 0; i < maps.GetLength(0); i++)
            {
                for(int j = 0; j < maps.GetLength(1); j++)
                {
                    s += maps[i, j].ToString()+" ";
                }
                s += "\r\n";
            }
            Console.WriteLine(s);
        }
    }
}

Cell.cs:

namespace MazePath
{
    class Cell
    {
        public int x;
        public int y;
        //directon 索引0-3分別是東西南北,預設為0表示不可走,1則表示可走
        private int[] directions = new int[4];

        public void SetPos(int x,int y)
        {
            this.x = x;
            this.y = y;
        }

        public bool IsEnable(int index)
        {
            return directions[index]==1;
        }
        public void SetDirection(int index,int result)
        {
            directions[index] = result;
        }
        public int GetDirection(int index)
        {
            return directions[index];
        }
    }
}

Const.cs:

namespace MazePath
{
    public static class Const
    {
        public const int EAST = 0;   //東
        public const int WEST = 1;   //西
        public const int SOUTH = 2;  //南
        public const int NORTH = 3;  //北

        public const int ENABLE = 1;
        public const int DISABLE = 0;

    }
}

相關推薦

c#實現迷宮演算法

一、解決問題:在Unity3d的一些2d遊戲製作上,有時需要敵人在眾多箱子(障礙物)中向主角移動,如果是簡單的移動ai程式碼實現,敵人有可能陷入死衚衕然後左右移動,卡死在衚衕上,為了一個智慧的ai實現,比較常用的是A*演算法,但這裡為了簡便,我們使用了深度搜索的方式進行判斷。

【資料結構】棧實現迷宮問題

思路: 解決迷宮求解的問題,從入口出發,順某一方向向前探索,若能走通,則繼續往前走;否則沿原路退回,換一個方向再繼續探索,直至所有可能的通路都探索到為止。為了保證在任何位置上都能沿原路退回,所以需要用一個後進先出的結構來儲存從入口到當前位置的路徑。因此,在求迷宮通路的演算法

C#實現A*

網上有關A*演算法的文章已經非常豐富了,各種語言各種思路都有,本來我實在不想再寫一篇,,但因為最近工作動盪因此專門抽空又看了一下,然後就想寫個文章防止以後印象模糊,好歹看自己寫的東西可以很快回憶起來。如果是初次接觸A*演算法的朋友可以先看看這篇參考文章,我這邊只是做一個總結,

js實現A*演算法

js使用canvas繪製介面。 定義兩個類:Node儲存點及A*演算法中的F=G+H值;Point。 /** * 節點 * p : 節點對應的座標 * pn : 節點的父節點 * g : A*-g * h : A*-h */ function Node(p,

Unity3d 實現 A * 演算法

原理A* 演算法是一種啟發式搜尋演算法,通過代價函式f = g+h,A*演算法每次查詢代價最低的點作為搜尋點,並更新搜尋節點列表。最終搜尋到目標位置。需要定義兩個列表 (Open和Closed列表):    private List<Tile> openList

javascript實現A*演算法

A*尋路演算法是遊戲中經常用到的一種自動路徑計算演算法,比如連連看、NPC自動巡邏等等。本文章預設使用者已經熟悉A*尋路演算法演算法,不熟悉的可參閱下面連結的文章: 先來看看效果圖: Node 定義尋路過程中的點物件 var Node =

C語言-老鼠走迷宮(廣度演算法)

老鼠走迷宮-c語言(基於廣度優先的尋路演算法) 深讀優先尋路演算法原文:https://blog.csdn.net/qq_42476927/article/details/81868068  本文是基於之前的深度優先尋路演算法改進而來,參考了許多廣度遍歷的程式碼結合自己程

C語言-老鼠走迷宮(深度演算法)

老鼠走迷宮-c語言(基於深度優先的尋路演算法) 這個是學校的課設,剛開始有點頭疼,但是感覺越做越有意思了,於是就有如下程式碼,可能相較於大佬還有差距,但是這是我目前所能做的最優的程式了吧!    話不多說,說一下程式碼的核心內容吧!   &nb

c++實現的A* 靜態演算法 程式碼

在此僅提供程式碼,不對原理進行解釋。 如果想知道原理請自行百度,已經有很多前輩寫過了。 這裡用到了簡單的圖形庫 easyX #include<iostream> #include<math.h> #include<graphics.h> using n

A星演算法(遊戲演算法)的C++實現

      先吐槽一句:CODE功能太不給力了,怎麼弄怎麼崩潰,難道是CSDN也被掃黃打非了??? ---------------------------------------------     A星演算法的實現原理看這裡:http://www.cnblogs.com

A*演算法基於C#實現

 玩過即時戰略,RPG等型別的遊戲的朋友一定會知道,當我們用滑鼠選取某些單位並命令其到達地圖上確定的位置時,這些單位總是可以自動的選擇最短的路徑到達。這個時候我們就會聯想到大名鼎鼎的A*尋路演算法,下文簡略介紹演算法實現原理,並附上C#實現方法。using System; u

A*演算法C++簡單實現

2007/8/13 17:26:59 #include <iostream> #include <ctime> #include <list> #include <algorithm> #include <cassert&

遺傳演算法解決迷宮問題(Java實現

1.什麼是遺傳演算法? 就個人理解,遺傳演算法是模擬神奇的大自然中生物“優勝劣汰”原則指導下的進化過程,好的基因有更多的機會得到繁衍,這樣一來,隨著繁衍的進行,生物種群會朝著一個趨勢收斂。而生物繁衍過程中的基因雜交和變異會給種群提供更好的基因序列,這樣種群的繁

A*演算法C++簡單實現

參考文章: A*尋路演算法是遊戲中常用的AI演算法,這裡用C++簡單實現了一下演算法,便於理解。 搜尋區域 如圖所示簡易地圖, 其中綠色方塊的是起點 (用 A 表示), 中間藍色的是障礙物, 紅色的方塊 (用 B 表示) 是目的地. 為了可以用一個二

C#中的演算法

目錄 介紹 問題 Dijkstra演算法 A *演算法 結果 結論 挑戰 Dijkstra和Astar的比較 Download source - 571.3 KB 在Visual Studio 2017中解壓縮並開啟解決方案 介紹 你有沒

如何實現A星演算法 Cocos2d-x 3 0 beta2

bool pathFound = false;_spOpenSteps.clear();_spClosedSteps.clear();// 首先,新增貓的方塊座標到open列表this->insertInOpenSteps(ShortestPathStep::createWithPosition(fro

人工智慧: 自動演算法實現(一、廣度優先搜尋)

前言 隨著人工智慧技術的日益發達,我們的生活中也出現了越來越多的智慧產品。我們今天要關注的是智慧家居中的一員:掃地機器人。智慧掃地機器人可以在主人不在家的情況下自動檢測到地面上的灰塵,並且進行清掃。有些更為對路線進行規劃,找到可以清理灰塵的最短路徑,達到省電的

流場演算法學習及實現

流場尋路演算法簡單實現 Flow field pathfinding algorithm implementation Introduction: 流場尋路演算法主要用於解決地圖中大量目標尋路問題,像傳統的尋路演算法(如A*)需要對每個移動目標進行單獨的

Unity3d利用A*演算法實現模擬

這裡我先引用一篇詳細文章來介紹A*演算法文章內容如下簡易地圖 如圖所示簡易地圖, 其中綠色方塊的是起點 (用 A 表示), 中間藍色的是障礙物, 紅色的方塊 (用 B 表示) 是目的地. 為了可以用一個二維陣列來表示地圖, 我們將地圖劃分成一個個的小方塊.二維陣列在遊戲中的應

A星演算法的Lua實現

A*搜尋演算法俗稱A星演算法。這是一種在圖形平面上,有多個節點的路徑,求出最低通過成本的演算法。 對A星演算法的理解還是要從公式 F = G + H開始:在節點化的地圖上,每一步的操作,使得已走距離 + 距離終點距離最小。具體的實現上是維護一個open表和