Finding neighbor cells in a grid with the same value. Ideas how to improve this function?
Here's an approach that involves less copying and pasting -- hopefully it gives you some idea of how to break things down into the smallest number of the most reusable pieces possible. :)
The general idea here is to come up with a way of expressing the concept of scanning a line across the board in different directions in such a way that you can just express the direction and then let the same block of code handle the scan regardless of what the direction is.
from typing import List, Optional, Tuple
def do_we_have_a_winner(board: List[List[Optional[str]]], length: int) -> Optional[str]:
"""Returns the 'mark' of the player with a row of the given length."""
width = range(len(board))
height = range(len(board[0]))
# Do four scans across the board -- right, down, and diagonals.
for dx, dy in [(0, 1), (1, 0), (1, 1), (1, -1)]:
edges: List[Tuple[int, int]] = []
if dx > 0:
# scanning right, start from left edge
edges += [(0, y) for y in height]
if dy > 0:
# scanning down, start from top edge
edges += [(x, 0) for x in width]
if dy < 0:
# scanning up, start from bottom edge
edges += [(x, height[-1]) for x in width]
for ex, ey in edges:
mark: Optional[str] = None
row = 0
x, y = ex, ey
while x in width and y in height:
if board[x][y] == mark:
row += 1
else:
mark = board[x][y]
row = 1
if mark is not None and row >= length:
return mark
x, y = x + dx, y + dy
return None
print(do_we_have_a_winner([
['X', 'O', 'O'],
['O', 'X', 'O'],
['O', 'O', 'X'],
], 3)) # X
Note that this function assumes one at most winner, so if there are multiple winners, it will only return one of them -- I'll leave it as an exercise for the reader to figure out how to change it to handle that situation better. :)