1

I have the following piece of code that presented below with tic-tac-toe implementation. As far as I understand variable "player" is global one and it's value 'X' should be accessed from any place of the program.

board = [['_' for x in range(3)] for y in range(3)]
player = 'X'

def print_board():
    for row in board:
        print(row)

def check_win():
    for i in range(3):
        if board[i][0] == board[i][1] == board[i][2] != '_':
            return board[i][0]
        if board[0][i] == board[1][i] == board[2][i] != '_':
            return board[0][i]
    if board[0][0] == board[1][1] == board[2][2] != '_':
        return board[0][0]
    if board[0][2] == board[1][1] == board[2][0] != '_':
        return board[0][2]
    return None

def greet():
    while True:
        print_board()
        print(f"Player {player}, make your move (row column): ")
        row, col = map(int, input().split())
        if board[row][col] != '_':
            print("Invalid move, try again.")
            continue
        board[row][col] = player
        winner = check_win()
        if winner:
            print_board()
            print(f"Player {winner} wins!")
            break
        if "_" not in [cell for row in board for cell in row]:
            print_board()
            print("Tie!")
            break
        player = 'X' if player == 'O' else 'O'

greet()

But as a result I got the error: print(f"Player {player}, make your move (row column): ") UnboundLocalError: local variable 'player' referenced before assignment. How to declare global variables in a correct way in Python?

What I'm doing wrong?

I expected the code of tic-tac-toe working correctly but it didn't. To resolve the issue I tried to change "player" scope and moved an assignment inside greet() method before infinite loop. It works perfect, but I have no clue why it didn't work before, as a global variable.

  • You mentioned ... *To resolve the issue I tried to change "player" scope and moved an assignment inside greet() method before infinite loop. It works perfect, but I have no clue why it didn't work before, as a global variable.* Could you show snippet of this section of code that works. That will enrich your question. Inbtw, you might simply have a scope problem – semmyk-research Jan 29 '23 at 06:56

4 Answers4

4

You "declare" it outside the the functions as you did here. But you're missing the global keyword.

Then:

  • If you only read its value inside a function, it's treated as a global variable.

    variable_name = "old value"
    
    def function():
        print(variable_name)
    
    function()  # old value
    print(variable_name)  # old value
    
  • Normally, if you write to it, it's treated as a local variable.

    variable_name = "old value"
    
    def function():
        variable_name = "new value"
        print(variable_name)
    
    function()  # new value
    print(variable_name)  # old value
    
  • To write to it as a global variable, add the global keyword in the function definition before using the variable.

    variable_name = "old value"
    
    def function():
        global variable_name
        variable_name = "new value"
        print(variable_name)
    
    function()  # new value
    print(variable_name)  # new value
    

Source: https://docs.python.org/faq/programming.html#what-are-the-rules-for-local-and-global-variables-in-python

eccentricOrange
  • 876
  • 5
  • 18
3

If a function assigns to a variable name (which your greet() function does for the player variable), then that variable name is treated as local everywhere in the function, even if there is a global variable of the same name.

If you want the function to use the global variable, put this at the top of the function:

global player

By contrast, your print_board() function does not assign to a variable named board, therefore it is able to use that global variable without explicitly declaring global board.

John Gordon
  • 29,573
  • 7
  • 33
  • 58
1

To declare a global variable you simply need to add a line above the declerration saying global followed by the name of the variable.

E.g:

global name
name = "daniel"
Amen
  • 69
  • 8
0

You 'declare' a variable player and assigned it a string value X.
player = 'X'

You then 'reference' this variable within a function that doesn't have the variable passed to it as argument).
If you go through the full error code you received, you'll note the offending line of code.
PS: you only paste the specific part of the error (which is fine though).

To resolve this, within the function greet(), simply declare global player

Pls, read more on UnboundLocalError, on local and global variables.
Also, do check a previous question with is incidentally a duplicate of another question! Why does this UnboundLocalError occur (closure)?

[Additions] With that said, I'll strongly recommend that you wrapped up your functions within a class. It'll come up handy in referencing your variables, assigning values to them, keeping state through self.
Also, give due thoughts to try, error handling especially around input(), and board assigning.

board = [['_' for x in range(3)] for y in range(3)]
player = 'X'

def print_board():
    for row in board:
        print(row)

def check_win():
    for i in range(3):
        if board[i][0] == board[i][1] == board[i][2] != '_':
            return board[i][0]
        if board[0][i] == board[1][i] == board[2][i] != '_':
            return board[0][i]
    if board[0][0] == board[1][1] == board[2][2] != '_':
        return board[0][0]
    if board[0][2] == board[1][1] == board[2][0] != '_':
        return board[0][2]
    return None

def greet():
    global player. ##add to resolve UnboundLocalError
    while True:
        print_board()
        print(f"Player {player}, make your move (row column): ")
        row, col = map(int, input().split())
        if board[row][col] != '_':
            print("Invalid move, try again.")
            continue
        board[row][col] = player
        winner = check_win()
        if winner:
            print_board()
            print(f"Player {winner} wins!")
            break
        if "_" not in [cell for row in board for cell in row]:
            print_board()
            print("Tie!")
            break
        player = 'X' if player == 'O' else 'O'

print(f'player outside greet() | {player}')
greet()
semmyk-research
  • 333
  • 1
  • 9