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 trialDavid McCarty
5,214 PointsMade the monster Follow You! My variation on the grid based game.
I decided to make my own little spin on the grid based python game you create in the course "Python Collections"
Before I even watched the videos on making the game, I embarked on making it myself. I figured by the cute little animation depicting the game that you wanted us to make the monster follow the player. Turns out that wasn't the case, but I got it to work anyways :P
Here it is! Let me know if you have any suggestions, I know the coding work is probably a bit sloppy and there is, I'm sure, many improvements to be made. But! I hope you enjoy it nonetheless
In case you're wondering how I got the monster to follow the player, to pick the best move that gets it closest to the player, it was actually rather simple. What I did was take the distance between lines formula, which is sqrt((x2^2 - x1^2) + (y2^2 - y1^2)) of each possible move (up, down, left, and right) so long as they don't go outside the grid, and the monster just picked the move that resulted in the smallest number. Turns out, that's all it takes to get a monster to chase you!
import random
def create_moves(player):
plyr = player
removeable = (-1, -1)
while True:
up = ((plyr[0] - 1), plyr[1])
down = ((plyr[0] + 1), plyr[1])
left = (plyr[0], (plyr[1] - 1))
right = (plyr[0], (plyr[1] + 1))
move_list = [up, down, left, right]
if move_list[1][0] > 4:
move_list[1] = removeable
if move_list[3][1] > 4:
move_list[3] = removeable
if move_list[0][0] < 0:
move_list[0] = removeable
if move_list[2][1] < 0:
move_list[2] = removeable
break
try:
choice_list = ["1 = Up {}".format(up), "2 = Down {}".format(down), "3 = Left {}".format(left),
"4 = Right {}".format(right)]
for index, moves in enumerate(move_list):
if move_list[index] == removeable:
choice_list[index] = ""
updated_list = list()
for items in choice_list:
if items == "":
continue
else:
updated_list.append(items)
print(*updated_list, sep='\n')
user_choice = input("\nChoice: ")
user_choice = int(user_choice)
if user_choice > 4 or user_choice < 1:
int("bacon") #Used to throw an exception to avoid
#users entering in letters
if user_choice == 1:
return up
elif user_choice == 2:
return down
elif user_choice == 3:
return left
elif user_choice == 4:
return right
except:
print("Choice must be a number and it must be between 1 and 4")
create_moves(plyr)
def create_monster_moves(mon):
removeable = (-1, -1)
while True:
m_up = ((mon[0] - 1), mon[1])
m_down = ((mon[0] + 1), mon[1])
m_left = (mon[0], (mon[1] - 1))
m_right = (mon[0], (mon[1] + 1))
m_move_list = [m_up, m_down, m_left, m_right]
if m_move_list[1][0] > 4:
m_move_list[1] = removeable
if m_move_list[3][1] > 4:
m_move_list[3] = removeable
if m_move_list[0][0] < 0:
m_move_list[0] = removeable
if m_move_list[2][1] < 0:
m_move_list[2] = removeable
return m_move_list
def move_monster(mon, plyr):
removeable = (-1, -1)
m_move_list = create_monster_moves(mon)
best_move_num = 100.0
best_move_tup = (0,0)
while True:
for monster_moves in m_move_list:
if(monster_moves == removeable):
continue
else:
move = ((plyr[0] - monster_moves[0])**(2) + (plyr[1] -
monster_moves[1])**(2))**(.5)
if move < best_move_num:
best_move_num = move
best_move_tup = monster_moves
break
return best_move_tup
def draw_map(plyr, mon):
print(" _ _ _ _ _")
tile = "|{}"
for idx, cell in enumerate(CELLS):
if idx in [0, 1, 2, 3, 5, 6, 7, 8, 10, 11, 12, 13, 15, 16, 17, 18, 20, 21, 22, 23]:
if cell == plyr:
print(tile.format('X'), end='')
elif cell == mon:
print(tile.format('M'), end='')
else:
print(tile.format('_'), end='')
else:
if cell == plyr:
print(tile.format("X|"))
elif cell == mon:
print(tile.format("M|"))
else:
print(tile.format("_|"))
CELLS = [(0,0), (0,1), (0,2), (0,3), (0,4),
(1,0), (1,1), (1,2), (1,3), (1,4),
(2,0), (2,1), (2,2), (2,3), (2,4),
(3,0), (3,1), (3,2), (3,3), (3,4),
(4,0), (4,1), (4,2), (4,3), (4,4)]
monster = 0
player = 0,0
door = 0
user_choice = 0
#Sets each object a cell. If anyone has the same cell, it starts over
while True:
monster = random.choice(CELLS)
player = random.choice(CELLS)
door = random.choice(CELLS)
if monster == door or monster == player or door == player:
continue
else:
break
#If it's else, none of them were equal
while True:
print("\nYou are in cell {}".format(player))
draw_map(player, monster)
player = create_moves(player)
if player == door:
print("You win! You made it to the door!")
break
elif player == monster:
print("You got eaten by the monster :( Game over")
break
monster = move_monster(monster, player)
draw_map(player, monster)
if player == monster:
print("You got eaten by the monster :( Game over")
break
2 Answers
John Hill
Front End Web Development Techdegree Graduate 35,236 PointsDude…the gameplay is definitely heightened by the chasing monster! I'm playing it right now! Couple things: when I'm next to a wall, and even though the option is removed, I can still select that option and go off the grid. And it'd be cool to have a 'Play Again?' option at the end of a game. It also shows the updated map twice after I select a move.
I'm not deep enough yet to know how to improve the code or I'd let you know if I saw anything! Here are some conceptual ideas though: being able to select diff map sizes (more monsters on larger maps?); when the monster gets the player, have an option to battle it(!) in a turn-based style fight or a dice roll; maybe the user could land on a power-up that would show where the door is. Maybe too much, but I'm digging it!
Question though: why is the removable tuple set to (-1,-1)? Also, how is it that you can call mon[0] and mon[1]? I don't a a 'mon' list…does it trace back to removable somehow??
Brandon Wall
5,512 PointsDude this is awesome, I'm going to look at it a little harder and play around with it myself. Your distance between lines formula is a bit over my head since I never got far in the maths, but one thing I did see that was interesting was your line.
if user_choice > 4 or user_choice < 1:
int("bacon") #Used to throw an exception to avoid
#users entering in letters
Instead of doing it like that, which is clever, you can use the keyword raise, like this:
if user_choice > 4 or user_choice <1:
raise ValueError #You can also just use raise by itself. Check out help('raise') in the Python interpreter
raise is a great trick I learned recently, when used by itself it re-raises the last exception that was active in the current scope. If no exception is active in the current scope, A RuntimeError exception is raised indicating that this is an error.
John Hill
Front End Web Development Techdegree Graduate 35,236 Points"raise" the roof for this tip!! (I'm….SO….SORRY!!)
Distance formula [ (x2 - x1)^2 + (y2 - y1)^2 = c^2 ] is just an iteration of the Pythagorean Theorem [ a^2 + b^2 = c^2 ] to find a side of a triangle, where x2 - x1 = a and y2 - y1 = b.
So if y2 is 12 and y1 is 5, the distance from y2 to y1 (and the length of that particular side of the triangle) is 7. Now you can plug that new number 7 into the Pythag-Theorem. If you know the side lengths initially, you can omit the distance formula and just use the Pythag-Theorem. But if you have only coordinates to work with, you'd do the one extra step of subtracting the coordinate values to find the side lengths.
These all say the same thing:
a^2 + b^2 = c^2
(x2 - x1)^2 + (y2 - y1)^2 = c^2
sqrt( (x2 - x1)^2 + (y2 - y1)^2 ) = c
**note: the pic uses the variable 'd' instead of 'c', but it's the same biz-nass
David McCarty
5,214 PointsHuh, I had never heard of raise before, but I will definitely keep that in mind. A much more pythonic way to cause an exception that's for sure haha!
Oh, and thanks for the compliment :) Glad you like the program!
David McCarty
5,214 PointsDavid McCarty
5,214 PointsThose are some really good idea, I mean like really good ideas. I will definitely work on them when I get a chance, I will try and implement as much of them as I can. Some great practice if I could get them all implemented into the game.
As for your first question, I have the variable
removeable
set to (-1, -1) just as a way to set and test the list if any of the moves go into the negatives. Essentially, if a move results in anything greater than 4 or smaller than 0, it's off the map, and the move in that index of the list is replaced with the tupleremoveable
which is (-1, -1). This way, I can have a loop that looks through the entire list and omits any of the indexes that are equal to the variableremoveable
which is (-1,. -1). Basically, it's just my way of figuring and testing for the moves that are invalid.As for your second question: In the method
create_monster_moves(mon):
the passed in variablemon
is a reference of the monster variable which is a tuple containing the position of the monster. When the method is called, you have to pass in the monster variable and therefore you can reference indexes of the tuple by doing mon[0] to get the first part (the row) or mon[1] to get the second part of the tuple (the column).Oh, and I knew about being able to go off the grid. I am meaning to fix that since it's kind of sloppy to leave it in, but I hadn't been able to get around to it/I forgot it was there. So, thanks for the reminder! I will try and fix that while I try and add those other features and ideas