Quote:
Originally Posted by econophile
I'm working on a method that checks whether pieces are in the way of horizontal, vertical, or diagonal chess moves. (Other types of moves have another method). If the move is from square A to B, the method needs to look at each square between A and B. This is what I came up with as a first draft.
Code:
def clear_path(self):
(x1, y1), (x2, y2) = self.coords
(xmin, xmax), (ymin, ymax) = sorted([x1, x2]), sorted([y1, y2])
if x1 == x2:
for y in range(ymin + 1, ymax):
square = board.notation((x1, y))
if board.piece(square) != None:
print 'Move is not allowed because there is a',
print board.piece(square), 'in the way.'
return False
elif y1 == y2:
for x in range(xmin + 1, xmax):
square = board.notation((x, y1))
if board.piece(square) != None:
print 'Move is not allowed because there is a',
print board.piece(square), 'in the way.'
return False
elif xmax - xmin == ymax - ymin:
if x1 < x2:
x_change = 1
else:
x_change = -1
if y1 < y2:
y_change = 1
else:
y_change = -1
for i in range(xmax - xmin - 1):
x1 += x_change
y1 += y_change
square = board.notation((x1, y1))
if board.piece(square) != None:
print 'Move is not allowed because there is a',
print board.piece(square), 'in the way.'
return False
return True
That looked pretty ugly, so I figured out how to generalize a single approach that would handle all three types of moves and ended up with:
Code:
def clear_path(self):
(x1, y1), (x2, y2) = self.coords
xdist, ydist = (x1 - x2), (y1 - y2)
dist = max(abs(xdist), abs(ydist))
x_change, y_change = xdist/dist , ydist/dist
if x1 == x2 or y1 == y2 or abs(xdist) == abs(ydist):
for d in range(dist - 1):
x1 += x_change
y1 += y_change
square = board.notation((x1, y1))
if board.piece(square) != None:
print 'Move is not allowed because there is a',
print board.piece(square), 'in the way.'
return False
return True
It's a lot shorter, but it still doesn't seem very elegant.
I don't like how I'm basically entering formulas twice. I could write loops, but sometimes it seems like overkill to write a loop to just do one thing twice.
Also, instead of
x_change, y_change = xdist/dist, ydist/dist
I could write something like
x_change, y_change = [i/dist for i in (xdist, ydist)]
But that also seems silly.
Any advice? Should I break the method up into multiple functions? Use more loops?
Looking only at the second version, what are you assuming about the input your function will get? If the two squares are the same, you'll have a division by zero where x_change and y_change are computed. Also if the squares don't lie on the same diagonal, vertical, or horizontal line you're returning True, even though it's not a possible rook/bishop/queen move. Assuming the move is from (x1,y1) to (x2,y2), you're calculating the opposite of xdist, ydist and the line should be changed to this:
Code:
xdist, ydist = (x2 - x1), (y2 - y1)
Otherwise I think this works for determining if you have a clear path between the two squares. Given a piece of the right type on (x1,y1) and as long as (x2,y2) is either unoccupied or occupied by an enemy piece (and assuming the move didn't expose or leave your king in check), that's a legal move. That said, I wonder why you'd have this function at all. Any chess program is going to have a function that generates all legal moves, so instead of checking each possible move one by one, why not generate all legal moves and from there you'd just check whether this move appears on the move list?