寻找大于3x3棋盘的井字游戏对角线的算法

0 投票
1 回答
71 浏览
提问于 2025-04-13 12:44

我在用Python做一个简单的井字棋游戏,运行得很不错。我在这里讨论过如何改进它。最近我有个好主意,就是把棋盘做得更大,这个想法实现得也挺好,除了对角线的胜利条件只能在方形网格中实现,而且只能通过中间的那条线。不过我还添加了一个功能,让用户可以修改棋盘的大小,这个功能也运行得不错。这是我在遇到问题之前的样子。

import os
base_columns = [chr(x+97) for x in range(26)]
base_rows = [x for x in range(26)]
blank_spot = "-"
player_tracker = 0
player_character = ('X', 'O')
num_wins = {p:0 for p in player_character}
win_type = "Draw"
choice = ("y", "n")
game_running = True

def create_coords(s):
    global coords, columns, rows
    try:
        y = s.index('x')
        rows = base_rows[:int(s[:y])]
        columns = base_columns[:int(s[y+1:])]
        coords = {c:[blank_spot]*len(rows) for c in columns}
    except (IndexError, ValueError):
        create_coords("3x3")
        
def info_checker(s):
    s = s.lower()
    if 'x' in s and len(s) >= 3 and s.count('x') == 1:
        y = s.index('x')
        if y > 0 and s[:y].isnumeric() and s[y+1:].isnumeric():
            return True
    return False
    
def info_input(q, e="Not viable info"):
    x = input(q)
    while not(info_checker(x)):
        print(e)
        x = input(q)
    else:
        create_coords(x.lower())

def intro():
    intro_text = ["Welcome to Tic Tac Toe", "The Goal is to get 3 characters in a row", "Player 1 is 'X'; Player 2 is 'O'","You play the game on a board that's a grid","You have to input coords to place your character", "To input the coord for you charcter (Ex: a0, b2, c1):", "- First, put the letter column you want", "- Second, then put the number row"]
    for text in intro_text:
        print(text, end="\n\n")
    y = choice_input("Want to change the board size (y/n)? ")
    if y == choice[0]:
        board_text = ["Format: (Y)x(Z); Y is rows, Z is columns", "Ex: 3x3, 2x2, 3x2", "Note: If you enter a # greater than 26\nProgram defaluts to 3x3", "You can change this at the end of games"]
        print("")
        for text in board_text:
            print(text, end="\n\n")
        info_input("Input info to change board: ")
    else:
        create_coords("3x3")
    print("")
    input("Press enter to start playing ")
    os.system('clear')

def print_board():
    print("     " + "   ".join([c for c in columns]), end="\n\n")
    rows_formatted = []
    for r in rows:
        row_elements = []
        for c in columns:
            row_elements.append(coords[c][r])
        space = " "*((len(str(r))%2)+1)
        rows_formatted.append(f"{r} {space} {' | '.join(row_elements)}\n")
    seperator = "   " + "----"*len(columns) + "-\n"
    print(seperator.join(rows_formatted))
   
def coord_checker(s):
    try:
        if len(s) == 2 and s[0].lower() in columns and int(s[1]) in rows:
            if coords[s[0].lower()][int(s[1])] == blank_spot:
                return True
            else:
                return False
    except ValueError:
        return False
        
def coord_input(q, e="Not a selectable coord"):
    print(f"It's Player {player_tracker+1}'s  turn ({player_character[player_tracker]})")
    x = input(q)
    while not(coord_checker(x)):
        print(e)
        x = input(q)
    return x
    
def choice_input(q, e=f"Not '{choice[0]}' or '{choice[1]}', expecting 1 of them"):
    x = input(q).lower()
    while not(x in choice):
        print(e)
        x = input(q).lower()
    return x

def place_tac(c):
    global player_tracker
    coords[c[0].lower()][int(c[1])] = player_character[player_tracker]
    player_tracker = (player_tracker+1)%2
    
def someone_won():
    global win_type
    for c in columns:
        if all([coords[c][r] == coords[c][rows[0]] != blank_spot for r in rows]):
            win_type = coords[c][rows[0]]
    for r in rows:
        if all([coords[c][r] == coords[columns[0]][r] != blank_spot for c in columns]):
            win_type = coords[columns[0]][r]
    if len(rows) == len(columns):
        length = len(rows)
        if all([coords[columns[i]][rows[i]] == coords[columns[0]][0] != blank_spot for i in range(length)]):
            win_type = coords[columns[0]][0]
        elif all([coords[columns[0+i]][rows[(length-1)-i]] == coords[columns[0]][length-1] != blank_spot for i in range(length)]):
            win_type = coords[columns[0]][length-1]
    if win_type != "Draw":
        return True
    return False
        
