CSC8501_Advanced_Programming_For_Games / MazeGeneration / MazeGenerator.cpp
MazeGenerator.cpp
Raw
#include "MazeGenerator.h"


MazeGenerator::MazeGenerator(uint32_t height, uint32_t width) : m_areaHeight(height), m_areaWidth(width) {
	if ((!m_areaHeight % 2u) || (!(m_areaWidth % 2u))) {
		throw std::invalid_argument("The Heigh and Width must be odd numbers"); 
	}
	m_area = new char* [m_areaHeight];
	for (int y = 0; y < m_areaHeight; y++) {
		m_area[y] = new char[m_areaWidth];
		for (int x = 0; x < m_areaWidth; x++) {
			m_area[y][x] = Maze_Char_Wall;
		}
	}
	InitializeMapDetails();
}

MazeGenerator::~MazeGenerator() {
	for (int y = 0; y < m_areaHeight; y++) {
		delete[] m_area[y];
	}
	delete[] m_area;
}

void MazeGenerator::SetCell(uint32_t y, uint32_t x, uint32_t value) {
	if ((m_areaHeight <= y) || m_areaWidth <= x) {
		throw std::invalid_argument("Out of boundry"); 
	} else if ((Maze_Char_Space != 32) && (Maze_Char_Exit != 69) && (Maze_Char_Start != 83)
		&& (Maze_Char_Wall != 88) && (Maze_Char_Path != 111)) {
		throw std::invalid_argument("The input can only contain allowed ASCII character");
	} else {
		m_area[y][x] = value;
	}
}

void MazeGenerator::SetMaze(char** maze, uint32_t mazeHeight, uint32_t mazeWidth) {
	if ((m_areaHeight != mazeHeight) || (m_areaWidth != mazeWidth))	{
		throw std::invalid_argument("Maze height and width is not the same");
	}
	else {
		for (int y = 0; y < mazeHeight; y++) {
			for (int x = 0; x < mazeWidth; x++)	{
				if ((Maze_Char_Space != 32) && (Maze_Char_Exit != 69) && (Maze_Char_Start != 83)
					&& (Maze_Char_Wall != 88) && (Maze_Char_Path != 111)) {
					throw std::invalid_argument("The input can only contain allowed ASCII character");
				} else {
					m_area[y][x] = maze[y][x];
				}
			}
		}
	}
}

void MazeGenerator::GenerateWalls() {
	for (int y = 0; y < m_areaHeight; y++) {
		for (int x = 0; x < m_areaWidth; x++) {
			m_area[y][x] = Maze_Char_Wall;
		}
	}
}

void MazeGenerator::GenerateCentreSpace(uint32_t exitEntrance) {
	Maze_Height_Half = m_areaHeight / 2;
	Maze_Width_Half = m_areaWidth / 2;
	for (int i = Maze_Centre_Top; i < Maze_Centre_Bottom; i++)	{
		for (int j = (Maze_Centre_Left); j < Maze_Centre_Right; j++) {
			m_area[i][j] = Maze_Char_Space;
		}
	}
	m_area[Maze_Height_Half][Maze_Width_Half] = exitEntrance;
}

void MazeGenerator::GenerateRandomExit(int n, int* exitsLocation, int* playerLocation, uint32_t exitEntrance) {
	int constexpr min = 0;
	int maxH = m_areaHeight - 1;
	int maxW = m_areaWidth - 1;
	int exitsLocationCount = 0;
	int playersLocationCount = 0;
	srand(time(0));
	for (int i = 0; i < n; i++) {
		int randNum = rand() % (maxH - min + 1) + min;
		if ((randNum == 0) || (randNum == maxH)) {
			int randNum2 = rand() % (maxW - min + 1) + min;
			if (m_area[randNum][randNum2] != Maze_Char_Exit) { 
				m_area[randNum][randNum2] = Maze_Char_Exit;
				exitsLocation[exitsLocationCount] = randNum;
				exitsLocationCount++;
				exitsLocation[exitsLocationCount] = randNum2;
				exitsLocationCount++;
				if (((randNum == min) || (randNum == maxH)) && ((randNum2 == min || randNum2 == maxW)))
				{}
				else {
					if (randNum == 0) { 
						m_area[randNum + 1][randNum2] = exitEntrance;
						m_area[randNum + 2][randNum2] = Maze_Char_Space;
						if (playerLocation) {
							playerLocation[playersLocationCount] = randNum + 1;
							playersLocationCount++;
							playerLocation[playersLocationCount] = randNum2;
							playersLocationCount++;
						}
					
					} else {
						m_area[randNum - 1][randNum2] = exitEntrance;
						m_area[randNum - 2][randNum2] = Maze_Char_Space;
						if (playerLocation) {
							playerLocation[playersLocationCount] = randNum - 1;
							playersLocationCount++;
							playerLocation[playersLocationCount] = randNum2;
							playersLocationCount++;
						}
					}
				}
			}
			else {
				i--;
			}
		}
		else {
			int randomBit = rand() & 1;
			int randomBit2 = (randomBit == 1) ? maxW : 0;
			if (m_area[randNum][randomBit2] != Maze_Char_Exit) { 
				m_area[randNum][randomBit2] = Maze_Char_Exit;
				exitsLocation[exitsLocationCount] = randNum;
				exitsLocationCount++;
				exitsLocation[exitsLocationCount] = randomBit2;
				exitsLocationCount++;
				if (randomBit2 == 0) {
					m_area[randNum][randomBit2 + 1] = exitEntrance;
					m_area[randNum][randomBit2 + 2] = Maze_Char_Space;
					if (playerLocation) {
						playerLocation[playersLocationCount] = randNum;
						playersLocationCount++;
						playerLocation[playersLocationCount] = randomBit2 + 1;
						playersLocationCount++;
					}
				} else {
					m_area[randNum][randomBit2 - 1] = exitEntrance;
					m_area[randNum][randomBit2 - 2] = Maze_Char_Space;
					if (playerLocation) {
						playerLocation[playersLocationCount] = randNum;
						playersLocationCount++;
						playerLocation[playersLocationCount] = randomBit2 - 1;
						playersLocationCount++;
					}
				}
			} else {
				i--;
			}
		}
	}
}

void MazeGenerator::PrintMaze() {
	for (int y = 0; y < m_areaHeight; y++) {
		for (int x = 0; x < m_areaWidth; x++) {
			std::cout << m_area[y][x];
			std::cout << ((x == (m_areaWidth - 1)) ? "\n" : "");
		}
	}
}

void MazeGenerator::InitializeMapDetails() {
	Maze_Height_Half = m_areaHeight / 2;
	Maze_Width_Half = m_areaWidth / 2;
	Maze_Exits = (2 * (Maze_Height_Half - 1)) + (2 * (Maze_Width_Half - 1));
	Maze_Max_Exits = (2 * (m_areaHeight - 2)) + (2 * (m_areaWidth - 2));

	Maze_Centre_Top = Maze_Height_Half - 3;
	Maze_Centre_Bottom = Maze_Height_Half + 4;
	Maze_Centre_Left = Maze_Width_Half - 3;
	Maze_Centre_Right = Maze_Width_Half + 4;
	Maze_Centre_Size = (Maze_Centre_Bottom - Maze_Centre_Top) * (Maze_Centre_Right - Maze_Centre_Left);

	Maze_All_Nodes = m_areaHeight * m_areaWidth;
	Maze_Available_Nodes = Maze_All_Nodes - (Maze_Exits + Maze_Centre_Size);
	Maze_Nodes_To_Clear = (int)Maze_All_Nodes * 0.35;
}