#include #include #include #include #include #include enum{RESIZE, MOUSE, KEYBOARD}; Image *bunny; int state, win, dummy, g0, g1, won[2], played[2]; char *s0 = "I can reveal that there is no bunny behind door x."; char *s1 = "You may stick with door m or switch to door n. What'll it be?"; Rectangle doorrect(int n){ Point p; p.x = screen->r.min.x + screen->r.max.x - bunny->r.max.x >> 1; if(n < 1) p.x = screen->r.min.x + p.x - bunny->r.max.x >> 1; if(n > 1) p.x = p.x + screen->r.max.x >> 1; p.y = screen->r.min.y + screen->r.max.y - bunny->r.max.y >> 1; return rectaddpt(bunny->r, p); } void drawdoor(int n){ Rectangle r; r = doorrect(n); if(n == win && state == 3){ draw(screen, r, bunny, nil, ZP); return; } draw(screen, r, display->black, nil, ZP); if(n == dummy || state == 2 && n != win) return; r = insetrect(r, 12); draw(screen, r, display->white, nil, ZP); } int indoor(Point p){ if(ptinrect(p, doorrect(0))) return 0; if(ptinrect(p, doorrect(1))) return 1; if(ptinrect(p, doorrect(2))) return 2; return -1; } void one(int n){ g0 = n; if(n == win) dummy = (n + 1 + (lrand() & 1)) % 3; else for(dummy = 0; dummy == n || dummy == win; dummy++) ; for(g1 = 0; g1 == g0 || g1 == dummy; g1++) ; s0[48] = '1' + dummy; s1[24] = '1' + g0; s1[44] = '1' + g1; state = 1; } void two(int n){ if(n == win){ state = 3; won[n == g1]++; }else state = 2; played[n == g1]++; } void zero(void){ state = 0; dummy = -1; win = nrand(3); } void threadmain(int, char**){ Keyboardctl *kctl; Mousectl *mctl; uchar *d; Rune ᚱ; int i, j; Alt a[] = { [RESIZE]{nil, nil, CHANRCV}, [MOUSE]{nil, nil, CHANRCV}, [KEYBOARD]{nil, &ᚱ, CHANRCV}, {nil, nil, CHANEND} }; if(initdraw(nil, nil, "Monty Hall") < 0) sysfatal("initdraw: %r"); d = malloc(256 * 320); i = open("/lib/bunny.bit", OREAD); if(d == nil || i < 0 || (bunny = readimage(display, i, 0)) == nil) sysfatal("sad bunny"); close(i); unloadimage(bunny, Rect(24, 5, 152, 165), d, 128 * 160); freeimage(bunny); bunny = allocimage(display, Rect(0, 0, 256, 320), GREY8, 0, DNofill); for(i = 159; i >= 0; i--) for(j = 127; j >= 0; j--) d[i << 9 | j << 1] = d[i << 9 | j << 1 | 1] = d[2 * i + 1 << 8 | j << 1] = d[2 * i + 1 << 8 | j << 1 | 1] = d[i << 7 | j]; loadimage(bunny, bunny->r, d, 256 * 320); free(d); mctl = initmouse(nil, screen); kctl = initkeyboard(nil); if(mctl == nil || kctl == nil) sysfatal("init: %r"); a[RESIZE].c = mctl->resizec; a[MOUSE].c = mctl->c; a[MOUSE].v = &mctl->Mouse; a[KEYBOARD].c = kctl->c; srand(truerand()); zero(); sendul(mctl->resizec, 1); while(9){ switch(alt(a)){ case RESIZE: getwindow(display, Refnone); break; case MOUSE: if(mctl->buttons != 1) continue; i = indoor(mctl->xy); while(alt(a) != MOUSE || mctl->buttons) ; switch(state){ case 0: if(i < 0 || i != indoor(mctl->xy)) continue; one(i); break; case 1: if(i < 0 || i == dummy || i != indoor(mctl->xy)) continue; two(i); break; default: zero(); break; } break; case KEYBOARD: switch(ᚱ){ case Kdel: case 'q': print("games played: %d\n", played[0] + played[1]); if(played[0]) print("games won by sticking to your guns: %d / %d (%g%%)\n", won[0], played[0], 100.0 * won[0] / played[0]); if(played[1]) print("games won by swapping doors: %d / %d (%g%%)\n", won[1], played[1], 100.0 * won[1] / played[1]); threadexitsall(nil); case '1': case '2': case '3': i = ᚱ - '1'; if(state == 0){ one(i); break; } if(state == 1){ two(i); break; } default: if(state < 2) continue; zero(); break; } } draw(screen, screen->r, display->white, nil, ZP); drawdoor(0); drawdoor(1); drawdoor(2); switch(state){ case 0: string(screen, screen->r.min, display->black, ZP, font, "Choose the door you think the bunny is behind."); break; case 1: string(screen, screen->r.min, display->black, ZP, font, s0); string(screen, Pt(screen->r.min.x, screen->r.min.y + font->height), display->black, ZP, font, s1); break; case 2: string(screen, screen->r.min, display->black, ZP, font, "Sorry, no bunny there! Press q to quit or any other key to play again."); break; case 3: string(screen, screen->r.min, display->black, ZP, font, "Nice! you found the bunny! Press q to quit or any other key to play again."); break; } flushimage(display, 1); } }