initial
This commit is contained in:
commit
9fcbcc5af4
1 changed files with 231 additions and 0 deletions
231
min-steps.scm
Executable file
231
min-steps.scm
Executable file
|
|
@ -0,0 +1,231 @@
|
||||||
|
#! /usr/bin/env guile -e main -s
|
||||||
|
!#
|
||||||
|
|
||||||
|
(use-modules (srfi srfi-1)
|
||||||
|
(srfi srfi-11)
|
||||||
|
(srfi srfi-43)
|
||||||
|
(rnrs io ports)
|
||||||
|
(ice-9 control)
|
||||||
|
(ice-9 arrays))
|
||||||
|
|
||||||
|
(define (insert-sorted x xs <)
|
||||||
|
(merge (list x) xs <))
|
||||||
|
|
||||||
|
(define (make-pq . elems) (map (lambda (x) (cons x 0)) elems))
|
||||||
|
(define (pq-empty? pq) (null? pq))
|
||||||
|
(define (pq< a b) (< (cdr a) (cdr b)))
|
||||||
|
(define (pq-insert pq x prio) (insert-sorted (cons x prio) pq pq<))
|
||||||
|
(define (pq-pop pq) (values (cdr pq) (car pq)))
|
||||||
|
(define (pq-contains? pq x) (any (lambda (a) (equal? (car a) x)) x))
|
||||||
|
|
||||||
|
(define (ucs start succ win?)
|
||||||
|
(define frontier (make-pq start))
|
||||||
|
(define visited (make-hash-table))
|
||||||
|
(hash-set! visited start (cons #f 0))
|
||||||
|
|
||||||
|
(define (push! x cost)
|
||||||
|
(set! frontier (pq-insert frontier x cost)))
|
||||||
|
|
||||||
|
(define (pop!)
|
||||||
|
(let-values ([(pq node) (pq-pop frontier)])
|
||||||
|
(set! frontier pq)
|
||||||
|
(values (car node) (cdr node))))
|
||||||
|
|
||||||
|
(let/ec return
|
||||||
|
(while (not (pq-empty? frontier))
|
||||||
|
(let-values ([(node cost) (pop!)])
|
||||||
|
(when (win? node)
|
||||||
|
(return node cost))
|
||||||
|
|
||||||
|
(for-each
|
||||||
|
(lambda (neighbor)
|
||||||
|
(define total-cost (1+ cost))
|
||||||
|
(when (or
|
||||||
|
(not (hash-ref visited neighbor))
|
||||||
|
(< total-cost (cdr (hash-ref visited neighbor))))
|
||||||
|
(hash-set! visited neighbor (cons node total-cost))
|
||||||
|
(push! neighbor total-cost)))
|
||||||
|
(succ node))))
|
||||||
|
(values #f #f)))
|
||||||
|
|
||||||
|
(define (string->board s)
|
||||||
|
(define lines (list->vector (filter (compose not string-null?) (string-split s #\newline))))
|
||||||
|
(define widths (vector-map (lambda (_ line) (string-length line)) lines))
|
||||||
|
(define width (apply max (vector->list widths)))
|
||||||
|
(define height (vector-length lines))
|
||||||
|
(define squares (make-array #\space width height))
|
||||||
|
|
||||||
|
(vector-for-each
|
||||||
|
(lambda (y line)
|
||||||
|
(string-for-each-index
|
||||||
|
(lambda (x)
|
||||||
|
(array-set! squares (string-ref line x) x y))
|
||||||
|
line))
|
||||||
|
lines)
|
||||||
|
|
||||||
|
squares)
|
||||||
|
|
||||||
|
(define (char->stuff c)
|
||||||
|
(case c
|
||||||
|
[(#\.) '(goal)]
|
||||||
|
[(#\@) '(player)]
|
||||||
|
[(#\+) '(goal player)]
|
||||||
|
[(#\$) '(box)]
|
||||||
|
[(#\*) '(goal box)]
|
||||||
|
[(#\#) '(wall)]
|
||||||
|
[else '()]))
|
||||||
|
|
||||||
|
(define (stuff->char stuff)
|
||||||
|
(define goal? (memq 'goal stuff))
|
||||||
|
(define player? (memq 'player stuff))
|
||||||
|
(define box? (memq 'box stuff))
|
||||||
|
(define wall? (memq 'wall stuff))
|
||||||
|
|
||||||
|
(cond
|
||||||
|
[(and goal? player?) #\+]
|
||||||
|
[(and goal? box?) #\*]
|
||||||
|
[player? #\@]
|
||||||
|
[goal? #\.]
|
||||||
|
[box? #\$]
|
||||||
|
[wall? #\#]
|
||||||
|
[else #\space]))
|
||||||
|
|
||||||
|
(define (board-width b) (first (array-dimensions b)))
|
||||||
|
(define (board-height b) (second (array-dimensions b)))
|
||||||
|
|
||||||
|
(define (board-ref b x y)
|
||||||
|
(if (and (< -1 x (board-width b))
|
||||||
|
(< -1 y (board-height b)))
|
||||||
|
(char->stuff (array-ref b x y))
|
||||||
|
'(wall)))
|
||||||
|
|
||||||
|
(define (board-set! b x y stuff)
|
||||||
|
(array-set! b (stuff->char stuff) x y))
|
||||||
|
|
||||||
|
(define (board-remove! b x y thing)
|
||||||
|
(board-set! b x y (lset-difference eq? (board-ref b x y) (list thing))))
|
||||||
|
|
||||||
|
(define (board-add! b x y thing)
|
||||||
|
(board-set! b x y (lset-union eq? (board-ref b x y) (list thing))))
|
||||||
|
|
||||||
|
(define (board-move! b x0 y0 x y thing)
|
||||||
|
(board-remove! b x0 y0 thing)
|
||||||
|
(board-add! b x y thing))
|
||||||
|
|
||||||
|
(define (board-for-each f b)
|
||||||
|
(define width (board-width b))
|
||||||
|
(define height (board-height b))
|
||||||
|
(do ([x 0 (modulo (1+ x) width)]
|
||||||
|
[y 0 (if (= (1+ x) width) (1+ y) y)])
|
||||||
|
[(= y height)]
|
||||||
|
(f (board-ref b x y) x y)))
|
||||||
|
|
||||||
|
|
||||||
|
(define (board->string b)
|
||||||
|
(with-output-to-string
|
||||||
|
(lambda ()
|
||||||
|
(board-for-each
|
||||||
|
(lambda (c x y)
|
||||||
|
(write-char (stuff->char c))
|
||||||
|
(when (= (1+ x) (board-width b))
|
||||||
|
(newline)))
|
||||||
|
b))))
|
||||||
|
|
||||||
|
(define (board-won? b)
|
||||||
|
(let/ec return
|
||||||
|
(board-for-each
|
||||||
|
(lambda (c x y) (when (and (memq 'goal c) (not (memq 'box c)))
|
||||||
|
(return #f)))
|
||||||
|
b)
|
||||||
|
#t))
|
||||||
|
|
||||||
|
(define (solid? stuff)
|
||||||
|
(pair? (lset-intersection eq? stuff '(wall box player))))
|
||||||
|
|
||||||
|
(define (board-player-pos b)
|
||||||
|
(let/ec return
|
||||||
|
(board-for-each
|
||||||
|
(lambda (c x y) (when (memq 'player c) (return x y)))
|
||||||
|
b)
|
||||||
|
(values #f #f)))
|
||||||
|
|
||||||
|
(define (copy-board b) (array-copy b))
|
||||||
|
|
||||||
|
(define (board-move b dx dy)
|
||||||
|
(define-values (x0 y0) (board-player-pos b))
|
||||||
|
(define-values (x1 y1) (values (+ x0 dx) (+ y0 dy)))
|
||||||
|
(define-values (x2 y2) (values (+ x1 dx) (+ y1 dy)))
|
||||||
|
|
||||||
|
(define s0 (board-ref b x0 y0))
|
||||||
|
(define s1 (board-ref b x1 y1))
|
||||||
|
(define s2 (board-ref b x2 y2))
|
||||||
|
|
||||||
|
(define newb (copy-board b))
|
||||||
|
|
||||||
|
(cond
|
||||||
|
[(not (solid? s1)) (board-move! newb x0 y0 x1 y1 'player)]
|
||||||
|
[(and (memq 'box s1) (not (solid? s2)))
|
||||||
|
(board-move! newb x1 y1 x2 y2 'box)
|
||||||
|
(board-move! newb x0 y0 x1 y1 'player)])
|
||||||
|
|
||||||
|
newb)
|
||||||
|
|
||||||
|
(define (board-succ b)
|
||||||
|
(remove
|
||||||
|
(lambda (newb) (equal? newb b))
|
||||||
|
(map
|
||||||
|
(lambda (dx dy) (board-move b dx dy))
|
||||||
|
'( 0 0 -1 1)
|
||||||
|
'(-1 1 0 0))))
|
||||||
|
|
||||||
|
(define (min-steps b)
|
||||||
|
(define-values (final-board steps) (ucs b board-succ board-won?))
|
||||||
|
steps)
|
||||||
|
|
||||||
|
(define steaming-hot
|
||||||
|
(string->board "
|
||||||
|
# #
|
||||||
|
# # #
|
||||||
|
# # #
|
||||||
|
# # #
|
||||||
|
# # #
|
||||||
|
# # #
|
||||||
|
# # #
|
||||||
|
|
||||||
|
##########
|
||||||
|
#........####
|
||||||
|
# $$$$$$$# #
|
||||||
|
#.$......# #
|
||||||
|
# $$$$$$ # #
|
||||||
|
#......$+# #
|
||||||
|
#$$$$$$$ # #
|
||||||
|
# ####
|
||||||
|
##########
|
||||||
|
\"Steaming Hot\" by David Buchweitz
|
||||||
|
"))
|
||||||
|
|
||||||
|
(define microban-1
|
||||||
|
(string->board "
|
||||||
|
####
|
||||||
|
# .#
|
||||||
|
# ###
|
||||||
|
#*@ #
|
||||||
|
# $ #
|
||||||
|
# ###
|
||||||
|
####
|
||||||
|
"))
|
||||||
|
|
||||||
|
(define microban-2
|
||||||
|
(string->board "
|
||||||
|
######
|
||||||
|
# #
|
||||||
|
# #@ #
|
||||||
|
# $* #
|
||||||
|
# .* #
|
||||||
|
# #
|
||||||
|
######
|
||||||
|
"))
|
||||||
|
|
||||||
|
(define (main . args)
|
||||||
|
(format #t "~a\n"
|
||||||
|
(min-steps (string->board (get-string-all (current-input-port))))))
|
||||||
Loading…
Reference in a new issue