Доброго времени суток, «Хабр»!
Немногим больше, чем неделя назад, мир получил новую модель - 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? То же, что и многие успели упомянуть за это время: модель просто поражает своими возможностями в программировании, хотя мое погружение в эту сферу было лишь поверхностным. Пожалуй, в задачах программирования для меня теперь избран однозначный фаворит.
Спасибо за прочтение!
Комментарии (30)

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

positroid
05.12.2025 08:56
Доступен

rbdr
05.12.2025 08:56Доступен, но после пары вопросов снова будет недоступен :)

LuckyJewish
05.12.2025 08:56Эту проблему как раз и решили.
На него убрали отдельный лимит и удешевили модель в 3 раза, сейчас на про только им и пользуюсь. Плюс - сжатие контекста в длинных диалогах.
Это всё буквально было написано в релизе модели, если что...

rbdr
05.12.2025 08:56Да я им и пользуюсь на мах5 подписке - он сейчас новый главный конь платформы. Речь про про за 20, которой хватает на совсем ничего - чисто слюну пустить и купить макс. На реддите ровно на эту тему есть посты.

LuckyJewish
05.12.2025 08:56Ну, я использую его не для программирования, а для других прикладных задач, так что мне хватает)

nidalee
05.12.2025 08:56Да, по ощущениям где-то с конца октября аппетиты у claude code выросли очень сильно - оно теперь на редактирование не то чтобы шибко умного одностраничника с js готово смело выжрать 60-80к токенов в режиме plan. Я вот вчера снова проплатил и удивился, как быстро 33% pro за 20 баксов улетело считай что за сутки.
Так что не знаю, где и что там они удешевили, но явно наверстали внутренними инструкциями "дуй контекст как только можешь".

Nayaso
05.12.2025 08:56Так же можно сказать про claude code. После выхода opus 4.5 сильно оптимизировали агентный поиск в коде. Многие говорят что калькулятор - не показатель уровня, но я протестил и в больших проектах. Итог - причину проблемы находит идеально (может запустить несколько агентов с разными задачами параллельно и анализировать результаты) а исправляет как надо, особенно нравится как он использует askquestion инструмент собирая уточнения при решений проблемы.

ArZr
05.12.2025 08:56Могу ошибаться, но при поверхностном просмотре кода Арканоида возникли некоторые вопросы:
hit_pos = (ball.x - self.paddle.x) / self.paddle.widthangle = (hit_pos - 0.5) * 120 # от -60 до 60 градусовСудя по коду коллизий, hit_pos находится в пределах [-ball.radius/self.paddle.width, 1 + ball.radius/self.paddle.width], а не [0, 1], как предполагается. В случае изменений соответствующих параметров может возникнуть всякое странное. Зависимость угла отскока от расстояния по "x" между центром шара и левым краем платформы тоже выглядит немного странно (представьте огромную платформу и совсем-совсем маленький шар), но в данном контексте это не очень критично
ifevent.key == pygame.K_SPACEandself.state == "playing":...angle = random.uniform(-30, 30)ball.dx = BALL_SPEED * math.sin(math.radians(angle))ball.dy = -BALL_SPEEDСудя по тому, как это обрабатывается в других частях, тут потерялся косинус.
Возможно, есть ещё что-то (а может и нет, потому что код простой; всякие мелкие моменты, которые можно улучшить, не в счет). Интересно было бы скопировать весь код Арканоида в модель и поспрашивать, в каких местах могут возникнуть проблемы и при каких обстоятельствах.

SlavaVSLK
05.12.2025 08:56На днях в курсоре была доступна opus 4.5 max, попробовал на нескольких ежедневных задачах, не сказал бы, что прям сильно отличается...

Nik_Otin
05.12.2025 08:56Я не знаю как у людей получается кодить промтами, мне быстро надоело. Без ошибок ни один ИИ не может написать не то что программу, а простейшую процедуру. Причем когда ему указываешь на ошибку, он соглашается и продолжает её делать. Путается в версиях ЯП, применяет несуществующие функции, не понимает простейших инструкций. Новый супер-пупер Claude Opus 4.5 не сомг мне рассказать как в Visual Studio положить две панели на форму так чтобы одна была прижата к верхней части формы, а другая к нижней. Всё время указывал на несуществующее свойство Dock. Я уже ему и скриншоты давал, он делал вид что посмотрел, соглашался и продолжал писать что надо изменить это свойство.

hulitolku
05.12.2025 08:56Следует проанализировать свои промты, видимо плохо синхронизировались с ИИ.

Nik_Otin
05.12.2025 08:56Как говорится в правильном вопросе должно содержаться как минимум 50% ответа. )) Не спорю, возможно просто неверно общаюсь с ИИ и нужно какие-то команды давать чтобы он правильно меня понимал, причем желательно на английском языке. Но мне кажется в этом случае сложность вайбкодинга будет выше обычного с неоднозначным результатом - раздутый код, высокое потребление ресурсов, проблемы с защитой и т.д. По моему мнению на текущий момент вайбкодинг годится только на очень простых проектах, а и то - с оговорками.

