juggle.c 4.8 KB

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