13d156f8aSDavid du Colombier /* Federico Benavento <benavento@gmail.com> */
23d156f8aSDavid du Colombier #include <u.h>
33d156f8aSDavid du Colombier #include <libc.h>
43d156f8aSDavid du Colombier #include <draw.h>
53d156f8aSDavid du Colombier #include <event.h>
63d156f8aSDavid du Colombier
7*3039af76SDavid du Colombier enum {
8*3039af76SDavid du Colombier Facesize = 48
9*3039af76SDavid du Colombier };
10*3039af76SDavid du Colombier
11*3039af76SDavid du Colombier
12312a1df1SDavid du Colombier void memoinit(void);
13312a1df1SDavid du Colombier void redraw(void);
143d156f8aSDavid du Colombier void eresized(int);
153d156f8aSDavid du Colombier void resize(int i);
163d156f8aSDavid du Colombier void afaces(void);
173d156f8aSDavid du Colombier void allocblocks(void);
183d156f8aSDavid du Colombier Image *openface(char *path);
193d156f8aSDavid du Colombier
203d156f8aSDavid du Colombier Image *face[18];
213d156f8aSDavid du Colombier char buf[100];
223d156f8aSDavid du Colombier ushort winflag, level;
23312a1df1SDavid du Colombier Image *back;
24312a1df1SDavid du Colombier Image *fore;
253d156f8aSDavid du Colombier
26312a1df1SDavid du Colombier enum
273d156f8aSDavid du Colombier {
28312a1df1SDavid du Colombier Eninit,
29312a1df1SDavid du Colombier Eshow,
30312a1df1SDavid du Colombier Ehide,
31312a1df1SDavid du Colombier Edisc,
32312a1df1SDavid du Colombier };
33312a1df1SDavid du Colombier
34312a1df1SDavid du Colombier struct
35312a1df1SDavid du Colombier {
36312a1df1SDavid du Colombier Image *face;
37312a1df1SDavid du Colombier Rectangle r;
38312a1df1SDavid du Colombier int flag;
393d156f8aSDavid du Colombier }block[36];
403d156f8aSDavid du Colombier
413d156f8aSDavid du Colombier char *buttons[] =
423d156f8aSDavid du Colombier {
433d156f8aSDavid du Colombier "restart",
443d156f8aSDavid du Colombier "easy",
453d156f8aSDavid du Colombier "hard",
463d156f8aSDavid du Colombier "exit",
473d156f8aSDavid du Colombier 0
483d156f8aSDavid du Colombier };
493d156f8aSDavid du Colombier
503d156f8aSDavid du Colombier Menu menu =
513d156f8aSDavid du Colombier {
523d156f8aSDavid du Colombier buttons
533d156f8aSDavid du Colombier };
543d156f8aSDavid du Colombier
553d156f8aSDavid du Colombier void
main(int argc,char * argv[])563d156f8aSDavid du Colombier main(int argc, char *argv[])
573d156f8aSDavid du Colombier {
583d156f8aSDavid du Colombier Mouse m;
593d156f8aSDavid du Colombier int i, j;
60312a1df1SDavid du Colombier ushort ran, score, attempt, prev, br[2];
61312a1df1SDavid du Colombier Image *c[2];
623d156f8aSDavid du Colombier char *fmt;
633d156f8aSDavid du Colombier
643d156f8aSDavid du Colombier level = 16;
65312a1df1SDavid du Colombier fmt = "win in %d attempts!";
66312a1df1SDavid du Colombier
673d156f8aSDavid du Colombier ARGBEGIN{
683d156f8aSDavid du Colombier default:
693d156f8aSDavid du Colombier goto Usage;
703d156f8aSDavid du Colombier case 'h':
713d156f8aSDavid du Colombier level=36;
723d156f8aSDavid du Colombier break;
733d156f8aSDavid du Colombier }ARGEND
74312a1df1SDavid du Colombier
753d156f8aSDavid du Colombier if(argc){
763d156f8aSDavid du Colombier Usage:
773d156f8aSDavid du Colombier fprint(2, "usage: %s [-h]\n", argv0);
783d156f8aSDavid du Colombier exits("usage");
793d156f8aSDavid du Colombier }
803d156f8aSDavid du Colombier if(initdraw(0,0,"memo") < 0)
813d156f8aSDavid du Colombier sysfatal("initdraw failed: %r");
823d156f8aSDavid du Colombier srand(time(0));
83312a1df1SDavid du Colombier memoinit();
843d156f8aSDavid du Colombier einit(Emouse);
853d156f8aSDavid du Colombier
863d156f8aSDavid du Colombier Start:
873d156f8aSDavid du Colombier afaces();
883d156f8aSDavid du Colombier winflag=0;
893d156f8aSDavid du Colombier prev=level+1;
903d156f8aSDavid du Colombier score=attempt=0;
91312a1df1SDavid du Colombier for(i=0;i!=level;i++)
92312a1df1SDavid du Colombier block[i].flag = Eninit;
93312a1df1SDavid du Colombier
943d156f8aSDavid du Colombier for(i=0;i!=level/2;i++){
953d156f8aSDavid du Colombier for(j=0;j!=2;){
963d156f8aSDavid du Colombier ran = rand()%level;
97312a1df1SDavid du Colombier if(block[ran].flag == Eninit){
98312a1df1SDavid du Colombier block[ran].face = face[i];
99312a1df1SDavid du Colombier block[ran].flag = Eshow;
1003d156f8aSDavid du Colombier j++;
1013d156f8aSDavid du Colombier }
1023d156f8aSDavid du Colombier }
1033d156f8aSDavid du Colombier }
1043d156f8aSDavid du Colombier eresized(0);
105312a1df1SDavid du Colombier for(;;m=emouse())
1063d156f8aSDavid du Colombier if(m.buttons)
1073d156f8aSDavid du Colombier break;
108312a1df1SDavid du Colombier
1093d156f8aSDavid du Colombier for(i=0;i!=level;i++)
110312a1df1SDavid du Colombier block[i].flag = Ehide;
111312a1df1SDavid du Colombier
112312a1df1SDavid du Colombier redraw();
1133d156f8aSDavid du Colombier j = 0;
1143d156f8aSDavid du Colombier for(;; m=emouse()){
1153d156f8aSDavid du Colombier switch(m.buttons){
1163d156f8aSDavid du Colombier case 1:
1173d156f8aSDavid du Colombier while(m.buttons){
1183d156f8aSDavid du Colombier for(i=0;i!=level;i++){
119312a1df1SDavid du Colombier if(i!=prev && ptinrect(m.xy,block[i].r)){
120312a1df1SDavid du Colombier if(block[i].flag==Ehide && j<2){
121312a1df1SDavid du Colombier block[i].flag = Eshow;
122312a1df1SDavid du Colombier draw(screen, block[i].r, block[i].face, nil, ZP);
123312a1df1SDavid du Colombier c[j] = block[i].face;
124312a1df1SDavid du Colombier br[j] = prev = i;
1253d156f8aSDavid du Colombier j++;
1263d156f8aSDavid du Colombier }
1273d156f8aSDavid du Colombier break;
1283d156f8aSDavid du Colombier }
1293d156f8aSDavid du Colombier }
1303d156f8aSDavid du Colombier m=emouse();
1313d156f8aSDavid du Colombier }
1323d156f8aSDavid du Colombier break;
1333d156f8aSDavid du Colombier case 4:
1343d156f8aSDavid du Colombier switch(emenuhit(3, &m, &menu)) {
1353d156f8aSDavid du Colombier case 0: /* restart */
1363d156f8aSDavid du Colombier goto Start;
1373d156f8aSDavid du Colombier break;
1383d156f8aSDavid du Colombier case 1:
1393d156f8aSDavid du Colombier level=16;
1403d156f8aSDavid du Colombier goto Start;
1413d156f8aSDavid du Colombier break;
1423d156f8aSDavid du Colombier case 2:
1433d156f8aSDavid du Colombier level=36;
1443d156f8aSDavid du Colombier goto Start;
1453d156f8aSDavid du Colombier break;
1463d156f8aSDavid du Colombier case 3:
1473d156f8aSDavid du Colombier exits(0);
1483d156f8aSDavid du Colombier break;
1493d156f8aSDavid du Colombier }
1503d156f8aSDavid du Colombier }
1513d156f8aSDavid du Colombier if(j==2){
1523d156f8aSDavid du Colombier attempt++;
1533d156f8aSDavid du Colombier prev = level+1;
1543d156f8aSDavid du Colombier j = 0;
1553d156f8aSDavid du Colombier if(c[0] == c[1]){
1563d156f8aSDavid du Colombier score++;
157312a1df1SDavid du Colombier block[br[0]].flag = Edisc;
158312a1df1SDavid du Colombier block[br[1]].flag = Edisc;
1593d156f8aSDavid du Colombier } else{
160312a1df1SDavid du Colombier block[br[0]].flag = Ehide;
161312a1df1SDavid du Colombier block[br[1]].flag = Ehide;
1623d156f8aSDavid du Colombier }
163312a1df1SDavid du Colombier redraw();
164312a1df1SDavid du Colombier continue;
1653d156f8aSDavid du Colombier }
1663d156f8aSDavid du Colombier if(score == level/2){
1673d156f8aSDavid du Colombier winflag = 1;
1683d156f8aSDavid du Colombier sprint(buf, fmt, attempt);
169312a1df1SDavid du Colombier redraw();
170312a1df1SDavid du Colombier for(;;m=emouse())
171312a1df1SDavid du Colombier if(m.buttons&1 || m.buttons&4)
1723d156f8aSDavid du Colombier break;
1733d156f8aSDavid du Colombier goto Start;
1743d156f8aSDavid du Colombier }
1753d156f8aSDavid du Colombier }
1763d156f8aSDavid du Colombier }
1773d156f8aSDavid du Colombier
1783d156f8aSDavid du Colombier void
memoinit(void)179312a1df1SDavid du Colombier memoinit(void)
180312a1df1SDavid du Colombier {
181312a1df1SDavid du Colombier back = allocimagemix(display, DPalebluegreen,DWhite);
182312a1df1SDavid du Colombier fore = allocimagemix(display, 0x00DDDDFF, 0x00DDDDFF);
183312a1df1SDavid du Colombier }
184312a1df1SDavid du Colombier
185312a1df1SDavid du Colombier void
eresized(int new)1863d156f8aSDavid du Colombier eresized(int new)
1873d156f8aSDavid du Colombier {
188*3039af76SDavid du Colombier double sq;
189*3039af76SDavid du Colombier Point p;
190*3039af76SDavid du Colombier
1913d156f8aSDavid du Colombier if(new && getwindow(display, Refnone) < 0){
1923d156f8aSDavid du Colombier fprint(2, "can't reattach to window");
1933d156f8aSDavid du Colombier exits("resized");
1943d156f8aSDavid du Colombier }
195*3039af76SDavid du Colombier
196*3039af76SDavid du Colombier sq = sqrt(level);
197*3039af76SDavid du Colombier p = Pt(Dx(screen->r)+8, Dy(screen->r)+8);
198*3039af76SDavid du Colombier if(!new || !eqpt(p, Pt(Facesize*sq+sq*4+17, Facesize*sq+sq*4+17)))
199*3039af76SDavid du Colombier resize(Facesize*sq+sq*4+17);
200*3039af76SDavid du Colombier
2013d156f8aSDavid du Colombier allocblocks();
202312a1df1SDavid du Colombier draw(screen, screen->r, back, nil, ZP);
203312a1df1SDavid du Colombier redraw();
204312a1df1SDavid du Colombier }
205312a1df1SDavid du Colombier
206312a1df1SDavid du Colombier void
redraw(void)207312a1df1SDavid du Colombier redraw(void)
208312a1df1SDavid du Colombier {
209*3039af76SDavid du Colombier int i;
210312a1df1SDavid du Colombier Rectangle r;
211312a1df1SDavid du Colombier Point p;
212312a1df1SDavid du Colombier
2133d156f8aSDavid du Colombier if(winflag == 1){
214312a1df1SDavid du Colombier p = Pt(Dx(screen->r)/8, Dy(screen->r)/4);
215312a1df1SDavid du Colombier r = screen->r;
216312a1df1SDavid du Colombier r.min = addpt(r.min, p);
217312a1df1SDavid du Colombier r.max = subpt(r.max, p);
218312a1df1SDavid du Colombier draw(screen, r, fore, nil, ZP);
219312a1df1SDavid du Colombier p=addpt(r.min, Pt(5,5));
2203d156f8aSDavid du Colombier string(screen,p,display->black,ZP,font,buf);
221312a1df1SDavid du Colombier return;
222312a1df1SDavid du Colombier }
223312a1df1SDavid du Colombier
2243d156f8aSDavid du Colombier for(i=0;i!=level;i++){
225312a1df1SDavid du Colombier r = block[i].r;
2263d156f8aSDavid du Colombier switch(block[i].flag){
227312a1df1SDavid du Colombier case Eshow:
228312a1df1SDavid du Colombier draw(screen, r,block[i].face,nil,ZP);
2293d156f8aSDavid du Colombier break;
230312a1df1SDavid du Colombier case Edisc:
231312a1df1SDavid du Colombier draw(screen, r, back, nil, ZP);
2323d156f8aSDavid du Colombier break;
233312a1df1SDavid du Colombier case Ehide:
234312a1df1SDavid du Colombier draw(screen, r, fore, nil, ZP);
2353d156f8aSDavid du Colombier break;
2363d156f8aSDavid du Colombier default:
2373d156f8aSDavid du Colombier fprint(2, "something went wrong!");
2383d156f8aSDavid du Colombier exits("wrong");
2393d156f8aSDavid du Colombier break;
2403d156f8aSDavid du Colombier }
2413d156f8aSDavid du Colombier }
2423d156f8aSDavid du Colombier }
2433d156f8aSDavid du Colombier
2443d156f8aSDavid du Colombier char *facepaths[] = {
2453d156f8aSDavid du Colombier /* logos */
2463d156f8aSDavid du Colombier "/lib/face/48x48x4/g/glenda.1",
2473d156f8aSDavid du Colombier "/lib/face/48x48x2/p/pjw+9ball.2",
2483d156f8aSDavid du Colombier
2493d156f8aSDavid du Colombier /* /sys/doc/9.ms authors */
2503d156f8aSDavid du Colombier "/lib/face/48x48x2/k/ken.1",
2513d156f8aSDavid du Colombier "/lib/face/48x48x4/b/bobf.1",
2523d156f8aSDavid du Colombier "/lib/face/48x48x4/p/philw.1",
2533d156f8aSDavid du Colombier "/lib/face/48x48x4/p/presotto.1",
2543d156f8aSDavid du Colombier "/lib/face/48x48x4/r/rob.1",
2553d156f8aSDavid du Colombier "/lib/face/48x48x4/s/sean.1",
2563d156f8aSDavid du Colombier
2573d156f8aSDavid du Colombier /* additional authors and luminaries for harder levels */
2583d156f8aSDavid du Colombier "/lib/face/48x48x4/b/bwk.1",
2593d156f8aSDavid du Colombier "/lib/face/48x48x4/c/cyoung.1",
2603d156f8aSDavid du Colombier "/lib/face/48x48x4/d/dmr.1",
2613d156f8aSDavid du Colombier "/lib/face/48x48x4/d/doug.1",
2623d156f8aSDavid du Colombier "/lib/face/48x48x4/h/howard.1",
2633d156f8aSDavid du Colombier "/lib/face/48x48x4/j/jmk.1",
2643d156f8aSDavid du Colombier "/lib/face/48x48x4/s/sape.1",
2653d156f8aSDavid du Colombier "/lib/face/48x48x4/s/seanq.1",
2663d156f8aSDavid du Colombier "/lib/face/48x48x4/t/td.1",
2673d156f8aSDavid du Colombier "/lib/face/48x48x8/l/lucent.1",
2683d156f8aSDavid du Colombier };
2693d156f8aSDavid du Colombier
2703d156f8aSDavid du Colombier void
afaces(void)2713d156f8aSDavid du Colombier afaces(void)
2723d156f8aSDavid du Colombier {
2733d156f8aSDavid du Colombier int i;
2743d156f8aSDavid du Colombier
2753d156f8aSDavid du Colombier for(i=0; i<18; i++)
2763d156f8aSDavid du Colombier face[i] = openface(facepaths[i]);
2773d156f8aSDavid du Colombier }
2783d156f8aSDavid du Colombier
2793d156f8aSDavid du Colombier void
resize(int i)2803d156f8aSDavid du Colombier resize(int i)
2813d156f8aSDavid du Colombier {
2823d156f8aSDavid du Colombier int fd;
2833d156f8aSDavid du Colombier
2843d156f8aSDavid du Colombier fd = open("/dev/wctl", OWRITE);
2853d156f8aSDavid du Colombier if(fd >= 0){
2863d156f8aSDavid du Colombier fprint(fd, "resize -dx %d -dy %d", i, i);
2873d156f8aSDavid du Colombier close(fd);
2883d156f8aSDavid du Colombier }
2893d156f8aSDavid du Colombier }
2903d156f8aSDavid du Colombier
2913d156f8aSDavid du Colombier Image *
openimage(char * path)2923d156f8aSDavid du Colombier openimage(char *path)
2933d156f8aSDavid du Colombier {
2943d156f8aSDavid du Colombier Image *i;
2953d156f8aSDavid du Colombier int fd;
2963d156f8aSDavid du Colombier
2973d156f8aSDavid du Colombier fd = open(path, OREAD);
2983d156f8aSDavid du Colombier if(fd < 0)
2993d156f8aSDavid du Colombier sysfatal("open %s: %r", path);
3003d156f8aSDavid du Colombier i = readimage(display, fd, 0);
3013d156f8aSDavid du Colombier if(i == nil)
3023d156f8aSDavid du Colombier sysfatal("readimage %s: %r", path);
3033d156f8aSDavid du Colombier close(fd);
3043d156f8aSDavid du Colombier return i;
3053d156f8aSDavid du Colombier }
3063d156f8aSDavid du Colombier
307312a1df1SDavid du Colombier void
allocblocks(void)308312a1df1SDavid du Colombier allocblocks(void)
309312a1df1SDavid du Colombier {
310312a1df1SDavid du Colombier Rectangle r, b;
311312a1df1SDavid du Colombier ushort i, x, y, sq;
312312a1df1SDavid du Colombier
313312a1df1SDavid du Colombier sq = sqrt(level);
314312a1df1SDavid du Colombier r = insetrect(screen->r, 5);
315312a1df1SDavid du Colombier r.max.x = r.min.x+Facesize*sq+sq*4-1;
316312a1df1SDavid du Colombier r.max.y = r.min.y+Facesize*sq+sq*4-1;
317312a1df1SDavid du Colombier b.max.y = r.min.y;
318312a1df1SDavid du Colombier for(i=level-1, y=0; y!=sq; y++){
319312a1df1SDavid du Colombier b.min.y = b.max.y;
320312a1df1SDavid du Colombier b.max.y = r.min.y+Dy(r)*(y+1)/sq;
321312a1df1SDavid du Colombier b.max.x = r.min.x;
322312a1df1SDavid du Colombier for(x=0; x!=sq; x++, i--){
323312a1df1SDavid du Colombier b.min.x = b.max.x;
324312a1df1SDavid du Colombier b.max.x = r.min.x+Dx(r)*(x+1)/sq;
325312a1df1SDavid du Colombier block[i].r = insetrect(b, 2 );
326312a1df1SDavid du Colombier }
327312a1df1SDavid du Colombier }
328312a1df1SDavid du Colombier }
3293d156f8aSDavid du Colombier
3303d156f8aSDavid du Colombier Image*
readbit(int fd,ulong chan,char * path)3313d156f8aSDavid du Colombier readbit(int fd, ulong chan, char *path)
3323d156f8aSDavid du Colombier {
3333d156f8aSDavid du Colombier char buf[4096], hx[4], *p;
3343d156f8aSDavid du Colombier uchar data[Facesize*Facesize]; /* more than enough */
3353d156f8aSDavid du Colombier int nhx, i, n, ndata, nbit;
3363d156f8aSDavid du Colombier Image *img;
3373d156f8aSDavid du Colombier
3383d156f8aSDavid du Colombier n = readn(fd, buf, sizeof buf);
3393d156f8aSDavid du Colombier if(n <= 0)
3403d156f8aSDavid du Colombier return nil;
3413d156f8aSDavid du Colombier if(n >= sizeof buf)
3423d156f8aSDavid du Colombier n = sizeof(buf)-1;
3433d156f8aSDavid du Colombier buf[n] = '\0';
3443d156f8aSDavid du Colombier
3453d156f8aSDavid du Colombier n = 0;
3463d156f8aSDavid du Colombier nhx = 0;
3473d156f8aSDavid du Colombier nbit = chantodepth(chan);
3483d156f8aSDavid du Colombier ndata = (Facesize*Facesize*nbit)/8;
3493d156f8aSDavid du Colombier p = buf;
3503d156f8aSDavid du Colombier while(n < ndata) {
3513d156f8aSDavid du Colombier p = strpbrk(p+1, "0123456789abcdefABCDEF");
3523d156f8aSDavid du Colombier if(p == nil)
3533d156f8aSDavid du Colombier break;
3543d156f8aSDavid du Colombier if(p[0] == '0' && p[1] == 'x')
3553d156f8aSDavid du Colombier continue;
3563d156f8aSDavid du Colombier
3573d156f8aSDavid du Colombier hx[nhx] = *p;
3583d156f8aSDavid du Colombier if(++nhx == 2) {
3593d156f8aSDavid du Colombier hx[nhx] = 0;
3603d156f8aSDavid du Colombier i = strtoul(hx, 0, 16);
3613d156f8aSDavid du Colombier data[n++] = ~i;
3623d156f8aSDavid du Colombier nhx = 0;
3633d156f8aSDavid du Colombier }
3643d156f8aSDavid du Colombier }
3653d156f8aSDavid du Colombier if(n < ndata)
3663d156f8aSDavid du Colombier sysfatal("short face %s", path);
3673d156f8aSDavid du Colombier
3683d156f8aSDavid du Colombier img = allocimage(display, Rect(0,0,Facesize,Facesize), chan, 0, 0);
3693d156f8aSDavid du Colombier if(img == nil)
3703d156f8aSDavid du Colombier return nil;
371312a1df1SDavid du Colombier
3723d156f8aSDavid du Colombier loadimage(img, img->r, data, ndata);
3733d156f8aSDavid du Colombier return img;
3743d156f8aSDavid du Colombier }
3753d156f8aSDavid du Colombier
3763d156f8aSDavid du Colombier Image*
openface(char * path)3773d156f8aSDavid du Colombier openface(char *path)
3783d156f8aSDavid du Colombier {
3793d156f8aSDavid du Colombier char *p;
3803d156f8aSDavid du Colombier int fd, n;
3813d156f8aSDavid du Colombier
3823d156f8aSDavid du Colombier p = strstr(path, "48x48x");
3833d156f8aSDavid du Colombier if(p == nil)
3843d156f8aSDavid du Colombier return openimage(path);
3853d156f8aSDavid du Colombier n = atoi(p+6);
3863d156f8aSDavid du Colombier if(n < 4){
3873d156f8aSDavid du Colombier if((fd = open(path, OREAD)) < 0)
3883d156f8aSDavid du Colombier sysfatal("open %s: %r", path);
3893d156f8aSDavid du Colombier return readbit(fd, n==1 ? GREY1 : GREY2, path);
3903d156f8aSDavid du Colombier }
3913d156f8aSDavid du Colombier return openimage(path);
3923d156f8aSDavid du Colombier }
393