def who_won():
    if win_type == "Draw":
        print(f"It was a draw! {num_wins['X']}-{num_wins['O']}")
    else:
        num_wins[win_type] += 1
        print(f"{win_type} won! {num_wins['X']}-{num_wins['O']}")
    
def game():
    turn_tracker = 0
    while not(someone_won()) and turn_tracker < len(rows)*len(columns):
        print_board()
        c = coord_input("Choose a coord: ")
        place_tac(c)
        os.system('clear')
        turn_tracker += 1
    print_board()
    who_won()
    
def reset():
    global coords, player_tracker, win_type
    coords = {c:[blank_spot]*len(rows) for c in columns}
    if win_type != "Draw":
        player_tracker = (player_character.index(win_type)+1)%2
        win_type = "Draw"
    
def replay():
    global game_running
    x = choice_input("Do you want to keep playing (y/n)? ")
    if x == choice[0]:
        y = choice_input("Change the board size (y/n)? ")
        if y == choice[0]:
            info_input("Input info (Ex: 2x2, 3x3, 3x2) ")
        os.system('clear')
    else:
        print("Thanks for playing")
        game_running = False

intro()
while game_running:
    game()
    reset()
    replay()

不过,实际上,棋盘变大后,游戏变得更难玩和获胜。特别是你必须在棋盘的长度或宽度上有连续的字符。所以我一个朋友建议我,获胜的条件可以改成只需要3个字符连成一行,除非棋盘小于3x3。

我大部分功能都是自己实现的。

这个函数用来判断是否有3个'tac'连成一行(参数'tics'是一个布尔值列表)。

def tic_tac_toe(tics):
    toes = 0
    if len(coords[columns[0]]) >= 3:
        for t in tics:
            if t:
                toes += 1
        if toes >= 3:
            return True
    else:
        return all(tics)
    return False

还有两个函数用来找出谁在某一列或某一行获胜。

def find_column_tics(c):
    count = 1
    previous = coords[c][rows[0]]
    for r in rows:
        current = coords[c][r]
        if current in player_character:
            if r != rows[0] and previous == current:
                count+=1
            else:
                count = 1
            previous = current
            if count >= 3:
                return current
    
def find_row_tacs(r):
    count = 1
    previous = coords[columns[0]][r]
    for c in columns:
        current = coords[c][r]
        if current in player_character:
            if c != columns[0] and previous == current:
                count+=1
            else:
                count = 1
            previous = current
            if count >= 3:
                return current

在'someone_won()'这个函数里,它们的样子都是这样的。

def someone_won():
    global win_type
    # For finding a win in columns
    for c in columns:
        for r in rows:
            if tic_tac_toe([coords[c][i] == coords[c][r] != blank_spot for i in rows]):
                    win_type = find_column_tics(c)
    # For finding a win in rows
    for r in rows:
        for c in columns:
            if tic_tac_toe([coords[i][r] == coords[c][r] != blank_spot for i in columns]):
                    win_type = find_row_tacs(r)

这些都运行得很好,但我在尝试解决对角线的问题时遇到了麻烦。在一个4x4的棋盘上,有8种方式可以通过对角线获胜,但我不知道该怎么写一个算法来实现这一点。我试过好几种方法,但都不行。我想自己搞定这个问题,但我觉得自己经验不足。我在想你们有没有什么想法或解决方案。写这段话的时候,我已经尝试了3天,真的希望能找到解决办法。

1 个回答

1

你可以试试这样的做法:

def check_diagonals(board, color):
    # upper left to bottom right
    for i in range(len(board) - 2):
        for j in range(len(board[0]) - 2):
            if board[i][j] == color and board[i + 1][j + 1] == color and board[i + 2][j + 2] == color:
                return True
    
    # bottom left to top right
    for i in range(2, len(board)):
        for j in range(len(board[0]) - 2):
            if board[i][j] == color and board[i - 1][j + 1] == color and board[i - 2][j + 2] == color:
                return True
    
    return False


board = [
    "0001",
    "0010",
    "0100"
]

print(check_diagonals(board, "1"))  # True

因为实际上有两种对角线,它们是朝相反方向的,所以只需要检查所有可能的对角线就可以了。

撰写回答