#lang racket
(require 2htdp/universe 2htdp/image lang/posn)
(struct world (key brave flag))
;; ここは実際に画像を「挿入」する
(define *images* '(. . . . .))
(define *width* 620)
(define *height* 434)
(define *step* 62)
;; マップ描画の準備
(define *image-posns*
(append-map (lambda (y)
(map (lambda (x)
(make-posn x y))
(range (/ *step* 2) *width* *step*)))
(range (/ *step* 2) *height* *step*)))
;; マップデータ
(define *map-data* '((1 0 1 1 1 1 1 1 1 1)
(1 0 0 1 2 0 0 1 3 1)
(1 1 0 1 1 1 0 1 0 1)
(1 0 0 0 0 0 0 1 0 1)
(1 0 1 1 1 1 1 1 0 1)
(1 0 0 0 0 0 0 0 0 1)
(1 1 1 1 1 1 1 1 1 1)))
;; バックグラウンド
(define *background*
(place-images (map (lambda (i)
(list-ref *images* (if (< i 3)
i
0)))
(apply append *map-data*))
*image-posns*
(empty-scene *width* *height*)))
;; *map-data* 上の座標を構造体 posn に変換
(define *d-pairs* (append-map (lambda (y)
(map (lambda (x)
(cons x y))
(range 0
(length
(list-ref *map-data* 0)))))
(range 0 (length *map-data*))))
(define *d-pair->posn-table*
(make-hash (map (lambda (x y)
(cons x y))
*d-pairs* *image-posns*)))
(define (d-pair->posn d-pair)
(hash-ref *d-pair->posn-table* d-pair))
;; *map-posn*上のデータを座標に変換
(define *posn->d-pair-table*
(make-hash (map (lambda (x y)
(cons x y))
*image-posns* *d-pairs*)))
(define (posn->d-pair posn)
(hash-ref *posn->d-pair-table* posn))
;; キー配置関数
(define (place-key p flag scene)
(place-image
(list-ref *images* (if flag
0
3))
(posn-x p)
(posn-y p)
scene))
;; 勇者配置関数
(define (place-brave p scene)
(place-image
(list-ref *images* 4)
(posn-x p)
(posn-y p)
scene))
;; 移動用関数のユーティリティ
(define (map-ref x y)
(list-ref (list-ref *map-data* y) x))
(define (movable? x y)
(not (or (negative? y) (= (map-ref x y) 1))))
;; 移動用のキーを使ってworldを更新する
(define (change w a-key)
(let ((dir (posn->d-pair (world-brave w))))
(let ((x (car dir)) (y (cdr dir)))
(world
(world-key w)
(cond
((key=? a-key "left") (let ((x (- x 1)))
(if (movable? x y)
(d-pair->posn (cons x y))
(world-brave w))))
((key=? a-key "right") (let ((x (+ x 1)))
(if (movable? x y)
(d-pair->posn (cons x y))
(world-brave w))))
((= (string-length a-key) 1) (world-brave w))
((key=? a-key "up") (let ((y (- y 1)))
(if (movable? x y)
(d-pair->posn (cons x y))
(world-brave w))))
((key=? a-key "down") (let ((y (+ y 1)))
(if (movable? x y)
(d-pair->posn (cons x y))
(world-brave w))))
(else (world-brave w)))
(if (= (map-ref x y) 3) #t (world-flag w))))))
;; world 配置関数
(define (place-world w)
(place-brave (world-brave w)
(place-key (world-key w)
(world-flag w)
*background*)))
;; エンディング表示
(define (game-ends? w)
(let ((dir (posn->d-pair (world-brave w))))
(let ((x (car dir)) (y (cdr dir)))
(and (world-flag w) (= (map-ref x y) 2)))))
(define (ending w)
(place-image (text "ゴールおめでとう。
だが、君の戦いはまだ始まったばかりだ。
......つづく?" 15 "white")
300
200
(empty-scene *width* *height* "black")))
;; main プログラム
(big-bang (world (d-pair->posn '(8 . 1))
(d-pair->posn '(1 . 0))
#f)
(to-draw place-world)
(on-key change)
(stop-when game-ends? ending)
(name "Dungeon & Racket"))