Help Improving my Map Generator (Drunkard)

So I'm trying to create a map generator which creates cave-like areas connected by pathways. I'm pretty sure I should have some second array which stores integer values to each cell, but right now I don't. It also, uh, doesn't have any support for adding paths and is waaay too random. It'll add resources on top of water or traps in walls, etc.

I'm using the Drunkard algorithm (add a copy of the current cell to a randomly selected adjacent cell, NESW).

What I have so far works like this:
1) Choose tile type (Floor, Resource..).
2) Choose number of seeds (randomly placed on the map).
3) Choose growth rate (how many Drunkard iterations to perform).

The program then loops through the array like so:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
while(Iterations < Growth)
{
    for(int y = 0; y < MapY; y++)
    {
        for(int x = 0; x < MapX; x++)
        {
            if(Map[y][x] == TileType[CurrentType])
            {
                Direction = Random(0, 4);

                switch(Direction)
                {
                    case N: Map[y-1][x] = TileType[CurrentType]; break;
                    case E: Map[y][x+1] = TileType[CurrentType]; break;
                    case S: Map[y+1][x] = TileType[CurrentType]; break;
                    case W: Map[y][x-1] = TileType[CurrentType]; break;
                }
            }
        }
    }

    Iterations++;
}

As you can see, this has no bias or pattern-following at all. It works well in a sense that you can create 3 large areas (eg. Floor, 3 Seeds, 14 Growth) or many smaller resource pockets (eg. Resource, 12 Seeds, 4 Growth), but there are a few setbacks with how it currently works:

1) Each time you add a type to the map, it overwrites whatever was underneath it - regardless of what was there (walls, items).
2) If you add floors (3 Seeds, 10 Growth) then add more floors (4 Seeds, 6 Growth), the second batch will increase the growth of the first (as if you entered 3 Seeds, 16 Growth) since it just scans for the Floor char and iterates it.

There are other problems and an overall general lack of functionality that you'll likely spot. I'm just hoping you guys can help me improve this a little so that it's somewhat useful, at least on a basic level. I'd like to get resources to show up in pockets in the walls, next to floor tiles, for example. Thanks in advance.

Full code:

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
95
96
97
98
99
100
101
#include <iostream>
#include <windows.h>
#include <ctime>

using namespace std;

enum DIRECTIONS { N, E, S, W };
enum Colour { black, blue, green, cyan, red, purple, yellow, grey, dgrey, hblue, hgreen, hcyan, hred, hpurple, hyellow, white };

// Colours:
void coutc(int color)
{
    HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleTextAttribute(handle, color);
}

// Randomizer:
int Random(int LowEnd, int Range)
{
    return (int) rand() % (Range + 0) + LowEnd;
}

// Prototypes:
void PrintMap(char Map[][81], const int MapY, const int MapX);

// MAIN:
int main()
{
    srand(time(0));

    bool Generating = true;
    const int MapY = 22, MapX = 80;
    char Map[MapY+1][MapX+1]; // +1 for null
    const char TileType[4] = {'W', 'F', 'R', 'T'};
    int Direction, CurrentType = 0, NumOfSeeds = 2000, Iterations, Growth = 20, Select;

    while(Generating)
    {
        // Plant Seeds:
        for(int i = 0; i < NumOfSeeds; i++)
        {
            Map[Random(0, MapY)][Random(0, MapX)] = TileType[CurrentType];
        }

        Iterations = 0;

        // Generate Map:
        while(Iterations < Growth)
        {
            for(int y = 0; y < MapY; y++)
            {
                for(int x = 0; x < MapX; x++)
                {
                    if(Map[y][x] == TileType[CurrentType])
                    {
                        Direction = Random(0, 4);

                        switch(Direction)
                        {
                            case N: Map[y-1][x] = TileType[CurrentType]; break;
                            case E: Map[y][x+1] = TileType[CurrentType]; break;
                            case S: Map[y+1][x] = TileType[CurrentType]; break;
                            case W: Map[y][x-1] = TileType[CurrentType]; break;
                        }
                    }
                }
            }

            Iterations++;
        }

        PrintMap(Map, MapY, MapX);
        coutc(dgrey); cout << "TYPES : 1 Wall, 2 Floor, 3 Resource, 4 Trap\n";
        coutc(white); cout << "      : X) Type X) Seeds X) Growth\n";
                      cout << "      > ";
        cin >> Select;
        if(Select == 0){ Generating = false; continue; }
        cin >> NumOfSeeds >> Growth;
        CurrentType = Select - 1;
        system("cls");
    }
}

