-
Notifications
You must be signed in to change notification settings - Fork 0
/
maze.go
131 lines (116 loc) · 3.24 KB
/
maze.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
package main
import (
"errors"
"image"
"image/color"
"math/rand"
)
type Position struct {
x int
y int
}
type Maze struct {
cells [][]Cell
}
//Represent a cell of a maze. True for top,left,right,bottom means open in this direction
type Cell struct {
top bool
left bool
right bool
bottom bool
visited bool
}
func (maze Maze) Size() (int, int) {
dx := 0
dy := 0
for i, cols := range maze.cells {
dy = len(cols)
dx = i + 1
}
return dx, dy
}
//Return a a random unvisited neighbour Cell in the Maze.
//Return Error, if there are no unvisited Cells remain.
func (current Position) RollUnvisitedNeighbour(maze Maze) (Position, error) {
candidates := make([]Position, 0)
candidates = appendIfValidUnvisited(candidates, Position{current.x, current.y - 1}, maze)
candidates = appendIfValidUnvisited(candidates, Position{current.x - 1, current.y}, maze)
candidates = appendIfValidUnvisited(candidates, Position{current.x + 1, current.y}, maze)
candidates = appendIfValidUnvisited(candidates, Position{current.x, current.y + 1}, maze)
if len(candidates) == 0 {
return Position{}, errors.New("no unvisited remain")
} else {
return candidates[rand.Intn(len(candidates))], nil
}
}
func appendIfValidUnvisited(candidates []Position, candidate Position, maze Maze) []Position {
xMax, yMax := maze.Size()
inBounds := candidate.x < xMax && candidate.x >= 0 && candidate.y < yMax && candidate.y >= 0
if inBounds && !maze.cells[candidate.x][candidate.y].visited {
return append(candidates, candidate)
} else {
return candidates
}
}
//Positions are not allowed to be out of the bounds of the maze
func (maze Maze) RemoveWalls(curr Position, neighb Position) error {
if curr.x == neighb.x {
//vertikal
if curr.y > neighb.y {
maze.cells[curr.x][curr.y].top = true
maze.cells[neighb.x][neighb.y].bottom = true
} else {
maze.cells[curr.x][curr.y].bottom = true
maze.cells[neighb.x][neighb.y].top = true
}
} else {
if curr.x > neighb.x {
maze.cells[curr.x][curr.y].left = true
maze.cells[neighb.x][neighb.y].right = true
} else {
maze.cells[curr.x][curr.y].right = true
maze.cells[neighb.x][neighb.y].left = true
}
}
return nil
}
func CreateMaze(dx int, dy int) Maze {
maze := make([][]Cell, dx)
for i := range maze {
maze[i] = make([]Cell, dy)
}
return Maze{cells: maze}
}
//Visualize a Maze with each Cell as its 3x3 px representation
func (maze Maze) Visualize() image.Image {
dx, dy := maze.Size()
img := image.NewGray(image.Rect(0, 0, dx*3, dy*3))
for i := 0; i < dx; i++ {
for j := 0; j < dy; j++ {
cell := maze.cells[i][j]
//Render 1 particular Cell as 3x3 pixel representation
//TOP Line
imageX := i * 3
imageY := j * 3
img.Set(imageX, imageY, color.Black)
img.Set(imageX+1, imageY, whiteIf(cell.top))
img.Set(imageX+2, imageY, color.Black)
//Middle Line
img.Set(imageX, imageY+1, whiteIf(cell.left))
img.Set(imageX+1, imageY+1, color.White)
img.Set(imageX+2, imageY+1, whiteIf(cell.right))
//Bottom Line
img.Set(imageX, imageY+2, color.Black)
img.Set(imageX+1, imageY+2, whiteIf(cell.bottom))
img.Set(imageX+2, imageY+2, color.Black)
}
}
return img
}
func whiteIf(direction bool) color.Color {
if direction {
return color.White
} else {
return color.Black
}
}