今日の雑記

生きることでいっぱいいっぱい

Rogue ソースその後

昨日のちょっとコメントがあったのもあって、今現在のソースを公開してみる。ちなみにバグありです。<こら
デバッグ中の記述やらなにやらありますが。C プログラマならわかるでしょ?@ほったらかし

#include <stdio.h>

#ifndef FALSE
#define FALSE (0)
#endif
#ifndef TRUE
#define TRUE (1)
#endif

/*
 * Things that appear on the screens
 */
#define PASSAGE ('#')
#define DOOR ('+')
#define FLOOR ('.')
#define PLAYER ('@')
#define TRAP ('^')
#define TRAPDOOR ('>')
#define ARROWTRAP ('{')
#define SLEEPTRAP ('$')
#define BEARTRAP ('}')
#define TELTRAP ('~')
#define DARTTRAP ('`')
#define SECRETDOOR ('&')
#define STAIRS ('%')
#define GOLD ('*')
#define POTION ('!')
#define SCROLL ('?')
#define MAGIC ('$')
#define FOOD (':')
#define WEAPON (')')
#define ARMOR (']')
#define AMULET (',')
#define RING ('=')
#define STICK ('/')
#define SPACE (' ')
#define CALLABLE (-1)

/*
 * Various flag bits
 */
#define ISDARK	(0x0000001)
#define ISCURSED (0x000001)
#define ISBLIND (0x0000001)
#define ISGONE	(0x0000002)
#define ISKNOW  (0x0000002)
#define ISRUN	(0x0000004)
#define ISFOUND (0x0000010)
#define ISINVIS (0x0000020)
#define ISMEAN  (0x0000040)
#define ISGREED (0x0000100)
#define ISBLOCK (0x0000200)
#define ISHELD  (0x0000400)
#define ISHUH   (0x0001000)
#define ISREGEN (0x0002000)
#define CANHUH  (0x0004000)
#define CANSEE  (0x0010000)
#define ISMISL  (0x0020000)
#define ISCANC	(0x0020000)
#define ISMANY  (0x0040000)
#define ISSLOW	(0x0040000)
#define ISHASTE (0x0100000)

/*
 * Maximum number of different things
 */
#define MAXROOMS (9)
//#define MAXROOMS (32)
#define MAXTHINGS (9)
#define MAXOBJ (9)
#define MAXPACK (23)
#define MAXTRAPS (10)
#define	NUMTHINGS (7)	/* number of types of things (scrolls, rings, etc.) */

/*
 * Console size
 */
//#define COLS (640 / 16)
//#define LINES (480 / 16)
#define COLS (80)
#define LINES (28)
//#define COLS (256)
//#define LINES (80)

#define move(y, x)\
{\
	map_x = x;\
	map_y = y;\
}
//	printf("map-xy %d,%d\n", map_x, map_y);\

#define cmov(xy) move((xy).y, (xy).x)

#define ce(a, b) ((a).x == (b).x && (a).y == (b).y)

#define getyx(stdscr, y, x)\
{\
	x = map_x;\
	y = map_y;\
}

#define addch(c)\
{\
	floor_map[map_y][map_x] = c;\
	map_x++;\
}
//	printf("add chr-xy '%c' %d,%d\n", c, map_x, map_y);\

#define mvaddch(y, x, c)\
{\
	map_x = x;\
	map_y = y;\
	floor_map[map_y][map_x] = c;\
	map_x++;\
}
//	printf("add map-xy %d,%d\n", map_x, map_y);\

#define mvinch(y, x) floor_map[y][x]

/*
 * Coordinate data type
 */
typedef struct{
	int x;
	int y;
}COORD;

/*
 * Room structure
 */
typedef struct{
	COORD r_pos;			/* Upper left corner */
	COORD r_max;			/* Size of room */
	COORD r_gold;			/* Where the gold is */
	int r_goldval;			/* How much the gold is worth */
	int r_flags;			/* Info about the room */
	int r_nexits;			/* Number of exits */
	COORD r_exit[4];		/* Where the exits are */
}ROOM;

