Практика 3. Практика к лекции 3
Цель: освоить операторы Swift (арифметические, сравнения, логические, nil-coalescing, диапазоны) и управляющие конструкции (if/else, switch, for-in, while, repeat-while, guard, labeled statements, stride). Научиться выбирать подходящую конструкцию для конкретной задачи.
Рекомендации по выполнению:
- Каждое задание оформляйте в отдельном файле (например,
task1.swift). - Запускайте через
swift имя_файла.swiftна Linux. - Обращайте внимание на то, что
switchв Swift не требуетbreak(нет «проваливания») и требует исчерпывающего покрытия случаев. - Используйте
guardвместо вложенныхifдля раннего выхода — это идиоматичный Swift.
A. Разминка — операторы
- Арифметика и остатки. Напишите программу, которая для двух чисел
a = 23иb = 7выводит результаты всех арифметических операций, включая остаток от деления и вещественное деление:
let a = 23let b = 7
print("\(a) + \(b) = \(a + b)")print("\(a) - \(b) = \(a - b)")print("\(a) * \(b) = \(a * b)")print("\(a) / \(b) = \(a / b)") // целочисленноеprint("\(a) % \(b) = \(a % b)") // остатокprint("\(a) / \(b) = \(Double(a) / Double(b))") // вещественноеДополнительно: объясните в комментарии, чем % в Swift отличается от % в Python для отрицательных чисел (проверьте -7 % 3).
- Nil-coalescing и Optional. Напишите программу, демонстрирующую оператор
??:
let userInput: String? = nillet name = userInput ?? "Гость"print("Привет, \(name)!") // Привет, Гость!
let parsed: Int? = Int("abc")let value = parsed ?? 0print("Значение: \(value)") // Значение: 0Создайте массив let inputs: [String?] = ["42", nil, "hello", "100", nil]. Для каждого элемента выведите число или "нет данных", используя ??.
B. switch и диапазоны
- Калькулятор через switch. Напишите программу, которая принимает два числа и оператор, затем вычисляет результат:
let x = 10.0let y = 3.0let op = "/"
let result: String
switch op {case "+": result = "\(x + y)"case "-": result = "\(x - y)"case "*": result = "\(x * y)"case "/": if y != 0 { result = "\(x / y)" } else { result = "Ошибка: деление на ноль" }default: result = "Неизвестный оператор: \(op)"}
print("\(x) \(op) \(y) = \(result)")Протестируйте для всех операторов (+, -, *, /), а также для деления на ноль и неизвестного оператора.
- Оценка через switch с диапазонами. Напишите функцию, которая по числовому баллу (0–100) возвращает текстовую оценку:
func grade(score: Int) -> String { switch score { case 90...100: return "Отлично (A)" case 75..<90: return "Хорошо (B)" case 60..<75: return "Удовлетворительно (C)" case 0..<60: return "Неудовлетворительно (F)" default: return "Некорректный балл" }}Протестируйте для значений: 95, 82, 67, 45, 100, 0, -5, 110. Ожидаемый вывод:
95 → Отлично (A)82 → Хорошо (B)67 → Удовлетворительно (C)45 → Неудовлетворительно (F)100 → Отлично (A)0 → Неудовлетворительно (F)-5 → Некорректный балл110 → Некорректный баллC. guard и валидация
- Валидатор пароля. Напишите функцию
validatePassword(_ password: String?) -> Bool, использующуюguardдля проверки:- Пароль не
nil. - Длина >= 8 символов.
- Содержит хотя бы одну цифру.
- Содержит хотя бы одну заглавную букву.
- Пароль не
func validatePassword(_ password: String?) -> Bool { guard let password = password else { print("Ошибка: пароль не задан") return false } guard password.count >= 8 else { print("Ошибка: длина менее 8 символов") return false } guard password.contains(where: { $0.isNumber }) else { print("Ошибка: нет цифры") return false } guard password.contains(where: { $0.isUppercase }) else { print("Ошибка: нет заглавной буквы") return false } return true}Протестируйте для: nil, "abc", "abcdefgh", "abcdefg1", "Abcdefg1", "MyP@ss1". Выведите результат каждой проверки.
- Валидатор регистрации. Используя
guard, напишите функциюvalidateRegistration(name:email:age:), которая проверяет:- Имя не пустое.
- Email содержит
"@"и".". - Возраст от 16 до 120.
Функция возвращает
(valid: Bool, error: String?).
let checks = [ ("Иван", "ivan@mail.ru", 20), ("", "test@mail.ru", 25), ("Анна", "anna-mail.ru", 22), ("Пётр", "petr@mail.ru", 15),]
for (name, email, age) in checks { let result = validateRegistration(name: name, email: email, age: age) if result.valid { print("✓ \(name): регистрация успешна") } else { print("✗ \(name): \(result.error!)") }}D. Циклы
- FizzBuzz. Напишите классическую задачу FizzBuzz для чисел от 1 до 30:
- Если число делится на 3 — выведите
"Fizz". - Если число делится на 5 — выведите
"Buzz". - Если делится на оба — выведите
"FizzBuzz". - Иначе — выведите само число.
- Если число делится на 3 — выведите
Реализуйте два варианта:
- С использованием
if/else if/else. - С использованием
switchи кортежа(n % 3 == 0, n % 5 == 0):
for n in 1...30 { switch (n % 3 == 0, n % 5 == 0) { case (true, true): print("FizzBuzz") case (true, false): print("Fizz") case (false, true): print("Buzz") default: print(n) }}- Фибоначчи. Выведите первые 20 чисел Фибоначчи, используя цикл
while:
var fib1 = 0var fib2 = 1var count = 0
while count < 20 { print(fib1, terminator: " ") let next = fib1 + fib2 fib1 = fib2 fib2 = next count += 1}print()Ожидаемый вывод:
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181Реализуйте второй вариант — через repeat-while. В комментарии объясните, в чём разница между while и repeat-while.
E. stride и labeled statements
- stride. Выведите:
- Чётные числа от 2 до 50 (через
stride(from:through:by:)). - Обратный отсчёт от 10 до 0 (через
stride(from:through:by:)с отрицательным шагом). - Числа с шагом 0.5 от 0.0 до 5.0 (через
stride(from:to:by:)).
- Чётные числа от 2 до 50 (через
// чётные от 2 до 50for n in stride(from: 2, through: 50, by: 2) { print(n, terminator: " ")}print()
// обратный отсчётfor n in stride(from: 10, through: 0, by: -1) { print(n, terminator: " ")}print()В комментарии объясните разницу между stride(from:to:by:) и stride(from:through:by:).
- Поиск пары (labeled break). Найдите первую пару
(i, j)из диапазона1...20, гдеi * j == 200, используя labeled statements:
search: for i in 1...20 { for j in 1...20 { if i * j == 200 { print("Найдена пара: (\(i), \(j))") break search } }}Модифицируйте программу: найдите все пары (i, j) где i * j == 200 и i <= j (чтобы не дублировать). Используйте labeled continue для пропуска ненужных итераций.
F. Мини-проект — «Угадай число»
- Создайте консольную игру
guess.swift:
- Программа «загадывает» число от 1 до 100 (используйте
Int.random(in: 1...100)). - Пользователь вводит число через
readLine(). - Программа отвечает:
"Больше","Меньше"или"Угадали за N попыток!". - Используйте
guardдля валидации ввода (неnil, является числом, в диапазоне 1–100). - Используйте
repeat-whileдля основного цикла. - Ограничьте количество попыток (например, 10). При превышении —
"Вы проиграли! Было загадано: \(secret)".
Примерный ход игры:
Я загадал число от 1 до 100. У вас 10 попыток.Ваш ответ: 50Больше!Ваш ответ: 75Меньше!Ваш ответ: 63Угадали за 3 попытки!Подсказки:
readLine()возвращаетString?.Int(readLine() ?? "")— безопасное преобразование.- Используйте
switchдля сравнения введённого числа с загаданным.
G. Критерии оценивания
- Корректность компиляции и работы всех программ на Linux: 0–4 балла
- Правильное использование
switch,guard, циклов,stride: 0–4 балла - Полнота выполнения заданий (все 11 пунктов): 0–4 балла
- Оформление кода: комментарии с пояснениями, отсутствие дублирования, читаемость: 0–4 балла
Максимум: 16 баллов. Бонус до +2 за задания из раздела «Дополнительно».
H. Дополнительно (по желанию)
- В игре «Угадай число» добавьте режим, где компьютер угадывает число пользователя методом бинарного поиска.
- Напишите программу, выводящую «треугольник Паскаля» первых 10 строк, используя вложенные циклы.
- Реализуйте
switchс кортежем для простой системы координат: определите, в каком квадранте находится точка(x, y), используяswitch (x > 0, y > 0).