用GOLANG实现了一个走迷宫程序

GOALGN实现的一个走迷宫程序,用到广度优先和深度优先算法。

首先从filename指定的文件读取地图,文件中第一行的两个数表示地图的行数,列数;第二行前面两个坐标表示起点和终点,括号不要去改,改数字就行了。后边是地图。

比如有如下地图:

6 5
(0, 0) (5, 4)
0 1 0 0 0
0 0 0 1 0
0 1 0 1 0
1 1 1 0 0
0 1 0 0 0
0 1 0 0 0

运行程序后输出如下:

Got a map from file:maze_map.in
  0  1  0  0  0
  0  0  0  1  0
  0  1  0  1  0
  1  1  1  0  0
  0  1  0  0  0
  0  1  0  0  0
Find the end point:
  0  0  4  5  6
  1  2  3  0  7
  2  0  4  0  8
  0  0  0 10  9
  0  0 12 11 10
  0  0  0 12 11
The path is :
{0 0} {1 0} {1 1} {1 2} {0 2} {0 3} {0 4} {1 4} {2 4} {3 4} {4 4} {5 4} 
Picture:
  *  0  *  *  *
  *  *  *  0  *
  2  0  4  0  *
  0  0  0 10  *
  0  0 12 11  *
  0  0  0 12  *

Process finished with exit code 0

代码如下,因为只是练习,就先不考虑设计模式和分package了。代码和filename指定的地图在同一个目录下面。

package main

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

//struct of point
type Point struct {
	i, j int
}
//struct of maze
type Maze struct {
	root [][]int
	row, col int
}
//direction of a point
var dir = [...]Point{
	{-1,0},  //up
	{0, -1}, //left
	{1, 0},  //down
	{0, 1},  //right
}
var (
	startPoint Point = Point{i:0, j:0}
	endPoint Point = Point{i:0, j:0}
)
// map information read from filename
const filename = "maze_map.in"

func main() {
	// read maze map from filename
	maze := readMazeFromFile(filename)
	footPrint, err := walkMaze( maze, startPoint, endPoint )
	if err != nil {
		fmt.Println(err.Error())
		footPrint.Show()
		return
	}
	fmt.Println("Find the end point:")
	footPrint.Show()
	footPrint.printThePath(startPoint, endPoint)
}
/** method of Point *****/
func (p Point)add(point Point) Point  {
	return Point{p.i + point.i, p.j + point.j}
}
/***********************/

/** method of Maze *****/
func (maze * Maze)Visitable(tryPoint Point, targetValue int ) bool {
	if tryPoint.i < 0 || tryPoint.j < 0 || tryPoint.i >= maze.row || tryPoint.j >= maze.col {
		return false
	}
	if maze.root[tryPoint.i][tryPoint.j] == targetValue {
		return true
	} else {
		return false
	}
}

func (maze * Maze)Show()  {
	for i := range maze.root {
		for j := range maze.root[i] {
			fmt.Printf("%3d", maze.root[i][j])
		}
		fmt.Println()
	}
}

func (maze * Maze)printThePath(start, end Point)  {
	var steps []Point

	//find from end point
	steps = append(steps, end)
	//start point is the target point
	var ok bool
	if steps, ok = maze.dfsMaze(steps, start); !ok {
		fmt.Println("cannot found the path from the start point")
		return
	}
	fmt.Println("The path is :")
	sLen := len(steps)
	var cur Point
	for i := sLen - 1; i >= 0; i-- {
		cur = steps[i]
		fmt.Printf("%v ", cur)
		maze.root[cur.i][cur.j] = -1
	}
	fmt.Println("\nPicture:")
	for i := range maze.root {
		for j := range maze.root[i] {
			if maze.root[i][j] == -1 {
				fmt.Printf("  *", )
			} else {
				fmt.Printf("%3d", maze.root[i][j])
			}
		}
		fmt.Println()
	}
}

