'2D dungeon map generation

I'm currently working on a text-based dungeon-crawler game.

My question is: What is the simplest method to make a randomly generated dungeon (say, like the binding of isaac), where there are 4 possible directions to go (north, south, east, west)? Since there are no visuals, I literally just need an object (a level) that is a bunch of these tiles). I also need every tile to connect to at least one other tile.

I've thought about using a center and then randomly generating 1-4 tiles away from the center, then 1-4 tiles from those tiles and so on, but that is highly inefficient since it creates a lot of overlap. I'd also like to decide the number of tiles, and I can't with that.

I'm using python 3. I've created a rudimentary Tile class where it has 4 outgoing variables (n,s,e,w) which can be set to other tiles. I'm stuck there.

Thanks!

Edit. This is what I've done so far, it should work but I don't have any way to test it right now:

from random import randint

class Level(object):
    """Class that represents a level/floor"""
    class Tile(object):
        """Class that represents a tile."""
        def __init__(self, previousDirection = None, previousTile = None, location = ''):
            self.paths = {'n': None, 's': None, 'e': None, 'w': None}
            if previousTile != None and previousDirection!=None:
                self.paths[Level.Tile.antipath(previousDirection)] = previousTile
            self.enemies = [0]*randint(0,10)
            self.location = location

        def __str__(self):
            rep = "Location: {}, ".format(self.location)
            rep += "Enemies: "
            for enemy in self.enemies:
                rep += (str(enemy) + ", ")
            rep += 'Paths: '
            for path in self.paths:
                if self.paths[path]!=None:
                    rep += (path + ', ')
            return rep

        def __add__(self, other):
            if len(self.enemies)>len(other.enemies):
                return self
            else:
                return other

        @staticmethod
        def locationparser(location):
            directions_l = []
            for direction in location:
                antidirection = Level.Tile.antipath(direction)
                if antidirection in directions_l:
                    directions_l.remove(antidirection)
                else:
                    directions_l.append(direction)
            return "".join(sorted(directions_l))

        @staticmethod
        def antipath(path):
            for pathpair in [['n', 's'], ['e','w']]:
                if path in pathpair:
                    pathpair.remove(path)
                    return pathpair[0]
            raise ValueError('No such path exists')

    def __init__(self, stage): #stage will start at 1
        self.center_tile = Level.Tile()
        self.stage = stage
        self.maxdepth = randint(3, int(stage) + 5)
        self.tiles = 1
        self.locations = []
        #number of iterations around center
        
    def r_generate(self, tile, location, depth):
        if depth == self.maxdepth:
            return
        else:
            for path in tile.paths:
                location_next = Level.Tile.locationparser(location + path)
                if tile.paths[path] == None:
                    if randint(0,1) == 1:
                        if location_next in self.locations:
                            existing_tile = Level.find_tile_from_plocation(location_next)
                            tile.paths[path] = existing_tile
                            existing_tile.paths[Level.Tile.antipath(path)] = tile
                        else:
                            self.locations += location_next
                            self.tiles += 1 #counting tiles
                            tile.paths[path] = Level.Tile(path, tile, location_next)
                            Level.r_generate(self, tile.paths[path], location_next, depth+1)

    def find_tile_from_plocation(self, plocation):
        """Finds a tile from the center from a parsed location"""
        current_tile = self.center_tile
        for direction in plocation:
            if current_tile.paths[direction] != None:
                current_tile = current_tile.paths[direction]
            else:
                raise ValueError("There is no tile at that location")
        return current_tile


Solution 1:[1]

take a look at thoses, and just choose one

https://en.wikipedia.org/wiki/Maze_generation_algorithm

ps: to have multiple paths available you can modify the algos to let multiple paths open

Solution 2:[2]

I figured it out. The code is under the github repo "true_adventure" from the user super1iminal. It's the file called tiles. I don't want to put it here since it uses other files and blah blah.

-super1iminal

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Ren
Solution 2 super1iminal