Advertisement
Guest User

Untitled

a guest
Jun 25th, 2017
63
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 6.65 KB | None | 0 0
  1. /* Solves the knight tours using backtracking */
  2.  
  3. #include <stdio.h>
  4. #include <string.h>
  5. #include <stdlib.h>
  6. #include <stdint.h>
  7. #include <time.h>
  8. #include <ctype.h>
  9.  
  10. #define USE_ASM 1
  11.  
  12. #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
  13.  
  14. /* defines */
  15. #define BOARD_MASK 0xFFFFFFFFFFFFFFFFULL
  16. #define SQ(X)  (1ULL << (X))
  17. #define AFILE  0x0101010101010101ULL
  18. #define BFILE  0x0202020202020202ULL
  19. #define CFILE  0x0404040404040404ULL
  20. #define DFILE  0x0808080808080808ULL
  21. #define EFILE  0x1010101010101010ULL
  22. #define FFILE  0x2020202020202020ULL
  23. #define GFILE  0x4040404040404040ULL
  24. #define HFILE  0x8080808080808080ULL
  25.  
  26. typedef unsigned int uint;
  27. typedef uint64_t     board_t;
  28.  
  29. /* the struct in which we save our path that
  30.  * the knight take to solve the tour */
  31. typedef struct Solution_
  32. {
  33.     uint moves[64];
  34.     uint nmoves;
  35. } Solution;
  36.  
  37. /* the struct that holds everything */
  38. typedef struct KT_
  39. {
  40.     size_t   nsolutions;
  41.     uint     pos;
  42.     Solution cursolution;
  43.     board_t  board, solved;
  44. } KT;
  45.  
  46. /* data */
  47. static KT kt;
  48. static board_t knight_moves[64];
  49. static int     knight_popcount[64];
  50.  
  51. /* functions */
  52. static void        init           (void);
  53. static void        setup          (KT *kt, const char *startpos);
  54. static size_t      gen_moves      (KT *kt, uint *moves);
  55. static void        solve          (KT *kt);
  56. static int         lsb            (board_t v);
  57. static void        make_move      (KT *kt, uint move);
  58. static void        undo_move      (KT *kt, uint move);
  59. static void        print_board    (KT *kt, int solved);
  60. static void        print_solution (Solution *s);
  61. static int         popcount       (board_t b);
  62.  
  63. int main(int argc, char *argv[])
  64. {
  65.     time_t start;
  66.    
  67.     if (argc < 2 || (argv[1][0] < 'a'  || argv[1][0] > 'h') ||
  68.                     (argv[1][1] <= '0' || argv[1][1] >= '9'))
  69.     {
  70.         printf("Usage: <square to solve>\n");
  71.         return 1;
  72.     }
  73.  
  74.     init();
  75.     setup(&kt, argv[1]);
  76.     printf("Solving\n");
  77.     print_board(&kt, 1);
  78.     start = time(NULL);
  79.     solve(&kt);
  80.     printf("Took %d seconds.\n", time(NULL) - start);
  81.     return 0;    
  82. }
  83.  
  84. /* return lsb of a bit, used for extracting move sequences
  85.  * from the bitboard */
  86. static int lsb(board_t v)
  87. {
  88.  
  89. /* this is x86 32 bit asm */
  90. #if USE_ASM
  91.  
  92.     int x;
  93.       __asm__(
  94.           "bsfl %1, %0\n\t"
  95.           "jnz done\n\t"
  96.           "bsfl %2, %0\n\t"
  97.           "addl $32, %0\n\t"
  98.           "done:\n\t"
  99.           : "=r" (x)
  100.           : "r" (v & 0xFFFFFFFFUL), "0" ((v >> 32) & 0xFFFFFFFFUL)
  101.          );
  102.       return x;
  103.  
  104. #else
  105.     uint  i;
  106.  
  107.     for (i = 0; i < 64; i += 4)
  108.     {
  109.         if (v & SQ(i))
  110.             return i;
  111.  
  112.         if (v & SQ(i+1))
  113.             return i+1;
  114.  
  115.         if (v & SQ(i+2))
  116.             return i + 2;
  117.    
  118.         if (v & SQ(i+3))
  119.             return i + 3;
  120.     }
  121.  
  122.     return 0;
  123.  
  124. #endif
  125.  
  126. }
  127.  
  128. static int popcount(board_t v)
  129. {
  130.     int ret   = 0;
  131.     board_t b = v;
  132.  
  133.     while (b)
  134.     {
  135.         b &= (b - 1);
  136.         ret++;
  137.     }
  138.  
  139.     return ret;
  140. }
  141.  
  142. /* init stuff */
  143. static void init(void)
  144. {
  145.     int i;
  146.  
  147.     /* pre-compute the knight moves
  148.      * so we can generate knight moves quickly */
  149.     for (i = 0; i < 64; i++)
  150.     {
  151.         knight_moves[i] = ((SQ(i) << 17) & ~(AFILE))         |    
  152.                           ((SQ(i) << 15) & ~(HFILE))         |
  153.                           ((SQ(i) << 10) & ~(AFILE | BFILE)) |
  154.                           ((SQ(i) <<  6) & ~(GFILE | HFILE)) |
  155.                           ((SQ(i) >> 17) & ~(HFILE))         |
  156.                           ((SQ(i) >> 10) & ~(GFILE | HFILE)) |
  157.                           ((SQ(i) >>  6) & ~(AFILE | BFILE)) |
  158.                           ((SQ(i) >> 15) & ~(AFILE));
  159.        
  160.         knight_popcount[i] = popcount(knight_moves[i]);
  161.     }
  162. }
  163.  
  164. /* reset the board to default state */
  165. static void setup(KT *kt, const char *startpos)
  166. {
  167.     size_t i;
  168.     uint sq;
  169.    
  170.     sq = ((startpos[1] - '1') * 8) + (tolower(startpos[0]) - 'a');
  171.    
  172.     kt->nsolutions = 0;
  173.     kt->pos        = sq;
  174.     kt->solved     = SQ(sq);
  175.     kt->board      = SQ(sq);
  176.    
  177.     kt->cursolution.moves[0] = sq;
  178.     kt->cursolution.nmoves   = 1;
  179. }
  180.  
  181. /* print out the solved board or the current board */
  182. static void print_board(KT *kt, int solved)
  183. {
  184.     board_t b = (solved) ? kt->solved : kt->board;
  185.     board_t sq;
  186.     int     i, k;
  187.  
  188.     printf("\n");
  189.     for (i = 56; i >= 0; i -= 8)
  190.     {
  191.         for (k = 0; k < 8; k++)
  192.         {
  193.             sq = SQ(i + k);
  194.             if (b & sq)
  195.                 printf("N ");
  196.             else
  197.                 printf(". ");
  198.         }
  199.         printf("\n");
  200.     }
  201.     printf("\n");
  202. }
  203.  
  204. /* print out a solution */
  205. static void print_solution(Solution *s)
  206. {
  207.     uint   sq;
  208.     size_t i;
  209.     for (i = 0; i < s->nmoves; i++)
  210.     {
  211.         sq = s->moves[i] & 0x3F;
  212.         printf("Move %d: N%c%d\n", i, (sq & 7) + 'a', (sq / 8) + 1);
  213.     }
  214.     printf("\n");
  215. }
  216.  
  217. /* make a move */
  218. static void make_move(KT *kt, uint move)
  219. {
  220.     move &= 0x3F;
  221.     kt->pos     = move;
  222.     kt->board   = SQ(move);
  223.     kt->solved |= SQ(move);
  224. }
  225.  
  226. /* undo a move */
  227. static void undo_move(KT *kt, uint move)
  228. {
  229.     uint oldpos = move >> 8;
  230.     kt->pos     =  oldpos;
  231.     kt->board   =  SQ(oldpos);
  232.     kt->solved &= ~SQ(move & 0x3F);
  233. }
  234.  
  235. /* generate a move */
  236. static size_t gen_moves(KT *kt, uint *moves)
  237. {
  238.     int       popcnt[2] = { -1 };
  239.     size_t    i         = 0;
  240.     board_t   b         = knight_moves[kt->pos] & ~kt->solved,
  241.                           sq;
  242.     uint      temp,
  243.               oldpos    = kt->pos;
  244.  
  245.     while (b)
  246.     {
  247.         sq = lsb(b);
  248.    
  249.         popcnt[0] = popcnt[1];
  250.         popcnt[1] = knight_popcount[sq];
  251.        
  252.         moves[i]  = sq | (oldpos << 8);
  253.  
  254.         /* heuristic where the moves are sorted by
  255.          * least degrees of freedom, seems to  
  256.          * finds solutions much faster */
  257.         if (popcnt[1] < popcnt[0])
  258.         {
  259.             temp         = moves[i];
  260.             moves[i]     = moves[i - 1];
  261.             moves[i - 1] = temp;
  262.         }
  263.  
  264.         i++;
  265.         b &= (b - 1);
  266.     }
  267.  
  268.     return i;
  269. }
  270.  
  271. /* solve it using backtracking */
  272. static void solve(KT *kt)
  273. {
  274.     size_t i, nmoves;
  275.     uint   moves[16];
  276.  
  277.     if (kt->solved == BOARD_MASK)
  278.     {
  279.         printf("Solution #%d\n", ++kt->nsolutions);
  280.         print_solution(&kt->cursolution);
  281.         return;
  282.     }
  283.    
  284.     nmoves = gen_moves(kt, moves);
  285.    
  286.     for (i = 0; i < nmoves; i++)
  287.     {
  288.         kt->cursolution.moves[kt->cursolution.nmoves++] = moves[i];
  289.         make_move(kt, moves[i]);
  290.        
  291.         solve(kt);
  292.        
  293.         kt->cursolution.nmoves--;
  294.         undo_move(kt, moves[i]);
  295.     }
  296. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement