---
layout: ../Site.layout.js
---
# (lisp)Games As Knowledge - plant-insect-bird post-mortem
In the end, my [lispgamejam25 submission](https://itch.io/jam/spring-lisp-game-jam-2025/rate/3546880) was two hours of implementing a trivial random walk. On the other hand, this was two hours of representing a random walk as a conjunction of disparate pieces of knowledge, some of which were arbitrary lisp programs, and some of which are a sitcalc oriented extension to first order logic. Let us, one more time and in painstaking detail review what this knowledge was and how it was created and accessed.
## The knowledgebase to store the knowledge
### Code
```
crek game-kb
loadk game-kb
setk game-kb
```
### Details
Entered interactively. This seems reasonable to create, load, and set as active the knowledge that will constitute a game.
## Add a place for types and functions
### Code
```
crefil types-and-fun
loadk types-and-fun
```
### Details
Entered interactively. Creating an entityfile to store entities. The idea is that this entityfile will hold type definitions (`thingtype`s) and functions relating to those types as a common resource shared by other entityfiles in this knowledgebase.
## Defining new type entities
### Code
```
put organism type thingtype
put organism attributes {row col map sensor-range}
addmember (get types-and-fun contents) organism
put plant type thingtype
put plant attributes {row col map sensor-range}
put plant subsumed-by {organism}
addmember (get types-and-fun contents) plant
put insect type thingtype
put insect attributes {row col map sensor-range}
put insect subsumed-by {organism}
addmember (get types-and-fun contents) insect
put tile type thingtype
put tile attributes {row col contains}
addmember (get types-and-fun contents) tile
writefil types-and-fun
loadk types-and-fun
```
### Details
Of course, the `insect` type got written out of my gamejam time budget as well. `subsumed-by` seems not very useful so far, but I understand it to be more a piece of commentary that such that in a different context, where a type `organism` is being refered to, apparently disjoint to this game, `organism` might be able to be understood as subsuming the `plant` and `insect` types here. My plant definition could have and probably should have been:
```
put plant type thingtype
put plant subsumed-by {organism}
put plant attributes (get organism attributes)
addmember (get types-and-fun contents) plant
```
or more generally
```
put plant type thingtype
put plant subsumed-by {organism}
put plant attributes (union (get organism attributes) {extra, plant, attributes})
addmember (get types-and-fun contents) plant
```
I think that the reason you do not delete attributes as such (our KRF only provides `union`) is that an unset, i.e. `nil` attribute is understood to be a lack of that feature. In fact `attributes` literally means if-these-are-present-their-values-must-be-persisted. A whale's `legs` attribute would be `nil`. It is reasonable that a whale's known attributes contains legs because whales are closely related to horses, which have legs. One could imagine a whale re-evolving a meaningful value for legs.
## `entityfile` for tracking particular organisms
### Code
```
crefil organisms
loadk organisms
put dandelion-01 type plant
put dandelion-01 row 1
put dandelion-01 col 2
put dandelion-01 map test-map
addmember (get organisms contents) dandelion-01
writefil organisms
```
### Details
A new catch-all location for any `entity` of `type`, `organism` and creating a first particular organism.
## Add a `tile`d 'test-map' organisms might be in
### Code
```
crefil test-map
loadk test-map
. (defparameter *tiles-in* (loop :for idx :below 25 :for (row col) := (multiple-value-list (truncate idx 5)) :collect (intern (format nil "tile-~d-~d" row col))))
. ;; cle uses readline. Sorry about the one-liners.
. (loop :for tile :in *tiles-in* :do (setf (get tile 'type) 'tile))
. (setf (get 'test-map 'contents) `(seq& ,(append '(test-map) *tiles-in*)))
. (loop :for idx :from 0 :for (row col) := (multiple-value-list (truncate idx 5)) :for tile :in *tiles-in* :do (setf (get tile 'row) row (get tile 'col) col))
writefil test-map
```
### Details
Here, I have to say I am a little shakier. I respect that `(cle)` is readline based. I think that similarly to `eev`, the intent is to stop people from introducing lengthy data via the interactive interface. On the other hand, as turns up in `shell` useage, I basically want to use `loop` to auto-populate all the tile entities to make up a rectangular map using the access to ansi common lisp, the extremely high level implementation language of our KRF. So far as shell one-liners are acceptable, I think this is an acceptable useage. Ideally each line would be completely readable as a sentence. I guess it depends how deep into lisp you are for how readable the loop facility is. I could probably have written those neater too.
## A plant propagating function
### Code
```
put living-life type lispdef
addmember (get types-and-fun contents) living-life
writefil types-and-fun
```
doing this interactively stubs this inside `Game/types-and-fun.leo`:
```
---------------------------------------------------------
-- living-life
[: type lispdef]
[: latest-rearchived nil]
```
into which I `lisp-mode` wrote:
```
---------------------------------------------------------
-- living-life
[: type lispdef]
[: latest-rearchived nil]
(leodef live-life live-life ()
(loop :for organism :in (cdadr (get 'organisms 'contents))
:do
(case (get organism 'type)
(plant
(let* ((new-name (gensym "dandelion-"))
(prev-row (get organism 'row))
(prev-col (get organism 'col))
(tile (intern
(format nil "tile-~d-~d"
prev-row
prev-col)))
(new-row (+ prev-row
(1- (random 3))))
(new-col (+ prev-col
(1- (random 3))))
(new-tile
(intern
(format nil "tile-~d-~d"
new-row
new-col))))
(when (and (get new-tile 'type)
(null
(get new-tile
'contains)))
(setf
(get new-tile 'contains)
new-name
(get new-name 'row) new-row
(get new-name 'col) new-col
(get new-name 'type) 'plant)
(nconc
(cadr (get 'organisms 'contents))
`(,new-name))))))))
```
### Details
This is the flow when not entering interactive one-liners. The flip from writing `(get .thing foo)` to the lisp exact equivalent `(get 'thing 'foo)` is a bit jarring but the use of `cadr` is not. This is because loaded objects can be `cdadr`ed to interactively, to check that your guess was right / feel around a little bit for where you are trying to get. This is a somewhat bizarre point of interactive lisp useage that Sandewall leaned in to.
My interpretation of typed programming was to introduce `(case (get thing 'type) (plant '(do some plant type things)))` reflecting that we cannot `(typecase thing (plant ..))` because `type` is simply a key/value in `thing`'s `symbol-plist` in lisp terms, and they have different useages.
I used `when` on a hypothetical `new-tile`'s `type` to logically filter out tiles that do not exist.
## "Rendering" to ascii
### Code
```
put render type lispdef
addmember (get types-and-fun contents) render
writefil types-and-fun
```
similarly to `live-life`.
```
---------------------------------------------------------
-- render
[: type lispdef]
[: latest-rearchived nil]
(leodef do-render do-render ()
(loop :for tile :in (cadr (get 'test-map 'contents))
:for idx :from 0
:for (row col) :=
(multiple-value-list
(truncate idx 5))
:for thing := (get tile 'contains)
:when (zerop col) :do
(terpri)
:when thing :do
(princ "*")
:else :do
(princ #\")
:finally (terpri)))
```
### Details
A simple lisp `loop` to show the `tile`s to standard output for a magic-number-5 width grid on the hardcoded-in-name `test-map` entityfile contents. Mistakenly prints a final " character. Useable either as an action or in lisp again.
## The game
### Code
```
loadk types-and-fun
. (loop :repeat 5 :do (live-life))
```
### Details
I am not sure how many steps I triggered interactively, about five. The grid after which was
```
ses.052) do-render
""*"*
*****
**""*
*""""
*""""
"
ses.053)
```
# Broad overview
This was not very many interactive steps, as expected to achieve the small task: A persisted random walk of dandelions growing in a grid field. Key attributes were the persisted nature, and the inclusion of the two lisp definitions as pieces of the data being persisted.
My initial plans for a fancy-research game overlooked that I did not know how this simple scenario truly shook out before doing it in this jam. In hindsight, the use of the three entityfiles is trivial. The plant-eating `insect`s could be defined into the `case` statement in `live-life`. And `sensor` type of thing with a `last-reading` and `scan` values could be added and integrated algorithmically to insects and plants to become more `Vehicles`-ish as was originally planned.