---
layout: ../Site.layout.js
---
# Leonardo Calculus Knowledge Representation: Running and rendering the Plant Insect Bird simulation once

๐Ÿชด๐ŸŒณ๐ŸŽ„๐ŸŒฒ๐ŸŒดโธ™๐Ÿƒ๐Ÿฅฌ๐Ÿฅ•๐Ÿฅฆ๐Ÿ๐Ÿ€๐Ÿ‚๐Ÿ‰๐Ÿ๐ŸŽ๐Ÿ๐ŸŒต๐ŸŒฟ๐Ÿฅ—๐Ÿฅ’๐Ÿฅ”๐Ÿˆ๐ŸŒ๐ŸŽ‹๐Ÿ„๐Ÿชต๐Ÿฅ๐Ÿซ๐Ÿซ’๐Ÿ ๐Ÿ“๐Ÿฅฅ๐Ÿ‹๐Ÿ‡๐Ÿฅœ๐Ÿชท๐Ÿ‘๐Ÿ๐ŸŽƒ๐Ÿฅ’๐ŸŒพ๐ŸŒฝ๐ŸŒนโš˜๐Ÿ’ฎ๐Ÿ’๐ŸŽ•๐Ÿฅ€๐Ÿถ๐Ÿต๐ŸŒฑ๐ŸŒป๐ŸŒท๐Ÿซ˜
๐Ÿ›๐Ÿชฑ๐Ÿฆ‹๐Ÿชฒ๐Ÿ๐Ÿชฐ๐Ÿž๐Ÿœ๐ŸฆŸ๐Ÿ•ท๐Ÿฆ€๐Ÿฆž๐Ÿชณ๐ŸŒ๐Ÿš๐Ÿฆ‚๐Ÿ•ธ๐Ÿฆ๐Ÿงš
๐Ÿฅ๐Ÿฆ๐Ÿฆ…๐Ÿ”๐Ÿ“๐Ÿฆ†๐Ÿฆข๐Ÿค๐Ÿฃ๐Ÿฆƒ๐Ÿ•Š๐Ÿง๐Ÿฆ‰๐Ÿฆซ๐Ÿฆฉ๐Ÿฆš๐Ÿฆค

Alright, now getting to video visualization of our Plant Insect Bird [Braitenbergian simulation](/complex/book-review-braitenberg-vehicles) game. When freshly starting emacs, I visited [the last article](/lispgames/LCKR-completing-the-simulation/) in emacs eww in order to just-press-F8-over-and-over in eev style to load everything, though I found that eev ditches the non-printing eev-mode red star character, so I had to make the buffer editable and write that in myself.

I think most of what's remaining to do is add a fall-off-table-edge action, maybe called `deluge`, that `nil`s organisms outside some bounding rectangle to run periodically, so that I don't experience infinite-ish entity growth. Then, since the leonardo system enforces latin1 script, I was thinking about adding a char-code property to organism, actually, let's just do that here and now (setup from the last article I linked)

## Add display char-code attribute to `organism`

`addmember (get organism attributes) char-code`

`writefil organisms`

`loadk organisms`

`(get organism attributes)`

```
ses.016) loadk organisms
Load-ef: organisms at ../../../demus/Organisms/organisms.leo

ses.017) (get organism attributes)
 => {x-position y-position starvation-rate current-direction opening-angle sensor-scale natality-rate mortality-rate propagation-distance eating-distance lethality-rate prey-species sensor-weights char-code}
```

