unexpected indent error inside a definition for a function - python

I have this code for the movement of a monster to move randomly between rooms but I get an unexpected intention error for the global value.
def monster(): """moves the monster randomly"""
global monster_current_room
if monster_current_room["name"] != current_room:
print('The monster is currently in', monster_current_room["name"])
exits = list(monster_current_room["exits"].values())
if random.randint(1, 4) == 4:
monster_current_room = rooms[random.choice(exits)]
elif monster_current_room["name"] == current_room:
game_over = True
if I unindent the global value it acts as the end of the definition and wants two lines between the definition and global value. when I try to run with the indent the program fails with the error.

You have misplaced the function comment:
def monster():
"""
moves the monster randomly
"""
global monster_current_room
if monster_current_room["name"] != current_room:
print('The monster is currently in', monster_current_room["name"])
exits = list(monster_current_room["exits"].values())
if random.randint(1, 4) == 4:
monster_current_room = rooms[random.choice(exits)]
elif monster_current_room["name"] == current_room:
game_over = True
or if you prefer an inline comment you can do like that
def monster(): # moves the monster randomly
global monster_current_room
if monster_current_room["name"] != current_room:
print('The monster is currently in', monster_current_room["name"])
exits = list(monster_current_room["exits"].values())
if random.randint(1, 4) == 4:
monster_current_room = rooms[random.choice(exits)]
elif monster_current_room["name"] == current_room:
game_over = True
when you write a multiline string like
"""
moves the monster randomly
"""
it has to respect the rules of the classic sentences of the python code. So you can't place them whenever you want like comments.

Related

how to avoid infinite loop when using a constructor function to create an object

