memo.c 6.7 KB

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