I have problem with ending loop by outside function. This is for my tick tack toe game.
Below is part of my code, my function win(x) with conditions to win, and I would like it to finish the "while game" loop. I tried many ways, it does print "X wins" if conditions of win_x() are met, but the loop keeps going as by range(5)
How can I change the win_x() function to end loop?
def win_x():
global game
global win
global board_numbers
if board_numbers[30]=="X" and board_numbers[62]=="X" and board_numbers[94]=="X":
os.system('clear')
print(board_numbers)
print("X wins")
game=True
while game:
os.system('clear')
print(board_numbers)
for i in range(5):
if player_marker=="X" or player_marker=="x":
player_X()
os.system('clear')
win_x()
computer_O()
else:
os.system('clear')
computer_X()
player_O()
I kept trying and I figured it out. code looks silly but works:
def win_x():
global game
global board_numbers
if board_numbers[30]=="X" and board_numbers[62]=="X" and board_numbers[94]=="X":
os.system('clear')
print(board_numbers)
print("X wins")
game=False #placing just game=False on its own didn't help
game=True
while game:
os.system('clear')
print(board_numbers)
for i in range(5):
if player_marker=="X" or player_marker=="x":
player_X()
os.system('clear')
win_x()
if game==False: #it is still weird as game=False was in above function
break #so I am not sure why I had to state it here
computer_O()
else:
os.system('clear')
computer_X()
player_O()
Related
I have a simple Python game where two players deal some damage to each other in turns until one player has 0 or less than 0 HP. I don't like how much I've repeated myself but I'm unsure how to fix this. I thought about using a list of players but then I'm unsure how to index the next player when it's their turn, without running into the list index out of range error.
If this kind of question is not allowed please let me know and I will remove it.
Below is my game logic to determine when a player has won. I may not have pasted in the exact code I have but it runs how it's expected locally.
def check_win_state(current_player):
if current_player.get_player_health() > 0:
return True
elif current_player.get_player_health() <= 0:
return False
def main():
player1 = player.Player("Me")
player2 = player.Player("You")
while True:
if check_win_state(player1):
take_turn(player1, player2)
else:
print(f"\n{player2.get_player_name()} ({player2.get_player_health()} HP) wins! {player1.get_player_name()} has {player1.get_player_health()} HP left.\n")
break
if check_win_state(player2):
take_turn(player2, player1)
else:
print(f"\n{player1.get_player_name()} ({player1.get_player_health()} HP) wins! {player2.get_player_name()} has {player2.get_player_health()} HP left.\n")
break
The easiest approach to reduce code duplication in situations like these is to use a secondary variable to hold the primary variable. Here, instead of having different code for player1 and player2, we instead have just one code, and use the variables current_player and opposing_player to hold player1 and player2, and swap with every iteration.
def main():
player1 = player.Player("Me")
player2 = player.Player("You")
current_player = player1
opposing_player = player2
while True:
if check_win_state(current_player):
take_turn(current_player, opposing_player)
else:
print(f"\n{opposing_player.get_player_name()} ({opposing_player.get_player_health()} HP) wins! {current_player.get_player_name()} has {current_player.get_player_health()} HP left.\n")
break
current_player, opposing_player = opposing_player, current_player
If you have more than two players, then a more extensible approach might be to have a list of players, and have an index rotate through the list with each iteration to specify which player is the 'current' one.
also, you can simplify check_win_state():
def check_win_state(current_player):
return current_player.get_player_health() > 0
because the check a > b returns a boolean anyway.
You can make the first function short using this logic:-
def check_win_state(current_player):
return current_player.get_player_health() > 0:
And now you can create another function to do the work of inside while loop
def work_in_while(pl, another_pl):
if check_win_state(pl):
take_turn(pl, another_pl)
else:
print(f"\n{another_pl.get_player_name()} ({another_pl.get_player_health()} HP) wins! {pl.get_player_name()} has {pl.get_player_health()} HP left.\n")
return "kill"
And use it like:-
while True:
if work_in_while(player1, player2) == "kill":
break
if work_in_while(player2, player1) == "kill":
break
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
Hello I am just starting to try to teach my self python and with one of the resources I read, I saw this dice game to make. So I did the basic but then I wanted to make it more full. My idea was to add a loop and have after each round it would prompt the user to enter at first q but now 0 to try to determine if it is an error in my input.
def gamestate():
print('enter 0 if you would like to quit anything else to continue')
game = input()
print(game == 0) # diagnostic to check if value is correct
print(type(game)) #diagnostic to make sure type is correct
print(game != str(0))
def play():
print('do you want to play a game enter yes to start')
game = '1' #filler value
game=input()
str(game)
if game == "yes": #confirms start of the game
Dice()
else:
print('Ok Goodbye') #plays game anyways will fix after loop issue
gamestate()
______________________________________________________________
while game !=str(0): #cannot escape loop for some reason
if game == str(0) :
break #to break
Dice()
gamestate()
print('ok good bye')
___________________________________________________________
play()
First, sorry if code long for this, but what I expect is 0 as an input to break the loop, what I get is having to kill my console process in spyder in order to stop this from looping
You have the variable name game at 2 different variable scopes and so they have different state. Try returning a game from gamestate() and comparing the value
Short description of the scoping rules?
def gamestate():
print('enter 0 if you would like to quit anything else to continue')
game = input()
print(game == 0) # diagnostic to check if value is correct
print(type(game)) #diagnostic to make sure type is correct
print(game != str(0))
return game
while game !=str(0): #cannot escape loop for some reason
if gamestate() == str(0) :
break #to break
Dice()
print('ok good bye')
You have to return game value from gamestate function and assign it in while loop. Check below code:
def gamestate():
print('enter 0 if you would like to quit anything else to continue')
game = input()
print(game == 0) # diagnostic to check if value is correct
print(type(game)) #diagnostic to make sure type is correct
print(game != str(0))
return game
def play():
print('do you want to play a game enter yes to start')
game = '1' #filler value
game=input()
str(game)
if game == "yes": #confirms start of the game
Dice()
else:
print('Ok Goodbye') #plays game anyways will fix after loop issue
gamestate()
while game !=str(0): #cannot escape loop for some reason
if game == str(0) :
break #to break
Dice()
game = gamestate()
print('ok good bye')
play()
In order to compare with zero as a string you need merely do something like if game == "0":. The issue you may be running into is that of extra whitespace chars like "\n". If you use input().trimspace() you'll remove extraneous chars and do comparisons with the values you want to.
Also another problem in the code is that it will enter the while loop if game does not equal "0" and so the if condition that follows will automatically not be met. So break is never hit.
You need to modify your program to convert input to int and not converting 0 to string at multiple places.changes needs to be done in while loop and gamestate function
I am writing a rock, paper, scissors game in Python but my code doesn't work as it should. I'm new to Python so please let me know if my code isn't formatted corectly. The game runs fine, assuming you enter one of the already existing answers. However, if you enter one that is different, the code seems to loop randomly after the 'end()' function is executed.
Here is my code:
# imports needed files
from random import randint
import time
# creates a function that ends the game
def end(cpuScore,playerScore):
time.sleep(1)
cont = input("Would you like to play again? (y or n)\n")
if cont=="y":
time.sleep(1)
start()
else:
print("Well... That's a bit rude.")
# creates a function to play the game
def rps(cpuScore,playerScore,num):
# loops code 3 times (unless 'num' is different)
for x in range(num):
num-=1
# creates options
options = ["rock","paper","scissors"]
# picks a random choice for cpu
cpu = options[randint(0,2)]
# asks the player to choose
player = input("rock, paper or scissors?\n")
# why not gun?
if player=="gun":
result = "w"
elif player==cpu:
result = "d"
elif player=="rock":
if cpu=="paper":
result = "l"
if cpu=="scissors":
result = "w"
elif player=="paper":
if cpu=="scissors":
result = "l"
if cpu=="rock":
result = "w"
elif player=="scissors":
if cpu=="rock":
result = "l"
if cpu=="paper":
result = "w"
# if they choose something other than rock, paper, scissors or gun
else:
print("That's an invalid input!")
# adds one to num so that this round is not counted as one of the 3
num+=1
# plays the game again with the amount of rounds remaining
rps(cpuScore,playerScore,num)
# tells the player how they did
if result=="w":
playerScore+=1
time.sleep(1)
print("Fine! You win! Your silly " + player + " beat my " + cpu + "!!!")
if result=="l":
cpuScore+=1
time.sleep(1)
print("Ha! Sucker!! My epic " + cpu + " smashed your measly " + player + "!!!")
if result=="d":
time.sleep(1)
print("Ah! We drew by both choosing %s! Like they say, great minds think alike!" % cpu)
# announces the scores
print("You are on %s and the computer is on %s!" % (playerScore,cpuScore))
# ends the game after 3 rounds
end(cpuScore,playerScore)
# creates the funtion that sets the variables and starts the game
def start():
result=""
cont=""
cpuScore=0
playerScore=0
rps(cpuScore,playerScore,3)
# begins the game
start()
Thanks
Basically your rps function loops num times, with num = 3 initially. If the user enters an incorrect input, you call back the function, which starts the whole process again, in a new context, for num+1 times.
Thus if you answer wrong the first time you have at least six games to play: four new added and the two initial ones you didn't try to play.
My advice try first to do a program that do one and only one iteration of the rock-paper-scissor game. Adding more iteration is a simple fact of adding a global loop.
Ok so im working on a basic dice game, But when it gets to the while loop it doesnt print the message inside, The message is just a placeholder.
dicenumber = None
numberchoice = None
ready = None
test = "Lol"
class playerClass():
points = 0
class enemyClass():
point = 0
def rolldice():
dicenumber = dicenumber.randint(1,9)
def start():
print("Hello welcome to the dice game.")
print("The goal of the game is to guess what number the dice will land on.")
print("The option are 1 to 6 and the game is won by getting 3 points.")
print()
print("Are you ready to play?")
print("1 - Yes")
print("2 - No")
ready = int(input())
start()
while ready == 1:
print("hello")
Use global inside your start function. Also, as you were trying to put while ready==1, it will be in infinite loop!
dicenumber = None
numberchoice = None
ready = None
test = "Lol"
class playerClass():
points = 0
class enemyClass():
point = 0
def rolldice():
dicenumber = dicenumber.randint(1,9)
def start():
global ready
print("Hello welcome to the dice game.")
print("The goal of the game is to guess what number the dice will land on.")
print("The option are 1 to 6 and the game is won by getting 3 points.")
print()
print("Are you ready to play?")
print("1 - Yes")
print("2 - No")
ready = int(input())
start()
while ready == 1:
print("hello")
When you access ready inside the start() method, you are accessing it as a local variable. Python assumes that all variables you use are local, not global. Put global ready in the start() method before you set the ready variable. This will tell python to access ready as a global variable.
There is a scoping issue. ready variable defined in a global scope is not updated inside the start() function.
Simple demo of what is happening:
>>> ready = None
>>> def start():
... ready = 1
...
>>> start()
>>> print ready
None
Better return ready variable from the start():
def start():
print("Hello welcome to the dice game.")
print("The goal of the game is to guess what number the dice will land on.")
print("The option are 1 to 6 and the game is won by getting 3 points.")
print()
print("Are you ready to play?")
print("1 - Yes")
print("2 - No")
return int(input())
ready = start()
You can also make it global as #S.M. Al Mamun suggested, but i would not recommend it. Global variables are needed for sharing data, state between functions. In this case there is no need for it - your start() function defines a value for the ready variable. It is a single one place where ready is defined - no need to make it global. start() is an entry point and it would be a good idea to return a "state" (ready variable) from it.
See also:
Short Description of the Scoping Rules?
ready is defined in the global scope, but you are setting it in the local scope of the start function. Also, your rolldice function returns a number from 1 to 9 instead of 1 to 6.
from random import randint
class Player:
def __init__(self, name):
self.name = name
self.points = 0
self.won = False
def add_point(self):
self.points += 1
self.won = True
print('''
Hello welcome to the dice game.
The goal of the game is to guess what number the dice will land on.
The options are 1 to 6 and the game is won by getting 3 points.
Are you ready to play?
0 - No
1 - Yes'''
ready = int(input())
if ready:
players = []
number_of_players = int(input('How many players? '))
for i in range(number_of_players):
name = input('What is the name of player {}?'.format(i+1))
players.append(Player(name))
winners = []
while ready:
random_number = randint(1, 6)
for player in players:
guess = int(input('What is your guess, {}?'.format(player.name)))
if guess == random_number:
player.add_point()
if player.won:
winners.append(player.name)
if winners:
print('Winners: {}'.format(', '.join(winners)))
break
You are accessing a variable(ready) which was defined originally as a global variable, then you are accessing it in your start function without mentioning in your code('start' function) that is a global variable and finally in your while loop you are again trying to access a variable which you assume it has a value assigned to it.
The other thing is you while loop. when you set ready==1, you need to some where break from your loop if you don't want it to be infinite loop.