/*********************************************************//**
* Author: migf1
* from Book: C Programming, A Modern Approach (2nd edition)
* Chapter: 8 (Arrays)
* Programming project: 9 (page 179)
************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define UNAVAIL -1 /* flag unavailable pos */
#define NROWS 10 /* table height in rows */
#define NCOLS 10 /* table width in cols */
#define myMIN(x,y) ( (x) < (y) ? (x) : (y) )
#define ROW(pos) ( (pos) / NCOLS ) /* calc row-index of pos*/
#define COL(pos) ( (pos) % NCOLS ) /* calc col-index of pos*/
#define POSUP(pos) ( (pos) - NCOLS ) /* calc pos minus 1 row */
#define POSDN(pos) ( (pos) + NCOLS ) /* calc pos plus 1 row */
#define POSLF(pos) ( (pos) - 1 ) /* calc pos minus 1 col */
#define POSRT(pos) ( (pos) + 1 ) /* calc pos plus 1 col */
#define EMPTY '.' /* empty cells' content */
#define USED "ABCDEFGHIJKLMNOPQRSTUVWXYZ" /* used cells' contents */
#define ISEMPTY(pos, tab) ( EMPTY == (tab)[ (pos) ] ) /* is tab[pos] empty? */
#define ISBLOCKED(pos, tab) \
( ROW(pos) == 0 || !ISEMPTY( POSUP(pos), tab ) ) \
&& ( ROW(pos) == NROWS-1 || !ISEMPTY( POSDN(pos), tab ) ) \
&& ( COL(pos) == 0 || !ISEMPTY( POSLF(pos), tab ) ) \
&& ( COL(pos) == NCOLS-1 || !ISEMPTY( POSRT(pos), tab ) )
enum Dir { UP=0, DN, LF, RT }; /* allowed mv directions*/
/*********************************************************//**
* Print the contents of the board.
************************************************************/
void tab_print( const char tab[] )
{
for (int n=0; n < NROWS * NCOLS; n++)
{
if ( n != 0 && n % NCOLS == 0 )
}
}
/*********************************************************//**
* ** UNUSED **
* The macro: ISBLOCKED() is used instead, but it has not been debuged thoroughly yet.
* In case of problems, try using this function instead of the macro.
************************************************************/
_Bool isblocked( const int pos, const char tab[] )
{
int nblocked = 0;
if ( ROW(pos) == 0 || !ISEMPTY(POSUP(pos), tab) )
nblocked++;
if ( ROW(pos) == NROWS-1 || !ISEMPTY(POSDN(pos), tab) )
nblocked++;
if ( COL(pos) == 0 || !ISEMPTY(POSLF(pos), tab) )
nblocked++;
if ( COL(pos) == NCOLS-1 || !ISEMPTY(POSRT(pos), tab) )
nblocked++;
//printf("%c: nblocked = %d\n", tab[pos], nblocked );
return 4 == nblocked;
}
/*********************************************************//**
* Calc a new position in table tab, according to current position pos & direction dir.
* Return the newlly calculated position, or UNAVAIL on error.
************************************************************/
int get_nextpos( const int pos, const enum Dir dir, const char tab[] )
{
int ret = UNAVAIL;
switch (dir)
{
case UP:
ret = ROW(pos) > 0 && ISEMPTY( POSUP(pos), tab )
? POSUP(pos)
: UNAVAIL;
break;
case DN:
ret = ROW(pos) < NROWS-1 && ISEMPTY( POSDN(pos), tab )
? POSDN(pos)
: UNAVAIL;
break;
case LF:
ret = COL(pos) > 0 && ISEMPTY( POSLF(pos), tab )
? POSLF(pos)
: UNAVAIL;
break;
case RT:
ret = COL(pos) < NCOLS-1 && ISEMPTY( POSRT(pos), tab )
? POSRT(pos)
: UNAVAIL;
break;
default:
break;
}
return ret;
}
/*********************************************************//**
*
************************************************************/
int main( void )
{
/* total # of moves allowed */
const int MVTOTAL
= myMIN
( NROWS
*NCOLS
, (int)(strlen(USED
) - 1) ); int mvcount = 0; /* moves counter */
int pos = 0, try = 0; /* current & next move positions*/
char tab[ NROWS * NCOLS ]; /* our un-initialized board */
srand( (unsigned)time(NULL
) ); /* init pseudo-random seed */ memset( tab
, EMPTY
, sizeof(tab
) ); /* init table with dots */
tab[0] = USED[0]; /* start with filled 1st pos */
while ( mvcount < MVTOTAL )
{
/* a blocked pos terminates the loop */
if ( ISBLOCKED(pos, tab) )
break;
/* try moves until an available pos is found */
do
try
= get_nextpos
( pos
, rand() % 4, tab
); while ( UNAVAIL == try );
/* accept available move as next pos */
pos = try;
tab[ pos ] = USED[ ++mvcount ];
}
tab_print( tab );
}