where I guess the video display, whatever, will use [`code-char`](http://lispm.de/docs/clhs/HyperSpec/Body/f_code_c.htm#code-char) on the organism's `char-code` attribute. So ๐Ÿ˜บ is `128570`.

```
CL-USER> (princ (code-char 128570))
๐Ÿ˜บ
#\\U01F63A
```

in a unicode-extended lisp. (Our Leonardo system is strictly latin1, but video is going to be external to our individual.).

## `deluge` action for enforcing falling-off-the-table

`put deluge type lispdef`

`addmember (get organisms contents) deluge`

`writefil organisms`

And writing it into `#p"~/leocommunity/Plantworld/demus/Organisms/organisms.leo"`:

```
---------------------------------------------------------
-- deluge

[: type lispdef]
[: latest-rearchived nil]

(leodef deluge deluge (xmin xmax ymin ymax)
(loop
 :for organism :in (cdadr (get 'world 'contents))
 :unless (and (< xmin (get organism 'x-position) xmax)
            (< ymin (get organism 'y-position) ymax))
 :do (setf (get organism 'type) nil)))

ooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
```

`writefil organisms`

`loadk organisms`

hopefully that will do.

```
ses.026) (get world contents)
 => <world>

ses.027) put parrot type bird
put: parrot type bird

ses.028) put parrot x-position -10
put: parrot x-position -10

ses.029) put parrot y-position 0
put: parrot y-position 0

ses.030) addmember (get world contents) parrot

ses.031) deluge -5 5 -5 5

ses.032) (get parrot type)
 => nil
```

seems so.

## A literally so `random-new-organism` maker

`put random-new-organism type lispdef`

`addmember (get organisms contents) random-new-organism`

`writefil organisms`

```
---------------------------------------------------------
-- random-new-organism

[: type lispdef]
[: latest-rearchived nil]

(leodef random-new-organism random-new-organism ()
       (let* ((type (nth (random 3)
                         '(plant insect bird)))
              (x-position (random 100))
              (y-position (random 100))
              (starvation-rate (random 100))
              (current-direction
                (nth (random 8)
                     '(e ne n nw w sw s se)))
              (opening-angle
                (+ 23 (random (- 180 23))))
              (sensor-scale
                (1+ (random 8)))
              (natality-rate
                (random 100))
              (mortality-rate
                (random 100))
              (propagation-distance
                (1+ (random 8)))
              (lethality-rate
                (random 100))
              (prey-species
                `(set&
                  ,(nth
                    (random 8)
                    '(()
                      (plant)
                      (insect)
                      (bird)
                      (plant insect)
                      (plant bird)
                      (bird insect)
                      (plant bird insect)))))
              (sensor-weights
                `(seq&
                  (
                   (seq& (plant ,(- (random 10) 5)))
                   (seq& (insect ,(- (random 10) 5)))
                   (seq& (bird ,(- (random 10) 5)))
                   )))
              (char-code
                (let ((plants '(129716 127795 127876 127794
                                127796 11801 127811 129388
                                129365 129382 127809 127808
                                127810 127817 127823 127822
                                127821 127797 127807 129367
                                129362 129364 127816 127820
                                127883 127812 129717 129373
                                129744 129746 127840 127827
                                129381 127819 127815 129372
                                129719 127825 127824 127875
                                129362 127806 127805 127801
                                9880 128174 128144 127893
                                129344 127990 127989 127793
                                127803 127799 129752 129361))
                      (insects
                        '(128027 129713 129419 129714 128029
                          129712 128030 128028 129439 128375
                          129408 129438 129715 128012 128026
                          129410 128376 129424 129498))
                      (birds
                        '(128037 128038 129413 128020 128019
                          129414 129442 128036 128035 129411
                          128330 128039 129417 129451
                          129449 129434 129444)))
                  (case type
                    (plant
                     (nth (random (length plants)) plants))
                    (insect
                     (nth (random (length insects))
                          insects))
                    (bird
                     (nth (random (length birds))
                          birds)))))
              (sym (intern
                    (symbol-name
                     (gensym (symbol-name type))))))
         (setf (symbol-plist sym)
               `(type
                 ,type
                 x-position ,x-position
                 y-position ,y-position
                 starvation-rate ,starvation-rate
                 current-direction ,current-direction
                 opening-angle ,opening-angle
                 sensor-scale ,sensor-scale
                 natality-rate ,natality-rate
                 mortality-rate ,mortality-rate
                 propagation-distance ,propagation-distance
                 lethality-rate ,lethality-rate
                 prey-species ,prey-species
                 sensor-weights ,sensor-weights
                 char-code ,char-code))
         (nconc (cdadr (get 'world 'contents))
                  (list sym))
         (print sym)
         (print (symbol-plist sym))
         (values sym)))

