sokoban.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <draw.h>
  4. #include <event.h>
  5. #include "sokoban.h"
  6. #define SOKOTREE "/sys/games/lib/sokoban/"
  7. char *LEasy = SOKOTREE "levels/easy.slc";
  8. char *LHard = SOKOTREE "levels/hard.slc";
  9. char *levelfile;
  10. #define SOKOIMG SOKOTREE "images/"
  11. char *GRImage = SOKOIMG "right.bit";
  12. char *GLImage = SOKOIMG "left.bit";
  13. char *WallImage = SOKOIMG "wall.bit";
  14. char *EmptyImage = SOKOIMG "empty.bit";
  15. char *CargoImage = SOKOIMG "cargo.bit";
  16. char *GoalCargoImage= SOKOIMG "goalcargo.bit";
  17. char *GoalImage = SOKOIMG "goal.bit";
  18. char *WinImage = SOKOIMG "win.bit";
  19. char *buttons[] =
  20. {
  21. "restart",
  22. "easy",
  23. "hard",
  24. "noanimate", /* this menu string initialized in main */
  25. "exit",
  26. 0
  27. };
  28. char **levelnames;
  29. Menu menu =
  30. {
  31. buttons,
  32. };
  33. Menu lmenu =
  34. {
  35. levelnames,
  36. };
  37. void
  38. buildmenu(void)
  39. {
  40. int i;
  41. if (levelnames != nil) {
  42. for(i=0; levelnames[i] != 0; i++)
  43. free(levelnames[i]);
  44. }
  45. levelnames = realloc(levelnames, sizeof(char*)*(numlevels+1));
  46. if (levelnames == nil)
  47. sysfatal("cannot allocate levelnames");
  48. for(i=0; i < numlevels; i++)
  49. levelnames[i] = genlevels(i);
  50. levelnames[numlevels] = 0;
  51. lmenu.item = levelnames;
  52. }
  53. Image *
  54. eallocimage(Rectangle r, int repl, uint color)
  55. {
  56. Image *tmp;
  57. tmp = allocimage(display, r, screen->chan, repl, color);
  58. if(tmp == nil)
  59. sysfatal("cannot allocate buffer image: %r");
  60. return tmp;
  61. }
  62. Image *
  63. eloadfile(char *path)
  64. {
  65. Image *img;
  66. int fd;
  67. fd = open(path, OREAD);
  68. if(fd < 0) {
  69. fprint(2, "cannot open image file %s: %r\n", path);
  70. exits("image");
  71. }
  72. img = readimage(display, fd, 0);
  73. if(img == nil)
  74. sysfatal("cannot load image: %r");
  75. close(fd);
  76. return img;
  77. }
  78. void
  79. allocimages(void)
  80. {
  81. Rectangle one = Rect(0, 0, 1, 1);
  82. bg = eallocimage(one, 1, DDarkyellow);
  83. text = eallocimage(one, 1, DBluegreen);
  84. gright = eloadfile(GRImage);
  85. gleft = eloadfile(GLImage);
  86. wall = eloadfile(WallImage);
  87. empty = eloadfile(EmptyImage);
  88. empty->repl = 1;
  89. goalcargo = eloadfile(GoalCargoImage);
  90. cargo = eloadfile(CargoImage);
  91. goal = eloadfile(GoalImage);
  92. win = eloadfile(WinImage);
  93. }
  94. int
  95. key2move(int key)
  96. {
  97. int k = 0;
  98. switch(key) {
  99. case 61454:
  100. k = Up;
  101. break;
  102. case 63488:
  103. k = Down;
  104. break;
  105. case 61457:
  106. k = Left;
  107. break;
  108. case 61458:
  109. k = Right;
  110. break;
  111. }
  112. return k;
  113. }
  114. static Route*
  115. mouse2route(Mouse m)
  116. {
  117. Point p, q;
  118. Route *r;
  119. p = subpt(m.xy, screen->r.min);
  120. p.x /= BoardX;
  121. p.y /= BoardY;
  122. q = subpt(p, level.glenda);
  123. // fprint(2, "x=%d y=%d\n", q.x, q.y);
  124. if (q.x == 0 && q.y == 0)
  125. return nil;
  126. if (q.x == 0 || q.y == 0) {
  127. if (q.x < 0)
  128. r = extend(nil, Left, -q.x, Pt(level.glenda.x, p.y));
  129. else if (q.x > 0)
  130. r = extend(nil, Right, q.x, Pt(level.glenda.x, p.y));
  131. else if (q.y < 0)
  132. r = extend(nil, Up, -q.y, level.glenda);
  133. else if (q.y > 0)
  134. r = extend(nil, Down, q.y, level.glenda);
  135. else
  136. r = nil;
  137. if (r != nil && isvalid(level.glenda, r, validpush))
  138. return r;
  139. freeroute(r);
  140. }
  141. return findroute(level.glenda, p);
  142. }
  143. char *
  144. genlevels(int i)
  145. {
  146. if(i >= numlevels)
  147. return 0;
  148. return smprint("level %d", i+1);
  149. }
  150. int
  151. finished(void)
  152. {
  153. int x, y;
  154. for(x = 0; x < MazeX; x++)
  155. for(y = 0; y < MazeY; y++)
  156. if(level.board[x][y] == Goal)
  157. return 0;
  158. return 1;
  159. }
  160. void
  161. eresized(int new)
  162. {
  163. Point p;
  164. if(new && getwindow(display, Refnone) < 0)
  165. sysfatal("can't reattach to window");
  166. p = Pt(Dx(screen->r), Dy(screen->r));
  167. if(!new || !eqpt(p, boardsize(level.max))) {
  168. drawlevel();
  169. }
  170. drawscreen();
  171. }
  172. void
  173. main(int argc, char **argv)
  174. {
  175. Mouse m;
  176. Event ev;
  177. int e;
  178. Route *r;
  179. int timer;
  180. Animation a;
  181. int animate;
  182. if(argc == 2)
  183. levelfile = argv[1];
  184. else
  185. levelfile = LEasy;
  186. if(! loadlevels(levelfile)) {
  187. fprint(2, "usage: %s [levelfile]\n", argv[0]);
  188. exits("usage");
  189. }
  190. buildmenu();
  191. animate = 0;
  192. buttons[3] = animate ? "noanimate" : "animate";
  193. if(initdraw(nil, nil, "sokoban") < 0)
  194. sysfatal("initdraw failed: %r");
  195. einit(Emouse|Ekeyboard);
  196. timer = etimer(0, 200);
  197. initanimation(&a);
  198. allocimages();
  199. glenda = gright;
  200. eresized(0);
  201. for(;;) {
  202. e = event(&ev);
  203. switch(e) {
  204. case Emouse:
  205. m = ev.mouse;
  206. if(m.buttons&1) {
  207. stopanimation(&a);
  208. r = mouse2route(m);
  209. if (r)
  210. setupanimation(&a, r);
  211. if (! animate) {
  212. while(onestep(&a))
  213. ;
  214. drawscreen();
  215. }
  216. }
  217. if(m.buttons&2) {
  218. int l;
  219. /* levels start from 1 */
  220. lmenu.lasthit = level.index;
  221. l=emenuhit(2, &m, &lmenu);
  222. if(l>=0){
  223. stopanimation(&a);
  224. level = levels[l];
  225. drawlevel();
  226. drawscreen();
  227. }
  228. }
  229. if(m.buttons&4)
  230. switch(emenuhit(3, &m, &menu)) {
  231. case 0:
  232. stopanimation(&a);
  233. level = levels[level.index];
  234. drawlevel();
  235. drawscreen();
  236. break;
  237. case 1:
  238. stopanimation(&a);
  239. loadlevels(LEasy);
  240. buildmenu();
  241. drawlevel();
  242. drawscreen();
  243. break;
  244. case 2:
  245. stopanimation(&a);
  246. loadlevels(LHard);
  247. buildmenu();
  248. drawlevel();
  249. drawscreen();
  250. break;
  251. case 3:
  252. animate = !animate;
  253. buttons[3] = animate ? "noanimate" : "animate";
  254. break;
  255. case 4:
  256. exits(nil);
  257. }
  258. break;
  259. case Ekeyboard:
  260. if(level.done)
  261. break;
  262. stopanimation(&a);
  263. switch(ev.kbdc) {
  264. case 127:
  265. case 'q':
  266. case 'Q':
  267. exits(nil);
  268. case 'n':
  269. case 'N':
  270. if(level.index < numlevels - 1) {
  271. level = levels[++level.index];
  272. drawlevel();
  273. drawscreen();
  274. }
  275. break;
  276. case 'p':
  277. case 'P':
  278. if(level.index > 0) {
  279. level = levels[--level.index];
  280. drawlevel();
  281. drawscreen();
  282. }
  283. break;
  284. case 'r':
  285. case 'R':
  286. level = levels[level.index];
  287. drawlevel();
  288. drawscreen();
  289. break;
  290. case 61454:
  291. case 63488:
  292. case 61457:
  293. case 61458:
  294. case ' ':
  295. move(key2move(ev.kbdc));
  296. drawscreen();
  297. break;
  298. default:
  299. // fprint(2, "key: %d]\n", e.kbdc);
  300. break;
  301. }
  302. break;
  303. default:
  304. if (e == timer) {
  305. if (animate)
  306. onestep(&a);
  307. else
  308. while(onestep(&a))
  309. ;
  310. drawscreen();
  311. }
  312. break;
  313. }
  314. if(finished()) {
  315. level.done = 1;
  316. drawwin();
  317. drawscreen();
  318. sleep(3000);
  319. if(level.index < numlevels - 1) {
  320. level = levels[++level.index];
  321. drawlevel();
  322. drawscreen();
  323. }
  324. }
  325. }
  326. }