ライフゲーム
Posted feedbacks - Common Lisp
Common Lisp です。あえて CLOS(Common Lisp Object System)で。
print-object で印字形式を設定していること、setf で更新している位であとは普通です。
こんな感じで試します。
cl-user(27): (setq b (make-glider))
#<board
.X........
X.........
XXX.......
..........
..........
..........
..........
..........
..........
..........
>
cl-user(28): (update b)
#<board
..........
X.X.......
XX........
.X........
..........
..........
..........
..........
..........
..........
>
初めてライフゲームを実装して、とても楽しかったです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | ;;;
;; dokaku 126
;;
(defclass board ()
((width :accessor board-width :initarg :w)
(height :accessor board-height :initarg :h)
(cells :accessor board-cells :initarg :cells)))
(defmethod print-object ((board board) stream)
(print-unreadable-object (board stream)
(format stream "board~%")
(loop for y from 0 below (board-height board)
do
(loop for x from 0 below (board-width board)
do
(format stream "~a" (if (cell board x y) "X" ".")))
(format stream "~%"))))
(defun make-board (w h)
"constructor"
(make-instance 'board :w w :h h :cells (make-array (list w h) :initial-element nil)))
(defun make-random-board (w h)
(let ((board (make-board w h)))
(loop for y from 0 below (board-height board)
do
(loop for x from 0 below (board-width board)
do
(setf (cell board x y) (< (random 10) 3))))
board))
(defmethod cell ((board board) x y)
"accessor"
(aref (board-cells board) (mod x (board-width board)) (mod y (board-height board))))
;; (setf (cell board x y) value)
(defsetf cell (board x y) (value)
`(setf (aref (board-cells ,board) (mod ,x (board-width ,board))
(mod ,y (board-height ,board))) ,value))
(defmethod cell-neighbours ((board board) x y)
(list (cell board (1- x) (1- y))
(cell board x (1- y))
(cell board (1+ x) (1- y))
(cell board (1- x) y)
(cell board (1+ x) y)
(cell board (1- x) (1+ y))
(cell board x (1+ y))
(cell board (1+ x) (1+ y))))
(defmethod cell-survivep ((board board) x y)
(let ((c (cell board x y))
(n (count-if #'identity (cell-neighbours board x y))))
(cond
((and (not c) (= n 3)) t) ;; born
((and c (or (= n 3) (= n 2))) t) ;; keep
(t nil)))) ;; die
(defmethod update ((board board))
(let ((next
(loop for y from 0 below (board-height board)
append
(loop for x from 0 below (board-width board)
collect (list x y (cell-survivep board x y))))))
(loop for elt in next
do
(destructuring-bind (x y v) elt
(setf (cell board x y) v))))
board)
(defun make-blinker ()
(let ((b (make-board 10 10)))
(setf (cell b 1 0) t
(cell b 1 1) t
(cell b 1 2) t)
b))
(defun make-glider ()
(let ((b (make-board 10 10)))
(setf (cell b 1 0) t
(cell b 0 1) t
(cell b 0 2) t
(cell b 1 2) t
(cell b 2 2) t)
b))
|
大分色物な感じですが、超並列計算機 Connection Machine用のLisp処理系
である*LISP(スターリスプ)のCommon Lisp用のシミュレータパッケージを
使用して書いてみました。
本来、処理をプロセッサノードに割り振って並列に計算するので、今回位の計算
ならば、一度にどかんと計算させて、ループは全く使わないのが*LISPの流儀
だと思うのですが、構文がみつけられなかったため、全く普通に直列な
書き方になっており、あまり意味がないことになっています…。
表示は、グリッドの内容を綺麗に表示するプリティプリンタが付いてくるので、
それを使ってみました。
動作は、AllegroとCLISPで確認しています。
(SBCL等では、ソースを修正しないと*LISPがコンパイルできないようです。)
ソースは参考ページからダウンロード可能でチュートリアル付きです。
;; 実行結果 (グライダー)
DIMENSION 0 (X) ----->
0 1 0 0 0 0 0 0 0 0
1 0 0 0 0 0 0 0 0 0
1 1 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
である*LISP(スターリスプ)のCommon Lisp用のシミュレータパッケージを
使用して書いてみました。
本来、処理をプロセッサノードに割り振って並列に計算するので、今回位の計算
ならば、一度にどかんと計算させて、ループは全く使わないのが*LISPの流儀
だと思うのですが、構文がみつけられなかったため、全く普通に直列な
書き方になっており、あまり意味がないことになっています…。
表示は、グリッドの内容を綺麗に表示するプリティプリンタが付いてくるので、
それを使ってみました。
動作は、AllegroとCLISPで確認しています。
(SBCL等では、ソースを修正しないと*LISPがコンパイルできないようです。)
ソースは参考ページからダウンロード可能でチュートリアル付きです。
;; 実行結果 (グライダー)
DIMENSION 0 (X) ----->
0 1 0 0 0 0 0 0 0 0
1 0 0 0 0 0 0 0 0 0
1 1 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
see: Simulator for *Lisp language for Connection Machine, circa 1989.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | (defpackage :doukaku-126 (:use :cl :*lisp))
(in-package :doukaku-126)
(*cold-boot :initial-dimensions '(10 10))
(defconstant +alive+ 1)
(defconstant +dead+ 0)
(defun grid10 (x y)
(grid (mod x 10) (mod y 10)))
(defun get-env (grid x y)
(values (pref grid (grid x y))
(count +alive+
(list (pref grid (grid10 (1- x) (1- y)))
(pref grid (grid10 x (1- y)))
(pref grid (grid10 (1+ x) (1- y)))
(pref grid (grid10 (1- x) y))
(pref grid (grid10 (1+ x) y))
(pref grid (grid10 (1- x) (1+ y)))
(pref grid (grid10 x (1+ y)))
(pref grid (grid10 (1+ x) (1+ y)))))))
(defun gen-next (cur)
(*let ((next +dead+))
(loop :for x :from 0 :to 9
:do (loop :for y :from 0 :to 9
:do (multiple-value-bind (self env) (get-env cur x y)
(cond ((and (eql +dead+ self) (= 3 env))
(*setf (pref next (grid x y)) +alive+))
((and (= +alive+ self) (<= 2 env 3))
(*setf (pref next (grid x y)) +alive+))
('T (*setf (pref next (grid x y)) +dead+))))))
next))
;; グライダーを作る
(defun make-glider ()
(*let ((g +dead+))
(*setf (pref g (grid 1 0)) +alive+
(pref g (grid 0 1)) +alive+
(pref g (grid 0 2)) +alive+
(pref g (grid 1 2)) +alive+
(pref g (grid 2 2)) +alive+)
g))
;; 初期値をグライダーにしてループ
(loop :for gen = (make-glider) then (gen-next gen)
:do (ppp gen :mode :grid)
:unless (y-or-n-p) :do (return))
|
Connection Machine用のLISP、*LISPのCL用シミュレータパッケージを
使用しています。
前回投稿したバージョンは、並列実行の構文を活用できていませんでしたが、
何となく構文が分かって来たので再挑戦してみました。
実行例(初期値をランダムに設定してループ表示):
; DIMENSION 0 (X) ----->
;
;0 1 1 1 1 1 1 1 1 1
;1 0 1 0 1 1 1 0 0 1
;1 1 0 1 1 1 1 0 0 0
;0 0 1 1 1 1 0 0 1 0
;1 1 0 0 1 0 1 1 0 0
;1 0 1 1 1 0 1 1 0 1
;1 0 0 0 1 0 1 1 1 1
;0 1 1 0 0 0 1 1 1 0
;0 0 0 0 1 1 0 0 0 1
;0 1 1 1 1 0 0 0 1 0
;
; DIMENSION 0 (X) ----->
;
;0 0 0 0 0 0 0 0 0 0
;0 0 0 0 0 0 0 0 0 0
;1 0 0 0 0 0 0 1 0 0
;0 0 0 0 0 0 0 0 0 1
;1 0 0 0 0 0 0 0 0 0
;0 0 1 0 1 0 0 0 0 0
;0 0 0 0 1 0 0 0 0 0
;0 1 0 1 1 0 0 0 0 0
;1 0 0 0 1 1 1 0 0 1
;0 1 0 0 0 0 0 0 0 0
使用しています。
前回投稿したバージョンは、並列実行の構文を活用できていませんでしたが、
何となく構文が分かって来たので再挑戦してみました。
実行例(初期値をランダムに設定してループ表示):
; DIMENSION 0 (X) ----->
;
;0 1 1 1 1 1 1 1 1 1
;1 0 1 0 1 1 1 0 0 1
;1 1 0 1 1 1 1 0 0 0
;0 0 1 1 1 1 0 0 1 0
;1 1 0 0 1 0 1 1 0 0
;1 0 1 1 1 0 1 1 0 1
;1 0 0 0 1 0 1 1 1 1
;0 1 1 0 0 0 1 1 1 0
;0 0 0 0 1 1 0 0 0 1
;0 1 1 1 1 0 0 0 1 0
;
; DIMENSION 0 (X) ----->
;
;0 0 0 0 0 0 0 0 0 0
;0 0 0 0 0 0 0 0 0 0
;1 0 0 0 0 0 0 1 0 0
;0 0 0 0 0 0 0 0 0 1
;1 0 0 0 0 0 0 0 0 0
;0 0 1 0 1 0 0 0 0 0
;0 0 0 0 1 0 0 0 0 0
;0 1 0 1 1 0 0 0 0 0
;1 0 0 0 1 1 1 0 0 1
;0 1 0 0 0 0 0 0 0 0
see: Simulator for *Lisp language for Connection Machine, circa 1989.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | (defpackage :doukaku-126 (:use :cl :*lisp))
(in-package :doukaku-126)
(*cold-boot :initial-dimensions '(10 10))
(defconstant +alive+ 1)
(defconstant +dead+ 0)
(defun gen-next!! (pvar)
(let ((env (count!! +alive+
(vector!!
(news!! pvar -1 -1) (news!! pvar -1 0) (news!! pvar -1 1)
(news!! pvar 0 -1) (news!! pvar 0 1)
(news!! pvar 1 -1) (news!! pvar 1 0) (news!! pvar 1 1)))))
(cond!! ((and!! (eql!! +dead+ pvar) (=!! env 3)) +alive+)
((and!! (eql!! +alive+ pvar) (<=!! 2 env 3)) +alive+)
(t!! +dead+))))
;; 実行例(初期値をランダムに設定してループ表示):
(loop :for gen = (truncate!! (random!! 10) 5) :then (gen-next!! gen)
:do (ppp gen)
:unless (y-or-n-p) :do (return))
|


saws
#5330()
Rating6/12=0.50
see: Wikipedia:ライフゲーム
[ reply ]