summaryrefslogtreecommitdiffstats
path: root/balls.c
diff options
context:
space:
mode:
authorSam Anthony <sam@samanthony.xyz>2024-10-30 19:38:10 -0400
committerSam Anthony <sam@samanthony.xyz>2024-10-30 19:38:10 -0400
commit647531dced5cb79107b768418cbf400b583300c2 (patch)
tree3fe2fde9eeb3d17f64f7bea6147e396d7f7d14a5 /balls.c
parentcfeb3bad9cfc92ecd21d0be92ee2cf793a009242 (diff)
downloadballs-thread.zip
ring broadcastthread
Diffstat (limited to 'balls.c')
-rw-r--r--balls.c162
1 files changed, 58 insertions, 104 deletions
diff --git a/balls.c b/balls.c
index f156aab..adf7964 100644
--- a/balls.c
+++ b/balls.c
@@ -39,20 +39,19 @@ typedef struct {
Channel *frametick;
- Channel **in; /* <-chan Ball */
- Channel **out; /* chan<- Ball */
+ /* threads communicate in a ring */
+ Channel *lneighbor; /* <-chan Ball */
+ Channel *rneighbor; /* chan<- Ball */
int nothers; /* number of other balls */
} BallArg;
static int ballcolors[] = { DRed, DGreen, DBlue };
-static uint radii[] = { 20, 30, 50 };
+static uint radii[] = { 24, 32, 48 };
static Rectangle bounds = {{0, 0}, {WIDTH, HEIGHT}};
-int init(char *label, Mousectl **mctl, Keyboardctl **kctl);
void spawnballs(int n);
+void eventloop(Image *bg, Image *walls);
Channel **allocchans(int nchans, int elsize, int nel);
-void mcopycolskip(Channel *vec[], Channel **matrix[], int n, int col, int skip);
-void vcopyskip(Channel *dst[], Channel *src[], int n, int skip);
void nooverlapcircles(Point centers[], int n, uint radius);
Point randptinrect(Rectangle r);
int randint(int lo, int hi);
@@ -60,17 +59,12 @@ uint maxelem(uint arr[], uint n);
double mass(uint radius);
double area(double radius);
void ball(void *arg);
-void broadcast(Channel *cs[], int n, void *v);
void frametick(void *arg);
void
threadmain(int argc, char *argv[]) {
int nballs;
Image *bg, *walls;
- Mousectl *mctl;
- Keyboardctl *kctl;
- int resize[2];
- Rune key;
nballs = DEFAULT_NBALLS;
if (argc > 1) {
@@ -81,8 +75,8 @@ threadmain(int argc, char *argv[]) {
}
printf("nballs: %ud\n", nballs);
- if (init(argv[0], &mctl, &kctl))
- sysfatal("%s: %r", argv[0]);
+ if (initdraw(nil, nil, "Balls") < 0)
+ sysfatal("initdraw() failed\n");
printf("screen: (%d,%d) (%d,%d)\n", screen->r.min.x, screen->r.min.y,
screen->r.max.x, screen->r.max.y);
@@ -98,47 +92,16 @@ threadmain(int argc, char *argv[]) {
spawnballs(nballs);
- enum { RESIZE = 0, KEYBD = 1 };
- Alt alts[3] = {
- {mctl->resizec, &resize, CHANRCV},
- {kctl->c, &key, CHANRCV},
- {nil, nil, CHANEND},
- };
- for (;;) {
- switch (alt(alts)) {
- case RESIZE:
- if (getwindow(display, Refnone) < 0)
- sysfatal("%s: %r", argv[0]);
- drawbg(walls, bg);
- break;
- case KEYBD:
- if (key == KEY_QUIT)
- threadexitsall(0);
- break;
- case -1: /* interrupted */
- break;
- }
- }
-}
-
-int
-init(char *label, Mousectl **mctl, Keyboardctl **kctl) {
- if (initdraw(nil, nil, label) < 0)
- return 1;
- if ((*mctl = initmouse(nil, screen)) == nil)
- return 1;
- if ((*kctl = initkeyboard(nil)) == nil)
- return 1;
- return 0;
+ eventloop(bg, walls);
}
void
spawnballs(int n) {
Channel **ticks;
Point *ps;
- int i, j;
+ int i;
BallArg *arg;
- Channel ***cs;
+ Channel **cs;
if ((ticks = allocchans(n, sizeof(int), TICK_BUFSIZE)) == nil)
sysfatal("failed to allocate frame ticker channels");
@@ -149,17 +112,11 @@ spawnballs(int n) {
sysfatal("failed to allocate position array");
nooverlapcircles(ps, n, maxelem(radii, NELEMS(radii)));
- if ((cs = malloc(n*sizeof(Channel **))) == nil)
+ if ((cs = malloc(n*sizeof(Channel *))) == nil)
sysfatal("failed to allocate channel matrix");
for (i = 0; i < n; i++) {
- if ((cs[i] = malloc(n*sizeof(Channel *))) == nil)
- sysfatal("failed to allocate row of channel matrix");
- for (j = 0; j < n; j++) {
- if (j == i)
- continue;
- if ((cs[i][j] = chancreate(sizeof(Ball), BALL_BUFSIZE)) == nil)
- sysfatal("failed to create channel");
- }
+ if ((cs[i] = chancreate(sizeof(Ball), BALL_BUFSIZE)) == nil)
+ sysfatal("failed to create channel");
}
for (i = 0; i < n; i++) {
@@ -170,19 +127,10 @@ spawnballs(int n) {
arg->b.v = V((double) randint(-VMAX, VMAX+1), (double) randint(-VMAX, VMAX+1));
arg->b.r = radii[randint(0, NELEMS(radii))];
arg->b.m = mass(arg->b.r);
-
arg->color = ballcolors[randint(0, NELEMS(ballcolors))];
-
arg->frametick = ticks[i];
-
- if ((arg->in = malloc((n-1)*sizeof(Channel *))) == nil)
- sysfatal("failed to allocate array of incoming channels");
- mcopycolskip(arg->in, cs, n, i, i);
-
- if ((arg->out = malloc((n-1)*sizeof(Channel *))) == nil)
- sysfatal("failed to allocate array of outgoing channels");
- vcopyskip(arg->out, cs[i], n, i);
-
+ arg->lneighbor = cs[i];
+ arg->rneighbor = cs[(i+1) % n];
arg->nothers = n-1;
printf("create ball p(%d,%d) v(%f,%f) r(%u) m(%f)\n", arg->b.p.x, arg->b.p.y, arg->b.v.x, arg->b.v.y, arg->b.r, arg->b.m);
@@ -190,11 +138,45 @@ spawnballs(int n) {
}
free(ps);
- for (i = 0; i < n; i++)
- free(cs[i]);
free(cs);
}
+void
+eventloop(Image *bg, Image *walls) {
+ Mousectl *mctl;
+ Keyboardctl *kctl;
+ int resize[2];
+ Rune key;
+
+ if ((mctl = initmouse(nil, screen)) == nil)
+ sysfatal("failed to initialize mouse\n");
+ if ((kctl = initkeyboard(nil)) == nil)
+ sysfatal("failed to initialize keyboard\n");
+
+ enum { RESIZE = 0, KEYBD = 1 };
+ Alt alts[3] = {
+ {mctl->resizec, &resize, CHANRCV},
+ {kctl->c, &key, CHANRCV},
+ {nil, nil, CHANEND},
+ };
+ for (;;) {
+ switch (alt(alts)) {
+ case RESIZE:
+ if (getwindow(display, Refnone) < 0)
+ sysfatal("getwindow() failed\n");
+ drawbg(walls, bg);
+ break;
+ case KEYBD:
+ if (key == KEY_QUIT)
+ threadexitsall(0);
+ break;
+ case -1: /* interrupted */
+ break;
+ }
+ }
+}
+
+/* allocate nil-terminated array of channels */
Channel **
allocchans(int nchans, int elsize, int nel) {
Channel **cs;
@@ -217,28 +199,7 @@ allocchans(int nchans, int elsize, int nel) {
return cs;
}
-/* copy column col of nxn matrix, except for element skip, into n-1 length vec */
-void
-mcopycolskip(Channel *vec[], Channel **matrix[], int n, int col, int skip) {
- int i;
-
- for (i = 0; i < skip; i++)
- vec[i] = matrix[i][col];
- for (i = skip+1; i < n; i++)
- vec[i-1] = matrix[i][col];
-}
-
-/* copy each element in n-length src, except for element skip, into n-1 length dst */
-void
-vcopyskip(Channel *dst[], Channel *src[], int n, int skip) {
- int i;
-
- for (i = 0; i < skip; i++)
- dst[i] = src[i];
- for (i = skip+1; i < n; i++)
- dst[i-1] = src[i];
-}
-
+/* populate array of circle coordinates within bounds so that circles don't overlap */
void
nooverlapcircles(Point centers[], int n, uint radius) {
int i, j;
@@ -305,38 +266,31 @@ ball(void *arg) {
if (fill == nil ||erase == nil)
sysfatal("failed to allocate image");
- oldpos = b.p;
+ oldpos = b.p; /* keep track of previous position so it can be erased */
for (;;) {
b.v.y += G;
-
b.p = ptaddv(b.p, b.v);
printf("(%d,%d) %f %f\n", b.p.x, b.p.y, b.v.x, b.v.y);
- broadcast(barg->out, barg->nothers, &b);
-
/* check for ball collision */
+ other = b; /* send our own ball first */
for (i = 0; i < barg->nothers; i++) {
- recv(barg->in[i], &other);
+ send(barg->rneighbor, &other); /* pass balls around the ring */
+ recv(barg->lneighbor, &other);
collideball(&b, &other);
}
collidewall(&b, bounds);
- recv(barg->frametick, &t);
+ recv(barg->frametick, &t); /* wait for next frame */
drawcircle(erase, oldpos);
drawcircle(fill, b.p);
oldpos = b.p;
-
}
}
-void
-broadcast(Channel *cs[], int n, void *v) {
- while (n-- > 0)
- send(cs[n], v);
-}
-
+/* arg is nil-terminated array of chan int */
void
frametick(void *arg) {
Channel **cs, **c;