typedef struct{
	int	conn[MAXROOMS];		/* possible to connect to room i? */
	int	isconn[MAXROOMS];	/* connection been made to room i? */
	int	ingraph;			/* this room in graph already? */
}RDES;

static void do_rooms(void);
static void draw_room(ROOM *rp);
static void horiz(int cnt);
static void vert(int cnt);
static void rnd_pos(ROOM *rp, COORD *cp);
static int rnd_room(void);

static void do_passages(void);
static void conn(int r1, int r2);
static void door(ROOM *rm, COORD *cp);
static void add_pass(void);

static int rnd(int val);

static void disp_dungeon(void);

ROOM rooms[MAXROOMS];

static char floor_map[LINES][COLS + 1];
static int map_x;
static int map_y;

static level;

static RDES rdes[MAXROOMS] = {
	{ { 0, 1, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },
	{ { 1, 0, 1, 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },
	{ { 0, 1, 0, 0, 0, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },
	{ { 1, 0, 0, 0, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },
	{ { 0, 1, 0, 1, 0, 1, 0, 1, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },
	{ { 0, 0, 1, 0, 1, 0, 0, 0, 1 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },
	{ { 0, 0, 0, 1, 0, 0, 0, 1, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },
	{ { 0, 0, 0, 0, 1, 0, 1, 0, 1 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },
	{ { 0, 0, 0, 0, 0, 1, 0, 1, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },
};

int main(int argc, char *argv[])
{
	int i;
	int s;

	level = 1;
//	s = (int)time(NULL);
//	printf("rand %d\n", s);
//	s = 1222095957;	// OK
//	s = 1222095726;	// NG
	s = 1222097302;	// NG
	srand(s);

	do_rooms();
	disp_dungeon();
	do_passages();
	disp_dungeon();

	return 0;
}

void do_rooms(void)
{
	int i, j;
	ROOM *rp;
/*	struct linked_list *item;*/
/*	struct thing *tp;*/
	int left_out;
	COORD top;
	COORD bsze;
	COORD mp;

	/*
	 * bsze is the maximum room size
	 */
	bsze.x = COLS  / 3;
	bsze.y = LINES / 3;

//printf("baze %2d,%2d\n", bsze.x, bsze.y);

	/*
	 * Clear things for a new level
	 */
	for(rp = rooms; rp <= &rooms[MAXROOMS - 1]; rp++){
		rp->r_goldval = rp->r_nexits = rp->r_flags = 0;
	}

	/*
	 * Clear things for a floor map
	 */
	for(i = 0; i < LINES; i++){
		for(j = 0; j < COLS; j++){
			floor_map[i][j] = SPACE;
		}
		floor_map[i][COLS] = 0;
	}

	/*
	 * Put the gone rooms, if any, on the level
	 */
	left_out = rnd(4);
	for(i = 0; i < left_out; i++){
		rooms[rnd_room()].r_flags |= ISGONE;
	}

	/*
	 * dig and populate all the rooms on the level
	 */
	for(i = 0, rp = rooms; i < MAXROOMS; rp++, i++){
		/*
		 * Find upper left corner of box that this room goes in
		 */
		top.x = (i % 3) * bsze.x + 1;
		top.y = (i / 3) * bsze.y;
		if(rp->r_flags & ISGONE){
			/*
			 * Place a gone room.  Make certain that there is a blank line
			 * for passage drawing.
			 */
			do{
				rp->r_pos.x = top.x + rnd(bsze.x - 2) + 1;
				rp->r_pos.y = top.y + rnd(bsze.y - 2) + 1;
				rp->r_max.x = -COLS;
				rp->r_max.y = -LINES;
			}while(!(rp->r_pos.y > 0 && rp->r_pos.y < (LINES - 1)));
//printf("roomA %+2d,%+2d %+2d,%+2d\n", rp->r_pos.x, rp->r_pos.y, rp->r_max.x, rp->r_max.y);
			continue;
		}
#if 0
		if(rnd(10) < (level - 1)){
			rp->r_flags |= ISDARK;
		}
#endif
		/*
		 * Find a place and size for a random room
		 */
		do{
			rp->r_max.x = rnd(bsze.x - 4) + 4;
			rp->r_max.y = rnd(bsze.y - 4) + 4;
			rp->r_pos.x = top.x + rnd(bsze.x - rp->r_max.x);
			rp->r_pos.y = top.y + rnd(bsze.y - rp->r_max.y);
		}while(!(rp->r_pos.y != 0));
//printf("roomB %+2d,%+2d %+2d,%+2d\n", rp->r_pos.x, rp->r_pos.y, rp->r_max.x, rp->r_max.y);
#if 0
		/*
		 * Put the gold in
		 */
		if(rnd(100) < 50 && (!amulet || level >= max_level)){
			rp->r_goldval = GOLDCALC;
			rnd_pos(rp, &rp->r_gold);
			if(roomin(&rp->r_gold) != rp){
				endwin(), abort();
			}
		}
#endif
		draw_room(rp);
#if 0
		/*
		 * Put the monster in
		 */
		if(rnd(100) < (rp->r_goldval > 0 ? 80 : 25)){
			item = new_item(sizeof *tp);
			tp = (struct thing *)ldata(item);
			do{
				rnd_pos(rp, &mp);
			}while(!(mvwinch(stdscr, mp.y, mp.x) == FLOOR));
			new_monster(item, randmonster(FALSE), &mp);
			/*
			 * See if we want to give it a treasure to carry around.
			 */
			if(rnd(100) < monsters[tp->t_type - 'A'].m_carry){
				attach(tp->t_pack, new_thing());
			}
		}
#endif
	}
}

/*
 * Draw a box around a room
 */
void draw_room(ROOM *rp)
{
	int j, k;

	move(rp->r_pos.y, rp->r_pos.x + 1);
	vert(rp->r_max.y - 2);				/* Draw left side */
	move(rp->r_pos.y + rp->r_max.y - 1, rp->r_pos.x);
	horiz(rp->r_max.x);					/* Draw bottom */
	move(rp->r_pos.y, rp->r_pos.x);
	horiz(rp->r_max.x);					/* Draw top */
	vert(rp->r_max.y - 2);				/* Draw right side */

	/*
	 * Put the floor down
	 */
	for(j = 1; j < (rp->r_max.y - 1); j++){
		move(rp->r_pos.y + j, rp->r_pos.x + 1);
		for(k = 1; k < (rp->r_max.x - 1); k++){
			addch(FLOOR);
		}
	}
#if 0
	/*
	 * Put the gold there
	 */
	if(rp->r_goldval){
		mvaddch(rp->r_gold.y, rp->r_gold.x, GOLD);
	}
#endif
}

/*
 * horiz:
 *	draw a horizontal line
 */
void horiz(int cnt)
{
	while(cnt--){
		addch('-');
	}
}

/*
 * vert:
 *	draw a vertical line
 */
void vert(int cnt)
{
	int x, y;

	getyx(stdscr, y, x);
	x--;
	while(cnt--){
		move(++y, x);
		addch('|');
	}
}

/*
 * rnd_pos:
 *	pick a random spot in a room
 */
void rnd_pos(ROOM *rp, COORD *cp)
{
	cp->x = rp->r_pos.x + rnd(rp->r_max.x - 2) + 1;
	cp->y = rp->r_pos.y + rnd(rp->r_max.y - 2) + 1;
}

/*
 * Pick a room that is really there
 */
int rnd_room(void)
{
	int rm;

	do{
		rm = rnd(MAXROOMS);
	}while(rooms[rm].r_flags & ISGONE);

	return rm;
}

/*
 * do_passages:
 *	Draw all the passages on a level.
 */
void do_passages(void)
{
	RDES *r1, *r2;
	int i, j, k = 0;
	int roomcount;

	/*
	 * reinitialize room graph description
	 */
	for(r1 = rdes; r1 <= &rdes[MAXROOMS - 1]; r1++){
		for(j = 0; j < MAXROOMS; j++){
			r1->isconn[j] = FALSE;
		}
		r1->ingraph = FALSE;
	}

	/*
	 * starting with one room, connect it to a random adjacent room and
	 * then pick a new room to start with.
	 */
	roomcount = 1;
	r1 = &rdes[rnd(MAXROOMS)];
	r1->ingraph = TRUE;
	do{
		/*
		 * find a room to connect with
		 */
		j = 0;
		for(i = 0; i < MAXROOMS; i++){
			if(r1->conn[i] && !rdes[i].ingraph && rnd(++j) == 0){
				r2 = &rdes[i];
			}
		}
		/*
		 * if no adjacent rooms are outside the graph, pick a new room
		 * to look from
		 */
		if(j == 0){
			do{
				r1 = &rdes[rnd(MAXROOMS)];
			}while(!(r1->ingraph));
		}else{
			/*
			 * otherwise, connect new room to the graph, and draw a tunnel
			 * to it
			 */
			r2->ingraph = TRUE;
			i = r1 - rdes;
			j = r2 - rdes;
			conn(i, j);
			r1->isconn[j] = TRUE;
			r2->isconn[i] = TRUE;
			roomcount++;
		}
	}while(roomcount < MAXROOMS);

	/*
	 * attempt to add passages to the graph a random number of times so
	 * that there isn't just one unique passage through it.
	 */
	for(roomcount = rnd(5); roomcount > 0; roomcount--){
		r1 = &rdes[rnd(MAXROOMS)];	/* a random room to look from */
		/*
		 * find an adjacent room not already connected
		 */
		j = 0;
		for(i = 0; i < MAXROOMS; i++){
			if(r1->conn[i] && !r1->isconn[i] && rnd(++j) == 0){
				r2 = &rdes[i];
			}
		}
		/*
		 * if there is one, connect it and look for the next added
		 * passage
		 */
		if(j != 0){
			i = r1 - rdes;
			j = r2 - rdes;
			conn(i, j);
			r1->isconn[j] = TRUE;
			r2->isconn[i] = TRUE;
		}
	}
}

/*
 * conn:
 *	Draw a corridor from a room in a certain direction.
 */
void conn(int r1, int r2)
{
	ROOM *rpf, *rpt;
	char rmt;
	int distance, turn_spot, turn_distance;
	int rm;
	char direc;
	COORD delta, curr, turn_delta, spos, epos;

	if(r1 < r2){
		rm = r1;
		if(r1 + 1 == r2){
printf("room type 1 direction right %d->%d\n", r1, r2);
			direc = 'r';
		}else{
printf("room type 1 direction down %d->%d\n", r1, r2);
			direc = 'd';
		}
	}else{
		rm = r2;
		if(r2 + 1 == r1){
printf("room type 2 direction right %d->%d\n", r1, r2);
			direc = 'r';
		}else{
printf("room type 2 direction down %d->%d\n", r1, r2);
			direc = 'd';
		}
	}
	rpf = &rooms[rm];
//printf("room %d - %d / %d\n", r1, r2, rm);

	/*
	 * Set up the movement variables, in two cases:
	 * first drawing one down.
	 */
	if(direc == 'd'){
		rmt = rm + 3;								/* room # of dest */
		rpt = &rooms[rmt];							/* room pointer of dest */
		delta.x = 0;								/* direction of move */
		delta.y = 1;
		spos.x = rpf->r_pos.x;						/* start of move */
		spos.y = rpf->r_pos.y;
		epos.x = rpt->r_pos.x;						/* end of move */
		epos.y = rpt->r_pos.y;
		distance = 0;
		while(distance < 2){
			if(!(rpf->r_flags & ISGONE)){			/* if not gone pick door pos */
				spos.x += rnd(rpf->r_max.x - 2) + 1;
				spos.y += rpf->r_max.y - 1;
			}
			if(!(rpt->r_flags & ISGONE)){
				epos.x += rnd(rpt->r_max.x-2)+1;
			}
			distance = abs(spos.y - epos.y) - 1;	/* distance to move */
		}
		turn_delta.y = 0;							/* direction to turn */
		turn_delta.x = (spos.x < epos.x ? 1 : -1);
		turn_distance = abs(spos.x - epos.x);		/* how far to turn */
		turn_spot = rnd(distance - 1) + 1;			/* where turn starts */
	}else if(direc == 'r'){							/* setup for moving right */
		rmt = rm + 1;
		rpt = &rooms[rmt];
		delta.x = 1;
		delta.y = 0;
		spos.x = rpf->r_pos.x;
		spos.y = rpf->r_pos.y;
		epos.x = rpt->r_pos.x;
		epos.y = rpt->r_pos.y;
		distance = 0;
		while(distance < 2){
			if(!(rpf->r_flags & ISGONE)){
				spos.x += rpf->r_max.x - 1;
				spos.y += rnd(rpf->r_max.y - 2) + 1;
			}
			if(!(rpt->r_flags & ISGONE)){
				epos.y += rnd(rpt->r_max.y - 2) + 1;
			}
			distance = abs(spos.x - epos.x) - 1;
		}
		turn_delta.y = (spos.y < epos.y ? 1 : -1);
		turn_delta.x = 0;
		turn_distance = abs(spos.y - epos.y);
		turn_spot = rnd(distance - 1) + 1;
	}else{
		/*fatal("error in connection tables");*/
		printf("error in connection tables");
		/*
		 * Draw in the doors on either side of the passage or just put #'s
		 * if the rooms are gone.
		 */
		if(!(rpf->r_flags & ISGONE)){
			door(rpf, &spos);
		}else{
			cmov(spos);
			addch(PASSAGE);
//disp_dungeon();
		}
	}

	if(!(rpt->r_flags & ISGONE)){
		door(rpt, &epos);
//disp_dungeon();
	}else{
		cmov(epos);
		addch(PASSAGE);
//disp_dungeon();
	}

	/*
	 * Get ready to move...
	 */
	curr.x = spos.x;
	curr.y = spos.y;
	while(distance){
		/*
		 * Move to new position
		 */
		curr.x += delta.x;
		curr.y += delta.y;
		/*
		 * Check if we are at the turn place, if so do the turn
		 */
		if(distance == turn_spot && turn_distance > 0)
			while(turn_distance--)
			{
			cmov(curr);
			addch(PASSAGE);
//disp_dungeon();
			curr.x += turn_delta.x;
			curr.y += turn_delta.y;
			}
		/*
		 * Continue digging along
		 */
		cmov(curr);
		addch(PASSAGE);
//disp_dungeon();
		distance--;
	}
	curr.x += delta.x;
	curr.y += delta.y;
	if(!ce(curr, epos)){
		printf("Warning, connectivity problem on this level.\n");
		/*msg("Warning, connectivity problem on this level.");*/
	}

}

/*
 * Add a door or possibly a secret door
 * also enters the door in the exits array of the room.
 */
void door(ROOM *rm, COORD *cp)
{
	cmov(*cp);
	addch((rnd(10) < (level - 1) && rnd(100) < 20 ? SECRETDOOR : DOOR));
	rm->r_exit[rm->r_nexits++] = *cp;
}

/*
 * add_pass:
 *	add the passages to the current window (wizard command)
 */
void add_pass(void)
{
#if 0
	int y, x, ch;

	for(y = 1; y < (LINES - 2); y++){
		for(x = 0; x < COLS; x++){
			if((ch = mvinch(y, x)) == PASSAGE || ch == DOOR || ch == SECRETDOOR){
				mvwaddch(cw, y, x, ch);
			}
		}
	}
#endif
}

int rnd(int val)
{
//	if(!val) return 1;

	return rand() % val;
}

void disp_dungeon(void)
{
	int i;

	for(i = 0; i < LINES; i++){
		printf("%s\n", floor_map[i]);
	}

	printf("================================================================================\n");
}