muhachev
05.12.2025 08:56CLAUDE.md или для других свои инструктивные файлы нормальные сперва надо делать. Они только их слушаются всегда. Почти.

sidewinder1
05.12.2025 08:56Помните про принцип "garbage in - garbage out ". Если не получается с одного промпта - добавьте модели правило задавать уточняющие вопросы.

imanushin
05.12.2025 08:56Это зависит от сложности запроса, а точнее - от того, насколько много уже готовых/похожих ответов есть на GitHub/StackOverflow.
Например, если задать вопрос "напиши перевод из двоичной системы в десятичную на питоне", то реализация будет идеальной. Но если вопрос будет в стиле "на С++ версии С++11 скорректируй модуль большого приложения А, с учетом требований Б и без явных проблем с памятью/производительностью", то вероятность ответа будет стремиться к нулю. Правда, во второй части LLM может неплохо сделать ревью кода, так что определенный процент рекомендаций будет даже полезен.
Собственно, из-за этого и разнятся отзывы об LLM - очень популярные задачи на очень популярных технологиях (и, желательно, без своих типов) генерятся очень хорошо, тогда как если у человека работа в другой области, то LLM превращается в просто слегка более умный autocomplete.

Nik_Otin
05.12.2025 08:56Как помощник ИИ это огромный шаг вперед. Мне он по большей части облегчил работу в тривиальных случаях, когда надо писать много очевидного когда. Например создать sql сложный запрос. Мне проще скопировать структуру таблиц и сказать что хочу - он создаст довольно рабочий код. Но когда дело касается версионности ЯП (функция новая или изменена, или убрана) - он плывёт, когда дело касается сложной логики - он плывёт, когда дело касается обработки образов - он плывёт, когда дело касается творчества - он плывёт. Да бог бы с ним, кто без греха, но он упорствует в своих ошибках. Формально он их признает, соглашается и... продолжает их делать. Сказал бы просто - не знаю, я бы понял. или хотя бы уточняющие вопросы задал. Так нет, утверждает что так и должно быть - вот сейчас -то 100% всё в порядке, а смотришь - всё осталось как есть или изменено, но так же неправильно, т.е. одну ошибку поменял на другую оставив суть ошибки.

nidalee
05.12.2025 08:561) Я для discord написал интеграшку с comfyui (чистый python), чтобы генерировать картинки из дискорда.

Простите, с работы только так. Это все используется несколькими людьми ежедневно, все со скриншота работает, ничего не утекает и не падает (в "проде" работает примерно с конца лета).
2) Переписал TunProxy (java + C -> kotlin + c), чтобы принимал HTTPS прокси с авторизацией, и выглядел субъективно посимпатичнее.

Оригинал: https://github.com/raise-isayan/TunProxy 3) Написал велосипед для отложенного постинга (по расписанию) в communities twitter\x (html + css + js).
Первые два примерно за неделю-две не сильно плотного вайбкодинга (а-ля "http -> https работает, логин:пароль работают, что бы еще добавить?"), третий за сутки.
Мне кажется, что программисты, которые пишут, что "без ошибок ни один ИИ не может написать не то что программу, а простейшую процедуру", в принципе не хотят, чтобы ИИ им написал программу или процедуру. Чтобы себе или кому-то что-то доказать. Потому что если я без знания языков могу навайбкодить что-то работающее, то уж вы со знанием точно должны.
Это туда же.

Nik_Otin
05.12.2025 08:56Когда "в принципе не хотят", не убивают на это несколько дней времени и не пытаются вновь и вновь этим пользоваться. Так что ваше предположение не верно, я не только хочу, я пользуюсь и пишу исходя из личного опыта. Всё что даёт ИИ приходится дорабатывать, а иногда так вообще быстрее самому сделать, чем получить от ИИ то что хочешь. И если вы не программист со стажем, то вам не понять, что поделки ИИ - вообще не программа, а именно поделки. Там не пахнет ни удобством, ни эстетикой и с кучей условностей. Я уж молчу про раздутый код и вечные ошибки. Нет, конечно если программа предполагает 3 кнопки и пару всем известных функций не зависящих от версионности ЯП, то ИИ с этим справится. Но если копнуть чуть глубже, например попросить построить программу отображающую 3D мир на основе загруженного файла своего формата, в котором описана поверхность - высота земли, тип объекта, высота объекта и при этом нужно чтобы по этому миру можно было двигаться, вращать и т.д., учитывая что это область (в смысле регион РФ) с 50-метровой точностью, то увы. Тут он уже пасует на всём чем можно. Но ладно, допустим для него это через чур сложная программа,, можно попросить его написать html страницу по картинке - ни в жизнь не сделает как на картинке, как не проси. Разве что расписать по косточкам какие элементы где должны стоять и какие стили должны быть применены. Но такое описание по сути уже и есть HTML страница, смысл мне тогда всё это писать словами, когда можно быстрее закодить.
А так-то да, контента и недопрограмм развелось просто звиздец, в этом море гавна утонуть можно. И уже кажется что это норма. Другими словами ИИ что-то генерит.
nidalee
05.12.2025 08:56Я не программист, но так со стороны - рендерить 3D мир - это задача нетривиальная, люди для этого движки пишут. Это ведь блендер по сути. Вы пытаетесь свой написать, или приспособить чужой? Так из описания не понял.
В любом случае, не ожидаю в таком случае чуда от ИИ, но встречный вопрос: вот вы несколько дней времени убили, а лично вы сколько такое будете писать без ИИ?

