unity應用實例——模擬深度優先遍歷流程(DFS)

DFS是被廣泛運用的搜索算法,它屬於一種盲目搜索,定義如下:

1、起始訪問的頂點是指定的;

2、若當前訪問的頂點的鄰接頂點有未被訪問的,則任選一個訪問;反之,退回到最近訪問過的頂點;直到與起始頂點相通的全部頂點都訪問完畢;

3、若此時圖中尚有頂點未被訪問,則再選其中一個頂點作爲起始頂點並訪問之,轉 2; 反之,遍歷結束。

    大多數時候我們用dfs時會採用遞歸的方式,但是非遞歸的方式更加直觀,思路更清晰,更便於我們去理解”深度“的思想。這篇文章主要介紹如何用unity引擎來可視化模擬非遞歸的dfs算法。爲了方便理解,給出一個經典的紅黑格題目,要求如下:

    有一個長方形的房間,房間裏的地面上佈滿了正方形的瓷磚,瓷磚要麼是紅色的,要麼是黑色的。一個人站在其中一塊黑色的瓷磚上,他可以向四周的瓷磚上移動,但是不能移動到紅色的瓷磚上,只能在黑色的瓷磚上移動,用深度優先搜索的思想模擬該過程。

    輸入數據有三個,分別是房間的長和寬,以及一個字符串。字符串含有房間中磚塊的顏色信息,例如“#”表示黑色瓷磚,“*”表示紅色瓷磚,“@”表示該位置的黑色瓷磚,那麼字符串可以是

"***#**######@#***##**#***##***#***#****##*###*#**"

(注意,長和寬的乘積應該和字符串字符數相同。)

腳本代碼如下(c#):

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Threading;
using System;
using UnityEditor;

public class NewBehaviourScript : MonoBehaviour
{
    public GameObject redcube, blackcube, yellowcube, origncube, Ethan;
    public string Str1;
    public int weight, height;
    private int k = 0;
    public char[,] map;
    public int[] path;//記錄走過的座標
    private int[] dx = { 1, -1, 0, 0 }, dy = { 0, 0, 1, -1 };
    public int[,] visited;//記錄每一塊磚走過的次數
    private int cnt = 0, row = 0, cnt2 = 0;
    private int sx = 0, sy = 0;
    public float time = 0;
    private bool moved = false, isbacking = false, once = false;
    private float deltaposxy = 4.2f, deltaposz = 0.27f;
    void Start()
    {
        //初始化map 生成地圖
        Transform temp = transform;
        temp.position = new Vector3(orign.transform.position.x, 0, orign.transform.position.z);
        visited = new int[weight, height];
        map = new char[weight, height];
        path = new int[weight * height * 100];
        for (int j = 0; j < height; j++)
        {
            for (int i = 0; i < weight; i++)
            {
                if (Str1[k] == '*')
                {
                    map[i, j] = Str1[k];
                    temp.position = new Vector3(orign.transform.position.x + i * deltaposxy, 0, orign.transform.position.z + j * deltaposxy);
                    GameObject ared = Instantiate(red, temp.position, temp.rotation);
                    k++;
                    continue;
                }
                if (Str1[k] == '#')
                {

                    map[i, j] = Str1[k];
                    temp.position = new Vector3(orign.transform.position.x + i * deltaposxy, 0, orign.transform.position.z + j * deltaposxy);
                    GameObject ablack = Instantiate(black, temp.position, temp.rotation);
                    k++;
                    continue;
                }
                if (Str1[k] == '@')
                {
                    map[i, j] = Str1[k];
                    sx = i; sy = j;
                    temp.position = new Vector3(orign.transform.position.x + i * deltaposxy, 0, orign.transform.position.z + j * deltaposxy);
                    GameObject ayellow = Instantiate(yellow, temp.position, temp.rotation);
                    k++;
                    continue;
                }
            }
        }
        k = 0;
        gameObject.transform.position = new Vector3(orign.transform.position.x + sx * deltaposxy, deltaposz, orign.transform.position.z + sy * deltaposxy);
        dfs();
    }
    private int j = 0;
    void Update()
    {
        time++;
        if (time % 30 == 0)
        {
            if (cnt2 > 0)
            {
                Transform temp = transform;
                temp.position = new Vector3(orign.transform.position.x + path[j] * deltaposxy, deltaposz, orign.transform.position.z + path[j + 1] * deltaposxy);
                GameObject aethan = Instantiate(Ethan, temp.position, temp.rotation);
                j += 2;
                Destroy(aethan, 0.35f);
                cnt2--;
            }
        }
    }
    void dfs()
    {
        visited[sx, sy] = 1;//標記1表示Ethan走過此磚一次
        cnt++;
        while (true)
        {
            for (int i = 0; i < 4; i++)
            {
                int nx = sx + dx[i], ny = sy + dy[i];//前後左右選擇一個方向判斷

                if (nx >= 0 && nx < weight && ny >= 0 && ny < height)
                {
                    if (visited[nx, ny] == 0 && map[nx, ny] != '*')//找到了某一方向有從未走過的磚,前進
                    {
                        path[row] = nx; row++;
                        path[row] = ny; row++;
                        moved = true;
                        //在返回的途中發現沒走過的磚,將現在腳下拐彎的磚標記爲1(原本應該標記爲2),因爲後面一定還會至少再經過一次
                        if (isbacking == true) visited[sx, sy] = 1; //
                        isbacking = false;
                        sx = nx; sy = ny;
                        visited[sx, sy] = 1;//將走過一次的磚標記爲1
                        cnt++;
                        cnt2++;
                        time = 0;
                        break;
                    }
                }

            }
            if (moved == true)
            {
                moved = false;
                continue;
            }
            //前後左右都不存在沒走過的磚,此時找走過一次的磚
            for (int i = 0; i < 4; i++)
            {
                int nx = sx + dx[i], ny = sy + dy[i];//前後左右選擇一個方向判斷
                if (nx >= 0 && nx < weight && ny >= 0 && ny < height)
                {
                    if (visited[nx, ny] == 1 && map[nx, ny] != '*')//找到了某一方向有走過一次的磚,前進
                    {
                        path[row] = nx; row++;
                        path[row] = ny; row++;
                        moved = true;
                        sx = nx; sy = ny;
                        visited[sx, sy] = 2;//將走過兩次的磚標記爲2
                        isbacking = true;
                        time = 0;
                        cnt2++;
                        break;
                    }
                }
            }
            if (moved == true)
            {
                moved = false;
                continue;
            }
            Debug.Log(cnt);
            break;
        }
    }
}

將此腳本掛在一個空物體上,並在unity中給腳本的每一個數據成員賦上初始值,點擊開始就可以開到模擬出的dfs算法思路。效果如下:

 


謝謝觀看:)

 

 

 

 

 

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