A_star_algorithm.sf 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. #!/usr/bin/ruby
  2. #
  3. ## https://rosettacode.org/wiki/A*_search_algorithm
  4. #
  5. class AStarGraph {
  6. has barriers = [
  7. [2,4],[2,5],[2,6],[3,6],[4,6],[5,6],[5,5],[5,4],[5,3],[5,2],[4,2],[3,2]
  8. ]
  9. method heuristic(start, goal) {
  10. var (D1 = 1, D2 = 1)
  11. var dx = abs(start[0] - goal[0])
  12. var dy = abs(start[1] - goal[1])
  13. (D1 * (dx + dy)) + ((D2 - 2*D1) * Math.min(dx, dy))
  14. }
  15. method get_vertex_neighbours(pos) {
  16. gather {
  17. for dx, dy in [[1,0],[-1,0],[0,1],[0,-1],[1,1],[-1,1],[1,-1],[-1,-1]] {
  18. var x2 = (pos[0] + dx)
  19. var y2 = (pos[1] + dy)
  20. (x2<0 || x2>7 || y2<0 || y2>7) && next
  21. take([x2, y2])
  22. }
  23. }
  24. }
  25. method move_cost(_a, b) {
  26. barriers.contains(b) ? 100 : 1
  27. }
  28. }
  29. func AStarSearch(start, end, graph) {
  30. var G = Hash()
  31. var F = Hash()
  32. G{start} = 0
  33. F{start} = graph.heuristic(start, end)
  34. var closedVertices = []
  35. var openVertices = [start]
  36. var cameFrom = Hash()
  37. while (openVertices) {
  38. var current = nil
  39. var currentFscore = Inf
  40. for pos in openVertices {
  41. if (F{pos} < currentFscore) {
  42. currentFscore = F{pos}
  43. current = pos
  44. }
  45. }
  46. if (current == end) {
  47. var path = [current]
  48. while (cameFrom.contains(current)) {
  49. current = cameFrom{current}
  50. path << current
  51. }
  52. path.flip!
  53. return (path, F{end})
  54. }
  55. openVertices.remove(current)
  56. closedVertices.append(current)
  57. for neighbour in (graph.get_vertex_neighbours(current)) {
  58. if (closedVertices.contains(neighbour)) {
  59. next
  60. }
  61. var candidateG = (G{current} + graph.move_cost(current, neighbour))
  62. if (!openVertices.contains(neighbour)) {
  63. openVertices.append(neighbour)
  64. }
  65. elsif (candidateG >= G{neighbour}) {
  66. next
  67. }
  68. cameFrom{neighbour} = current
  69. G{neighbour} = candidateG
  70. var H = graph.heuristic(neighbour, end)
  71. F{neighbour} = (G{neighbour} + H)
  72. }
  73. }
  74. die "A* failed to find a solution"
  75. }
  76. var graph = AStarGraph()
  77. var (route, cost) = AStarSearch([0,0], [7,7], graph)
  78. var w = 10
  79. var h = 10
  80. var grid = h.of { w.of { "." } }
  81. for y in (^h) { grid[y][0] = "█"; grid[y][-1] = "█" }
  82. for x in (^w) { grid[0][x] = "█"; grid[-1][x] = "█" }
  83. for x,y in (graph.barriers) { grid[x+1][y+1] = "█" }
  84. for x,y in (route) { grid[x+1][y+1] = "x" }
  85. grid.each { .join.say }
  86. say "Path cost #{cost}: #{route}"
  87. assert_eq(route, [[0, 0], [1, 1], [2, 2], [3, 1], [4, 1], [5, 1], [6, 2], [6, 3], [6, 4], [6, 5], [6, 6], [7, 7]])