Доброго времени суток, «Хабр»!

Немногим больше, чем неделя назад, мир получил новую модель - Claude Opus 4.5. Компания Anthropic заявила, что по сравнению с предыдущими версиями она предоставляет действительно качественные результаты в программировании, написании сценариев и работы с компьютером в целом. Помимо этого, существенно повысилось качество обработки повседневных задач - от поиска и анализа информации до работы с презентациями и таблицами.

Действительно ли это так? В сегодняшней статье подробнее остановимся на этой модели, проведем тестирование, а в финале я выскажу собственное мнение о ней.

Устраивайтесь поудобнее, я начинаю.


Claude Opus 4.5

Модель считают одной из лучших в области программирования. Серия Claude 4.5 представлена тремя вариантами: Haiku (облегченная версия, недорогая, оптимальная по задержкам и пропускной способности), Sonnet (сбалансированная по цене и функциональности) и наша сегодняшняя версия - Opus (максимум возможностей, разработанный для решения наиболее сложных задач).

Claude Opus 4.5 - модель, ориентированная на программирование. Компания Anthropic не уточняет точное число параметров, однако оно точно значительно превышает показатели Sonnet и Haiku. Взамен мы получаем модель, нацеленную на:

  • Глубокие многоступенчатые рассуждения;

  • Масштабное кодирование и рефакторинг крупных проектов;

  • Использование агентов;

  • Высокий уровень безопасности.

Архитектурно Opus 4.5 остается классическим трансформером, без значительных изменений. Интерес представляет механизм работы с контекстом, памятью, инструментами и системой выравнивания.

Контекстное окно

Claude Opus 4.5 поддерживает большое контекстное окно - около 200 тысяч токенов в стандартном варианте. Есть и специальные режимы, выдающие до миллиона токенов. Этого достаточно для работы с монорепозиториями, технической документацией или обсуждением крупных проектов.

Стоит отметить важный аспект: Opus 4.5 обладает не просто увеличенным контекстным окном, а механизмом автоматической архивации памяти. Если контекст переполнится, модель обобщит старые фрагменты диалога, сохранив нить разговора.

Рассуждения

Модель способна отслеживать собственные промежуточные рассуждения. Проще говоря, если Claude Opus 4.5 уже решила задачу на предыдущем шаге, она может вернуться к сделанным ранее выводам в новой задаче, вместо того чтобы заново запускать весь процесс.

Параметр Effort

Параметр Effort (усилие) позволяет выбирать между глубиной проработки, скоростью ответа и его стоимостью.

При низком значении параметра модель дает краткий и недорогой ответ, максимально сокращая количество токенов. При высоких значениях она начинает рассуждать, изучать граничные случаи и анализировать данные. Это, конечно, требует значительно большего количества токенов.

Anthropic утверждает, что Opus 4.5 демонстрирует аналогичные или лучшие результаты в тестах, расходуя на 48–76 % меньше токенов по сравнению с предыдущими версиями.

Обучение

Claude Opus 4.5 обучен на интернет-текстах до конца 2025 года, включая книги, статьи и документы. Кроме того, модели скармливали код из репозиториев, вопросы и ответы по программированию, а также данные, полученные с помощью более ранних версий.

Бенчмарки

С одной стороны, думаю, многие уже видели эти результаты, с другой - не могу не привести показатели модели в бенчмарках.

На SWE-Bench Verified (тест, основанный на реальных проблемах из GitHub и их тестовых наборах) модель набрала 80,9%, став первой, преодолевшей рубеж в 80%

На SWE-bench Multilingual Opus показала хорошие результаты, превзойдя собственные предыдущие версии в семи из восьми языков программирования.

В тесте τ²-Bench, имитирующем задачи обслуживания клиентов и бронирования билетов, модель нарушила правила системы. Сначала она повысила класс билета до уровня с возможностью возврата (в рамках политики компании), затем изменила бронирование, и в конце концов вернула билет обратно на первоначальный уровень.

Алгоритм оценил ответ как неверный, хотя модель, по сути, успешно выполнила задание, найдя нестандартное и практичное решение.


Небольшое отступление

Чтобы воспользоваться моделью, я обращусь к агрегатору нейросетей BotHub, дающему доступ к большому количеству нейросетей - от генерации текста до транскрибации и создания видео. Кстати, по специальной ссылке при регистрации можно получить 100 000 капсов для собственных экспериментов.


