كيف تجعل Android "يلقي النرد"؟ نحلل توليد الأرقام العشوائية بلغة Kotlin
\n\nهل تساءلت يومًا كيف "يختار" هاتفك رقمًا عشوائيًا؟ تبدو مهمة بسيطة - الحصول على عدد صحيح عشوائي من 5 إلى 10. ولكن تحت غطاء Android و Kotlin تختبئ آلية كاملة تعتمد عليها ليس فقط سهولة الاستخدام، بل وأمان تطبيقك. ليس من المستغرب أن سؤال "How can I generate random number in specific range in Android?" قد جمع آلاف المشاهدات على Stack Overflow. لن نقدم إجابة جاهزة فحسب - بل سننظر في المصادر ونتعرف على ما يحدث بالفعل.
\n\nفي هذه المقالة ستتعلم:
\n- \n
- كيفية توليد رقم عشوائي بشكل صحيح في نطاق معين بلغة Kotlin. \n
- الفرق بين
kotlin.random.Randomوjava.util.RandomوSecureRandom. \n - لماذا تحتاج ألعاب الحظ إلى فئة واحدة، بينما تحتاج توليد كلمات المرور إلى فئة أخرى. \n
- كيف تتجنب الأخطاء النمطية التي تحول "العشوائية" إلى قابلية للتنبؤ. \n
هيا بنا!
\n\nكلاسيكيات النوع: Random في Kotlin (ولماذا هذا ليس صحيحًا دائمًا)
\n\nالطريقة الأكثر وضوحًا هي استخدام kotlin.random.Random. إنه مدمج مباشرة في اللغة ويعمل فورًا. إليك كيفية توليد رقم عشوائي من 0 إلى 100 (شامل):
import kotlin.random.Random\n\nfun main() {\n val randomNumber = Random.nextInt(0, 101) // من 0 إلى 100 شامل\n println("الرقم العشوائي: $randomNumber")\n}\n\nكل شيء بسيط. لكن دعنا ننظر تحت الغطاء. Random.nextInt(from, until) داخليًا يستخدم java.util.Random (على منصة JVM). وهذا بدوره يولد الأرقام باستخدام مولد خطي متطابق (LCG). الصيغة بسيطة:
new_seed = (old_seed * A + C) mod M
حيث A و C و M ثوابت. هذا سريع، لكنه غير آمن تشفيريًا. إذا تمكن المهاجم من معرفة بضعة أرقام، يمكنه استعادة البذرة (seed) والتنبؤ بجميع الأرقام اللاحقة.
\n\nمتى تستخدم: للألعاب (غير النقدية)، الاختيار العشوائي لعنصر من قائمة، خلط البطاقات في تطبيق عادي.
\n\nالمستوى المتقدم: ThreadLocalRandom لتعدد الخيوط
\n\nإذا كان تطبيقك يستخدم بشكل نشط coroutines أو تعدد الخيوط، فإن Random العادي قد يصبح عنق زجاجة. كل استدعاء لـ nextInt() يتم مزامنته لتجنب حالات السباق. الحل هو ThreadLocalRandom من Java:
import java.util.concurrent.ThreadLocalRandom\n\nfun getRandomInRange(min: Int, max: Int): Int {\n return ThreadLocalRandom.current().nextInt(min, max + 1)\n}\n\nهذه الفئة تخصص نسخة منفصلة من Random لكل خيط. لا حاجة للمزامنة - كل خيط يعمل مع المولد الخاص به. عمليًا، هذا يعطي زيادة في الأداء في سيناريوهات تعدد الخيوط.
الأمان قبل كل شيء: SecureRandom
\n\nتخيل الآن أنك تقوم بتوليد كلمة مرور لمرة واحدة (OTP) أو رمز لاستعادة الوصول. استخدام Random العادي هو جريمة. هنا يأتي دور SecureRandom:
import java.security.SecureRandom\n\nfun generateSecureCode(length: Int): String {\n val secureRandom = SecureRandom()\n val digits = "0123456789"\n return (1..length)\n .map { digits[secureRandom.nextInt(digits.length)] }\n .joinToString("")\n}\n\nSecureRandom يجمع الإنتروبيا من مصادر نظام التشغيل: ضوضاء الميكروفون، توقيتات ضغطات المفاتيح (في المحاكي - من ملف /dev/random أو /dev/urandom). هذا يجعله غير قابل للتنبؤ. لكن الثمن هو السرعة - يمكن أن يكون أبطأ بعشرات المرات من Random العادي.
هام: على Android، S