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

  1. Newsgroups: comp.sources.misc
  2. From: tom@travis.csd.harris.com (Tom Horsley)
  3. Subject: v37i065:  assist7g - 7th Guest Assistant programs, Part01/02
  4. Message-ID: <csm-v37i065=assist7g.214943@sparky.IMD.Sterling.COM>
  5. X-Md4-Signature: e08d3018b3242c110f5a9bd3c6cd0888
  6. Date: Tue, 18 May 1993 02:49:57 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 65
  11. Archive-name: assist7g/part01
  12. Environment: UNIX, Perl
  13.  
  14. This is a set of small programs I wrote to solve or help solve puzzles in
  15. the 7th Guest game (a terrific CDROM based PC multimedia game). I have
  16. gotten several requests for these, and since I have now finished the game,
  17. the set of programs is as complete as it will ever get, so I am submitting
  18. it to comp.sources.misc.
  19. ---------------------
  20. #! /bin/sh
  21. # This is a shell archive.  Remove anything before this line, then unpack
  22. # it by saving it into a file and typing "sh file".  To overwrite existing
  23. # files, type "sh file -c".  You can also feed this as standard input via
  24. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  25. # will see the following message at the end:
  26. #        "End of archive 1 (of 2)."
  27. # Contents:  MANIFEST README cans cell.c knight.c queen.c tile.c tiles
  28. # Wrapped by tom@amber on Mon May 17 08:22:23 1993
  29. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  30. if test -f 'MANIFEST' -a "${1}" != "-c" ; then 
  31.   echo shar: Will not clobber existing file \"'MANIFEST'\"
  32. else
  33. echo shar: Extracting \"'MANIFEST'\" \(393 characters\)
  34. sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
  35. X   File Name        Archive #    Description
  36. X-----------------------------------------------------------
  37. X MANIFEST                   1    This shipping list
  38. X README                     1    
  39. X bishop.c                   2    
  40. X cans                       1    
  41. X cell.c                     1    
  42. X knight.c                   1    
  43. X queen.c                    1    
  44. X tile.c                     1    
  45. X tiles                      1    
  46. END_OF_FILE
  47. if test 393 -ne `wc -c <'MANIFEST'`; then
  48.     echo shar: \"'MANIFEST'\" unpacked with wrong size!
  49. fi
  50. # end of 'MANIFEST'
  51. fi
  52. if test -f 'README' -a "${1}" != "-c" ; then 
  53.   echo shar: Will not clobber existing file \"'README'\"
  54. else
  55. echo shar: Extracting \"'README'\" \(1982 characters\)
  56. sed "s/^X//" >'README' <<'END_OF_FILE'
  57. XThis is the 7th Guest Assistant family of programs. These tools can be
  58. Xused to solve (or help solve) many of the puzzles in the 7th Guest game.
  59. XAs I have now managed to finish the game, this is the final release
  60. Xof these tools. If there are other programs you want, you'll have to
  61. Xwrite them yourself :-). I found the cell.c program to be by far the
  62. Xmost useful and the tile.c program to be close to useless.
  63. X
  64. XThere are loads of puzzles not represented here. I solved all of them by
  65. Xhand, most without too much difficulty (although there are still things I
  66. Xwould like to know about the picture box puzzle in the doll room).
  67. X
  68. XREADME         This file.
  69. Xbishop.c       Computes shortest solution to the bishop exchange problem.
  70. Xcans           Perl script to generate potential solutions for the cans
  71. Xcell.c         Plays Blue for the microscope game well enough to beat Green
  72. Xknight.c       Computes a solution to the knight exchange problem.
  73. Xqueen.c        Computes a solution to the 8 queens problem.
  74. Xtile.c         Walks floor tiles (to very little avail).
  75. Xtiles          Listing of color<->number permutations (it didn't help me :-).
  76. X
  77. XWARNING: Many of these programs don't simply help you play, but compute the
  78. Xactual solution. Running them will be a spolier. You have been warned...
  79. X
  80. XAll of these have been of use to me in solving the puzzles in 7th Guest
  81. X(sometimes only accidentally). The cell game require two computers, since
  82. Xyou have to interact with the game as well as the assistant program.
  83. X
  84. XI ran all of these programs on a U**x workstation, so I didn't pay too much
  85. Xattention to how much memory they used, I don't know if they are likely to
  86. Xfit on DOS without a 32 bit compiler and a 386 or better (but they might, I
  87. Xjust don't know).
  88. X
  89. XIf you want support for these programs, you've got to be joking :-).
  90. X
  91. XAll these programs are in the public domain (You'll notice I didn't put my
  92. Xname in any of them, in the hope that no one would send me email asking for
  93. Xchanges :-).
  94. END_OF_FILE
  95. if test 1982 -ne `wc -c <'README'`; then
  96.     echo shar: \"'README'\" unpacked with wrong size!
  97. fi
  98. # end of 'README'
  99. fi
  100. if test -f 'cans' -a "${1}" != "-c" ; then 
  101.   echo shar: Will not clobber existing file \"'cans'\"
  102. else
  103. echo shar: Extracting \"'cans'\" \(5332 characters\)
  104. sed "s/^X//" >'cans' <<'END_OF_FILE'
  105. X#!/usr/bin/perl
  106. X#
  107. X# NOTE: Be sure you edit the definition of $dictfile below.
  108. X#
  109. X# This is a perl script to find the sentence spelled by the cans in the
  110. X# kitchen. It looks horrid with an umpteen deep nested loop, but there are
  111. X# not a lot of words with no vowels but 'y' in them, so it doesn't have too
  112. X# many choices to iterate through. With my dictionary, it still finds a lot
  113. X# of potential sentences (about 500 or 600), but many of them are just the
  114. X# same 5 letter words arranged differently, and only one of the sentences
  115. X# really fits the hint from the library book.
  116. X#
  117. X# You can probably cut down on excess sentence generation if you edit your
  118. X# dictionary to remove words that match sometimes, but are unlikely to be
  119. X# part of a sentence (for instance, I discovered I have the word 'yb' in my
  120. X# dictionary, whatever that is :-).
  121. X
  122. Xsub rarity {
  123. X   local($arg)=@_;
  124. X   local($bcghm,$lprt,$s,$y);
  125. X   $bcghm=($arg=~tr/bcghm/bcghm/);
  126. X   $lprt=($arg=~tr/lprt/lprt/);
  127. X   $s=($arg=~tr/s/s/);
  128. X   $y=($arg=~tr/y/y/);
  129. X   $bcghm * 2048 + $lptr * 512 + $s * 32 + $y;
  130. X}
  131. X
  132. Xsub byrarity {
  133. X   local($acop)=$a;
  134. X   local($bcop)=$b;
  135. X   &rarity($bcop) <=> &rarity($acop);
  136. X}
  137. X
  138. X# You will need to point this at a good dictionary (the kind that is likely
  139. X# to have lots of funny words with lots of y's in them).
  140. X
  141. X$dictfile="/usr2/spell/wsp.orig";
  142. X
  143. X$con{'b'}=1;
  144. X$con{'c'}=1;
  145. X$con{'g'}=1;
  146. X$con{'h'}=1;
  147. X$con{'m'}=1;
  148. X$con{'l'}=3;
  149. X$con{'p'}=3;
  150. X$con{'r'}=3;
  151. X$con{'t'}=3;
  152. X$con{'s'}=5;
  153. X$con{'y'}=11;
  154. Xopen(DICT,"<$dictfile") || die "Cannot read dictionary $dictfile\n";
  155. Xmainloop: while (<DICT>) {
  156. X   chop;
  157. X   y/A-Z/a-z/;
  158. X   next if (/[\. adefijknoquvwxz-]/);
  159. X   s/\'//g;
  160. X   next if (/^[aeiouy]+$/);
  161. X   next if (/^[bcdfghjklmnpqrstvwxz]+$/);
  162. X   $len=length($_);
  163. X   if ($len==3 || $len == 5 || $len == 6 || $len == 2) {
  164. X      undef %cnt;
  165. X      for ($i = 0; $i < $len; ++$i) {
  166. X         $cnt{substr($_,$i,1)} ++;
  167. X      }
  168. X      foreach $chk (keys(%con)) {
  169. X         next mainloop if ($cnt{$chk} > $con{$chk});
  170. X      }
  171. X      if ($len == 2) {
  172. X         push(@two,$_);
  173. X      } elsif ($len == 3) {
  174. X         push(@three,$_);
  175. X      } elsif ($len == 5) {
  176. X         push(@five,$_);
  177. X      } elsif ($len == 6) {
  178. X         push(@six,$_);
  179. X      }
  180. X   }
  181. X}
  182. X$|=1;
  183. Xprint "Sorting by rarity value...\n";
  184. X@three=sort byrarity @three;
  185. X@five=sort byrarity @five;
  186. X@six=sort byrarity @six;
  187. X@two=sort byrarity @two;
  188. Xprint "Sort completed.\n";
  189. Xsix1loop: foreach $six1 (@six) {
  190. X   print "Trying 6 character word $six1.\n";
  191. X   five1loop: foreach $five1 (@five) {
  192. X      $combo=$six1 . $five1;
  193. X      undef %cnt;
  194. X      for ($i = 0; $i < 11; ++$i) {
  195. X         $cnt{substr($combo,$i,1)} ++;
  196. X      }
  197. X      foreach $chk (keys(%con)) {
  198. X         next five1loop if ($cnt{$chk} > $con{$chk});
  199. X      }
  200. X      five2loop: foreach $five2 (@five) {
  201. X         $combo = $six1 . $five1 . $five2;
  202. X         undef %cnt;
  203. X         for ($i = 0; $i < 16; ++$i) {
  204. X            $cnt{substr($combo,$i,1)} ++;
  205. X         }
  206. X         foreach $chk (keys(%con)) {
  207. X            next five2loop if ($cnt{$chk} > $con{$chk});
  208. X         }
  209. X         five3loop: foreach $five3 (@five) {
  210. X            $combo = $six1 . $five1 . $five2 . $five3;
  211. X            undef %cnt;
  212. X            for ($i = 0; $i < 21; ++$i) {
  213. X               $cnt{substr($combo,$i,1)} ++;
  214. X            }
  215. X            foreach $chk (keys(%con)) {
  216. X               next five3loop if ($cnt{$chk} > $con{$chk});
  217. X            }
  218. X            five4loop: foreach $five4 (@five) {
  219. X               $combo = $six1 . $five1 . $five2 . $five3 . $five4;
  220. X               undef %cnt;
  221. X               for ($i = 0; $i < 26; ++$i) {
  222. X                  $cnt{substr($combo,$i,1)} ++;
  223. X               }
  224. X               foreach $chk (keys(%con)) {
  225. X                  next five4loop if ($cnt{$chk} > $con{$chk});
  226. X               }
  227. X               three1loop: foreach $three1 (@three) {
  228. X                  $combo = $six1 . $five1 . $five2 . $five3 . $five4 . $three1;
  229. X                  undef %cnt;
  230. X                  for ($i = 0; $i < 29; ++$i) {
  231. X                     $cnt{substr($combo,$i,1)} ++;
  232. X                  }
  233. X                  foreach $chk (keys(%con)) {
  234. X                     next three1loop if ($cnt{$chk} > $con{$chk});
  235. X                  }
  236. X                  two1loop: foreach $two1 (@two) {
  237. X                     $combo = $six1 . $five1 . $five2 . $five3 . $five4 .
  238. X                              $three1 . $two1;
  239. X                     undef %cnt;
  240. X                     for ($i = 0; $i < 31; ++$i) {
  241. X                        $cnt{substr($combo,$i,1)} ++;
  242. X                     }
  243. X                     foreach $chk (keys(%con)) {
  244. X                        next two1loop if ($cnt{$chk} > $con{$chk});
  245. X                     }
  246. X                     two2loop: foreach $two2 (@two) {
  247. X                        $combo = $six1 . $five1 . $five2 . $five3 . $five4 .
  248. X                                 $three1 . $two1 . $two2;
  249. X                        undef %cnt;
  250. X                        for ($i = 0; $i < 33; ++$i) {
  251. X                           $cnt{substr($combo,$i,1)} ++;
  252. X                        }
  253. X                        foreach $chk (keys(%con)) {
  254. X                           next two2loop if ($cnt{$chk} != $con{$chk});
  255. X                        }
  256. X                        print "$three1 $five1 $five2 $six1 $five3 $two1 $two2 $five4.\n";
  257. X                     }
  258. X                  }
  259. X               }
  260. X            }
  261. X         }
  262. X      }
  263. X   }
  264. X}
  265. END_OF_FILE
  266. if test 5332 -ne `wc -c <'cans'`; then
  267.     echo shar: \"'cans'\" unpacked with wrong size!
  268. fi
  269. chmod +x 'cans'
  270. # end of 'cans'
  271. fi
  272. if test -f 'cell.c' -a "${1}" != "-c" ; then 
  273.   echo shar: Will not clobber existing file \"'cell.c'\"
  274. else
  275. echo shar: Extracting \"'cell.c'\" \(12268 characters\)
  276. sed "s/^X//" >'cell.c' <<'END_OF_FILE'
  277. X/* OK. Here it is. The most ridiculous program yet. It uses the minimax
  278. X * algorithm to play the silly microscope game (I hope I can get a good
  279. X * enough solution in a reasonable time with minimax - I would hate to have
  280. X * to code up alpha-beta pruning as well).
  281. X *
  282. X * NOTE: This program uses the non-portable routine alloca() to allocate
  283. X * space on the stack. If you don't have alloca() (or you don't have much
  284. X * stack space), you may have to change the routines that call alloca() to
  285. X * call malloc() and free() appropriately.
  286. X *
  287. X * The difference between this game and the one in the microscope is that
  288. X * this game moves first and plays the blue blood cells, and the user
  289. X * (really the 7th Guest Game) plays the green viruses (you need two
  290. X * computers at the same time for this, or maybe 7th Guest will run in a DOS
  291. X * box under OS/2 :-).
  292. X *
  293. X * The rules:
  294. X *
  295. X * Played on a 7x7 board.
  296. X *
  297. X * Blue starts in top left and bottom right.
  298. X *
  299. X * Green starts in bottom left and top right.
  300. X *
  301. X * Blue moves first.
  302. X *
  303. X * Players take turns until one player cannot move, then the other fills
  304. X * any remaining cells.
  305. X *
  306. X * Player with most cells filled wins.
  307. X *
  308. X * Moves consist of moving any cell of your color 1 or 2 squares in any
  309. X * direction. If the move is only 1 square, the cell divides and fills both
  310. X * cells. If the move lands adjacent to any cells of the opposite color, the
  311. X * cell takes over all adjacent cells.
  312. X *
  313. X * This game seems to be working now. It even plays well enough to beat
  314. X * the nasty ol' viruses by 25 to 24 (which is plenty good enough :-).
  315. X * It doesn't run as fast as it could, but it does run fast enough to
  316. X * make it possible to play (at least the combination of my machine
  317. X * and my patience is not strained too much). Several things could speed
  318. X * it up, but since it works I am not going to do them.
  319. X *
  320. X *    * Smarter move generation. Sometimes any number of cells can move to
  321. X *      the same spot, but the end result will be identical. If these
  322. X *      duplicate moves were eliminated, the tree size would be cut down
  323. X *      quite a bit. (This could probably best be done by keeping a record
  324. X *      of the positions of the pieces after each call to MakeMove in the
  325. X *      recursive eval move routines, then checking to see if it is
  326. X *      identical to a move already evaluated).
  327. X *
  328. X *    * Enhancing the straight minimax algorithm do do alpha-beta pruning
  329. X *      could also cut down the size of the tree a lot, possibly allowing
  330. X *      a deeper tree walk (but the default tree walk depth currently
  331. X *      built into the program would not be able to take much advantage
  332. X *      of alpha-beta pruning).
  333. X *
  334. X * I suspect it would run quite fast with these changes, but since I only
  335. X * had to run it once, the changes are not worth it.
  336. X *
  337. X * Other possible enhancements:
  338. X *
  339. X *    * Teach it to recognize when the game is over. (Probably should add a
  340. X *      new bit to the Move struct and return a special "game over" move
  341. X *      from the eval routine when it can't move anymore).
  342. X *    * Teach it to be able to backup move in case you make a mistake.
  343. X *    * Add options to play blue or green, or both (for the computer to play
  344. X *      against itself, you definitely need to teach it to recognize the end
  345. X *      of the game :-).
  346. X */
  347. X
  348. X#include <stdio.h>
  349. X#include <limits.h>
  350. X
  351. Xint max_level = 2; /* max level to search in the game tree */
  352. X
  353. Xtypedef enum {
  354. X   Green,
  355. X   Blue,
  356. X   Open
  357. X} Pieces;
  358. X
  359. X/* There is only one copy of the board. Each move stores enough information
  360. X * to put the board back the way it was, so as we walk up and down the tree,
  361. X * we change the board back and forth.
  362. X */
  363. XPieces board [7] [7] = {
  364. X   {Blue,  Open, Open, Open, Open, Open, Green},
  365. X   {Open,  Open, Open, Open, Open, Open, Open},
  366. X   {Open,  Open, Open, Open, Open, Open, Open},
  367. X   {Open,  Open, Open, Open, Open, Open, Open},
  368. X   {Open,  Open, Open, Open, Open, Open, Open},
  369. X   {Open,  Open, Open, Open, Open, Open, Open},
  370. X   {Green, Open, Open, Open, Open, Open, Blue},
  371. X};
  372. X
  373. X/* The following defines are used to make a bit mask for each move
  374. X * indicating which directions around the destination cell had opposite
  375. X * color cells that were eaten.
  376. X */
  377. X#define ATE_N   0x01
  378. X#define ATE_NE  0x02
  379. X#define ATE_E   0x04
  380. X#define ATE_SE  0x08
  381. X#define ATE_S   0x10
  382. X#define ATE_SW  0x20
  383. X#define ATE_W   0x40
  384. X#define ATE_NW  0x80
  385. X
  386. Xtypedef struct mv {
  387. X   unsigned int food :8; /* Mask indicating directions we ate cells in */
  388. X   int from_row :4;      /* moved cell from this row & col */
  389. X   int from_col :4;
  390. X   int to_row :4;        /* moved to this row & col */
  391. X   int to_col :4;
  392. X} Move;
  393. X
  394. Xtypedef struct mi {
  395. X   int row_delta;
  396. X   int col_delta;
  397. X   unsigned int food_bit;
  398. X} MoveInfo;
  399. X
  400. XMoveInfo moves[8] = {
  401. X   {-1, 0, ATE_N},
  402. X   {-1, 1, ATE_NE},
  403. X   {0, 1, ATE_E},
  404. X   {1, 1, ATE_SE},
  405. X   {1, 0, ATE_S},
  406. X   {1, -1, ATE_SW},
  407. X   {0, -1, ATE_W},
  408. X   {-1, -1, ATE_NW}
  409. X};
  410. X
  411. X/* MakeMove makes a move on the board, clearing the source cell if the
  412. X * distance moved was greater than 1 and eating any adjacent cells.  It also
  413. X * records eaten cells in the food field of the input Move struct.
  414. X */
  415. Xvoid
  416. XMakeMove(Move * mp)
  417. X{
  418. X   int fr = mp->from_row;
  419. X   int tr = mp->to_row;
  420. X   int fc = mp->from_col;
  421. X   int tc = mp->to_col;
  422. X   int dr = fr - tr;
  423. X   int dc = fc - tc;
  424. X   Pieces pc = board[fr][fc];
  425. X   Pieces np = ((pc == Green) ? Blue : Green);
  426. X   int i;
  427. X
  428. X   if (dr < 0) dr = - dr;
  429. X   if (dc < 0) dc = - dc;
  430. X   board[tr][tc] = pc;
  431. X   if (dr > 1 || dc > 1) {
  432. X      board[fr][fc] = Open;
  433. X   }
  434. X   for (i = 0; i < 8; ++i) {
  435. X      int nr = moves[i].row_delta + tr;
  436. X      int nc = moves[i].col_delta + tc;
  437. X      if (nr >= 0 && nr < 7 && nc >= 0 && nc < 7) {
  438. X         if (board[nr][nc] == np) {
  439. X            board[nr][nc] = pc;
  440. X            mp->food |= moves[i].food_bit;
  441. X         }
  442. X      }
  443. X   }
  444. X}
  445. X
  446. X/* UnMakeMove reverses what MakeMove did and puts the board back the way it
  447. X * was before the move happened.
  448. X */
  449. Xvoid
  450. XUnMakeMove(Move * mp)
  451. X{
  452. X   int fr = mp->from_row;
  453. X   int tr = mp->to_row;
  454. X   int fc = mp->from_col;
  455. X   int tc = mp->to_col;
  456. X   Pieces pc = board[tr][tc];
  457. X   Pieces np = ((pc == Green) ? Blue : Green);
  458. X   int i;
  459. X
  460. X   board[tr][tc] = Open;
  461. X   board[fr][fc] = pc;
  462. X   for (i = 0; i < 8; ++i) {
  463. X      if ((mp->food & moves[i].food_bit) != 0) {
  464. X         board[tr + moves[i].row_delta][tc + moves[i].col_delta] = np;
  465. X      }
  466. X   }
  467. X}
  468. X
  469. X/* EvaluateBoard comes up with an estimate of how Blue is doing (positive is
  470. X * good for blue, negative is good for green).  Just to get this working I
  471. X * made this simply count numbers of cells, blue counts 1, green counts -1.
  472. X *
  473. X * It turns out that evaluation routine is good enough to win, which
  474. X * is also good enough for me.
  475. X */
  476. X
  477. Xint
  478. XBoardValue()
  479. X{
  480. X   int i,j;
  481. X   int value;
  482. X
  483. X   value = 0;
  484. X   for (i = 0; i < 7; ++i) {
  485. X      for (j = 0; j < 7; ++j) {
  486. X         if (board[i][j] == Green) {
  487. X            value -= 1;
  488. X         } else if (board[i][j] == Blue) {
  489. X            value += 1;
  490. X         }
  491. X      }
  492. X   }
  493. X   return value;
  494. X}
  495. X
  496. XMove movelist[1176]; /* Definite upper bound on number of legal moves :-) */
  497. X
  498. X/* The ListMoves function goes through the board finding all pieces of
  499. X * the given color and listing all possible moves in the movelist array,
  500. X * returning the number of moves found.
  501. X */
  502. Xint
  503. XListMoves(Pieces color)
  504. X{
  505. X   int i,j,dr,dc,row,col;
  506. X   int movecount;
  507. X
  508. X   movecount = 0;
  509. X   for (i = 0; i < 7; ++i) {
  510. X      for (j = 0; j < 7; ++j) {
  511. X         if (board[i][j] == color) {
  512. X            for (dr = -2; dr <= 2; ++dr) {
  513. X               for (dc = -2; dc <= 2; ++dc) {
  514. X                  if ((dr != 0) || (dc != 0)) {
  515. X                     row = i + dr;
  516. X                     col = j + dc;
  517. X                     if (row >= 0 && row < 7 && col >= 0 && col < 7) {
  518. X                        if (board[row][col] == Open) {
  519. X                           movelist[movecount].food = 0;
  520. X                           movelist[movecount].from_row = i;
  521. X                           movelist[movecount].from_col = j;
  522. X                           movelist[movecount].to_row = row;
  523. X                           movelist[movecount].to_col = col;
  524. X                           ++movecount;
  525. X                        }
  526. X                     }
  527. X                  }
  528. X               }
  529. X            }
  530. X         }
  531. X      }
  532. X   }
  533. X   return movecount;
  534. X}
  535. X
  536. X/* EvalBlueMove looks for the best move for Blue. It returns the value of
  537. X * the best move, and fills in the move itself in the best_move struct.
  538. X *
  539. X * If no move is possible, or the max level is exceeded, it simply returns
  540. X * the value of the current board, but does not pick a move.
  541. X *
  542. X * This routine does not make the move, it simply computes it. The board
  543. X * is unchanged following this call.
  544. X *
  545. X * Because positive numbers are good for blue, this looks for the highest
  546. X * value move.
  547. X */
  548. Xint
  549. XEvalBlueMove(Move * best_move, int level)
  550. X{
  551. X   Move * ml;
  552. X   int    mc;
  553. X   int    bestval, bestmove;
  554. X   Move   dummy;
  555. X   int    mval;
  556. X   int    i;
  557. X
  558. X   if ((level > max_level) || ((mc = ListMoves(Blue)) == 0)) {
  559. X      return BoardValue();
  560. X   }
  561. X   ml = (Move *)alloca(sizeof(Move) * mc);
  562. X   memcpy((void *)ml, (void *)&movelist[0], sizeof(Move) * mc);
  563. X   bestval = INT_MIN;
  564. X   bestmove = -1;
  565. X   for (i = 0; i < mc; ++i) {
  566. X      MakeMove(ml + i);
  567. X      mval = EvalGreenMove(&dummy, level + 1);
  568. X      if (mval > bestval) {
  569. X         bestval = mval;
  570. X         bestmove = i;
  571. X      }
  572. X      UnMakeMove(ml + i);
  573. X   }
  574. X   *best_move = ml[bestmove];
  575. X   return bestval;
  576. X}
  577. X
  578. X/* EvalGreenMove is the mirror image routine to EvalBlueMove. It looks for the
  579. X * smallest value as the best move for Green.
  580. X */
  581. Xint
  582. XEvalGreenMove(Move * best_move, int level)
  583. X{
  584. X   Move * ml;
  585. X   int    mc;
  586. X   int    bestval, bestmove;
  587. X   Move   dummy;
  588. X   int    mval;
  589. X   int    i;
  590. X
  591. X   if ((level > max_level) || ((mc = ListMoves(Green)) == 0)) {
  592. X      return BoardValue();
  593. X   }
  594. X   ml = (Move *)alloca(sizeof(Move) * mc);
  595. X   memcpy((void *)ml, (void *)&movelist[0], sizeof(Move) * mc);
  596. X   bestval = INT_MAX;
  597. X   bestmove = -1;
  598. X   for (i = 0; i < mc; ++i) {
  599. X      MakeMove(ml + i);
  600. X      mval = EvalBlueMove(&dummy, level + 1);
  601. X      if (mval < bestval) {
  602. X         bestval = mval;
  603. X         bestmove = i;
  604. X      }
  605. X      UnMakeMove(ml + i);
  606. X   }
  607. X   *best_move = ml[bestmove];
  608. X   return bestval;
  609. X}
  610. X
  611. Xvoid
  612. XPrintBoard()
  613. X{
  614. X   int i,j;
  615. X
  616. X   printf("  a b c d e f g\n");
  617. X   for (i = 0; i < 7; ++i) {
  618. X      printf("%d", i+1);
  619. X      for (j = 0; j < 7; ++j) {
  620. X         if (board[i][j] == Green) {
  621. X            printf(" G");
  622. X         } else if (board[i][j] == Blue) {
  623. X            printf(" B");
  624. X         } else {
  625. X            printf(" .");
  626. X         }
  627. X      }
  628. X      printf("\n");
  629. X   }
  630. X   fflush(stdout);
  631. X}
  632. X
  633. X/* ReadMove asks for and verifies a move for a piece of the given color.
  634. X */
  635. XMove
  636. XReadMove(Pieces color)
  637. X{
  638. X   char buf[80];
  639. X   int mc = ListMoves(color);
  640. X   Move rval;
  641. X   int from_row, to_row, i;
  642. X   char from_col, to_col;
  643. X
  644. X   rval.food = 0;
  645. X   for ( ; ; ) {
  646. X      printf("Move? ");
  647. X      fflush(stdout);
  648. X      if (fgets(buf, sizeof(buf), stdin) == NULL) {
  649. X         printf("\n");
  650. X         exit(0);
  651. X      }
  652. X      if (buf[0] == 'q') {
  653. X         exit(0);
  654. X      }
  655. X      if (4 == sscanf(buf,"%c%d%c%d",&from_col,&from_row,&to_col,&to_row)) {
  656. X         from_col -= 'a';
  657. X         to_col -= 'a';
  658. X         from_row -= 1;
  659. X         to_row -= 1;
  660. X         for (i = 0; i < mc; ++i) {
  661. X            if (movelist[i].from_col == from_col &&
  662. X                movelist[i].from_row == from_row &&
  663. X                movelist[i].to_col == to_col &&
  664. X                movelist[i].to_row == to_row) {
  665. X               rval.from_row = from_row;
  666. X               rval.from_col = from_col;
  667. X               rval.to_row = to_row;
  668. X               rval.to_col = to_col;
  669. X               return rval;
  670. X            }
  671. X         }
  672. X         printf("Not a valid move: %s", buf);
  673. X         printf("Please input from col from row to col to row as in: b2c2\n");
  674. X         printf("Or type q to quit.\n");
  675. X      }
  676. X   }
  677. X}
  678. X
  679. Xint
  680. Xmain(int argc, char ** argv)
  681. X{
  682. X   if (argc > 1) {
  683. X      max_level = atoi(argv[1]);
  684. X   }
  685. X   for ( ; ; ) {
  686. X      Move tm;
  687. X      printf("Thinking...");
  688. X      fflush(stdout);
  689. X      EvalBlueMove(&tm, 0);
  690. X      MakeMove(&tm);
  691. X      printf("My move is %c%d%c%d\n", tm.from_col + 'a', tm.from_row + 1,
  692. X         tm.to_col + 'a', tm.to_row + 1);
  693. X      PrintBoard();
  694. X      tm = ReadMove(Green);
  695. X      MakeMove(&tm);
  696. X      PrintBoard();
  697. X   }
  698. X}
  699. END_OF_FILE
  700. if test 12268 -ne `wc -c <'cell.c'`; then
  701.     echo shar: \"'cell.c'\" unpacked with wrong size!
  702. fi
  703. # end of 'cell.c'
  704. fi
  705. if test -f 'knight.c' -a "${1}" != "-c" ; then 
  706.   echo shar: Will not clobber existing file \"'knight.c'\"
  707. else
  708. echo shar: Extracting \"'knight.c'\" \(11900 characters\)
  709. sed "s/^X//" >'knight.c' <<'END_OF_FILE'
  710. X/* Yet another program in the 7th guest collection. This one solves the
  711. X * knights problem which I have done by hand, but I want to see if I can get
  712. X * a program to work as well.
  713. X *
  714. X * Pieces of this were cut and pasted from bishop.c, but a breadth first
  715. X * search doesn't work here - there are way too many moves.  I need to do a
  716. X * depth first search with a move ordering algorithm that orders the moves
  717. X * first that put the most white knights in the black positions and
  718. X * vice-versa.
  719. X *
  720. X * Here's the deal. There are 12 black knights and 12 white knights arranged
  721. X * on a 5 x 5 chessboard like so:
  722. X *
  723. X *   a b c d e
  724. X * 1 B B B B W
  725. X * 2 B B B W W
  726. X * 3 B B . W W
  727. X * 4 B B W W W
  728. X * 5 B W W W W
  729. X *
  730. X * The idea is to swap the white and black knights.
  731. X *
  732. X * This program tackles the problem with a depth first search operating
  733. X * like so:
  734. X *
  735. X * A hash table is kept of all board positions examined, computing legal
  736. X * moves from one board position involves both checking for knights that are
  737. X * free to move to the empty square as well as checking to see if we were
  738. X * ever at this board configuration before. Repeated configurations are not
  739. X * allowed.
  740. X *
  741. X * The hash table (in addition to being keyed off the board configuration)
  742. X * keeps a pointer to the board configuration which was the parent of this
  743. X * one (since repeated configurations are not allowed, duplicate parents
  744. X * will not be possible, so only one pointer is needed).
  745. X *
  746. X * Moves are ordered by the simple criteria of counting white knights
  747. X * in black positions and black knights in white positions and adding
  748. X * the two together. The highest scoring moves are tried first and the
  749. X * algorithm proceeds recursively doing a depth first walk.
  750. X *
  751. X * When the desired configuration is created, the algorithm terminates, and
  752. X * back-tracks through the hash table entry pointers to trace out the
  753. X * sequence of moves from the initial to the final configuration.
  754. X *
  755. X * Just for the heck of it, I put in some code to allow it to continue
  756. X * searching for a shorter solution than the original one it finds, but
  757. X * it takes too long and eats too much space, so I have it automatically
  758. X * cut itself off after a certain amount of work.
  759. X */
  760. X
  761. X#include <stdio.h>
  762. X
  763. X#define HASH_MAX 2063
  764. X
  765. X/* The BoardConfiguration struct records a particular board configuration.
  766. X * it is also the element kept in the hash table.
  767. X *
  768. X * The board is stored as two words, each holding 25 bits. One mask
  769. X * represents the white knight positions, the other the black positions.
  770. X *
  771. X * If you imagine the board squares numbered as follows:
  772. X *
  773. X *   0  1  2  3  4
  774. X *   5  6  7  8  9
  775. X *  10 11 12 13 14
  776. X *  15 16 17 18 19
  777. X *  20 21 22 23 24
  778. X *
  779. X * Then the bit masks store knight positions by shifting 1 left by the
  780. X * board position number, then oring it into the mask for the appropriate
  781. X * color. For example, the initial board configuration is:
  782. X */
  783. X#define START_BLACK ((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 5) | \
  784. X                     (1 << 6) | (1 << 7) | (1 << 10) | (1 << 11) | (1 << 15) | \
  785. X                     (1 << 16) | (1 << 20))
  786. X#define START_WHITE ((1 << 4) | (1 << 8) | (1 << 9) | (1 << 13) | (1 << 14) | \
  787. X                     (1 << 17) | (1 << 18) | (1 << 19) | (1 << 21) | \
  788. X                     (1 << 22) | (1 << 23) | (1 << 24))
  789. X
  790. Xtypedef struct bc {
  791. X   struct bc *    next;        /* identical hash codes linked through this */
  792. X   struct bc *    parent;      /* points to board config this derived from */
  793. X   unsigned long  black_mask;  /* black knight positions */
  794. X   unsigned long  white_mask;  /* white knight positions */
  795. X   int            depth;       /* depth in tree where this was found */
  796. X} BoardConfiguration;
  797. X
  798. X/* hash_tab is the hash table of moves already seen
  799. X */
  800. XBoardConfiguration * hash_tab[HASH_MAX];
  801. X
  802. X/* Each row is a list of positions you can move to from a given position.
  803. X * (each row is terminated with 25 to mark the end of the list.
  804. X */
  805. Xchar move_to[25][9] = {
  806. X   {7, 11, 25},
  807. X   {8, 12, 10, 25},
  808. X   {9, 13, 11, 5, 25},
  809. X   {14, 12, 6, 25},
  810. X   {13, 7, 25},
  811. X   {2, 12, 16, 25},
  812. X   {3, 13, 17, 15, 25},
  813. X   {4, 14, 18, 16, 10, 0, 25},
  814. X   {19, 17, 11, 1, 25},
  815. X   {18, 12, 2, 25},
  816. X   {1, 7, 17, 21, 25},
  817. X   {2, 8, 18, 22, 20, 0, 25},
  818. X   {3, 9, 19, 23, 21, 15, 5, 1, 25},
  819. X   {4, 24, 22, 16, 6, 2, 25},
  820. X   {23, 17, 7, 3, 25},
  821. X   {6, 12, 22, 25},
  822. X   {7, 13, 23, 5, 25},
  823. X   {8, 14, 24, 20, 10, 6, 25},
  824. X   {9, 21, 11, 7, 25},
  825. X   {22, 12, 8, 25},
  826. X   {11, 17, 25},
  827. X   {12, 18, 10, 25},
  828. X   {13, 19, 15, 11, 25},
  829. X   {14, 16, 12, 25},
  830. X   {17, 13, 25}
  831. X};
  832. X
  833. Xint board_count = 0;
  834. Xint mod_count = 0;
  835. X
  836. X/* NewBoardConfiguration looks up a proposed new board configuration in the
  837. X * hash table. If it is not already there, it creates the new object and
  838. X * installs it in the table, returning a pointer to it. Otherwise it just
  839. X * returns NULL.
  840. X */
  841. XBoardConfiguration *
  842. XNewBoardConfiguration(
  843. X   BoardConfiguration * parent,
  844. X   unsigned long black_mask,
  845. X   unsigned long white_mask)
  846. X{
  847. X   /* xor is a terrible hash here since almost all but one of the bits are
  848. X    * always set in the union of both masks.
  849. X    */
  850. X   unsigned long hash = (black_mask * white_mask) % HASH_MAX;
  851. X   BoardConfiguration * ptr = hash_tab[hash];
  852. X   while (ptr != NULL) {
  853. X      if ((ptr->black_mask == black_mask) && (ptr->white_mask == white_mask)) {
  854. X         return NULL;
  855. X      }
  856. X      ptr = ptr->next;
  857. X   }
  858. X   ptr = (BoardConfiguration *)malloc(sizeof(BoardConfiguration));
  859. X   ptr->next = hash_tab[hash];
  860. X   ptr->parent = parent;
  861. X   if (parent == NULL) {
  862. X      ptr->depth = 0;
  863. X   } else {
  864. X      ptr->depth = parent->depth + 1;
  865. X   }
  866. X   ptr->black_mask = black_mask;
  867. X   ptr->white_mask = white_mask;
  868. X   hash_tab[hash] = ptr;
  869. X   ++board_count;
  870. X   ++mod_count;
  871. X   if (mod_count == 1000) {
  872. X      printf("At %d positions and counting...\n", board_count);
  873. X      fflush(stdout);
  874. X      mod_count = 0;
  875. X   }
  876. X   return ptr;
  877. X}
  878. X
  879. Xint
  880. XCountBits(unsigned long m)
  881. X{
  882. X   int c = 0;
  883. X   while (m > 0) {
  884. X      c += (m & 1);
  885. X      m >>= 1;
  886. X   }
  887. X   return c;
  888. X}
  889. X
  890. Xint
  891. XBoardValue(BoardConfiguration * bp)
  892. X{
  893. X   return CountBits(bp->white_mask & START_BLACK) +
  894. X          CountBits(bp->black_mask & START_WHITE);
  895. X}
  896. X
  897. Xint
  898. XCompareBoards(void * a, void * b)
  899. X{
  900. X   BoardConfiguration * ba = *(BoardConfiguration **)a;
  901. X   BoardConfiguration * bb = *(BoardConfiguration **)b;
  902. X   return BoardValue(bb) - BoardValue(ba);
  903. X}
  904. X
  905. X/* FindSolution runs the depth first algorithm, returning the first solution
  906. X * it finds (I suppose I could keep looking until I find a shorter and shorter
  907. X * solution, but that would probably take awhile).
  908. X *
  909. X * Actually, I just ran this, and it found a 160 move solution in practically
  910. X * zero time, so I think maybe I will have it keep searching for the shortest
  911. X * path, perhaps it really won't take very long...
  912. X *
  913. X * OK. It does take too long. I added a cutoff to make it stop after looking
  914. X * at 10000 different board configurations.
  915. X */
  916. XBoardConfiguration *
  917. XFindSolution(BoardConfiguration * hp, int depth, BoardConfiguration * sp)
  918. X{
  919. X   BoardConfiguration * moves[8];
  920. X   int move_count = 0;
  921. X   int i;
  922. X   unsigned long mask;
  923. X
  924. X   if ((sp != NULL) && ((board_count > 10000) || (depth >= sp->depth))) {
  925. X      return sp;
  926. X   }
  927. X   /* Compute all the legal moves I can make from this board configuration.
  928. X    */
  929. X   for (i = 0, mask = (1 << 0); i < 25; ++i, mask <<= 1) {
  930. X      if ((hp->black_mask & mask) != 0) {
  931. X         /* There is a black knight at position i, check each move it
  932. X          * can make.
  933. X          */
  934. X         int j, d;
  935. X         for (j = 0; ((d = move_to[i][j]) != 25); ++j) {
  936. X            unsigned long dmask = (1 << d);
  937. X            /* Make sure I don't move on top of a another piece.
  938. X             */
  939. X            if ((dmask & (hp->black_mask | hp->white_mask)) == 0) {
  940. X               BoardConfiguration * np =
  941. X                  NewBoardConfiguration(hp,
  942. X                     (hp->black_mask ^ mask) | dmask,
  943. X                     hp->white_mask);
  944. X               if (np != NULL) {
  945. X                  /* If this is what we have been looking for, return
  946. X                   * it now.
  947. X                   */
  948. X                  if ((np->black_mask == START_WHITE) &&
  949. X                      (np->white_mask == START_BLACK)) {
  950. X                     printf("Found solution at depth %d\n", np->depth);
  951. X                     return np;
  952. X                  }
  953. X                  moves[move_count++] = np;
  954. X               }
  955. X            }
  956. X         }
  957. X      }
  958. X      if ((hp->white_mask & mask) != 0) {
  959. X         /* There is a white knight at position i, check each move it
  960. X          * can make.
  961. X          */
  962. X         int j, d;
  963. X         for (j = 0; ((d = move_to[i][j]) != 25); ++j) {
  964. X            unsigned long dmask = (1 << d);
  965. X            /* Make sure I don't move on top of a another piece.
  966. X             */
  967. X            if ((dmask & (hp->black_mask | hp->white_mask)) == 0) {
  968. X               BoardConfiguration * np =
  969. X                  NewBoardConfiguration(hp,
  970. X                     hp->black_mask,
  971. X                     (hp->white_mask ^ mask) | dmask);
  972. X               if (np != NULL) {
  973. X                  /* If this is what we have been looking for, return
  974. X                   * it now.
  975. X                   */
  976. X                  if ((np->black_mask == START_WHITE) &&
  977. X                      (np->white_mask == START_BLACK)) {
  978. X                     printf("Found solution at depth %d\n", np->depth);
  979. X                     return np;
  980. X                  }
  981. X                  moves[move_count++] = np;
  982. X               }
  983. X            }
  984. X         }
  985. X      }
  986. X   }
  987. X   if (move_count == 0) {
  988. X      return sp;
  989. X   }
  990. X   qsort((void *)&moves[0], move_count, sizeof(moves[0]), CompareBoards);
  991. X   for (i = 0; i < move_count; ++i) {
  992. X      sp = FindSolution(moves[i], depth + 1, sp);
  993. X      if ((sp != NULL) && (board_count > 10000)) {
  994. X         /* If the hash table is starting to get really full, just give up
  995. X          * and go with the solution we already have...
  996. X          */
  997. X         return sp;
  998. X      }
  999. X   }
  1000. X   return sp;
  1001. X}
  1002. X
  1003. Xchar * bit_names[25] = {
  1004. X   "a1", "b1", "c1", "d1", "e1",
  1005. X   "a2", "b2", "c2", "d2", "e2",
  1006. X   "a3", "b3", "c3", "d3", "e3",
  1007. X   "a4", "b4", "c4", "d4", "e4",
  1008. X   "a5", "b5", "c5", "d5", "e5"
  1009. X};
  1010. X
  1011. Xvoid
  1012. XPrintBit(unsigned long mask)
  1013. X{
  1014. X   unsigned long t;
  1015. X   int i;
  1016. X   for (i = 0, t = (1 << 0); i < 25; ++i, t <<= 1) {
  1017. X      if (mask & t) {
  1018. X         printf(bit_names[i]);
  1019. X         return;
  1020. X      }
  1021. X   }
  1022. X   printf("??");
  1023. X   return;
  1024. X}
  1025. X
  1026. Xstatic int move_num = 0;
  1027. X
  1028. Xvoid
  1029. XPrintSolution(BoardConfiguration * bp)
  1030. X{
  1031. X   int i,j;
  1032. X   unsigned long mask;
  1033. X
  1034. X   if (bp == NULL) {
  1035. X      return;
  1036. X   }
  1037. X   PrintSolution(bp->parent);
  1038. X   printf("Board %d:\tvalue = %d\n", move_num++, BoardValue(bp));
  1039. X   printf("  a b c d e ");
  1040. X   if (bp->parent == NULL) {
  1041. X      printf("starting position\n");
  1042. X   } else {
  1043. X      /* Figure out what the move was in algebraic notation and print that.
  1044. X       */
  1045. X      unsigned long old_mask = (bp->parent->black_mask |
  1046. X                                bp->parent->white_mask);
  1047. X      unsigned long new_mask = (bp->black_mask | bp->white_mask);
  1048. X      unsigned long changed_mask = old_mask ^ new_mask;
  1049. X      unsigned long old_bit = old_mask & changed_mask;
  1050. X      unsigned long new_bit = new_mask & changed_mask;
  1051. X      PrintBit(old_bit);
  1052. X      printf("-");
  1053. X      PrintBit(new_bit);
  1054. X      printf("\n");
  1055. X   }
  1056. X   mask = (1 << 0);
  1057. X   for (i = 0; i < 5; ++i) {
  1058. X      printf("%d", i + 1);
  1059. X      for (j = 0; j < 5; ++j) {
  1060. X         if (bp->black_mask & mask) {
  1061. X            printf(" B");
  1062. X         } else if (bp->white_mask & mask) {
  1063. X            printf(" W");
  1064. X         } else {
  1065. X            printf(" .");
  1066. X         }
  1067. X         mask <<= 1;
  1068. X      }
  1069. X      printf("\n");
  1070. X   }
  1071. X}
  1072. X
  1073. Xint
  1074. Xmain(int argc, char ** argv)
  1075. X{
  1076. X   BoardConfiguration * bp =
  1077. X      FindSolution(NewBoardConfiguration(NULL, START_BLACK, START_WHITE),
  1078. X      0,
  1079. X      NULL);
  1080. X   if (bp == NULL) {
  1081. X      printf("Failed to find solution.\n");
  1082. X      exit(2);
  1083. X   }
  1084. X   PrintSolution(bp);
  1085. X   printf("The total board count examined was %d.\n",board_count);
  1086. X}
  1087. END_OF_FILE
  1088. if test 11900 -ne `wc -c <'knight.c'`; then
  1089.     echo shar: \"'knight.c'\" unpacked with wrong size!
  1090. fi
  1091. # end of 'knight.c'
  1092. fi
  1093. if test -f 'queen.c' -a "${1}" != "-c" ; then 
  1094.   echo shar: Will not clobber existing file \"'queen.c'\"
  1095. else
  1096. echo shar: Extracting \"'queen.c'\" \(1188 characters\)
  1097. sed "s/^X//" >'queen.c' <<'END_OF_FILE'
  1098. X/* This is just a quickie program to compute a solution to the 8 queens
  1099. X * problem (which shows up in the game room).
  1100. X */
  1101. X#include <stdio.h>
  1102. X
  1103. Xstatic char board[8][8];
  1104. X
  1105. Xint
  1106. Xsumline(int start_row, int start_col, int row_inc, int col_inc)
  1107. X{
  1108. X   int sum = 0;
  1109. X   while ((start_row >= 0) && (start_row <= 7) &&
  1110. X          (start_col >= 0) && (start_col <= 7)) {
  1111. X      sum += board[start_row][start_col];
  1112. X      start_row += row_inc;
  1113. X      start_col += col_inc;
  1114. X   }
  1115. X   return sum;
  1116. X}
  1117. X
  1118. Xvoid
  1119. Xtryrow(int rownum)
  1120. X{
  1121. X   int i,j,col,row;
  1122. X   if (rownum >= 8) {
  1123. X      printf("Solution:\n");
  1124. X      for (i = 0; i < 8; ++i) {
  1125. X         for (j = 0; j < 8; ++j) {
  1126. X            if (board[i][j]) {
  1127. X               printf(" Q");
  1128. X            } else {
  1129. X               printf(" .");
  1130. X            }
  1131. X         }
  1132. X         printf("\n");
  1133. X      }
  1134. X      return;
  1135. X   }
  1136. X   for (col = 0; col < 8; ++col) {
  1137. X      board[rownum][col] = 1;
  1138. X      if ((sumline(rownum, col, -1, 0) +
  1139. X          sumline(rownum, col, -1, 1) +
  1140. X          sumline(rownum, col, -1, -1)) == 3) {
  1141. X         tryrow(rownum + 1);
  1142. X      }
  1143. X      board[rownum][col] = 0;
  1144. X   }
  1145. X}
  1146. X
  1147. Xint
  1148. Xmain(int argc, char ** argv)
  1149. X{
  1150. X   memset((void *)board, 0, sizeof(board));
  1151. X   tryrow(0);
  1152. X}
  1153. END_OF_FILE
  1154. if test 1188 -ne `wc -c <'queen.c'`; then
  1155.     echo shar: \"'queen.c'\" unpacked with wrong size!
  1156. fi
  1157. # end of 'queen.c'
  1158. fi
  1159. if test -f 'tile.c' -a "${1}" != "-c" ; then 
  1160.   echo shar: Will not clobber existing file \"'tile.c'\"
  1161. else
  1162. echo shar: Extracting \"'tile.c'\" \(6331 characters\)
  1163. sed "s/^X//" >'tile.c' <<'END_OF_FILE'
  1164. X/* The floor tiles in the basement make no sense even trying all possible
  1165. X * color->number assignments and taking the hint into account. So I am
  1166. X * writing this program to simply enumerate all possible paths so I can
  1167. X * try them one at a time...
  1168. X *
  1169. X * I did accidentally solve the puzzle once by going up the left side and
  1170. X * across the top, but I am not sure what I did. This will allow me to
  1171. X * eliminate a large class of the possible paths and may keep the list
  1172. X * down to a manageable size.
  1173. X *
  1174. X * Tiles are assigned numbers starting with 0 at the bottom left corner and
  1175. X * numbering up each column ending with 30 at the top right corner. Because
  1176. X * of my previous accidental solution, I know I must go through tile 16
  1177. X * and I must not go through tile 24 (I can achieve this effect by simply
  1178. X * not listing any paths through 24 which means all valid paths must wind
  1179. X * up going through 16).
  1180. X *
  1181. X * Yeech! There turn out to be way too many combinations. I need to look for
  1182. X * patterns again (maybe I can teach this program to look for patterns).
  1183. X *
  1184. X * I can help some by making the tile cutoff at 15 and 14 instead of just
  1185. X * 24.
  1186. X *
  1187. X * I am also going to record the colors of the tiles and eliminate sequences 
  1188. X * that duplicate the same color sequence even if they don't do the same
  1189. X * tile sequence.
  1190. X *
  1191. X * Well, it's getting smaller. Its down to 431 possible sequences. I am now
  1192. X * going to print all six possible numeric color mappings for each path to
  1193. X * see if any of them look like obvious patterns...
  1194. X *
  1195. X * [Why do I get the feeling that if I ever figure this out, I will look
  1196. X * like an idiot for going to all this trouble :-].
  1197. X *
  1198. X * Sigh. I still see no patterns of any kind, but it turns out that if I
  1199. X * just start trying the 400 or so patterns this program generates, the
  1200. X * second one does the trick (I hope prior state doesn't determine what
  1201. X * works - if so, the second pattern probably *isn't* what really worked,
  1202. X * but all the random attempts leading up to it :-).
  1203. X */
  1204. X
  1205. X#include <stdio.h>
  1206. X
  1207. Xtypedef enum {
  1208. X   Finish,
  1209. X   Purple,
  1210. X   Yellow,
  1211. X   Blue,
  1212. X   Start
  1213. X} TileColor;
  1214. X
  1215. Xchar color_names[] = "FPYBS";
  1216. X
  1217. Xint number_perms[6][5] = {
  1218. X   {0, 1, 2, 3, 4},
  1219. X   {0, 1, 3, 2, 4},
  1220. X   {0, 2, 1, 3, 4},
  1221. X   {0, 2, 3, 1, 4},
  1222. X   {0, 3, 1, 2, 4},
  1223. X   {0, 3, 2, 1, 4}
  1224. X};
  1225. X
  1226. Xchar number_names[] = "B123A";
  1227. X
  1228. Xtypedef struct ft {
  1229. X   int         prev;  /* Number of the tile I was on before this */
  1230. X   int         mark;  /* Set TRUE if I have seen this tile already */
  1231. X   TileColor   color; /* Color of this tile */
  1232. X} FloorTile;
  1233. X
  1234. XFloorTile tile[31] = {
  1235. X/*  0 */   {0,0,Start},
  1236. X/*  1 */   {0,0,Yellow},
  1237. X/*  2 */   {0,0,Purple},
  1238. X/*  3 */   {0,0,Purple},
  1239. X/*  4 */   {0,0,Purple},
  1240. X/*  5 */   {0,0,Purple},
  1241. X/*  6 */   {0,0,Blue},
  1242. X/*  7 */   {0,0,Blue},
  1243. X/*  8 */   {0,0,Yellow},
  1244. X/*  9 */   {0,0,Purple},
  1245. X/* 10 */   {0,0,Yellow},
  1246. X/* 11 */   {0,0,Purple},
  1247. X/* 12 */   {0,0,Blue},
  1248. X/* 13 */   {0,0,Blue},
  1249. X/* 14 */   {0,0,Yellow},
  1250. X/* 15 */   {0,0,Purple},
  1251. X/* 16 */   {0,0,Yellow},
  1252. X/* 17 */   {0,0,Blue},
  1253. X/* 18 */   {0,0,Yellow},
  1254. X/* 19 */   {0,0,Purple},
  1255. X/* 20 */   {0,0,Blue},
  1256. X/* 21 */   {0,0,Yellow},
  1257. X/* 22 */   {0,0,Purple},
  1258. X/* 23 */   {0,0,Purple},
  1259. X/* 24 */   {0,0,Blue},
  1260. X/* 25 */   {0,0,Blue},
  1261. X/* 26 */   {0,0,Yellow},
  1262. X/* 27 */   {0,0,Blue},
  1263. X/* 28 */   {0,0,Purple},
  1264. X/* 29 */   {0,0,Blue},
  1265. X/* 30 */   {0,0,Finish}
  1266. X};
  1267. X
  1268. Xint step[31][6] = {
  1269. X/*  0 */   {4, 31},
  1270. X/*  1 */   {5, 6, 31},
  1271. X/*  2 */   {7, 8, 31},
  1272. X/*  3 */   {9, 31},
  1273. X/*  4 */   {0, 10, 5, 31},
  1274. X/*  5 */   {1, 6, 11, 10, 4, 31},
  1275. X/*  6 */   {7, 11, 5, 1, 31},
  1276. X/*  7 */   {2, 8, 31},
  1277. X/*  8 */   {7, 2, 9, 12, 31},
  1278. X/*  9 */   {3, 13, 12, 8, 31},
  1279. X/* 10 */   {4, 5, 11, /*15, 14,*/ 31},
  1280. X/* 11 */   {/*15,*/ 10, 5, 6, 31},
  1281. X/* 12 */   {8, 9, 13, 16, 31},
  1282. X/* 13 */   {9, 12, 16, 31},
  1283. X/* 14 */   {10, 15, 17, 31},
  1284. X/* 15 */   {18, 17, 14, 10, 11, 31},
  1285. X/* 16 */   {12, 13, 20, 19, 31},
  1286. X/* 17 */   {14, 15, 18, 22, 21, 31},
  1287. X/* 18 */   {15, 17, 22, 23, 31},
  1288. X/* 19 */   {16, 20, 26, 25, 31},
  1289. X/* 20 */   {16, 19, 26, 31},
  1290. X/* 21 */   {27, 17, 22, 31},
  1291. X/* 22 */   {21, 17, 18, 23, 28, 31},
  1292. X/* 23 */   {18, 22, 28, /*24,*/ 31},
  1293. X/* 24 */   {/*23, 25, 29,*/ 31},
  1294. X/* 25 */   {19, 26, /*24,*/ 29, 31},
  1295. X/* 26 */   {25, 19, 20, 30, 31},
  1296. X/* 27 */   {21, 31},
  1297. X/* 28 */   {22, 23, 31},
  1298. X/* 29 */   {/*24,*/ 25, 31},
  1299. X/* 30 */   {26, 31}
  1300. X};
  1301. X
  1302. Xint max_len = 19;
  1303. X
  1304. Xvoid
  1305. XPrintPath(int this_tile)
  1306. X{
  1307. X   if (this_tile == 0) {
  1308. X      printf("  Path: 0");
  1309. X   } else {
  1310. X      PrintPath(tile[this_tile].prev);
  1311. X      printf("-%d",this_tile);
  1312. X   }
  1313. X}
  1314. X
  1315. X#define HASH_MAX 2063
  1316. X
  1317. Xtypedef struct he {
  1318. X   struct he * next;
  1319. X   char        name[1];
  1320. X} HashEntry;
  1321. X
  1322. XHashEntry * hash_tab[HASH_MAX];
  1323. X
  1324. Xvoid
  1325. XCheckSequence()
  1326. X{
  1327. X   char seq_name[32];
  1328. X   int i;
  1329. X   int p;
  1330. X   char * namep;
  1331. X   unsigned long hash = 0;
  1332. X   HashEntry * hep;
  1333. X
  1334. X   seq_name[31] = '\0';
  1335. X   for (i = 30, p = 30; p != -1; --i, p = tile[p].prev) {
  1336. X      int c = (int)(tile[p].color);
  1337. X      seq_name[i] = (char)c;
  1338. X      hash = ((hash << 2) ^ c);
  1339. X   }
  1340. X   ++i;
  1341. X   namep = &seq_name[i];
  1342. X   hash = hash % HASH_MAX;
  1343. X   for (hep = hash_tab[hash]; hep != NULL; hep = hep->next) {
  1344. X      if (strcmp(hep->name, namep) == 0) {
  1345. X         /* Return without printing anything - we already saw this
  1346. X          * sequence of colors.
  1347. X          */
  1348. X         return;
  1349. X      }
  1350. X   }
  1351. X   hep = (HashEntry *)malloc(sizeof(HashEntry) + strlen(namep));
  1352. X   strcpy(hep->name, namep);
  1353. X   hep->next = hash_tab[hash];
  1354. X   hash_tab[hash] = hep;
  1355. X   PrintPath(30);
  1356. X   printf("\n");
  1357. X   printf("Colors:");
  1358. X   while ((*namep) != '\0') {
  1359. X      printf(" %c", color_names[*namep]);
  1360. X      ++namep;
  1361. X   }
  1362. X   printf(" %c\n", color_names[0]);
  1363. X   for (p = 0; p < 6; ++p) {
  1364. X      namep = &seq_name[i];
  1365. X      printf("Perm %d:", p);
  1366. X      while ((*namep) != '\0') {
  1367. X         printf(" %c", number_names[number_perms[p][*namep]]);
  1368. X         ++namep;
  1369. X      }
  1370. X      printf(" %c\n", number_names[number_perms[p][0]]);
  1371. X   }
  1372. X}
  1373. X
  1374. Xvoid
  1375. XWalkTile(int this_tile, int prev_tile, int len)
  1376. X{
  1377. X   int i, d;
  1378. X
  1379. X   tile[this_tile].mark = 1;
  1380. X   tile[this_tile].prev = prev_tile;
  1381. X   if (this_tile == 30) {
  1382. X      CheckSequence();
  1383. X   } else if (len < max_len) {
  1384. X      for (i = 0; (d = step[this_tile][i]) != 31; ++i) {
  1385. X         if (tile[d].mark == 0) {
  1386. X            WalkTile(d, this_tile, len + 1);
  1387. X         }
  1388. X      }
  1389. X   }
  1390. X   tile[this_tile].mark = 0;
  1391. X}
  1392. X
  1393. Xint
  1394. Xmain(int argc, char ** argv)
  1395. X{
  1396. X   if (argc > 1) {
  1397. X      max_len = atoi(argv[1]);
  1398. X   }
  1399. X   WalkTile(0, -1, 1);
  1400. X}
  1401. END_OF_FILE
  1402. if test 6331 -ne `wc -c <'tile.c'`; then
  1403.     echo shar: \"'tile.c'\" unpacked with wrong size!
  1404. fi
  1405. # end of 'tile.c'
  1406. fi
  1407. if test -f 'tiles' -a "${1}" != "-c" ; then 
  1408.   echo shar: Will not clobber existing file \"'tiles'\"
  1409. else
  1410. echo shar: Extracting \"'tiles'\" \(873 characters\)
  1411. sed "s/^X//" >'tiles' <<'END_OF_FILE'
  1412. XJust looking for patterns in the permutations of color to number assignments
  1413. X(I can't find any).
  1414. X
  1415. XP=1      P=3      P=1      P=2      P=2      P=3
  1416. XB=2      B=2      B=3      B=3      B=1      B=1
  1417. XY=3      Y=1      Y=2      Y=1      Y=3      Y=2
  1418. X
  1419. X1 2 2 O  3 2 2 O  1 3 3 O  2 3 3 O  2 1 1 O  3 1 1 O
  1420. X 1 3 3    3 1 1    1 2 2    2 1 1    2 3 3    3 2 2
  1421. X  2 1      2 3      3 1      3 2      1 2      1 3
  1422. X 3   2    1   2    2   3    1   3    3   1    2   1
  1423. X1     2  3     2  1     3  2     3  2     1  3     1
  1424. X 2   2    2   2    3   3    3   3    1   1    1   1
  1425. X
  1426. X 2   1    2   3    3   1    3   2    1   2    1   3
  1427. X3 1 3 1  1 3 1 3  2 1 2 1  1 2 1 2  3 2 3 2  2 3 2 3
  1428. X 1 1 1    3 3 3    1 1 1    2 2 2    2 2 2    3 3 3
  1429. X  3 2      1 2      2 3      1 3      3 1      2 1
  1430. X 1 3 3    3 1 1    1 2 2    2 1 1    2 3 3    3 2 2
  1431. XI     2  I     2  I     3  I     3  I     1  I     1
  1432. END_OF_FILE
  1433. if test 873 -ne `wc -c <'tiles'`; then
  1434.     echo shar: \"'tiles'\" unpacked with wrong size!
  1435. fi
  1436. # end of 'tiles'
  1437. fi
  1438. echo shar: End of archive 1 \(of 2\).
  1439. cp /dev/null ark1isdone
  1440. MISSING=""
  1441. for I in 1 2 ; do
  1442.     if test ! -f ark${I}isdone ; then
  1443.     MISSING="${MISSING} ${I}"
  1444.     fi
  1445. done
  1446. if test "${MISSING}" = "" ; then
  1447.     echo You have unpacked both archives.
  1448.     rm -f ark[1-9]isdone
  1449. else
  1450.     echo You still need to unpack the following archives:
  1451.     echo "        " ${MISSING}
  1452. fi
  1453. ##  End of shell archive.
  1454. exit 0
  1455. --
  1456. ======================================================================
  1457. domain: tahorsley@csd.harris.com       USMail: Tom Horsley
  1458.   uucp: ...!uunet!hcx1!tahorsley               511 Kingbird Circle
  1459.                                                Delray Beach, FL  33444
  1460. +==== Censorship is the only form of Obscenity ======================+
  1461. |     (Wait, I forgot government tobacco subsidies...)               |
  1462. +====================================================================+
  1463.  
  1464. exit 0 # Just in case...
  1465.