返回顶部
扩大
缩小

人外有人天外有天

Go 迷宫算法

首先读取一个迷宫文件maze.in (第一行是文件的行列  下面是文件内容:1表示墙 0表示此路可走)

如何读取?

//读取一个二维数组 
func readMaze(filename string) [][]int {
    // 先打开文件 默认是已经存在这个文件 故没有做其他出错处理
    file, err := os.Open(filename)  
    if err != nil {
        panic(err)
    }
    //需要先将行、列读出来 利用Fscanf读取
    var row, col int
    fmt.Fscanf(file, "%d %d", &row, &col)
    //创建二维slice 注意:这里是传入参数行row 因为二维数组其实就是:有row这么多一维数组构成 这里是使用切片
    maze := make([][]int, row)
    for i := range maze {
        maze[i] = make([]int, col)  //利用make创建
        for j := range maze[i] {
            fmt.Fscanf(file, "%d", &maze[i][j])
        }
    }
    return maze
}

func main() {
    maze := readMaze("mazepractice/maze.in")
    for _,row := range maze {
        for _,val := range row {
            fmt.Printf("%3d",val)
        }
        fmt.Println()
    }
}

 迷宫算法解读

package main

import (
    "fmt"
    "os"
)

func readMaze(filename string) [][]int {
    file, err := os.Open(filename)
    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
}
// 定义点的结构体 因为这里是数组 最好不要用x,y定义(以免自己与坐标混淆)
type point struct {
    i, j int
}
// 定义4个方向分别是:上 左 下 右 方向
var dirs = [4]point{
    {-1, 0}, {0, -1}, {1, 0}, {0, 1}}
// 走迷宫需要从上左下右方向去走,因此坐标会相应的变化  注:这里是利用返回一个新的point 而不是利用指针(当然,指针也可以)
func (p point) add(r point) point {
    return point{p.i + r.i, p.j + r.j}
}
//判断走的点是不是合理的 有没越界  返回值是点和一个状态值
func (p point) at(grid [][]int) (int, bool) {
    if p.i < 0 || p.i >= len(grid) {
        return 0, false
    }

    if p.j < 0 || p.j >= len(grid[p.i]) {
        return 0, false
    }

    return grid[p.i][p.j], true
}
// 走迷宫的关键算法 通过传入3个参数:二维切片,开始点,结束点  返回的是:一个二维切片
func walk(maze [][]int, start, end point) [][]int {
    // 这里其实是创建一个走过路线的steps 根据我们读取的文件maze.in规格大小来创建
    steps := make([][]int, len(maze))
    for i := range steps {
        steps[i] = make([]int, len(maze[i]))
    }
    // 创建一个队列 开始点是(0,0)
    Q := []point{start}
    // 队列不空
    for len(Q) > 0 {
        cur := Q[0]  //cur代表队列开始点(0,0)
        Q = Q[1:]    //去掉队列第一个点
        // 发现终点 退出
        if cur == end {
            break
        }
       // 没有走到的请看
        for _, dir := range dirs {
            // 通过上 左 下 右 走这些路
            next := cur.add(dir)
            // 判断走的路线是不是可以走:0 可以走  1 不可以走  当然越界也是不行的
            val, ok := next.at(maze)
            if !ok || val == 1 {
                continue
            }
            // 判断这些点有没有走过:就是不要走回头路
            val, ok = next.at(steps)
            if !ok || val != 0 {
                continue
            }
            // 不是0 可能回到起点 不行的
            if next == start {
                continue
            }
            // 当前的步骤数
            curSteps, _ := cur.at(steps)
            steps[next.i][next.j] = curSteps + 1
            // 把这个放在队列的后面
            Q = append(Q, next)
        }
    }

    return steps
}

func main() {
    maze := readMaze("mazepractice/maze.in")
    steps := walk(maze, point{0, 0}, point{len(maze) - 1, len(maze[0]) - 1})
    // 打印实际走的这个数组
    for _, row := range steps {
        for _, val := range row {
            fmt.Printf("%3d", val)
        }
        fmt.Println()
    }
    lessStep := steps[len(maze)-1][len(maze[0])-1]
    fmt.Printf("这个迷宫最少需要%d步走完",lessStep)
    // TODO: construct path from steps

}

 左边是读取的文件,右边是输出结果:

 

 左边是读取的文件,右边是输出结果:

 

posted on 2018-07-31 19:51  笔记是研究的开始  阅读(309)  评论(0编辑  收藏  举报

导航