воскресенье, 28 июня 2026 г.

Уголки

 import pygame

import sys

import copy


# Настройки окна и графики

WIDTH, HEIGHT = 600, 600

ROWS, COLS = 8, 8

SQ_SIZE = WIDTH // COLS


# Цвета

WHITE = (240, 240, 240)

DARK_SQ = (180, 180, 180)

GREEN = (46, 204, 113)      # Игрок (Зеленые)

RED = (231, 76, 60)         # ИИ (Красные)

BLUE = (52, 152, 219)       # Выделение и подсказки

BLACK = (44, 62, 80)


pygame.init()

WIN = pygame.display.set_mode((WIDTH, HEIGHT))

pygame.display.set_caption('Уголки: Игрок против ИИ')


# Инициализация доски (Игрок 1 в левом верхнем углу, ИИ 2 в правом нижнем)

def create_initial_board():

    board = [[0 for _ in range(COLS)] for _ in range(ROWS)]

    # База игрока 1 (верхний левый угол 3х3)

    for r in range(3):

        for c in range(3):

            board[r][c] = 1

    # База ИИ (нижний правый угол 3х3)

    for r in range(5, 8):

        for c in range(5, 8):

            board[r][c] = 2

    return board


board = create_initial_board()

selected_piece = None

turn = 1            # 1 - Игрок, 2 - ИИ

is_jumping = False  # Флаг, находится ли игрок в процессе серии прыжков


# --- Логика ходов ---


def get_valid_moves(board, row, col, only_jumps=False):

    """Возвращает список доступных ходов (r, c) для фишки в точке (row, col)"""

    moves = []

    directions = [(-1, 0), (1, 0), (0, -1), (0, 1), (-1, -1), (-1, 1), (1, -1), (1, 1)]

    

    for dr, dc in directions:

        # 1. Обычные шаги (только если не в серии прыжков)

        if not only_jumps:

            nr, nc = row + dr, col + dc

            if 0 <= nr < ROWS and 0 <= nc < COLS and board[nr][nc] == 0:

                moves.append((nr, nc))

                

        # 2. Прыжки через фигуры

        mid_r, mid_c = row + dr, col + dc

        if 0 <= mid_r < ROWS and 0 <= mid_c < COLS and board[mid_r][mid_c] != 0:

            end_r, end_c = row + 2*dr, col + 2*dc

            if 0 <= end_r < ROWS and 0 <= end_c < COLS and board[end_r][end_c] == 0:

                moves.append((end_r, end_c))

                

    return moves


def get_all_valid_moves(board, player):

    """Генерирует все возможные ходы для игрока (нужно для ИИ)"""

    all_moves = []

    for r in range(ROWS):

        for c in range(COLS):

            if board[r][c] == player:

                # Добавляем обычные ходы и одиночные прыжки

                for nr, nc in get_valid_moves(board, r, c):

                    all_moves.append(((r, c), (nr, nc)))

    return all_moves


# --- Искусственный интеллект (Минимакс + Альфа-Бета) ---


def evaluate_board(board):

    """Оценка позиции: чем ближе фишки к цели, тем больше очков"""

    score = 0

    for r in range(ROWS):

        for c in range(COLS):

            if board[r][c] == 2:  # ИИ стремится в верхний левый угол (0,0)

                score += (14 - (r + c))

            elif board[r][c] == 1: # Игрок стремится в нижний правый угол (7,7)

                score -= (r + c)

    return score


def minimax(board, depth, alpha, beta, maximizing_player):

    """Алгоритм поиска лучшего хода для ИИ"""

    if depth == 0:

        return evaluate_board(board), None

        

    if maximizing_player:

        max_eval = -float('inf')

        best_move = None

        moves = get_all_valid_moves(board, 2)

        if not moves:

            return evaluate_board(board), None

            

        for start, end in moves:

            temp_board = copy.deepcopy(board)

            temp_board[end[0]][end[1]] = 2

            temp_board[start[0]][start[1]] = 0

            

            # ИИ проверяет, можно ли сделать прыжок еще дальше (серия)

            if abs(start[0] - end[0]) == 2 or abs(start[1] - end[1]) == 2:

                next_jumps = get_valid_moves(temp_board, end[0], end[1], only_jumps=True)

                if next_jumps: # Если есть куда прыгнуть дальше, ИИ симулирует лучший прыжок

                    for jr, jc in next_jumps:

                        jump_board = copy.deepcopy(temp_board)

                        jump_board[jr][jc] = 2

                        jump_board[end[0]][end[1]] = 0

                        eval_score, _ = minimax(jump_board, depth - 1, alpha, beta, False)

                        if eval_score > max_eval:

                            max_eval = eval_score

                            best_move = (start, (jr, jc))

                    continue


            eval_score, _ = minimax(temp_board, depth - 1, alpha, beta, False)

            if eval_score > max_eval:

                max_eval = eval_score

                best_move = (start, end)

            alpha = max(alpha, eval_score)

            if beta <= alpha:

                break

        return max_eval, best_move

    else:

        min_eval = float('inf')

        best_move = None

        moves = get_all_valid_moves(board, 1)

        if not moves:

            return evaluate_board(board), None

            

        for start, end in moves:

            temp_board = copy.deepcopy(board)

            temp_board[end[0]][end[1]] = 1

            temp_board[start[0]][start[1]] = 0

            

            eval_score, _ = minimax(temp_board, depth - 1, alpha, beta, True)

            if eval_score < min_eval:

                min_eval = eval_score

                best_move = (start, end)

            beta = min(beta, eval_score)

            if beta <= alpha:

                break

        return min_eval, best_move


