screwlisp proposes kittens

NicCLIM alpha exposition part iii: Map edit macros

In hindsight, there was a succinct description of these three NicCLIM alpha intro parts. (1) Making a map, (2) put host lisp lambdas in the map and finally (3) map edit macros. (This one).

I guess the map edit macros are the most important because they bridge the map and host lisp. So the map has secret alien technology, and the secret alien technology is given physical form to run rampant in.

A quick book review of the Dungeon Crawler Carl series

If you will allow a diversion, I read the first five-ish books of Dungeon Crawler Carl recently. This genre of scifi has a confusing feature for me in contrast to Stephenson’s Snow Crash and Gibson’s Neuromancer. In Snow Crash’s The Metaverse and Neuromancer’s The Matrix, you could reasonably construe either of those as a science fantasy realm the characters sometimes magically teleport to. However, they are both overtly useful- basically wedding physical intuition and computer usability.

In contrast, Dungeon Crawler Carl’s The Crawl is a sort of post-world-of-warcraft concept of virtual reality, where the player has magic and enhanced stats with all the literal meaning of Lorem Ipsum. Dungeon Crawler Carl does present this meaninglessness of The Crawl’s magic when the character’s body is briefly outside The Crawl, and the character has to physically adjust to not experiencing the super-strength they have inside the game (The Crawl).

Dungeon Crawler Carl does make a move in the Matrix and Metaverse direction by introducing Enhancement Zones, real places where The Crawl’s game master AI is able to give players outside The Crawl limited access to their magic and enhanced stats from inside the game in the physical world.

This is different to The Metaverse and The Matrix, in that The Crawl’s magic is a game feature, whereas in the former two it is an abstraction over real computer programs being used.

In NicCLIM, my intent is that the magic as such of fantasy maps, here including Conway’s game of life in my definition of fantasy, is host common lisp lambda forms literally in the map, and (lisp) wizardry is the NicCLIM map editor’s macro system for directly performing and scripting map actions involving those lambdas. Sufficiently advanced magic is secret alien technology, to invert a phrase.

Starting point

After the NicCLIM alpha parts I and II, we have a game map (actually a normal lisp s-expression file), where symbols can be represented as layered graphics or text in a hextille grid. Structurally, it serendipitously made sense to consider the actual game map as being the second quadrant of the map and to store the lambdas in the fourth quadrant. Perhaps auxiliary data could be stored in the first and third quadrants, though this is future speculation.

I guess you saw parts I and II.

(enclose-map 'gol)

The Plan

EDIT: I decided to just show picking up a lambda using eval and applying it (actually funcall in this case) in the interest of concission. I will add a note about the player application database storage. Then the completed Conway’s game of life game we are moving towards will be separate to this intro part 3, which is already pretty long.

My idea is to use the host lisp lambdas we made in part ii to run a hextille game of life in the left half of the 10x8 game map we originally made.

  1. For the cells in rows 1
6 (indexing from 0)
  2. For cells 1
4 in those rows
  3. For all those cells, write the neighbor count 5 cells to the right in the same row
  4. For all those cells, apply the LIFE rule on the neighbor count into the original cells.

We will effect these by writing a sequence of NicCLIM actions in several stages

  1. Setup
  2. do everyone’s neighbor counts
  3. write back the game of life updates for the neighbor counts

This will perform one game of life update. The hextille game of life rule we wrote was H:B2S34 which I got from Wikipedia.

I am writing this here, now, for the first time, as I think of it for the purpose of this documentation. If you construe more powerful useage idioms for NicCLIM as such, please announce them to me in the Mastodon thread (I will formally name them after you in NicCLIM).

Map edit macs

Hmm, it looks like I was subconsciously making an emacs pun. Memacs.

Example

I noticed that I wrote a lot of exposition in the next section, so let us just do the first bit first and talk about it after.

Jump to the lambda quadrant, the fourth quadrant of the map.

jump 

Pick it up using eval

set cur1 eval
funcall

It puts the result in cursor 2.

Jump to the game map, quadrant 2 and use that lambda

jump
swap
funcall

Jump to the location, put the lambda in cursor 1, funcall the lambda (it gets the current cell as an arguement).

If you do not like playing spot-the-difference, the lambda in cursor 1 replaced cursor 2, which had been the symbol EVAL, with 1, since this cell (with the @ in it) contained LIFE per the lambda form we picked up.

Picking up a lambda form using eval

Since the lambdas exist as s-expressions, to pick up “our copy” of one, we eval the s-expression. This is not a discouraged useage of eval, since we really are saying “Set cursor 2 to be the evaluation of this data s-expression”, which is oddly reminiscent of the roguelike take action. We could alternately pick up the data as data. It is possible to be a bit tricky with what lisp thinks about unevaluated lambda forms, but in practice here I suggest just thinking of the unevaluated form as data and the eval’ed form as being the one suitable for applying or funcalling. The material difference between apply and funcall is essentially that apply takes a list of arguements to the lambda, whereas funcall takes the arguement as an arguement. Both are available because this difference turns out to be quite useful.

After evaluating it, the object we now have in our cursor is unreadable, and could be a closure (i.e. a lambda with enclosed state) as implied by some of the lambdas we wrote in part ii. Closures are very useful.

NB: If you are new to lisp, we can get a lambda expression and readable states out of an unreadable lambda or closure by using function-lambda-expression when we want data again instead.

Calling this a victory

Since I already talked a lot, and this is meant to be an initial exploration, I am going to cease doing new stuff here except the following quick note on ephemeral application database storage.

I introduced the idea of an active player (the player is actually the map’s
 cartographer in this case). Remember that nothing but the map is stored in the map, so this storage is not persisted.

Ephemeral storage

(enclose-map 'gol)

Basically

Change Player screwlisp
set cur1 foo
swap
set cur1 bar
setsgets

this saves FOO⼕BAR for SCREWLISP.

Gets

This replaced FOO in cursor 1 with screwlisp’s saved value for FOO, which is BAR.

Conclusions

In part 3, we minimally saw picking up a lambda form, possibly a closure, for useage using eval. (Actually, a map editor command named com-eval) in practice, where we jumped to a live cell in the nascent game-of-life, and funcalled the lambda to see that this live cell would count for 1 (in the neighbors count). Cursor 1 gets applied/funcalled to the current cell, denoted with an @. The result gets placed in cursor 2.

Then we saw that a “current player” can ephemerally store values using setsgets, and retrieve stored values (per player) using gets. These values are not part of the map, so they are stored in the current lisp image’s memory, similar to how the unreadable compiled lambda in the cursor will not be stored as part of the map.

Hence we can

  1. Make a map (symbols/layered pictures in hextille)
  2. Literally put host lisp lambdas as map data
  3. Pick up (eval) those lambdas and apply/funcall them in the map
  4. Bonus: Ephemeral per-player storage.

The complete game of life example, which will basically be repeating and composing these activities I have separated out from this three part alpha announcement.

The only feature not pictured that is actually included and ~ finished in the alpha sense is the spacetime boxes, which are a way of syncronising distributed maps advancing through time loosely based on Ken Olum’s c. 2025 ANSI CL supercomputing at Tuft astrophysics. 4D spacetime volume propagation as multiplayer syncronisation is a slightly heavy topic that I am still exploring idioms for.

Fin.

See you on the Mastodon!

screwlisp proposes kittens