Exploratory Programming


Interactive Programminging

1. Every Cold Boot Is A Failure

Turning it off and back on again is not how anything good works. Sleep and garbage collection are good. Powering off is death.

Occasionally the odds are made better for a longer, healthier life by killing someone, doing emergency surgeory and then trying to bring them back to life or the scenario where someone has died unexpectedly. As we know from medical dramas and defibrillators. This isn't a general approach to medicine.

So too with computer programs.

1.1. Exploratory Programming

Lisp style is the main lifesaver in this practice.

While the joke is that having a highly unique fancy style of your very own is the lisp style, they tend to what the language tends to- long life in an environment with every possible comfort.

One key feature is not believing we know what success is going to look like in the distant future and so focusing on taking strong steps in the best direction that occurs to us here and now. Less obviously, being able to take big steps quickly seems to be important. This has been called exploratory programming.

I'm going to share a really plain example of twenty minutes of a live video of my own programming (video at the end). Different lispers will be a bit different, but we will have lots of features and goals in common.

1.2. Sticking a description to a symbol

I wanted named rooms, with description text a la https://lambda.moo.mud.org so I named a new source block from within my lisp image

(ed 'screwtapes-room)

(check the video for what that does for me)

and stuck a description property in the plist (property list) of a test room name, screwtapes-room

(setf (getf (symbol-plist 'screwtapes-room) 'description)
      "The room of screwlisp")

} this is also an example of the Big Steps approach I said lispers have found important so I will quickly run through each function inside-out

1.2.1. (symbol-plist 'screwtapes-room)

The lisp image has a special list to keep stuff in for every interned symbol (symbol that has been seen). A plist is an alternating list of =(key-a value-a key-b value-b)= etc.

1.2.2. (getf (symbol-plist 'screwtapes-room) 'description)

Gets description-value from the ='( ... description description-value ...)=

1.2.3. (setf (getf (symbol-plist 'screwtapes-room) 'description) "The room of screwlisp")

setf makes it so =(getf (symbol-plist 'screwtapes-room) 'description)= now getfs ="The room of screwlisp"=.

1.3. Back to the video

I now have an example room name with a description. The lisp image opens interactive prompts if I do want to read and then eval the new snippet I had worked on.

1.4. The frame (lisp windowed application)

when I issued =(ed 'frame)= this source appears:

(define-application-frame moonclimb
    ()
  ((current-room :initform nil :accessor current-room))
  (:panes
   (int :interactor)
   (title :title :title-string "my title")
   (app :application :display-function 'display-current-room))
  (:layouts (default (vertically () title (horizontally () int app )))))

(defun display-current-room (frame pane)
  (format pane "~a" (current-room frame)))

which was the whole program so far. CLIM is the best interactive GUI development gets by the way.

Add a slot, make the names a little better, jiggle layout, say I want the description displayed when it changes, suggest a low height :

(define-application-frame moonclimb
    ()
  ((current-room :initform nil :accessor current-room)
   (current-description :initform nil :accessor current-description))
  (:panes
   (int :interactor)
   (title :title :title-string "my title")
   (current-room :application :display-function 'display-current-room)
   (current-description :application :display-function
                        'display-current-room-description))
  (:layouts (default (vertically () (horizontally (:height 64) current-room title)
                       (horizontally () int current-description )))))

(defun display-current-room (frame pane)
  (format pane "Currently in: ~a" (current-room frame)))

(defun display-current-room-description (frame pane)
    (format pane "Description:~%~a" (current-description frame)))

while incrementally looking at the frame to see how it's going and checking that "change room" prompts for and changes the symbolic room.

1.5. Update change room to update the description

(define-moonclimb-command (com-change-room :menu t :name "change room")
    ()
  (let* ((frame *application-frame*)
         (string (accepting-values () (accept 'string)))
         (symbol (intern (format nil "~@:(~a~)" string))))
    (setf (current-room frame) symbol
          (current-description frame) (getf (symbol-plist symbol) 'description))))

1.6. Start adding more rooms

(setf
   (getf (symbol-plist 'living-room) 'description)
   "Lisdude is out on his feet")

1.7. Epilogue

Turning a computer off and then on again isn't a powerful way to grow programs.

Instead, constructive wandering able to take big steps and with high visibility and interactivity are powerful ways to explore a program's future goals.

https://toobnix.org/w/kTjp7StwkZvdzdgfQwmR6J

Author: screwtape

Created: 2024-08-16 Fri 21:00

Validate

Comments

Log in with itch.io to leave a comment.

(+1)

That’s dope!

(+1)

Thanks <3 

I'm now trying to figure out how I can do (symbol-plist foo)s to your entities + component properties in https://awkravchuk.itch.io/cl-fast-ecs ie so I can use your beam search / A*

(+1)

For example if I have an arbitrary number of room entities and doors to other rooms can be created or removed over time, how should I achieve this?

I guess I could fix the exits to be only of type (member :north :east :south :west :up :down) since that's mostly adhered to anyway and then since your ecs is fast, 

for players solely keep the player-room connection in a property of the player entity and just search what players are in a room at a point in time. Which I guess works for a relatively large small number of players. I guess you did this somewhere I should have looked at already in your games..!

(2 edits) (+1)

Matter of fact, you can use A* w/out ECS library, I’ve made the cl-astar to be fully framework-agnostic. The only problem is it does not support sparse worlds, only dense grids; at least I haven’t designed or tried that case.

If you insist on ECS, I’d start with “current room” component (which perhaps points to the room entity) and put it onto player entity, and then perhaps I’d have “exists” component for rooms with four booleans for each direction maybe.

I don’t think cl-fast-ecs would play nice with symbol-plists, the closest thing to it would be the actual component (you can have arbitrary number of different components set on an entity).

(+1)

Ah, when I referred to using a plist, I meant in sketching component properties I put these properties in the plist as an implementation detail. So I think

(defmacro symbols2ecs (symbols)
 `(ecs:make-object
   ',(loop for symbol in symbols
           for key = (intern (symbol-name symbol) :keyword)
           for plist = (symbol-plist symbol)
           collect (cons key plist))))

Ends up with your spec for me ;p sorry for thinking out loud. I see it's been tested on ECL, I'll figure out why mine wasn't working.

I had an old version of cl-fast-ecs in my source-registry

Right, got it, sorry for misunderstanding :)

(+1)

As to searching, you might find :index feature of component slots usable.

The source is secretly stored as an exportable web page https://codeberg.org/tfw/moonclimb/src/branch/main/scratch.org

Also, my repo for starting a lisp image in emacs: https://codeberg.org/tfw/slimeclimorg/src/branch/main/slime-ecl.org