123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180 |
- #include <u.h>
- #include <libc.h>
- #include <draw.h>
- #include <event.h>
- #define NSTEP 10 /* number of steps between throws */
- #define RBALL 10 /* radius of ball images */
- #define NBALL 100
- 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};
- }
- Image *image, *disk;
- 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++)
- draw(image, rectaddpt(disk->r, sub(bpos(j, i, t), Pt(RBALL, RBALL))),
- disk, nil, ZP);
- draw(screen, screen->r, image, nil, image->r.min);
- flushimage(display, 1);
- if(delay>0)
- sleep(delay);
- }
- }
- 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);
- disk=allocimage(display, Rect(0, 0, 2*RBALL+1, 2*RBALL+1), screen->chan, 0, DWhite);
- fillellipse(disk, Pt(RBALL, RBALL), RBALL, RBALL, display->black, ZP);
- 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');
- }
- }
|