Python Forum
It's saying my global variable is a local variable
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
It's saying my global variable is a local variable
#1
EDIT: Okay I found this video that explains the issue well: https://www.youtube.com/watch?v=qsf_pM9Ge_g
but this issue does not exist in C++. So what is different about Python?


I was creating a little test to check if the pieces listed were part of a valid chess set. But I am getting an error when i call on pawnCounter in my function. It says "UnboundLocalError: cannot access local variable 'pawnCounter' where it is not associated with a value". But.... it's not a local variable. It is in the global scope; I defined it right at the beginning of my project:
pieces = {'wqueen': 'a6', 'wrook': 'g2', 'wking': 'a5', 'bpawn': 'b4', 'bking': 'h6', 'brook': 'a4'}
pawnCounter = 0

def isValidChessBoard():
    for piece in pieces:
        if 'pawn' in piece:
            pawnCounter += 1
        
        if piece[0] != 'w' and piece[0] != 'b'\
        or piece[1:] not in ('queen', 'pawn', 'rook', 'king', 'bishop', 'knight')\
        or pawnCounter > 16:
            return False
    return True
I looked online for help, and I found some advice saying to put "pawnConuter = pawnCounter" in the function parameters, like so:
def isValidChessBoard(pawnCounter = pawnCounter):
or putting "global pawnCounter" at the start of the function:
def isValidChessBoard():
    global pawnCounter
and these do work. But I shouldn't have to do this, and it's too tedious to do every time for every variable. I don't understand why it's necessary. What is going on here? (P.S. This logic works in C++ without issue or needing to specify a global scope)
Reply
#2
Python allows creating variables during runtime. Assignment creates a new variable if the variable does not exist. In C++ variables are compiled into the program and no new variables can be made during runtime. In C++, the scope of every variable is known because you specified the scope in the code. In Python there are rules that specify the scope of a variable. The python rule is to create variables in the local local scope unless otherwise specified.

You should stop looking for parallels between Python and C++ and start looking for the differences. Learn why you might want to use Python or C++ for a particular project instead of trying to write python programs that look like they were written in C++
Reply
#3
Another problem with your code is that keys are unique in Python dictionaries, while in a chess game you can have two or more 'wbishop' or 'bpawn'. This cannot be the case in a Python dictionary. A solution would be to use a list
[('wbishop', 'a3'), ('bpawn', 'g7'), ('bpawn', 'h6'), ...]
Also the squares are unique on a chessboard, so you could use a reversed dictionary
{'a3': 'wbishop', 'g7': 'bpawn', 'h6': 'bpawn', ...}
Reply
#4
I would write something like this:
from collections import defaultdict


piece_counts = {"queen": 1, "pawn": 8, "rook": 2, "king": 1, "bishop": 2, "knight": 2}
valid_squares = [f"{r}{c}" for r in "abcdefgh" for c in "12345678"]
valid_pieces = [color+name for color in "bw" for name in piece_counts]
 

def is_valid_chessboard(board):
    count = defaultdict(lambda: 0)
    for s, p in board.items():
        count[p] += 1
        if s not in valid_squares or p not in valid_pieces or count[p] > piece_counts[p[1:]]:
            return False
    return count["wking"] + count["bking"] > 0


boards = (
    {"a6": "wqueen", "g2": "wrook", "a5": "wking", "b4": "bpawn", "h6": "bking", "a4": "brook"},
    {"6a": "wqueen", "g2": "wrook", "a5": "wking", "b4": "bpawn", "h6": "bking", "a4": "brook"},
    {"a6": "queen", "g2": "wrook", "a5": "wking", "b4": "bpawn", "h6": "bking", "a4": "brook"},
    {"a6": "wqueen", "g2": "wrook", "a5": "wqueen", "b4": "bpawn", "h6": "bking", "a4": "brook"},
    {"a6": "wqueen", "g2": "wrook", "b4": "bpawn", "a4": "brook"},
)

for board in boards:
    print(is_valid_chessboard(board), board)
Reply
#5
(Oct-01-2023, 11:31 AM)deanhystad Wrote: I would write something like this:
It doesn't work exactly like this because pawns can be promoted into other pieces, which means that theoretically, you could have 4 knights and 3 rooks for example.
Reply
#6
I'm grew up playing where you could only promote pawns to pieces you had lost. A non-rule enforced by not having extra pieces laying around.

