juggle.c 4.4 KB

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