Last active
February 26, 2017 06:57
-
-
Save peccu/c81c125242d2cc2eb47c90f149abc78c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;; from Land of Lisp 11.9 | |
;; http://landoflisp.com/robots.lisp | |
(defun robots () | |
;; 盤面を64文字×16行の1024文字で表現している。 | |
;; (65文字目が2行目の1文字目) | |
;; @を自分として、各キーの方向に進む | |
;; q w e | |
;; a @ d | |
;; z x c | |
;; tはランダムな場所に飛ぶ | |
;; return-from mainで抜けられる様に名前をつける | |
(loop named main | |
;; 幅64文字の盤面がつながっているので、この文字数分加算するとその方向に移動する (オフセット) | |
with directions = '((q . -65) (w . -64) (e . -63) (a . -1) | |
(d . 1) (z . 63) (x . 64) (c . 65)) | |
;;; プレイヤーの挙動 | |
;; 544 = (+ (/ 1024 2) (/ 64 2)) = 中心 | |
for pos = 544 | |
;; プロンプト | |
then (progn (format t "~%qwe/asd/zxc to move, (t)eleport, (l)eave:") | |
(force-output) | |
;; キー入力をもとに | |
(let* ((c (read)) | |
;; オフセットを取り出し | |
(d (assoc c directions))) | |
;; オフセットを加算 (=移動)するか | |
(cond (d (+ pos (cdr d))) | |
;; ランダムな場所に移動するか | |
((eq 't c) (random 1024)) | |
;; 終了する | |
((eq 'l c) (return-from main 'bye)) | |
;; それ以外は移動しない | |
(t pos)))) | |
;;; 敵の挙動 | |
;; 10体の初期位置をランダムに配置 | |
for monsters = (loop repeat 10 | |
collect (random 1024)) | |
;; 各敵に対して | |
then (loop for mpos in monsters | |
;; 同じ位置の敵がいればすでにスクラップなので動かない | |
collect (if (> (count mpos monsters) 1) | |
;; そのまま | |
mpos | |
;; その位置に敵が一つなので動かす | |
;; 全方向を取り出して動かしてみて、一番プレイヤーに近づくものを採用する | |
;; 新しい位置はソートされた要素のcdarにある (距離 . new-mpos) | |
(cdar (sort (loop for (k . d) in directions | |
;; 取り出した方向に動かしてみて (new-mpos) | |
for new-mpos = (+ mpos d) | |
;; 敵位置とプレイヤーの位置のマンハッタン距離を求める | |
;; マンハッタン距離 = x,yそれぞれの差の絶対値の総和。 | |
;; 「x方向にnブロック、y方向にmブロック」という様な距離 | |
;; collect (距離 . new-mpos) | |
collect (cons (+ (abs (- (mod new-mpos 64) ; x方向 | |
(mod pos 64))) | |
(abs (- (ash new-mpos -6) ; y方向 (6ビットシフトしてるから64で割ってる) | |
(ash pos -6)))) | |
new-mpos)) | |
;; 距離(car)でソートする (距離 . new-mpos) | |
'< | |
:key #'car)))) | |
;; プレイヤーの勝ち条件 | |
when (loop for mpos in monsters | |
;; すべての敵位置に複数の敵がいる = すべてスクラップ | |
always (> (count mpos monsters) 1)) | |
return 'player-wins | |
;; 盤面の表示とプレイヤーと敵の衝突 (プレイヤーの負け)判定、敵同士の衝突 (スクラップ)判定 | |
do (format t | |
;; 最初と最後に | を表示する | |
;; 1文字ずつ出力し、65文字おきに"|改行|"を出力するのを繰り返す | |
"~%|~{~<|~%|~,65:;~A~>~}|" | |
(loop for p | |
below 1024 | |
;; 敵位置なら | |
collect (cond ((member p monsters) | |
;; プレイヤー位置と同じならプレイヤーの負け | |
(cond ((= p pos) (return-from main 'player-loses)) | |
;; 同じ位置に敵が複数いれば衝突 (スクラップ) | |
((> (count p monsters) 1) #\#) | |
;; 敵の表示 | |
(t #\A))) | |
;; プレイヤー位置ならプレイヤー表示 | |
((= p pos) #\@) | |
;; それ以外は空白表示 | |
(t #\ )))))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment