🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: rec.games.programmer
Article #557

Re: Maze generating algorithm (here's one)

#557
From: Merlyn LeRoy
Date: Mon, 10 Aug 1992 18:56
378 lines
8608 bytes
rossw@ccu1.aukuni.ac.nz (Ross Williamson) writes:
(wants a maze generator)

OK, here's mine.

---cut here---

#include <stdio.h>

/*
 * maze - a simple maze generator
 *   useage: maze [h] [v] [rooms] [style] [seed1] [seed2]
 *
 * h is horizontal, v is vertical dimensions
 *
 * rooms is number of 2x2 rooms to try to place before generating maze
 * (not all rooms may be placed)
 *
 * style is one of:
 *  -1: change style throughout maze
 *   0: normal maze
 *   1: staircase/zigzag
 *   2: twisty maze
 *   3: long zigzags/corridors
 *   4: spiral maze
 *
 * seed1 & seed2 are random number seeds to use
 *
 */

/* note: longs should be 32 bits */
/* random number seeds */
unsigned long tseed, cseed;

unsigned long turn, curve, random;

int h, v, size;			/* h&v dimensions, and total size */
int style, rooms;		/* maze style, #rooms */
char *maze;
extern char *malloc();		/* maze array; can just use maze[10000] */

/* each cell has bits for the right & bottom wall */
#define NOWALL	0x00
#define RWALL	0x01
#define	BWALL	0x02
#define	RBWALL	0x03

/* part of a room, and which cell of room prints out room number */
#define	ROOM	0x04
#define	ROOMNO	(0x08|ROOM)
#define	RDOOR	0x10
#define	BDOOR	0x20

/* empty cells at start */
#define	EMPTY	0x40

/*
 * This is a good random number generator
 * someone posted to comp.lang.c
 */
unsigned long
rnd()
{
    cseed *= 69069;
    tseed ^= ((tseed >> 15) & 0x0001FFFF);
    tseed ^= (tseed << 17);

    return(tseed ^ cseed);
}

main(argc, argv)
int argc;
char *argv[];
{
    /* grab args, or plug in default values */
    if (argc >= 4)
	rooms = atoi(argv[3]);
    else
	rooms = -1;
    if (argc >= 3)
	v = atoi(argv[2]);
    else
	v = 20;
    if (argc >= 2)
	h = atoi(argv[1]);
    else
	h = 38;
    if (argc >= 5)
	style = atoi(argv[4]);
    else
	style = -1;
    if (argc >= 6)
	cseed = atoi(argv[5]);
    else
	cseed = h-v+style+rooms;
    if (argc >= 7)
	tseed = atoi(argv[6]);
    else
	tseed = h^(v<<4)^(style<<8);

    /* Let's get small... NOT! */
    if (h < 7 && v < 7)
	h = 7;
    if (h < 3)
	h = 3;
    if (v < 3)
	v = 3;

    /* We pad the maze 1 cell all around so we don't have to check edges */
    h += 2;
    v += 2;
    size = h*v;
    maze = malloc(size);

    if (maze) {
	genmaze();
	printmaze();
    }
}

genmaze()
{
    int i,j,k,ok,n,on,row,count;
    int oi, oj;
    int a[2];

    /* eat up first couple of rnds() */
    rnd();
    rnd();

    /* zero out maze */
    for (i = size-1; i; i--)
	maze[i] = EMPTY;
    
    /* set up borders */
    for (i = h-1; i; i--)
	maze[i] = BWALL;
    for (i = size-1; i >= size-h; i--)
	maze[i] = NOWALL;

    for (i = size - 2*h; i >= h; i -= h)
	maze[i] = RWALL;
    for (i = size-1; i >= 0; i -= h)
	maze[i] = NOWALL;

    /* turn is likelyhood of turning; curve is direction to turn */
    turn  = 0xFFFFFFFF;
    curve = 0xFFFFFFFF;
    random = 0;
    switch (style) {
    default:
    case -1:
	random = (rnd()+rnd())>>5; /* how often we change styles in maze */
	turn = rnd();			/* totally random attributes */
	curve = rnd();
	break;
    case 0:
	turn  >>= 1;	/* 50% chance to turn */
	curve >>= 1;	/* 50% chance to turn same way */
	break;
    case 1:
	turn  >>= 3;	/* 87% chance to turn */
	curve >>= 3;	/* 87% chance to turn same way */
	break;		/* gives us zigzag maze */
    case 2:
	turn  >>= 3;	/* 87% chance to turn */
	curve >>= 1;	/* 50% chance to turn same way */
	break;		/* gives us twisty maze */
    case 3:
	turn  >>= 4;
	turn = ~turn;	/* 6% chance to turn */
	curve >>= 1;	/* 50% chance to turn same way */
	break;		/* gives us long corridors */
    case 4:
	turn  >>= 4;
	turn = ~turn;	/* 6% chance to turn */
	curve >>= 4;	/* 87% chance to turn same way */
	break;		/* gives us spirals */
    }

    /* count of how many cells we dig until done */
    count = (h-2)*(v-2);

    /* put rooms in first */
    if (rooms == -1)
	rooms = (rnd() & 15) + 1;

    /* occupy top left corner so I can start there */
    maze[1+h] = RBWALL;
    for (; rooms--;) {
	/* pick a rnd location: this needs 32-bit math to work */
	i = ((rnd() & 0xFFFF) * (h-3))>>16;
	j = ((rnd() & 0xFFFF) * (v-3))>>16;
	i++, j++;
	row = j*h;
	/* if I can, put a room there */
	if (count > 4 &&
	  maze[i+row] == EMPTY &&
	  maze[i+row+1] == EMPTY &&
	  maze[i+row+h] == EMPTY &&
	  maze[i+row+h+1] == EMPTY) {
	    maze[i+row] = ROOMNO;
	    maze[i+row+1] = RWALL|ROOM;
	    maze[i+row+h] = BWALL|ROOM;
	    maze[i+row+h+1] = RBWALL|ROOM;
	    count -= 4;
	}
    }
    /* unfill starting cell */
    maze[1+h] = EMPTY;
    i = j = 1;
    row = j*h;

    /* ok & on are turn & curve state variables */
    ok = rnd() & 1;
    on = (rnd() & 2) - 1;

    /* don't branch out from a room unless I have no other choice */
    rooms = ROOM;
    for (; count--;) {
	oi = i; oj = j;
scan:
	a[0] = 3*(maze[i+row-1]!=EMPTY) + (maze[i+row+1]!=EMPTY);
	a[1] = 3*(maze[i+row-h]!=EMPTY) + (maze[i+row+h]!=EMPTY);
	/* This is an easy way to find an open direction */
	if (a[0]+a[1] == 8) {
	    /* blocked; find a new place to dig from */
	    do {
		i++;
		if (i >= h-1) {
		    i = 1;
		    j++;
		    row += h;
		    if (j >= v-1) {
			j = 1;
			row = h;
		    }
		}
		/* if we've scanned whole maze, there are undug places */
		/* that can only be gotten to by digging out rooms; do so */
		if (i== oi && j == oj)
		    rooms = 0;
	    } while (maze[i+row] == EMPTY || (maze[i+row] & rooms));
	    goto scan;
	}

	/* do I try to turn? */
	if (rnd() > turn)
	    ok = 1-ok;
	k = ok;

	/* if a 4, I can't go that way; turn */
	if (a[k] == 4) {
	    k = 1-k;
	    if (style != 3)	/* this lets style 3 produce long zigzags */
		ok = k;
	}

	/* do I change direction of turn? */
	if (rnd() > curve)
	    on = -on;
	n = on;
	/* if sum is 2, I can't go that way; go other way */
	if (a[k]+n == 2)
	    n = -n;

	/* If I am going right or down, remove a wall from this cell */
	if (n == 1) {
	    if (k == 0)
		maze[i+row] &= ~RWALL;
	    else
		maze[i+row] &= ~BWALL;
	}

	/* change to new cell */
	if (k == 0)
	    i += n;
	else {
	    j += n;
	    row = j*h;
	}

	/* new cell has walls */
	maze[i+row] = RBWALL;
	/* If I am going left or up, remove a wall from this cell */
	if (n == -1) {
	    if (k == 0)
		maze[i+row] &= ~RWALL;
	    else
		maze[i+row] &= ~BWALL;
	}

	/* If maze style is random, change styles occasionally */
	if (rnd() < random) {
	    turn = rnd();
	    curve = rnd();
	}
    }

    /* Now scan through and make doors out from rooms */
    row = 0;
    for (j = 1; j < v-1; j++) {
	row += h;
	for (i = 1; i < h-1; i++) {
	    if (maze[i+row] != ROOMNO)
		continue;
	    count = 0;
	    do {
		if (rnd() & 1) {
		    k = ((rnd() & 1) ? i+1 : i-1);
		    n = row + (rnd() & 1) * h;
		    if (k > 0 && k < h-2) {
			maze[k+n] &= ~RWALL;
			maze[k+n] |= RDOOR;
			count = 1;
		    }
		}
		else {
		    n = ((rnd() & 1) ? row+h : row-h);
		    k = i + (rnd() & 1);
		    if (n > 0 && n < (v-2)*h) {
			maze[k+n] &= ~BWALL;
			maze[k+n] |= BDOOR;
			count = 1;
		    }
		}
	    } while (!count || !(rnd() & 3));
	}
    }
}

printmaze()
{
    int i,j,row,room;

    room = 0;
    for (j = 0; j < v-1; j++) {
	row = h*j;
	for (i = 0; i < h; i++) {
	    if (maze[i+row] == EMPTY) {
		putchar('?');
		putchar('?');
		continue;
	    }
	    if (maze[i+row] == ROOMNO) {
		putchar((room/10)+'A');
		putchar((room%10)+'0');
		room++;
		continue;
	    }
	    if (maze[i+row] & BWALL)
		putchar('_');
	    else {
		if (maze[i+row] & BDOOR)
		    putchar('.');
		else
		    putchar(' ');
	    }
	    if (maze[i+row] & RWALL)
		putchar('|');
	    else {
		if (maze[i+row] & RDOOR)
		    putchar(':');
		else {
		    if ((maze[i+row] & (BWALL|BDOOR)) &&
		      (maze[i+row+1] & (BWALL|BDOOR)))
			putchar('_');
		    else
			putchar(' ');
		}
	    }
	}
	putchar('\n');
    }
}

---
Merlyn LeRoy
Technical Details
Message-ID: <1992Aug10.185642.14629@digibd.com>
Path: arc1-ca.pugleaf.net!sparky!uunet!digibd!merlyn
References: <1992Aug5.202648.12058@ccu1.aukuni.ac.nz> <bsko27.6wl@wang.com> <1992Aug7.002015.7250@ccu1.aukuni.ac.nz>

Show Full Headers
Complete Article Headers
Newsgroups: rec.games.programmer
Path: arc1-ca.pugleaf.net!sparky!uunet!digibd!merlyn
From: merlyn@digibd.com (Merlyn LeRoy)
Subject: Re: Maze generating algorithm (here's one)
Organization: DigiBoard Incorporated, Eden Prairie, MN
Date: Mon, 10 Aug 1992 18:56:42 GMT
Message-ID: <1992Aug10.185642.14629@digibd.com>
References: <1992Aug5.202648.12058@ccu1.aukuni.ac.nz> <bsko27.6wl@wang.com> <1992Aug7.002015.7250@ccu1.aukuni.ac.nz>
Lines: 378