123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226 |
- /*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
- #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');
- }
- }
|