Есть ли способ сконденсировать мой код check_winner для крестиков-ноликов?

#python

#python

Вопрос:

Я пытаюсь написать функцию, которая проверяет победителя с учетом игрового поля. Мой код работает, как показано ниже. Мне интересно, есть ли более короткий способ написания этого кода?

 board = [["X", "O", "O"],
        ["X", "O", "O"],
        ["O", "O", "X"]]

def winner(board):
    if board[0][0] == board[0][1] == board[0][2] != None:
        return board[0][0]

    if board[1][0] == board[1][1] == board[1][2] != None:
        return board[1][0]

    if board[2][0] == board[2][1] == board[2][2] != None:
        return board[2][0]

    if board[0][0] == board[1][0] == board[2][0] != None:
        return board[0][0]

    if board[0][1] == board[1][1] == board[2][1] != None:
        return board[0][1]
    
    if board[0][2] == board[1][2] == board[2][2] != None:
        return board[0][2]

    if board[0][0] == board[1][1] == board[2][2] != None:
        return board[0][0]
    
    if board[0][2] == board[1][1] == board[0][0] != None:
        return board[0][0]
    
    else:
        return None
  

Комментарии:

1. Вероятно, это больше подходит для codereview.stackexchange.com . Пожалуйста, ознакомьтесь с их рекомендациями по отправке перед публикацией.

Ответ №1:

Предполагая, что может быть только один победитель:

 def winner(board):
    for row in range(3):
        if len(set(board[row])) == 1: # If there is only one value (one player)
            return board[row][0] # If all 3 squares are None, then it will return None anyway.
    for column in range(3):
        if len(set([row[column] for row in board])) == 1:
            return board[0][column]
    if board[0][0] == board[1][1] == board[2][2] or board[0][2] == board[1][1] == board[2][0] # Diagonals
        return board[1][1]
    # If no value is returned, then the function will return None by default.
  

Надеюсь, вы найдете это полезным.

Комментарии:

1. Спасибо, но я этого не понимаю. Я пытался: for row in range(3): print(set(board[row]) И он выводит мне это: {‘X’, ‘O’} {‘X’, ‘O’} {‘O’, ‘X’} Нет Почему это так?

2. Наборы — это тип данных, который содержит только один из каждого элемента. Это означает, что если набор имеет длину 1, строка / столбец содержит только один символ, что подразумевает выигрыш.

3. О, понятно. Это очень умно.

Ответ №2:

В tic tac toe у вас может быть либо один победитель, либо ни одного. Хорошая идея — представить доску массивом 3×3 и присвоить каждому цвету число. Я решил использовать 1 для крестиков и -1 для кругов.

Теперь, чтобы определить, выиграл ли какой-либо цвет, вы можете просто суммировать по строке, столбцу и диагонали, чтобы проверить, равна ли сумма 3 (или -3). Если доска заполнена и сумма 3 (или -3) не найдена, то это ничья.

 import numpy as np

# Crosses will be 1, circles will be -1
board = np.zeros((3, 3))
board[0, 1] = 1
board[2, 1] = -1

def check_win(board):
    """
    A player has won if he completes a row, a column, or a diagonal.
    Thus, we can check the sum on each to see if a player has reached 3 or -3.

    Parameters
    ----------
    board : numpy 3x3 array representing the board.

    Returns
    -------
    winner : None, or string 'circles' or 'crosses'

    """
    # Check rows and columns
    axis0 = np.sum(board, axis=0) # Sum the columns
    axis1 = np.sum(board, axis=1) # Sum the rows
    
    # Check diagonals
    diag1 = np.sum(board.diagonal())
    diag2 = np.sum(np.fliplr(board).diagonal())
    
    # Look for crosses win:
    if np.where(axis0==3)[0].size   np.where(axis1==3)[0].size   int(diag1==3)   int(diag2==3) != 0:
        return 'crosses'
    elif np.where(axis0==-3)[0].size   np.where(axis1==-3)[0].size   int(diag1==-3)   int(diag2==-3)  != 0:
        return 'circles'
    else:
        return None
  

Еще одним преимуществом представления платы с матрицей 3×3 (массив numpy) является то, что она более оптимизирована, хотя это не имеет значения для такого тривиального приложения.