Домашнє завдання #9: Вечір у кафе — рахунок, чайові та паролі
П'ятниця, ти з друзями в кафе. Офіціант приносить рахунок — і починається класика: «скинемось порівну?», «а чайові рахував хтось?», «у мене тільки готівка, без копійок». Ти дістаєш ноутбук: «Спокійно. Я програміст». Сьогодні ти напишеш інструменти, якими реально можна користуватись — і які працюють на умовних конструкціях та функціях.
Частина 1: Ділимо рахунок — splitBill(total, people, tipPercent)
Функція приймає суму рахунку (грн), кількість людей і відсоток чайових. Повертає об'єкт із трьома полями: tip (чайові), grandTotal (рахунок + чайові), perPerson (скільки платить кожен).
Правила:
- Спочатку валідація: якщо
totalне більший за 0 — поверни рядок"Помилка: сума рахунку має бути більшою за 0"; якщоpeopleменший за 1 — поверни"Помилка: людей має бути щонайменше 1" tip= відсоток відtotalperPersonокруглюється до цілої гривні вгору (Math.ceil) — щоб ніхто не рахував копійки, а офіціант не залишився в мінусі
Приклади (це тест-кейси — твоя функція має повертати саме це):
| Виклик | Результат |
|---|---|
splitBill(1000, 4, 10) | { perPerson: 275, tip: 100, grandTotal: 1100 } |
splitBill(847, 3, 15) | { perPerson: 325, tip: 127.05, grandTotal: 974.05 } |
splitBill(500, 1, 0) | { perPerson: 500, tip: 0, grandTotal: 500 } |
splitBill(1000, 0, 10) | "Помилка: людей має бути щонайменше 1" |
splitBill(-200, 3, 10) | "Помилка: сума рахунку має бути більшою за 0" |
Частина 2: Оцінюємо пароль — passwordStrength(password)
Після вечері компанія вирішує завести спільний акаунт для бронювання столиків. Хтось пропонує пароль qwerty. Твоя функція має чесно сказати, наскільки це погана ідея.
Перевір 4 критерії:
- Довжина щонайменше 8 символів
- Є хоча б одна цифра
- Є і великі, і малі літери
- Є хоча б один спецсимвол із набору
!@#$%^&*
Поверни об'єкт { level, tips }, де level залежить від кількості виконаних критеріїв: 0–2 → "слабкий", 3 → "середній", 4 → "надійний". А tips — масив порад: по одній для кожного невиконаного критерію (формулювання — на твій смак, головне щоб порада відповідала критерію).
| Виклик | Результат |
|---|---|
passwordStrength("qwerty") | level: "слабкий", у tips — 4 поради |
passwordStrength("1234") | level: "слабкий", у tips — 3 поради (цифри вже є) |
passwordStrength("Korovai42") | level: "середній", у tips — 1 порада (про спецсимвол) |
passwordStrength("Vechir#Kavi2026") | level: "надійний", tips: [] |
Частина 3: Генеруємо пароль — generatePassword(length, options)
Оцінювати чужі паролі легко — тепер згенеруй надійний сам. options — об'єкт із трьома полями-прапорцями: useUppercase, useDigits, useSymbols. Малі латинські літери використовуються завжди.
Правила:
- Якщо
lengthменший за 4 — поверни"Помилка: мінімальна довжина пароля — 4" - Пароль складається лише з дозволених опціями символів (спецсимволи — з набору
!@#$%^&*) - Якщо опція ввімкнена — у паролі має бути хоча б один символ цього типу (генератор, який за
useDigits: trueвидає пароль без жодної цифри — зламаний)
Приклади (пароль випадковий — у тебе будуть інші символи, але властивості мають збігатися):
| Виклик | Приклад результату | Що перевіряємо |
|---|---|---|
generatePassword(8, { useUppercase: false, useDigits: true, useSymbols: false }) | "k2p9mx4a" | 8 символів, лише малі літери й цифри, є хоча б одна цифра |
generatePassword(12, { useUppercase: true, useDigits: true, useSymbols: true }) | "aK4#mZ8!pQ2r" | 12 символів, є всі чотири типи |
generatePassword(3, { useUppercase: true, useDigits: true, useSymbols: true }) | "Помилка: мінімальна довжина пароля — 4" | валідація |
Перевір себе: згенерований пароль, прогнаний через passwordStrength, з усіма опціями має давати "надійний".
Бонус (+15): Нерівний поділ — splitBillUneven(foodTotal, drinksTotal, people, drinkers, tipPercent) 🍷
Найгарячіша тема вечора: двоє з чотирьох не пили вино — чому вони мають платити за нього порівну? Їжа ділиться на всіх, напої — лише між тими, хто пив, чайові рахуються від усього рахунку і діляться на всіх. Обидві суми округлюються до гривні вгору.
| Виклик | Результат |
|---|---|
splitBillUneven(800, 400, 4, 2, 10) | { drinkerPays: 430, nonDrinkerPays: 230 } |
Перевірка: 2 * 430 + 2 * 230 = 1320 — рівно їжа + напої + чайові (800 + 400 + 120). Ніхто не переплатив, офіціант задоволений.
Підказки
Рівень 1: напрямок думки
- Валідацію роби першою: якщо дані погані — одразу
returnз рядком помилки, решта коду навіть не виконається - Для
passwordStrengthзаведи лічильник виконаних критеріїв і масив порад — кожна перевірка або збільшує лічильник, або додає пораду - Для генератора: спочатку збери рядок з усіх дозволених символів, потім бери з нього випадкові
Рівень 2: які інструменти використати
- Округлення вгору:
Math.ceil(x) - Пошук цифри в рядку: пройдись по символах або використай
password.includes(...)для кожної цифри; ще зручніше — порівнянняpassword !== password.toLowerCase()каже, що є великі літери - Випадковий індекс:
Math.floor(Math.random() * chars.length), символ за індексом —chars[index] - Побудувати рядок потрібної довжини — цикл
for(він у наступному уроці, але для генератора знадобиться — вважай це спойлером)
Рівень 3: псевдокод генератора
функція generatePassword(length, options):
якщо length < 4 → повернути помилку
chars = "abc...xyz"
якщо options.useUppercase → chars += "ABC...XYZ"
якщо options.useDigits → chars += "0123456789"
якщо options.useSymbols → chars += "!@#$%^&*"
повторювати:
password = порожній рядок
length разів: додати випадковий символ із chars
поки password не містить по одному символу кожного ввімкненого типу
повернути password
Як здати
- Робота — в публічному GitHub-репозиторії курсу
my-web-course, у папціhw-09/ - У папці:
script.jsз трьома функціями і демо-викликами (console.logдля кожного прикладу з таблиць) таindex.html-обгортка, щоб запустити скрипт у браузері:
<!DOCTYPE html>
<html lang="uk">
<head><meta charset="UTF-8"><title>HW-09</title></head>
<body>
<script src="script.js"></script>
</body>
</html>
- Відкрий
index.htmlу браузері → консоль (F12) — там мають бути результати всіх демо-викликів - У папці —
README.md: 2-3 речення що зроблено + як запустити - Мінімум 3 коміти з осмисленими повідомленнями (не «fix» та «update»)
- Надішли посилання на репозиторій у форму на цій сторінці
Критерії оцінки
| Критерій | Тип | Бали |
|---|---|---|
splitBill: чайові, округлення вгору, об'єкт з трьома полями — збігається з таблицею прикладів | [код] | 25 |
splitBill: обидві валідації повертають точні рядки помилок | [код] | 10 |
passwordStrength: правильний level для всіх 4 прикладів | [код] | 15 |
passwordStrength: tips містить пораду для кожного невиконаного критерію | [код] | 10 |
generatePassword: довжина, лише дозволені символи, валідація довжини | [код] | 15 |
generatePassword: кожен увімкнений тип символів гарантовано присутній | [код] | 10 |
Демо-виклики всіх функцій у script.js — консоль показує результати | [код] | 10 |
| Контракт здачі: 3+ осмислені коміти, README | [код] | 5 |
Бонус: splitBillUneven рахує чесно (перевірка сум сходиться) | [код] | +15 |
Що далі
Не видаляй цей код: у Block 5 ти навчишся підключати функції до кнопок та полів вводу на сторінці — і генератор паролів перетвориться на справжній міні-інструмент з інтерфейсом.