Без лишних предисловий - давайте сделаем два абсолютно одинаковых запроса для создания приложения на SwiftUI и сравним, какая модель лучше справится с этими задачами.
Я решила дать два задания. Начнём с первого: нужно написать игру "Змейка", вот мой промпт:
Напиши полностью с нуля приложение на SwiftUI. В приложении должен быть один экран. Сделай простейший вариант игры змейка. Изначально зеленая змея из 3-х кваратиков, по мере съедания квадратика она увеличивается на 1 квадрат (квадратики которые она съедает - разных цветов)
Если лень читать - в конце ссылка на короткое видео сравнения (в телеграм канале).
Посмотрим, что нам выдал ChatGPT:
Ответ ChatGPT
Вот готовый код для простейшей игры «Змейка» на SwiftUI. Змея стартует с длиной в 3 квадрата и растёт при поедании еды разного цвета. Управление происходит свайпами.
import SwiftUI struct SnakeGameView: View { @State private var snake: [CGPoint] = [CGPoint(x: 100, y: 100), CGPoint(x: 80, y: 100), CGPoint(x: 60, y: 100)] @State private var food: CGPoint = CGPoint(x: 200, y: 200) @State private var direction: CGPoint = CGPoint(x: 20, y: 0) @State private var timer = Timer.publish(every: 0.2, on: .main, in: .common).autoconnect() let gridSize: CGFloat = 20 let colors: [Color] = [.red, .blue, .yellow, .purple, .orange] var body: some View { ZStack { Color.black.ignoresSafeArea() ForEach(snake.indices, id: \..self) { index in Rectangle() .fill(Color.green) .frame(width: gridSize, height: gridSize) .position(snake[index]) } Rectangle() .fill(colors.randomElement()!) .frame(width: gridSize, height: gridSize) .position(food) } .gesture(DragGesture() .onEnded { gesture in let xMove = gesture.translation.width let yMove = gesture.translation.height if abs(xMove) > abs(yMove) { direction = xMove > 0 ? CGPoint(x: gridSize, y: 0) : CGPoint(x: -gridSize, y: 0) } else { direction = yMove > 0 ? CGPoint(x: 0, y: gridSize) : CGPoint(x: 0, y: -gridSize) } } ) .onReceive(timer) { _ in moveSnake() } } private func moveSnake() { var newHead = snake.first! newHead.x += direction.x newHead.y += direction.y if newHead == food { snake.insert(newHead, at: 0) food = generateNewFood() } else { snake.insert(newHead, at: 0) snake.removeLast() } } private func generateNewFood() -> CGPoint { let x = CGFloat(Int.random(in: 0..<Int(UIScreen.main.bounds.width / gridSize))) * gridSize let y = CGFloat(Int.random(in: 0..<Int(UIScreen.main.bounds.height / gridSize))) * gridSize return CGPoint(x: x, y: y) } } struct ContentView: View { var body: some View { SnakeGameView() } } @main struct SnakeGameApp: App { var body: some Scene { WindowGroup { ContentView() } } }
Этот код создаёт простейшую змейку, которая управляется свайпами. Когда змея съедает еду, она увеличивается в длине, а еда появляется в новом случайном месте и меняет цвет. Игра бесконечна, но можно добавить столкновение с границами или самой собой для усложнения. 🚀
И вот что мы получили:

