我是Python新手(学习了1个多月),我尝试着创建Tic Tac Toe。然而,一旦我完成了它,我决定扩大棋盘(从3x3到9x9,取决于客户的输入),并允许在棋盘的任何地方连接4个行、列或对角线来赢。
因此,我需要一个功能,根据客户的输入,在棋盘的各个方向上搜索--在不过度的情况下,寻找3个具有相同标记的连接单元。
然后我意识到,实际上我需要同时检查与标记相反的两个方向,因为有可能当前放置的标记可以连接相同标记的其他组,并通过这样做赢得。
下面你可以找到我的上述中奖条件的解决方案,它是有效的,然而它看起来并不漂亮,因为有很多重复的几乎相同的for循环。但是我完全不知道如何组合它们。
有8个循环(因为有8个方向),分为4组相反的方向,每个循环检查下一个单元格是否与客户当前放置的单元格('O'或'X')具有相同的值(标记),如果是,则计数变量增加1,如果不是,则循环中断。然后,我检查两个相反方向的循环是否能够使count == 4。如果是 - 我们有一个赢家。如果没有 - 我们进入下一个对子。
我相信应该有更容易维护的代码,但我想不出任何代码。
谢谢你的帮助
P.S.如果有需要,我会从我的代码中发布更多的信息
def do_we_have_a_winner(position, current_mark):
global game_board
connect = 4
# unpacking the coordinates of the current position
x, y = coordinates[position]
length = len(game_board)
count = 0
for i in range(0, connect):
if (x-i in range(0, length)) and (y+i in range(0, length)):
if game_board[x-i][y+i] != current_mark:
break
else:
count += 1
for i in range(1, connect):
if (x+i in range(0, length)) and (y-i in range(0, length)):
if game_board[x+i][y-i] != current_mark:
break
else:
count += 1
if count == connect:
print("We have a winner!")
return True
count = 0
for i in range(0, connect):
if (x+i in range(0, length)) and (y+i in range(0, length)):
if game_board[x+i][y+i] != current_mark:
break
else:
count += 1
for i in range(1, connect):
if (x-i in range(0, length)) and (y-i in range(0, length)):
if game_board[x-i][y-i] != current_mark:
break
else:
count += 1
if count == connect:
print("We have a winner!")
return True
count = 0
for i in range(0, connect):
if (y+i in range(0, length)):
if game_board[x][y+i] != current_mark:
break
else:
count += 1
for i in range(1, connect):
if (y-i in range(0, length)):
if game_board[x][y-i] != current_mark:
break
else:
count += 1
if count == connect:
print("We have a winner!")
return True
count = 0
for i in range(0, connect):
if (x+i in range(0, length)):
if game_board[x+i][y] != current_mark:
break
else:
count += 1
for i in range(1, connect):
if (x-i in range(0, length)):
if game_board[x-i][y] != current_mark:
break
else:
count += 1
if count == connect:
print("We have a winner!")
return True
return False
这里有一个方法,涉及到较少的复制和粘贴 -- 希望它能给你一些想法,如何把事情分解成尽可能少的最可重复使用的部分。)
总的来说,这里的想法是想出一种方法来表达在不同方向上扫描一条线的概念,你可以只表达方向,然后让同一个代码块来处理扫描,不管方向是什么。
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
请注意,这个函数假设最多只有一个赢家,所以如果有多个赢家,它将只返回其中的一个--我将把它作为一个练习,让读者找出如何改变它来更好地处理这种情况。)