Почему «Сапер» — идеальный тест для ИИ-кодеров?
Когда мы говорим о генерации кода искусственным интеллектом, большинство примеров ограничиваются простыми функциями или фрагментами. Но настоящая проверка — создать целостное приложение с логикой, интерфейсом и обработкой ошибок. Классическая игра «Сапер» идеально подходит для этого теста по нескольким причинам:
- Средняя сложность: Не слишком просто (как «Крестики-нолики»), но и не космический симулятор
- Четкие правила: Алгоритм подсчета мин вокруг клетки — отличный тест на логику
- Требуется интерфейс: Консольный или графический — уже вызов
- Известный паттерн: Модели должны быть знакомы с концепцией
Методология теста: Каждой модели давалась одна и та же промпт-инструкция: «Создай игру "Сапер" на Python с консольным интерфейсом. Игра должна генерировать поле 10×10 с 15 минами, позволять открывать клетки и показывать количество мин вокруг. Реализуй проверку победы/поражения.» Время выполнения не ограничивалось, но фиксировалось количество итераций (запросов) до получения рабочего кода.
Участники битвы: 4 современных ИИ-кодера
| Модель | Производитель | Специализация | Контекст (токены) |
|---|---|---|---|
| OpenAI Codex (GPT-4) | OpenAI | Универсальная генерация кода | 128K |
| Claude Code (Claude 3.5 Sonnet) | Anthropic | Безопасность и рассуждения | 200K |
| Mistral Vibe (Mixtral 8x22B) | Mistral AI | Эффективность, офлайн-работа | 64K |
| Gemini CLI (Gemini 1.5 Pro) | Мультимодальность, поиск | 1M |
1 OpenAI Codex: Ветеран показывает класс
Codex, лежащий в основе GitHub Copilot, — самый опытный игрок на поле. Результат:
import random
class Minesweeper:
def __init__(self, width=10, height=10, mines=15):
self.width = width
self.height = height
self.mines = mines
self.board = [[0 for _ in range(width)] for _ in range(height)]
self.revealed = [[False for _ in range(width)] for _ in range(height)]
self.game_over = False
self.win = False
self.place_mines()
self.calculate_numbers()
def place_mines(self):
mines_placed = 0
while mines_placed < self.mines:
x = random.randint(0, self.width-1)
y = random.randint(0, self.height-1)
if self.board[y][x] != -1:
self.board[y][x] = -1 # -1 означает мину
mines_placed += 1
def calculate_numbers(self):
for y in range(self.height):
for x in range(self.width):
if self.board[y][x] == -1:
continue
count = 0
for dy in [-1, 0, 1]:
for dx in [-1, 0, 1]:
ny, nx = y + dy, x + dx
if 0 <= ny < self.height and 0 <= nx < self.width:
if self.board[ny][nx] == -1:
count += 1
self.board[y][x] = count
def reveal(self, x, y):
if not (0 <= x < self.width and 0 <= y < self.height):
return False
if self.revealed[y][x]:
return True
self.revealed[y][x] = True
if self.board[y][x] == -1:
self.game_over = True
return False
if self.board[y][x] == 0:
for dy in [-1, 0, 1]:
for dx in [-1, 0, 1]:
self.reveal(x + dx, y + dy)
self.check_win()
return True
def check_win(self):
for y in range(self.height):
for x in range(self.width):
if self.board[y][x] != -1 and not self.revealed[y][x]:
return
self.win = True
def display(self):
print(" " + " ".join(str(i) for i in range(self.width)))
for y in range(self.height):
row = f"{y:2} "
for x in range(self.width):
if not self.revealed[y][x]:
row += "# "
elif self.board[y][x] == -1:
row += "* "
elif self.board[y][x] == 0:
row += ". "
else:
row += f"{self.board[y][x]} "
print(row)
2 Claude Code: Перестраховщик с идеальным кодом
Claude известен своей осторожностью и вниманием к деталям. Его подход:
# ... (аналогичная структура класса, но с комментариями к каждому методу)
def play_game():
game = Minesweeper()
print("Добро пожаловать в Сапер!")
print("Вводите координаты в формате 'x y' (0-9).")
print("Для выхода введите 'exit'.")
while not game.game_over and not game.win:
game.display()
try:
user_input = input("\nВаш ход: ").strip()
if user_input.lower() == 'exit':
print("Игра завершена.")
return
parts = user_input.split()
if len(parts) != 2:
print("Ошибка: нужно ввести две координаты")
continue
x, y = map(int, parts)
if not game.reveal(x, y):
print("Некорректные координаты!")
except ValueError:
print("Ошибка: введите числа")
except KeyboardInterrupt:
print("\nИгра прервана.")
return
game.display()
if game.win:
print("\nПоздравляем! Вы победили!")
else:
print("\nБУМ! Вы наступили на мину!")
print("Игра окончена.")
Claude не только создал класс игры, но и полноценный игровой цикл с обработкой ошибок, включая KeyboardInterrupt. Код содержит подробные комментарии и сообщения для пользователя. Однако потребовалось 2 итерации: в первой версии не было рекурсивного открытия пустых клеток.
3 Mistral Vibe: Эффективный, но с ограничениями
Mistral Vibe, который можно запускать офлайн на своем компьютере, показал интересные результаты:
Проблема: Mistral сгенерировал код, который компилировался, но логика подсчета мин была ошибочной. Модель считала только 4 соседние клетки (по вертикали и горизонтали), игнорируя диагонали. Типичная ошибка новичка!
После уточняющего промпта «Учти, что мины могут быть по диагонали» Mistral исправил код, но потребовалось 3 итерации. Конечный результат рабочий, но код менее структурирован, чем у Codex и Claude.
4 Gemini CLI: Мультимодальный гигант споткнулся
Самое неожиданное поражение. Gemini 1.5 Pro с контекстом в 1 миллион токенов:
# Первая попытка Gemini:
board = [[0]*10 for _ in range(10)]
mines = []
for _ in range(15):
while True:
x, y = random.randint(0,9), random.randint(0,9)
if (x,y) not in mines:
mines.append((x,y))
board[y][x] = 'M'
break
# Проблема: нет подсчета чисел вокруг мин!
# Вместо этого сразу предложил функцию отображения...
Gemini пропустил ключевой шаг — подсчет чисел. После напоминания сгенерировал сложную функцию с ошибками в граничных условиях. Потребовалось 4 итерации для получения рабочего кода, и даже тогда интерфейс был минимальным.
Сводная таблица результатов
| Критерий | OpenAI Codex | Claude Code | Mistral Vibe | Gemini CLI |
|---|---|---|---|---|
| Рабочий код с 1 попытки | ✅ Да | ❌ Нет (2 попытки) | ❌ Нет (3 попытки) | ❌ Нет (4 попытки) |
| Полнота (игровой цикл) | ❌ Только логика | ✅ Полная игра | ❌ Только логика | ❌ Только логика |
| Качество кода (PEP8, структура) | ✅ Отличное | ✅ Идеальное | ⚪ Среднее | ⚪ Среднее |
| Обработка ошибок | ❌ Нет | ✅ Полная | ⚪ Базовая | ❌ Нет |
| Рекурсивное открытие пустых клеток | ✅ Есть | ✅ Есть | ✅ Есть (после правок) | ❌ Нет |
Выводы: когда какую модель использовать?
На основе этого теста можно сделать практические рекомендации:
- OpenAI Codex (GPT-4) — лучший выбор для быстрой генерации рабочего кода. Если нужно быстро получить основу и дорабатывать самостоятельно.
- Claude Code — идеален для production-ready кода. Если нужна полнота, обработка краевых случаев и безопасность. Отлично подойдет для создания продакшен-агентов.
- Mistral Vibe — хорош для офлайн-разработки и когда важна эффективность. Требует больше проверок, но работает локально.
- Gemini CLI — пока отстает в чистой генерации кода, несмотря на мультимодальность. Лучше использовать для анализа существующего кода или документации.
FAQ: Частые вопросы о тестировании ИИ для кодинга
Вопрос: Почему ИИ иногда генерирует код с очевидными ошибками?
ИИ работает на статистике, а не на понимании. Если в обучающих данных было много примеров с ошибкой (например, подсчет только 4 соседей), модель может воспроизвести эту ошибку. Всегда проверяйте критическую логику!
Вопрос: Стоит ли полностью доверять ИИ в создании сложных систем?
Нет. Как показал тест, даже для относительно простой игры потребовались итерации и проверки. Для сложных систем, вроде финансового трейдера на Python, ИИ — помощник, а не замена разработчика.
Вопрос: Как улучшить результаты генерации кода?
- Давайте четкие, конкретные требования
- Разбивайте задачу на подзадачи
- Просите объяснить логику перед генерацией кода
- Тестируйте каждый компонент отдельно
Что дальше? Будущее ИИ-кодинга
Тест показал, что современные ИИ уже способны генерировать рабочий код для нетривиальных задач. Но ключевое слово — «помощник». Лучшие результаты достигаются в симбиозе: человек задает архитектуру, проверяет логику, а ИИ генерирует шаблонный код, предлагает варианты, находит баги.
Интересно, что те же технологии ИИ, которые создают игры, используются в более серьезных областях — например, для оптимизации операционного времени в больницах. Принцип тот же: алгоритмы, логика, обработка данных.