ooooooooooooooooooooooooooooooooooooooooooooooooooooooooo

```

Got slightly carried away just brainstorming unicode codes for plants/insects/birds.

## Annoyingly non-portable copy-to-gnu-emacs definition

```
(defun world-to-emacs () (swank:eval-in-emacs `(setq *world* ',(loop :for thing :in (cdadr (get 'world 'contents)) :collect (symbol-plist thing)))))
```

Since cle uses `'read-line`, we need to pitch just one line. Sorry for the overflowing line.

## A bunch of new organisms

First off, I noticed that `mortality-rate` is overwhelmingly high, and secondarily, cannibalistic organisms will eat themselves if they are the oldest available prey-species at hand.

Still, I felt like it was possible that an unattended search would turn up some quasistable alien ecologies.

I might use the `senesce` action to control the total population size- i.e. if there are more than a thousand entities, call senesce until there are below a thousand entities. This means there is differential survival rates between species of culls.

Maybe tomorrow, we can look at some planned dynamics as well as the silliness of these random ones. I'm pretty sure that a mixture of very prolific plants with a high propagation-range + short-sighted/short-propagation herbivorous insects will naturally form quasi-stable wavefronts, that would then be able to host bird species. But it would be fun if something emerges out of randomness.

```
ses.065) (get world contents)
 => <world parrot>

ses.066) random-new-organism

PLANT39744
(type plant x-position 20 y-position 23 starvation-rate 96 current-direction nw
opening-angle 170 sensor-scale 4 natality-rate 57 mortality-rate 74
propagation-distance 1 lethality-rate 54 prey-species (set& (plant bird))
sensor-weights (seq& ((seq& (plant 0)) (seq& (insect -3)) (seq& (bird 3))))
char-code 127820) PLANT39744

ses.067) (get world contents)
 => <world parrot PLANT39744>

ses.068) random-new-organism

PLANT39761
(type plant x-position 96 y-position 43 starvation-rate 75 current-direction e
opening-angle 143 sensor-scale 7 natality-rate 19 mortality-rate 76
propagation-distance 3 lethality-rate 42 prey-species (set& (plant insect))
sensor-weights (seq& ((seq& (plant -2)) (seq& (insect -4)) (seq& (bird 3))))
char-code 129344) PLANT39761

ses.069) random-new-organism

BIRD39770
(type bird x-position 74 y-position 41 starvation-rate 76 current-direction sw
opening-angle 27 sensor-scale 6 natality-rate 17 mortality-rate 13
propagation-distance 4 lethality-rate 83 prey-species (set& (plant bird))
sensor-weights (seq& ((seq& (plant 4)) (seq& (insect 4)) (seq& (bird 3))))
char-code 129436) BIRD39770

ses.070) random-new-organism

INSECT39779
(type insect x-position 71 y-position 60 starvation-rate 26 current-direction
nw opening-angle 50 sensor-scale 8 natality-rate 2 mortality-rate 5
propagation-distance 2 lethality-rate 46 prey-species (set& (bird insect))
sensor-weights (seq& ((seq& (plant 4)) (seq& (insect 2)) (seq& (bird -3))))
char-code 129408) INSECT39779

ses.071) random-new-organism

INSECT39788
(type insect x-position 81 y-position 1 starvation-rate 97 current-direction ne
opening-angle 172 sensor-scale 7 natality-rate 38 mortality-rate 51
propagation-distance 7 lethality-rate 87 prey-species (set& (plant))
sensor-weights (seq& ((seq& (plant 1)) (seq& (insect -4)) (seq& (bird 4))))
char-code 129408) INSECT39788

ses.072) random-new-organism

INSECT39797
(type insect x-position 46 y-position 52 starvation-rate 5 current-direction ne
opening-angle 170 sensor-scale 1 natality-rate 50 mortality-rate 29
propagation-distance 2 lethality-rate 90 prey-species (set& (plant bird))
sensor-weights (seq& ((seq& (plant 0)) (seq& (insect -2)) (seq& (bird -5))))
char-code 128026) INSECT39797

ses.073) (get world contents)
 => <world parrot PLANT39744 PLANT39761 BIRD39770 INSECT39779 INSECT39788 INSECT39797>

```

# Actually driving the simulation

I guess I am going to sit in an embeddable common lisp image, and drive the Plantworld individual via the emacs-server, and print the state of the world.

## eepitch-send (emacs lisp)

[Like before](/complex/eepitch-send/)

```
(defun eepitch-send
   (buffername line)
 (setq eepitch-buffer-name buffername)
 (setq line (eepitch-preprocess-line line))
 (eepitch-prepare)
(eepitch-line line))
```

## eepitch (common lisp)

but in this case I need to send strings, since the leonardo calculus often doesn't manifest in normal-looking s-expressions.

` (setq eepitch-buffer-name "*slime-repl ECL*")`

`'a`

```
(defun e-e-str (buffername line)
 "'external-eepitch-send'
buffername      string (emacs buffer name string)
line            string (as eepitch)
"
 (require "asdf")
 (uiop:launch-program
  (let ((*print-pretty* nil))
   (format
     nil
     "emacsclient --eval '(eepitch-send ~s \\"~a\\")'"
buffername line))))
```

```
CL-USER> (e-e-str "*slime-repl ECL*" "`foo")
#<a UIOP/RUN-PROGRAM::PROCESS-INFO 0x7f9b62824a00>
CL-USER> `foo
FOO
CL-USER>
```

everything seems to be going according to plan. However, this article has been a kind of run-on do-everything-that-hasn't-been-done, so let us try and wrap things up for now.

# Print the world

## Copy the world file to emacs

` (setq eepitch-buffer-name "*slime-repl ECL*")`

`(e-e-str "*slime-repl clisp*" ". (world-to-emacs)")`

` (setq eepitch-buffer-name "*slime-repl ECL*")`

`(swank:eval-in-emacs '*world*)`

Well, it's a hassle that those symbols got interned in `SWANK-IO-PACKAGE`.


`*world*`

```
(defun interpret-world (plists)
 (loop
  :with x-position
  := (intern "X-POSITION" "SWANK-IO-PACKAGE")
  :with y-position
  := (intern "Y-POSITION" "SWANK-IO-PACKAGE")
  :with char-code
  := (intern "CHAR-CODE" "SWANK-IO-PACKAGE")
  :for plist :in plists
  :collect
  `((,(getf plist x-position) ,(getf plist y-position))
    ,(code-char (getf plist char-code)))))

