home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume37 / assist7g / part02 < prev    next >
Encoding:
Text File  |  1993-05-16  |  16.4 KB  |  499 lines

  1. Newsgroups: comp.sources.misc
  2. From: tom@travis.csd.harris.com (Tom Horsley)
  3. Subject: v37i066:  assist7g - 7th Guest Assistant programs, Part02/02
  4. Message-ID: <1993May18.025124.12495@sparky.imd.sterling.com>
  5. X-Md4-Signature: 717c668bf4d46da6ee8b9fe715205a0c
  6. Date: Tue, 18 May 1993 02:51:24 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: tom@travis.csd.harris.com (Tom Horsley)
  10. Posting-number: Volume 37, Issue 66
  11. Archive-name: assist7g/part02
  12. Environment: UNIX, Perl
  13.  
  14. #! /bin/sh
  15. # This is a shell archive.  Remove anything before this line, then unpack
  16. # it by saving it into a file and typing "sh file".  To overwrite existing
  17. # files, type "sh file -c".  You can also feed this as standard input via
  18. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  19. # will see the following message at the end:
  20. #        "End of archive 2 (of 2)."
  21. # Contents:  bishop.c
  22. # Wrapped by tom@amber on Mon May 17 08:22:23 1993
  23. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  24. if test -f 'bishop.c' -a "${1}" != "-c" ; then 
  25.   echo shar: Will not clobber existing file \"'bishop.c'\"
  26. else
  27. echo shar: Extracting \"'bishop.c'\" \(14089 characters\)
  28. sed "s/^X//" >'bishop.c' <<'END_OF_FILE'
  29. X/* Yet another program in the 7th guest collection. This one solves the
  30. X * bishops problem (which some people claim is easy, but stumped me
  31. X * totally).
  32. X *
  33. X * Here's the deal. There are 4 black bishops and 4 white bishops arranged
  34. X * on a 4 x 5 chessboard like so:
  35. X *
  36. X * B . . . W
  37. X * B . . . W
  38. X * B . . . W
  39. X * B . . . W
  40. X *
  41. X * The idea is to swap the white and black bishops without ever allowing a
  42. X * black bishop to attack a white one and vice versa.
  43. X *
  44. X * This program tackles the problem with a breadth first search operating
  45. X * like so:
  46. X *
  47. X * A hash table is kept of all board positions examined, computing legal
  48. X * moves from one board position involves both checking for positions that
  49. X * can be occupied without being under attack as well as checking to see if
  50. X * we were ever at this board configuration before. Repeated configurations
  51. X * are not allowed.
  52. X *
  53. X * The hash table (in addition to being keyed off the board configuration)
  54. X * keeps a pointer to the board configuration which was the parent of this
  55. X * one (since repeated configurations are not allowed, duplicate parents
  56. X * will not be possible, so only one pointer is needed).
  57. X *
  58. X * A queue of board configurations is kept by starting with the initial
  59. X * board as the only element in the queue.
  60. X *
  61. X * The algorithm proceeds through the queue, creating all possible new board
  62. X * configurations for each element it pops off the head of the queue and
  63. X * placing them on the tail of the queue.
  64. X *
  65. X * When the desired configuration is created, the algorithm terminates, and
  66. X * back-tracks through the hash table entry pointers to trace out the
  67. X * sequence of moves from the initial to the final configuration.
  68. X */
  69. X
  70. X#include <stdio.h>
  71. X
  72. X#define HASH_MAX 2063
  73. X
  74. X/* The BoardConfiguration struct records a particular board configuration.
  75. X * it is also the element kept in the hash table and serves as a member of
  76. X * the processing queue.
  77. X *
  78. X * The board is stored as two words, each holding 20 bits. One mask
  79. X * represents the white bishop positions, the other the black positions.
  80. X *
  81. X * If you imagine the board squares numbered as follows:
  82. X *
  83. X *   0  1  2  3  4
  84. X *   5  6  7  8  9
  85. X *  10 11 12 13 14
  86. X *  15 16 17 18 19
  87. X *
  88. X * Then the bit masks store bishop positions by shifting 1 left by the
  89. X * board position number, then oring it into the mask for the appropriate
  90. X * color. For example, the initial board configuration is:
  91. X */
  92. X#define START_BLACK ((1 << 0) | (1 << 5) | (1 << 10) | (1 << 15))
  93. X#define START_WHITE ((1 << 4) | (1 << 9) | (1 << 14) | (1 << 19))
  94. X
  95. Xtypedef struct bc {
  96. X   struct bc *    next;        /* identical hash codes linked through this */
  97. X   struct bc *    parent;      /* points to board config this derived from */
  98. X   unsigned long  black_mask;  /* black bishop positions */
  99. X   unsigned long  white_mask;  /* white bishop positions */
  100. X} BoardConfiguration;
  101. X
  102. X/* The ProcessQueue struct is used to create a queue of entries to be
  103. X * processed.
  104. X */
  105. Xtypedef struct pq {
  106. X   struct pq * next;
  107. X   BoardConfiguration * bc;
  108. X} ProcessQueue;
  109. X
  110. XProcessQueue * free_space = NULL;
  111. X
  112. XProcessQueue * queue_head = NULL;
  113. XProcessQueue * * queue_tail = &queue_head;
  114. X
  115. X/* hash_tab is the hash table of moves already seen
  116. X */
  117. XBoardConfiguration * hash_tab[HASH_MAX];
  118. X
  119. X/* attacked_from is an array with each entry corresponding to a board
  120. X * position. Each entry is a bit mask showing the other board positions
  121. X * which might attack this one.
  122. X */
  123. Xunsigned long attacked_from[20] = {
  124. X   ((1 << 0) | (1 << 6) | (1 << 12) | (1 << 18)),
  125. X   ((1 << 1) | (1 << 7) | (1 << 13) | (1 << 19) | (1 << 5)),
  126. X   ((1 << 2) | (1 << 8) | (1 << 14) | (1 << 6) | (1 << 10)),
  127. X   ((1 << 3) | (1 << 9) | (1 << 7) | (1 << 11) | (1 << 15)),
  128. X   ((1 << 4) | (1 << 8) | (1 << 12) | (1 << 16)),
  129. X   ((1 << 5) | (1 << 11) | (1 << 17) | (1 << 1)),
  130. X   ((1 << 6) | (1 << 12) | (1 << 18) | (1 << 2) | (1 << 0) | (1 << 10)),
  131. X   ((1 << 7) | (1 << 13) | (1 << 19) | (1 << 3) | (1 << 1) | (1 << 11) |
  132. X    (1 << 15)),
  133. X   ((1 << 8) | (1 << 14) | (1 << 4) | (1 << 2) | (1 << 12) | (1 << 16)),
  134. X   ((1 << 9) | (1 << 3) | (1 << 13) | (1 << 17)),
  135. X   ((1 << 10) | (1 << 16) | (1 << 6) | (1 << 2)),
  136. X   ((1 << 11) | (1 << 17) | (1 << 7) | (1 << 3) | (1 << 5) | (1 << 15)),
  137. X   ((1 << 12) | (1 << 18) | (1 << 8) | (1 << 4) | (1 << 6) | (1 << 0) |
  138. X    (1 << 16)),
  139. X   ((1 << 13) | (1 << 19) | (1 << 9) | (1 << 7) | (1 << 1) | (1 << 17)),
  140. X   ((1 << 14) | (1 << 8) | (1 << 2) | (1 << 18)),
  141. X   ((1 << 15) | (1 << 11) | (1 << 7) | (1 << 3)),
  142. X   ((1 << 16) | (1 << 12) | (1 << 8) | (1 << 4) | (1 << 10)),
  143. X   ((1 << 17) | (1 << 13) | (1 << 9) | (1 << 11) | (1 << 5)),
  144. X   ((1 << 18) | (1 << 14) | (1 << 12) | (1 << 6) | (1 << 0)),
  145. X   ((1 << 19) | (1 << 13) | (1 << 7) | (1 << 1))
  146. X};
  147. X
  148. X/* Each row is a list of positions you can move to from a given position.
  149. X * (each row is terminated with 20 to mark the end of the list.
  150. X */
  151. Xchar move_to[20][7] = {
  152. X   {6, 12, 18, 20},
  153. X   {7, 13, 19, 5, 20},
  154. X   {8, 14, 6, 10, 20},
  155. X   {9, 7, 11, 15, 20},
  156. X   {8, 12, 16, 20},
  157. X   {11, 17, 1, 20},
  158. X   {12, 18, 2, 0, 10, 20},
  159. X   {13, 19, 3, 1, 11, 15, 20},
  160. X   {14, 4, 2, 12, 16, 20},
  161. X   {3, 13, 17, 20},
  162. X   {16, 6, 2, 20},
  163. X   {17, 7, 3, 5, 15, 20},
  164. X   {18, 8, 4, 6, 0, 16, 20},
  165. X   {19, 9, 7, 1, 17, 20},
  166. X   {8, 2, 18, 20},
  167. X   {11, 7, 3, 20},
  168. X   {12, 8, 4, 10, 20},
  169. X   {13, 9, 11, 5, 20},
  170. X   {14, 12, 6, 0, 20},
  171. X   {13, 7, 1, 20}
  172. X};
  173. X
  174. X/* ReflectPieces takes a board mask word and reflects the board positions
  175. X * top for bottom to make a mirror image board position.
  176. X *
  177. X *   0  1  2  3  4
  178. X *   5  6  7  8  9
  179. X *  10 11 12 13 14
  180. X *  15 16 17 18 19
  181. X *
  182. X * becomes:
  183. X *
  184. X *  15 16 17 18 19
  185. X *  10 11 12 13 14
  186. X *   5  6  7  8  9
  187. X *   0  1  2  3  4
  188. X */
  189. Xunsigned long
  190. XReflectPieces(unsigned long bm)
  191. X{
  192. X   unsigned long r0_4 = bm & 0x1f;
  193. X   unsigned long r5_9 = (bm >> 5) & 0x1f;
  194. X   unsigned long r10_14 = (bm >> 10) & 0x1f;
  195. X   unsigned long r15_19 = (bm >> 15) & 0x1f;
  196. X   return (r0_4 << 15) | (r5_9 << 10) | (r10_14 << 5) | r15_19;
  197. X}
  198. X
  199. Xint board_count = 0;
  200. X
  201. X/* NewBoardConfiguration looks up a proposed new board configuration in the
  202. X * hash table. If it is not already there, it creates the new object and
  203. X * installs it in the table, returning a pointer to it. Otherwise it just
  204. X * returns NULL.
  205. X */
  206. XBoardConfiguration *
  207. XNewBoardConfiguration(
  208. X   BoardConfiguration * parent,
  209. X   unsigned long black_mask,
  210. X   unsigned long white_mask)
  211. X{
  212. X   unsigned long hash = (black_mask ^ (white_mask << 11)) % HASH_MAX;
  213. X   BoardConfiguration * ptr = hash_tab[hash];
  214. X   while (ptr != NULL) {
  215. X      if ((ptr->black_mask == black_mask) && (ptr->white_mask == white_mask)) {
  216. X         return NULL;
  217. X      }
  218. X      ptr = ptr->next;
  219. X   }
  220. X   ptr = (BoardConfiguration *)malloc(sizeof(BoardConfiguration));
  221. X   ptr->next = hash_tab[hash];
  222. X   ptr->parent = parent;
  223. X   ptr->black_mask = black_mask;
  224. X   ptr->white_mask = white_mask;
  225. X   hash_tab[hash] = ptr;
  226. X   ++board_count;
  227. X   {
  228. X      /* Before we go, make an entry for the symmetric board configuration
  229. X       * to avoid mirror image duplication of effort...
  230. X       */
  231. X      unsigned long mirror_white = ReflectPieces(white_mask);
  232. X      unsigned long mirror_black = ReflectPieces(black_mask);
  233. X      if ((mirror_white != white_mask) || (mirror_black != black_mask)) {
  234. X         unsigned long hash = (mirror_black ^ (mirror_white << 11)) % HASH_MAX;
  235. X         BoardConfiguration * mptr = hash_tab[hash];
  236. X         while (mptr != NULL) {
  237. X            if ((mptr->black_mask == mirror_black) &&
  238. X                (mptr->white_mask == mirror_white)) {
  239. X               return ptr;
  240. X            }
  241. X            mptr = mptr->next;
  242. X         }
  243. X         mptr = (BoardConfiguration *)malloc(sizeof(BoardConfiguration));
  244. X         mptr->next = hash_tab[hash];
  245. X         mptr->parent = parent;
  246. X         mptr->black_mask = mirror_black;
  247. X         mptr->white_mask = mirror_white;
  248. X         hash_tab[hash] = mptr;
  249. X      }
  250. X   }
  251. X   return ptr;
  252. X}
  253. X
  254. Xvoid
  255. XMakeQueueEntry(BoardConfiguration * new_board)
  256. X{
  257. X   ProcessQueue * qe;
  258. X   if (new_board == NULL) {
  259. X      return;
  260. X   }
  261. X   if (free_space == NULL) {
  262. X      free_space = (ProcessQueue *)malloc(sizeof(ProcessQueue));
  263. X      free_space->next = NULL;
  264. X   }
  265. X   qe = free_space;
  266. X   free_space = qe->next;
  267. X   qe->next = NULL;
  268. X   qe->bc = new_board;
  269. X   *queue_tail = qe;
  270. X   queue_tail = &qe->next;
  271. X}
  272. X
  273. XBoardConfiguration *
  274. XGetQueueHead()
  275. X{
  276. X   ProcessQueue * qe;
  277. X   BoardConfiguration * bc;
  278. X   if (queue_head == NULL) {
  279. X      return NULL;
  280. X   }
  281. X   qe = queue_head;
  282. X   queue_head = qe->next;
  283. X   if (queue_head == NULL) {
  284. X      queue_tail = &queue_head;
  285. X   }
  286. X   bc = qe->bc;
  287. X   qe->next = free_space;
  288. X   free_space = qe;
  289. X   return bc;
  290. X}
  291. X
  292. X/* FindLastPosition actually runs the search algorithm, stopping
  293. X * when it finds a solution and returning a pointer to the final
  294. X * BoardConfiguration entry.
  295. X */
  296. XBoardConfiguration *
  297. XFindLastPosition()
  298. X{
  299. X   BoardConfiguration * hp;
  300. X
  301. X   /* Install the initial board
  302. X    */
  303. X   MakeQueueEntry(NewBoardConfiguration(NULL, START_BLACK, START_WHITE));
  304. X   while ((hp = GetQueueHead()) != NULL) {
  305. X      /* Compute all the legal moves I can make from this board configuration.
  306. X       */
  307. X      int i;
  308. X      unsigned long mask;
  309. X      for (i = 0, mask = (1 << 0); i < 20; ++i, mask <<= 1) {
  310. X         if ((hp->black_mask & mask) != 0) {
  311. X            /* There is a black bishop at position i, check each move it
  312. X             * can make.
  313. X             */
  314. X            int j, d;
  315. X            for (j = 0; ((d = move_to[i][j]) != 20); ++j) {
  316. X               unsigned long dmask = (1 << d);
  317. X               /* Make sure I don't move on top of a piece of the same color
  318. X                */
  319. X               if ((dmask & hp->black_mask) == 0) {
  320. X                  /* And make sure I don't move to a location under attack
  321. X                   * by a piece of the opposite color.
  322. X                   */
  323. X                  if ((attacked_from[d] & hp->white_mask) == 0) {
  324. X                     /* This entry seems legal. Make the new entry and
  325. X                      * make sure it is not a board we have already
  326. X                      * seen before.
  327. X                      */
  328. X                     BoardConfiguration * np =
  329. X                        NewBoardConfiguration(hp,
  330. X                           (hp->black_mask ^ mask) | dmask,
  331. X                           hp->white_mask);
  332. X                     if (np != NULL) {
  333. X                        /* If this is what we have been looking for, return
  334. X                         * it now.
  335. X                         */
  336. X                        if ((np->black_mask == START_WHITE) &&
  337. X                            (np->white_mask == START_BLACK)) {
  338. X                           return np;
  339. X                        }
  340. X                        MakeQueueEntry(np);
  341. X                     }
  342. X                  }
  343. X               }
  344. X            }
  345. X         }
  346. X         if ((hp->white_mask & mask) != 0) {
  347. X            /* There is a white bishop at position i, check each move it
  348. X             * can make.
  349. X             */
  350. X            int j, d;
  351. X            for (j = 0; ((d = move_to[i][j]) != 20); ++j) {
  352. X               unsigned long dmask = (1 << d);
  353. X               /* Make sure I don't move on top of a piece of the same color
  354. X                */
  355. X               if ((dmask & hp->white_mask) == 0) {
  356. X                  /* And make sure I don't move to a location under attack
  357. X                   * by a piece of the opposite color.
  358. X                   */
  359. X                  if ((attacked_from[d] & hp->black_mask) == 0) {
  360. X                     /* This entry seems legal. Make the new entry and
  361. X                      * make sure it is not a board we have already
  362. X                      * seen before.
  363. X                      */
  364. X                     BoardConfiguration * np =
  365. X                        NewBoardConfiguration(hp,
  366. X                           hp->black_mask,
  367. X                           (hp->white_mask ^ mask) | dmask);
  368. X                     if (np != NULL) {
  369. X                        /* If this is what we have been looking for, return
  370. X                         * it now.
  371. X                         */
  372. X                        if ((np->white_mask == START_WHITE) &&
  373. X                            (np->black_mask == START_BLACK)) {
  374. X                           return np;
  375. X                        }
  376. X                        MakeQueueEntry(np);
  377. X                     }
  378. X                  }
  379. X               }
  380. X            }
  381. X         }
  382. X      }
  383. X   }
  384. X}
  385. X
  386. Xchar * bit_names[20] = {
  387. X   "a1", "b1", "c1", "d1", "e1",
  388. X   "a2", "b2", "c2", "d2", "e2",
  389. X   "a3", "b3", "c3", "d3", "e3",
  390. X   "a4", "b4", "c4", "d4", "e4"
  391. X};
  392. X
  393. Xvoid
  394. XPrintBit(unsigned long mask)
  395. X{
  396. X   unsigned long t;
  397. X   int i;
  398. X   for (i = 0, t = (1 << 0); i < 20; ++i, t <<= 1) {
  399. X      if (mask & t) {
  400. X         printf(bit_names[i]);
  401. X         return;
  402. X      }
  403. X   }
  404. X   printf("??");
  405. X   return;
  406. X}
  407. X
  408. Xstatic int move_num = 0;
  409. X
  410. Xvoid
  411. XPrintSolution(BoardConfiguration * bp)
  412. X{
  413. X   int i,j;
  414. X   unsigned long mask;
  415. X
  416. X   if (bp == NULL) {
  417. X      return;
  418. X   }
  419. X   PrintSolution(bp->parent);
  420. X   printf("Board %d:\n", move_num++);
  421. X   printf("  a b c d e ");
  422. X   if (bp->parent == NULL) {
  423. X      printf("starting position\n");
  424. X   } else {
  425. X      /* Figure out what the move was in algebraic notation and print that.
  426. X       */
  427. X      unsigned long old_mask = (bp->parent->black_mask |
  428. X                                bp->parent->white_mask);
  429. X      unsigned long new_mask = (bp->black_mask | bp->white_mask);
  430. X      unsigned long changed_mask = old_mask ^ new_mask;
  431. X      unsigned long old_bit = old_mask & changed_mask;
  432. X      unsigned long new_bit = new_mask & changed_mask;
  433. X      PrintBit(old_bit);
  434. X      printf("-");
  435. X      PrintBit(new_bit);
  436. X      printf("\n");
  437. X   }
  438. X   mask = (1 << 0);
  439. X   for (i = 0; i < 4; ++i) {
  440. X      printf("%d", i + 1);
  441. X      for (j = 0; j < 5; ++j) {
  442. X         if (bp->black_mask & mask) {
  443. X            printf(" B");
  444. X         } else if (bp->white_mask & mask) {
  445. X            printf(" W");
  446. X         } else {
  447. X            printf(" .");
  448. X         }
  449. X         mask <<= 1;
  450. X      }
  451. X      printf("\n");
  452. X   }
  453. X}
  454. X
  455. Xint
  456. Xmain(int argc, char ** argv)
  457. X{
  458. X   BoardConfiguration * bp = FindLastPosition();
  459. X   if (bp == NULL) {
  460. X      printf("Failed to find solution.\n");
  461. X      exit(2);
  462. X   }
  463. X   PrintSolution(bp);
  464. X   printf("The total board count examined was %d.\n",board_count);
  465. X}
  466. END_OF_FILE
  467. if test 14089 -ne `wc -c <'bishop.c'`; then
  468.     echo shar: \"'bishop.c'\" unpacked with wrong size!
  469. fi
  470. # end of 'bishop.c'
  471. fi
  472. echo shar: End of archive 2 \(of 2\).
  473. cp /dev/null ark2isdone
  474. MISSING=""
  475. for I in 1 2 ; do
  476.     if test ! -f ark${I}isdone ; then
  477.     MISSING="${MISSING} ${I}"
  478.     fi
  479. done
  480. if test "${MISSING}" = "" ; then
  481.     echo You have unpacked both archives.
  482.     rm -f ark[1-9]isdone
  483. else
  484.     echo You still need to unpack the following archives:
  485.     echo "        " ${MISSING}
  486. fi
  487. ##  End of shell archive.
  488. exit 0
  489. --
  490. ======================================================================
  491. domain: tahorsley@csd.harris.com       USMail: Tom Horsley
  492.   uucp: ...!uunet!hcx1!tahorsley               511 Kingbird Circle
  493.                                                Delray Beach, FL  33444
  494. +==== Censorship is the only form of Obscenity ======================+
  495. |     (Wait, I forgot government tobacco subsidies...)               |
  496. +====================================================================+
  497.  
  498. exit 0 # Just in case...
  499.