xanthian@zorch.SF-Bay.ORG (Kent Paul Dolan) (04/18/91)
Archive-name: townmaze/part02 #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of archive 2 (of 4)." # Contents: connectst.c getargs.c makeunused.c townmaze.h townmaze.lmk # townproto.h townuser.doc # Wrapped by xanthian@zorch on Wed Apr 17 20:34:40 1991 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'connectst.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'connectst.c'\" else echo shar: Extracting \"'connectst.c'\" \(4740 characters\) sed "s/^X//" >'connectst.c' <<'END_OF_FILE' X/* X** connectst.c Copyright 1991 Kent Paul Dolan, X** Mountain View, CA, USA 94039-0755 X** X** Written to satisfy an inquiry on USENet's rec.games.programmer newsgroup. X** May be freely used or modified in any non-commercial work. Copyrighted X** only to prevent patenting by someone else. X*/ X X#include <stdio.h> X#include "townmaze.h" X#include "townproto.h" X X#ifdef __STDC__ Xvoid connectstreets() X#else Xint connectstreets() X#endif X{ X int targetcell; X int livewalk, i; X int deadwalk, lastdead, j, k; X int cheapdir; X int nhbrid; X X/* X** Sanity check; make sure we don't go spinning off with no work possible. X*/ X X if (streetnumct < 1) X { X fprintf(stderr,"No streets seeded! Oops! Logic bomb!\n"); X freespace(); X exit(1); X } X X/* X** Three phase maneuver; phase 1, try to connect streets by using live X** cells to turn into street cells. X*/ X X#if PROGRESS X fprintf(stderr,"Streets 1 "); X#endif X X X while((streetnumct > 1) && (livect > 0)) X { X targetcell = RANDOM()%livect; X livewalk = live; X for (i = 0; i < (targetcell - 1); i++) X if (livewalk == NOPOINTER) X { X fprintf(stderr,"live list too short in connectstreets\n"); X showdebugmaze(); X freespace(); X exit(1); X } X else X { X livewalk = statlist[livewalk].next; X } X/* X** Since this is a live cell, it is supposed to have a street cell X** neighbor; find one and adopt its street number. If directions X** are implemented, then this has to be expanded to pick a random X** neighbor street fairly and adopt its number and direction. X** [Done in makestreet(), instead, by the "-1" direction parameter..] X*/ X for (nhbrid = 0; nhbrid < 4; nhbrid++) X if (nhbrexists(livewalk,nhbrid)) X if (statlist[nhbris(livewalk,nhbrid)].status == STREET) X { X makestreet(livewalk, X statlist[nhbris(livewalk,nhbrid)].streetnum,-1); X break; X } X } X X/* X** Phase 2: try for a cheap connect by only using dead cells between streets X** with different streetnums; this should get some more streets connected, X** without turning the whole map into streets. X*/ X X if ((streetnumct > 1) && (deadct > 0)) X { X X#if PROGRESS X fprintf(stderr,"Streets 2 "); X#endif X X deadwalk = dead; X for (i = 0; i < deadct; i++) X { X if (deadwalk == NOPOINTER) break; X if (streetnumct <= 1) break; X lastdead = deadwalk; X deadwalk = statlist[deadwalk].next; X if (interiorcell(lastdead)) X { X for (j = 0; j < 4; j++) X if (nhbrexists(lastdead,j)) X for (k = 0; k < 4; k++) X { X if (j == k) continue; X if (nhbrexists(lastdead,k)) X/* X** The reason this loop doesn't keep trying to make a street out of the X** chosen cell after it has done so once is that makestreet() causes X** all the adjacent streets to be merged and have the same street number, X** so that the next if always fails after the first success. It can thus X** safely be let run to completion. X*/ X if ( (statlist[nhbris(lastdead,j)].status == STREET) X && (statlist[nhbris(lastdead,k)].status == STREET) X && (statlist[nhbris(lastdead,j)].streetnum X != statlist[nhbris(lastdead,k)].streetnum) X ) X { X cheapdir = ((j+2)%4); X if (statlist[nhbris(lastdead,k)].streetdir == ((k+2)%4)) X cheapdir = ((k+2)%4); X makestreet(lastdead,statlist[nhbris(lastdead,j)].streetnum, X cheapdir); X } X } X } X X } X } X X/* X** Phase 3: when out of luck, use brute force (haven't ever seen this X** required, but can't prove it isn't).. X*/ X X#if PROGRESS X if (streetnumct > 1) fprintf(stderr,"Streets 3 "); X#endif X X while((streetnumct > 1) && (deadct > 0)) X { X targetcell = RANDOM()%deadct; X deadwalk = dead; X for (i = 0; i < (targetcell - 1); i++) X if (deadwalk == NOPOINTER) X { X fprintf(stderr,"dead list too short in connectstreets\n"); X showdebugmaze(); X freespace(); X exit(1); X } X else X { X deadwalk = statlist[deadwalk].next; X } X/* X** Since this is a dead cell, it is necessary to check that it is an interior X** one. This should again be enhanced when directions are installed. X*/ X if (interiorcell(deadwalk)) X { X for (nhbrid = 0; nhbrid < 4; nhbrid++) X if (nhbrexists(deadwalk,nhbrid)) X if (statlist[nhbris(deadwalk,nhbrid)].status == STREET) X { X makestreet(deadwalk, X statlist[nhbris(deadwalk,nhbrid)].streetnum,-1); X break; X } X } X } X X} END_OF_FILE if test 4740 -ne `wc -c <'connectst.c'`; then echo shar: \"'connectst.c'\" unpacked with wrong size! fi # end of 'connectst.c' fi if test -f 'getargs.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'getargs.c'\" else echo shar: Extracting \"'getargs.c'\" \(2964 characters\) sed "s/^X//" >'getargs.c' <<'END_OF_FILE' X/* X** getargs.c Copyright 1991 Kent Paul Dolan, X** Mountain View, CA, USA 94039-0755 X** X** Written to satisfy an inquiry on USENet's rec.games.programmer newsgroup. X** May be freely used or modified in any non-commercial work. Copyrighted X** only to prevent patenting by someone else. X*/ X X X#include <stdio.h> X#include "townmaze.h" X#include "townproto.h" X X X#ifdef __STDC__ Xvoid getargs(int argc,char *argv[]) X#else Xint getargs(argc,argv) X int argc; X char *argv[]; X#endif X{ X int i; X X#if PROGRESS X fprintf(stderr,"Get arguments "); X#endif X X if (argc > 1) X { X if ((argc%2) != 1) X { X usage(); X exit(1); X } X i = 1; X while (i < argc) X { X if ((*argv[i]) != '-') X { X usage(); X exit(1); X } X switch (*(argv[i]+1)) X { X case 'h': X if (sscanf(argv[i+1],"%d",&mazeheight) == EOF) X { X usage(); X exit(1); X } X break; X X case 'w': X if (sscanf(argv[i+1],"%d",&mazewidth) == EOF) X { X usage(); X exit(1); X } X break; X X case 'r': X if (sscanf(argv[i+1],"%ld",&randomseed) == EOF) X { X usage(); X exit(1); X } X SEEDRANDOM(randomseed); /* override clock seed in main() */ X break; X X case 'g': X if (sscanf(argv[i+1],"%d",&mazegates) == EOF) X { X usage(); X exit(1); X } X break; X X case 'l': X if (sscanf(argv[i+1],"%d",&leftgates) == EOF) X { X usage(); X exit(1); X } X break; X X case 'c': X if (sscanf(argv[i+1],"%d",&mazecourts) == EOF) X { X usage(); X exit(1); X } X break; X X case 'u': X if (sscanf(argv[i+1],"%d",&mazeunused) == EOF) X { X usage(); X exit(1); X } X break; X X case 's': X if (sscanf(argv[i+1],"%d",&mazestraightness) == EOF) X { X usage(); X exit(1); X } X break; X X default: X usage(); X exit(1); X } X i += 2; X } X } X if ( ((mazewidth%2) != 1) X || ((mazeheight%2) != 1) X || (mazewidth < 11) X || (mazeheight < 11) X || (mazegates < 0) X || (mazegates > (2*((mazeheight - 6)/7) + 2*((mazewidth- 6)/7))) X || (leftgates < 0) X || (leftgates > mazegates) X || (mazecourts < 0) X || (mazecourts > (((mazeheight - 5)/6)*((mazewidth - 5)/6))) X || ((mazecourts + mazegates) < 1) X || (mazeunused > (((mazeheight - 1)/14)*((mazewidth - 1)/14))) X || (mazestraightness < 0) X || (mazestraightness > 998) X ) X { X usage(); X exit(1); X } X listsize = ((mazeheight - 1)/2)*((mazewidth - 1)/2); X X#if HEADER X fprintf(stdout, X "ht %d wd %d gates %d left %d courts %d unused %d straight %d seed %ld\n", X mazeheight,mazewidth,mazegates,leftgates,mazecourts,mazeunused, X mazestraightness,randomseed); X#endif X return; X} END_OF_FILE if test 2964 -ne `wc -c <'getargs.c'`; then echo shar: \"'getargs.c'\" unpacked with wrong size! fi # end of 'getargs.c' fi if test -f 'makeunused.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'makeunused.c'\" else echo shar: Extracting \"'makeunused.c'\" \(8699 characters\) sed "s/^X//" >'makeunused.c' <<'END_OF_FILE' X/* X** makeunused.c Copyright 1991 Kent Paul Dolan, X** Mountain View, CA, USA 94039-0755 X** X** Written to satisfy an inquiry on USENet's rec.games.programmer newsgroup. X** May be freely used or modified in any non-commercial work. Copyrighted X** only to prevent patenting by someone else. X*/ X X#include <stdio.h> X#include "townmaze.h" X#include "townproto.h" X X#ifdef __STDC__ Xvoid makeunused() X#else Xint makeunused() X#endif X{ X X int totalcells; X int chosencell; X int tries; X int i; X int mazei, mazej; X/* X** Pepper unused cells around the city interior; keep them apart for X** algorithmic robustness and connectivity reasons. X*/ X X#if PROGRESS X fprintf(stderr,"Unused "); X#endif X X totalcells = ((mazeheight-1)/2 * (mazewidth-1)/2); X X for (i = 0; i < mazeunused; i++) X { X X/* fprintf(stderr,"Unused %d\n",i); */ X X/* X** Set up to prevent infinite loop from unforseen geometry problems. X*/ X X tries = 0; X X/* X** Keep looking until a candidate cell is found for this ith unused cell. X*/ X do X { X /* not perfectly fair, but good enough for moderate sized mazes. */ X X chosencell = RANDOM()%totalcells; X X/* fprintf(stderr," chosencell %d\n",chosencell); */ X X tries++; X X } while X ( (tries <= MAXTRIES) X && ( /* To avoid locking in an isolated room, check all 49 cells */ X /* centered on this cell, the hard way: no loop, no direct */ X /* index to the cells. Goal is to be able to run a street */ X /* on all four sides of the 3x3 cell array centered at this */ X /* cell. */ X X /* First verify cell and immediate neighbors two out all */ X /* have all their neighbors; if not, we're too close to a */ X /* border. */ X X (interiorcell(chosencell) != (1==1)) X X || (interiorcell(nhbris(chosencell,0)) != (1==1)) X || (interiorcell(nhbris(nhbris(chosencell,0),0)) != (1==1)) X || (interiorcell(nhbris(chosencell,1)) != (1==1)) X || (interiorcell(nhbris(nhbris(chosencell,1),1)) != (1==1)) X || (interiorcell(nhbris(chosencell,2)) != (1==1)) X || (interiorcell(nhbris(nhbris(chosencell,2),2)) != (1==1)) X || (interiorcell(nhbris(chosencell,3)) != (1==1)) X || (interiorcell(nhbris(nhbris(chosencell,3),3)) != (1==1)) X X /* Now check all 49 cells for ISOLATED status -- yeech! */ X X /* check the chosen cell */ X || (statlist[chosencell].status != ISOLATED) X X /* check to the north/up */ X || (statlist[nhbris(chosencell,0)].status != ISOLATED) X || (statlist[nhbris(nhbris(chosencell,0),0)].status != ISOLATED) X || (statlist[nhbris(nhbris(nhbris(chosencell, X 0),0),1)].status != ISOLATED) X || (statlist[nhbris(nhbris(nhbris(chosencell, X 0),0),3)].status != ISOLATED) X || (statlist[nhbris(nhbris(nhbris(nhbris(chosencell, X 0),0),3),3)].status != ISOLATED) X || (statlist[nhbris(nhbris(nhbris(chosencell, X 0),0),0)].status != ISOLATED) X || (statlist[nhbris(nhbris(nhbris(nhbris(chosencell, X 0),0),0),1)].status != ISOLATED) X || (statlist[nhbris(nhbris(nhbris(nhbris(nhbris(chosencell, X 0),0),0),1),1)].status != ISOLATED) X || (statlist[nhbris(nhbris(nhbris(nhbris(chosencell, X 0),0),0),3)].status != ISOLATED) X || (statlist[nhbris(nhbris(nhbris(nhbris(nhbris(chosencell, X 0),0),0),3),3)].status != ISOLATED) X || (statlist[nhbris(nhbris(nhbris(nhbris(nhbris(nhbris(chosencell, X 0),0),0),3),3),3)].status != ISOLATED) X || (statlist[nhbris(nhbris(chosencell,0),3)].status != ISOLATED) X X /* check to the east/right */ X || (statlist[nhbris(chosencell,1)].status != ISOLATED) X || (statlist[nhbris(nhbris(chosencell,1),0)].status != ISOLATED) X || (statlist[nhbris(nhbris(chosencell,1),1)].status != ISOLATED) X || (statlist[nhbris(nhbris(nhbris(chosencell, X 1),1),2)].status != ISOLATED) X || (statlist[nhbris(nhbris(nhbris(chosencell, X 1),1),0)].status != ISOLATED) X || (statlist[nhbris(nhbris(nhbris(nhbris(chosencell, X 1),1),0),0)].status != ISOLATED) X || (statlist[nhbris(nhbris(nhbris(chosencell, X 1),1),1)].status != ISOLATED) X || (statlist[nhbris(nhbris(nhbris(nhbris(chosencell, X 1),1),1),2)].status != ISOLATED) X || (statlist[nhbris(nhbris(nhbris(nhbris(nhbris(chosencell, X 1),1),1),2),2)].status != ISOLATED) X || (statlist[nhbris(nhbris(nhbris(nhbris(chosencell, X 1),1),1),0)].status != ISOLATED) X || (statlist[nhbris(nhbris(nhbris(nhbris(nhbris(chosencell, X 1),1),1),0),0)].status != ISOLATED) X || (statlist[nhbris(nhbris(nhbris(nhbris(nhbris(nhbris(chosencell, X 1),1),1),0),0),0)].status != ISOLATED) X X /* check to the south/down */ X || (statlist[nhbris(chosencell,2)].status != ISOLATED) X || (statlist[nhbris(nhbris(chosencell,2),1)].status != ISOLATED) X || (statlist[nhbris(nhbris(chosencell,2),2)].status != ISOLATED) X || (statlist[nhbris(nhbris(nhbris(chosencell, X 2),2),3)].status != ISOLATED) X || (statlist[nhbris(nhbris(nhbris(chosencell, X 2),2),1)].status != ISOLATED) X || (statlist[nhbris(nhbris(nhbris(nhbris(chosencell, X 2),2),1),1)].status != ISOLATED) X || (statlist[nhbris(nhbris(nhbris(chosencell, X 2),2),2)].status != ISOLATED) X || (statlist[nhbris(nhbris(nhbris(nhbris(chosencell, X 2),2),2),3)].status != ISOLATED) X || (statlist[nhbris(nhbris(nhbris(nhbris(nhbris(chosencell, X 2),2),2),3),3)].status != ISOLATED) X || (statlist[nhbris(nhbris(nhbris(nhbris(chosencell, X 2),2),2),1)].status != ISOLATED) X || (statlist[nhbris(nhbris(nhbris(nhbris(nhbris(chosencell, X 2),2),2),1),1)].status != ISOLATED) X || (statlist[nhbris(nhbris(nhbris(nhbris(nhbris(nhbris(chosencell, X 2),2),2),1),1),1)].status != ISOLATED) X X /* check to the west/left */ X || (statlist[nhbris(chosencell,3)].status != ISOLATED) X || (statlist[nhbris(nhbris(chosencell,3),2)].status != ISOLATED) X || (statlist[nhbris(nhbris(chosencell,3),3)].status != ISOLATED) X || (statlist[nhbris(nhbris(nhbris(chosencell, X 3),3),0)].status != ISOLATED) X || (statlist[nhbris(nhbris(nhbris(chosencell, X 3),3),2)].status != ISOLATED) X || (statlist[nhbris(nhbris(nhbris(nhbris(chosencell, X 3),3),2),2)].status != ISOLATED) X || (statlist[nhbris(nhbris(nhbris(chosencell, X 3),3),3)].status != ISOLATED) X || (statlist[nhbris(nhbris(nhbris(nhbris(chosencell, X 3),3),3),0)].status != ISOLATED) X || (statlist[nhbris(nhbris(nhbris(nhbris(nhbris(chosencell, X 3),3),3),0),0)].status != ISOLATED) X || (statlist[nhbris(nhbris(nhbris(nhbris(chosencell, X 3),3),3),2)].status != ISOLATED) X || (statlist[nhbris(nhbris(nhbris(nhbris(nhbris(chosencell, X 3),3),3),2),2)].status != ISOLATED) X || (statlist[nhbris(nhbris(nhbris(nhbris(nhbris(nhbris(chosencell, X 3),3),3),2),2),2)].status != ISOLATED) X ) X ); X X if (tries <= MAXTRIES) X { X movefromto(&isolated,&isolatedct,&unused,&unusedct,UNUSED,chosencell); X mazei = (chosencell/((mazewidth-1)/2)); X mazej = (chosencell%((mazewidth-1)/2)); X mazei = (2*mazei) + 1; X mazej = (2*mazej) + 1; X cmaze[mazei][mazej] = WALL; X/* X** Tried moving neighbors of unused cells to the DEAD list here; big mistake; X** ended up with isolated dead cells; let the later routines do it. X*/ X } X } X return; X} END_OF_FILE if test 8699 -ne `wc -c <'makeunused.c'`; then echo shar: \"'makeunused.c'\" unpacked with wrong size! fi # end of 'makeunused.c' fi if test -f 'townmaze.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'townmaze.h'\" else echo shar: Extracting \"'townmaze.h'\" \(4580 characters\) sed "s/^X//" >'townmaze.h' <<'END_OF_FILE' X/* X** townmaze.h Copyright 1991 Kent Paul Dolan, X** Mountain View, CA, USA 94039-0755 X** X** Written to satisfy an inquiry on USENet's rec.games.programmer newsgroup. X** May be freely used or modified in any non-commercial work. Copyrighted X** only to prevent patenting by someone else. X*/ X X/* X** Avoid infinite loops in several routines. X*/ X X#define MAXTRIES 5000 X X/* X** Define PROGRESS as 1 to see a "walking progress" line of routines X** announcing themselves as they run, 0 otherwise. X** X** Define SHOWSTART as 1 to see a debug maze that shows the situation X** after the gates and courts are added but before the streets are X** otherwise built; 0 to skip it. X** X** Define SHOWEND as 1 to see a debug maze that shows the situation X** after the maze is completed; 0 to skip it; X** X** Define HEADER as 1 to see the parameter values echoed back just above X** the maze, 0 to suppress the header. X** X** Define RAND48 in the makefile to use the srand48() and lrand48() X** functions instead of the srandom() and random() functions. X*/ X X#define PROGRESS 0 X#define SHOWSTART 0 X#define SHOWEND 0 X#define HEADER 1 X X#ifdef RAND48 X#include <math.h> X#define RANDOM lrand48 X#define SEEDRANDOM srand48 X#else X#define RANDOM random X#define SEEDRANDOM srandom X#endif X X/* X** Control for defintion (allocation) of globals in main only, X** declaration only elsewhere. X*/ X X#ifdef MAINLINE X#define SIDETRACK X#else X#define SIDETRACK extern X#endif X X/* X** X** The maze is sized in terms of X cells by Y cells, and of X charcters X** by Y characters; there are 2*cells+1 characters in each maze X** direction. For purposes of screen display, the horizontal direction X** is X and the vertical direction is Y, and the origin is at the top X** left, with Y positive going down and X positive going right. X** X** For various reasons in the code, a maze must have at least 5 cells X** per side (which will be a very boring maze indeed. Corner cells are X** not used, to ease the design problem. X** X** The primary maze determinant is its size in characters; this X** must be odd in both dimensions. X** X*/ X X/* X** P A R A M E T E R S X** X** -h mazeheight -- Y size in characters X** -w mazewidth -- X size in characters X** listsize -- number of cells in the cell array; computed global X** -r randomseed -- use to get the same maze again; replaces clock X** seed; seed used is reported in the header for use X** in a repeat run. X** -g mazegates -- number of streets to start at the city wall X** -l leftgates -- number of them to leave doors leading outside on X** -c mazecourts -- number of streets to start away from the city wall X** -u mazeunused -- number of cells to leave unused in the maze X** -s mazestraightness -- times per thousand to retry on average before X** accepting a random cell that makes a street turn X** rather than go straight X** X** All parameters have default values. Listsize is computed when mazeheight X** and mazewidth are known. X** X*/ X X#ifdef MAINLINE Xint mazeheight = 23; Xint mazewidth = 77; Xint listsize; Xlong randomseed; Xint mazegates = 4; Xint leftgates = 2; Xint mazecourts = 0; Xint mazeunused = 0; Xint mazestraightness = 750; X#else Xextern int mazeheight; Xextern int mazewidth; Xextern int listsize; Xextern long randomseed; Xextern int mazegates; Xextern int leftgates; Xextern int mazecourts; Xextern int mazeunused; Xextern int mazestraightness; X#endif X X/* X** T Y P E D E F S X*/ X Xtypedef struct dlelem X{ X int next; X int prev; X int status; X int streetnum; X int streetdir; X} DLENODE; X X/* X** M A Z E A R R A Y S X*/ X X/* X** The cell list used for storing cell status information. Although the X** maze is 2D, this list is kept 1D to make it simple to use list array X** indices as link list "pointers". X*/ X XSIDETRACK DLENODE *statlist; XSIDETRACK int isolated, street, live, dead, unused; XSIDETRACK int isolatedct,streetct,livect,deadct, unusedct; XSIDETRACK int streetnumct; X X/* X** The maze used for display. X*/ X XSIDETRACK char **cmaze; X X/* X** P R I N T I N G S Y M B O L S X*/ X X/* X** maze drawing elements for ascii screen presentation X*/ X X#define WALL '#' X#define VDOOR '|' X#define HDOOR '-' X#define BLANK ' ' X X/* X** D E F I N E D C O N S T A N T S X*/ X X/* X** status of maze locations X*/ X X#define ISOLATED 1 X#define LIVE 2 X#define DEAD 3 X#define STREET 4 X#define UNUSED 5 X X/* X** Bogus null pointer for indices used as pointers, since zero is valid. X*/ X X#define NOPOINTER -1 END_OF_FILE if test 4580 -ne `wc -c <'townmaze.h'`; then echo shar: \"'townmaze.h'\" unpacked with wrong size! fi # end of 'townmaze.h' fi if test -f 'townmaze.lmk' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'townmaze.lmk'\" else echo shar: Extracting \"'townmaze.lmk'\" \(3734 characters\) sed "s/^X//" >'townmaze.lmk' <<'END_OF_FILE' X# townmake.lmk Copyright 1991 by Kent Paul Dolan, X# Mountain View, CA, USA, 94039-0755 X# May be freely used in any non-commercial venture. X# Copyrighted only to prevent patenting of the ideas X# contained herein by others. X# X# BSD 4.3 Unix make file for use with "make -f townmaze.lmk" command X# Amiga Lattice C 5.05 make file for use with "lmk -f townmzae.lmk" command; X# (after minor edits) -- needs townmaze.with for blink command. X# X# C files: X# X# cleanupmap.c X# closedoors.c X# closegates.c X# connectst.c X# filllist.c X# fillmaze.c X# finishalleys.c X# freespace.c X# getargs.c X# interiorcell.c X# makecourts.c X# makegates.c X# makestreet.c X# makespace.c X# makeunused.c X# movefromto.c X# nhbrexists.c X# nhbris.c X# showdbmaze.c X# showlistdet.c X# showlistsum.c X# showmaze.c X# townmain.c X# usage.c X# X# townmaze.h X# townproto.h X# X# pick a compile command X# X# Amiga Lattice C 5.05: X# X#CC = lc -dRAND48 X# X# or BSD 4.3 Unix oldstyle cc: X# XCC = cc -c X# X# The link command is too complex to just define up here; it will need X# changes in the body of the makefile where "townmaze" is created. X# X XHEADERS = townmaze.h \ X townproto.h X XSOURCES = cleanupmap.c \ X closedoors.c \ X closegates.c \ X connectst.c \ X filllist.c \ X fillmaze.c \ X finishalleys.c \ X freespace.c \ X getargs.c \ X interiorcell.c \ X makecourts.c \ X makegates.c \ X makestreet.c \ X makespace.c \ X makeunused.c \ X movefromto.c \ X nhbrexists.c \ X nhbris.c \ X showdbmaze.c \ X showlistdet.c \ X showlistsum.c \ X showmaze.c \ X townmain.c \ X usage.c X XOBJECTS = cleanupmap.o \ X closedoors.o \ X closegates.o \ X connectst.o \ X filllist.o \ X fillmaze.o \ X finishalleys.o \ X freespace.o \ X getargs.o \ X interiorcell.o \ X makegates.o \ X makecourts.o \ X makespace.o \ X makestreet.o \ X makeunused.o \ X movefromto.o \ X nhbrexists.o \ X nhbris.o \ X showdbmaze.o \ X showlistdet.o \ X showlistsum.o \ X showmaze.o \ X townmain.o \ X usage.o X X# X# Pick a link command X# X# Amiga Lattice C 5.05: X# X X#townmaze: $(OBJECTS) X# blink with townmaze.with X X# X# or BSD 4.3 Unix old style cc: X# X Xtownmaze: $(OBJECTS) X cc -o townmaze ${OBJECTS} X Xcleanupmap.o: $(HEADERS) cleanupmap.c X $(CC) cleanupmap.c X Xclosedoors.o: $(HEADERS) closedoors.c X $(CC) closedoors.c X Xclosegates.o: $(HEADERS) closegates.c X $(CC) closegates.c X Xconnectst.o: $(HEADERS) connectst.c X $(CC) connectst.c X Xfilllist.o: $(HEADERS) filllist.c X $(CC) filllist.c X Xfillmaze.o: $(HEADERS) fillmaze.c X $(CC) fillmaze.c X Xfinishalleys.o: $(HEADERS) finishalleys.c X $(CC) finishalleys.c X Xfreespace.o: $(HEADERS) freespace.c X $(CC) freespace.c X Xgetargs.o: $(HEADERS) getargs.c X $(CC) getargs.c X Xinteriorcell.o: $(HEADERS) interiorcell.c X $(CC) interiorcell.c X Xmakecourts.o: $(HEADERS) makecourts.c X $(CC) makecourts.c X Xmakegates.o: $(HEADERS) makegates.c X $(CC) makegates.c X Xmakespace.o: $(HEADERS) makespace.c X $(CC) makespace.c X Xmakestreet.o: $(HEADERS) makestreet.c X $(CC) makestreet.c X Xmakeunused.o: $(HEADERS) makeunused.c X $(CC) makeunused.c X Xmovefromto.o: $(HEADERS) movefromto.c X $(CC) movefromto.c X Xnhbrexists.o: $(HEADERS) nhbrexists.c X $(CC) nhbrexists.c X Xnhbris.o: $(HEADERS) nhbris.c X $(CC) nhbris.c X Xshowdbmaze.o: $(HEADERS) showdbmaze.c X $(CC) showdbmaze.c X Xshowlistdet.o: $(HEADERS) showlistdet.c X $(CC) showlistdet.c X Xshowlistsum.o: $(HEADERS) showlistsum.c X $(CC) showlistsum.c X Xshowmaze.o: $(HEADERS) showmaze.c X $(CC) showmaze.c X Xtownmain.o: $(HEADERS) townmain.c X $(CC) townmain.c X Xusage.o: $(HEADERS) usage.c X $(CC) usage.c END_OF_FILE if test 3734 -ne `wc -c <'townmaze.lmk'`; then echo shar: \"'townmaze.lmk'\" unpacked with wrong size! fi # end of 'townmaze.lmk' fi if test -f 'townproto.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'townproto.h'\" else echo shar: Extracting \"'townproto.h'\" \(3198 characters\) sed "s/^X//" >'townproto.h' <<'END_OF_FILE' X/* X** townproto.h Copyright 1991 Kent Paul Dolan, X** Mountain View, CA, USA 94039-0755 X** X** Written to satisfy an inquiry on USENet's rec.games.programmer newsgroup. X** May be freely used or modified in any non-commercial work. Copyrighted X** only to prevent patenting by someone else. X*/ X X/* X** This file contains the prototypes for the functions in townmaze; X** it is quite a mess since the program was developed in both an X** ANSI C prototyping environment (Lattice C 5.05) on the Amiga X** under AmigaOS, and in a BSD 4.3 Unix pre-ANSI C "cc" environment X** without prototypes. X*/ X X/* functions in cleanupmap.c */ X X#ifdef __STDC__ Xvoid cleanupmap(); X#else Xint cleanupmap(); X#endif X X/* functions in closedoors.c */ X X#ifdef __STDC__ Xvoid closedoors(); X#else Xint closedoors(); X#endif X X/* functions in closegates.c */ X X#ifdef __STDC__ Xvoid closegates(); X#else Xint closegates(); X#endif X X/* functions in connectst.c */ X X#ifdef __STDC__ Xvoid connectstreets(); X#else Xint connectstreets(); X#endif X X/* functions in filllist.c */ X X#ifdef __STDC__ Xvoid filllist(); X#else Xint filllist(); X#endif X X/* functions in fillmaze.c */ X X#ifdef __STDC__ Xvoid fillmaze(); X#else Xint fillmaze(); X#endif X X/* functions in finishalleys.c */ X X#ifdef __STDC__ Xvoid finishalleys(); X#else Xint finishalleys(); X#endif X X/* functions in freespace.c */ X X#ifdef __STDC__ Xvoid freespace(); X#else Xint freespace(); X#endif X X/* functions in getargs.c */ X X#ifdef __STDC__ Xvoid getargs(int argc,char *argv[]); X#else Xint getargs(); X#endif X X/* functions in interiorcell.c */ X X#ifdef __STDC__ Xint interiorcell(int cellid); X#else Xint interiorcell(); X#endif X X/* functions in makecourts.c */ X X#ifdef __STDC__ Xvoid makecourts(); X#else Xint makecourts(); X#endif X X/* functions in makegates.c */ X X#ifdef __STDC__ Xvoid makegates(); X#else Xint makegates(); X#endif X X/* functions in makespace.c */ X X#ifdef __STDC__ Xvoid makespace(); X#else Xint makespace(); X#endif X X/* functions in makestreet.c */ X X#ifdef __STDC__ Xint makestreet(int chosencell,int streetid,int streetpoints); X#else Xint makestreet(); X#endif X X/* functions in makeunused.c */ X X#ifdef __STDC__ Xvoid makeunused(); X#else Xint makeunused(); X#endif X X/* functions in movefromto.c */ X X#ifdef __STDC__ Xvoid movefromto(int *fromlist,int *fromcount,int *tolist,int *tocount, X int newstat,int cellnum); X#else Xint movefromto(); X#endif X X/* functions in nhbrexists.c */ X X#ifdef __STDC__ Xint nhbrexists(int cellid,int nhbrid); X#else Xint nhbrexists(); X#endif X X/* functions in nhbris.c */ X X#ifdef __STDC__ Xint nhbris(int cellid,int nhbrid); X#else Xint nhbris(); X#endif X X/* functions in showdbmaze.c */ X X#ifdef __STDC__ Xvoid showdebugmaze(); X#else Xint showdebugmaze(); X#endif X X/* functions in showlistdet.c */ X X#ifdef __STDC__ Xvoid showlistdetail(); X#else Xint showlistdetail(); X#endif X X/* functions in showlistsum.c */ X X#ifdef __STDC__ Xvoid showlistsummary(); X#else Xint showlistsummary(); X#endif X X/* functions in showmaze.c */ X X#ifdef __STDC__ Xvoid showmaze(); X#else Xint showmaze(); X#endif X X/* functions in townmain.c */ X X#ifdef __STDC__ Xvoid main(int argc,char *argv[]); X#else Xint main(); X#endif X X/* functions in usage.c */ X X#ifdef __STDC__ Xvoid usage(); X#else Xint usage(); X#endif X END_OF_FILE if test 3198 -ne `wc -c <'townproto.h'`; then echo shar: \"'townproto.h'\" unpacked with wrong size! fi # end of 'townproto.h' fi if test -f 'townuser.doc' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'townuser.doc'\" else echo shar: Extracting \"'townuser.doc'\" \(8428 characters\) sed "s/^X//" >'townuser.doc' <<'END_OF_FILE' XWelcome, as it were, to townmaze. X XJust typing "townmaze" at the command line will do an example maze for Xyou, once the program has been compiled and installed (see README). X XTyping "townmaze help" at the command line will get you a "usage" Xdisplay about 22 lines high, describing each of the parameters and Xtheir limits. X XYou might want to try both of these before reading the rest of this Xdocument. X XWhat you see in a townmaze: X XIt should be obvious, but the symbols in the townmaze output are "#" Xfor walls or solid rock, "-" or "|" for horizontal or vertical doors, Xand " " (blank), for streets and room interiors. X XThis program is not, in essence, a game, but instead a tool to use in Xmaking games. What it does is to lay out a city after the fashion of Xthe top level of Bard's Tale I. You can then use this city layout in Xeither a paper and pencil dungeon crawling game, or as part the design Xof a 3D computer dungeon crawling game. You can even (see Xtownpgmr.doc) install this code into such a game to create city maze Xlayouts on demand. X XTownmaze has a rich variety of parameters, to let you vary your city Xin size, shape, building density, and complexity. The parameters are Xentered at the command line in standard Unix fashion, as "dash, flag Xletter, space, value" sets, like X X townmaze -h 23 -w 77 -g 4 -l 2 -c 0 -u 0 -s 750 -r 123456789 X XExcept for the "r" parameter, the values shown are the defaults, and Xif the parameter and its value are omitted from the command line, the Xabove defaults are used. The exception "r", the random number seed, Xis read off the system clock unless it is overridden by a command line Xparameter. X XHere is what the parameters mean. X X X P A R A M E T E R S X X -h mazeheight -- vertical size of the maze, in characters X X -w mazewidth -- horizontal size of the maze, in characters X X -g mazegates -- number of streets to start at the city wall X X -l leftgates -- number of the gates to leave doors leading X outside from the city (the rest are turned X back into city wall) X X -c mazecourts -- number of streets to start away from the city X wall in the city interior X X -u mazeunused -- number of cells to leave unused (solid rock) X in the maze; these cells will be inaccessible X X -s mazestraightness -- times per thousand to retry on average before X accepting a random cell that makes a street X turn rather than go straight X X -r randomseed -- use to get the same maze again; replaces clock X seed; seed used is reported in the header for use X in a repeat run. X XThe maze is normally written to the screen (more exactly, to "standard Xoutput"), and benefits a lot from screens that can show more than 25 Xlines and more than 80 characters; the more room townmaze has to work, Xthe better job it can do. The maze is sized in characters, but it Xreally exists in cells, it takes several characters to draw a single Xcell. In the Bard's Tale I game, the main level was 32 by 32 cells. XIn townmaze, that is a maze 65 by 65 characters, since it takes two Xrows of characters to make each cell, plus one extra row for the last Xwall, each way. X XThus, a really effective way to use townmaze is to capture and print Xits output on paper, to get bigger, more interesting mazes. X XTownmaze will make a maze as big as your computer will provide the Xmemory needed for storing the maze and a corresponding list of cells, Xand should fail gracefully if you ask for a maze bigger than your Xcomputer can hold. X XAs mentioned, townmaze has a rich variety of parameters, and the best Xway to understand what they do is to try them; they interact with one Xanother, so that there is no simple description of what results in the Xmaze as you vary each one, but here's an approximation. X XThe -h and -w parameters just make the maze bigger; that's easy enough. X XTownmaze works by building a maze that is solid room cells with no Xdoors, then changing a few room cells to street cells, then knocking Xout more room cells to make street cells until all the streets are Xconnected and all the room cells have a door. Room cells get a door Xwhen they are adjacent to at least one street cell. X XThe -g parameter tells how many of the starting street cells will be Xon the border of the maze, next to the city wall. To start with, each Xof these cells is given a door which is a gate through the city wall. XLots of these "gate" cells help break up the street that otherwise runs Xall around the perimeter of the city to provide doors to the border Xcells. X XWhen the straightness parameter is very strict, rows of room cells Xoften run from each side of a gate toward the middle of town, like the Xones in Bard's Tale I did. There need not be any gate cells at all, Xin which case your town will have a street that runs all around the Xoutside. Presumably then you would put the biggest treasures and Xnastiest monsters in the middle of town, unlike Bard's tale, which put Xthem near the corners. X XThe -l parameter tells how many of the gates will survive; the rest get Xturned back into city wall. This lets you enjoy the complex border of Xa city with lots of gate cells, without having lots of, or even any, Xreal gates leaving town. X XA town maze must start with at least one street somewhere, so the -c X("courtyard") parameter lets you start streets in the interior of the Xtown, instead of the border. Interesting things happen if you do 1 Xcourtyard and no gates, and also if you do maximums of courtyards and Xgates, and all other combinations. In general, lots of courtyards Xmakes for a less dense, more "gangly" city structure with lots of Xcul de sacs. X XTownmaze with just those parameters tends to create long runs of rooms Xsnaking about the town. To give more elaborate structures, and still Xhave all rooms accessible, it is necessary to leave some cells unused. XThe -u ("unused") parameter tells how many unused cells to allow. The Xlimit is low, because the rule is that a street cannot be adjacent to Xan unused cell, which means unused cells make it hard to connect all Xthe streets together. By forcing at least three cells between unused Xcells, this connectivity is assured, but doing this means only about X2% of the interior cells can be unused cells. Unused cells tend to Xallow room structures with three or four "arms", rather than just Xlinear snaking structures, and give the town a more interesting Xappearance. X XThe most important parameter affecting the appearance of the towns Xdesigned by townmaze is -s, the straightness parameter. It can take Xvalues from 0 (don't worry about straightness) to 998 (try as hard Xas possible to make streets run straight). Townmaze implements this Xstraightness by repeatedly trying a random room to see if it will let Xa street run straight, so straightness has a profound effect on the Xtime it takes townmaze to design a town. A set of parameters that Xallows a town to be drawn in a few seconds with a straightness of 0, Xwill take about the same number of minutes with a straightness of 996, Xfor example. X XNonetheless, the city streets wander around a lot, and knock out lots Xof extra rooms, leading to sparse looking towns, until the highest Xlevels of straightness are used. This isn't all bad, as the empty Xspace is like some of the big open courtyards in Bard's Tale I; you Xcan play with this parameter until you get the appearance you like. X XThe -r parameter allows you to generate the same town maze repeatedly. X XIf the townmaze program is installed with the HEADER definition turned Xon, then above the maze output you will see a line showing the Xparameters for this run, including "seed", typically eight or nine Xdigits. If you feed this seed value back in as the value of the -r Xparameter, you will get the identical maze again. Even without the XHEADER turned on, you can enter your own choices of seed until you Xfind the town maze that suits your needs, then run townmaze again with Xthe same parameters to save the maze to a file, to print it, or, if Xyou install the software in a computer game, to be able to use a level Xover and over without having to store its design explicitly in the Xgame. X XI hope you have fun with my toy. X XCopyright 1991, Kent Paul Dolan, XPO Box 390755, Mountain View, CA, USA, 94039-0755 END_OF_FILE if test 8428 -ne `wc -c <'townuser.doc'`; then echo shar: \"'townuser.doc'\" unpacked with wrong size! fi # end of 'townuser.doc' fi echo shar: End of archive 2 \(of 4\). cp /dev/null ark2isdone MISSING="" for I in 1 2 3 4 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 4 archives. rm -f ark[1-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0