標籤:ret 混淆 bubuko 檔案的 str col fun dir walk
首先讀取一個迷宮檔案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 mainimport ( "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}
左邊是讀取的檔案,右邊是輸出結果:
左邊是讀取的檔案,右邊是輸出結果:
Go 迷宮演算法