# --- Отрисовка интерфейса ---


def draw_board(win, board, selected, valid_moves):

    win.fill(WHITE)

    # Сетка

    for row in range(ROWS):

        for col in range(COLS):

            if (row + col) % 2 == 1:

                pygame.draw.rect(win, DARK_SQ, (col*SQ_SIZE, row*SQ_SIZE, SQ_SIZE, SQ_SIZE))

            else:

                pygame.draw.rect(win, WHITE, (col*SQ_SIZE, row*SQ_SIZE, SQ_SIZE, SQ_SIZE))

            

            # Фишки

            piece = board[row][col]

            if piece == 1:

                pygame.draw.circle(win, GREEN, (col*SQ_SIZE + SQ_SIZE//2, row*SQ_SIZE + SQ_SIZE//2), SQ_SIZE//3)

            elif piece == 2:

                pygame.draw.circle(win, RED, (col*SQ_SIZE + SQ_SIZE//2, row*SQ_SIZE + SQ_SIZE//2), SQ_SIZE//3)


    # Подсветка выбранной фишки

    if selected:

        r, c = selected

        pygame.draw.circle(win, BLUE, (c*SQ_SIZE + SQ_SIZE//2, r*SQ_SIZE + SQ_SIZE//2), SQ_SIZE//3, 4)

        # Подсветка возможных ходов

        for r_move, c_move in valid_moves:

            pygame.draw.circle(win, BLUE, (c_move*SQ_SIZE + SQ_SIZE//2, r_move*SQ_SIZE + SQ_SIZE//2), 8)


def check_winner(board):

    # Условие победы: занять целевой угол 3х3 полностью

    p1_win = all(board[r][c] == 1 for r in range(5, 8) for c in range(5, 8))

    p2_win = all(board[r][c] == 2 for r in range(3) for c in range(3))

    if p1_win: return 1

    if p2_win: return 2

    return 0


# --- Основной цикл ---


def main():

    global board, selected_piece, turn, is_jumping

    clock = pygame.time.Clock()

    valid_moves = []


    while True:

        clock.tick(60)

        

        # Ход Искусственного Интеллекта

        if turn == 2:

            pygame.time.delay(500)  # Небольшая задержка для реалистичности ходов

            _, move = minimax(board, 3, -float('inf'), float('inf'), True)

            if move:

                start, end = move

                board[end[0]][end[1]] = 2

                board[start[0]][start[1]] = 0

            turn = 1

            is_jumping = False

            selected_piece = None


        # Обработка событий игрока

        for event in pygame.event.get():

            if event.type == pygame.QUIT:

                pygame.quit()

                sys.exit()


            if event.type == pygame.KEYDOWN and turn == 1:

                # Нажатие на ПРОБЕЛ завершает серию прыжков игрока

                if event.key == pygame.K_SPACE and is_jumping:

                    turn = 2

                    is_jumping = False

                    selected_piece = None

                    valid_moves = []


            if event.type == pygame.MOUSEBUTTONDOWN and turn == 1:

                pos = pygame.mouse.get_pos()

                row, col = pos[1] // SQ_SIZE, pos[0] // SQ_SIZE


                # Если кликнули на доступную для хода клетку

                if (row, col) in valid_moves and selected_piece:

                    start_r, start_c = selected_piece

                    board[row][col] = 1

                    board[start_r][start_c] = 0


                    # Проверяем, был ли это прыжок (дистанция 2 клетки)

                    if abs(start_r - row) == 2 or abs(start_c - col) == 2:

                        selected_piece = (row, col)

                        valid_moves = get_valid_moves(board, row, col, only_jumps=True)

                        

                        # Если прыгать дальше некуда, завершаем ход

                        if not valid_moves:

                            turn = 2

                            is_jumping = False

                            selected_piece = None

                        else:

                            is_jumping = True # Входим в режим серийных прыжков

                    else:

                        # Обычный шаг завершает ход сразу

                        turn = 2

                        is_jumping = False

                        selected_piece = None

                        valid_moves = []

                

                # Если выбираем свою фишку (и мы не посреди серии прыжков)

                elif board[row][col] == 1 and not is_jumping:

                    selected_piece = (row, col)

                    valid_moves = get_valid_moves(board, row, col)

                    

        # Отрисовка интерфейса

        draw_board(WIN, board, selected_piece, valid_moves)

        

        # Проверка финала

        winner = check_winner(board)

        if winner != 0:

            print(f"Игра окончена! Победил Игрок {winner}")

            pygame.time.delay(3000)

            break


        pygame.display.update()


if __name__ == '__main__':

    main()


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

Отправить комментарий