20200210 quil sketch: hesitant wobblers

Draft of 2020.02.10

May include: programmingClojurequil&c.

This sketch is a departure from the ones I worked on last week, and relatively simple because I wasted much of my coding time today down in the guts of the navigation-2d middleware, learning that what I thought were bugs are just poorly-documented features….

In this simple sketch, I’ve dropped 25 circles in random positions, which will eventually represent “agents” who are trying to move to an optimal position. You can see a few sketchy lines connecting some of them: each agent is connected to one or more others that are its “objects of desire”. When the code is written (another day), each agent will “want” to move towards a point that’s an ideal (close) distance from each of its personal object(s) of desire.

But it will also “want” to be maximally far away from all the other undesired agents. So it can, you know, be alone with its true loves.

If you glance at the graph, you might begin to suspect how this network is asymmetric, and what that might entail—at least once this goal-seeking movement is implemented. For the moment, the placeholder movement algorithm is set to be “wiggle back and forth, with wraparound”.

It’ll do for today.



(ns negative-space-quil.core
  (:require [quil.core :as q :include-macros true]
            [quil.middleware :as m]
            [clojure.set :as s]

(defrecord Agent [idx hue x y neighbors others])

(defn random-neighbors
  [idx how-many pool-size]
  (let [pool (remove #{idx} (range pool-size))]
    (take how-many (shuffle pool))

(defn rand-node
  [idx connectedness pool-size]
  (let [neighbors (random-neighbors idx connectedness pool-size)]
      idx ; idx
      (rand-int 256) ; hue
      (rand-int (q/width)) ; x
      (rand-int (q/height)) ; y
      neighbors ; neighbors
      (remove (conj neighbors idx) (range pool-size)) ; others

(defn setup []
  (q/frame-rate 30)
  (q/color-mode :hsb)
  (q/blend-mode :blend)
  (q/ellipse-mode :radius)
  (q/image-mode :center)
    (map #(rand-node % 1 25) (range 25))
    :spring-distance 30
    :hooke-constant 0.1

(defn update-state
  (let [dudes (:dudes state)]
        #(update % :x (fn [x] (mod (+ (rand-int 3) -1 x) (q/width))))

(defn draw-state [state]
  (let [dudes (:dudes state)]
    (q/background 200)
    (doseq [dude dudes]
      (q/fill (q/color (:hue dude) 255 255 150))
      (q/ellipse (:x dude) (:y dude) 10 10)
      (q/stroke 100 100)
      (doseq [nb (:neighbors dude)]
        (q/line (:x dude) (:y dude) (:x (nth dudes nb)) (:y (nth dudes nb)))

; this function is called in index.html
(defn ^:export run-sketch []
  (q/defsketch negative-space-quil
    :host "20200210-quil"
    :size [300 300]
    :setup setup
    :update update-state
    :draw draw-state
    :middleware [m/fun-mode]

; uncomment this line to reset the sketch:
; (run-sketch)