func (maze * Maze)dfsMaze(steps []Point, end Point) ([]Point, bool) {
	var tryPoint, cur Point
	stepsLen := len(steps)
	//peak last Point
	cur = steps[stepsLen-1]

	if cur == end {
		//the end point
		return steps, true
	}

	for _, tmpPoint := range dir {
		tryPoint = cur.add(tmpPoint)
		if maze.Visitable(tryPoint, maze.root[cur.i][cur.j] - 1) {
			steps = append(steps, tryPoint)
			var ok bool
			if steps ,ok = maze.dfsMaze(steps, end); ok {
				return steps, true
			} else {//pop this point
				steps = steps[0:len(steps)-1]
			}
		}
	}

	return steps, false
}

func (maze * Maze)setVisited(tryPoint Point )  {
	maze.root[tryPoint.i][tryPoint.j] = 2
}
func (maze * Maze)stepMark(cur, tryPoint Point) (int, error)  {
	curStep,err := maze.stepAt(cur)
	if err != nil {
		log.Printf("Got an bad point in maze.stepAt: %v, %s", cur, err.Error())
		return 0, err
	}
	maze.root[tryPoint.i][tryPoint.j] = curStep + 1

	return curStep + 1, nil
}
func (maze * Maze)stepAt(dstPoint Point ) (int, error) {
	if dstPoint.i < 0 || dstPoint.j < 0 || dstPoint.i >= maze.row || dstPoint.j >= maze.col {
		return 0, errors.New("point out of maze range")
	}
	return maze.root[dstPoint.i][dstPoint.j], nil
}

func walkMaze(maze * Maze, start, end Point ) (* Maze, error)  {
	var footPrint Maze
	footPrint.row = maze.row
	footPrint.col = maze.col
	footPrint.root = make([][]int, footPrint.row)
	for i := range footPrint.root {
		footPrint.root[i] = make([]int, footPrint.col)
	}

	step := make([]Point, 0)
	step = append(step, start)
	var tryPoint Point
	for len(step) != 0 {
		me := step[0]

		if me == end {
			//me is the end point
			return &footPrint, nil
		}
		//find and append the visitable point into Q
		for _, tmpPoint := range dir {
			tryPoint = me.add(tmpPoint)
			if maze.Visitable(tryPoint, 0) {
				// appen this tryPoint to Q
				step = append(step, tryPoint)
				//reject double add to Q
				maze.root[tryPoint.i][tryPoint.j] = 3
				// mark this point in footPrint base cur stepNum
				footPrint.stepMark(me, tryPoint)
			}
		}
		maze.setVisited(me)
		step = step[1:]
	}

	return &footPrint, errors.New("can not get to the target point")
}
/***********************/

func readMazeFromFile(filename string)  * Maze {
	var (
		err error
	    maze Maze
		file *os.File
	)
	file, err = os.Open(filename)
	if err != nil {
		fmt.Println("Open file failed:",filename )
		panic(err.Error())
	}
	defer file.Close()

	_, err = fmt.Fscanf(file, "%d %d\n", &maze.row, &maze.col)
	if err != nil {
		fmt.Printf("Read row and col form %s failed\n",filename )
		panic(err.Error())
	}
	//get start and end point
	_, err = fmt.Fscanf(file, "(%d, %d) (%d, %d)",
								&startPoint.i, &startPoint.j,
								&endPoint.i, &endPoint.j)
	if err != nil {
		fmt.Printf("Read start and end point from %s failed\n",filename )
		panic(err.Error())
	}
	fmt.Fscanln(file) //eat the '\n'

	maze.root = make([][]int, maze.row)
	for i :=  range maze.root {
		maze.root[i] = make([]int, maze.col)
		for j := range maze.root[i] {
			fmt.Fscanf(file, "%d", &maze.root[i][j] )
		}
		fmt.Fscanln(file) //eat the '\n'
	}
	fmt.Printf("Got a map from file:%s\n", filename)
	maze.Show()

	return &maze
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值