route.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <draw.h>
  4. #include "sokoban.h"
  5. static int trydir(int, Point, Point, Route*, Visited*);
  6. static int dofind(Point, Point, Route*, Visited*);
  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. Route*
  23. newroute(void)
  24. {
  25. Route *r = malloc(sizeof(Route));
  26. memset(r, 0, sizeof(Route));
  27. return r;
  28. }
  29. void
  30. freeroute(Route *r)
  31. {
  32. if (r->step != nil) {
  33. free(r->step);
  34. memset(r, 0, sizeof(Route));
  35. }
  36. free(r);
  37. }
  38. void
  39. reverseroute(Route *r)
  40. {
  41. int i;
  42. Step tmp;
  43. for (i=1; i< r->nstep; i++) {
  44. tmp = r->step[i];
  45. r->step[i] = r->step[i-1];
  46. r->step[i-1] = tmp;
  47. }
  48. }
  49. void
  50. pushstep(Route *r, int dir, int count)
  51. {
  52. if (r->beyond < r->nstep+1) {
  53. r->beyond = r->nstep+1;
  54. r->step = realloc(r->step, sizeof(Step)*r->beyond);
  55. }
  56. if (r->step == nil)
  57. exits("pushstep out of memory");
  58. r->step[r->nstep].dir = dir;
  59. r->step[r->nstep].count = count;
  60. r->nstep++;
  61. }
  62. void
  63. popstep(Route*r)
  64. {
  65. if (r->nstep > 0) {
  66. r->nstep--;
  67. r->step[r->nstep].dir = 0;
  68. r->step[r->nstep].count = 0;
  69. }
  70. }
  71. int
  72. validpush(Point g, Step s, Point *t)
  73. {
  74. int i;
  75. Point m = dir2point(s.dir);
  76. // first test for Cargo next to us (in direction dir)
  77. if (s.count > 0) {
  78. g = addpt(g, m);
  79. if (!ptinrect(g, Rpt(Pt(0,0), level.max)))
  80. return 0;
  81. switch (level.board[g.x ][g.y]) {
  82. case Wall:
  83. case Empty:
  84. case Goal:
  85. return 0;
  86. }
  87. }
  88. // then test for enough free space for us _and_ Cargo
  89. for (i=0; i < s.count; i++) {
  90. g = addpt(g, m);
  91. if (!ptinrect(g, Rpt(Pt(0,0), level.max)))
  92. return 0;
  93. switch (level.board[g.x ][g.y]) {
  94. case Wall:
  95. case Cargo:
  96. case GoalCargo:
  97. return 0;
  98. }
  99. }
  100. if (t != nil)
  101. *t = g;
  102. return 1;
  103. }
  104. int
  105. validwalk(Point g, Step s, Point *t)
  106. {
  107. int i;
  108. Point m = dir2point(s.dir);
  109. for (i=0; i < s.count; i++) {
  110. g = addpt(g, m);
  111. if (!ptinrect(g, Rpt(Pt(0,0), level.max)))
  112. return 0;
  113. switch (level.board[g.x ][g.y]) {
  114. case Wall:
  115. case Cargo:
  116. case GoalCargo:
  117. return 0;
  118. }
  119. }
  120. if (t != nil)
  121. *t = g;
  122. return 1;
  123. }
  124. int
  125. isvalid(Point s, Route* r, int (*isallowed)(Point, Step, Point*))
  126. {
  127. int i;
  128. Point m = s;
  129. for (i=0; i< r->nstep; i++)
  130. if (! isallowed(m, r->step[i], &m))
  131. return 0;
  132. return 1;
  133. }
  134. static int
  135. trydir(int dir, Point m, Point d, Route *r, Visited *v)
  136. {
  137. Point p = dir2point(dir);
  138. Point n = addpt(m, p);
  139. if (ptinrect(n, Rpt(Pt(0,0), level.max)) &&
  140. v->board[n.x][n.y] == 0) {
  141. v->board[n.x][n.y] = 1;
  142. switch (level.board[n.x ][n.y]) {
  143. case Empty:
  144. case Goal:
  145. pushstep(r, dir, 1);
  146. if (dofind(n, d, r, v))
  147. return 1;
  148. else
  149. popstep(r);
  150. }
  151. }
  152. return 0;
  153. }
  154. static int
  155. dofind(Point m, Point d, Route *r, Visited *v)
  156. {
  157. if (eqpt(m, d))
  158. return 1;
  159. v->board[m.x][m.y] = 1;
  160. return trydir(Left, m, d, r, v) ||
  161. trydir(Up, m, d, r, v) ||
  162. trydir(Right, m, d, r, v) ||
  163. trydir(Down, m, d, r, v);
  164. }
  165. static int
  166. dobfs(Point m, Point d, Route *r, Visited *v)
  167. {
  168. if (eqpt(m, d))
  169. return 1;
  170. v->board[m.x][m.y] = 1;
  171. return trydir(Left, m, d, r, v) ||
  172. trydir(Up, m, d, r, v) ||
  173. trydir(Right, m, d, r, v) ||
  174. trydir(Down, m, d, r, v);
  175. }
  176. int
  177. findwalk(Point src, Point dst, Route *r)
  178. {
  179. Visited* v;
  180. int found;
  181. v = malloc(sizeof(Visited));
  182. memset(v, 0, sizeof(Visited));
  183. found = dofind(src, dst, r, v);
  184. free(v);
  185. return found;
  186. }
  187. void
  188. applyroute(Route *r)
  189. {
  190. int j, i;
  191. for (i=0; i< r->nstep; i++) {
  192. j = r->step[i].count;
  193. while (j > 0) {
  194. move(r->step[i].dir);
  195. if (animate) {
  196. drawscreen();
  197. sleep(200);
  198. }
  199. j--;
  200. }
  201. }
  202. }