---
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.