<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-22986986</id><updated>2011-04-22T13:05:46.549+10:00</updated><title type='text'>gameylisp</title><subtitle type='html'>Investigating Common Lisp for games</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://gameylisp.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22986986/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://gameylisp.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Damyan</name><uri>http://www.blogger.com/profile/12580803323346455950</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>10</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-22986986.post-115894367795241316</id><published>2006-09-23T02:39:00.000+10:00</published><updated>2006-10-20T08:03:28.826+10:00</updated><title type='text'>arnesi continuations</title><content type='html'>I've just moved back to the UK from Australia.  With a few days of jet-lagged downtime I've managed to fit in some fiddling with CL.  The CVS version of SBCL now appears to work with Slime under Win32 (which is very very cool), and I've been playing with with-call/cc from arnesi.  It took a bit of fiddling to realise that you need to use defun/cc - documentation seems to be quite thin on the ground.  Once I twigged, it was pretty easy to port Fig 22.4 of OnLisp to CL:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;(defparameter *paths* nil)&lt;br /&gt;&lt;br /&gt;(defun/cc choose (choices)&lt;br /&gt;  (if (null choices)&lt;br /&gt;   (fail)&lt;br /&gt;   (let/cc cc&lt;br /&gt;  (push (lambda () (kall cc (choose (cdr choices)))) *paths*)&lt;br /&gt;  (kall cc (car choices)))))&lt;br /&gt;&lt;br /&gt;(defun/cc fail ()&lt;br /&gt;  (if (null *paths*)&lt;br /&gt;   (kall arnesi::*toplevel-k* '@)&lt;br /&gt;   (funcall (pop *paths*))))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;So that now Fig 22.3 can be written:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;(defun/cc two-numbers ()&lt;br /&gt;  (list (choose '(0 1 2 3 4 5))&lt;br /&gt;  (choose '(0 1 2 3 4 5))))&lt;br /&gt;&lt;br /&gt;(defun parlor-trick (sum)&lt;br /&gt;  (with-call/cc&lt;br /&gt; (let ((nums (two-numbers)))&lt;br /&gt;   (if (= (apply #'+ nums) sum)&lt;br /&gt;    `(the sum of ,@nums)&lt;br /&gt;    (fail)))))&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22986986-115894367795241316?l=gameylisp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gameylisp.blogspot.com/feeds/115894367795241316/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22986986&amp;postID=115894367795241316' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22986986/posts/default/115894367795241316'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22986986/posts/default/115894367795241316'/><link rel='alternate' type='text/html' href='http://gameylisp.blogspot.com/2006/09/arnesi-continuations.html' title='arnesi continuations'/><author><name>Damyan</name><uri>http://www.blogger.com/profile/12580803323346455950</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22986986.post-115089465823610332</id><published>2006-06-21T22:40:00.000+10:00</published><updated>2006-06-24T19:03:35.076+10:00</updated><title type='text'>How much memory gets allocated when you call a generic function?</title><content type='html'>I was wondering what actually happens when you call a generic function - specifically, how much memory would get allocated.  I've become a bit addicted to clisp's ext:times macro because it provides quite a good insight into the performance characteristics of a function.&lt;br /&gt;&lt;br /&gt;I knocked together a quick test and got some results...and then got distracted making a nice way to collect and display the results.  It turned into quite a fun little one-evening project that exercised some string manipulation and use of format.&lt;br /&gt;&lt;br /&gt;So here's the code to define my 'show-bytes-allocated' macro:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(asdf:oos 'asdf:load-op "split-sequence")&lt;br /&gt;(import 'split-sequence:split-sequence)&lt;br /&gt;&lt;br /&gt;(defun make-adjustable-string ()&lt;br /&gt;  (make-array '(0) :element-type 'base-char :fill-pointer 0 :adjustable t))&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;(defmacro times-to-string (&amp;body body)&lt;br /&gt;  `(let ((times (make-adjustable-string))&lt;br /&gt;         result)&lt;br /&gt;     (with-output-to-string (*trace-output* times)&lt;br /&gt;       (setf result (ext:times ,@body)))&lt;br /&gt;     (values result times)))&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;(defmacro bytes-allocated (&amp;body body)&lt;br /&gt;  `(let ((result))&lt;br /&gt;     (destructuring-bind (head perm-count perm-bytes temp-count temp-bytes)&lt;br /&gt;         (find-if (lambda (e) (equal (first e) "Total"))&lt;br /&gt;                  (mapcar (lambda (l) (split-sequence #\Space l&lt;br /&gt;                                                      :remove-empty-subseqs t))&lt;br /&gt;                          (split-sequence #\Newline&lt;br /&gt;                                          (multiple-value-bind (r s) (times-to-string ,@body)&lt;br /&gt;                                            (setf result r)&lt;br /&gt;                                            s)&lt;br /&gt;                                          :remove-empty-subseqs t)))&lt;br /&gt;       (declare (ignore head perm-count temp-count))&lt;br /&gt;       (list (read-from-string perm-bytes) (read-from-string temp-bytes) ',@body result))))&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;(defmacro show-bytes-allocated (&amp;body body)&lt;br /&gt;  `(progn&lt;br /&gt;     (format t "~20A ~20A ~10@A ~10@A~%" "Form" "Result" "Permament" "Temporary")&lt;br /&gt;     (format t "~63,,,'-A~%" "")&lt;br /&gt;     ,@(mapcar (lambda (form)&lt;br /&gt;                `(destructuring-bind (permament temporary f r) (bytes-allocated ,form)&lt;br /&gt;                   (format t "~20S ~20S ~10D ~10D~%" f r permament temporary)))&lt;br /&gt;               body)))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;This let me quite easily write a little test, creating a couple of classes and a generic function:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(defclass foo ()&lt;br /&gt;  ())&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;(defclass bar ()&lt;br /&gt;  ())&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;(defgeneric com (thing))&lt;br /&gt;&lt;br /&gt;(defmethod com (thing)&lt;br /&gt;  (declare (ignore thing))&lt;br /&gt;  'something)&lt;br /&gt;&lt;br /&gt;(defmethod com ((thing foo))&lt;br /&gt;  (declare (ignore thing))&lt;br /&gt;  'foo)&lt;br /&gt;&lt;br /&gt;(defmethod com ((thing bar))&lt;br /&gt;  (declare (ignore thing))&lt;br /&gt;  'bar)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;(defparameter athing nil)&lt;br /&gt;(defparameter afoo (make-instance 'foo))&lt;br /&gt;(defparameter abar (make-instance 'bar))&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;(show-bytes-allocated&lt;br /&gt;  (com athing)&lt;br /&gt;  (com afoo)&lt;br /&gt;  (com abar)&lt;br /&gt;  (com athing)&lt;br /&gt;  (com afoo)&lt;br /&gt;  (com abar))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Here's the output:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Form                 Result                Permament  Temporary&lt;br /&gt;---------------------------------------------------------------&lt;br /&gt;(COM ATHING)         SOMETHING                   192      15716&lt;br /&gt;(COM AFOO)           FOO                          52       1744&lt;br /&gt;(COM ABAR)           BAR                          52       1772&lt;br /&gt;(COM ATHING)         SOMETHING                     0          0&lt;br /&gt;(COM AFOO)           FOO                           0          0&lt;br /&gt;(COM ABAR)           BAR                           0          0&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;So we can see that the first time a generic function is called on a particular thing it goes away and allocates a bunch of stuff, but then subsequent calls to it don't need any more allocations.&lt;br /&gt;&lt;br /&gt;Disassembling (function com) after each call is quite instructive too - you can see how the function is modified each time.  I expect that there's a limit to how many specialisations it'll keep around.  It helps my mental model of generic functions to know that they behave in this way.&lt;br /&gt;&lt;br /&gt;Another interesting thing I found whilst writing it is that nearly every time I'm tempted to use dolist, I always end up actually using mapcar.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22986986-115089465823610332?l=gameylisp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gameylisp.blogspot.com/feeds/115089465823610332/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22986986&amp;postID=115089465823610332' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22986986/posts/default/115089465823610332'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22986986/posts/default/115089465823610332'/><link rel='alternate' type='text/html' href='http://gameylisp.blogspot.com/2006/06/how-much-memory-gets-allocated-when.html' title='How much memory gets allocated when you call a generic function?'/><author><name>Damyan</name><uri>http://www.blogger.com/profile/12580803323346455950</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22986986.post-115055130508243005</id><published>2006-06-17T23:32:00.000+10:00</published><updated>2006-06-21T02:07:40.846+10:00</updated><title type='text'>Silly idea?</title><content type='html'>I wonder if it's worth considering setting up something that'll generate C++ code from sexps?  Similar to the various HTML or HLSL/CG generators.  Might be interesting to think about...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22986986-115055130508243005?l=gameylisp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gameylisp.blogspot.com/feeds/115055130508243005/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22986986&amp;postID=115055130508243005' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22986986/posts/default/115055130508243005'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22986986/posts/default/115055130508243005'/><link rel='alternate' type='text/html' href='http://gameylisp.blogspot.com/2006/06/silly-idea.html' title='Silly idea?'/><author><name>Damyan</name><uri>http://www.blogger.com/profile/12580803323346455950</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22986986.post-115029016020035545</id><published>2006-06-14T22:59:00.000+10:00</published><updated>2006-06-14T23:03:18.426+10:00</updated><title type='text'>Update Functions</title><content type='html'>Ah, it's been a while.&lt;br /&gt;&lt;br /&gt;I managed to get even better performance by precreating all the bitmaps for the cells.  Obvious really, but it's now running pretty well.&lt;br /&gt;&lt;br /&gt;Since the whole point of this exercise is for me to experiment with lisp features I've been experimenting with storing an update and render closure in each cell.  This has worked out really nicely, allowing me to have a more efficient board update when opening up empty cells and also the ability to do neat effects like control the speed that the board opens up.&lt;br /&gt;&lt;br /&gt;So the function below creates an update function that'll expose surrounding cells on the next update:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt; &lt;br /&gt;(defun show-surrounding-cells ()&lt;br /&gt; (make-updatefn (board ix iy) &lt;br /&gt; (do-surrounding-cells (mine-x mine-y board ix iy) &lt;br /&gt;   (let ((cell (aref (board-cells board) mine-x mine-y))) &lt;br /&gt;  (when (cell-mine-count cell) &lt;br /&gt;   (setf (cell-updatefn cell) (update-expose))))) &lt;br /&gt; nil)) &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;It's also possible to create animation effects by using an update function and a render function sharing the same closure:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(defun hit-mine (cell speed) &lt;br /&gt;  (let ((count *cell-size*) &lt;br /&gt;  (delay speed)) &lt;br /&gt;   &lt;br /&gt; (labels &lt;br /&gt;  ((render (bitmap board ix iy left top right bottom cell mouse-inside) &lt;br /&gt;      &lt;br /&gt;     (draw-cell bitmap board ix iy left top right bottom cell mouse-inside) &lt;br /&gt; &lt;br /&gt;     (let ((remain (- *cell-size* count))) &lt;br /&gt;    (alleg:blit *invisible-cell* bitmap &lt;br /&gt;       remain remain &lt;br /&gt;       (+ remain left) (+ remain top) &lt;br /&gt;       (- *cell-size* (* 2 remain)) (- *cell-size* (* 2 remain)))))) &lt;br /&gt; &lt;br /&gt;   (setf (cell-renderfn cell) #'render) &lt;br /&gt; &lt;br /&gt;   (make-updatefn () &lt;br /&gt;  (cond &lt;br /&gt;    ((zerop delay) (decf count) (setf delay speed)) &lt;br /&gt;    (t (decf delay))) &lt;br /&gt;  (if (zerop count) &lt;br /&gt;   (progn &lt;br /&gt;     (setf (cell-renderfn cell) nil) &lt;br /&gt;     nil) &lt;br /&gt;   self))))) &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;So this one makes the invisible cell bitmap shrink to nothingness leaving the new one behind.&lt;br /&gt;&lt;br /&gt;I can create higher-level update functions as well.  One useful one is delay, that just waits a certain number of frames before switching the given function in.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(defun delay-update (count function) &lt;br /&gt;  (make-updatefn () &lt;br /&gt; (decf count) &lt;br /&gt; (if (zerop count) &lt;br /&gt;  function &lt;br /&gt;  self))) &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;However, this leaves open the possibility of setting an update function over the top of another one that might be doing useful work. We can deal with this nicely with a combine update function:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(defun combine-updatefn (fn1 fn2) &lt;br /&gt;  (make-updatefn (board ix iy) &lt;br /&gt; (setf fn1 (when fn1 (funcall fn1 board ix iy)) &lt;br /&gt;    fn2 (when fn2 (funcall fn2 board ix iy))) &lt;br /&gt; (cond &lt;br /&gt;   ((and fn1 fn2) self) &lt;br /&gt;   (fn1 fn1) &lt;br /&gt;   (fn2 fn2) &lt;br /&gt;   (t nil)))) &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This runs both the update functions, eventually removing itself when one of the sub ones finishes.&lt;br /&gt;&lt;br /&gt;As a debugging aid I can print out the current function on each cell, and it should be possible to set it up to inspect a particulary cell by clicking on it.  Very cool potential there.&lt;br /&gt;&lt;br /&gt;The great thing about this is that means I can store arbitrary data on a cell and do processing on it without having to make room for it in my main cell datastrucure.  So by doing this I've decoupled the update logic and animation data from my simple board representation.  Of course this sort of thing isn't limited to lisp, but it's an interesting way to think about it that falls into place quite naturally.&lt;br /&gt;&lt;br /&gt;My latest distraction is trying to get SLIME and CLISP to work better with macro argument lists.  I've been doing some hacking replacing lisp's standard defmacro with my own version that stores away some extra data, but I think the proper solution is going to be modifying CLISP itself.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22986986-115029016020035545?l=gameylisp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gameylisp.blogspot.com/feeds/115029016020035545/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22986986&amp;postID=115029016020035545' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22986986/posts/default/115029016020035545'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22986986/posts/default/115029016020035545'/><link rel='alternate' type='text/html' href='http://gameylisp.blogspot.com/2006/06/update-functions.html' title='Update Functions'/><author><name>Damyan</name><uri>http://www.blogger.com/profile/12580803323346455950</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22986986.post-114490425013608780</id><published>2006-04-13T14:52:00.000+10:00</published><updated>2006-12-03T13:41:03.643+11:00</updated><title type='text'>Profiling and Optimisation</title><content type='html'>I've managed to spend some time profiling.  It turns out that it makes things much easier if everything is put in a package - then you can do slime-profile-package rather than fiddling with profiling each function individually.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/6556/569/1600/profile-20050413.jpg"&gt;&lt;img style="cursor: pointer;" src="http://photos1.blogger.com/blogger/6556/569/320/profile-20050413.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;The first results shows that we're spending most of our time talking through CFFI to get values of variables.  This turned out to be mostly things like *font* and *mouse-x*.  So I've added a system to allow easy updating of these variables through a couple of macros - define-updateable-var and update-var that uses the symbol plist to record a function to execute when updating the variable.  Now I only calculate colors on initialisation and grab the updated version of things like *mouse-x* once per frame.  This has resulted in much better performance - the fan on my laptop doesn't turn on while running it anymore and it seems to hover around 30% of CPU usage.  I've also inlined draw-cell which made quite a big difference.&lt;br /&gt;&lt;br /&gt;The new profile shows a much more evenly distributed set of function calls.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/6556/569/1600/profile-20050413-2.jpg"&gt;&lt;img style="cursor: pointer;" src="http://photos1.blogger.com/blogger/6556/569/320/profile-20050413-2.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I'm going to be spending some time now playing around with cl-emb and cl-who to generate a photo-album style website.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22986986-114490425013608780?l=gameylisp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gameylisp.blogspot.com/feeds/114490425013608780/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22986986&amp;postID=114490425013608780' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22986986/posts/default/114490425013608780'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22986986/posts/default/114490425013608780'/><link rel='alternate' type='text/html' href='http://gameylisp.blogspot.com/2006/04/profiling-and-optimisation.html' title='Profiling and Optimisation'/><author><name>Damyan</name><uri>http://www.blogger.com/profile/12580803323346455950</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22986986.post-114265405058206084</id><published>2006-03-18T14:38:00.000+11:00</published><updated>2006-03-18T14:54:10.596+11:00</updated><title type='text'>Nearly playable...</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/6556/569/1600/minesweeper-20060318.jpg"&gt;&lt;img style="cursor: pointer;" src="http://photos1.blogger.com/blogger/6556/569/320/minesweeper-20060318.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Managed to find some time for some more fiddling. I've made the board display a bit prettier and it detects mouse presses and updates it all. It's dog slow at the moment though - is actually unplayable unless I compile it. Guess it's time to learn about profiling and optimising in lisp.&lt;br /&gt;&lt;br /&gt;A couple of useful macros came out of it:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;   &lt;li&gt;with-board-geometry sets up an environment where a bunch of useful variables are defined - cell-width, total-width, total board area, etc. So the mouse click detection and board drawing code both use this.&lt;/li&gt;   &lt;li&gt;do-all-cells iterates over all the cells in the board and evaluates the given form on them.&lt;/li&gt;   &lt;li&gt;do-surrounding-cells iterates over all the cells surrounding a given cell&lt;/li&gt;   &lt;li&gt;do-steps is a simple wrapper around do that increments a given variable by a certain amount for a given number of times. This is used when drawing the board.&lt;/li&gt; &lt;/ul&gt; So it is nice to have code that looks like this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(do-all-cells (ix iy board)&lt;br /&gt;  (update-cell-visibility board ix iy))&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;(defun add-counts-for-mine (board mine-x mine-y)&lt;br /&gt;"Increment the mine counts for all cells surrounding mine-x mine-y"&lt;br /&gt;(let ((cells (board-cells board)))&lt;br /&gt; (do-surrounding-cells (ix iy board mine-x mine-y)&lt;br /&gt;   (when (cell-mine-count (aref cells ix iy))&lt;br /&gt;  (incf (cell-mine-count (aref cells ix iy)))))))&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22986986-114265405058206084?l=gameylisp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gameylisp.blogspot.com/feeds/114265405058206084/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22986986&amp;postID=114265405058206084' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22986986/posts/default/114265405058206084'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22986986/posts/default/114265405058206084'/><link rel='alternate' type='text/html' href='http://gameylisp.blogspot.com/2006/03/nearly-playable.html' title='Nearly playable...'/><author><name>Damyan</name><uri>http://www.blogger.com/profile/12580803323346455950</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22986986.post-114208330015294617</id><published>2006-03-12T00:20:00.000+11:00</published><updated>2006-03-12T00:22:44.160+11:00</updated><title type='text'>cl-alleg on Sourceforge</title><content type='html'>I've set up a sourceforge project for hosting the Allegro/CFFI stuff: &lt;a href="http://cl-alleg.sourceforge.net/"&gt;http://cl-alleg.sourceforge.net/&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22986986-114208330015294617?l=gameylisp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gameylisp.blogspot.com/feeds/114208330015294617/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22986986&amp;postID=114208330015294617' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22986986/posts/default/114208330015294617'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22986986/posts/default/114208330015294617'/><link rel='alternate' type='text/html' href='http://gameylisp.blogspot.com/2006/03/cl-alleg-on-sourceforge.html' title='cl-alleg on Sourceforge'/><author><name>Damyan</name><uri>http://www.blogger.com/profile/12580803323346455950</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22986986.post-114144296902734542</id><published>2006-03-04T14:20:00.000+11:00</published><updated>2006-03-04T14:29:29.036+11:00</updated><title type='text'>Taking shape</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/6556/569/1600/minesweeper-20060304.jpg"&gt;&lt;img style="cursor: pointer;" src="http://photos1.blogger.com/blogger/6556/569/320/minesweeper-20060304.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;I started getting some of the stuff from Allegro's test.c going but very quickly got bored of that so I've started some actual work on the game itself.&lt;br /&gt;&lt;br /&gt;There's a main loop going that attempts to run an update function 60 times a second and render the screen as often as it can.  (I'm not convinced my version is working quite how I expect it to though!)  I've got a very basic 'button' class that monitors the mouse and works like a button in a GUI.  There's also the simple first-pass at the game logic - storing a minesweeper grid and calculating the number of neighbouring mines and that stuff.&lt;br /&gt;&lt;br /&gt;Something that struck me while writing this is just how natural it feels to work with lexical scoping.  I didn't really think about the fact that I was passing closures to an 'onclick' style function in my button object - it just turned out that way after I wrote it the first way I thought of.  Very nice.&lt;br /&gt;&lt;br /&gt;I'm also looking into setting up somewhere to host the source for the allegro / cffi stuff.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22986986-114144296902734542?l=gameylisp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gameylisp.blogspot.com/feeds/114144296902734542/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22986986&amp;postID=114144296902734542' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22986986/posts/default/114144296902734542'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22986986/posts/default/114144296902734542'/><link rel='alternate' type='text/html' href='http://gameylisp.blogspot.com/2006/03/taking-shape.html' title='Taking shape'/><author><name>Damyan</name><uri>http://www.blogger.com/profile/12580803323346455950</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22986986.post-114086327293666773</id><published>2006-02-25T21:07:00.000+11:00</published><updated>2006-02-25T21:27:52.943+11:00</updated><title type='text'>Hello World!</title><content type='html'>I've got Allegro's exhello.c working from within clisp. It's quite cool to be able to type stuff in a SLIME REPL and get an Allegro window up.&lt;br /&gt;&lt;br /&gt;For what it's worth here's the code:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;;;; The hello world example&lt;br /&gt;(defun test-hello-world ()&lt;br /&gt;(with-allegro&lt;br /&gt;   (progn&lt;br /&gt;     (install-keyboard)&lt;br /&gt;  &lt;br /&gt;     (unless (set-gfx-mode *gfx-autodetect-windowed* 320 200 0 0)&lt;br /&gt;       (set-gfx-mode *gfx-text 0 0 0 0)&lt;br /&gt;       (error "Unable to set graphics mode"))&lt;br /&gt;  &lt;br /&gt;     ;; set_palette(desktop_palette)&lt;br /&gt;  &lt;br /&gt;     (clear-to-color *screen* (make-col 255 255 255))&lt;br /&gt;  &lt;br /&gt;     (with-acquire-screen&lt;br /&gt;         (textout-centre-ex *screen*&lt;br /&gt;                            *font*&lt;br /&gt;                            "Hello, world!"&lt;br /&gt;                            (/ (screen-w) 2)&lt;br /&gt;                            (/ (screen-h) 2)&lt;br /&gt;                            (make-col 0 0 0)&lt;br /&gt;                            -1))&lt;br /&gt;  &lt;br /&gt;     (read-key))))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Things that are slightly different from the straight forward C version are:&lt;br /&gt;&lt;ul&gt;   &lt;li&gt;the with-allegro and with-acquire-screen macros that wrap up the install_allegro / exit_allegro calls inside unwind-protects&lt;/li&gt;   &lt;li&gt;screen-w and screen-h are actually macros (just like they are in the C version) but unlike the C version macros look different whereas in C they just look like variables&lt;/li&gt; &lt;/ul&gt; install_allegro requires a pointer to errno. I couldn't find a way to get hold of that from CFFI, but it looks like passing a NULL pointer works. Dodgy!&lt;br /&gt;&lt;br /&gt;Also read-key doesn't seem to actually work until I've switch focus a few times.  It's fine in full screen mode.  Odd.&lt;br /&gt;&lt;br /&gt;Wrapping stuff up with CFFI is an absolute breeze.  Here's a few examples:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(defcvar "screen" :pointer)&lt;br /&gt;&lt;br /&gt;(defcfun "clear_to_color" :void&lt;br /&gt; (bitmap :pointer)&lt;br /&gt; (color :int))&lt;br /&gt;&lt;br /&gt;(defcfun "acquire_screen" :void)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;CFFI automatically converts the C-style names into more LISP-style ones.  So screen becomes *screen* and clear_to_color becomes clear-to-color.  You can provide your own LISP name as well if you want.  CFFI just smells of quality.&lt;br /&gt;&lt;br /&gt;So what problems did I have?  Well they were all to do with getting set up - once that was done it was a breeze actually hooking things up.&lt;br /&gt;&lt;br /&gt;The first mistake was to try and build Allegro from sources in Microsoft Visual Studio 2005 express.  VS2005 doesn't come with the platform SDK or DirectX SDK and so I had to download and install those.  Then it turned out that the Allegro fix.sh script didn't have the changes for msvc8 that the fix.bat script has.  Then I considered that I'd have to try and set my environment variables up.  Then I downloaded the binary distribution of Allegro for VC8!&lt;br /&gt;&lt;br /&gt;That was my second mistake.  I don't know about manifests and at this point I don't care what they are or why they are.  But I do care that every time I tried to link against alleg42.dll I'd get an error about not being able to find msvcrt80.dll.  This seems to be a well known problem and the quickest fix of course would be to just download the allegro binary compiled in an earlier version of VC.&lt;br /&gt;&lt;br /&gt;Armed with that I tried to get CFFI working.  That needed ASDF so I had to get that working.  Now all of the docs do say how to set up search paths, but it is kinda buried deep.  It took a bit of fiddling, but I finally got them all talking to each other.&lt;br /&gt;&lt;br /&gt;All in all I'm quite pleased with that.  It looks like getting the Allegro interface isn't going to be too hard to do.  I think my next task might be to try and get bits of the main test app up and running.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22986986-114086327293666773?l=gameylisp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gameylisp.blogspot.com/feeds/114086327293666773/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22986986&amp;postID=114086327293666773' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22986986/posts/default/114086327293666773'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22986986/posts/default/114086327293666773'/><link rel='alternate' type='text/html' href='http://gameylisp.blogspot.com/2006/02/hello-world.html' title='Hello World!'/><author><name>Damyan</name><uri>http://www.blogger.com/profile/12580803323346455950</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22986986.post-114083645484335835</id><published>2006-02-25T13:45:00.000+11:00</published><updated>2006-02-25T14:00:54.850+11:00</updated><title type='text'>The beginning....</title><content type='html'>So here I am! I've been writing video games professionally for the last 6 years or so and at the same time have started to get interested in LISP, probably as result of the &lt;a href="http://c2.com/cgi/wiki?SmugLispWeenie"&gt;smug LISP weenies&lt;/a&gt; on c2.com.&lt;br /&gt;&lt;br /&gt;I've got started...I've read &lt;a href="http://www.gigamonkeys.com/book/"&gt;Practical Common Lisp&lt;/a&gt; online and bought a copy of &lt;a href="http://www.paulgraham.com/acl.html"&gt;ANSI Common Lisp&lt;/a&gt;. Of course the next big problem after that is choosing an implementation.  Since I run Windows at home (it's just too convenient to have the same OS at work and at home) I'm not exactly spoiled for choice.  I don't want to use a commercial implementation, so I'm playing around with &lt;a href="http://clisp.cons.org/"&gt;CLISP&lt;/a&gt;, at least until the &lt;a href="http://www.codecomments.com/Lisp/message773548.html"&gt;Windows port of SBCL&lt;/a&gt; becomes more stable.  My rough guess (not based on anything concrete) is that CLISP have the same sort of performance as something like Ruby or Python.  We'll see!&lt;br /&gt;&lt;br /&gt;My first exercise was to get an accounting system for dealing with all the rent at my house written.  Quite simple stuff really, but it got me familiar with writing, reading and editing LISP.  At the same time I found myself playing a lot of multiplayer minesweeper under MSN messenger.  I started thinking that it'd be quite cool to try and write a real-time (ie not turned based) version of this.  So that's my current project, and this blog is going to try and track my progress.&lt;br /&gt;&lt;br /&gt;Current status is a few ideas, and no visible working graphics library for clisp.  That's my first task.  I figured I'd try and get some bindings sorted out for &lt;a href="http://www.talula.demon.co.uk/allegro/"&gt;Allegro&lt;/a&gt;.  Why Allegro?  Well, firstly I've used it before and secondly it was written by my &lt;a href="http://www.talula.demon.co.uk"&gt;mate&lt;/a&gt; and I think he'd find it quite cool to have lisp bindings for it!&lt;br /&gt;&lt;br /&gt;So - I've gotta get Allegro built on my machine and then start hooking up functions for it.  &lt;a href="http://common-lisp.net/project/cffi/"&gt;CFFI&lt;/a&gt; seems to be worth looking at for this.&lt;br /&gt;&lt;br /&gt;Lets see how far I get before I get bored!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22986986-114083645484335835?l=gameylisp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gameylisp.blogspot.com/feeds/114083645484335835/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22986986&amp;postID=114083645484335835' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22986986/posts/default/114083645484335835'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22986986/posts/default/114083645484335835'/><link rel='alternate' type='text/html' href='http://gameylisp.blogspot.com/2006/02/beginning.html' title='The beginning....'/><author><name>Damyan</name><uri>http://www.blogger.com/profile/12580803323346455950</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
