]> git.lizzy.rs Git - plan9front.git/blob - sys/src/games/juggle.c
merging erik quanstros nupas
[plan9front.git] / sys / src / games / juggle.c
1 #include <u.h>
2 #include <libc.h>
3 #include <draw.h>
4 #include <event.h>
5
6 enum
7 {
8         NSTEP           = 10,           /* number of steps between throws */
9         RBALL           = 10,           /* radius of ball images */
10         Nball           = 100,
11 };
12
13 Image *image, **disk;
14 int ndisk=0;
15 int nhand=2;
16 int delay=20;                   /* ms delay between steps */
17 int nball;
18 int maxhgt;
19 Rectangle win;
20
21
22 #define add addpt
23 #define sub subpt
24 #define inset insetrect
25
26
27 /*
28  * pattern lists the heights of a repeating sequence of throws.
29  * At time t, hand t%nhand throws.  At that time, it must
30  * hold exactly one ball, unless it executes a 0 throw,
31  * in which case it must hold no ball.  A throw of height h
32  * at time t lands at time t+h in hand (t+h)%nhand.
33  */
34 typedef struct Ball Ball;
35 struct Ball{
36         int oldhand;    /* hand that previously held the ball */
37         int hgt;        /* how high the throw from oldhand was */
38         int time;       /* time at which ball will arrive */
39         int hand;       /* hand in which ball will rest on arrival */
40 };
41 Ball ball[Nball];
42 void throw(int t, int hgt){
43         int hand=t%nhand;
44         int i, b, n;
45         b=n=0;
46         for(i=0;i!=nball;i++) if(ball[i].hand==hand && ball[i].time<=t){
47                 n++;
48                 b=i;
49         }
50         if(hgt==0){
51                 if(n!=0){
52                         print("bad zero throw at t=%d, nball=%d\n", t, n);
53                         exits("bad");
54                 }
55         }
56         else if(n!=1){
57                 print("bad ball count at t=%d, nball=%d\n", t, n);
58                 exits("bad");
59         }
60         else{
61                 ball[b].oldhand=hand;
62                 ball[b].hgt=hgt;
63                 ball[b].time=t+hgt;
64                 ball[b].hand=(hand+hgt)%nhand;
65         }
66 }
67 Point bpos(int b, int step, int t){
68         Ball *bp=&ball[b];
69         double dt=t-1+(step+1.)/NSTEP-(bp->time-bp->hgt);
70         double hgt=(bp->hgt*dt-dt*dt)*4./(maxhgt*maxhgt);
71         double alpha=(bp->oldhand+(bp->hand-bp->oldhand)*dt/bp->hgt)/(nhand-1);
72         return (Point){win.min.x+(win.max.x-win.min.x)*alpha,
73                        win.max.y-1+(win.min.y-win.max.y)*hgt};
74 }
75
76 void move(int t){
77         int i, j;
78         for(i=0;i!=NSTEP;i++){
79                 while(ecanmouse()) emouse();
80                 draw(image, inset(image->r, 3), display->white, nil, ZP);
81                 for(j=0;j!=nball;j++)
82                         fillellipse(image, bpos(j, i, t), RBALL, RBALL, disk[j%ndisk], ZP);
83                 draw(screen, screen->r, image, nil, image->r.min);
84                 flushimage(display, 1);
85                 if(delay>0)
86                         sleep(delay);
87         }
88 }
89
90 void
91 adddisk(int c)
92 {
93         Image *col;
94         disk = realloc(disk, (ndisk+1)*sizeof(Image*));
95         col=allocimage(display, Rect(0,0,1,1), CMAP8, 1, c);
96         disk[ndisk]=col;
97         ndisk++;
98 }
99
100 void
101 diskinit(void)
102 {
103         /* colors taken from /sys/src/cmd/stats.c */
104
105         adddisk(0xFFAAAAFF);
106         adddisk(DPalegreygreen);
107         adddisk(DDarkyellow);
108         adddisk(DMedgreen);
109         adddisk(0x00AAFFFF);
110         adddisk(0xCCCCCCFF);
111
112         adddisk(0xBB5D5DFF);
113         adddisk(DPurpleblue);
114         adddisk(DYellowgreen);
115         adddisk(DDarkgreen);
116         adddisk(0x0088CCFF);
117         adddisk(0x888888FF);
118 }
119
120 void
121 usage(char *name)
122 {
123         fprint(2, "usage: %s [start] pattern\n", name);
124         exits("usage");
125 }
126
127 void 
128 eresized(int new){
129         if(new && getwindow(display, Refnone) < 0) {
130                 sysfatal("can't reattach to window");
131         }
132         if(image) freeimage(image);
133         image=allocimage(display, screen->r, screen->chan, 0, DNofill);
134         draw(image, image->r, display->black, nil, ZP);
135         win=inset(screen->r, 4+2*RBALL);
136 }
137 void
138 main(int argc, char *argv[]){
139         int sum, i, t, hgt, nstart, npattern;
140         char *s, *start = nil, *pattern = nil;
141
142         ARGBEGIN{
143         default:
144                 usage(argv0);
145         case 'd':
146                 s = ARGF();
147                 if(s == nil)
148                         usage(argv0);
149                 delay = strtol(argv[0], &s, 0);
150                 if(delay < 0 || s == argv[0] || *s != '\0')
151                         usage(argv0);
152                 break;
153         case 'h':
154                 s = ARGF();
155                 if(s == nil)
156                         usage(argv0);
157                 nhand = strtol(argv[0], &s, 0);
158                 if(nhand <= 0 || s == argv[0] || *s != '\0')
159                         usage(argv0);
160                 break;
161         }ARGEND
162         
163         switch(argc) {
164         case 1: 
165                         start=""; 
166                         pattern=argv[0]; 
167                         break;
168         case 2: 
169                         start=argv[0]; 
170                         pattern=argv[1]; 
171                         break;
172         default: 
173                         usage(argv0);
174         }
175         sum=0;
176         maxhgt=0;
177         for(s=pattern;*s;s++){
178                 hgt=*s-'0';
179                 sum+=hgt;
180                 if(maxhgt<hgt) maxhgt=hgt;
181         }
182         npattern=s-pattern;
183         for(s=start;*s;s++){
184                 hgt=*s-'0';
185                 if(maxhgt<hgt) maxhgt=hgt;
186         }
187         if(sum%npattern){
188                 print("%s: non-integral ball count\n",argv[0]);
189                 exits("partial ball");
190         }
191         nball=sum/npattern;
192         for(i=0;i!=nball;i++){
193                 ball[i].oldhand=(i-nball)%nhand;
194                 if(ball[i].oldhand<0) ball[i].oldhand+=nhand;
195                 ball[i].hgt=nball;
196                 ball[i].time=i;
197                 ball[i].hand=i%nhand;
198         }
199         if(initdraw(nil, nil, "juggle") < 0)
200                 sysfatal("initdraw failed: %r");
201         einit(Emouse);
202         diskinit();
203         eresized(0);
204         if(image==0){
205                 print("can't allocate bitmap");
206                 exits("no space");
207         }
208         for(t=0;start[t];t++){
209                 move(t);
210                 throw(t, start[t]-'0');
211         }
212         nstart=t;
213         for(;;t++){
214                 move(t);
215                 throw(t, pattern[(t-nstart)%npattern]-'0');
216         }
217 }