# Import Modules
from Dice import dice
d10 = dice(10,1)
d4 = dice(4,1)
# Assign Classes
class Player_Character:
def __init__(self, hp, maxhp, ac, THAC0, Surprise_Adjustment, Initiative_Adjustment):
self.hp = int(hp)
self.maxhp = int(maxhp)
self.ac = int(ac)
self.THAC0 = int(THAC0)
self.Surprise_Adjustment = int(Surprise_Adjustment)
self.Initiative_Adjustment = int(Initiative_Adjustment)
def attack(self, goblin):
Player_Character_Damage = d10.die_roll()
goblin.hp -= Player_Character_Damage
if (goblin.hp <= 0):
print("congratulations you killed the goblin")
def flee(self):
print("you run away ")
quit()
def heal(self, Player_Character):
Player_Character.hp += d10.die_roll()
if Player_Character.hp >= Player_Character.maxhp:
Player_Character.hp = Player_Character.maxhp
class goblin:
def __init__(self, hp, maxhp, ac, THAC0, Surprise_Adjustment, Initiative_Adjustment):
self.hp = int(hp)
self.maxhp = int(maxhp)
self.ac = int(ac)
self.THAC0 = int(THAC0)
self.Surprise_Adjustment = int(Surprise_Adjustment)
self.Initiative_Adjustment = int(Initiative_Adjustment)
def attack(self, Player_Character):
goblin_damage = d4.die_roll()
Player_Character.hp -= goblin_damage
if (Player_Character.hp <= 0):
print("oh dear you have died")
del Player_Character
MrHezy = Player_Character(10, 20, 10, 15, 0, 2)
def spawn_goblin(goblin):
G1 = goblin(5, 10, 8, 18, 0, 0)
return G1
goblin1 = spawn_goblin(goblin)
def battle(goblin1):
# user input
player_initiative_adjustment = MrHezy.Initiative_Adjustment
monster_initiative_adjustment = goblin1.Initiative_Adjustment
#define while loop for the battle
battle_not_over = 'yes'
while battle_not_over == 'yes':
#use random.randint(a,b) to generate player and monster base initiative
player_base_initiative = d10.die_roll()
monster_base_initiative = d10.die_roll()
#subtract the adjustment to get player and monster initiative
player_initiative = player_base_initiative - player_initiative_adjustment
monster_initiative = monster_base_initiative - monster_initiative_adjustment
#compare the initiatives and display the results
if (player_initiative < monster_initiative):
attack_flee_heal = input("congratulations you go first. Would you like to attack, flee, or heal?")
while attack_flee_heal != 'attack' or 'flee' or 'heal':
if attack_flee_heal == 'attack':
MrHezy.attack(goblin1)
elif attack_flee_heal == 'heal':
MrHezy.heal(MrHezy)
print("the goblin attacks")
goblin1.attack(MrHezy)
break
elif attack_flee_heal == 'flee':
MrHezy.flee()
break
else:
print("uhoh, the monsters go first, they attack!")
goblin1.attack(MrHezy)
attack_flee_heal = input("Would you like to attack, flee, or heal? ")
while attack_flee_heal != 'attack' or 'flee' or 'heal':
if attack_flee_heal == 'attack':
MrHezy.attack(goblin1)
elif attack_flee_heal == 'heal':
MrHezy.heal(MrHezy)
print("the goblin attacks")
goblin1.attack(MrHezy)
break
elif attack_flee_heal == 'flee':
MrHezy.flee()
break
#main game loop
while True:
spawn_goblin(goblin)
battle(goblin1)
This is a code for a battle simulator that ive been working on. it starts by importing a module that i made which consists of a class called 'dice' which I use for randomly generating numbers. Defining classes is next, with attributes including hp, maxhp, armor class, 'to hit armor class 0', surprise adjustment, and initiative adjustment, and methods including attack which allows you to attack the monsters, flee which exits the battle, and heal which gives your character more hit points. The program moves on to define the spawn_goblin() function which spawns a goblin (this works just fine for the first iteration of the loop). Then it moves on to the battle part which is pretty simple; all it does is check who goes first and then allows you to attack, or flee, or heal yourself. Please ignore the "heal" and "flee" methods, these are working just fine. The problem occurs when I attack the goblin. Instead of killing the goblin and spawning another it creates an infinite loop saying "congratulations you killed the goblin"
while (goblin.hp <= 0):
print("congratulations you killed the goblin")
I think this part of your code is wrong. The while should be if, since you only want to check if the goblin has died, and run some code once. Once the goblin's HP becomes lesser than or equal to 0, the print statement will loop forever since the expression goblin.hp <= 0 will always return True.
EDIT: Now where I think your code is wrong is here:
while attack_flee_heal != 'attack' or 'flee' or 'heal':
if attack_flee_heal == 'attack':
MrHezy.attack(goblin1)
elif attack_flee_heal == 'heal':
MrHezy.heal(MrHezy)
...
I think you have missed the break in the first if (if attack_flee_heal == 'attack'
Also, it would be more appropriate to use an if here rather than a while, since, as I mentioned above, you only want to check once.

Why does this loop continuously run (asking player for their turn)?

Having an issue with the while loop for the win_checker method which I can't seem to figure out. I tried doing 2 while loops but that didn't work, so then I stuck with just one:
# Checking for win
def win_checker():
global is_game_on
if board[0] == board[1] == board[2] != "-":
print(board[0] + " won!")
is_game_on = False
# Start the game using a method
def start_game():
global is_game_on
is_game_on = True
display_board()
while is_game_on:
handle_turn_x()
win_checker()
tie_checker()
handle_turn_o()
start_game()
If I set the while loop to run only when is_game_on is True, and if my win_checker sets is_game_on to False (when appropriate), then why does the game keep going and ask the next player for its turn?
I suspect this is something to do with how I'm trying to jump out of the while loop.
Where am I wrong here?
Thanks for your help!!
The condition of the while loop is only checked when the program is "reading" the line that says
while <condition>:
I would recommend, instead of global variables, you make win_checker and tie_checker return a boolean value (True or False), and then make your while loop look like this:
while True: # run forever
handle_turn_x()
if win_checker() or tie_checker():
break # jump out of the while loop
handle_turn_o()
if win_checker() or tie_checker():
break
Globals are generally a bad idea...
instead of using a global, return True or False from that function.
Then in start_game:
def start_game():
display_board()
while True:
handle_turn_x()
if(not win_checker()):
break
tie_checker()
handle_turn_o()
start_game()
Then you can do the same for the tie checker
You could simply return is_game_on instead of modifying the global value, for example like so:
# Checking for win.
def win_checker():
if board[0] == board[1] == board[2] != "-":
print(board[0] + " won!")
return False
else
return True
# Start the game using a function.
def start_game():
while True:
handle_turn_x()
if win_checker() or tie_checker():
break
handle_turn_o()
if win_checker() or tie_checker():
break
Now this would be a little repetitive, so I think the win and tie checkers should be included to the turn handler. Something like this:
while True:
for player in ("x", "o"):
handle_turn(player)
if win_checker(player) or tie_checker():
break

Boolean condition is reading True, but the while loop still isn't breaking

For some reason the while loop is not breaking when the condition is met. The while loop should be checking for a players input to fill up a tic tac toe board until the variable "win" reads True.
Once the board reflects one of the winning conditions of tic tac toe, it assigns the variable "win" to True, and in turn should break out of the loop.
For some reason the loop isn't breaking, but the variable "win" is still reading True.
Can someone explain why the loop isn't breaking? I have tried rewriting the condition for the while loop to read "while win == False", but that doesn't seem to resolve the issue either.
I have included some of the functions I am using, and explained some of the simpler ones with a comment next to it.
I am using repl.it to do all of this online and not on a program on my local machine, so I think this may be part of the issue as well.
import os
board = ["#"," "," "," "," "," "," "," "," "," "]
def determine_win(marker):
# Winning Patterns:
# (1,2,3), (4,5,6), (7,8,9), (1,4,7), (2,5,8), (3,6,9), (3,5,7), (1,5,9)
if board[1]== board[2]==board[3]==marker:
return True
elif board[4]== board[5]==board[6]==marker:
return True
elif board[7]== board[8]==board[9]==marker:
return True
elif board[1]== board[4]==board[7]==marker:
return True
elif board[2]== board[5]==board[8]==marker:
return True
elif board[3]== board[6]==board[9]==marker:
return True
elif board[3]== board[5]==board[7]==marker:
return True
elif board[1]== board[5]==board[9]==marker:
return True
else:
return False
player1 = xo() # A Function that takes user input either "X" or O"
if player1 == "X":
player2 = "O"
else:
player2 = "X"
win = False
while not win:
display_board(board) # display_baord(board) takes the list "board" and uses it as input to display the tic tac toe board to the screen.
print("\nPlayer 1")
board[player_turn()] = player1
win = determine_win(player1)
print(win) # used to verify if win is changing
input() # used to pause the screen for troubleshooting
display_board(board)
print("\nPlayer 2")
board[player_turn()] = player2
win = determine_win(player2)
print(win) # used to verify if win is changing
input() # used to pause the screen for troubleshooting
print("Win Declared")
As the comment said, the reason is because while only check the condition of win when you finish the whole iteration of the loop. I would prefer the following way to make the code neater:
# win = False <-- you don't need this now
while True:
display_board(board) # display_baord(board) takes the list "board" and uses it as input to display the tic tac toe board to the screen.
print("\nPlayer 1")
board[player_turn()] = player1
if determine_win(player1):
print("Player 1 won")
break # break out of the loop
display_board(board)
print("\nPlayer 2")
board[player_turn()] = player2
if determine_win(player2):
print("Player 2 won")
break # break out of the loop
if not determine_win(player1):
display_board(board)
print("\nPlayer 2")
board[player_turn()] = player2
win = determine_win(player2)
# player 2 wins
else:
# player 1 wins
win = True
use something like this. It is same as #jasonharper and #Idlehands answered

Checking for a draw in Tic Tac Toe [Python]

I have this Python program that plays tic tac toe between two human players. If Player A or Player B ever wins, it is announced and the program terminates. However, if the program ends in a draw, it will keep requesting user input.
I'm not sure how to check for a draw. Does it have to be within the while loop or does it require it's own separate function?
import sys
## Define and create tic tac toe gameboard
board = range(0,9)
def show_board():
print board[0], '|', board[1], '|', board[2]
print '---------'
print board[3], '|', board[4], '|', board[5]
print '---------'
print board[6], '|', board[7], '|', board[8]
# Function used to check for winner
def line(char, box1, box2, box3):
if board[box1] == char and board[box2] == char and board[box3] == char:
return True
# Function used to automate process for checking every possible way to win
def all(char):
# Horizontal check
if line(char, 0, 1, 2):
return True
if line(char, 3, 4, 5):
return True
if line(char, 6, 7, 8):
return True
# Vertical check
if line(char, 0, 3, 6):
return True
if line(char, 1, 4, 7):
return True
if line(char, 2, 5, 8):
return True
# Diagnol check
if line(char, 0, 4, 8):
return True
if line(char, 2, 4, 6):
return True
show_board()
# Initial while loop will ask for player A input and show the board as well
# check conditions to see whether or not player A wins. If player A wins,
# the program will terminate so it does not ask for player B input after.
while True:
player_a = int(raw_input('Player A, please select a spot that is not taken \
(0-8): '))
# Checks for empty spot and places an 'X' if it exists, otherwise
# asks again.
if board[player_a] != 'X' and board[player_a] != 'O':
board[player_a] = 'X'
show_board()
# Check to see if Player A wins.
if all('X') == True:
print "Player A wins."
sys.exit()
break;
# While loop to ask for player B input and display the board as well as check
# the conditions as to whether or not player B wins. If player B wins, the
# program will terminate so it does not ask for player A input after.
while True:
player_b = int(raw_input('Player B, please select a spot that is \
not taken (0-8): '))
# Checks for empty spot and places an 'O' if it exists, otherwise
# asks again.
if board[player_b] != 'O' and board[player_b] != 'X':
board[player_b] = 'O'
# Check to see if Player B wins.
if all('O') == True:
show_board()
print "Player B wins."
sys.exit()
break;
break;
show_board()
Without extensively going through the code, I can tell you that a draw is occurs after 9 turns, and only if both Player A and B do not receive a win on that final turn. For your simple program, what I would do is create a global variable called ELAPSED_TURNS or something of the sort, that increments each time a player enters a character, and then after checking both of the players' win conditions, and if there is no win, check ELAPSED_TURNS. If it is equal to 9, then the game must be a draw.
Here's the function that does what you want.
def is_tie():
for position in board:
if isinstance(position, int):
return False
print "The game is a tie."
sys.exit()
Put a call to is_tie() directly after both while loops like this...
while True:
is_tie()
player_a = int(raw_input(...
while True:
is_tie()
player_b = int(raw_input(...
If this is a learning exercise for you I would recommend refactoring your code to find a way wrap all your logic blocks into functions and getting everything to flow without the use of sys.exit(). Doing so will increase the readability and make it easier to splice in new logic.
EDIT to your comment:
You can create an integer test function using just try / except statements like this...
def is_int(s):
try:
int(s)
return True
except ValueError:
return False
Credit here: Python: Check if a string represents an int, Without using Try/Except?
Your is_tie() function would then look like this:
def is_tie():
for position in board:
if is_int(position):
return False
print "The game is a tie."
sys.exit()

Can't break out of a while loop

I'm writing a terrible text-based adventure, and I can't figure out how to break this loop. I'll try to post the relevant stuff here. Please tell me if my comments don't adequately explain what I'm trying to do.
chained = 1
finished = 0
# home() and club() act as rooms in the game
def home():
while chained == 1:
# there's a way to unchain yourself that works
chained = 0
while chained == 0:
print 'your are in the room'
input = raw_input('> ')
if 'exit' in input or 'leave' in input or 'club' in input:
current_room = 'club'
break
def club():
print "this works"
# These sort of move you around the rooms.
# current_room keeps track of what room you're in
current_room = 'home'
while finished == 0:
if current_room == 'home':
home()
if current_room == 'club':
club()
The expected behavior is that I would enter "exit" or "leave" or "club" into the input, the home() function would end, and the club() function would start. What actually happens is that the terminal just keeps printing "you are in the room" and keeps giving me the input.
I'll post my completely unabridged code if I must, but I'd rather not, as the actual adventure isn't exactly...professional.
What break is doing is breaking out of the loop in the home() function. So when that breaks, it will go back to the beginning of
while finished == 0:
And will keep on repeating that input.
You have to also supply a break after home() (and club()):
while finished == 0:
if current_room == 'home':
home()
break
if current_room == 'club':
club()
break
Your code is extremely messy, by the way. While loops shouldn't be used for things like this (except when you're trying to get an input of exit or leave)
You may as well get rid of the final while loop.
Though I never really understood what the code was meant for here's solution that works. You haven't stated if the variable's were global or local and why would you use loops when simple if-else statements could be used
chained = 0
finished = 0
# home() and club() act as rooms in the game
def home():
global chained,current_room
if chained == 1:
# there's a way to unchain yourself that works
chained = 0
if chained == 0:
print 'your are in the room'
input = raw_input('> ')
if 'exit' in input or 'leave' in input or 'club' in input:
current_room = 'club'
club()
# Not sure if finished is a local or global variable
def club():
global finished,current_room
print "this is messy code!!"
# These sort of move you around the rooms.
# current_room keeps track of what room you're in
current_room = 'home'
if finished == 0:
if current_room == 'home':
home()
if current_room == 'club':
club()
home()
I think you need to do make the current_room a global variable. Because the variable current_room in home() and the one in while finished has different scopes.
Something like the following is what you are trying to achieve I guess. Look up on python variable scopes
chained = 1
finished = 0
current_room = 'home'
# home() and club() act as rooms in the game
def home():
global chained
# without the following line current_room has local scope and updating its value will not be
# reflected in the while at the end
global current_room
while chained == 1:
# there's a way to unchain yourself that works
chained = 0
while chained == 0:
print 'your are in the room'
input = raw_input('> ')
if 'exit' in input or 'leave' in input or 'club' in input:
current_room = 'club'
break
def club():
print "this works"
# These sort of move you around the rooms.
# current_room keeps track of what room you're in
while finished == 0:
if current_room == 'home':
home()
if current_room == 'club':
club()

Categories

Resources