Skip to content

Instantly share code, notes, and snippets.

@peccu
Last active February 26, 2017 06:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save peccu/c81c125242d2cc2eb47c90f149abc78c to your computer and use it in GitHub Desktop.
Save peccu/c81c125242d2cc2eb47c90f149abc78c to your computer and use it in GitHub Desktop.
;; 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