```

=>

```
(((20 23) #\\U01F34C) ((96 43) #\\U01F940) ((74 41) #\\U01F99C)
((71 60) #\\U01F980) ((81 1) #\\U01F980) ((46 52) #\\U01F41A))
```

of which, I can just print something like that. I recall the enclosure is 100x100.

```
(defun print-world (alist)
 (loop :for y :below 100 :do
       (loop
        :for x :below 100
        :for ch := (cadr (assoc `(,x ,y) alist
                                :test 'equal))
        :if ch :do (princ ch)
        :else :do (princ #\\Space)
        :finally (terpri))))
```
so.
```

                                                                                ๐Ÿฆ€





















                   ๐ŸŒ

















                                                                         ๐Ÿฆœ

                                                                                               ๐Ÿฅ€








                                             ๐Ÿš







                                                                      ๐Ÿฆ€
```

Let's call this here, we implemented rendering states of the world in a separate lisp.

# Conclusion

We saw our way to operating and accessing the Leonardo system simulation from a different, embeddable common lisp image in the same emacs, which is fundamental progress. We were able to render it.

The `(random 100)` mortality rates are very high: But maybe `senesce` can be repurposed as a randomly weighted culling. And there are oddities like cannibalistic species eating themselves.

I think this is the last of the desperate-scramble articles, given that there is a rendered unicode crab visible slightly up from here we got *somewhere*. It seems like all that is left tomorrow is to practice using our simulation, which should be more sane for you to read (sorry about your sanity hitherto).

# Fin.

See you [on the Mastodon thread to talk about it](https:/gamerplus.org/@screwlisp).