So, im making a tic-tac-toe game and im nearly finished i think. im trying to make it so the game can be played more than just once before it ends. So i put it into a def() function… but running it results in NameError: name 'turn' is not defined. Any ideas why and how to fix this?
def game():
blanksheet = "|1|2|3|\n|4|5|6|\n|7|8|9|"
sheet = blanksheet
print(sheet)
gone = []
turn = 0
def play(XO,player,listXO):
global turn
global sheet
global listx
global listo
while True:
num = input(player+" enter an available number where you want to put an "+XO+".\n > ")
try:
num = int(num)
except ValueError:
print("Not a valid number, try again.")
continue
if num < 1 or num > 9:
print("Number not in correct range, try again.")
continue
if num in gone:
print("Number already used, try again.")
continue
gone.append(num)
listXO.append(num)
turn += 1 #the "problem is here"
sheet = sheet.replace(str(num),XO)
print(sheet)
break
win = "h"
listx = []
listo = []
def checkstatus(listXO, playerwin):
if len(listXO) >= 3:
if 1 in listXO and 2 in listXO and 3 in listXO:
winspeak(playerwin) #vertical
elif 4 in listXO and 5 in listXO and 6 in listXO:
winspeak(playerwin) #vertical
elif 7 in listXO and 8 in listXO and 9 in listXO:
winspeak(playerwin) #vertical
elif 1 in listXO and 4 in listXO and 7 in listXO:
winspeak(playerwin) #horizontal
elif 2 in listXO and 5 in listXO and 8 in listXO:
winspeak(playerwin) #horizontal
elif 3 in listXO and 6 in listXO and 9 in listXO:
winspeak(playerwin) #horizontal
elif 1 in listXO and 5 in listXO and 9 in listXO:
winspeak(playerwin) #diagonal
elif 3 in listXO and 5 in listXO and 7 in listXO:
winspeak(playerwin) #diagonal
if (len(listx) + len(listo)) == 9:
print("\n Neither player wins, thats a tie!")
exit()
def winspeak(player):
print("\n"+player+" wins!")
exit()
def checkplay():
while win != "Xwin" or win != "Owin":
if turn % 2 == 0:
play("X","Player 1",listx)
checkstatus(listx,"Player 1")
else:
play("O","Player 2",listo)
checkstatus(listo,"Player 2")
checkplay()
game()
Why are your other functions defined inside game()? There are occasionally reasons to do this (like closures), but I don’t think they apply here.
You’ve told play() that it should find turn as a global variable. But you’ve never created a global variable with that name. You’ve created turn above it, but that one is inside game(), so it’s local to that function.
So the variable in game() is local, while the variable in play() is global.
I would probably take turn out of play(). It doesn’t seem to need it. Have the caller increment it when play() returns.
I honestly don’t know why I put the other functions in game()… Ill put them in a while loop, but I dont really know what condition. Doing that would solve the other errors right?
You’ve told play() that it should find turn as a global variable. But you’ve never created a global variable with that name. You’ve created turn above it, but that one is inside game(), so it’s local to that function.
So the variable in game() is local, while the variable in play() is global.
I would probably take turn out of play(). It doesn’t seem to need it. Have the caller increment it when play() returns.
Those aren’t “other errors”, they’re an attempt to explain what is currently happening in your code.
You need to decide if you’re going to be using a global variable or not. If you are, then the variable has to be assigned in global scope. (Either outside any function, or in a function where it’s declared global).
It may not need to be a global if the only other place it is used is in play(). My recommendation is to
Remove the nested function definitions. They’re not making your code clearer.
Remove turn from play(). Put that logic elsewhere. Now play() doesn’t need to modify it and you don’t have to make it a global variable.
Remember that Python uses indentation to tell what is inside a function
and what is outside it. You should define your functions at the top of
you file. Each function should start at level 1 (unindented) like this:
def game():
# block is indented
# don't indent the function signature
def play(XO, player, listXO):
# block is indented
# Finally at the end:
game() # not indented
Don’t indent functions inside other functions.
Leave a nice space (two lines) between functions to make it easier to
spot when one ends and the next begins. That makes no difference to the
Python interpreter, but it helps the reader (you) spot where one
function ends and the next begins.
Constants that never change should be defined at the top of your
program, before the functions. It is the convention to write them in
all capitals so the reader knows that they should never change:
BLANKSHEET = "|1|2|3|\n|4|5|6|\n|7|8|9|\n"
Your global variables should be defined in the game() function:
Simply because it isn’t needed. play()'s job seems to be to ask the player where they want to move in the game. It needs to know what moves have happened before (so it can not duplicate them), what are valid moves, etc. And then it returns the chosen move to the caller.
But it doesn’t matter whose turn it is. The only thing it uses the variable for is to update it when the play is made. Well, the caller could do that just as well. That makes play() shorter and more single-purpose. That makes it easier to write correctly and debug.
It’s not required at all. You could certainly pass turn between them, or set it up as a global variable. But reducing the scope of where things are used is usually best.