I have the following code with the only difference being the j and the I position in my list. Is there any way to make it better by writing a function or something like that because I can't quite figure it out?
for i in range(dimension):
for j in range(dimension - 4):
k = 1
while k < 5 and gameboard[i][j k] == gameboard[i][j]:
k = 1
if k == 5:
winner = gameboard[i][j]
for i in range(dimension):
for j in range(dimension - 4):
k = 1
while k < 5 and gameboard[j k][i] == gameboard[j][i]:
k = 1
if k == 5:
winner = gameboard[j][i]
CodePudding user response:
You could merge the two loops by inserting an additional nested loop that handles the permutations of i and j and the corresponding dimension deltas:
for i in range(dimension):
for j in range(dimension - 4):
for i,j,di,dj in [ (i,j,0,1), (j,i,1,0) ]:
k = 1
while k < 5 and gameboard[i k*di][j k*dj] == gameboard[i][j]:
k = 1
if k == 5:
winner = gameboard[i][j]
Generalized for all directions
Alternatively you could create a function that tells you if there is a win in a given direction and use that in a loop.
def directionWinner(board,i,j,di,dj):
player,pi,pj = board[i][j],i,j
# if player == empty: return
for _ in range(4):
pi,pj = pi di, pj dj
if pi not in range(len(board)): return
if pj not in range(len(board)): return
if board[pi][pj] != player: return
return player
Then use it to check all directions:
for pos in range(dimensions*dimensions):
i,j = divmod(pos,dimensions)
for direction in [ (0,1),(1,0),(1,1),(1,-1) ]:
winner = directionWinner(gameboard,i,j,*direction)
if winner is not None: break
else: continue; break
The directions are represented by the increase/decrease in vertical and horizontal coordinates (deltas) for each step of one. So [ (0,1),(1,0),(1,1),(1,-1) ]
gives you "down", "across", "diagonal 1", diagonal 2" respectively.
Checking only from last move
The same idea can be used to check for a winner from a specific position (e.g. checking if last move is a win):
# count how may consecutive in a given direction (and its inverse)
def countDir(board,i,j,di,dj,inverted=False):
player,pi,pj = board[i][j],i,j
count = 0
while pi in range(len(board) and pj in range(len(board)):
if board[pi][pj] == player: count = 1
else: break
pi, pj = pi di, pj dj
if not inverted:
count = countDir(board,i,j,-di,-dj,True)-1
return count
def winnerAt(board,i,j):
for direction in [ (0,1),(1,0),(1,1),(1,-1) ]:
if countDir(board,i,j,*direction)>=5:
return board[i,j]
Then, after playing at position i,j, you can immediately know if the move won the game:
if winnerAt(gameboard,i,j) is not None:
print(gameboard[i][j],"wins !!!")
CodePudding user response:
It's maybe a trivial change, but why don't you just put the second check in the first loop just by swapping indices and using another variable for the while part? I mean something like this:
def check_winner(gameboard, dimension):
for i in range(dimension):
for j in range(dimension - 4):
# perform the first check
k = 1
while k < 5 and gameboard[i][j k] == gameboard[i][j]:
k = 1
if k == 5:
return gameboard[i][j]
# and the second check
l = 1
while l < 5 and gameboard[j k][i] == gameboard[j][i]:
l = 1
if l == 5:
return gameboard[j][i]
Anyways, it's cleaner to just return if you found the winner, and avoid redundancy.