Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

List not defined in a function in Python

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.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

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

>Solution :

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, which makes it easier to change and extend.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading