mz.c

Jim Balter jim at ism780c.UUCP
Wed Nov 5 20:27:19 AEST 1986


#ifdef README
This little program produces random rectangular mazes suitable for display on
a ASCII character device.  It should be easy to convert it for a bitmap
or vector display if desired.
Invoke as "mz nrows ncols".  The output consists of nrows + 1 lines of
2 * ncols + 1 characters, so "mz 22 39" fits on a standard CRT screen.
For more of a challenge, try "mz 65 65" on 11"x17" printer paper.

There is always exactly one solution.
#endif

#include <stdio.h>

#define oneof(n)    (int)(((long)(n) * rand())/32768)
#define BOT     0
#define LEFT    1
#define TOP     2
#define RIGHT   3

typedef struct {unsigned c_group:14, c_bot:1, c_left:1, c_next;} cell_t;
#define group(cell)         cells[cell].c_group
#define setgroup(cell, g)   (cells[cell].c_group = (g))
#define next(cell)          cells[cell].c_next
#define setnext(cell, g)    (cells[cell].c_next = (g))
#define botwall(cell)       !cells[cell].c_bot
#define leftwall(cell)      !cells[cell].c_left
#define isborder(cell)      (group(cell) == 0)
cell_t  *cells;

#define neighbor(cell, side) ((cell) + nboff[side])
int     nboff[4];

#define loc(r, c)           ((r) * width + (c) + 1)
int     nrows, ncols, width, ncells;

blast (cell, side)
{
	switch( side )
	{   case BOT:   cells[cell].c_bot  = 1; break;
	    case LEFT:  cells[cell].c_left = 1; break;
	    case TOP:   cells[neighbor(cell, TOP  )].c_bot  = 1; break;
	    case RIGHT: cells[neighbor(cell, RIGHT)].c_left = 1; break;
	}
}

init ()
{
	register        r, c, cell;
	register long   t;
	extern   long   time();
	extern   char   *calloc();

	t = time((long *)NULL);
	srand((unsigned)t + (unsigned)(t >> 16) + getpid());

	ncells = nrows * ncols;
	width = ncols + 1;

	cells = (cell_t *)calloc((nrows+2) * width, sizeof(cell_t));
	if( !cells ) { fprintf(stderr, "Not enough memory\n"); exit(-1); }
	cells += width;

	for( c = ncols; --c >= 0; )
	{   for( r = nrows; --r >= 0; )
	    {   cell = loc(r, c);
		setgroup(cell, cell);
	    }
	    blast(loc(-1, c), LEFT);
	}
	blast(loc(-1, ncols), BOT);
	blast(loc(-1, ncols), LEFT);
	blast(loc(-1, -1), BOT);

	nboff[BOT]   = width;
	nboff[LEFT]  = -1;
	nboff[TOP]   = -width;
	nboff[RIGHT] = 1;
}

#define isconnected(cell1, cell2) (group(cell1) == group(cell2))

join (cell, side)
	register        cell;
	register        side;
{
	register        ocell;
	register        newgroup, oldgroup;

	blast(cell, side);

	oldgroup = group(cell);
	newgroup = group(neighbor(cell, side));

	for( cell = oldgroup; cell; ocell = cell, cell = next(cell) )
	    setgroup(cell, newgroup);

	setnext(ocell, next(newgroup));
	setnext(newgroup, oldgroup);
}

connect (cell)
	register        cell;
{
	register        side, nb;

	side = oneof(2);
	if( isborder(nb = neighbor(cell, side)) || isconnected(cell, nb) )
	{   side = 1 - side;
	    if( isborder(nb = neighbor(cell, side)) || isconnected(cell, nb) )
		return 0;
	}
	join(cell, side);
	return 1;
}

print ()
{
	register        r, c, cell, ch;

	for( r = -1; r < nrows; putchar('\n'), r++ )
	    for( c = 0; c <= ncols; c++ )
	    {   cell = loc(r, c);
		if( leftwall(cell) )
		    ch = '|';
		else
		{   ch = '_';
		    if( leftwall(neighbor(cell, BOT)) )
		    {   if( !botwall(cell) || !botwall(neighbor(cell, LEFT)) )
			    ch = '.';
		    }
		    else
			if( !botwall(cell) && !botwall(neighbor(cell, LEFT)) )
			    ch = '.';
		}
		putchar(ch);

		if( c == ncols ) break;

		putchar(botwall(cell)? '_' : ' ');
	    }
}

main (argc, argv)
		 char   **argv;
{
	register        n, ncon;

	if( argc != 3 )
	{   fprintf(stderr, "usage: %s nrows ncols\n", argv[0]);
	    exit(-1);
	}

	nrows = atoi(argv[1]);
	ncols = atoi(argv[2]);

	init();

	for( ncon = ncells - 1; --ncon >= 0; )
	    for( n = oneof(ncells);; n = (n+1) % ncells )
		if( connect(loc(n/ncols, n%ncols)) ) break;

	blast(loc(0, oneof(ncols)), TOP);
	blast(loc(nrows-1, oneof(ncols)), BOT);

	print();
}
-- 
-- Jim Balter ({sdcrdcf!ism780c,ima}!jim)



More information about the Comp.sources.unix mailing list