1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94

#include "gfCSimpleMazeComponent.h"

#include <stack>
#include <iostream>

void gfCSimpleMazeComponent::print() {
    for (int i = 0; i < height; i++) {
        for (int j = 0; j < width; j++) {
            std::cout << maze[i][j];
        }
        std::cout << std::endl;
    }
}

std::pair<int, int> gfCSimpleMazeComponent::findCell(char contents) const{

    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width; j++) {
            if (maze[i][j] == contents) {
            return std::make_pair(j, i);
        }}
    }
    return std::make_pair(-1, -1);
}

void gfCSimpleMazeComponent::generateMaze() {
    maze.assign(height, std::vector<char>(width, '#'));

    // Start from position inside the maze (not on border)
    int startX = 1, startY = width / 2;
    if (startY % 2 == 0) startY = (startY % 2 == 0) ? startY + 1 : startY;  // Ensure odd position<--- Condition 'startY%2==0' is always true<--- Assuming that condition 'startY%2==0' is not redundant
    maze[startX][startY] = ' ';

    // Create path using recursive backtracking
    std::stack<std::pair<int, int>> stack;
    stack.push({startX, startY});

    while (!stack.empty()) {
        auto [x, y] = stack.top();

        // Get unvisited neighbors (staying inside borders)
        std::vector<int> neighbors;
        for (int i = 0; i < 4; i++) {
            int nx = x + dx[i] * 2;  // Move 2 steps to skip walls
            int ny = y + dy[i] * 2;

            // Keep 1-cell border, so check bounds are 1 to width-2 and 1 to height-2
            if (nx >= 1 && nx < height - 1 && ny >= 1 && ny < width - 1 && isWall(nx, ny)) {
                neighbors.push_back(i);
            }
        }

        if (!neighbors.empty()) {
            // Choose random neighbor
            int dir = neighbors[rng() % neighbors.size()];
            int nx = x + dx[dir] * 2;
            int ny = y + dy[dir] * 2;

            // Create path
            maze[x + dx[dir]][y + dy[dir]] = ' ';  // Remove wall between
            maze[nx][ny] = ' ';  // Mark as path

            stack.push({nx, ny});
        } else {
            stack.pop();
        }
    }

    // Create entrance at top row - connect to nearest internal path
    int entranceX = startY;  // Use same Y position as internal start
    maze[0][entranceX] = 'S';  // Entrance on border

    // Find the closest path cell in the second-to-last row
    std::vector<int> exitOptions;
    for (int x = 1; x < width - 1; x += 1) {  // Check odd positions
        if (maze[height - 2][x] == ' ') {
            exitOptions.push_back(x);
        }
    }
    int exitX = exitOptions[rng() % exitOptions.size()];
    maze[height - 1][exitX] = 'F';  // Exit on border
}

gfCSimpleMazeComponent::gfCSimpleMazeComponent(int w, int h) : width(w), height(h), rng(std::random_device{}()) {
    // Ensure odd dimensions for proper maze generation and minimum size
    if (width % 2 == 0) width++;
    if (height % 2 == 0) height++;
    if (width < 5) width = 5;   // Minimum size to have proper borders
    if (height < 5) height = 5;

    generateMaze();
}