Search code examples
pythongame-development

How to fix error in the generation of maze in the game?


I decided to make a digital version of the board game "Labyrinth" in order to develop my skills, and first I planned to output through the console. I'm in the very early stages of development right now and I'm working on maze generation at the moment.

The labyrinth is a field of 7 * 7 squares on which there is a road of one of 3 types - an angle, a straight line or a T-shaped one. Each field may contain some kind of treasure, or it may not be there at all, but at the moment it is not so important. Here is the class I wrote to describe one square:

class Square:
    def __init__(self, square_type, angle, treasure=None):
        self.square_type = square_type # possible values "angular", "straight" or "t-shaped"
        self.angle = angle # possible values 0, 90, 180 и 270
        self.treasure = treasure

I suggested that the field should be described in a two-dimensional 7 * 7 array of elements of the Square class. According to the rules of the game, all elements located in positions that have both indices from the set of even numbers or 0 are predetermined and immobile. I added their values to the field array right after the array definition:

from squares import Square

rows = 7
columns = 7
field = [[None for _ in range(columns)] for _ in range(rows)]
for i in range(rows):
    for j in range(columns):
        field[i][j] = Square

field[0][0] = Square("angular", 0)
field[0][2] = Square("t-shaped", 0, "skull")
field[0][4] = Square("t-shaped", 0, "sword")
field[0][6] = Square("angular", 90)

field[2][0] = Square("t-shaped", 270, "pouch")
field[2][2] = Square("t-shaped", 270, "keys")
field[2][4] = Square("t-shaped", 0, "emerald")
field[2][6] = Square("t-shaped", 90, "helmet")


field[4][0] = Square("t-shaped", 270,"book")
field[4][2] = Square("t-shaped", 180, "crown")
field[4][4] = Square("t-shaped", 90, "chest")
field[4][6] = Square("t-shaped", 90, "chandelier")

field[6][0] = Square("angular", 270)
field[6][2] = Square("t-shaped", 0, "map")
field[6][4] = Square("t-shaped", 0, "ring")
field[6][6] = Square("angular", 180)

The rest of the loose squares also have certain types of paths and treasures on them, but their positions and angles are determined randomly before the start of the game. Here is their definition:

undefined_squares = []

for i in range(0, 12):
    undefined_squares.append(Square("straight", 0))


for i in range(12, 22):
    undefined_squares.append(Square("angular", 0))


undefined_squares.append(Square("angular", 0, "spider"))
undefined_squares.append(Square("angular", 0, "owl"))
undefined_squares.append(Square("angular", 0, "butterfly"))
undefined_squares.append(Square("angular", 0, "mouse"))
undefined_squares.append(Square("angular", 0, "lizard"))
undefined_squares.append(Square("angular", 0, "scarab"))
undefined_squares.append(Square("t-shaped", 0, "hobbit"))
undefined_squares.append(Square("t-shaped", 0, "ghost"))
undefined_squares.append(Square("t-shaped", 0, "bat"))
undefined_squares.append(Square("t-shaped", 0, "enchantress"))
undefined_squares.append(Square("t-shaped", 0, "jinn"))
undefined_squares.append(Square("t-shaped", 0, "dragon"))

And here is the generator that I wrote to fill the empty field elements with squares from the undefined_squares array:

from field import field
from squares import undefined_squares
import numpy.random as rand


def field_generator():
    for i in range(7):
        for j in range(7):
            if field[i][j] is None:
                field[i][j] = rand.choice(undefined_squares, replace=False)

Since I want to do console output first, I created variables that correspond to each combination of track types and rotation angles, and then wrote a dictionary to call these variables according to the values of the Square class elements from the Playfield's Field array:

angular_0 = [
    "######",
    "##    ",
    "##  ##"
]

angular_90 = [
    "######",
    "    ##",
    "##  ##"
]

angular_180 = [
    "##  ##",
    "    ##",
    "######"
]

angular_270 = [
    "##  ##",
    "##    ",
    "######"
]

straight_0 = [
    "##  ##",
    "##  ##",
    "##  ##"
]

straight_90 = [
    "######",
    "      ",
    "######"
]

t_shaped_0 = [
    "##  ##",
    "      "
    "######"
]

t_shaped_90 = [
    "##  ##",
    "##    ",
    "##  ##"
]

t_shaped_180 = [
    "######",
    "      ",
    "##  ##"
]

t_shaped_270 = [
    "##  ##",
    "    ##",
    "##  ##"
]
from console_visual import (
    angular_0,
    angular_90,
    angular_180,
    angular_270,
    straight_0,
    straight_90,
    t_shaped_0,
    t_shaped_90,
    t_shaped_180,
    t_shaped_270,
)

templates = {
    ("angular", 0): angular_0,
    ("angular", 90): angular_90,
    ("angular", 180): angular_180,
    ("angular", 270): angular_270,
    ("straight", 0): straight_0,
    ("straight", 90): straight_90,
    ("t-shaped", 0): t_shaped_0,
    ("t-shaped", 90): t_shaped_90,
    ("t-shaped", 180): t_shaped_180,
    ("t-shaped", 270): t_shaped_270,
}

I decided to test these functions and wrote a simple code in the main that was supposed to generate a maze and output it:

from field_generator import field_generator, field
from templates import templates

field_generator()

for row in field:
    for square in row:
        template = templates.get((square.square_type, square.angle))

        if template:
            for line in template:
                print(line)

When executing the code, the following error occurs:

######
##    
##  ##
Traceback (most recent call last):
  File "/Users/polina/PycharmProjects/labirynth_game/main.py", line 8, in <module>
    template = templates.get((square.square_type, square.angle))
AttributeError: type object 'Square' has no attribute 'square_type'

Process finished with exit code 1

Please tell me what is my mistake?


Solution

  • The issue is if field[i][j] is None: is never hit in the field_generator file. In the field file the line field[i][j] = Square sets to a Square class (not object).

    Removing the lines

    for i in range(rows):
        for j in range(columns):
            field[i][j] = Square
    

    will let the element default to the None initialization.

    Lastly, if I would suggest introducing the undefined square values into the default initialization of the Square class.