route.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <draw.h>
  4. #include "sokoban.h"
  5. static int dirlist[] = { Up, Down, Left, Right, Up, Down, Left, Right, };
  6. static int ndir = 4;
  7. static Point
  8. dir2point(int dir)
  9. {
  10. switch(dir) {
  11. case Up:
  12. return Pt(0, -1);
  13. case Down:
  14. return Pt(0, 1);
  15. case Left:
  16. return Pt(-1, 0);
  17. case Right:
  18. return Pt(1, 0);
  19. }
  20. return Pt(0,0);
  21. }
  22. int
  23. validpush(Point g, Step *s, Point *t)
  24. {
  25. int i;
  26. Point m;
  27. if (s == nil)
  28. return 0;
  29. m = dir2point(s->dir);
  30. // first test for Cargo next to us (in direction dir)
  31. if (s->count > 0) {
  32. g = addpt(g, m);
  33. if (!ptinrect(g, Rpt(Pt(0,0), level.max)))
  34. return 0;
  35. switch (level.board[g.x][g.y]) {
  36. case Wall:
  37. case Empty:
  38. case Goal:
  39. return 0;
  40. }
  41. }
  42. // then test for enough free space for us _and_ Cargo
  43. for (i=0; i < s->count; i++) {
  44. g = addpt(g, m);
  45. if (!ptinrect(g, Rpt(Pt(0,0), level.max)))
  46. return 0;
  47. switch (level.board[g.x][g.y]) {
  48. case Wall:
  49. case Cargo:
  50. case GoalCargo:
  51. return 0;
  52. }
  53. }
  54. if (t != nil)
  55. *t = g;
  56. return 1;
  57. }
  58. int
  59. isvalid(Point s, Route* r, int (*isallowed)(Point, Step*, Point*))
  60. {
  61. Point m;
  62. Step *p;
  63. if (r == nil)
  64. return 0;
  65. m = s;
  66. for (p=r->step; p < r->step +r->nstep; p++)
  67. if (! isallowed(m, p, &m))
  68. return 0;
  69. return 1;
  70. }
  71. static Walk*
  72. newwalk(void)
  73. {
  74. Walk *w;
  75. w = malloc(sizeof(Walk));
  76. if (w->route == nil)
  77. sysfatal("cannot allocate walk");
  78. memset(w, 0, sizeof(Walk));
  79. return w;
  80. }
  81. static void
  82. resetwalk(Walk *w)
  83. {
  84. Route **p;
  85. if (w == nil || w->route == nil)
  86. return;
  87. for (p=w->route; p < w->route + w->nroute; p++)
  88. freeroute(*p);
  89. w->nroute = 0;
  90. }
  91. static void
  92. freewalk(Walk *w)
  93. {
  94. if (w == nil)
  95. return;
  96. resetwalk(w);
  97. if(w->route)
  98. free(w->route);
  99. free(w);
  100. }
  101. static void
  102. addroute(Walk *w, Route *r)
  103. {
  104. if (w == nil || r == nil)
  105. return;
  106. if (w->beyond < w->nroute+1) {
  107. w->beyond = w->nroute+1;
  108. w->route = realloc(w->route, sizeof(Route*)*w->beyond);
  109. }
  110. if (w->route == nil)
  111. sysfatal("cannot allocate route in addroute");
  112. w->route[w->nroute] = r;
  113. w->nroute++;
  114. }
  115. void
  116. freeroute(Route *r)
  117. {
  118. if (r == nil)
  119. return;
  120. if (r->step != nil)
  121. free(r->step);
  122. free(r);
  123. }
  124. Route*
  125. extend(Route *rr, int dir, int count, Point dest)
  126. {
  127. Route *r;
  128. r = malloc(sizeof(Route));
  129. if (r == nil)
  130. sysfatal("cannot allocate route in extend");
  131. memset(r, 0, sizeof(Route));
  132. r->dest = dest;
  133. if (count > 0) {
  134. r->nstep = 1;
  135. if (rr != nil)
  136. r->nstep += rr->nstep;
  137. r->step = malloc(sizeof(Step)*r->nstep);
  138. if (r->step == nil)
  139. sysfatal("cannot allocate step in extend");
  140. if (rr != nil)
  141. memmove(r->step, rr->step, sizeof(Step)*rr->nstep);
  142. r->step[r->nstep-1].dir = dir;
  143. r->step[r->nstep-1].count = count;
  144. }
  145. return r;
  146. }
  147. static Step*
  148. laststep(Route*r)
  149. {
  150. if (r != nil && r->nstep > 0) {
  151. return &r->step[r->nstep-1];
  152. }
  153. return nil;
  154. }
  155. static int*
  156. startwithdirfromroute(Route *r, int* dl, int n)
  157. {
  158. Step *s;
  159. int *p;
  160. if (r == nil || dl == nil)
  161. return dl;
  162. s = laststep(r);
  163. if (s == nil || s->count == 0)
  164. return dl;
  165. for (p=dl; p < dl + n; p++)
  166. if (*p == s->dir)
  167. break;
  168. return p;
  169. }
  170. static Route*
  171. bfstrydir(Route *r, int dir, Visited *v)
  172. {
  173. Point m, p, n;
  174. if (r == nil)
  175. return nil;
  176. m = r->dest;
  177. p = dir2point(dir);
  178. n = addpt(m, p);
  179. if (ptinrect(n, Rpt(Pt(0,0), level.max)) &&
  180. v->board[n.x][n.y] == 0) {
  181. v->board[n.x][n.y] = 1;
  182. switch (level.board[n.x][n.y]) {
  183. case Empty:
  184. case Goal:
  185. return extend(r, dir, 1, n);
  186. }
  187. }
  188. return nil;
  189. }
  190. static Route*
  191. bfs(Point src, Point dst, Visited *v)
  192. {
  193. Walk *cur, *new, *tmp;
  194. Route *r, **p;
  195. int progress, *dirs, *dirp;
  196. Point n;
  197. if (v == nil)
  198. return nil;
  199. cur = newwalk();
  200. new = newwalk();
  201. v->board[src.x][src.y] = 1;
  202. r = extend(nil, 0, 0, src);
  203. if (eqpt(src, dst)) {
  204. freewalk(cur);
  205. freewalk(new);
  206. return r;
  207. }
  208. addroute(cur, r);
  209. progress = 1;
  210. while (progress) {
  211. progress = 0;
  212. for (p=cur->route; p < cur->route + cur->nroute; p++) {
  213. dirs = startwithdirfromroute(*p, dirlist, ndir);
  214. for (dirp=dirs; dirp < dirs + ndir; dirp++) {
  215. r = bfstrydir(*p, *dirp, v);
  216. if (r != nil) {
  217. progress = 1;
  218. n = r->dest;
  219. if (eqpt(n, dst)) {
  220. freewalk(cur);
  221. freewalk(new);
  222. return(r);
  223. }
  224. addroute(new, r);
  225. }
  226. }
  227. }
  228. resetwalk(cur);
  229. tmp = cur;
  230. cur = new;
  231. new = tmp;
  232. }
  233. freewalk(cur);
  234. freewalk(new);
  235. return nil;
  236. }
  237. Route*
  238. findroute(Point src, Point dst)
  239. {
  240. Visited v;
  241. Route* r;
  242. memset(&v, 0, sizeof(Visited));
  243. r = bfs(src, dst, &v);
  244. return r;
  245. }