training

Code I wrote during training
git clone git://git.bitsmanent.org/training
Log | Files | Refs | README

mazegen.c (4872B)


      1 /* See LICENSE file for copyright and license details.
      2  *
      3  * Maze generator - Implements the Deep-First Search algorithm.
      4  */
      5 
      6 #include <stdio.h>
      7 #include <stdlib.h>
      8 #include <string.h>
      9 #include <time.h>
     10 #include <unistd.h>
     11 
     12 #define N (1<<3)	/* North */
     13 #define S (1<<2)	/* South */
     14 #define W (1<<1)	/* West */
     15 #define E (0x01)	/* East */
     16 #define A (N|S|W|E)	/* All the above */
     17 
     18 #define BORDERS		12	/* Unused */
     19 #define WALLS		8
     20 #define SOLUTION	4	/* Unused */
     21 #define BACKTICK	0	/* Unused */
     22 
     23 #define ROWS	20
     24 #define COLS	20
     25 
     26 #define ISSET(C, W)	(W == (C & W))
     27 
     28 /* globals */
     29 int rows, cols;
     30 
     31 /* function declarations */
     32 void maze_gen(short int *grid, int TotalCells);
     33 void maze_open(short int *grid);
     34 int nextcell(short int *grid, int cell);
     35 void pulldown(short int *grid, int CurrentCell, int cell);
     36 void push(int *stack, int *top, int cell);
     37 int pop(int *stack, int *top);
     38 void maze_show(short int *grid);
     39 
     40 /* function implementations */
     41 int
     42 main(int argc, char *argv[]) {
     43 	short int *grid;
     44 	int c;
     45 
     46 	rows = ROWS;
     47 	cols = COLS;
     48 
     49 	while((c = getopt(argc, argv, "c:r:h")) != -1) {
     50 		switch(c) {
     51 			case 'c':
     52 				cols = atoi(optarg);
     53 				break;
     54 			case 'r':
     55 				rows = atoi(optarg);
     56 				break;
     57 			case 'h':
     58 				printf(
     59 					"Usage: %s -<hV> [-c cols] [-r rows]\n"
     60 					"\nOptions\n"
     61 					"   -r rows\t: set the rows (default: %d)\n"
     62 					"   -c cols\t: set the columns (default: %d)\n"
     63 					"   -h\t: show this help\n"
     64 					"   -V\t: show the version and exit\n"
     65 					"\n",
     66 				argv[0], ROWS, COLS);
     67 				return 1;
     68 				break;
     69 			default:
     70 				printf("Usage: %s -<hV> [-c cols] [-r rows]\n", argv[0]);
     71 				return 1;
     72 		}
     73 	}
     74 
     75 	if(rows <= 0|| cols <= 0) {
     76 		fprintf(stderr, "%s: invalid maze size (columns or rows)\n", argv[0]);
     77 		return 1;
     78 	}
     79 
     80 	if((grid = malloc(rows * cols * sizeof(short int))) == NULL) {
     81 		fprintf(stderr, "Sorry, there is not enough memory available.\n");
     82 		return 1;
     83 	}
     84 
     85 	srandom(time(NULL));
     86 	memset(grid, '\0', rows * cols);
     87 
     88 	maze_gen(grid, rows * cols);
     89 	maze_open(grid);
     90 	maze_show(grid);
     91 
     92 	free(grid);
     93 
     94 	return 0;
     95 }
     96 
     97 void
     98 maze_open(short int *grid) {
     99 	int i;
    100 
    101 	for(i = 0; i < 2; i++) {
    102 		switch(1 + random() % 4) {
    103 			case 1: /* north */
    104 				grid[random() % cols] ^= N << WALLS;
    105 				break;
    106 			case 2: /* south */
    107 				grid[cols * (rows - 1) + (random() % cols)] ^= S << WALLS;
    108 				break;
    109 			case 3: /* east */
    110 				grid[(random() % rows) * cols + (cols - 1)] ^= E << WALLS;
    111 				break;
    112 			case 4: /* west */
    113 				grid[(random() % rows) * cols] ^= W << WALLS;
    114 				break;
    115 		}
    116 	}
    117 }
    118 
    119 void
    120 push(int *stack, int *top, int cell) {
    121 	stack[(*top)++] = cell;
    122 }
    123 
    124 int
    125 pop(int *stack, int *top) {  
    126 	if(! *top) {
    127 		printf("The stack is empty.\n");
    128 		return 0;
    129 	}
    130 
    131 	return stack[--(*top)];
    132 }
    133 
    134 void
    135 maze_gen(short int *grid, int TotalCells) {
    136 	int CurrentCell = random() / (RAND_MAX / TotalCells + 1);
    137 	int VisitedCells = 1;
    138 	int AdCell; /* Adiacent cell */
    139 	int *stack, top = 0;
    140 	int i;
    141 
    142 	if(! (stack = malloc(sizeof(int) * TotalCells)))
    143 		return;
    144 
    145 	for(i = 0; i < rows * cols; i++)
    146 		grid[i] = A << WALLS;
    147 
    148 	while(VisitedCells < TotalCells) {
    149 		if((AdCell = nextcell(grid, CurrentCell)) != -1) {
    150 			pulldown(grid, CurrentCell, AdCell);
    151 
    152 			push(stack, &top, CurrentCell);
    153 			CurrentCell = AdCell;
    154 			++VisitedCells;
    155 		}
    156 		else
    157 			CurrentCell = pop(stack, &top);
    158 	}
    159 }
    160 
    161 int
    162 nextcell(short int *grid, int cell) {
    163 	int idx = 0, cells[4] = {0};
    164 
    165 	/* TODO: cleanup this code */
    166 
    167 	if(cell % cols && cell - 1 >= 0 && ISSET(grid[cell - 1], A << WALLS))
    168 		cells[idx++] = cell - 1;
    169 
    170 	if((cell % cols) != (cols - 1) &&
    171 	     cell + 1 < rows * cols && ISSET(grid[cell + 1], A << WALLS))
    172 		cells[idx++] = cell + 1;
    173 
    174 	if(cell - cols >= 0 && ISSET(grid[cell - cols], A << WALLS))
    175 		cells[idx++] = cell - cols;
    176 
    177 	if(cell + cols < rows * cols && ISSET(grid[cell + cols], A << WALLS))
    178 		cells[idx++] = cell + cols;
    179 
    180 	return ! idx ? -1 : cells[random() / (RAND_MAX / idx + 1)];
    181 }
    182 
    183 void
    184 pulldown(short int *grid, int CurrentCell, int cell) {
    185 
    186 	/* Note: I have to pull down the walls in both CurrentCell and cell in
    187 	 * order be make showmaze() works properly. */
    188 
    189 	if(CurrentCell == cell - 1) {
    190 		grid[CurrentCell] ^= E << WALLS;
    191 		grid[cell] ^= W << WALLS;
    192 	}
    193 
    194 	else if(CurrentCell == cell + 1) {
    195 		grid[CurrentCell] ^= W << WALLS;
    196 		grid[cell] ^= E << WALLS;
    197 	}
    198 
    199 	else if(CurrentCell < cell) {
    200 		grid[CurrentCell] ^= S << WALLS;
    201 		grid[cell] ^= N << WALLS;
    202 	}
    203 
    204 	else if(CurrentCell > cell) {
    205 		grid[CurrentCell] ^= N << WALLS;
    206 		grid[cell] ^= S << WALLS;
    207 	}
    208 
    209 }
    210 
    211 void
    212 maze_show(short int *grid) {
    213 	int i;
    214 
    215 	printf(" ");
    216 	for(i = 0; i < cols; i++)
    217 		printf("%c%c", ISSET(grid[i], N << WALLS) ?
    218 			'_' : ' ', (i == cols - 1 ? ' ' : '_'));
    219 
    220 	for(i = 0; i < rows * cols; i++) {
    221 		if(!(i % cols)) {
    222 			printf("\n%c", ISSET(grid[i], W << WALLS) ? '|' : ' ');
    223 		}
    224 
    225 		printf("%c%c",
    226 			ISSET(grid[i], S << WALLS) ? '_' : ' ',
    227 			ISSET(grid[i], E << WALLS) ? '|' : '_');
    228 	}
    229 
    230 	printf("\n");
    231 
    232 }