memo.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  1. /* Federico Benavento <benavento@gmail.com> */
  2. #include <u.h>
  3. #include <libc.h>
  4. #include <draw.h>
  5. #include <event.h>
  6. void eresized(int);
  7. void resize(int i);
  8. void afaces(void);
  9. void allocblocks(void);
  10. Image *openface(char *path);
  11. Image *face[18];
  12. Rectangle brect[36];
  13. char buf[100];
  14. ushort winflag, level;
  15. typedef enum{
  16. ninit,
  17. hide,
  18. disc
  19. }bflag;
  20. struct Block
  21. {
  22. ushort nr;
  23. ushort nc;
  24. bflag flag;
  25. } block[36];
  26. char *buttons[] =
  27. {
  28. "restart",
  29. "easy",
  30. "hard",
  31. "exit",
  32. 0
  33. };
  34. Menu menu =
  35. {
  36. buttons
  37. };
  38. void
  39. main(int argc, char *argv[])
  40. {
  41. Mouse m;
  42. int i, j;
  43. ushort ran, score, attempt, prev, br[2], c[2];
  44. char *fmt;
  45. level=16;
  46. fmt = "you win in %d attempts!";
  47. ARGBEGIN{
  48. default:
  49. goto Usage;
  50. case 'h':
  51. level=36;
  52. break;
  53. }ARGEND
  54. if(argc){
  55. Usage:
  56. fprint(2, "usage: %s [-h]\n", argv0);
  57. exits("usage");
  58. }
  59. if(initdraw(0,0,"memo") < 0)
  60. sysfatal("initdraw failed: %r");
  61. srand(time(0));
  62. einit(Emouse);
  63. Start:
  64. afaces();
  65. winflag=0;
  66. prev=level+1;
  67. score=attempt=0;
  68. for(i=0;i!=level;i++){
  69. block[i].nr=i;
  70. block[i].nc=20;
  71. block[i].flag=ninit;
  72. }
  73. for(i=0;i!=level/2;i++){
  74. for(j=0;j!=2;){
  75. ran=rand()%level;
  76. if(block[ran].nc==20){
  77. block[ran].nc=i;
  78. j++;
  79. }
  80. }
  81. }
  82. eresized(0);
  83. for(;;){
  84. m=emouse();
  85. if(m.buttons)
  86. break;
  87. }
  88. for(i=0;i!=level;i++)
  89. block[i].flag=hide;
  90. eresized(0);
  91. j=0;
  92. for(;; m=emouse()){
  93. switch(m.buttons){
  94. case 1:
  95. while(m.buttons){
  96. for(i=0;i!=level;i++){
  97. if(i!=prev && ptinrect(m.xy,brect[i])){
  98. if(block[i].flag == hide && j<2){
  99. draw( screen,
  100. brect[i],
  101. face[block[i].nc],
  102. nil,
  103. ZP);
  104. c[j]=block[i].nc;
  105. br[j]=i;
  106. j++;
  107. prev=i;
  108. }
  109. break;
  110. }
  111. }
  112. m=emouse();
  113. }
  114. break;
  115. case 4:
  116. switch(emenuhit(3, &m, &menu)) {
  117. case 0: /* restart */
  118. goto Start;
  119. break;
  120. case 1:
  121. level=16;
  122. goto Start;
  123. break;
  124. case 2:
  125. level=36;
  126. goto Start;
  127. break;
  128. case 3:
  129. exits(0);
  130. break;
  131. }
  132. }
  133. if(j==2){
  134. attempt++;
  135. prev=level+1;
  136. j=0;
  137. if(c[0]==c[1]){
  138. score++;
  139. block[br[0]].flag=disc;
  140. block[br[1]].flag=disc;
  141. draw( screen,
  142. brect[br[0]],
  143. allocimagemix(display,DPalebluegreen,DWhite),
  144. nil,
  145. ZP);
  146. draw( screen,
  147. brect[br[1]],
  148. allocimagemix(display,DPalebluegreen,DWhite),
  149. nil,
  150. ZP);
  151. }else{
  152. draw( screen,
  153. brect[br[0]],
  154. allocimagemix(display, 0x00DDDDFF, 0x00DDDDFF),
  155. nil,
  156. ZP);
  157. draw( screen,
  158. brect[br[1]],
  159. allocimagemix(display, 0x00DDDDFF, 0x00DDDDFF),
  160. nil,
  161. ZP);
  162. }
  163. }
  164. if(score==level/2){
  165. winflag=1;
  166. sprint(buf, fmt, attempt);
  167. eresized(0);
  168. for(;;){
  169. m=emouse();
  170. if((m.buttons & 1) || (m.buttons & 4))
  171. break;
  172. }
  173. goto Start;
  174. }
  175. }
  176. }
  177. void
  178. eresized(int new)
  179. {
  180. ushort i, nx, ny;
  181. Point p;
  182. Rectangle wr;
  183. if(new && getwindow(display, Refnone) < 0){
  184. fprint(2, "can't reattach to window");
  185. exits("resized");
  186. }
  187. allocblocks();
  188. draw(screen, screen->r, allocimagemix(display, DPalebluegreen,DWhite), nil, ZP);
  189. if(winflag == 1){
  190. nx=screen->r.max.x/8;
  191. ny=screen->r.max.y/4;
  192. wr=Rect(screen->r.min.x+nx,
  193. screen->r.min.y+ny,
  194. screen->r.max.x-nx,
  195. screen->r.max.y-ny);
  196. draw(screen, wr, allocimagemix(display, 0x00DDDDFF, 0x00DDDDFF), nil, ZP);
  197. p=addpt(wr.min, Pt(5,5));
  198. draw(screen,
  199. Rpt(p, addpt(p, stringsize(font,buf))),
  200. allocimagemix(display,0x00DDDDFF,0x00DDDDFFF),
  201. nil,p);
  202. string(screen,p,display->black,ZP,font,buf);
  203. }else{
  204. for(i=0;i!=level;i++){
  205. switch(block[i].flag){
  206. case ninit:
  207. draw(screen,brect[i],face[block[i].nc],nil,ZP);
  208. break;
  209. case disc:
  210. draw( screen,
  211. brect[i],
  212. allocimagemix(display,DPalebluegreen,DWhite),
  213. nil,
  214. ZP);
  215. break;
  216. case hide:
  217. draw( screen,
  218. brect[i],
  219. allocimagemix(display, 0x00DDDDFF, 0x00DDDDFF),
  220. nil,
  221. ZP);
  222. break;
  223. default:
  224. fprint(2, "something went wrong!");
  225. exits("wrong");
  226. break;
  227. }
  228. }
  229. }
  230. }
  231. char *facepaths[] = {
  232. /* logos */
  233. "/lib/face/48x48x4/g/glenda.1",
  234. "/lib/face/48x48x2/p/pjw+9ball.2",
  235. /* /sys/doc/9.ms authors */
  236. "/lib/face/48x48x2/k/ken.1",
  237. "/lib/face/48x48x4/b/bobf.1",
  238. "/lib/face/48x48x4/p/philw.1",
  239. "/lib/face/48x48x4/p/presotto.1",
  240. "/lib/face/48x48x4/r/rob.1",
  241. "/lib/face/48x48x4/s/sean.1",
  242. /* additional authors and luminaries for harder levels */
  243. "/lib/face/48x48x4/b/bwk.1",
  244. "/lib/face/48x48x4/c/cyoung.1",
  245. "/lib/face/48x48x4/d/dmr.1",
  246. "/lib/face/48x48x4/d/doug.1",
  247. "/lib/face/48x48x4/h/howard.1",
  248. "/lib/face/48x48x4/j/jmk.1",
  249. "/lib/face/48x48x4/s/sape.1",
  250. "/lib/face/48x48x4/s/seanq.1",
  251. "/lib/face/48x48x4/t/td.1",
  252. "/lib/face/48x48x8/l/lucent.1",
  253. };
  254. void
  255. afaces(void)
  256. {
  257. int i;
  258. for(i=0; i<18; i++)
  259. face[i] = openface(facepaths[i]);
  260. }
  261. void
  262. allocblocks(void)
  263. {
  264. Rectangle r, b;
  265. ushort i, x, y, sq;
  266. sq=sqrt(level);
  267. resize(48*sq+sq*4+17);
  268. r=insetrect(screen->r, 5);
  269. r=Rect(r.min.x, r.min.y, r.min.x+48*sq+sq*4-1, r.min.y+48*sq+sq*4-1);
  270. b.max.y=r.min.y;
  271. for(i=level-1, y=0; y!=sq; y++){
  272. b.min.y=b.max.y;
  273. b.max.y=r.min.y+(r.max.y-r.min.y)*(y+1)/sq;
  274. b.max.x=r.min.x;
  275. for(x=0; x!=sq; x++, i--){
  276. b.min.x=b.max.x;
  277. b.max.x=r.min.x+(r.max.x-r.min.x)*(x+1)/sq;
  278. brect[i]=insetrect(b, 2 );
  279. }
  280. }
  281. }
  282. void
  283. resize(int i)
  284. {
  285. int fd;
  286. fd=open("/dev/wctl", OWRITE);
  287. if(fd >= 0){
  288. fprint(fd, "resize -dx %d -dy %d", i, i);
  289. close(fd);
  290. }
  291. }
  292. Image *
  293. openimage(char *path)
  294. {
  295. Image *i;
  296. int fd;
  297. fd=open(path, OREAD);
  298. if(fd < 0)
  299. sysfatal("open %s: %r", path);
  300. i=readimage(display, fd, 0);
  301. if(i == nil)
  302. sysfatal("readimage %s: %r", path);
  303. close(fd);
  304. return i;
  305. }
  306. enum { Facesize = 48 };
  307. Image*
  308. readbit(int fd, ulong chan, char *path)
  309. {
  310. char buf[4096], hx[4], *p;
  311. uchar data[Facesize*Facesize]; /* more than enough */
  312. int nhx, i, n, ndata, nbit;
  313. Image *img;
  314. n = readn(fd, buf, sizeof buf);
  315. if(n <= 0)
  316. return nil;
  317. if(n >= sizeof buf)
  318. n = sizeof(buf)-1;
  319. buf[n] = '\0';
  320. n = 0;
  321. nhx = 0;
  322. nbit = chantodepth(chan);
  323. ndata = (Facesize*Facesize*nbit)/8;
  324. p = buf;
  325. while(n < ndata) {
  326. p = strpbrk(p+1, "0123456789abcdefABCDEF");
  327. if(p == nil)
  328. break;
  329. if(p[0] == '0' && p[1] == 'x')
  330. continue;
  331. hx[nhx] = *p;
  332. if(++nhx == 2) {
  333. hx[nhx] = 0;
  334. i = strtoul(hx, 0, 16);
  335. data[n++] = ~i;
  336. nhx = 0;
  337. }
  338. }
  339. if(n < ndata)
  340. sysfatal("short face %s", path);
  341. img = allocimage(display, Rect(0,0,Facesize,Facesize), chan, 0, 0);
  342. if(img == nil)
  343. return nil;
  344. loadimage(img, img->r, data, ndata);
  345. return img;
  346. }
  347. Image*
  348. openface(char *path)
  349. {
  350. char *p;
  351. int fd, n;
  352. p = strstr(path, "48x48x");
  353. if(p == nil)
  354. return openimage(path);
  355. n = atoi(p+6);
  356. if(n < 4){
  357. if((fd = open(path, OREAD)) < 0)
  358. sysfatal("open %s: %r", path);
  359. return readbit(fd, n==1 ? GREY1 : GREY2, path);
  360. }
  361. return openimage(path);
  362. }