A* Algorithmus

  • Excel

    A* Algorithmus

    Hiho

    Ich habe mal den A* Algorithmus in Excel mit VBA realisiert.

    Ich denke es ist noch nicht perfekt, aber ich denke man kann damit arbeiten.

    Visual Basic-Quellcode

    1. Option Explicit
    2. Dim StartPoint As KoordPoint
    3. Dim ZielPoint As KoordPoint
    4. Dim openlist As Collection
    5. Dim closedList As Collection
    6. Dim wks As Worksheet
    7. Dim minX As Integer
    8. Dim maxX As Integer
    9. Dim minY As Integer
    10. Dim maxY As Integer
    11. Public Sub calc_click()
    12. Set wks = Application.Worksheets(1)
    13. Set openlist = New Collection
    14. Set closedList = New Collection
    15. minX = 2
    16. maxX = 51
    17. minY = 2
    18. maxY = 51
    19. Set StartPoint = New KoordPoint
    20. If wks.Cells(1, 1) < minY Then
    21. StartPoint.setY (minY)
    22. ElseIf wks.Cells(1, 1) > maxY Then
    23. StartPoint.setY (maxY)
    24. Else
    25. StartPoint.setY (wks.Cells(1, 1))
    26. End If
    27. If wks.Cells(1, 2) < minX Then
    28. StartPoint.setX (minX)
    29. ElseIf wks.Cells(1, 2) > maxX Then
    30. StartPoint.setX (maxX)
    31. Else
    32. StartPoint.setX (wks.Cells(1, 2))
    33. End If
    34. StartPoint.setG (0)
    35. openlist.Add StartPoint
    36. Set ZielPoint = New KoordPoint
    37. If wks.Cells(1, 3) < minY Then
    38. ZielPoint.setY (minY)
    39. ElseIf wks.Cells(1, 3) > maxY Then
    40. ZielPoint.setY (maxY)
    41. Else
    42. ZielPoint.setY (wks.Cells(1, 3))
    43. End If
    44. If wks.Cells(1, 4) < minX Then
    45. ZielPoint.setX (minX)
    46. ElseIf wks.Cells(1, 4) > maxX Then
    47. ZielPoint.setX (maxX)
    48. Else
    49. ZielPoint.setX (wks.Cells(1, 4))
    50. End If
    51. Call prepare
    52. If FindPath Then
    53. Call PaintPath
    54. End If
    55. End Sub
    56. Private Function FindPath() As Boolean
    57. Dim AktPoint As KoordPoint
    58. Dim i As Integer
    59. Dim j As Integer
    60. Dim x As Integer
    61. Dim y As Integer
    62. Dim index As Integer
    63. Dim runner As Integer
    64. Dim found As Boolean
    65. found = False
    66. Set AktPoint = openlist.Item(1)
    67. index = 1
    68. runner = 0
    69. Do
    70. j = openlist.Count
    71. For i = 1 To j
    72. If AktPoint Is Nothing = True Then
    73. Set AktPoint = openlist.Item(i)
    74. index = i
    75. ElseIf AktPoint.getF > openlist.Item(i).getF Then
    76. Set AktPoint = openlist.Item(i)
    77. index = i
    78. End If
    79. Next i
    80. openlist.Remove (index)
    81. closedList.Add AktPoint
    82. Call getNeighborPoints(AktPoint)
    83. Set AktPoint = Nothing
    84. If isZielInOpenList Then
    85. found = True
    86. Exit Do
    87. End If
    88. runner = runner + 1
    89. Loop While Not openlist.Count = 0 And runner < 1000
    90. FindPath = found
    91. End Function
    92. Private Function rateCosts(inX As Integer, inY As Integer) As Integer
    93. Dim costs As Integer
    94. Dim x As Integer
    95. Dim y As Integer
    96. x = inX
    97. y = inY
    98. costs = 0
    99. Do While (x > ZielPoint.getX())
    100. costs = costs + 10
    101. x = x - 1
    102. Loop
    103. Do While (x < ZielPoint.getX())
    104. costs = costs + 10
    105. x = x + 1
    106. Loop
    107. Do While (y > ZielPoint.getY())
    108. costs = costs + 10
    109. y = y - 1
    110. Loop
    111. Do While (y < ZielPoint.getY())
    112. costs = costs + 10
    113. y = y + 1
    114. Loop
    115. rateCosts = costs
    116. End Function
    117. Private Function calcCosts(PointA As KoordPoint, PointB As KoordPoint) As Double
    118. Dim costs As Double
    119. Dim ax As Integer
    120. Dim ay As Integer
    121. Dim bx As Integer
    122. Dim by As Integer
    123. costs = 0
    124. ax = PointA.getX()
    125. ay = PointA.getY()
    126. bx = PointB.getX()
    127. by = PointB.getY()
    128. Do While ax < bx And ay < by
    129. costs = costs + Sqr(20)
    130. ax = ax + 1
    131. ay = ay + 1
    132. Loop
    133. Do While ax > bx And ay > by
    134. costs = costs + Sqr(20)
    135. ax = ax - 1
    136. ay = ay - 1
    137. Loop
    138. Do While ax < bx And ay > by
    139. costs = costs + Sqr(20)
    140. ax = ax + 1
    141. ay = ay - 1
    142. Loop
    143. Do While ax > bx And ay < by
    144. costs = costs + Sqr(20)
    145. ax = ax - 1
    146. ay = ay + 1
    147. Loop
    148. Do While ax < bx
    149. costs = costs + 10
    150. ax = ax + 1
    151. Loop
    152. Do While ax > bx
    153. costs = costs + 10
    154. ax = ax - 1
    155. Loop
    156. Do While ay < by
    157. costs = costs + 10
    158. ay = ay + 1
    159. Loop
    160. Do While ay > by
    161. costs = costs + 10
    162. ay = ay - 1
    163. Loop
    164. calcCosts = costs
    165. End Function
    166. Private Function getNeighborPoints(AktPoint As KoordPoint)
    167. Dim startx As Integer
    168. Dim endx As Integer
    169. Dim starty As Integer
    170. Dim endy As Integer
    171. Dim x As Integer
    172. Dim y As Integer
    173. Dim NeighborPoint As KoordPoint
    174. startx = AktPoint.getX() - 1
    175. endx = AktPoint.getX() + 1
    176. starty = AktPoint.getY() - 1
    177. endy = AktPoint.getY() + 1
    178. If startx < minX Then
    179. startx = minX
    180. End If
    181. If starty < minY Then
    182. starty = minY
    183. End If
    184. If endx > maxX Then
    185. endx = maxX
    186. End If
    187. If endy > maxY Then
    188. endy = maxY
    189. End If
    190. For x = startx To endx
    191. For y = starty To endy
    192. 'If AktPoint.getX = 4 And AktPoint.getY = 3 Then
    193. ' Call canMoveDiagonal(AktPoint, x, y)
    194. 'End If
    195. If canMoveDiagonal(AktPoint, x, y) And Not isInClosedList(x, y) And Not wks.Cells(y, x).Value = "x" And (Not x = AktPoint.getX Or Not y = AktPoint.getY) Then
    196. Call paint(x, y, 6)
    197. Set NeighborPoint = New KoordPoint
    198. NeighborPoint.setX (x)
    199. NeighborPoint.setY (y)
    200. NeighborPoint.setParent AktPoint
    201. NeighborPoint.setH (rateCosts(x, y))
    202. NeighborPoint.setG (calcCosts(NeighborPoint, AktPoint) + AktPoint.getG())
    203. Call addToOpenList(NeighborPoint, AktPoint)
    204. Set NeighborPoint = Nothing
    205. Call paint(x, y, 5)
    206. End If
    207. Next y
    208. Next x
    209. End Function
    210. Private Function addToOpenList(checkPoint As KoordPoint, AktPoint As KoordPoint)
    211. Dim tmpPoint As KoordPoint
    212. Dim found As Boolean
    213. Dim index As Integer
    214. index = 0
    215. found = False
    216. For Each tmpPoint In openlist
    217. index = index + 1
    218. If tmpPoint.getX = checkPoint.getX And tmpPoint.getY = checkPoint.getY Then
    219. found = True
    220. If tmpPoint.getG > checkPoint.getG Then
    221. Call openlist.Add(checkPoint, , index)
    222. openlist.Remove (index + 1)
    223. End If
    224. End If
    225. Next
    226. If Not found Then
    227. index = 0
    228. For Each tmpPoint In closedList
    229. index = index + 1
    230. If tmpPoint.getX = checkPoint.getX And tmpPoint.getY = checkPoint.getY Then
    231. found = True
    232. If tmpPoint.getG > checkPoint.getG Then
    233. closedList.Add checkPoint, index, index, index - 1
    234. closedList.Remove index + 1
    235. End If
    236. End If
    237. Next
    238. End If
    239. If Not found Then
    240. openlist.Add checkPoint
    241. End If
    242. End Function
    243. Private Function paint(x As Integer, y As Integer, color As Integer)
    244. wks.Cells(y, x).Interior.ColorIndex = color
    245. End Function
    246. Private Function isInClosedList(x As Integer, y As Integer) As Boolean
    247. Dim tmpPoint As KoordPoint
    248. Dim found As Boolean
    249. found = False
    250. For Each tmpPoint In closedList
    251. If tmpPoint.getX = x And tmpPoint.getY = y Then
    252. found = True
    253. Exit For
    254. End If
    255. Next
    256. isInClosedList = found
    257. End Function
    258. Private Function isZielInOpenList() As Boolean
    259. Dim tmpPoint As KoordPoint
    260. Dim found As Boolean
    261. found = False
    262. For Each tmpPoint In openlist
    263. If tmpPoint.getX = ZielPoint.getX And tmpPoint.getY = ZielPoint.getY Then
    264. found = True
    265. Exit For
    266. End If
    267. Next
    268. isZielInOpenList = found
    269. End Function
    270. Private Function PaintPath()
    271. Dim tmpPoint As KoordPoint
    272. For Each tmpPoint In openlist
    273. If tmpPoint.getX = ZielPoint.getX And tmpPoint.getY = ZielPoint.getY Then
    274. Exit For
    275. End If
    276. Next
    277. Do While tmpPoint.getParent Is Nothing = False
    278. If tmpPoint.getX = ZielPoint.getX And tmpPoint.getY = ZielPoint.getY Then
    279. Call paint(tmpPoint.getX, tmpPoint.getY, 3)
    280. Else
    281. Call paint(tmpPoint.getX, tmpPoint.getY, 7)
    282. End If
    283. Set tmpPoint = tmpPoint.getParent
    284. Loop
    285. End Function
    286. Private Function canMoveDiagonal(inAktPoint As KoordPoint, inX As Integer, inY As Integer) As Boolean
    287. Dim ax As Integer
    288. Dim ay As Integer
    289. Dim bx As Integer
    290. Dim by As Integer
    291. Dim AktPoint As KoordPoint
    292. Dim tmp1 As Variant
    293. Dim tmp2 As Variant
    294. Dim erg As Boolean
    295. erg = True
    296. Set AktPoint = inAktPoint
    297. ax = AktPoint.getX
    298. ay = AktPoint.getY
    299. bx = inX
    300. by = inY
    301. tmp1 = wks.Cells(ay - 1, ax)
    302. tmp2 = wks.Cells(ay, ax - 1)
    303. If ax - 1 = bx And ay - 1 = by And (tmp1 = "x" Or tmp2 = "x") Then
    304. erg = False
    305. End If
    306. tmp1 = wks.Cells(ay + 1, ax)
    307. tmp2 = wks.Cells(ay, ax - 1)
    308. If ax - 1 = bx And ay + 1 = by And (tmp1 = "x" Or tmp2 = "x") Then
    309. erg = False
    310. End If
    311. tmp1 = wks.Cells(ay + 1, ax)
    312. tmp2 = wks.Cells(ay, ax + 1)
    313. If ax + 1 = bx And ay + 1 = by And (tmp1 = "x" Or tmp2 = "x") Then
    314. erg = False
    315. End If
    316. tmp1 = wks.Cells(ay - 1, ax)
    317. tmp2 = wks.Cells(ay, ax + 1)
    318. If ax + 1 = bx And ay - 1 = by And (tmp1 = "x" Or tmp2 = "x") Then
    319. erg = False
    320. End If
    321. canMoveDiagonal = erg
    322. End Function
    323. Private Function prepare()
    324. Dim x As Integer
    325. Dim y As Integer
    326. Dim tmp As String
    327. For x = minX To maxX
    328. For y = minY To maxY
    329. tmp = wks.Cells(y, x)
    330. If tmp = "x" Then
    331. wks.Cells(y, x).Interior.ColorIndex = 1
    332. ElseIf x = StartPoint.getX And y = StartPoint.getY Then
    333. wks.Cells(y, x).Interior.ColorIndex = 4
    334. ElseIf x = ZielPoint.getX And y = ZielPoint.getY Then
    335. wks.Cells(y, x).Interior.ColorIndex = 3
    336. Else
    337. wks.Cells(y, x).Interior.ColorIndex = 0
    338. End If
    339. Next y
    340. Next x
    341. End Function


    Und die Klasse "KoordPoint"

    Visual Basic-Quellcode

    1. Option Explicit
    2. Private parent As KoordPoint
    3. Private x As Integer
    4. Private y As Integer
    5. Private g As Double
    6. Private h As Double
    7. Public Function setParent(inParent As KoordPoint)
    8. Set parent = inParent
    9. End Function
    10. Public Function getParent() As KoordPoint
    11. Set getParent = parent
    12. End Function
    13. Public Function setX(inX As Integer)
    14. x = inX
    15. End Function
    16. Public Function getX() As Integer
    17. getX = x
    18. End Function
    19. Public Function setY(inY As Integer)
    20. y = inY
    21. End Function
    22. Public Function getY() As Integer
    23. getY = y
    24. End Function
    25. Public Function setG(inG As Double)
    26. g = inG
    27. End Function
    28. Public Function getG() As Double
    29. getG = g
    30. End Function
    31. Public Function setH(inH As Double)
    32. h = inH
    33. End Function
    34. Public Function getH() As Double
    35. getH = h
    36. End Function
    37. Public Function getF() As Double
    38. getF = g + h
    39. End Function


    In A1 muss der Y-Wert des Startpunkts angegeben werden

    In B1 muss der X-Wert des Startpunkts angegeben werden

    In C1 muss der Y-Wert des Zielpunkts angegeben werden

    In D1 muss der X-Wert des Zielpunkts angegeben werden



    Außerdem muss man am Anfang des Scripts die Grenzen des Feldes angeben (hier beginnt das Feld bei B2 und ist 50x50 Felder groß)

    Ich denke das Script lässt sich noch optimieren, oder?