#include <stdio.h>
#include <string.h>
#include <peekpoke.h>

unsigned char my_random(unsigned char range)
{
	if (range==0)
		return 0;
	else
		return ((PEEK(0xD20A))%range);
}


#define MAP_SIZE 32
unsigned char Map[MAP_SIZE][MAP_SIZE];

#define GRID 5
#define GRID_SIZE ((MAP_SIZE/GRID))
#define MAX_CORRIDORS ((GRID_SIZE)*(GRID_SIZE-1))

unsigned char BuildingCorridorsX[MAX_CORRIDORS];
unsigned char BuildingCorridorsY[MAX_CORRIDORS];

#define VERTICAL_DOOR 251
#define DOOR 252
#define WALL 253
#define ROOM 254
#define CORRIDOR 255

#define TILE_CORRIDOR ','
#define TILE_ROOM '.'
#define TILE_WALL '#'
#define TILE_DOOR '['

void CreateBuilding()
{
	register unsigned char x,y,x1,y1,i,j;
	register unsigned char corridor=0;

	puts("Phase 1");

	memset(Map,ROOM,sizeof(Map));
	// Phase 1. Place Corridors
	memset(BuildingCorridorsX+1,0,sizeof(BuildingCorridorsX)-1);
	memset(BuildingCorridorsY+1,0,sizeof(BuildingCorridorsY)-1);
	BuildingCorridorsX[0]=GRID_SIZE/2;
	BuildingCorridorsY[0]=GRID_SIZE/2;
		
	while(corridor<MAX_CORRIDORS-1) // -1 to avoid buffer overflow in ++corridor
	{
		// find starting point
		i=my_random(corridor+1); // corridor+1 !!!???
		// place new corridor
		x=BuildingCorridorsX[i];
		y=BuildingCorridorsY[i];
		

		if (my_random(2))
			i=1;
		else
			i=0xFF;
		
		if (my_random(2)) // horizontal
		{
			x1=x+i;
			y1=y;
		}
		else // vertical
		{
			y1=y+i;
			x1=x;
		}
		
		if (x1<=GRID_SIZE && y1<=GRID_SIZE)
		{
					
			if (y==y1) // if horizontal corridor
			{
				// draw it on map
				for (j=x*GRID;j!=x1*GRID;j+=i)
				{
					Map[y*GRID][j]=CORRIDOR;
				}
				Map[y*GRID][j]=CORRIDOR;
			}
			else
			{
				// draw it on map
				for (j=y*GRID;j!=y1*GRID;j+=i)
				{
					Map[j][x*GRID]=CORRIDOR;
				}
				Map[j][x*GRID]=CORRIDOR;
			}
			if (x1<GRID_SIZE && y1<GRID_SIZE)
			{
				// check this ending is on the corridor list
				for (j=0;j<corridor;++j)
				{
					if (BuildingCorridorsX[j]==x1 && BuildingCorridorsY[j]==y1)
						break;
				}
				if (j==corridor) // not on the list
				{
					++corridor;	
					BuildingCorridorsX[corridor]=x1;
					BuildingCorridorsY[corridor]=y1;			
				}
			}
		}
	}
	
	puts("Phase 2");
	// Phase 2. Outline the Corridors
	for (y=0;y<MAP_SIZE;++y)
	{
		for (x=0;x<MAP_SIZE;++x)
		{
			// add border
			if (x>=GRID*GRID_SIZE || y>=GRID*GRID_SIZE)
				Map[y][x]=WALL;
				
			// add outline on corridors
			if (Map[y][x]==CORRIDOR)
			{
				for (y1=y-1;(signed char) y1<=(signed char)y+1;++y1)
				{
					for (x1=x-1;(signed char) x1<=(signed char)x+1;++x1)
					{
						if (x1<MAP_SIZE && y1<MAP_SIZE)
						{
							if (Map[y1][x1]==ROOM)
							{
								Map[y1][x1]=WALL;
							}
						}
					}
				}
			}
		}
	}
	// Phase 3 - add doors
	
	// imperfect fill
	memset(BuildingCorridorsX,0,sizeof(BuildingCorridorsX));
	memset(BuildingCorridorsY,0,sizeof(BuildingCorridorsY));
	j=0; // last room	
	
	for (y=0;y<MAP_SIZE;++y)
	{
		for (x=0;x<MAP_SIZE;++x)
		{
			if (Map[y][x]==ROOM)
			{
				if (y>0 && Map[y-1][x]<MAX_CORRIDORS)
				{
					Map[y][x]=Map[y-1][x];
				}
				else if (x>0 & Map[y][x-1]<MAX_CORRIDORS)
				{
					Map[y][x]=Map[y][x-1];
				}
				else
				{
					Map[y][x]=j;
					++j;
				}
			}				
			
		}
	}
	// check corridors
	memset(BuildingCorridorsX,0xFF,sizeof(BuildingCorridorsX));
	memset(BuildingCorridorsY,0xFF,sizeof(BuildingCorridorsY));
	
	i=0;
	for (y=0;y<MAP_SIZE;++y)
	{
		for (x=0;x<MAP_SIZE;++x)
		{
			if (Map[y][x]==CORRIDOR)
			{
				if (y>2 && (i=Map[y-2][x])<MAX_CORRIDORS)
				{
					if (BuildingCorridorsX[i]==0xFF || my_random(4)==0)
					{
						BuildingCorridorsX[i]=x;
						BuildingCorridorsY[i]=y-1;
					}
				}
				if (x>2 && (i=Map[y][x-2])<MAX_CORRIDORS)
				{
					if (BuildingCorridorsX[i]==0xFF || my_random(4)==0)
					{
						BuildingCorridorsX[i]=x-1;
						BuildingCorridorsY[i]=y;
					}
				}
				if (y<MAP_SIZE-3 && (i=Map[y+2][x])<MAX_CORRIDORS)
				{
					if (BuildingCorridorsX[i]==0xFF || my_random(4)==0)
					{
						BuildingCorridorsX[i]=x;
						BuildingCorridorsY[i]=y+1;
					}
				}
				if (x<MAP_SIZE-3 && (i=Map[y][x+2])<MAX_CORRIDORS)
				{
					if (BuildingCorridorsX[i]==0xFF || my_random(4)==0)
					{
						BuildingCorridorsX[i]=x+1;
						BuildingCorridorsY[i]=y;
					}
				}
			}
		}
	}
	
	// add door on given places
	
	for (i=0;i<j;++i)
	{
		Map [ BuildingCorridorsY[i] ][ BuildingCorridorsX[i] ] = DOOR;
	}
	// Phase 4 - add objects - type by room
	
	
}

void ShowMap()
{
	register unsigned char x,y,c;
	puts("");
	for (y=0;y<MAP_SIZE;++y)
	{
		for (x=0;x<MAP_SIZE;++x)
		{
			switch(Map[y][x])
			{
				case ROOM:
					c=TILE_ROOM;
					break;
				case WALL:
					c=TILE_WALL;
					break;
				case CORRIDOR:
					c=TILE_CORRIDOR;
					break;
				case DOOR:
					c=TILE_DOOR;
					break;
				default:
					c=Map[y][x]+'0';
			}
			putchar(c);
		}
		puts("");
	}
}

int main(void)
{
	puts("Press RETURN to start");
	getchar();

	CreateBuilding();
	ShowMap();
//	printf("MAX_CORRIDORS: %d",MAX_CORRIDORS);
	for (;;);
  return 0;
}
	