لا أحد ينتظر وحده: تعرّف على الوجوه المعتادة
كان فتح غرفة يعني الانتظار وحدك حتى تيأس. أما الآن فاثنا عشر لاعبًا معتادًا بأسماء حقيقية وشخصيات ثابتة وإيقاع بشري يملؤون المقاعد الفارغة.

بكلمات بسيطة
حتى هذا التحديث، لم يكن أي شيء ينضم إلى غرفة تنشئها أنت. تختار نمطًا، وتفتح طاولة، ثم تنتظر — وغالبًا تنتظر وحدك. أرقام الأسابيع الستة التي سبقت هذا التحديث صريحة:
| ما قِسناه | النتيجة |
|---|---|
| غرف فتحها لاعب ولم تبدأ أبدًا | 38 |
| متوسط الانتظار قبل الاستسلام | نحو 3.2 ساعة |
| غرفة اكتملت 4/4 ومع ذلك لم تبدأ | انتظرت يومين |
| ألعاب منتهية ضمّت أكثر من إنسان واحد | 46 من 231 |
أما الآن فالطاولة تمتلئ من تلقاء نفسها. بعد ما بين عشرين ثانية وأربع دقائق من فتحك الغرفة، يجلس أحدهم. اثنا عشر وجهًا معتادًا يتناوبون على الردهة — بأسماء عادية لا بأسماء تصرخ "روبوت" — وكل منهم هو اللاعب نفسه في كل مرة تلتقيه:
- شخصية ثابتة: الخصم نفسه يلعب دائمًا بحذر، أو يزايد دائمًا أكثر من اللازم؛
- تاريخ انضمام ومستوى خبرة لم يُختلقا هذا الصباح؛
- إيقاع خاص به — يفكر ما بين ثانية وست ثوانٍ، لا ثانيتين بانتظام الميترونوم؛
- جملة قصيرة في الدردشة بين الحين والآخر بدلًا من ملصق؛
- بلا شارة "bot" في غرفة الانتظار، لأنهم على الطاولة يتصرفون كلاعبين.
كما يظهرون في لوحة الصدارة، وهو التصرف الأمين ما داموا سيخوضون مباريات حقيقية — لكن بسقف يومي صارم لما يمكنهم كسبه، فيتقدمون كلاعب عادي لا كمن يحصد النقاط.
للمهتمين بالتفاصيل التقنية
تُنشأ الشخصيات الاثنتا عشرة بطريقة عديمة الأثر المتكرر عند إقلاع خادم اللعبة، وتُوسَم بقيمة كان جدول الملفات الشخصية يدعمها أصلًا — لذلك وصلت الميزة كلها بلا أي ترحيل لقاعدة البيانات وبلا تغيير أي قاعدة من قواعد اللعب.
آلية الملء نبضة في المجدول، لا مؤقت لكل غرفة. وكل تأخير مشتق من عشوائية مُبذَّرة مفتاحها الغرفة والمقعد، ومثبّتة على طابع زمني مخزَّن في قاعدة البيانات، فتستأنف إعادة تشغيل الخادم الجدول ذاته بدل توليد تأخيرات جديدة لغرف سبق جدولتها:
// scheduler.ts — seeded per (room, seat), anchored on a DB timestamp
const rng = createRng(`${game.id}:fill:${seat}`);
const isLastSeat = freeSeats === 1;
const delayMs = isLastSeat
? rng.int(LAST_SEAT_MIN_MS, LAST_SEAT_MAX_MS) // 3-8 min: leave room for a human
: rng.int(SEAT_MIN_MS, SEAT_MAX_MS); // 20 s - 4 min
if (Date.now() - Date.parse(game.created_at) < delayMs) continue;| الإعداد | القيمة |
|---|---|
| تأخير ملء المقعد | 20 ثانية – 4 دقائق، مُبذَّر لكل مقعد |
| المقعد الأخير | 3 – 8 دقائق |
| البدء التلقائي عند اكتمال القائمة وهدوئها | 3 دقائق |
| زمن تفكير البوت | 1 – 6 ثوانٍ، بمعامل حسب الشخصية |
| نقاط خبرة الشخصية | منحة واحدة على الأكثر في اليوم بتوقيت UTC |
ثلاثة عيوب لم تظهر إلا عند التشغيل الفعلي، وما كان أي اختبار وحدة ليكتشف أيًّا منها: الغرف الممتلئة كانت مستبعدة من استعلام المرشّحين لدى آلية الملء، فلم يرَ البدء التلقائي الحالة التي وُجد أصلًا من أجلها؛ وبوابة تأخير التفكير كانت مفتاحها اللعبة لا البوت، فكان توقف في دور ما يحجب أيضًا مزايدة البوت نفسه حتى يُمرَّر تلقائيًا خارج نافذته؛ ولعبة يبدأها الخادم لم تكن توقظ المجدولات من تراجعها في وضع الخمول، ما جعل بين البدء وأول رمية بوت 11.6 ثانية بدل 49 مللي ثانية.