В целом, всё максимально соответствует описанию, код работает с первого раза. Есть недочеты, что змейка может уйти за пределы экрана, например. Но для базы сойдёт.
Дальше такой же промпт вставляем в DeepSeek, вот что получаем:
Ответ DeepSeek
Создадим простейшую версию игры "Змейка" на SwiftUI. В этом приложении будет один экран, на котором змейка будет двигаться по экрану и "съедать" квадратики, увеличиваясь в длину.
Шаги для создания приложения:
Создадим структуру для змейки и еды.
Реализуем логику движения змейки.
Добавим обработку касаний для управления змейкой.
Отрисуем змейку и еду на экране.
Полный код приложения:
import SwiftUI struct ContentView: View { @State private var snake: [CGPoint] = [ CGPoint(x: 100, y: 100), CGPoint(x: 90, y: 100), CGPoint(x: 80, y: 100) ] @State private var food: CGPoint = CGPoint(x: 200, y: 200) @State private var direction: CGPoint = CGPoint(x: 10, y: 0) @State private var foodColor: Color = .red @State private var score: Int = 0 let timer = Timer.publish(every: 0.1, on: .main, in: .common).autoconnect() var body: some View { ZStack { Color.black.edgesIgnoringSafeArea(.all) // Рисуем змейку ForEach(snake, id: \.self) { segment in Rectangle() .fill(Color.green) .frame(width: 10, height: 10) .position(segment) } // Рисуем еду Rectangle() .fill(foodColor) .frame(width: 10, height: 10) .position(food) // Отображаем счет Text("Score: \(score)") .foregroundColor(.white) .font(.largeTitle) .padding() } .onReceive(timer) { _ in moveSnake() } .gesture( DragGesture() .onEnded { gesture in let delta = gesture.translation if abs(delta.width) > abs(delta.height) { // Горизонтальный свайп if delta.width > 0 { direction = CGPoint(x: 10, y: 0) // Вправо } else { direction = CGPoint(x: -10, y: 0) // Влево } } else { // Вертикальный свайп if delta.height > 0 { direction = CGPoint(x: 0, y: 10) // Вниз } else { direction = CGPoint(x: 0, y: -10) // Вверх } } } ) } func moveSnake() { var newSnake = snake let head = newSnake[0] // Новое положение головы let newHead = CGPoint(x: head.x + direction.x, y: head.y + direction.y) // ��роверяем, съела ли змейка еду if abs(newHead.x - food.x) < 10 && abs(newHead.y - food.y) < 10 { score += 1 generateFood() } else { newSnake.removeLast() } newSnake.insert(newHead, at: 0) snake = newSnake } func generateFood() { let maxX = UIScreen.main.bounds.width - 10 let maxY = UIScreen.main.bounds.height - 10 food = CGPoint( x: CGFloat.random(in: 0...maxX), y: CGFloat.random(in: 0...maxY) ) foodColor = Color( red: Double.random(in: 0...1), green: Double.random(in: 0...1), blue: Double.random(in: 0...1) ) } } @main struct SnakeApp: App { var body: some Scene { WindowGroup { ContentView() } } }
Описание кода:
Змейка и еда:
Змейка представлена массивом
CGPoint, где каждый элемент — это координата одного сегмента змейки.Еда — это случайная точка на экране, которая меняет цвет при каждом появлении.
Движение змейки:
Змейка движется с постоянной скоростью, обновляя свое положение каждые 0.1 секунды.
Если змейка "съедает" еду, ее длина увеличивается на один сегмент, и генерируется новая еда.
Управление:
Если пользователь свайпает вправо, змейка поворачивает вправо.
Если пользователь свайпает влево, змейка поворачивает влево.
Аналогично для свайпов вверх и вниз.
Отрисовка:
Змейка и еда отрисовываются с помощью
Rectangleв SwiftUI.
Как запустить:
Создайте новый проект в Xcode с использованием SwiftUI.
Замените содержимое файла
ContentView.swiftна приведенный выше код.Запустите приложение на симуляторе или устройстве.
Теперь у вас есть простая версия игры "Змейка" на SwiftUI!

Что тут интересного: змейка по размерам сильно меньше, скорость чуть выше. При изначально одинаковом запросе, DeepSeek добавил от себя лейбл с подсчётом очков. Так же проблема с тем, что змейка уходит за рамки экрана и не возвращается.
И кстати, я нигде не указывала, каким должно быть управление и по умолчанию обе модели сделали управление по свайпу (это логично, но с другой стороны, вариантов много: стрелочки, гироскоп и пр.)
Считаю что с первым заданием обе модели справились. Счёт 1:1.
Далее в преддверии 14 февраля в голову ударили сердечки, поэтому попросила сделать обе модели простенькую анимацию. Вот такой был промпт:
Напиши полностью с нуля приложение на SwiftUI. В приложении должен быть один экран. На нём на тёмном фоне должна быть такая анимация:
Сердечки плавно падают сверху экрана, но при клике по экрану они разлетаются в стороны. Выглядит ярко и визуально привлекательно.
Сердечки должны быть разных оттенков розового и разного размера.
Начнём с ChatGPT. Вот результат:
Ответ ChatGPT
Вот полный код приложения на SwiftUI, которое реализует эффект падающих сердечек с разлетом при клике.
Что делает этот код?
• Сердечки падают сверху экрана с разной скоростью и размером.
• Клик по экрану заставляет сердечки разлететься в стороны.
• Разные оттенки розового и размеры сердечек делают анимацию визуально привлекательной.
import SwiftUI struct Heart: Identifiable { let id = UUID() var position: CGPoint var size: CGFloat var color: Color var velocity: CGFloat } struct ContentView: View { @State private var hearts: [Heart] = [] @State private var explode = false let screenWidth = UIScreen.main.bounds.width let screenHeight = UIScreen.main.bounds.height var body: some View { ZStack { Color.black.ignoresSafeArea() ForEach(hearts) { heart in HeartShape() .fill(heart.color) .frame(width: heart.size, height: heart.size) .position(heart.position) .opacity(explode ? 0.5 : 1) .animation(.easeInOut(duration: 1.5), value: explode) } } .onAppear { startDroppingHearts() } .onTapGesture { explodeHearts() } } func startDroppingHearts() { Timer.scheduledTimer(withTimeInterval: 0.3, repeats: true) { timer in let newHeart = Heart( position: CGPoint(x: CGFloat.random(in: 0...screenWidth), y: -50), size: CGFloat.random(in: 20...50), color: Color(red: Double.random(in: 0.8...1), green: Double.random(in: 0...0.3), blue: Double.random(in: 0.5...0.7)), velocity: CGFloat.random(in: 2...5) ) hearts.append(newHeart) withAnimation(.linear(duration: 3)) { for index in hearts.indices { hearts[index].position.y += screenHeight + 50 } } hearts.removeAll { $0.position.y > screenHeight + 50 } } } func explodeHearts() { explode = true withAnimation(.easeOut(duration: 0.5)) { for index in hearts.indices { hearts[index].position.x += CGFloat.random(in: -100...100) hearts[index].position.y += CGFloat.random(in: -100...100) } } DispatchQueue.main.asyncAfter(deadline: .now() + 0.7) { explode = false } } } struct HeartShape: Shape { func path(in rect: CGRect) -> Path { var path = Path() let width = rect.width let height = rect.height path.move(to: CGPoint(x: width / 2, y: height)) path.addCurve(to: CGPoint(x: 0, y: height / 3), control1: CGPoint(x: width * 0.3, y: height * 1.1), control2: CGPoint(x: 0, y: height * 0.6)) path.addArc(center: CGPoint(x: width * 0.25, y: height / 3), radius: width * 0.25, startAngle: .degrees(180), endAngle: .degrees(0), clockwise: false) path.addArc(center: CGPoint(x: width * 0.75, y: height / 3), radius: width * 0.25, startAngle: .degrees(180), endAngle: .degrees(0), clockwise: false) path.addCurve(to: CGPoint(x: width / 2, y: height), control1: CGPoint(x: width, y: height * 0.6), control2: CGPoint(x: width * 0.7, y: height * 1.1)) return path } } @main struct HeartsApp: App { var body: some Scene { WindowGroup { ContentView() } } }
Как это работает?
• Падающие сердечки создаются каждые 0.3 секунды и плавно движутся вниз.
• Сердечки разного размера и оттенка розового.
• При клике по экрану сердечки разлетаются в случайном направлении.
• Анимации делают разлет плавным и красивым.
Попробуй запустить этот код в Xcode, и ты увидишь магию 💖✨!

Получилась какая-то хрень. Но я решила дать ему ещё один шанс и попросила исправить, чтобы сердечки падали на весь экран.
Со второго раза:

Нуууу, почти. Сердечки падают, они разного цвета и размера. При нажатии происходит "улёт" вниз и дальше опять глюк, что они только в первой четверти экрана появляются.
В целом ок, с учётом того, что код я не смотрела вообще.
Теперь посмотрим ответ от DeepSeek
Ответ DeepSeek
Создадим приложение на SwiftUI с анимацией падающих сердечек, которые разлетаются при нажатии на экран. Вот полный код:
import SwiftUI struct Heart: Identifiable { let id = UUID() var position: CGPoint var color: Color var size: CGFloat var isFlying: Bool = false } struct ContentView: View { @State private var hearts: [Heart] = [] @State private var timer: Timer? var body: some View { ZStack { Color.black .edgesIgnoringSafeArea(.all) ForEach(hearts) { heart in Image(systemName: "heart.fill") .font(.system(size: heart.size)) .foregroundColor(heart.color) .position(heart.position) .animation(.linear(duration: heart.isFlying ? 0.5 : 10), value: heart.position) } } .onAppear { startHeartsAnimation() } .onDisappear { timer?.invalidate() } .onTapGesture { explodeHearts() } } private func startHeartsAnimation() { timer = Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true) { _ in let size = CGFloat.random(in: 20...50) let heart = Heart( position: CGPoint(x: CGFloat.random(in: 0...UIScreen.main.bounds.width), y: -size), color: Color(red: Double.random(in: 0.7...1), green: Double.random(in: 0.2...0.5), blue: Double.random(in: 0.4...0.7)), size: size ) hearts.append(heart) DispatchQueue.main.asyncAfter(deadline: .now() + 10) { if let index = hearts.firstIndex(where: { $0.id == heart.id }) { hearts.remove(at: index) } } withAnimation(.linear(duration: 10)) { if let index = hearts.firstIndex(where: { $0.id == heart.id }) { hearts[index].position.y = UIScreen.main.bounds.height + size } } } } private func explodeHearts() { for index in hearts.indices { let angle = Double.random(in: 0..<2 * .pi) let distance = CGFloat.random(in: 100...300) let newX = hearts[index].position.x + cos(angle) * distance let newY = hearts[index].position.y + sin(angle) * distance withAnimation(.easeOut(duration: 0.5)) { hearts[index].position = CGPoint(x: newX, y: newY) hearts[index].isFlying = true } DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { if let index = hearts.firstIndex(where: { $0.id == hearts[index].id }) { hearts.remove(at: index) } } } } } @main struct HeartAnimationApp: App { var body: some Scene { WindowGroup { ContentView() } } }

DeepSeek с первого раза выдал довольно пристойную реализацию. Максимально соответствует запросу.
Единственный минус, что после того как я нажимаю на экран и сердечки разлетаются - превью крашится.
Я считаю, что во второй задаче победил DeepSeek. К моему удивлению, я была скептически настроена, но посмотрев и сравнив их на практике - кажется, что DeepSeek вообще ничем не уступает ChatGPT, по крайней мере в написании кода. И ещё надо учитывать то, что DeepSeek работает бесплатно и без ВПН и для регистрации мне не потребовалось ничего, кроме почты.
Кто ещё тестировал на других языках, пишите как вам?
