Загрузка данных


# Улучшенные крестики-нолики
# С цветами, красивым полем, очисткой консоли
# и тремя режимами ввода.
#
# Люди изобрели компьютеры, чтобы автоматизировать расчеты.
# Потом начали рисовать ✖ и ◯ в терминале.
# Эволюция полна неожиданных поворотов.

import os
from colorama import init, Fore, Style

# Инициализация colorama
init(autoreset=True)

# Игровое поле
board = [
    ["1", "2", "3"],
    ["4", "5", "6"],
    ["7", "8", "9"]
]

# Текущий игрок
current_player = "✖"


def clear_screen():
    """Очистка консоли"""

    os.system("cls" if os.name == "nt" else "clear")


def colored_symbol(symbol):
    """Цветные символы"""

    if symbol == "✖":
        return Fore.RED + symbol + Style.RESET_ALL

    if symbol == "◯":
        return Fore.CYAN + symbol + Style.RESET_ALL

    return Fore.YELLOW + symbol + Style.RESET_ALL


def print_board():
    """Отрисовка поля"""

    clear_screen()

    print(Fore.MAGENTA + "\n        КРЕСТИКИ-НОЛИКИ\n")

    print("       A   B   C")

    for i in range(3):

        if i == 0:
            print("     ┌───┬───┬───┐")
        else:
            print("     ├───┼───┼───┤")

        row_content = []

        for cell in board[i]:
            row_content.append(colored_symbol(cell))

        print(f"   {i + 1} │ {row_content[0]} │ {row_content[1]} │ {row_content[2]} │")

    print("     └───┴───┴───┘")


def check_winner(player):
    """Проверка победы"""

    # Строки
    for row in board:
        if row.count(player) == 3:
            return True

    # Столбцы
    for col in range(3):
        if (
            board[0][col] == player and
            board[1][col] == player and
            board[2][col] == player
        ):
            return True

    # Диагонали
    if (
        board[0][0] == player and
        board[1][1] == player and
        board[2][2] == player
    ):
        return True

    if (
        board[0][2] == player and
        board[1][1] == player and
        board[2][0] == player
    ):
        return True

    return False


def check_draw():
    """Проверка ничьей"""

    for row in board:
        for cell in row:
            if cell not in ["✖", "◯"]:
                return False

    return True


def get_coordinates(choice):
    """
    Поддержка трех режимов ввода:

    1  -> номер клетки
    A1 -> шахматный стиль
    1 1 -> строка и столбец
    """

    choice = choice.upper().strip()

    # Вариант 1: номер клетки
    if choice in "123456789":

        number = int(choice) - 1

        row = number // 3
        col = number % 3

        return row, col

    # Вариант 2: шахматный стиль
    if len(choice) == 2:

        letters = {
            "A": 0,
            "B": 1,
            "C": 2
        }

        if choice[0] in letters and choice[1] in "123":

            col = letters[choice[0]]
            row = int(choice[1]) - 1

            return row, col

    # Вариант 3: строка столбец
    parts = choice.split()

    if len(parts) == 2:

        if parts[0].isdigit() and parts[1].isdigit():

            row = int(parts[0]) - 1
            col = int(parts[1]) - 1

            if 0 <= row <= 2 and 0 <= col <= 2:
                return row, col

    return None


# Главный игровой цикл
while True:

    print_board()

    print(Fore.GREEN + f"\nХод игрока {current_player}")

    print(Fore.WHITE + """
Доступные способы хода:
• 1-9        → номер клетки
• A1 / B2    → шахматный стиль
• 1 1        → строка и столбец
""")

    while True:

        choice = input("Ваш ход: ")

        coordinates = get_coordinates(choice)

        if coordinates is None:
            print(Fore.RED + "Некорректный ввод.")
            continue

        row, col = coordinates

        # Проверка занятости клетки
        if board[row][col] in ["✖", "◯"]:
            print(Fore.RED + "Клетка уже занята.")
            continue

        break

    # Ставим символ
    board[row][col] = current_player

    # Проверка победы
    if check_winner(current_player):

        print_board()

        print(
            Fore.GREEN +
            f"\nИгрок {current_player} победил!"
        )

        break

    # Проверка ничьей
    if check_draw():

        print_board()

        print(
            Fore.YELLOW +
            "\nНичья."
        )

        break

    # Смена игрока
    if current_player == "✖":
        current_player = "◯"
    else:
        current_player = "✖"