613775e34d23

Add game of life example
[view raw] [browse files]
author Steve Losh <steve@stevelosh.com>
date Tue, 14 Mar 2017 13:34:16 +0000
parents 0851848a9c65
children a70cb449bc42
branches/tags (none)
files examples/life.lisp

Changes

diff -r 0851848a9c65 -r 613775e34d23 examples/life.lisp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/life.lisp	Tue Mar 14 13:34:16 2017 +0000
@@ -0,0 +1,108 @@
+(ql:quickload '(:cl-blt :losh :iterate))
+
+(defpackage :cl-blt.examples.life
+  (:use :cl :losh :iterate))
+
+(in-package :cl-blt.examples.life)
+
+(defconstant +world-size+ 128)
+
+(deftype world-index ()
+  `(integer 0 (,+world-size+)))
+
+(deftype world ()
+  `(simple-array bit (,+world-size+ ,+world-size+)))
+
+(defun make-world ()
+  (make-array (list +world-size+ +world-size+)
+              :element-type 'bit
+              :initial-element 0))
+
+(defun randomize-world (world)
+  (iterate (for (cell row col) :in-array world)
+           (setf (aref world row col)
+                 (if (randomp) 1 0))))
+
+(defun clear-world (world)
+  (iterate (for (cell row col) :in-array world)
+           (setf (aref world row col) 0)))
+
+(defun-inline wref (world row col)
+  (aref world
+        (mod row +world-size+)
+        (mod col +world-size+)))
+
+(defun count-neighbors (world row col)
+  (declare (optimize speed)
+           (type world world)
+           (type world-index row col))
+  (flet ((cell (dr dc)
+           (wref world (+ row dr) (+ col dc))))
+    (+ (cell -1 -1)
+       (cell -1  0)
+       (cell -1  1)
+       (cell  0 -1)
+       (cell  0  1)
+       (cell  1 -1)
+       (cell  1  0)
+       (cell  1  1))))
+
+(defun tick-cell (cell neighbors)
+  (if (= cell 1)
+    (cond
+      ((<= neighbors 1) 0)
+      ((<= neighbors 3) 1)
+      ((>= neighbors 4) 0))
+    (if (= neighbors 3)
+      1
+      0)))
+
+(defun tick-world (world next)
+  (iterate
+    (for (cell row col) :in-array world)
+    (setf (aref next row col)
+          (tick-cell cell (count-neighbors world row col)))))
+
+(defun draw (world)
+  (iterate
+    (with srows = (blt:height))
+    (with scols = (blt:width))
+    (for (cell row col) :in-array world)
+    (when (and (< row srows)
+               (< col scols))
+      (setf (blt:cell-char col row)
+            (if (zerop cell) #\Space #\*))))
+  (blt:refresh))
+
+(defun config ()
+  (blt:set "window.resizeable = true")
+  (blt:set "window.cellsize = 6x6")
+  (blt:set "window.title = LIFE"))
+
+(defun input ()
+  (blt:key-case (blt:read)
+    (:r :randomize)
+    (:c :clear)
+    (:space :tick)
+    (:escape :quit)
+    (:close :quit)))
+
+(defun main ()
+  (blt:with-terminal
+    (config)
+    (iterate
+      (with world = (make-world))
+      (with next = (make-world))
+      (initially (setf
+                   (aref world 3 4) 1
+                   (aref world 4 5) 1
+                   (aref world 5 3) 1
+                   (aref world 5 4) 1
+                   (aref world 5 5) 1))
+      (draw world)
+      (case (input)
+        (:randomize (randomize-world world))
+        (:clear (clear-world world))
+        (:tick (tick-world world next) (rotatef world next))
+        (:quit (return))))))
+