Welcome to the Treehouse Community
Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.
Looking to learn something new?
Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.
Start your free trialIsak Landström
2,882 PointsDungeon game - OOP basics
Hello everyone!
I wanted to solidify my knowledge of the Python basics and OOP course by making the dungeon game that was suggested as a project after completing the memory game. Please have a look and review my code, if you have an alternate or easier way of coding something, please let me know, it's very appreciated.
Thanks also to @mel Rumsey who suggested I should use a linter or pep8 checker before I post my code to make sure it's clean and follow syntax rules of python coding.
import random
import os
class Game:
def __init__(self, game_size):
self.game_size = game_size
self.game_field = []
self.debug_mode = False
for x in range(game_size):
for y in range(game_size):
self.game_field.append((x, y))
self.door = random.choice(self.game_field)
self.door_visible = False
def cls(self):
os.system('clear')
def draw_grid(self, player, monster):
if monster.position == self.door:
self.door = random.choice(self.game_field)
grid_ceiling = " " + ("_ " * int(self.game_size))
print(grid_ceiling, end="\n")
for cell in self.game_field:
x, y = cell
if (x, y) == player.position and player.visible:
fill = player
elif (x, y) == monster.position and monster.visible:
fill = monster
elif (x, y) == self.door and self.door_visible:
fill = "D"
else:
fill = "_"
if y == int(self.game_size) - 1:
print(f"|{fill}|", end="\n")
else:
print(f"|{fill}", end="")
def show_help(self):
self.cls()
print("To move, please write any direction that is"
"avaiable in the 'available moves' list")
print("To enter debug mode, write: 'debug'")
print("To show this help: write 'help'")
input()
def check_win(self, player, monster):
if player == monster:
monster.visible = True
return "lose"
elif player.position == self.door:
self.door_visible = True
return "win"
else:
return "continue"
class Player:
def __init__(self, game_field, position):
self.position = position
self.symbol = "X"
self.visible = True
def __str__(self):
return str(self.symbol)
def __eq__(self, other):
return self.position == other.position
def show_moves(self, grid_size):
move_options = ["UP", "DOWN", "LEFT", "RIGHT"]
x, y = self.position
if x == 0:
move_options.remove("UP")
if y == 0:
move_options.remove("LEFT")
if x == grid_size - 1:
move_options.remove("DOWN")
if y == grid_size - 1:
move_options.remove("RIGHT")
return move_options
def move_player(self, direction, game_field):
x, y = self.position
if direction == "UP":
x -= 1
elif direction == "DOWN":
x += 1
elif direction == "LEFT":
y -= 1
elif direction == "RIGHT":
y += 1
if (x, y) not in game_field:
raise ValueError
else:
self.position = x, y
class Monster:
def __init__(self, game_field, position):
self.position = position
self.symbol = "@"
self.visible = False
def __str__(self):
return str(self.symbol)
if __name__ == '__main__':
program = True
while program:
field_size = input("Welcome to the Dungeon game, please"
"select difficulty: 'easy', 'medium' or 'hard'")
difficulty = {"easy": 4, "medium": 5, "hard": 6}
game = Game(difficulty[field_size])
# Making sure all positions are unique
pos_door, pos_monster, pos_player = random.sample(game.game_field, 3)
player = Player(game.game_field, pos_player)
monster = Monster(game.game_field, pos_monster)
game.door = pos_door
game_loop = True
while game_loop:
game.cls()
game.draw_grid(player, monster)
available_moves = player.show_moves(difficulty[field_size])
print("\nAvailable Moves: ", ", ".join(available_moves))
move = input().upper()
if move == "HELP":
game.show_help()
elif move == "DEBUG":
monster.visible = True
game.door_visible = True
game.debug_mode = True
else:
try:
player.move_player(move, game.game_field)
except ValueError:
print("Move is out of bounds")
input()
else:
if game.check_win(player, monster) == "win":
game.cls()
player.visible = False
game.draw_grid(player, monster)
print("You won the game!")
break
elif game.check_win(player, monster) == "lose":
game.cls()
player.visible = False
game.draw_grid(player, monster)
print("You lost the game, GAME OVER!")
break
else:
continue
retry = input("Play again? Y/N ").upper()
if retry == "Y" or retry == "YES":
game.cls()
continue
else:
print("Okay, thanks for playing, bye!")
program = False
1 Answer
Mel Rumsey
Treehouse ModeratorHi Isak Landström ! This is awesome. I won on my first try! (Granted, it was on easy 😜 lol lost on hard of course haha)
The code looks excellent. You have some good error handling for when a player enters a direction that is out of bounds. I would suggest also adding some error handling to the inputs especially to the main menu. The game crashes if anything other than 'easy', 'medium', or 'hard' is entered.
So, one thing I noticed is that the clear command doesn't work for players who are on Windows. Anytime it tries to clear there is an error in the console that says
'clear' is not recognized as an internal or external command,
operable program or batch file.
This is because clear
is not a command for windows. So, a way to fix this so that it works for anyone, regardless of their os is by adding an if/else
statement in the system method:
def clear():
os.system('cls' if os.name == 'nt' else 'clear')
Windows, oddly returns 'nt' as the os.name
, so it will type cls
and clear the console if it's windows... else
it will run clear
which will work for Mac.
Your OOP looks solid! Nice job creating this game with different difficulties, everything runs pretty smoothly. Also, that pep8 compliant code you have there is beautiful! ;)
Isak Landström
2,882 PointsIsak Landström
2,882 PointsHi and thank you once again for a great reply.
Yeah, there might have been one or two places where I could have handled the error the user might have generated (god damn users...!). Did you notice my debug method though? It was very useful when I wrote the code cause i could for example see that when I sometimes got the same position for door as monster, which made it so I couldn't win/lose the game. I fixed this error by making sure I got 3 unique samples with the random.sample function. Before this I asigned the position in the init method and used random.choice but that sometimes like I mentioned above gave the same position for either door or monster, so random.sample was the solution for me here.
I have seen the clear and 'cls' before but this time I forgot to add it :). What I am curious about though is the syntax in the clear method:
For me this way of using the 'if' keyword deviates from what I'm normally have been seeing. Here 'if' is preceeded by 'cls' and furthermore there is no ':' operator that indicates that the if clause body starts. Maybe this is just some pythonic way of writing an if/else clause?
Cheers, Isak