This makes things tougher. Will need to recompute piece counts after counting pawns. Also need to count number of white and black pieces to verify they don't exceed 16.
from collections import defaultdict


piece_counts = {"queen": 1, "pawn": 8, "rook": 2, "king": 1, "bishop": 2, "knight": 2}
valid_squares = [row+col for row in "abcdefgh" for col in "12345678"]
valid_pieces = [color+name for color in "bw" for name in piece_counts]
 

def is_valid_chessboard(board):
    # Count the pieces
    black = defaultdict(lambda: 0)
    white = defaultdict(lambda: 0)
    for s, p in board.items():
        if s not in valid_squares or p not in valid_pieces:
            return False
        elif p[0] == 'b':
            black[p[1:]] += 1
        else:
            white[p[1:]] += 1

    # Check counts don't exceed allowable values.
    for color in (black, white):
        if sum(color.values()) > 16 or color['pawn'] > 8 or color['king'] > 1:
            return False

        promotions = sum(color[p] - piece_counts[p] for p in color if p != "pawn")
        if promotions > 8 - color["pawn"]:
            return False

    return black["king"] > 0 or white["king"] > 0


boards = (
    {"a6": "wqueen", "g2": "wrook", "a5": "wking", "b4": "bpawn", "h6": "bking", "a4": "brook"},
    {"6a": "wqueen", "g2": "wrook", "a5": "wking", "b4": "bpawn", "h6": "bking", "a4": "brook"},
    {"a6": "queen", "g2": "wrook", "a5": "wking", "b4": "bpawn", "h6": "bking", "a4": "brook"},
    {"a6": "wqueen", "g2": "wrook", "a5": "wqueen", "b4": "bpawn", "h6": "bking", "a4": "brook"},
    {"a6": "wqueen", "g2": "wrook", "b4": "bpawn", "a4": "brook"},
    {"a6": "wking"},
    {"a6": "wking", "a7": "wking"},
    {"a6": "wking", "b1": "wpawn", "b2": "wpawn", "b3": "wpawn", "b4": "wpawn", "b5": "wpawn", "b6": "wpawn", "b7": "wpawn", "b8": "wpawn"},
    {"a6": "wking", "b1": "wpawn", "b2": "wpawn", "b3": "wpawn", "b4": "wpawn", "b5": "wpawn", "b6": "wpawn", "b7": "wpawn", "b8": "wpawn", "c1": "wpawn"},
    {"a6": "wking", "b1": "wqueen", "b2": "wqueen", "b3": "wqueen", "b4": "wqueen", "b5": "wqueen", "b6": "wqueen", "b7": "wqueen", "b8": "wqueen", "c1": "wqueen"},
    {"a6": "wking", "b1": "wqueen", "b2": "wqueen", "b3": "wqueen", "b4": "wqueen", "b5": "wqueen", "b6": "wqueen", "b7": "wqueen", "b8": "wqueen", "c1": "wqueen", "c2": "wqueen"},
)

for board in boards:
    print(is_valid_chessboard(board), board)
The code does not account for lost pawns, which makes it useless.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Help with writing monitored data to mysql upon change of one particular variable donottrackmymetadata 3 305 Apr-18-2024, 09:55 PM
Last Post: deanhystad
  Commas issue in variable ddahlman 6 461 Apr-05-2024, 03:45 PM
Last Post: deanhystad
  Variable Explorer in spyder driesdep 1 235 Apr-02-2024, 06:50 AM
Last Post: paul18fr
  Mediapipe. Not picking up second variable stevolution2024 1 196 Mar-31-2024, 05:56 PM
Last Post: stevolution2024
Question Variable not defined even though it is CoderMerv 3 299 Mar-28-2024, 02:13 PM
Last Post: Larz60+
  optimum chess endgame with D=3 pieces doesn't give an exact moves_to_mate variable max22 1 283 Mar-21-2024, 09:31 PM
Last Post: max22
  unbounded variable akbarza 3 508 Feb-07-2024, 03:51 PM
Last Post: deanhystad
  Variable for the value element in the index function?? Learner1 8 668 Jan-20-2024, 09:20 PM
Last Post: Learner1
  Variable definitions inside loop / could be better? gugarciap 2 448 Jan-09-2024, 11:11 PM
Last Post: deanhystad
  working directory if using windows path-variable chitarup 2 743 Nov-28-2023, 11:36 PM
Last Post: chitarup

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020