Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
		if(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
}