1. 程式人生 > >day21 Go 實現的深度優先搜尋實現迷宮演算法

day21 Go 實現的深度優先搜尋實現迷宮演算法

 

# Go 實現的深度優先搜尋實現迷宮演算法

package main

import (
	"errors"
	"fmt"
	"os"
)

// 讀取檔案中的資料,使用迴圈生成迷宮圖
func readMazeFile(filename string) [][]int {
	file, err := os.Open(filename)
	defer file.Close()

	if err != nil {
		panic(err)
	}

	var row, col int
	fmt.Fscanf(file, "%d %d", &row, &col)
	maze := make([][]int, row)

	for i := range maze {
		maze[i] = make([]int, col)
		for j := range maze[i] {
			fmt.Fscanf(file, "%d", &maze[i][j])
		}
	}

	return maze
}

type point struct {
	i, j int
}

// 反轉slice
func reverse(lst []point) []point {
	newList := []point{}
	for index, _ := range lst {
		n := len(lst) - index - 1
		newList = append(newList, lst[n])
	}
	return newList
}

func isExist(lst []point, n point) error {
	for _, ex := range lst {
		if ex == n {
			return errors.New(" is exist!")
		}
	}
	return nil
}

// 移動步驟順序: 上、左、下、右
var direction = [4]point{
	{-1, 0}, {0, -1}, {1, 0}, {0, 1}}

// 執行上左下右移動操作
func (p point) move(r point) point {
	return point{p.i + r.i, p.j + r.j}
}

// 判斷移動之後的位置是否有越界或者撞牆
func (p point) at(grid [][]int) (int, error) {
	if p.i < 0 || p.i >= len(grid) {
		return 0, errors.New("raw out of range")
	}

	if p.j < 0 || p.j >= len(grid[0]) {
		return 0, errors.New("col out of range")
	}

	return grid[p.i][p.j], nil
}

func walk(maze [][]int, start, end point) []point {

	Q := []point{start}
	history := []point{start}
	search_path := []point{}

	for {
		// 此處的flag用於判斷當前的座標的下幾個步驟是否都是死路,如果有一個出口就標記為true,後面需要判斷死路使用
		flag := false

		now := Q[len(Q)-1]
		search_path = append(search_path, now)

		// 找到出口
		if now == end {
			break
		}

		for _, d := range direction {
			next := now.move(d)

			// 判斷下個點在前面沒有探測過, 避免重複探測
			if isExist(history, next) == nil {
				// 判斷移動沒有越界,而且沒有撞牆的話將下個點加入到佇列中
				val, err := next.at(maze)
				if err == nil && val != 1 {
					Q = append(Q, next)
					history = append(history, next)
					//fmt.Printf("now:%d, moveTo:%d, next:%d \n", now, d, next)
					flag = true
					continue
				}

			} else {
				//fmt.Println("3--> history is exist ", next)
			}
		}

		// 判斷當前座標移動的下一步都是是死路的時候刪除佇列中最後一個元素
		if flag == false && isExist(history, now) != nil {
			//fmt.Println("dead way", now)
			Q = Q[:len(Q)-1]
			search_path = search_path[:len(search_path)-1]
		}

	}

	return search_path
}

func main() {

	maze := readMazeFile("/Users/fanghongbo/CloudStation/go/goDemo/src/chapter09/maze.txt")
/* maze.txt的內容如下:
6 5
0 1 0 0 0
0 0 0 1 0
0 1 0 1 0
1 1 1 0 0
0 1 0 0 1
0 1 0 0 0
*/
	fmt.Printf("maze: \n\n")
	for i := range maze {
		for j := range maze[i] {
			fmt.Printf("%3d", maze[i][j])
		}
		fmt.Println()
	}
	fmt.Println()

	path := walk(maze, point{0, 0}, point{len(maze) - 1, len(maze[0]) - 1})
	fmt.Printf("最終路徑為:%d\n",path)
}