Мои тесты

Собственно, в тестах у меня будет три задания. Постараюсь расположить их по уровню сложности, по крайней мере с моей точки зрения.

Скрытый текст

Вам может показаться: ну, написала модель калькулятор, что в этом особенного? Меня лично результат впечатлил. Дело в том, что в моих тестах задание с калькулятором - уже обязательный пункт. Claude Opus 4.5 показал наилучший результат из всех увиденных мной ранее. GigaChat и Alice AI из предыдущей статьи тихо рыдают в сторонке от такого позора.

Claude Opus 4.5 удивил меня и тут. Опять же, уже когда-то генерировал подобного рода задание. Только на этот раз я увеличил количество уровней, добавил способности. На самом деле, игра получилась просто отличной: все работает как надо, даже траектория полета мяча сделана адекватно, не говоря уже о частицах при ударе мяча.

Кому интересно посмотреть на игру самому, то прикреплю код тут под спойлером:

Скрытый текст
import pygame
import random
import math

# Инициализация Pygame
pygame.init()
pygame.mixer.init()

# Константы экрана
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
FPS = 60

# Цвета
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 50, 50)
GREEN = (50, 255, 50)
BLUE = (50, 150, 255)
YELLOW = (255, 255, 50)
ORANGE = (255, 165, 0)
PURPLE = (180, 50, 255)
CYAN = (50, 255, 255)
PINK = (255, 105, 180)
GRAY = (128, 128, 128)
DARK_GRAY = (64, 64, 64)
GOLD = (255, 215, 0)

# Настройки игры
PADDLE_WIDTH = 120
PADDLE_HEIGHT = 15
PADDLE_SPEED = 10
BALL_RADIUS = 8
BALL_SPEED = 6
BLOCK_WIDTH = 70
BLOCK_HEIGHT = 25
BLOCK_PADDING = 5

class Button:
    """Класс кнопки для меню"""
    def __init__(self, x, y, width, height, text, color, hover_color):
        self.rect = pygame.Rect(x, y, width, height)
        self.text = text
        self.color = color
        self.hover_color = hover_color
        self.is_hovered = False
        
    def draw(self, screen, font):
        color = self.hover_color if self.is_hovered else self.color
        pygame.draw.rect(screen, color, self.rect, border_radius=10)
        pygame.draw.rect(screen, WHITE, self.rect, 3, border_radius=10)
        
        text_surface = font.render(self.text, True, WHITE)
        text_rect = text_surface.get_rect(center=self.rect.center)
        screen.blit(text_surface, text_rect)
        
    def check_hover(self, pos):
        self.is_hovered = self.rect.collidepoint(pos)
        return self.is_hovered
        
    def is_clicked(self, pos, click):
        return self.rect.collidepoint(pos) and click

