I am working on one of my first codes (Tic Tac Toe), and I cannot figure out why I'm getting a name error.
First I have a list (board).
Then I have a function (possible_victory_for() ) that I define. It is supposed to to something with a list (temp_board) that will be defined later, within the next function.
The next function (computer_move() ) says temp_board = board and then calls the possible_victory_for().
In my understanding, seeing as "board" seems to work fine, the temp_board = board should be enough of a definition for temp_board. But Python disagrees.
I tried to recreate the error on a simple example, like this:
board = [1, 2, 3]
temp_board = board
if temp_board[0] == 1:
print("it works")
But this works fine and doesn't produce the error. So maybe it's something related to communication between functions (or simply a typo somewhere)?
As I fail to shorten the code and get the same error, I am attaching everything I made for now. Sorry for a long post.
(if you decide to run the code, go for Medium difficulty, that's where the error happens).
# I need these functions to make everything work
# clear_output was imported by Google Colab, not sure if it's standard
# all mentions of clear_output can be deleted if needed, the code will work
# but it will show every turn made by computer/human, not just the current board
from IPython.core.display import clear_output
from random import randrange
# Sets the board at the beginning
board = [1, 2, 3, 4, 5, 6, 7, 8, 9]
# Just displays the current board
def display_board():
print(
"\n ------- ------- ------- ",
"\n| | | |",
"\n| ",board[0]," | ",board[1]," | ",board[2]," |",
"\n| | | |",
"\n ------- ------- ------- ",
"\n| | | |",
"\n| ",board[3]," | ",board[4]," | ",board[5]," |",
"\n| | | |",
"\n ------- ------- ------- ",
"\n| | | |",
"\n| ",board[6]," | ",board[7]," | ",board[8]," |",
"\n| | | |",
"\n ------- ------- ------- "
)
# Asks player to define who plays first (human or computer). Impacts the order of turns.
def who_plays_first():
global first_player
while True:
first_player = int(input("Choose who plays first: 1 for human, 2 for computer"))
if first_player == 1 or first_player == 2:
break
print("invalid input, read the instruction")
if first_player == 1:
first_player = "human"
else:
first_player = "computer"
return(first_player)
# Asks player to set difficulty. Impacts how computer decides on its move.
def choose_difficulty():
global difficulty
while True:
difficulty = int(input("Choose difficulty: 1 = easy, 2 = medium, 3 = hard"))
if difficulty == 1 or difficulty == 2 or difficulty == 3:
break
print("invalid input, read the instruction")
if difficulty == 1:
difficulty = "easy"
elif difficulty == 2:
difficulty = "medium"
else:
difficulty = "hard"
return(difficulty)
# Makes a list of free fields. Used in other functions.
def make_list_of_free_fields():
list_of_free_fields = []
for field in range(1,10):
if field in board:
list_of_free_fields.append(field)
return(list_of_free_fields)
# Checks whether the player (defined by the sign) won.
def victory_for(sign):
if (board[0] == sign and board[1] == sign and board[2] == sign or
board[3] == sign and board[4] == sign and board[5] == sign or
board[6] == sign and board[7] == sign and board[8] == sign or
board[0] == sign and board[3] == sign and board[6] == sign or
board[1] == sign and board[4] == sign and board[7] == sign or
board[2] == sign and board[5] == sign and board[8] == sign or
board[0] == sign and board[4] == sign and board[8] == sign or
board[2] == sign and board[4] == sign and board[6] == sign):
return True
else:
return False
# Same as victory_for, but only used to help computer make its move on medium/hard.
def possible_victory_for(sign):
if (temp_board[0] == sign and temp_board[1] == sign and temp_board[2] == sign or
temp_board[3] == sign and temp_board[4] == sign and temp_board[5] == sign or
temp_board[6] == sign and temp_board[7] == sign and temp_board[8] == sign or
temp_board[0] == sign and temp_board[3] == sign and temp_board[6] == sign or
temp_board[1] == sign and temp_board[4] == sign and temp_board[7] == sign or
temp_board[2] == sign and temp_board[5] == sign and temp_board[8] == sign or
temp_board[0] == sign and temp_board[4] == sign and temp_board[8] == sign or
temp_board[2] == sign and temp_board[4] == sign and temp_board[6] == sign):
return True
else:
return False
# Asks the human player to make their move.
def human_move():
while True:
human_input = int(input("Choose a field"))
if human_input in make_list_of_free_fields():
break
print("You must choose one of the free fields on the board by typing 1-9")
board[human_input-1] = "O"
# This is how the computer makes its move.
# Depends on the difficulty.
# Easy is completely random.
# Medium checks whether:
# a) there's a (list of) move(s) that could guarantee computer's victory
# b) there's a (list of) move(s) that could guarantee human's victory
# - then play a random move out of that list (computer victory has priority)
# Hard is yet to be defined.
def computer_move():
if difficulty == "easy":
while True:
computer_input = randrange(10)
if computer_input in make_list_of_free_fields():
break
board[computer_input-1] = "X"
# elif difficulty == "medium":
else:
brings_computer_victory = []
brings_human_victory = []
for field in make_list_of_free_fields():
temp_board = board
temp_move = field
temp_board[temp_move-1] = "X"
if possible_victory_for("X") == True:
brings_computer_victory.append(temp_move)
if brings_computer_victory != []:
computer_input = randrange(1, len(brings_computer_victory) 1)
board[computer_input-1] = "X"
for field in make_list_of_free_fields():
temp_board = board
temp_move = field
temp_board[temp_move-1] = "O"
if possible_victory_for("O") == True:
brings_human_victory.append(temp_move)
if brings_human_victory != []:
computer_input = randrange(1, len(brings_human_victory) 1)
board[computer_input-1] = "X"
# This is the final piece of code that connects all the functions.
who_plays_first()
choose_difficulty()
clear_output()
if first_player == "human":
display_board()
while True:
human_move()
clear_output()
display_board()
if victory_for("O") == True:
print("You won!")
break
if len(make_list_of_free_fields()) == 0:
print("it's a tie")
break
computer_move()
clear_output()
display_board()
if victory_for("X") == True:
print("You lost!")
break
else:
while True:
computer_move()
clear_output()
display_board()
if victory_for("X") == True:
print("You lost!")
break
if len(make_list_of_free_fields()) == 0:
print("it's a tie")
break
human_move()
clear_output()
display_board()
if victory_for("O") == True:
print("You won!")
break
Here's the error traceback:
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-11-322daee905b6> in <module>
28
29 while True:
---> 30 computer_move()
31 clear_output()
32 display_board()
1 frames
<ipython-input-10-6530342ed281> in computer_move()
24 temp_move = field
25 temp_board[temp_move-1] = "X"
---> 26 if possible_victory_for("X") == True:
27 brings_computer_victory.append(temp_move)
28 if brings_computer_victory != []:
<ipython-input-8-bd71fed33fb4> in possible_victory_for(sign)
1 # Same as victory_for, but only used to help computer make its move on medium/hard.
2 def possible_victory_for(sign):
----> 3 if (temp_board[0] == sign and temp_board[1] == sign and temp_board[2] == sign or
4 temp_board[3] == sign and temp_board[4] == sign and temp_board[5] == sign or
5 temp_board[6] == sign and temp_board[7] == sign and temp_board[8] == sign or
NameError: name 'temp_board' is not defined
CodePudding user response:
temp_board
is local to computer_move
, but you're treating it as if it were a global. You should make it a parameter to possible_victory_for
:
def possible_victory_for(sign, temp_board):
# if (temp_board[0] ...
and then pass it from computer_move
as an argument:
if possible_victory_for("X", temp_board) == True:
In general I'd recommend passing variables to your functions as arguments rather than relying on pulling them implicitly from an outer scope; it makes the dependencies between different parts of your code more obvious (in this case possible_victory_for
depends on not only sign
but the current values of temp_board
), which makes it easier to change and extend.