#! /usr/bin/racket
;Windows だと
;
;; @echo off
;; Racket.exe "%~f0" %*
;
;詳しくは
;https://d...content-available-to-author-only...g.org/guide/scripts.html#%28part._.Unix_.Scripts%29
;参照
#lang racket
;一般化されたset!
;https://w...content-available-to-author-only...s.com/ja/tech/srfi/srfi-17/
;を使用
(require srfi/17)
;壁(*wall*)と空(*empty*)を定義
(define *empty* #\□)
(define *wall* #\■)
;フィールド作成
(define (make-field m n)
(let ((x (+ m 2)) (y (+ n 2)))
(let loop ((i 0) (j 0) (raw '()) (raws '()))
(cond ((= i x) (reverse raws))
((= j y)
(loop (+ i 1) 0 '() (cons (reverse raw) raws)))
(else
(loop i (+ j 1)
(cons
(if (or (zero? i) (= i (- x 1))
(zero? j) (= j (- y 1))
(and (even? i) (even? j)))
*wall* *empty*) raw) raws))))))
;フィールド(迷路)を文字列に変換
(define (maze->string maze)
(apply string-append
(map (lambda (x)
(list->string
(append x '(#\newline))))
maze)))
;サイコロ、及び方向を定義
(define (dice n)
(list-ref '(right down left up) (random 0 n)))
;maze(迷路)作成
(define (make-maze field)
(let ((x (length field)) (y (length (car field))))
; 端以外は行・列共に偶数の時は壁なので、ループを回す初期値は2、
; 以降カウンタは2づつ増やす
(let loop ((i 2) (j 2) (field field))
(cond ((>= i (- x 1)) field)
((>= j (- y 1)) (loop (+ i 2) 2 field))
(else
(loop i (+ j 2)
(select
(cond ((= i 2) 4)
((char=?
(list-ref (list-ref field i) (- j 1))
*wall*) 2)
(else 3)) i j field)))))))
;条件によりn面体サイコロが代わり、
;変換されたベクタのどこを変更するか決める
(define (select n i j field)
(let ((v (list->vector (map list->vector field)))
(direction (dice n)))
(set! (vector-ref
(vector-ref v
(case direction
((down) (+ i 1))
((up) (- i 1))
(else i)))
(case direction
((right) (+ j 1))
((left) (- j 1))
(else j))) *wall*)
(vector->list (vector-map vector->list v))))
(let ((argv (map (lambda (x)
(string->number x 10))
(command-line #:args (x y) (list x y)))))
(display (maze->string (make-maze (make-field (car argv)
(cadr argv))))))