savitch.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <ctype.h>
  5. #include <math.h>
  6. #include "sokoban.h"
  7. #include "savitch.h"
  8. #include "solver.h"
  9. //corners are mark 'c' in the corner stirng
  10. // g also points to level, rather than goal
  11. void level_find_corner_2(char *lvl, char * g, char *corner, int wh, int w){
  12. int i,j,k;
  13. //init
  14. for(i=0;i<wh;i++) {
  15. switch(lvl[i]){
  16. case '#':
  17. case '_':
  18. corner[i]=lvl[i];break;
  19. default: corner[i]='-'; break;
  20. }
  21. }
  22. //first mark
  23. for(i=0;i<wh;i++){
  24. if(corner[i]=='-'){
  25. if( (corner[i-1]=='#' && corner[i-w]=='#') ||
  26. (corner[i-1]=='#' && corner[i+w]=='#') ||
  27. (corner[i+1]=='#' && corner[i-w]=='#') ||
  28. (corner[i+1]=='#' && corner[i+w]=='#') ){
  29. if(g[i]!='$') corner[i]='c'; //mark corner squares
  30. }
  31. else if( corner[i-1]=='#' || corner[i+1]=='#' ||
  32. corner[i-w]=='#' || corner[i+w]=='#' ){
  33. if(g[i]!='$') corner[i]='e'; //mark edge squares
  34. }
  35. }
  36. }
  37. //second mark
  38. for(i=0;i<wh;i++){
  39. if(corner[i]=='e'){
  40. //horizontal check
  41. if(corner[i-1]=='c'){
  42. for(j=i; corner[j]=='e';j++){
  43. }
  44. if(corner[j]=='c'){
  45. for(k=i;k<j;k++) corner[k]='c'; //mark a line of edge squares
  46. }
  47. }
  48. //vertical check
  49. if(corner[i-w]=='c'){
  50. for(j=i; corner[j]=='e'; j+=w){}
  51. if(corner[j]=='c'){
  52. for(k=i;k<j;k+=w) corner[k]='c'; //mark a vertical edge
  53. }
  54. }
  55. }
  56. }
  57. }
  58. //return 1 is done
  59. //return 0 if the current configuration is the last configuration
  60. int box_next_config(int *box, int nbox, int nsquare){
  61. int i=1,j;
  62. if(box[nbox-1]!=nsquare-1) {
  63. (box[nbox-1])++;
  64. return 1;
  65. }
  66. for(; box[nbox-i]==nsquare-i && i<=nbox; i++){}
  67. if(i== (nbox+1) ) return 0;
  68. box[nbox-i]++;
  69. for(j=nbox-i+1; j<nbox;j++){
  70. box[j]=box[j-1]+1;
  71. }
  72. return 1;
  73. }
  74. void box_init_config(int *box, int nbox){
  75. int i;
  76. for(i=0;i<nbox;i++){
  77. box[i]=i;
  78. }
  79. }
  80. void box_printf(int *box, int nbox){
  81. int i;
  82. for(i=0;i<nbox;i++){
  83. printf("%d,",box[i]);
  84. }
  85. printf("\n");
  86. }
  87. //return the number of different boxes
  88. //the index [in lvl1] of the last box is return by 'box'
  89. int level_compare_box(char *lvl1, char *lvl2, int wh, int *box){
  90. int i,n=0;
  91. for(i=0;i<wh;i++){
  92. if(lvl1[i]=='$'){
  93. if(lvl2[i]!='$') {*box=i; n++;}
  94. }
  95. }
  96. return n;
  97. }
  98. //return 1 if r2 and be obtained from r1 in at most n pushes
  99. // 0 otherwise
  100. int savitch(RNODE *r1, RNODE *r2, int n, int k){
  101. RNODE rm;
  102. int i,j;
  103. int box1,box2;
  104. int wh=r1->w * r1->h;
  105. int bi2i[LEVEL_SIZE * sizeof(int)];
  106. int box[LEVEL_SIZE * sizeof(int)];
  107. char corner[LEVEL_SIZE * sizeof(int)];
  108. int nbox=0;
  109. int nsquare=0;
  110. char clvl[LEVEL_SIZE]; // a copy of the level without boxes
  111. //char mlvl[LEVEL_SIZE];
  112. int t[LEVEL_SIZE * sizeof(int)];
  113. int timestamp=1;
  114. int direction;
  115. int n1=n/2;
  116. int n2=n/2 + n%2;
  117. int dead;
  118. k++;
  119. memset(t,0,LEVEL_SIZE *sizeof(int));
  120. //printf("n1,n2=%d,%d (k=%d)\n",n1,n2, k);
  121. //
  122. strncpy(clvl, r1->level, wh);
  123. for(i=0;i<wh;i++) {
  124. if(clvl[i]=='$') clvl[i]='-';
  125. }
  126. //find the number of boxes and squares
  127. for(i=0;i<wh;i++){
  128. switch(r1->level[i]){
  129. case '$':
  130. bi2i[nsquare]=i;
  131. nbox++;
  132. nsquare++;break;
  133. case '@':
  134. case '-':
  135. bi2i[nsquare]=i;
  136. nsquare++;break;
  137. default: bi2i[i]=0xFFFFFFFF;break;
  138. }
  139. }
  140. //printf("#box=%d\n", nbox);
  141. //printf("#square=%d\n", nsquare);
  142. //find corner
  143. level_find_corner_2(r1->level, r2->level, corner, wh, r1->w);
  144. //check for 0 or 1 step
  145. switch(level_compare_box(r1->level, r2->level, wh, &box1)){
  146. case 0:
  147. if ( level_compare(r1->level,r1->w, r1->pusher, r2->pusher, t, &timestamp)) return 1;
  148. break;
  149. case 1:
  150. level_compare_box(r2->level, r1->level, wh, &box2);
  151. direction=box2-box1;
  152. //printf("direction=%d\n",direction);
  153. if(direction==1 || direction==-1 || direction==r1->w || direction==r1->w * (-1) ){
  154. if ( level_compare(r1->level, r1->w, r1->pusher, box1-direction, t, &timestamp) &&
  155. level_compare(r2->level, r1->w, box1, r2->pusher, t, &timestamp) ) return 1; // tricky
  156. }
  157. break;
  158. default:
  159. break;
  160. }
  161. if(n<=1){ return 0;}
  162. //
  163. box_init_config(box, nbox);
  164. do{
  165. //box_printf(box,nbox);
  166. dead=0;
  167. strncpy(rm.level,clvl,wh);
  168. for(i=0;i<nbox;i++){
  169. if( corner[ bi2i[box[i]] ]=='c') {dead=1;break;}
  170. rm.level[ bi2i[box[i]] ]='$';
  171. }
  172. if(dead) continue;//this is a dead configuration, try next
  173. rm.w=r1->w;
  174. rm.h=r1->h;
  175. rm.pusher=0;
  176. for(i=0;i<nsquare;i++){
  177. if( rm.level[ bi2i[i] ]!='$' ) { //assign pusher to each of the empty square
  178. if(rm.pusher!=0 && level_compare(rm.level, rm.w, rm.pusher, bi2i[i], t, &timestamp) ) continue; //next square
  179. rm.pusher = bi2i[i];
  180. //printf("pusher=%d\n",rm.pusher);
  181. //recursive part
  182. if( savitch(r1, &rm, n1, k) && savitch(&rm, r2, n2, k) ) {
  183. for(j=0;j<wh;j++){
  184. if(j%r1->w==0) printf("\n");
  185. printf("%c", rm.level[j]);
  186. }printf(" (pusher=%d) [%d] \n",rm.pusher,k);
  187. return 1;
  188. }
  189. }
  190. }
  191. }
  192. while(box_next_config(box, nbox, nsquare));
  193. return 0;
  194. }
  195. //the main function for SOKOBAN type
  196. //return 1 if the level can be solved in n pushes,
  197. //return 0 otherwise
  198. int sokoban_savitch(SOKOBAN *skb, int n){
  199. RNODE r1;
  200. RNODE r2;
  201. int i,j,k=0;
  202. int wh=skb->w *skb->h;
  203. int t[LEVEL_SIZE * sizeof(int)];
  204. int timestamp=1;
  205. memset(t,0,LEVEL_SIZE *sizeof(int));
  206. //init r1
  207. strncpy(r1.level, skb->level, wh);
  208. r1.w=skb->w;
  209. r1.h=skb->h;
  210. r1.pusher=skb->w* skb->pi + skb->pj;
  211. r1.level[r1.pusher]='-';
  212. /*
  213. for(i=0;i<wh;i++){
  214. if(i%skb->w==0) printf("\n");
  215. printf("%c", r1.level[i]);
  216. }printf("\n");*/
  217. //init r2
  218. strncpy(r2.level, skb->level, wh);
  219. for(i=0;i<wh;i++){
  220. if(r2.level[i]=='$') r2.level[i]='-';
  221. if(skb->target[i]=='.') r2.level[i]='$';
  222. }
  223. r2.w=skb->w;
  224. r2.h=skb->h;
  225. r2.pusher=0;
  226. /*
  227. printf("pusher=%d\n",r2.pusher);
  228. for(i=0;i<wh;i++){
  229. if(i%skb->w==0) printf("\n");
  230. printf("%c", r2.level[i]);
  231. }printf("\n");
  232. printf("diff=%d\n", level_compare_box(r1.level, r2.level, wh, &i) ); */
  233. //as we have no idea where the pusher should be
  234. // in the solved configuration, we should check all possible positions
  235. for(i=0;i<wh;i++){
  236. if(r2.level[i]=='-'){ // a possible final position of the pusher
  237. if(r2.pusher!=0 && level_compare(r2.level, r2.w, r2.pusher, i, t, &timestamp) ) continue; //next square
  238. r2.pusher=i;
  239. if( savitch(&r1, &r2, n, k) ){
  240. return 1;
  241. }
  242. }
  243. }
  244. return 0;
  245. }