Posts: 13
Threads: 8
Joined: Sep 2023
Sep-30-2023, 06:34 PM
(This post was last modified: Sep-30-2023, 06:34 PM by Radical.)
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)
Posts: 6,756
Threads: 20
Joined: Feb 2020
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++
Posts: 4,775
Threads: 76
Joined: Jan 2018
Oct-01-2023, 06:11 AM
(This post was last modified: Oct-01-2023, 06:11 AM by Gribouillis.)
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', ...}
Posts: 6,756
Threads: 20
Joined: Feb 2020
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)
Posts: 4,775
Threads: 76
Joined: Jan 2018
Oct-01-2023, 01:26 PM
(This post was last modified: Oct-01-2023, 01:26 PM by Gribouillis.)
(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.
Posts: 6,756
Threads: 20
Joined: Feb 2020
Oct-02-2023, 12:57 AM
(This post was last modified: Oct-02-2023, 12:57 AM by deanhystad.)
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.
|