diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/games/juggle.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/games/juggle.c')
-rwxr-xr-x | sys/src/games/juggle.c | 217 |
1 files changed, 217 insertions, 0 deletions
diff --git a/sys/src/games/juggle.c b/sys/src/games/juggle.c new file mode 100755 index 000000000..01dea4146 --- /dev/null +++ b/sys/src/games/juggle.c @@ -0,0 +1,217 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> +#include <event.h> + +enum +{ + NSTEP = 10, /* number of steps between throws */ + RBALL = 10, /* radius of ball images */ + Nball = 100, +}; + +Image *image, **disk; +int ndisk=0; +int nhand=2; +int delay=20; /* ms delay between steps */ +int nball; +int maxhgt; +Rectangle win; + + +#define add addpt +#define sub subpt +#define inset insetrect + + +/* + * pattern lists the heights of a repeating sequence of throws. + * At time t, hand t%nhand throws. At that time, it must + * hold exactly one ball, unless it executes a 0 throw, + * in which case it must hold no ball. A throw of height h + * at time t lands at time t+h in hand (t+h)%nhand. + */ +typedef struct Ball Ball; +struct Ball{ + int oldhand; /* hand that previously held the ball */ + int hgt; /* how high the throw from oldhand was */ + int time; /* time at which ball will arrive */ + int hand; /* hand in which ball will rest on arrival */ +}; +Ball ball[Nball]; +void throw(int t, int hgt){ + int hand=t%nhand; + int i, b, n; + b=n=0; + for(i=0;i!=nball;i++) if(ball[i].hand==hand && ball[i].time<=t){ + n++; + b=i; + } + if(hgt==0){ + if(n!=0){ + print("bad zero throw at t=%d, nball=%d\n", t, n); + exits("bad"); + } + } + else if(n!=1){ + print("bad ball count at t=%d, nball=%d\n", t, n); + exits("bad"); + } + else{ + ball[b].oldhand=hand; + ball[b].hgt=hgt; + ball[b].time=t+hgt; + ball[b].hand=(hand+hgt)%nhand; + } +} +Point bpos(int b, int step, int t){ + Ball *bp=&ball[b]; + double dt=t-1+(step+1.)/NSTEP-(bp->time-bp->hgt); + double hgt=(bp->hgt*dt-dt*dt)*4./(maxhgt*maxhgt); + double alpha=(bp->oldhand+(bp->hand-bp->oldhand)*dt/bp->hgt)/(nhand-1); + return (Point){win.min.x+(win.max.x-win.min.x)*alpha, + win.max.y-1+(win.min.y-win.max.y)*hgt}; +} + +void move(int t){ + int i, j; + for(i=0;i!=NSTEP;i++){ + if(ecanmouse()) emouse(); + draw(image, inset(image->r, 3), display->white, nil, ZP); + for(j=0;j!=nball;j++) + fillellipse(image, bpos(j, i, t), RBALL, RBALL, disk[j%ndisk], ZP); + draw(screen, screen->r, image, nil, image->r.min); + flushimage(display, 1); + if(delay>0) + sleep(delay); + } +} + +void +adddisk(int c) +{ + Image *col; + disk = realloc(disk, (ndisk+1)*sizeof(Image*)); + col=allocimage(display, Rect(0,0,1,1), CMAP8, 1, c); + disk[ndisk]=col; + ndisk++; +} + +void +diskinit(void) +{ + /* colors taken from /sys/src/cmd/stats.c */ + + adddisk(0xFFAAAAFF); + adddisk(DPalegreygreen); + adddisk(DDarkyellow); + adddisk(DMedgreen); + adddisk(0x00AAFFFF); + adddisk(0xCCCCCCFF); + + adddisk(0xBB5D5DFF); + adddisk(DPurpleblue); + adddisk(DYellowgreen); + adddisk(DDarkgreen); + adddisk(0x0088CCFF); + adddisk(0x888888FF); +} + +void +usage(char *name) +{ + fprint(2, "usage: %s [start] pattern\n", name); + exits("usage"); +} + +void +eresized(int new){ + if(new && getwindow(display, Refnone) < 0) { + sysfatal("can't reattach to window"); + } + if(image) freeimage(image); + image=allocimage(display, screen->r, screen->chan, 0, DNofill); + draw(image, image->r, display->black, nil, ZP); + win=inset(screen->r, 4+2*RBALL); +} +void +main(int argc, char *argv[]){ + int sum, i, t, hgt, nstart, npattern; + char *s, *start = nil, *pattern = nil; + + ARGBEGIN{ + default: + usage(argv0); + case 'd': + s = ARGF(); + if(s == nil) + usage(argv0); + delay = strtol(argv[0], &s, 0); + if(delay < 0 || s == argv[0] || *s != '\0') + usage(argv0); + break; + case 'h': + s = ARGF(); + if(s == nil) + usage(argv0); + nhand = strtol(argv[0], &s, 0); + if(nhand <= 0 || s == argv[0] || *s != '\0') + usage(argv0); + break; + }ARGEND + + switch(argc) { + case 1: + start=""; + pattern=argv[0]; + break; + case 2: + start=argv[0]; + pattern=argv[1]; + break; + default: + usage(argv0); + } + sum=0; + maxhgt=0; + for(s=pattern;*s;s++){ + hgt=*s-'0'; + sum+=hgt; + if(maxhgt<hgt) maxhgt=hgt; + } + npattern=s-pattern; + for(s=start;*s;s++){ + hgt=*s-'0'; + if(maxhgt<hgt) maxhgt=hgt; + } + if(sum%npattern){ + print("%s: non-integral ball count\n",argv[0]); + exits("partial ball"); + } + nball=sum/npattern; + for(i=0;i!=nball;i++){ + ball[i].oldhand=(i-nball)%nhand; + if(ball[i].oldhand<0) ball[i].oldhand+=nhand; + ball[i].hgt=nball; + ball[i].time=i; + ball[i].hand=i%nhand; + } + if(initdraw(nil, nil, "juggle") < 0) + sysfatal("initdraw failed: %r"); + einit(Emouse); + diskinit(); + eresized(0); + if(image==0){ + print("can't allocate bitmap"); + exits("no space"); + } + for(t=0;start[t];t++){ + move(t); + throw(t, start[t]-'0'); + } + nstart=t; + for(;;t++){ + move(t); + throw(t, pattern[(t-nstart)%npattern]-'0'); + } +} |