Nik_Otin
05.12.2025 08:56Движок понятно не пишу, а использую готовый. Я такое всё же написал без ИИ, правда не совсем то что хотел. Я хотел произвести на заказчика ВАУ-эффект, хотел сделать что-то вроде 3D игры. Но пришлось воспользоваться тем что знал - geo web. Это типа яндекс карт 3D. Заказчика устроило, он тут особых требований не ставил и не знал о моих желаниях ))
И задача не супер сложная на самом деле. Если знаешь как пользоваться готовыми наработками. Там выходит довольно небольшая программа - буквально 2-3 модуля в 1000 строк в среднем. Но я в этой области не специалист, потому чтобы решать задачу, надо изучать тему работы с этими компонентами. А на это надо время. Поэтому собственно и обратился к ИИ. Потерял неделю и на выходе фиаско.Я ИИ пользуюсь как помощником. Иногда это проще и быстрее, чем писать самому, особенно на очевидных вещах. Но вот того, про что пишут как ИИ круто может делать программы - так и не увидел. Более того, прогресса начиная с ChatGPT 3 особого не вижу. Единственный прорыв в ИИ в этом году я видел у Suno AI, но это не про программирование. Хотя и там есть куда развиваться.

nidalee
05.12.2025 08:56А можете мне написать такое своего рода ТЗ? И дать файлик, который нужно открыть. Интересно, что у меня получится за пару часов.
Более того, прогресса начиная с ChatGPT 3 особого не вижу.
Ой, ну вы скажете тоже. ChatGPT - это когда ты ему один файлик весьма ограниченного размера кидаешь, а он пытается тебе что-то по нему сказать, блок кода в ответ выдать исправленный или сниппет. Я так выстрадывал конвертацию своего AHK скрипта в Python.
Claude Code - это когда я пишу так:
Things to fix:
In queue, previews are broken (empty boxes). Text data is fine.
In compose, unconfigured and unavailiable platforms should be disabled.
In queue, color-code the platform\user.
In queue, differ style of cards depending on their status (posted \ waiting). Maybe grey done out.
In compose, deleting image from media box triggers file selection window. It shouldn't on user pressing X.
И он делает все сам за минуту-другую.
Еще более продвинутый вокрфлоу - это когда агент сам из похожего списка хотелок делает полноценное ТЗ:
Из:
Add periodic update check. 24-hour interval checks using WorkManager Proper notification handling when updates are available
В:
Implement a 24-hour periodic background update check using Android WorkManager that notifies users when a new app version is available.
Requirements
-
WorkManager Integration:
Create a periodic PeriodicWorkRequest with 24-hour interval
Implement a Worker class (UpdateCheckWorker) to perform the update check
-
Notification Handling:
Create a notification channel for update notifications (IMPORTANCE_DEFAULT)
Generate a notification when an update is available
-
Notification should include:
Title: "Update Available"
Description: App version info (current vs. new)
Action button: "Update" that runs in-app update
Notification ID: Use a consistent ID to allow replacing/updating the notification
-
Background Work:
Schedule WorkManager task on app startup (in MyApplication or MainActivity)
Ensure work is persisted across device reboots
Use BackoffPolicy for retry on failures (exponential with min/max delays)
Add appropriate logging for diagnostics
Acceptance Criteria
Periodic work request is scheduled with 24-hour interval
Notifications are shown when updates are available
Notification channel is created before API 26+
Work persists across app restarts
Proper error handling and logging throughout
No crashes or ANRs when performing background checks

Nik_Otin
05.12.2025 08:56Нет, файлик дать не могу - связан условиями контракта. А ТЗ в общем я описал, там дополнение только то что надо было отображать послойно покрытие (определенная область) внутри зданий. Но я завалился на отображении мира.

nidalee
05.12.2025 08:56Я понял. Ну без файла я просто скорее всего нагорожу что-то совершенно левое, но суть я понял, думаю, что одним ИИ это не делается. Максимум какие-то части.
AdrianoVisoccini
Напиши "калькулятор", напиши "арканоид"... ну модель же в данном случае даже не решает задачу в полной мере а просто перебирает уже кем-то реализованные варианты, может вместо арканоида стоит написать:
И посомртреть какой тогда результат будет?
MrRjxrby Автор
Достаточно интересная задумка, попробую.
SergTaranov
Эту задачу делали уже, как только нейросети более- менее рабочий код стали выдавать