mirror of
https://github.com/ashinn/chibi-scheme.git
synced 2025-05-20 06:09:18 +02:00
They can be close()d explicitly with close-file-descriptor, and will close() on gc, but only explicitly closing the last port on them will close the fileno. Notably needed for network sockets where we open separate input and output ports on the same socket.
206 lines
5.6 KiB
Scheme
206 lines
5.6 KiB
Scheme
;;; MAZEFUN -- Constructs a maze in a purely functional way,
|
|
;;; written by Marc Feeley.
|
|
|
|
(define iota
|
|
(lambda (n)
|
|
(iota-iter n '())))
|
|
|
|
(define iota-iter
|
|
(lambda (n lst)
|
|
(if (= n 0)
|
|
lst
|
|
(iota-iter (- n 1) (cons n lst)))))
|
|
|
|
(define foldr
|
|
(lambda (f base lst)
|
|
|
|
(define foldr-aux
|
|
(lambda (lst)
|
|
(if (null? lst)
|
|
base
|
|
(f (car lst) (foldr-aux (cdr lst))))))
|
|
|
|
(foldr-aux lst)))
|
|
|
|
(define foldl
|
|
(lambda (f base lst)
|
|
|
|
(define foldl-aux
|
|
(lambda (base lst)
|
|
(if (null? lst)
|
|
base
|
|
(foldl-aux (f base (car lst)) (cdr lst)))))
|
|
|
|
(foldl-aux base lst)))
|
|
|
|
(define for
|
|
(lambda (lo hi f)
|
|
|
|
(define for-aux
|
|
(lambda (lo)
|
|
(if (< lo hi)
|
|
(cons (f lo) (for-aux (+ lo 1)))
|
|
'())))
|
|
|
|
(for-aux lo)))
|
|
|
|
(define concat
|
|
(lambda (lists)
|
|
(foldr append '() lists)))
|
|
|
|
(define list-read
|
|
(lambda (lst i)
|
|
(if (= i 0)
|
|
(car lst)
|
|
(list-read (cdr lst) (- i 1)))))
|
|
|
|
(define list-write
|
|
(lambda (lst i val)
|
|
(if (= i 0)
|
|
(cons val (cdr lst))
|
|
(cons (car lst) (list-write (cdr lst) (- i 1) val)))))
|
|
|
|
(define list-remove-pos
|
|
(lambda (lst i)
|
|
(if (= i 0)
|
|
(cdr lst)
|
|
(cons (car lst) (list-remove-pos (cdr lst) (- i 1))))))
|
|
|
|
(define duplicates?
|
|
(lambda (lst)
|
|
(if (null? lst)
|
|
#f
|
|
(or (member (car lst) (cdr lst))
|
|
(duplicates? (cdr lst))))))
|
|
|
|
; Manipulation de matrices.
|
|
|
|
(define make-matrix
|
|
(lambda (n m init)
|
|
(for 0 n (lambda (i) (for 0 m (lambda (j) (init i j)))))))
|
|
|
|
(define matrix-read
|
|
(lambda (mat i j)
|
|
(list-read (list-read mat i) j)))
|
|
|
|
(define matrix-write
|
|
(lambda (mat i j val)
|
|
(list-write mat i (list-write (list-read mat i) j val))))
|
|
|
|
(define matrix-size
|
|
(lambda (mat)
|
|
(cons (length mat) (length (car mat)))))
|
|
|
|
(define matrix-map
|
|
(lambda (f mat)
|
|
(map (lambda (lst) (map f lst)) mat)))
|
|
|
|
(define initial-random 0)
|
|
|
|
(define next-random
|
|
(lambda (current-random)
|
|
(remainder (+ (* current-random 3581) 12751) 131072)))
|
|
|
|
(define shuffle
|
|
(lambda (lst)
|
|
(shuffle-aux lst initial-random)))
|
|
|
|
(define shuffle-aux
|
|
(lambda (lst current-random)
|
|
(if (null? lst)
|
|
'()
|
|
(let ((new-random (next-random current-random)))
|
|
(let ((i (modulo new-random (length lst))))
|
|
(cons (list-read lst i)
|
|
(shuffle-aux (list-remove-pos lst i)
|
|
new-random)))))))
|
|
|
|
(define make-maze
|
|
(lambda (n m) ; n and m must be odd
|
|
(if (not (and (odd? n) (odd? m)))
|
|
'error
|
|
(let ((cave
|
|
(make-matrix n m (lambda (i j)
|
|
(if (and (even? i) (even? j))
|
|
(cons i j)
|
|
#f))))
|
|
(possible-holes
|
|
(concat
|
|
(for 0 n (lambda (i)
|
|
(concat
|
|
(for 0 m (lambda (j)
|
|
(if (equal? (even? i) (even? j))
|
|
'()
|
|
(list (cons i j)))))))))))
|
|
(cave-to-maze (pierce-randomly (shuffle possible-holes) cave))))))
|
|
|
|
(define cave-to-maze
|
|
(lambda (cave)
|
|
(matrix-map (lambda (x) (if x '_ '*)) cave)))
|
|
|
|
(define pierce
|
|
(lambda (pos cave)
|
|
(let ((i (car pos)) (j (cdr pos)))
|
|
(matrix-write cave i j pos))))
|
|
|
|
(define pierce-randomly
|
|
(lambda (possible-holes cave)
|
|
(if (null? possible-holes)
|
|
cave
|
|
(let ((hole (car possible-holes)))
|
|
(pierce-randomly (cdr possible-holes)
|
|
(try-to-pierce hole cave))))))
|
|
|
|
(define try-to-pierce
|
|
(lambda (pos cave)
|
|
(let ((i (car pos)) (j (cdr pos)))
|
|
(let ((ncs (neighboring-cavities pos cave)))
|
|
(if (duplicates?
|
|
(map (lambda (nc) (matrix-read cave (car nc) (cdr nc))) ncs))
|
|
cave
|
|
(pierce pos
|
|
(foldl (lambda (c nc) (change-cavity c nc pos))
|
|
cave
|
|
ncs)))))))
|
|
|
|
(define change-cavity
|
|
(lambda (cave pos new-cavity-id)
|
|
(let ((i (car pos)) (j (cdr pos)))
|
|
(change-cavity-aux cave pos new-cavity-id (matrix-read cave i j)))))
|
|
|
|
(define change-cavity-aux
|
|
(lambda (cave pos new-cavity-id old-cavity-id)
|
|
(let ((i (car pos)) (j (cdr pos)))
|
|
(let ((cavity-id (matrix-read cave i j)))
|
|
(if (equal? cavity-id old-cavity-id)
|
|
(foldl (lambda (c nc)
|
|
(change-cavity-aux c nc new-cavity-id old-cavity-id))
|
|
(matrix-write cave i j new-cavity-id)
|
|
(neighboring-cavities pos cave))
|
|
cave)))))
|
|
|
|
(define neighboring-cavities
|
|
(lambda (pos cave)
|
|
(let ((size (matrix-size cave)))
|
|
(let ((n (car size)) (m (cdr size)))
|
|
(let ((i (car pos)) (j (cdr pos)))
|
|
(append (if (and (> i 0) (matrix-read cave (- i 1) j))
|
|
(list (cons (- i 1) j))
|
|
'())
|
|
(if (and (< i (- n 1)) (matrix-read cave (+ i 1) j))
|
|
(list (cons (+ i 1) j))
|
|
'())
|
|
(if (and (> j 0) (matrix-read cave i (- j 1)))
|
|
(list (cons i (- j 1)))
|
|
'())
|
|
(if (and (< j (- m 1)) (matrix-read cave i (+ j 1)))
|
|
(list (cons i (+ j 1)))
|
|
'())))))))
|
|
|
|
|
|
(let ((input (with-input-from-file "input.txt" read)))
|
|
(time (let loop ((n 500) (v 0))
|
|
(if (zero? n)
|
|
v
|
|
(loop (- n 1)
|
|
(make-maze 11 (if input 11 0)))))))
|