{"id":17217831,"url":"https://github.com/fzipp/astar","last_synced_at":"2025-04-13T22:31:23.710Z","repository":{"id":11372667,"uuid":"13810049","full_name":"fzipp/astar","owner":"fzipp","description":"Package astar implements the A* search algorithm for finding least-cost paths.","archived":false,"fork":false,"pushed_at":"2024-08-14T05:15:39.000Z","size":151,"stargazers_count":25,"open_issues_count":0,"forks_count":4,"subscribers_count":4,"default_branch":"main","last_synced_at":"2024-08-19T21:14:06.965Z","etag":null,"topics":["algorithm","astar-algorithm","go","golang","graph","least-cost-paths","pathfinding","search-algorithm","shortest-path"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fzipp.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2013-10-23T17:44:51.000Z","updated_at":"2024-08-14T05:15:42.000Z","dependencies_parsed_at":"2024-06-19T03:04:21.926Z","dependency_job_id":"e8168bde-6c69-49c7-b982-e7b37077aed9","html_url":"https://github.com/fzipp/astar","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fzipp%2Fastar","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fzipp%2Fastar/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fzipp%2Fastar/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fzipp%2Fastar/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fzipp","download_url":"https://codeload.github.com/fzipp/astar/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":219845257,"owners_count":16556449,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["algorithm","astar-algorithm","go","golang","graph","least-cost-paths","pathfinding","search-algorithm","shortest-path"],"created_at":"2024-10-15T03:44:48.105Z","updated_at":"2024-10-15T03:44:48.197Z","avatar_url":"https://github.com/fzipp.png","language":"Go","readme":"# astar\n\n[![PkgGoDev](https://pkg.go.dev/badge/github.com/fzipp/astar)](https://pkg.go.dev/github.com/fzipp/astar)\n![Build Status](https://github.com/fzipp/astar/workflows/build/badge.svg)\n[![Go Report Card](https://goreportcard.com/badge/github.com/fzipp/astar)](https://goreportcard.com/report/github.com/fzipp/astar)\n\nPackage astar implements the\n[A* search algorithm](https://en.wikipedia.org/wiki/A*_search_algorithm)\nfor finding least-cost paths.\n\n## Examples\n\nIn order to use the `astar.FindPath` function to find the least-cost path\nbetween two nodes of a graph you need a graph data structure that implements\nthe `Neighbours` method to satisfy the `astar.Graph[Node]` interface and a\ncost function. It is up to you how the graph is internally implemented.\n\n### A maze\n\nIn this example the graph is represented by a slice of strings, each character\nrepresenting a cell of a floor plan. Graph nodes are cell positions\nas `image.Point` values, with (0, 0) in the upper left corner. \nSpaces represent free cells available for walking, other characters like\n`#` represent walls.\nThe `Neighbours` method returns the positions of the adjacent free cells\nto the north, east, south, and west of a given position (diagonal movement\nis not allowed in this example).\n\nThe cost function `nodeDist` simply calculates the Euclidean distance\nbetween two cell positions.\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"image\"\n\t\"iter\"\n\t\"math\"\n\n\t\"github.com/fzipp/astar\"\n)\n\nfunc main() {\n\tmaze := floorPlan{\n\t\t\"###############\",\n\t\t\"#   # #     # #\",\n\t\t\"# ### ### ### #\",\n\t\t\"#   # # #   # #\",\n\t\t\"### # # # ### #\",\n\t\t\"# # #         #\",\n\t\t\"# # ### ### ###\",\n\t\t\"#   # # # #   #\",\n\t\t\"### # # # # ###\",\n\t\t\"# #       # # #\",\n\t\t\"# # ######### #\",\n\t\t\"#         #   #\",\n\t\t\"# ### # # ### #\",\n\t\t\"#   # # #     #\",\n\t\t\"###############\",\n\t}\n\tstart := image.Pt(1, 13) // Bottom left corner\n\tdest := image.Pt(13, 1)  // Top right corner\n\n\t// Find the shortest path\n\tpath := astar.FindPath[image.Point](maze, start, dest, nodeDist, nodeDist)\n\n\t// Mark the path with dots before printing\n\tfor _, p := range path {\n\t\tmaze.put(p, '.')\n\t}\n\tmaze.print()\n}\n\n// nodeDist is our cost function. We use points as nodes, so we\n// calculate their Euclidean distance.\nfunc nodeDist(p, q image.Point) float64 {\n\td := q.Sub(p)\n\treturn math.Sqrt(float64(d.X*d.X + d.Y*d.Y))\n}\n\ntype floorPlan []string\n\nvar offsets = [...]image.Point{\n\timage.Pt(0, -1), // North\n\timage.Pt(1, 0),  // East\n\timage.Pt(0, 1),  // South\n\timage.Pt(-1, 0), // West\n}\n\n// Neighbours implements the astar.Graph[Node] interface (with Node = image.Point).\nfunc (f floorPlan) Neighbours(p image.Point) iter.Seq[image.Point] {\n\treturn func(yield func(image.Point) bool) {\n\t\tfor _, off := range offsets {\n\t\t\tq := p.Add(off)\n\t\t\tif f.isFreeAt(q) {\n\t\t\t\tif !yield(q) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (f floorPlan) isFreeAt(p image.Point) bool {\n\treturn f.isInBounds(p) \u0026\u0026 f[p.Y][p.X] == ' '\n}\n\nfunc (f floorPlan) isInBounds(p image.Point) bool {\n\treturn (0 \u003c= p.X \u0026\u0026 p.X \u003c len(f[p.Y])) \u0026\u0026 (0 \u003c= p.Y \u0026\u0026 p.Y \u003c len(f))\n}\n\nfunc (f floorPlan) put(p image.Point, c rune) {\n\tf[p.Y] = f[p.Y][:p.X] + string(c) + f[p.Y][p.X+1:]\n}\n\nfunc (f floorPlan) print() {\n\tfor _, row := range f {\n\t\tfmt.Println(row)\n\t}\n}\n```\n\nOutput:\n\n```\n###############\n#   # #     #.#\n# ### ### ###.#\n#   # # #   #.#\n### # # # ###.#\n# # #  .......#\n# # ###.### ###\n#   # #.# #   #\n### # #.# # ###\n# #.....  # # #\n# #.######### #\n#...      #   #\n#.### # # ### #\n#.  # # #     #\n###############\n```\n\n### 2D points as nodes\n\nIn this example the graph is represented by an adjacency list. Nodes are\n2D points in Euclidean space as `image.Point` values. The `link` function\ncreates a bi-directed edge between a pair of nodes.\n\nThe cost function `nodeDist` calculates the Euclidean distance\nbetween two points (nodes).\n\n![Example graph with shortst path](doc/example1.png?raw=true)\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"image\"\n\t\"iter\"\n\t\"math\"\n\t\"slices\"\n\n\t\"github.com/fzipp/astar\"\n)\n\nfunc main() { \n\t// Create a graph with 2D points as nodes\n\tp1 := image.Pt(3, 1)\n\tp2 := image.Pt(1, 2)\n\tp3 := image.Pt(2, 4)\n\tp4 := image.Pt(4, 5)\n\tp5 := image.Pt(4, 3)\n\tp6 := image.Pt(5, 1)\n\tp7 := image.Pt(8, 4)\n\tp8 := image.Pt(8, 3)\n\tp9 := image.Pt(6, 3)\n\tg := newGraph[image.Point]().\n\t\tlink(p1, p2).link(p1, p3).\n\t\tlink(p2, p3).link(p2, p4).\n\t\tlink(p3, p4).link(p3, p5).\n\t\tlink(p4, p6).link(p4, p7).\n\t\tlink(p5, p7).\n\t\tlink(p6, p9).\n\t\tlink(p7, p8).\n\t\tlink(p8, p9)\n\n\t// Find the shortest path from p1 to p9\n\tp := astar.FindPath[image.Point](g, p1, p9, nodeDist, nodeDist)\n\n\t// Output the result\n\tif p == nil {\n\t\tfmt.Println(\"No path found.\")\n\t\treturn\n\t}\n\tfor i, n := range p {\n\t\tfmt.Printf(\"%d: %s\\n\", i, n)\n\t}\n}\n\n// nodeDist is our cost function. We use points as nodes, so we\n// calculate their Euclidean distance.\nfunc nodeDist(p, q image.Point) float64 {\n\td := q.Sub(p)\n\treturn math.Sqrt(float64(d.X*d.X + d.Y*d.Y))\n}\n\n// graph is represented by an adjacency list.\ntype graph[Node comparable] map[Node][]Node\n\nfunc newGraph[Node comparable]() graph[Node] {\n\treturn make(map[Node][]Node)\n}\n\n// link creates a bi-directed edge between nodes a and b.\nfunc (g graph[Node]) link(a, b Node) graph[Node] {\n\tg[a] = append(g[a], b)\n\tg[b] = append(g[b], a)\n\treturn g\n}\n\n// Neighbours returns the neighbour nodes of node n in the graph.\nfunc (g graph[Node]) Neighbours(n Node) iter.Seq[Node] {\n\treturn slices.Values(g[n])\n}\n```\n\nOutput:\n\n```\n0: (3,1)\n1: (2,4)\n2: (4,5)\n3: (5,1)\n4: (6,3)\n```\n\n## License\n\nThis project is free and open source software licensed under the\n[BSD 3-Clause License](LICENSE).\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffzipp%2Fastar","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffzipp%2Fastar","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffzipp%2Fastar/lists"}