ref: 6572c456f7cdf6f8aaaf361e618b41816084a7ae
author: rodri <rgl@antares-labs.eu>
date: Tue Jun 9 18:39:37 EDT 2020
initial commit. first stages of simulation, per-second steps avoiding the jail bars.
--- /dev/null
+++ b/main.c
@@ -1,0 +1,259 @@
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include <draw.h>
+#include <mouse.h>
+#include <keyboard.h>
+#include <geometry.h>
+
+enum {
+ TERMINALV = 20
+};
+
+enum {
+ Cbg,
+ Cfg,
+ NCOLOR
+};
+
+typedef struct Bird Bird;
+typedef struct Flock Flock;
+
+struct Bird
+{
+ Point2 p, v;
+ Image *color;
+};
+
+struct Flock
+{
+ Bird *birds;
+ int nbirds;
+ Rectangle jail;
+
+ void (*separate)(Flock*);
+ void (*align)(Flock*);
+ void (*cohesion)(Flock*);
+ void (*step)(Flock*);
+};
+
+RFrame worldrf;
+Image *pal[NCOLOR];
+Flock *flock;
+
+void flockseparate(Flock*);
+void flockalign(Flock*);
+void flockcohesion(Flock*);
+void flockstep(Flock*);
+
+Flock*
+newflock(int nbirds, Rectangle jail)
+{
+ Flock *f;
+ Bird *b;
+
+ f = malloc(sizeof(Flock));
+ if(f == nil)
+ sysfatal("malloc: %r");
+ setmalloctag(f, getcallerpc(&nbirds));
+ f->birds = nil;
+ f->nbirds = 0;
+ f->jail = jail;
+ f->separate = flockseparate;
+ f->align = flockalign;
+ f->cohesion = flockcohesion;
+ f->step = flockstep;
+
+ while(nbirds--){
+ f->birds = realloc(f->birds, ++f->nbirds*sizeof(Bird));
+ if(f->birds == nil)
+ sysfatal("realloc: %r");
+ setrealloctag(f->birds, getcallerpc(&nbirds));
+ b = &f->birds[f->nbirds-1];
+ b->p = Pt2(frand()*Dx(jail),frand()*Dy(jail),1);
+ b->v = Vec2(cos(frand()*2*PI),sin(frand()*2*PI));
+ b->v = mulpt2(b->v, TERMINALV);
+ b->color = pal[Cfg];
+ }
+
+ return f;
+}
+
+void
+flockseparate(Flock *)
+{
+}
+
+void
+flockalign(Flock *)
+{
+}
+
+void
+flockcohesion(Flock *)
+{
+}
+
+void
+flockstep(Flock *f)
+{
+ static double Δt = 1;
+ Bird *b;
+
+ //f->separate(f);
+ //f->align(f);
+ //f->cohesion(f);
+ for(b = f->birds; b < f->birds + f->nbirds; b++){
+ b->p = addpt2(b->p, mulpt2(b->v, Δt));
+ if(b->p.x < 0){
+ b->p.x = 0;
+ b->v.x = -b->v.x;
+ }
+ if(b->p.y < 0){
+ b->p.y = 0;
+ b->v.y = -b->v.y;
+ }
+ if(b->p.x > Dx(f->jail)){
+ b->p.x = Dx(f->jail);
+ b->v.x = -b->v.x;
+ }
+ if(b->p.y > Dy(f->jail)){
+ b->p.y = Dy(f->jail);
+ b->v.y = -b->v.y;
+ }
+ }
+}
+
+Point
+toscreen(Point2 p)
+{
+ p = invrframexform(p, worldrf);
+ return Pt(p.x,p.y);
+}
+
+Point2
+fromscreen(Point p)
+{
+ return rframexform(Pt2(p.x,p.y,1), worldrf);
+}
+
+void
+initpalette(void)
+{
+ pal[Cbg] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x000000ff);
+ pal[Cfg] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xffffffff);
+}
+
+void
+redraw(void)
+{
+ Bird *b;
+
+ lockdisplay(display);
+ draw(screen, screen->r, pal[Cbg], nil, ZP);
+ for(b = flock->birds; b < flock->birds + flock->nbirds; b++){
+ ellipse(screen, toscreen(b->p), 2, 2, 0, b->color, ZP);
+ }
+ flushimage(display, 1);
+ unlockdisplay(display);
+}
+
+void
+resized(void)
+{
+ lockdisplay(display);
+ if(getwindow(display, Refnone) < 0)
+ sysfatal("resize failed");
+ unlockdisplay(display);
+ worldrf.p = Pt2(screen->r.min.x,screen->r.max.y,1);
+ flock->jail = Rect(0,0,Dx(screen->r),Dy(screen->r));
+ redraw();
+}
+
+void
+mouse(Mouse)
+{
+}
+
+void
+key(Rune r)
+{
+ switch(r){
+ case Kdel:
+ case 'q':
+ threadexitsall(nil);
+ case ' ':
+ flock->step(flock);
+ break;
+ }
+}
+
+void
+usage(void)
+{
+ fprint(2, "usage: %s [-n nbirds]\n", argv0);
+ exits("usage");
+}
+
+void
+threadmain(int argc, char *argv[])
+{
+ Mousectl *mc;
+ Keyboardctl *kc;
+ Rune r;
+ char *s;
+ int nbirds;
+
+ nbirds = 10;
+ ARGBEGIN{
+ case 'n':
+ nbirds = strtol(EARGF(usage()), &s, 10);
+ if(*s != 0)
+ usage();
+ break;
+ default: usage();
+ }ARGEND;
+ if(argc > 0)
+ usage();
+
+ if(initdraw(nil, nil, nil) < 0)
+ sysfatal("initdraw: %r");
+ if((mc = initmouse(nil, screen)) == nil)
+ sysfatal("initmouse: %r");
+ if((kc = initkeyboard(nil)) == nil)
+ sysfatal("initkeyboard: %r");
+ initpalette();
+ worldrf.p = Pt2(screen->r.min.x,screen->r.max.y,1);
+ worldrf.bx = Vec2(1, 0);
+ worldrf.by = Vec2(0,-1);
+
+ flock = newflock(nbirds, Rect(0,0,Dx(screen->r),Dy(screen->r)));
+
+ display->locking = 1;
+ unlockdisplay(display);
+ redraw();
+
+ for(;;){
+ enum { MOUSE, RESIZE, KEYBOARD };
+ Alt a[] = {
+ {mc->c, &mc->Mouse, CHANRCV},
+ {mc->resizec, nil, CHANRCV},
+ {kc->c, &r, CHANRCV},
+ {nil, nil, CHANEND}
+ };
+
+ switch(alt(a)){
+ case MOUSE:
+ mouse(mc->Mouse);
+ break;
+ case RESIZE:
+ resized();
+ break;
+ case KEYBOARD:
+ key(r);
+ break;
+ }
+
+ redraw();
+ }
+}
--- /dev/null
+++ b/mkfile
@@ -1,0 +1,24 @@
+</$objtype/mkfile
+
+BIN=/$objtype/bin/games
+TARG=boids
+OFILES=\
+ main.$O\
+
+HFILES=\
+ libgeometry/geometry.h\
+
+LIB=\
+ libgeometry/libgeometry.a$O\
+
+CFLAGS=$CFLAGS -Ilibgeometry
+
+</sys/src/cmd/mkone
+
+libgeometry/libgeometry.a$O:
+ cd libgeometry
+ mk install
+
+clean nuke:V:
+ rm -f *.[$OS] [$OS].??* $TARG
+ @{cd libgeometry; mk $target}
--- /dev/null
+++ b/readme.md
@@ -1,0 +1,6 @@
+# Bird flock simulator
+
+This program shows the emergent behavior observed in bird flocks,
+mammal herds, fish schools and other such animal groups. It's based
+on Craig W. Reynolds' “Flocks, Herds and Schools: A Distributed
+Behavioral Model.”
--- /dev/null
+++ b/resources
@@ -1,0 +1,3 @@
+http://www.red3d.com/cwr/boids/
+http://www.red3d.com/cwr/papers/1987/boids.html
+http://www.red3d.com/cwr/boids/RipOff_Flocking.html