A* search algorithm: Difference between revisions
Content added Content deleted
(added Ol) |
|||
Line 1,538: | Line 1,538: | ||
█...xxxxx█ |
█...xxxxx█ |
||
██████████ |
██████████ |
||
</pre> |
|||
=={{header|Ol}}== |
|||
<lang scheme> |
|||
; level: list of lists, any except 1 means the cell is empty |
|||
; from: start cell in (x . y) mean |
|||
; to: destination cell in (x . y) mean |
|||
(define (A* level from to) |
|||
(define (hash xy) ; internal hash |
|||
(+ (<< (car xy) 16) (cdr xy))) |
|||
; naive test for "is the cell is empty?" |
|||
(define (floor? x y) |
|||
(let by-y ((y y) (map level)) |
|||
(cond |
|||
((< y 0) #true) |
|||
((null? map) #true) |
|||
((= y 0) |
|||
(let by-x ((x x) (map (car map))) |
|||
(if (< x 0) #true |
|||
(if (null? map) #true |
|||
(if (= x 0) |
|||
(not (eq? (car map) 1)) |
|||
(by-x (- x 1) (cdr map))))))) |
|||
(else |
|||
(by-y (- y 1) (cdr map)))))) |
|||
(unless (equal? from to) ; search not finished yet |
|||
(let step1 ((n 999) ; maximal count of search steps |
|||
(c-list-set #empty) |
|||
(o-list-set (put #empty (hash from) [from #f 0 0 0]))) |
|||
(unless (empty? o-list-set) ; do we have a space to move? |
|||
; no. let's find cell with minimal const |
|||
(let*((f (ff-fold (lambda (s key value) |
|||
(if (< (ref value 5) (car s)) |
|||
(cons (ref value 5) value) |
|||
s)) |
|||
(cons 9999 #f) o-list-set)) |
|||
(xy (ref (cdr f) 1)) |
|||
; move the cell from "open" to "closed" list |
|||
(o-list-set (del o-list-set (hash xy))) |
|||
(c-list-set (put c-list-set (hash xy) (cdr f)))) |
|||
; |
|||
(if (or (eq? n 0) |
|||
(equal? xy to)) |
|||
(let rev ((xy xy)) |
|||
; let's unroll the math and return only first step |
|||
(let*((parent (ref (get c-list-set (hash xy) #f) 2)) |
|||
(parent-of-parent (ref (get c-list-set (hash parent) #f) 2))) |
|||
(if parent-of-parent (rev parent) |
|||
(cons ;[ |
|||
(- (car xy) (car parent)) |
|||
(- (cdr xy) (cdr parent)) |
|||
;c-list-set |
|||
;o-list-set |
|||
)))) |
|||
(let*((x (car xy)) |
|||
(y (cdr xy)) |
|||
(o-list-set (fold (lambda (n v) |
|||
(if (and |
|||
(floor? (car v) (cdr v)) |
|||
(eq? #f (get c-list-set (hash v) #f))) |
|||
(let ((G (+ (ref (get c-list-set (hash xy) #f) 3) 1)); G of parent + 1 |
|||
; H calculated by "Manhattan method" |
|||
(H (* (+ (abs (- (car v) (car to))) |
|||
(abs (- (cdr v) (cdr to)))) |
|||
2)) |
|||
(got (get o-list-set (hash v) #f))) |
|||
(if got |
|||
(if (< G (ref got 3)) |
|||
(put n (hash v) [v xy G H (+ G H)]) |
|||
n) |
|||
(put n (hash v) [v xy G H (+ G H)]))) |
|||
n)) |
|||
o-list-set (list |
|||
(cons x (- y 1)) |
|||
(cons x (+ y 1)) |
|||
(cons (- x 1) y) |
|||
(cons (+ x 1) y))))) |
|||
(step1 (- n 1) c-list-set o-list-set)))))))) |
|||
</lang> |
|||
{{out}} |
|||
<lang scheme> |
|||
(define level '( |
|||
(1 1 1 1 1 1 1 1 1 1) |
|||
(1 A 0 0 0 0 0 0 0 1) |
|||
(1 0 0 0 0 0 0 0 0 1) |
|||
(1 0 0 0 0 1 1 1 0 1) |
|||
(1 1 0 0 0 0 0 1 0 1) |
|||
(1 0 0 1 0 0 0 1 0 1) |
|||
(1 0 0 1 1 1 1 1 0 1) |
|||
(1 0 0 0 0 0 0 0 0 1) |
|||
(1 0 0 0 1 0 0 0 B 1) |
|||
(1 1 1 1 1 1 1 1 1 1) |
|||
)) |
|||
(for-each print level) |
|||
; let's check that we can't move to (into wall) |
|||
(print (A* level '(1 . 1) '(9 . 9))) |
|||
(define to '(8 . 8)) |
|||
(define (plus a b) (cons (+ (car a) (car b)) (+ (cdr a) (cdr b)))) ; helper |
|||
(define path |
|||
(let loop ((me '(1 . 1)) (path '())) |
|||
(if (equal? me to) |
|||
(begin |
|||
(print "here I am!") |
|||
(cons to path)) |
|||
(let ((move (A* level me to))) |
|||
(unless move |
|||
(begin |
|||
(print "no way, sorry :(") |
|||
#false) |
|||
(let ((step (plus me move))) |
|||
(print me " + " move " -> " step) |
|||
(loop step (cons me path)))))))) |
|||
; let's draw the path? |
|||
(define (has? lst x) ; helper |
|||
(cond |
|||
((null? lst) #false) |
|||
((equal? (car lst) x) lst) |
|||
(else (has? (cdr lst) x)))) |
|||
(define solved |
|||
(map (lambda (row y) |
|||
(map (lambda (cell x) |
|||
(cond |
|||
((equal? (cons x y) '(1 . 1)) "A") |
|||
((equal? (cons x y) '(8 . 8)) "B") |
|||
((has? path (cons x y)) "*") |
|||
(else cell))) |
|||
row (iota 10))) |
|||
level (iota 10))) |
|||
(for-each print solved) |
|||
</lang> |
|||
<pre> |
|||
the map: |
|||
(1 1 1 1 1 1 1 1 1 1) |
|||
(1 A 0 0 0 0 0 0 0 1) |
|||
(1 0 0 0 0 0 0 0 0 1) |
|||
(1 0 0 0 0 1 1 1 0 1) |
|||
(1 1 0 0 0 0 0 1 0 1) |
|||
(1 0 0 1 0 0 0 1 0 1) |
|||
(1 0 0 1 1 1 1 1 0 1) |
|||
(1 0 0 0 0 0 0 0 0 1) |
|||
(1 0 0 0 1 0 0 0 B 1) |
|||
(1 1 1 1 1 1 1 1 1 1) |
|||
we should not reach the '(9 . 9) cell: |
|||
#false |
|||
ok, we got #false, so really can't. |
|||
now try to reach cell '(8 . 8) - the 'B' point: |
|||
(1 . 1) + (0 . 1) -> (1 . 2) |
|||
(1 . 2) + (0 . 1) -> (1 . 3) |
|||
(1 . 3) + (1 . 0) -> (2 . 3) |
|||
(2 . 3) + (0 . 1) -> (2 . 4) |
|||
(2 . 4) + (0 . 1) -> (2 . 5) |
|||
(2 . 5) + (0 . 1) -> (2 . 6) |
|||
(2 . 6) + (0 . 1) -> (2 . 7) |
|||
(2 . 7) + (1 . 0) -> (3 . 7) |
|||
(3 . 7) + (1 . 0) -> (4 . 7) |
|||
(4 . 7) + (1 . 0) -> (5 . 7) |
|||
(5 . 7) + (0 . 1) -> (5 . 8) |
|||
(5 . 8) + (1 . 0) -> (6 . 8) |
|||
(6 . 8) + (1 . 0) -> (7 . 8) |
|||
(7 . 8) + (1 . 0) -> (8 . 8) |
|||
here I am! |
|||
(1 1 1 1 1 1 1 1 1 1) |
|||
(1 A 0 0 0 0 0 0 0 1) |
|||
(1 * 0 0 0 0 0 0 0 1) |
|||
(1 * * 0 0 1 1 1 0 1) |
|||
(1 1 * 0 0 0 0 1 0 1) |
|||
(1 0 * 1 0 0 0 1 0 1) |
|||
(1 0 * 1 1 1 1 1 0 1) |
|||
(1 0 * * * * 0 0 0 1) |
|||
(1 0 0 0 1 * * * B 1) |
|||
(1 1 1 1 1 1 1 1 1 1) |
|||
</pre> |
</pre> |
||