Im making a chess game in python and was trying to generate the legal moves of each piece using 'if' statements to see if the space the player wants to move to is free and if the move is actually within the borders of the board. The problem is that there are too many 'if' statements as well as nested 'if' statements. This really makes my file look like spaghetti code and over-complicates the process.
Here is an example:
def valid_moves(self, board):
i = self.row
j = self.col
moves = []
if i > 0:
# TOP LEFT
if j > 0:
p = board[i - 1][j - 1]
if p == 0: # checks if space empty
moves.append((j - 1, i - 1,))
elif p.color != self.color:
moves.append((j - 1, i - 1,))
# TOP MIDDLE
p = board[i - 1][j]
if p == 0: # checks if space empty
moves.append((j, i - 1))
elif p.color != self.color:
moves.append((j, i - 1))
# TOP RIGHT
if j < 7:
p = board[i - 1][j 1]
if p == 0: # checks if space empty
moves.append((j 1, i - 1,))
elif p.color != self.color:
moves.append((j 1, i - 1,))
if i < 7:
# BOTTOM LEFT
if j > 0:
p = board[i 1][j - 1]
if p == 0: # checks if space empty
moves.append((j - 1, i 1,))
elif p.color != self.color:
moves.append((j - 1, i 1,))
# BOTTOM MIDDLE
p = board[i 1][j]
if p == 0: # checks if space empty
moves.append((j, i 1))
elif p.color != self.color:
moves.append((j, i 1))
# BOTTOM RIGHT
if j < 7:
p = board[i 1][j 1]
if p == 0: # checks if space empty
moves.append((j 1, i 1))
elif p.color != self.color:
moves.append((j 1, i 1))
# MIDDLE LEFT
if j > 0:
p = board[i][j - 1]
if p == 0: # checks if space empty
moves.append((j - 1, i))
elif p.color != self.color:
moves.append((j - 1, i))
# MIDDLE RIGHT
if j < 7:
p = board[i][j 1]
if p == 0: # checks if space empty
moves.append((j 1, i))
elif p.color != self.color:
moves.append((j 1, i))
return moves
This example is for just 1 piece out of 6 and so there is a lot of occurring 'if' statements. How can I refractor this to where I don't need to use as many 'if' statements?
CodePudding user response:
A local function helps to avoid code duplicates:
def valid_moves(self, board):
i = self.row
j = self.col
moves = []
def move(a: int, b: int) -> None:
p = board[a][b]
if p == 0 or p.color != self.color:
moves.append((b, a))
if i > 0:
# TOP LEFT
if j > 0:
move(i - 1, j - 1)
# TOP MIDDLE
move(i - 1, j)
# TOP RIGHT
if j < 7:
move(i - 1, j 1)
if i < 7:
# BOTTOM LEFT
if j > 0:
move(i 1, j - 1)
# BOTTOM MIDDLE
move(i 1, j)
# BOTTOM RIGHT
if j < 7:
move(i 1, j 1)
# MIDDLE LEFT
if j > 0:
move(i, j - 1)
# MIDDLE RIGHT
if j < 7:
move(i, j 1)
return moves
CodePudding user response:
First generate all possible moves, including illegal ones. Then filter the illegal ones. Also you check whether i > 0
or i < 7
, I think you meant i >= 0
and i < 8
if you're using zero-based indexing for an 8x8 chess board.
def valid_moves(self, board):
i = self.row
j = self.col
destinations = [
(j dj, i di)
for di [-1, 0, 1] for dj in [-1, 0, 1]
# Disallow staying in place - not a move.
if not (di == 0 and dj == 0)
]
legal_moves = [
(mj, mi)
for mj, mi in destinations
# In bounds.
if 0 <= mi < 8 and 0 <= mj < 8
# And empty or enemy occupied.
and (board[mi][mj] == 0 or board[mi][mj].color != self.color)
]
return legal_moves
CodePudding user response:
You seem to only be looking for a one space move so it could be simplified by looping on the vertical and horizontal deltas of each direction:
def valid_moves(self, board):
moves = []
for v,h in [(-1,-1),(0,-1),(0,1),(-1,0),(1,0),(1,1)]: # directions
r,c = self.row v,self.col h # advance by 1
if r not in range(8): continue # vertical bounds
if c not in range(8): continue # horizontal bounds
p = board[r][c]
if p==0 or p.color != self.color: # playable position
moves.append((r,c))
return moves
This isn't going to cover multi-step moves and non-linear moves. There is a strategy for all types of moves here.