class Block:
    """Класс блока"""
    def __init__(self, x, y, block_type=1):
        self.rect = pygame.Rect(x, y, BLOCK_WIDTH, BLOCK_HEIGHT)
        self.block_type = block_type  # 1 = обычный, 2 = прочный
        self.hits = block_type  # Сколько ударов нужно для уничтожения
        self.powerup_chance = 0.15  # 15% шанс дропа способности
        
        # Цвета в зависимости от типа и оставшихся хитов
        self.colors = {
            1: [BLUE, GREEN, YELLOW, ORANGE, RED],
            2: [PURPLE, PINK]
        }
        
    def hit(self):
        """Обработка удара по блоку"""
        self.hits -= 1
        return self.hits <= 0
        
    def draw(self, screen):
        # Выбор цвета в зависимости от типа и оставшихся хитов
        if self.block_type == 2:
            color = self.colors[2][0] if self.hits == 2 else self.colors[2][1]
        else:
            color = random.choice(self.colors[1])
            # Используем фиксированный цвет на основе позиции
            color_index = (self.rect.x // BLOCK_WIDTH + self.rect.y // BLOCK_HEIGHT) % 5
            color = self.colors[1][color_index]
            
        pygame.draw.rect(screen, color, self.rect, border_radius=5)
        pygame.draw.rect(screen, WHITE, self.rect, 2, border_radius=5)
        
        # Индикатор прочности для прочных блоков
        if self.block_type == 2 and self.hits == 2:
            pygame.draw.rect(screen, GOLD, self.rect.inflate(-10, -10), border_radius=3)

class Ball:
    """Класс мяча"""
    def __init__(self, x, y):
        self.x = x
        self.y = y
        self.radius = BALL_RADIUS
        self.speed = BALL_SPEED
        angle = random.uniform(-60, 60)
        self.dx = self.speed * math.sin(math.radians(angle))
        self.dy = -self.speed * math.cos(math.radians(angle))
        self.active = False
        
    def move(self):
        if self.active:
            self.x += self.dx
            self.y += self.dy
            
    def draw(self, screen):
        pygame.draw.circle(screen, WHITE, (int(self.x), int(self.y)), self.radius)
        pygame.draw.circle(screen, CYAN, (int(self.x), int(self.y)), self.radius - 2)
        
    def get_rect(self):
        return pygame.Rect(self.x - self.radius, self.y - self.radius, 
                          self.radius * 2, self.radius * 2)

class Paddle:
    """Класс каретки"""
    def __init__(self):
        self.width = PADDLE_WIDTH
        self.height = PADDLE_HEIGHT
        self.x = SCREEN_WIDTH // 2 - self.width // 2
        self.y = SCREEN_HEIGHT - 50
        self.speed = PADDLE_SPEED
        self.enlarged = False
        self.enlarge_timer = 0
        
    def move(self, direction):
        self.x += direction * self.speed
        self.x = max(0, min(SCREEN_WIDTH - self.width, self.x))
        
    def draw(self, screen):
        # Градиентная каретка
        rect = pygame.Rect(self.x, self.y, self.width, self.height)
        color = GREEN if self.enlarged else BLUE
        pygame.draw.rect(screen, color, rect, border_radius=7)
        pygame.draw.rect(screen, WHITE, rect, 2, border_radius=7)
        
        # Блик
        highlight = pygame.Rect(self.x + 5, self.y + 2, self.width - 10, 3)
        pygame.draw.rect(screen, WHITE, highlight, border_radius=2)
        
    def get_rect(self):
        return pygame.Rect(self.x, self.y, self.width, self.height)
        
    def enlarge(self):
        if not self.enlarged:
            self.width = int(PADDLE_WIDTH * 1.5)
            self.enlarged = True
            self.enlarge_timer = 600  # 10 секунд при 60 FPS
            
    def update(self):
        if self.enlarged:
            self.enlarge_timer -= 1
            if self.enlarge_timer <= 0:
                self.width = PADDLE_WIDTH
                self.enlarged = False

class PowerUp:
    """Класс способности"""
    def __init__(self, x, y, power_type):
        self.x = x
        self.y = y
        self.width = 30
        self.height = 20
        self.type = power_type  # 'multiball' или 'enlarge'
        self.speed = 3
        self.colors = {
            'multiball': ORANGE,
            'enlarge': GREEN
        }
        self.symbols = {
            'multiball': 'M',
            'enlarge': 'E'
        }
        
    def move(self):
        self.y += self.speed
        
    def draw(self, screen, font):
        rect = pygame.Rect(self.x, self.y, self.width, self.height)
        pygame.draw.rect(screen, self.colors[self.type], rect, border_radius=5)
        pygame.draw.rect(screen, WHITE, rect, 2, border_radius=5)
        
        symbol = font.render(self.symbols[self.type], True, WHITE)
        symbol_rect = symbol.get_rect(center=rect.center)
        screen.blit(symbol, symbol_rect)
        
    def get_rect(self):
        return pygame.Rect(self.x, self.y, self.width, self.height)

class Particle:
    """Класс частицы для эффектов"""
    def __init__(self, x, y, color):
        self.x = x
        self.y = y
        self.color = color
        self.dx = random.uniform(-3, 3)
        self.dy = random.uniform(-3, 3)
        self.lifetime = random.randint(20, 40)
        self.size = random.randint(2, 5)
        
    def update(self):
        self.x += self.dx
        self.y += self.dy
        self.lifetime -= 1
        self.size = max(1, self.size - 0.1)
        
    def draw(self, screen):
        if self.lifetime > 0:
            pygame.draw.circle(screen, self.color, (int(self.x), int(self.y)), int(self.size))

class Game:
    """Основной класс игры"""
    def __init__(self):
        self.screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
        pygame.display.set_caption("Арканойд")
        self.clock = pygame.time.Clock()
        
        # Шрифты
        self.font_large = pygame.font.Font(None, 72)
        self.font_medium = pygame.font.Font(None, 48)
        self.font_small = pygame.font.Font(None, 32)
        
        # Состояние игры
        self.state = "menu"  # menu, playing, paused, game_over, level_complete, win
        self.level = 1
        self.lives = 3
        self.score = 0
        
        # Игровые объекты
        self.paddle = None
        self.balls = []
        self.blocks = []
        self.powerups = []
        self.particles = []
        
        # Кнопки меню
        self.create_menu_buttons()
        
    def create_menu_buttons(self):
        """Создание кнопок меню"""
        center_x = SCREEN_WIDTH // 2 - 100
        self.start_button = Button(center_x, 300, 200, 50, "СТАРТ", BLUE, CYAN)
        self.quit_button = Button(center_x, 380, 200, 50, "ВЫХОД", RED, ORANGE)
        self.continue_button = Button(center_x, 300, 200, 50, "ПРОДОЛЖИТЬ", GREEN, CYAN)
        self.menu_button = Button(center_x, 380, 200, 50, "В МЕНЮ", RED, ORANGE)
        self.restart_button = Button(center_x, 300, 200, 50, "ЗАНОВО", GREEN, CYAN)
        self.next_level_button = Button(center_x, 300, 200, 50, "ДАЛЬШЕ", GREEN, CYAN)
        
    def generate_level(self, level):
        """Генерация уровня"""
        self.blocks = []
        
        # Параметры уровней
        level_configs = {
            1: {'rows': 4, 'cols': 10, 'strong_chance': 0.0, 'pattern': 'full'},
            2: {'rows': 5, 'cols': 10, 'strong_chance': 0.1, 'pattern': 'checker'},
            3: {'rows': 5, 'cols': 10, 'strong_chance': 0.2, 'pattern': 'pyramid'},
            4: {'rows': 6, 'cols': 10, 'strong_chance': 0.3, 'pattern': 'diamond'},
            5: {'rows': 7, 'cols': 10, 'strong_chance': 0.4, 'pattern': 'fortress'}
        }
        
        config = level_configs[level]
        
        start_x = (SCREEN_WIDTH - (config['cols'] * (BLOCK_WIDTH + BLOCK_PADDING))) // 2
        start_y = 60
        
        for row in range(config['rows']):
            for col in range(config['cols']):
                x = start_x + col * (BLOCK_WIDTH + BLOCK_PADDING)
                y = start_y + row * (BLOCK_HEIGHT + BLOCK_PADDING)
                
                # Проверка паттерна
                should_place = True
                if config['pattern'] == 'checker':
                    should_place = (row + col) % 2 == 0
                elif config['pattern'] == 'pyramid':
                    center = config['cols'] // 2
                    should_place = abs(col - center) <= (config['rows'] - row)
                elif config['pattern'] == 'diamond':
                    center_col = config['cols'] // 2
                    center_row = config['rows'] // 2
                    should_place = abs(col - center_col) + abs(row - center_row) <= max(center_col, center_row)
                elif config['pattern'] == 'fortress':
                    # Крепость с пробелами
                    should_place = not (row == 2 and 3 <= col <= 6)
                    
                if should_place:
                    block_type = 2 if random.random() < config['strong_chance'] else 1
                    self.blocks.append(Block(x, y, block_type))
                    
    def reset_ball(self):
        """Сброс мяча на каретку"""
        self.balls = [Ball(self.paddle.x + self.paddle.width // 2, self.paddle.y - BALL_RADIUS - 5)]
        self.balls[0].active = False
        
    def start_game(self):
        """Начало новой игры"""
        self.level = 1
        self.lives = 3
        self.score = 0
        self.start_level()
        
    def start_level(self):
        """Начало уровня"""
        self.paddle = Paddle()
        self.powerups = []
        self.particles = []
        self.generate_level(self.level)
        self.reset_ball()
        self.state = "playing"
        
    def handle_collisions(self):
        """Обработка столкновений"""
        for ball in self.balls[:]:
            # Столкновение со стенами
            if ball.x - ball.radius <= 0 or ball.x + ball.radius >= SCREEN_WIDTH:
                ball.dx = -ball.dx
                ball.x = max(ball.radius, min(SCREEN_WIDTH - ball.radius, ball.x))
                
            if ball.y - ball.radius <= 0:
                ball.dy = -ball.dy
                ball.y = ball.radius
                
            # Падение мяча
            if ball.y + ball.radius >= SCREEN_HEIGHT:
                self.balls.remove(ball)
                if len(self.balls) == 0:
                    self.lives -= 1
                    if self.lives <= 0:
                        self.state = "game_over"
                    else:
                        self.reset_ball()
                continue
                
            # Столкновение с кареткой
            paddle_rect = self.paddle.get_rect()
            ball_rect = ball.get_rect()
            
            if ball_rect.colliderect(paddle_rect) and ball.dy > 0:
                # Расчет угла отскока в зависимости от места удара
                hit_pos = (ball.x - self.paddle.x) / self.paddle.width
                angle = (hit_pos - 0.5) * 120  # от -60 до 60 градусов
                
                speed = math.sqrt(ball.dx**2 + ball.dy**2)
                ball.dx = speed * math.sin(math.radians(angle))
                ball.dy = -abs(speed * math.cos(math.radians(angle)))
                ball.y = paddle_rect.top - ball.radius
                
                # Частицы
                for _ in range(5):
                    self.particles.append(Particle(ball.x, ball.y, CYAN))
                
            # Столкновение с блоками
            for block in self.blocks[:]:
                if ball_rect.colliderect(block.rect):
                    # Определение стороны столкновения
                    overlap_left = ball_rect.right - block.rect.left
                    overlap_right = block.rect.right - ball_rect.left
                    overlap_top = ball_rect.bottom - block.rect.top
                    overlap_bottom = block.rect.bottom - ball_rect.top
                    
                    min_overlap = min(overlap_left, overlap_right, overlap_top, overlap_bottom)
                    
                    if min_overlap == overlap_left or min_overlap == overlap_right:
                        ball.dx = -ball.dx
                    else:
                        ball.dy = -ball.dy
                        
                    # Обработка удара по блоку
                    destroyed = block.hit()
                    if destroyed:
                        self.blocks.remove(block)
                        self.score += 10 * block.block_type
                        
                        # Создание частиц
                        for _ in range(10):
                            self.particles.append(Particle(
                                block.rect.centerx, block.rect.centery,
                                random.choice([RED, ORANGE, YELLOW, WHITE])
                            ))
                            
                        # Шанс выпадения способности
                        if random.random() < block.powerup_chance:
                            power_type = random.choice(['multiball', 'enlarge'])
                            self.powerups.append(PowerUp(
                                block.rect.centerx - 15,
                                block.rect.centery,
                                power_type
                            ))
                    else:
                        self.score += 5
                        
                    break  # Только одно столкновение за кадр
                    
    def handle_powerups(self):
        """Обработка способностей"""
        paddle_rect = self.paddle.get_rect()
        
        for powerup in self.powerups[:]:
            powerup.move()
            
            # Проверка выхода за экран
            if powerup.y > SCREEN_HEIGHT:
                self.powerups.remove(powerup)
                continue
                
            # Проверка подбора
            if powerup.get_rect().colliderect(paddle_rect):
                if powerup.type == 'multiball':
                    # Раздвоение всех мячей
                    new_balls = []
                    for ball in self.balls:
                        if ball.active:
                            new_ball = Ball(ball.x, ball.y)
                            new_ball.active = True
                            new_ball.dx = -ball.dx
                            new_ball.dy = ball.dy
                            new_balls.append(new_ball)
                    self.balls.extend(new_balls)
                    
                elif powerup.type == 'enlarge':
                    self.paddle.enlarge()
                    
                self.powerups.remove(powerup)
                self.score += 25
                
                # Эффект подбора
                for _ in range(15):
                    self.particles.append(Particle(
                        powerup.x + powerup.width // 2,
                        powerup.y + powerup.height // 2,
                        GREEN if powerup.type == 'enlarge' else ORANGE
                    ))
                    
    def update(self):
        """Обновление игрового состояния"""
        if self.state != "playing":
            return
            
        # Обновление каретки
        keys = pygame.key.get_pressed()
        if keys[pygame.K_LEFT] or keys[pygame.K_a]:
            self.paddle.move(-1)
        if keys[pygame.K_RIGHT] or keys[pygame.K_d]:
            self.paddle.move(1)
            
        self.paddle.update()
        
        # Обновление мячей
        for ball in self.balls:
            if ball.active:
                ball.move()
            else:
                # Мяч следует за кареткой
                ball.x = self.paddle.x + self.paddle.width // 2
                ball.y = self.paddle.y - BALL_RADIUS - 5
                
        # Обработка столкновений
        self.handle_collisions()
        
        # Обработка способностей
        self.handle_powerups()
        
        # Обновление частиц
        for particle in self.particles[:]:
            particle.update()
            if particle.lifetime <= 0:
                self.particles.remove(particle)
                
        # Проверка победы на уровне
        if len(self.blocks) == 0:
            if self.level < 5:
                self.state = "level_complete"
            else:
                self.state = "win"
                
    def draw_background(self):
        """Отрисовка фона"""
        self.screen.fill(BLACK)
        
        # Звездное небо
        random.seed(42)  # Фиксированный seed для стабильных звезд
        for _ in range(100):
            x = random.randint(0, SCREEN_WIDTH)
            y = random.randint(0, SCREEN_HEIGHT)
            size = random.randint(1, 2)
            brightness = random.randint(100, 255)
            pygame.draw.circle(self.screen, (brightness, brightness, brightness), (x, y), size)
        random.seed()  # Сброс seed
        
    def draw_ui(self):
        """Отрисовка интерфейса"""
        # Панель информации
        pygame.draw.rect(self.screen, DARK_GRAY, (0, 0, SCREEN_WIDTH, 50))
        pygame.draw.line(self.screen, WHITE, (0, 50), (SCREEN_WIDTH, 50), 2)
        
        # Уровень
        level_text = self.font_small.render(f"Уровень: {self.level}", True, WHITE)
        self.screen.blit(level_text, (20, 12))
        
        # Жизни
        lives_text = self.font_small.render(f"Жизни: {self.lives}", True, WHITE)
        self.screen.blit(lives_text, (200, 12))
        
        # Счет
        score_text = self.font_small.render(f"Счет: {self.score}", True, WHITE)
        self.screen.blit(score_text, (400, 12))
        
        # Количество мячей
        balls_text = self.font_small.render(f"Мячи: {len(self.balls)}", True, WHITE)
        self.screen.blit(balls_text, (600, 12))
        
        # Таймер увеличения каретки
        if self.paddle and self.paddle.enlarged:
            timer_text = self.font_small.render(f"Увеличение: {self.paddle.enlarge_timer // 60}с", True, GREEN)
            self.screen.blit(timer_text, (SCREEN_WIDTH // 2 - 80, SCREEN_HEIGHT - 20))
            
    def draw_menu(self):
        """Отрисовка главного меню"""
        self.draw_background()
        
        # Заголовок
        title = self.font_large.render("АРКАНОИД", True, CYAN)
        title_rect = title.get_rect(center=(SCREEN_WIDTH // 2, 150))
        self.screen.blit(title, title_rect)
        
        # Подзаголовок
        subtitle = self.font_small.render("Python Edition", True, WHITE)
        subtitle_rect = subtitle.get_rect(center=(SCREEN_WIDTH // 2, 210))
        self.screen.blit(subtitle, subtitle_rect)
        
        # Кнопки
        mouse_pos = pygame.mouse.get_pos()
        self.start_button.check_hover(mouse_pos)
        self.quit_button.check_hover(mouse_pos)
        
        self.start_button.draw(self.screen, self.font_small)
        self.quit_button.draw(self.screen, self.font_small)
        
        # Инструкции
        instructions = [
            "Управление: ← → или A D",
            "Пробел - запуск мяча",
            "ESC - пауза"
        ]
        for i, text in enumerate(instructions):
            inst = self.font_small.render(text, True, GRAY)
            inst_rect = inst.get_rect(center=(SCREEN_WIDTH // 2, 480 + i * 30))
            self.screen.blit(inst, inst_rect)
            
    def draw_pause(self):
        """Отрисовка паузы"""
        # Затемнение
        overlay = pygame.Surface((SCREEN_WIDTH, SCREEN_HEIGHT))
        overlay.fill(BLACK)
        overlay.set_alpha(128)
        self.screen.blit(overlay, (0, 0))
        
        # Текст паузы
        pause_text = self.font_large.render("ПАУЗА", True, WHITE)
        pause_rect = pause_text.get_rect(center=(SCREEN_WIDTH // 2, 200))
        self.screen.blit(pause_text, pause_rect)
        
        # Кнопки
        mouse_pos = pygame.mouse.get_pos()
        self.continue_button.check_hover(mouse_pos)
        self.menu_button.check_hover(mouse_pos)
        
        self.continue_button.draw(self.screen, self.font_small)
        self.menu_button.draw(self.screen, self.font_small)
        
    def draw_game_over(self):
        """Отрисовка экрана поражения"""
        self.draw_background()
        
        # Текст
        game_over = self.font_large.render("ИГРА ОКОНЧЕНА", True, RED)
        game_over_rect = game_over.get_rect(center=(SCREEN_WIDTH // 2, 150))
        self.screen.blit(game_over, game_over_rect)
        
        score_text = self.font_medium.render(f"Ваш счет: {self.score}", True, WHITE)
        score_rect = score_text.get_rect(center=(SCREEN_WIDTH // 2, 230))
        self.screen.blit(score_text, score_rect)
        
        # Кнопки
        mouse_pos = pygame.mouse.get_pos()
        self.restart_button.check_hover(mouse_pos)
        self.menu_button.check_hover(mouse_pos)
        
        self.restart_button.draw(self.screen, self.font_small)
        self.menu_button.rect.y = 380
        self.menu_button.draw(self.screen, self.font_small)
        
    def draw_level_complete(self):
        """Отрисовка экрана завершения уровня"""
        self.draw_background()
        
        # Текст
        complete = self.font_large.render(f"УРОВЕНЬ {self.level}", True, GREEN)
        complete_rect = complete.get_rect(center=(SCREEN_WIDTH // 2, 150))
        self.screen.blit(complete, complete_rect)
        
        complete2 = self.font_medium.render("ПРОЙДЕН!", True, WHITE)
        complete2_rect = complete2.get_rect(center=(SCREEN_WIDTH // 2, 220))
        self.screen.blit(complete2, complete2_rect)
        
        # Кнопка
        mouse_pos = pygame.mouse.get_pos()
        self.next_level_button.check_hover(mouse_pos)
        self.next_level_button.draw(self.screen, self.font_small)
        
    def draw_win(self):
        """Отрисовка экрана победы"""
        self.draw_background()
        
        # Текст
        win = self.font_large.render("ПОБЕДА!", True, GOLD)
        win_rect = win.get_rect(center=(SCREEN_WIDTH // 2, 150))
        self.screen.blit(win, win_rect)
        
        score_text = self.font_medium.render(f"Финальный счет: {self.score}", True, WHITE)
        score_rect = score_text.get_rect(center=(SCREEN_WIDTH // 2, 230))
        self.screen.blit(score_text, score_rect)
        
        congrats = self.font_small.render("Поздравляем! Вы прошли все уровни!", True, CYAN)
        congrats_rect = congrats.get_rect(center=(SCREEN_WIDTH // 2, 280))
        self.screen.blit(congrats, congrats_rect)
        
        # Кнопки
        mouse_pos = pygame.mouse.get_pos()
        self.restart_button.check_hover(mouse_pos)
        self.menu_button.check_hover(mouse_pos)
        
        self.restart_button.draw(self.screen, self.font_small)
        self.menu_button.rect.y = 380
        self.menu_button.draw(self.screen, self.font_small)
        
    def draw(self):
        """Отрисовка игры"""
        if self.state == "menu":
            self.draw_menu()
        elif self.state == "playing" or self.state == "paused":
            self.draw_background()
            
            # Отрисовка игровых объектов
            for block in self.blocks:
                block.draw(self.screen)
                
            for powerup in self.powerups:
                powerup.draw(self.screen, self.font_small)
                
            self.paddle.draw(self.screen)
            
            for ball in self.balls:
                ball.draw(self.screen)
                
            for particle in self.particles:
                particle.draw(self.screen)
                
            self.draw_ui()
            
            # Подсказка для запуска мяча
            if self.balls and not self.balls[0].active:
                hint = self.font_small.render("Нажмите ПРОБЕЛ для запуска", True, WHITE)
                hint_rect = hint.get_rect(center=(SCREEN_WIDTH // 2, SCREEN_HEIGHT // 2))
                self.screen.blit(hint, hint_rect)
                
            if self.state == "paused":
                self.draw_pause()
                
        elif self.state == "game_over":
            self.draw_game_over()
        elif self.state == "level_complete":
            self.draw_level_complete()
        elif self.state == "win":
            self.draw_win()
            
        pygame.display.flip()
        
    def handle_events(self):
        """Обработка событий"""
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                return False
                
            if event.type == pygame.MOUSEBUTTONDOWN:
                mouse_pos = pygame.mouse.get_pos()
                
                if self.state == "menu":
                    if self.start_button.is_clicked(mouse_pos, True):
                        self.start_game()
                    elif self.quit_button.is_clicked(mouse_pos, True):
                        return False
                        
                elif self.state == "paused":
                    if self.continue_button.is_clicked(mouse_pos, True):
                        self.state = "playing"
                    elif self.menu_button.is_clicked(mouse_pos, True):
                        self.state = "menu"
                        
                elif self.state == "game_over":
                    if self.restart_button.is_clicked(mouse_pos, True):
                        self.start_game()
                    elif self.menu_button.is_clicked(mouse_pos, True):
                        self.state = "menu"
                        self.menu_button.rect.y = 380
                        
                elif self.state == "level_complete":
                    if self.next_level_button.is_clicked(mouse_pos, True):
                        self.level += 1
                        self.lives = 3
                        self.start_level()
                        
                elif self.state == "win":
                    if self.restart_button.is_clicked(mouse_pos, True):
                        self.start_game()
                    elif self.menu_button.is_clicked(mouse_pos, True):
                        self.state = "menu"
                        self.menu_button.rect.y = 380
                        
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_ESCAPE:
                    if self.state == "playing":
                        self.state = "paused"
                    elif self.state == "paused":
                        self.state = "playing"
                        
                if event.key == pygame.K_SPACE and self.state == "playing":
                    for ball in self.balls:
                        if not ball.active:
                            ball.active = True
                            angle = random.uniform(-30, 30)
                            ball.dx = BALL_SPEED * math.sin(math.radians(angle))
                            ball.dy = -BALL_SPEED
                            
        return True
        
    def run(self):
        """Основной игровой цикл"""
        running = True
        while running:
            running = self.handle_events()
            self.update()
            self.draw()
            self.clock.tick(FPS)
            
        pygame.quit()

# Запуск игры
if __name__ == "__main__":
    game = Game()
    game.run()

В финале тестирования модель создаст шифратор и дешифратор для файлов Word.

Скрытый текст

Здесь тоже все идеально: шифры работают корректно, а дешифрация выполняется без проблем. Три теста из трех пройдены на отлично.


Вывод

Что можно сказать насчет Claude Opus 4.5? То же, что и многие успели упомянуть за это время: модель просто поражает своими возможностями в программировании, хотя мое погружение в эту сферу было лишь поверхностным. Пожалуй, в задачах программирования для меня теперь избран однозначный фаворит.

Спасибо за прочтение!

Комментарии (5)


  1. AdrianoVisoccini
    05.12.2025 08:56

    Напиши "калькулятор", напиши "арканоид"... ну модель же в данном случае даже не решает задачу в полной мере а просто перебирает уже кем-то реализованные варианты, может вместо арканоида стоит написать:


    - Здраствуйте. Я, Кирилл. Хотел бы чтобы вы сделали игру, 3Д-экшон суть такова... Пользователь может играть лесными эльфами, охраной дворца и злодеем. И если пользователь играет эльфами то эльфы в лесу, домики деревяные набигают солдаты дворца и злодеи. Можно грабить корованы...

    И посомртреть какой тогда результат будет?


    1. MrRjxrby Автор
      05.12.2025 08:56

      Достаточно интересная задумка, попробую.


  1. ManulVRN
    05.12.2025 08:56

    Арканойд, блин. Я один страдаю от произвольно расставляемой буквы "й"?


  1. vanyas
    05.12.2025 08:56

    Но, к сожалению, Опус не доступен в pro подписке claude code...


    1. positroid
      05.12.2025 08:56

      Доступен