Skip to content

Commit 00f1554

Browse files
author
Michael Ye
committed
update readme
1 parent 5b3e4dc commit 00f1554

File tree

2 files changed

+247
-6
lines changed

2 files changed

+247
-6
lines changed

README.md

+12-6
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,18 @@ Much of the code is from RosettaCode and standard lib, and is referenced within
99
Examples are available inside the [examples folder](https://github.com/gophergala/go-algos/tree/master/examples)
1010

1111
## Table of Contents
12-
1. [Sorting](https://github.com/gophergala/go-algos#sorting)
13-
2. [Compression](https://github.com/gophergala/go-algos#compression)
14-
3. [Trees](https://github.com/gophergala/go-algos#trees)
15-
4. [Artificial Intelligence](https://github.com/gophergala/go-algos#artificial-intelligence)
16-
5. [Search](https://github.com/gophergala/go-algos#search)
17-
6. [Concurrency](https://github.com/gophergala/go-algos#concurrency)
12+
[Sorting](https://github.com/gophergala/go-algos#sorting)
13+
14+
[Compression](https://github.com/gophergala/go-algos#compression)
15+
16+
[Trees](https://github.com/gophergala/go-algos#trees)
17+
18+
[Artificial Intelligence](https://github.com/gophergala/go-algos#artificial-intelligence)
19+
20+
[Search](https://github.com/gophergala/go-algos#search)
21+
22+
[Concurrency](https://github.com/gophergala/go-algos#concurrency)
23+
1824

1925
## Sorting
2026
1. BubbleSort

search/astar.go

+235
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
// source: https://github.com/xarg/gopathfinding/blob/master/astar.go
2+
3+
//pathfinding package implements pathfinding algorithms such as Dijkstra and A*
4+
package search
5+
6+
import (
7+
"fmt"
8+
)
9+
10+
//Defining possible graph elements
11+
const (
12+
UNKNOWN int = iota - 1
13+
LAND
14+
WALL
15+
START
16+
STOP
17+
)
18+
19+
type MapData [][]int
20+
21+
//Return a new MapData by value given some dimensions
22+
func NewMapData(rows, cols int) *MapData {
23+
result := make(MapData, rows)
24+
for i := 0; i < rows; i++ {
25+
result[i] = make([]int, cols)
26+
}
27+
return &result
28+
}
29+
30+
//A node is just a set of x, y coordinates with a parent node and a
31+
//heuristic value H
32+
type Node struct {
33+
x, y int //Using int for efficiency
34+
parent *Node
35+
H int //Heuristic (aproximate distance)
36+
cost int //Path cost for this node
37+
}
38+
39+
//Create a new node
40+
func NewNode(x, y int) *Node {
41+
node := &Node{
42+
x: x,
43+
y: y,
44+
parent: nil,
45+
H: 0,
46+
cost: 0,
47+
}
48+
return node
49+
}
50+
51+
//Return string representation of the node
52+
func (self *Node) String() string {
53+
return fmt.Sprintf("<Node x:%d y:%d addr:%d>", self.x, self.y, &self)
54+
}
55+
56+
//Start, end nodes and a slice of nodes
57+
type Graph struct {
58+
start, stop *Node
59+
nodes []*Node
60+
data *MapData
61+
}
62+
63+
//Return a Graph from a map of coordinates (those that are passible)
64+
func NewGraph(map_data *MapData) *Graph {
65+
var start, stop *Node
66+
var nodes []*Node
67+
for i, row := range *map_data {
68+
for j, _type := range row {
69+
if _type == START || _type == STOP {
70+
node := NewNode(i, j)
71+
nodes = append(nodes, node)
72+
if _type == START {
73+
start = node
74+
}
75+
if _type == STOP {
76+
stop = node
77+
}
78+
}
79+
}
80+
}
81+
g := &Graph{
82+
nodes: nodes,
83+
start: start,
84+
stop: stop,
85+
data: map_data,
86+
}
87+
return g
88+
}
89+
90+
//Get *Node based on x, y coordinates.
91+
func (self *Graph) Node(x, y int) *Node {
92+
//Check if node is not already in the graph and append that node
93+
for _, n := range self.nodes {
94+
if n.x == x && n.y == y {
95+
return n
96+
}
97+
}
98+
map_data := *self.data
99+
if map_data[x][y] == LAND || map_data[x][y] == STOP {
100+
//Create a new node and add it to the graph
101+
n := NewNode(x, y)
102+
self.nodes = append(self.nodes, n)
103+
return n
104+
}
105+
return nil
106+
}
107+
108+
//Get the nodes near some node
109+
func (self *Graph) adjacentNodes(node *Node) []*Node {
110+
var result []*Node
111+
map_data := *self.data
112+
rows := len(map_data)
113+
cols := len(map_data[0])
114+
115+
//If the coordinates are passable then create a new node and add it
116+
if node.x <= rows && node.y+1 < cols {
117+
if new_node := self.Node(node.x, node.y+1); new_node != nil {
118+
result = append(result, new_node)
119+
}
120+
}
121+
if node.x <= rows && node.y-1 >= 0 {
122+
new_node := self.Node(node.x, node.y-1)
123+
if new_node != nil {
124+
result = append(result, new_node)
125+
}
126+
}
127+
if node.y <= cols && node.x+1 < rows {
128+
new_node := self.Node(node.x+1, node.y)
129+
if new_node != nil {
130+
result = append(result, new_node)
131+
}
132+
}
133+
if node.y <= cols && node.x-1 >= 0 {
134+
new_node := self.Node(node.x-1, node.y)
135+
if new_node != nil {
136+
result = append(result, new_node)
137+
}
138+
}
139+
return result
140+
}
141+
142+
func abs(x int) int {
143+
if x < 0 {
144+
return -x
145+
}
146+
return x
147+
}
148+
149+
func removeNode(nodes []*Node, node *Node) []*Node {
150+
ith := -1
151+
for i, n := range nodes {
152+
if n == node {
153+
ith = i
154+
break
155+
}
156+
}
157+
if ith != -1 {
158+
copy(nodes[ith:], nodes[ith+1:])
159+
nodes = nodes[:len(nodes)-1]
160+
}
161+
return nodes
162+
}
163+
164+
func hasNode(nodes []*Node, node *Node) bool {
165+
for _, n := range nodes {
166+
if n == node {
167+
return true
168+
}
169+
}
170+
return false
171+
}
172+
173+
//Return the node with the minimum H
174+
func minH(nodes []*Node) *Node {
175+
if len(nodes) == 0 {
176+
return nil
177+
}
178+
result_node := nodes[0]
179+
minH := result_node.H
180+
for _, node := range nodes {
181+
if node.H < minH {
182+
minH = node.H
183+
result_node = node
184+
}
185+
}
186+
return result_node
187+
}
188+
189+
func retracePath(current_node *Node) []*Node {
190+
var path []*Node
191+
path = append(path, current_node)
192+
for current_node.parent != nil {
193+
path = append(path, current_node.parent)
194+
current_node = current_node.parent
195+
}
196+
//Reverse path
197+
for i, j := 0, len(path)-1; i < j; i, j = i+1, j-1 {
198+
path[i], path[j] = path[j], path[i]
199+
}
200+
return path
201+
}
202+
203+
// In our particular case: Manhatan distance
204+
func Heuristic(graph *Graph, tile *Node) int {
205+
return abs(graph.stop.x-tile.x) + abs(graph.stop.y-tile.y)
206+
}
207+
208+
//A* search algorithm. See http://en.wikipedia.org/wiki/A*_search_algorithm
209+
func Astar(graph *Graph) []*Node {
210+
var path, openSet, closedSet []*Node
211+
212+
openSet = append(openSet, graph.start)
213+
for len(openSet) != 0 {
214+
//Get the node with the min H
215+
current := minH(openSet)
216+
if current.parent != nil {
217+
current.cost = current.parent.cost + 1
218+
}
219+
if current == graph.stop {
220+
return retracePath(current)
221+
}
222+
openSet = removeNode(openSet, current)
223+
closedSet = append(closedSet, current)
224+
for _, tile := range graph.adjacentNodes(current) {
225+
if tile != nil && graph.stop != nil && !hasNode(closedSet, tile) {
226+
tile.H = Heuristic(graph, tile) + current.cost
227+
if !hasNode(openSet, tile) {
228+
openSet = append(openSet, tile)
229+
}
230+
tile.parent = current
231+
}
232+
}
233+
}
234+
return path
235+
}

0 commit comments

Comments
 (0)