// Print Map
void PrintMap(char Map[][81], const int MapY, const int MapX)
{
    for(int y = 0; y < MapY; y++)
    {
        for(int x = 0; x < MapX; x++)
        {
            switch(Map[y][x])
            {
                case 'W': coutc(red+(green*16));     cout << 'Y'; break;
                case 'F': coutc(hgreen+(green*16));  cout << ','; break;
                case 'R': coutc(purple+(green*16));  cout << 'o'; break;
                case 'T': coutc(cyan+(green*16));    cout << '~'; break;
            }

        }
    }
}
Last edited on
I fixed a few things, but it's still buggy. Now it'll only grow the seeds you just planted (it always ignores previously generated cells), resources only grow on wall tiles adjacent to floor tiles and water only grows on floor tiles. There's still no real pattern to the generation though, and no connecting paths etc.

This is what I'm using to limit where the seeds can grow:

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
            while(Iterations < Growth)
            {
                for(int y = 0; y < MapY; y++)
                {
                    for(int x = 0; x < MapX; x++)
                    {
                        if(Map[y][x] == TileType[CurrentType] && Active[y][x] == true)
                        {
                            Direction = Random(0, 4);

                            switch(Direction)
                            {
                                case N: if(CurrentType != Floor || Map[y-1][x] != TileType[Wall]){
                                        Map[y-1][x] = TileType[CurrentType];
                                        Active[y-1][x] = true; }
                                        break;
                                case E: if(CurrentType != Floor || Map[y-1][x] != TileType[Wall]){
                                        Map[y][x+1] = TileType[CurrentType];
                                        Active[y][x+1] = true; }
                                        break;
                                case S: if(CurrentType != Floor || Map[y-1][x] != TileType[Wall]){
                                        Map[y+1][x] = TileType[CurrentType];
                                        Active[y+1][x] = true; }
                                        break;
                                case W: if(CurrentType != Floor || Map[y-1][x] != TileType[Wall]){
                                        Map[y][x-1] = TileType[CurrentType];
                                        Active[y][x-1] = true; }
                                        break;
                            }
                        }
                    }
                }

Doesn't work quite right. The idea is that only Floors and more Walls can be planted on / overwrite Walls. It works for everything but the Floors - when I plant them it just adds the seeds and doesn't grow (so you get single cells of Floor where the seeds are).
No help because nobody knows what to suggest, because I'm being unclear about what I'm asking, or because wrong section?
I think you should probably stop that code from trampling memory you shouldn't be touching before worrying too much about the algorithm.

What happens when y is 0 and Direction is N? What happens when x is MapX-1 and Direction is E? What happens when y is MapY-1 and Direction is S? What happens when x is 0 and Direction is W?

Oh man good point, I'll probably take the easy way out and make the outer rectange of the map 'unavailable' for seeding and growth. I really wasn't thinking about that though, thanks.

I also just realized that the most recent code I posted is wrong in a couple of ways. For one, not every tile type has the rule of "can grow unless you hit a wall" since resources will do the opposite, and the CurrentType != Floor || Map[y-1][x] != TileType[Wall] would need to be split up anyway so that it actually did what it was meant to do (allow Floors to overwrite walls but nothing else).

I'm thinking that I should probably find a way to give each tile type a bunch of rules that are accounted for whenever they're used. The planting seeds function and the growth function are clashing a bit and are pretty similar.
Topic archived. No new replies allowed.