Recently I have been looking for a solution to a particular problem related
to my snek
data
structure. The problem is this:
What if I want to perform a particular action only if a given alteration is applied? Moreover, what if that action depends on changes to the data structure that will not exist until after the alteration has been applied?
A suitable example is a variation of a two-dimensional random walk, with the additional limitation that vertices are not allowed to be too close to any existing vertex. Below is an animation to give you an idea.
One way to implement this is to continuously try to place a new vertex in the vicinity of the previously added vertex. You can keep doing this until you find a free spot, or until you get into a deadlock.
It turns out I had the necessary functionality to solve this all along: custom alterations.
The ability to add your own alterations has been a
part of the design plan for snek
all along. After a bit of
testing I have come to the conclusion that custom alterations are probably
the best and most flexible solution to this problem as well.
Below is an example
using a snek
instance called snk
, and the current
vertex index w
. Also note that the (snek:append-edge?
...)
alteration
will attempt to create a new edge between an existing vertex and a new
point. The important thing to note here is that the point will turn into a
snek
vertex when the alteration has been applied.
; create custom alteration func
(defun do-append-edge-alt* (snk a); append edge if it is not too close
; to any existing vert
(if (<= (length (snek:verts-in-rad snk (snek:append-edge-alt-xy a) rad)) 1); (snek:append-edge-alt ...) returns index of
; the added vert. if the alteration is
; not applied, it returns nil.
(aif (snek:do-append-edge-alt snk a); update if alteration was applied
(setf w it))); override the func that applies
; append edge alterations
(let ((snk (snek:make :alts '((snek:append-edge-alt do-append-edge-alt*))))); initial vert at xy
(setf w (snek:add-vert! snk xy)) (loop for i from 0 below n do (snek:with (snk :zwidth rad); pick a point near w
; w will only be updated if the edge
; is applied
(snek:append-edge? w (add (snek:get-vert snk w) (rnd:in-circ rad)) :rel nil))))
This example extends the existing alteration (snek:append-edge?
...)
. There is obviously nothing stopping you from implementing
completely new alterations. While this might not be a perfect solution, it
seems to solve all the challenges I've encountered so far.
- In fact I have been thinking about this for a few days. Which is embarrassing for a number of reasons ...
- A complete working example can be seen in the repository.
- All alterations are now postfixed with
?
, to indicate that it may or may not be applied.