Після тижнів очікування ми з друзями збираємося на свою найпершу гру в Dungeons & Dragons (D&D). Оскільки це перша сесія гри, кожен гравець має згенерувати персонажа, яким гратиме. Характеристики персонажа визначаються кидками шестигранних кубиків, але де ж взяти кубики? З жахом ми розуміємо, що друзі чекають, коли кубики дістанемо саме ми; зрештою, пограти в D&D була наша ідея! Панікуючи, ми розуміємо, що забули взяти кубики, а це означало б, що гри в D&D не буде. Оскільки ми маємо базові навички програмування, ми швидко знаходимо рішення: напишемо програму, яка імітує кидки кубиків.
Для гри в Dungeons & Dragons кожен гравець починає зі створення персонажа, яким можна грати. Цей персонаж має, серед іншого, шість характеристик: силу, спритність, статуру, інтелект, мудрість і харизму. Значення цих шести характеристик визначаються випадково. Для цього ми кидаємо чотири шестигранні кубики й записуємо суму трьох найбільших. Робимо це шість разів, по одному разу для кожної характеристики.
Початкові хіти персонажа дорівнюють 10 + модифікатор статури персонажа. Модифікатор статури персонажа ми знаходимо так: віднімаємо 10 від статури персонажа, ділимо на 2 і округлюємо вниз.
Напишіть генератор випадкових персонажів, який дотримується наведених вище правил.
Наприклад, шість кидків чотирьох кубиків можуть мати такий вигляд:
Оскільки статура дорівнює 3, модифікатор статури становить -4, а хіти дорівнюють 6.
Більшість мов програмування мають (псевдо)випадкові генератори, але мало які мови програмування призначені для кидання кубиків. Одна з таких мов - Troll.
У функціональних мовах більшість функцій є чистими. Це означає, що для того самого набору аргументів вони завжди повертають ті самі вихідні дані й не роблять нічого іншого. Іншими словами, чисті функції є детермінованими.
Однак за визначенням випадкове значення є непередбачуваним і недетермінованим. Навіть псевдовипадковість, тобто повернення послідовності чисел, які здаються випадковими, не так легко отримати в чистому контексті. Річ у тім, що генератор псевдовипадкових чисел (PRNG) має відстежувати внутрішній стан, щоб повернути наступне число в послідовності.
Lean пропонує два можливі підходи до цієї задачі:
Скористатися монадою, яка дає змогу змінювати внутрішній стан генератора псевдовипадкових чисел.
Є готова функція IO.rand, яка робить саме це.
Скористатися чистими функціями, які приймають генератор як аргумент і повертають не лише отримане псевдовипадкове значення, а й оновлений генератор, «заряджений» на наступне число в послідовності.
У цій вправі використано другий підхід. Генератор передають кожній функції, яка має видавати псевдовипадкове значення, і від функції вимагається повернути як значення, так і оновлений генератор.
Зауважмо, що кожен конкретний генератор є детермінованим, тобто він завжди видає те саме значення. Щоб згенерувати наступне псевдовипадкове значення в послідовності, потрібно скористатися оновленим генератором.
У цій вправі випадковість перевіряють за допомогою критерію хі-квадрат на рівні значущості p < 0.0001.
Це означає, що якщо показник здібності згенеровано згідно з інструкціями, імовірність того, що правильна реалізація не пройде тест через випадковий збіг, менша за 0,01%.
Зауважмо, що згідно з інструкціями показник здібності - це сума трьох найбільших результатів із чотирьох кидків чесного d6 (шестигранного кубика).
Зареєструйтеся на Exercism, щоб вивчати й опановувати Lean, а також 100 вправ та справжнє наставництво від людей, і все це безкоштовно.
Ми розглянемо, як генерувати (начебто) випадкові кидки кубиків. Дізнаємося про зерна, псевдовипадкові числа та кілька типових пасток. Нарешті, побачимо, чим тестування на основі властивостей добре підходить для перевірки функцій, що повертають випадкові значення.