fork download
  1. /*********************************************************//**
  2.  * Author: migf1
  3.  * from Book: C Programming, A Modern Approach (2nd edition)
  4.  * Chapter: 8 (Arrays)
  5.  * Programming project: 9 (page 179)
  6.  ************************************************************/
  7.  
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include <time.h>
  12.  
  13. #define UNAVAIL -1 /* flag unavailable pos */
  14.  
  15. #define NROWS 10 /* table height in rows */
  16. #define NCOLS 10 /* table width in cols */
  17.  
  18. #define myMIN(x,y) ( (x) < (y) ? (x) : (y) )
  19.  
  20. #define ROW(pos) ( (pos) / NCOLS ) /* calc row-index of pos*/
  21. #define COL(pos) ( (pos) % NCOLS ) /* calc col-index of pos*/
  22.  
  23. #define POSUP(pos) ( (pos) - NCOLS ) /* calc pos minus 1 row */
  24. #define POSDN(pos) ( (pos) + NCOLS ) /* calc pos plus 1 row */
  25. #define POSLF(pos) ( (pos) - 1 ) /* calc pos minus 1 col */
  26. #define POSRT(pos) ( (pos) + 1 ) /* calc pos plus 1 col */
  27.  
  28. #define EMPTY '.' /* empty cells' content */
  29. #define USED "ABCDEFGHIJKLMNOPQRSTUVWXYZ" /* used cells' contents */
  30.  
  31. #define ISEMPTY(pos, tab) ( EMPTY == (tab)[ (pos) ] ) /* is tab[pos] empty? */
  32.  
  33. #define ISBLOCKED(pos, tab) \
  34. ( ROW(pos) == 0 || !ISEMPTY( POSUP(pos), tab ) ) \
  35. && ( ROW(pos) == NROWS-1 || !ISEMPTY( POSDN(pos), tab ) ) \
  36. && ( COL(pos) == 0 || !ISEMPTY( POSLF(pos), tab ) ) \
  37. && ( COL(pos) == NCOLS-1 || !ISEMPTY( POSRT(pos), tab ) )
  38.  
  39. enum Dir { UP=0, DN, LF, RT }; /* allowed mv directions*/
  40.  
  41. /*********************************************************//**
  42.  * Print the contents of the board.
  43.  ************************************************************/
  44. void tab_print( const char tab[] )
  45. {
  46. for (int n=0; n < NROWS * NCOLS; n++)
  47. {
  48. if ( n != 0 && n % NCOLS == 0 )
  49. putchar('\n');
  50. printf( "%c ", tab[n] );
  51. }
  52.  
  53. putchar('\n');
  54. }
  55.  
  56. /*********************************************************//**
  57.  * ** UNUSED **
  58.  * The macro: ISBLOCKED() is used instead, but it has not been debuged thoroughly yet.
  59.  * In case of problems, try using this function instead of the macro.
  60.  ************************************************************/
  61. _Bool isblocked( const int pos, const char tab[] )
  62. {
  63. int nblocked = 0;
  64.  
  65. if ( ROW(pos) == 0 || !ISEMPTY(POSUP(pos), tab) )
  66. nblocked++;
  67. if ( ROW(pos) == NROWS-1 || !ISEMPTY(POSDN(pos), tab) )
  68. nblocked++;
  69. if ( COL(pos) == 0 || !ISEMPTY(POSLF(pos), tab) )
  70. nblocked++;
  71. if ( COL(pos) == NCOLS-1 || !ISEMPTY(POSRT(pos), tab) )
  72. nblocked++;
  73.  
  74. //printf("%c: nblocked = %d\n", tab[pos], nblocked );
  75. return 4 == nblocked;
  76. }
  77.  
  78.  
  79. /*********************************************************//**
  80.  * Calc a new position in table tab, according to current position pos & direction dir.
  81.  * Return the newlly calculated position, or UNAVAIL on error.
  82.  ************************************************************/
  83. int get_nextpos( const int pos, const enum Dir dir, const char tab[] )
  84. {
  85. int ret = UNAVAIL;
  86.  
  87. switch (dir)
  88. {
  89. case UP:
  90. ret = ROW(pos) > 0 && ISEMPTY( POSUP(pos), tab )
  91. ? POSUP(pos)
  92. : UNAVAIL;
  93. break;
  94.  
  95. case DN:
  96. ret = ROW(pos) < NROWS-1 && ISEMPTY( POSDN(pos), tab )
  97. ? POSDN(pos)
  98. : UNAVAIL;
  99. break;
  100. case LF:
  101.  
  102. ret = COL(pos) > 0 && ISEMPTY( POSLF(pos), tab )
  103. ? POSLF(pos)
  104. : UNAVAIL;
  105. break;
  106.  
  107. case RT:
  108. ret = COL(pos) < NCOLS-1 && ISEMPTY( POSRT(pos), tab )
  109. ? POSRT(pos)
  110. : UNAVAIL;
  111. break;
  112. default:
  113. break;
  114. }
  115.  
  116. return ret;
  117. }
  118.  
  119. /*********************************************************//**
  120.  *
  121.  ************************************************************/
  122. int main( void )
  123. {
  124. /* total # of moves allowed */
  125. const int MVTOTAL = myMIN( NROWS*NCOLS, (int)(strlen(USED) - 1) );
  126. int mvcount = 0; /* moves counter */
  127. int pos = 0, try = 0; /* current & next move positions*/
  128. char tab[ NROWS * NCOLS ]; /* our un-initialized board */
  129.  
  130. srand( (unsigned)time(NULL) ); /* init pseudo-random seed */
  131. memset( tab, EMPTY, sizeof(tab) ); /* init table with dots */
  132.  
  133. tab[0] = USED[0]; /* start with filled 1st pos */
  134. while ( mvcount < MVTOTAL )
  135. {
  136. /* a blocked pos terminates the loop */
  137. if ( ISBLOCKED(pos, tab) )
  138. break;
  139.  
  140. /* try moves until an available pos is found */
  141. do
  142. try = get_nextpos( pos, rand() % 4, tab );
  143. while ( UNAVAIL == try );
  144.  
  145. /* accept available move as next pos */
  146. pos = try;
  147. tab[ pos ] = USED[ ++mvcount ];
  148. }
  149. tab_print( tab );
  150.  
  151. exit( EXIT_SUCCESS );
  152. }
  153.  
Success #stdin #stdout 0.01s 1720KB
stdin
Standard input is empty
stdout
A . . . . . . . . . 
B Y Z . . . . . . . 
C X W V . . . . . . 
D E . U . . . . . . 
G F . T . . . . . . 
H . . S . . . . . . 
I . . R Q . . . . . 
J K N O P . . . . . 
. L M . . . . . . . 
. . . . . . . . . .