Error in my maze game

I tried to make a maze game with a player (showed as @) and gold (showed as $). Walls are showed as #. It has some unknown error. It doesn’t identify walls correctly. Code is given below:

import os
import time

import keyboard


class MazeGame:
    def __init__(self, name):
        self.maze = []
        self.PlayerName = name
        # Store Gold Location
        self.GoldX = 1
        self.GoldY = 1
        self.moves = 0
        # Player Location
        self.playerX = 6
        self.playerY = 1
        self.rows = 20
        self.cols = 20
        self.construct()
        self.placeGold()

    def construct(self):
        r00 = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
        r01 = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1]
        r02 = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1]
        r03 = [1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1]
        r04 = [1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1]
        r05 = [1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]
        r06 = [1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]
        r07 = [1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1]
        r08 = [1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1]
        r09 = [1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1]
        r10 = [1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1]
        r11 = [1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1]
        r12 = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]
        r13 = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1]
        r14 = [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1]
        r15 = [1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1]
        r16 = [1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1]
        r17 = [1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1]
        r18 = [1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1]
        r19 = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
        self.maze.append(r00)
        self.maze.append(r01)
        self.maze.append(r02)
        self.maze.append(r03)
        self.maze.append(r04)
        self.maze.append(r05)
        self.maze.append(r06)
        self.maze.append(r07)
        self.maze.append(r08)
        self.maze.append(r09)
        self.maze.append(r10)
        self.maze.append(r11)
        self.maze.append(r12)
        self.maze.append(r13)
        self.maze.append(r14)
        self.maze.append(r15)
        self.maze.append(r16)
        self.maze.append(r17)
        self.maze.append(r18)
        self.maze.append(r19)

    def placeGold(self):
        self.maze[self.GoldY][self.GoldX] = 2

    def move(self, n):
        if n == 1:
            if self.playerX != 19 and self.maze[self.playerX + 1][self.playerY] != 1:
                self.maze[self.playerY][self.playerX] = 0
                self.playerX += 1
                self.moves += 1
        elif n == 2:
            if self.playerX != 0 and self.maze[self.playerX - 1][self.playerY] != 1:
                self.maze[self.playerY][self.playerX] = 0
                self.playerX -= 1
                self.moves += 1
        elif n == 3:
            if self.playerY != 19 and self.maze[self.playerX][self.playerY + 1] != 1:
                self.maze[self.playerY][self.playerX] = 0
                self.playerY += 1
                self.moves += 1
        elif n == 4:
            if self.playerY != 0 and self.maze[self.playerX][self.playerY - 1] != 1:
                self.maze[self.playerY][self.playerX] = 0
                self.playerY -= 1
                self.moves += 1

    def isFound(self):
        if self.playerX == self.GoldX and self.playerY == self.GoldY:
            return True
        else:
            return False

    def show(self):
        os.system('cls')
        self.maze[self.playerY][self.playerX] = 3
        print("Name : " + self.PlayerName)
        print("Lets Start")
        for i in range(0, 20):
            for j in range(0, 20):
                if self.maze[i][j] == 0:
                    print(" ", end=" ")
                elif self.maze[i][j] == 2:
                    print("$", end=" ")
                elif self.maze[i][j] == 3:
                    print("@", end=" ")
                else:
                    print("#", end=" ")
            print()


def main():
    a = input("Enter the name of Player: ")
    game = MazeGame(a)
    while True:
        game.show()
        # print(game.playerX, game.playerY)
        while True:
            key = keyboard.read_key()
            if key == 'right':
                game.move(1)
                break
            elif key == 'left':
                game.move(2)
                break
            elif key == 'down':
                game.move(3)
                break
            elif key == 'up':
                game.move(4)
                break
        if game.isFound():
            game.show()
            break
        time.sleep(0.2)
    print("You won!")
    print("Total moves: ", game.moves)


if __name__ == "__main__":
    main()

I’m newbie to Python development. I’m seeking for assistance from senior developers here.

This program will be easier to debug and easier to read/verify if you use symbolic constants (either strings or enums) instead of integers. In particular for the possible directions. For instance:

import enum
class Direction(enum.Enum):
    UP = 'up'
    DOWN = 'down'
    RIGHT = 'right'
    LEFT = 'left'

You could consider using a similar enum for the state of the cells in the Maze:

class Cell(enum.Enum):
    EMPTY = 0
    WALL = 1

Then in the move function, you could clarify the purpose like this:

def move(self, direction):
    if direction == Direction.RIGHT:
         ...

In the main function you could then do something like (I’m also simplifying the loop a bit):

   while not game.isFound():
       game.show()
       key = keyboard.read_key()
       direction = Direction(key)
       game.move(direction)

Then to find the errors in your code, it’s probably simplest to temporarily add some extra print statements in the relevant function (move). For instance when going right, print out that you’re going right and print out which coordinates are being tested and updated…
Extra hint: The errors the script is making are related to the 2D array (swapping cols and rows in rendering/testing).

1 Like

It seems like you expect this data to represent the maze, oriented the same way in the source code as it is “logically” - with the “X coordinate” being left to right, and the “Y coordinate” being top to bottom. This is a common mistake made by almost every beginner who tries to make some kind of “maze game”, in many different programming languages. (In some other languages, the natural way of doing this would make a true “two-dimensional array”, rather than a list that contains other lists. But the underlying logical error is the same.)

In fact, when you build the self.maze list out of these “rows”, those will be the elements of self.maze - so when you use an index into self.maze, it will select the row. If you write self.maze[a][b], then the [a] is the index used for self.maze, and the b is the index used for that result (self.maze[a]). But since self.maze contains the rows, that means that self.maze[0] will mean the top row, self.maze[1] will mean the next row after that, etc. In other words, that index controls the Y coordinate, not the X coordinate.

If we look more closely at the move code:

it seems you realized this in some places, but not in others :wink:

1 Like

Thanks, it made easier to read. But I had to modify array also which is now difficult to understand. So, added a multi-line commented version of old array now.

Thanks, it worked!