Глава 17 · Правила игры

Восемь выигрышных линий

Три строки, три столбца, две диагонали — и одна чистая функция, которая их все проверяет.

Все восемь выигрышных линий

Строки

X
X
X
Строка 1
X
X
X
Строка 2
X
X
X
Строка 3

Столбцы

X
X
X
Столбец 1
X
X
X
Столбец 2
X
X
X
Столбец 3

Диагонали

X
X
X
Диагональ 0-4-8
X
X
X
Диагональ 2-4-6

Константа WINNING_LINES

winning_lines.py
WINNING_LINES = (
    (0, 1, 2), (3, 4, 5), (6, 7, 8),  # строки
    (0, 3, 6), (1, 4, 7), (2, 5, 8),  # столбцы
    (0, 4, 8), (2, 4, 6),             # диагонали
)
ЗАГЛАВНЫМИ — это данные правил, а не алгоритм
WINNING_LINES написана ЗАГЛАВНЫМИ буквами: так в Python принято называть константы модуля (соглашение PEP 8 — договорённость между программистами, а не запрет интерпретатора на изменение). Это данные о правилах игры, отдельные от кода, который их использует. find_winner() сам по себе не знает о размере 3×3 — он просто перебирает готовые линии. Но константа решает не всё: индексная арифметика (// 3, % 3), длина [""] * 9 и сама 3×3-сетка виджетов тоже жёстко зашиты на размер поля — реальная поддержка другого размера потребовала бы менять всё это, а не только WINNING_LINES.

find_winner() — чистая функция

find_winner.py
def find_winner(board):
    for a, b, c in WINNING_LINES:
        mark = board[a]
        if mark and mark == board[b] == board[c]:
            return mark, (a, b, c)
    return None, None
Возвращает И победителя, И саму линию
Раздел 17.5 возвращал только победителя. find_winner() возвращает пару (winner, winning_line) — индексы линии нужны, чтобы подсветить именно её (раздел 17.25), не пересчитывая победителя заново.
Ничего не знает про Tkinter
find_winner(board) принимает обычный список строк — никаких кнопок, никакого root. Это то, что делает функцию тестируемой без единого открытого окна (раздел 17.28).
Практика: find_winner для всех восьми линий
Автоматическая проверка — find_winner на каждой из восьми линий для X и O
Открыть практику →