بازی هرگز پازلی را با دست طراحی نمیکند. آن را از یک عدد واحد میرویاند و سپس، پیش از آنکه شما آن را ببینید، همان پازل را در برابر خودش بازی میکند تا مطمئن شود نه پیشپاافتاده است و نه ناممکن.
به انگلیسی نوشته و ویرایش شده است. این نسخهٔ فارسی با ترجمهٔ ماشینی تهیه شده است؛ هر جا دقت اهمیت دارد، متن اصلی انگلیسی معتبر است. خواندن متن اصلی به انگلیسی ←
مرحلهٔ Contraption در هیچ جا ذخیره نمیشود. هیچ فایلی وجود ندارد که بگوید هدف کجا قرار دارد یا سکوها چگونه چیده شدهاند. در عوض، کل مرحله، یعنی نقطهٔ شروع توپ، موقعیت هدف، تعداد و جای دیوارهای ثابت، و فهرست قطعاتی که به دست شما داده میشود، از یک عدد آغازین واحد به نام بذر محاسبه میشود. همان بذر را به مولد بدهید و، بایت به بایت، همان پازل را تحویل میگیرید. 1
این از آن رو ممکن است که تنها منبع «تصادفی بودن» مولد، یک مولد کوچک و قطعی اعداد شبهتصادفی است. آنچه Contraption به کار میبرد mulberry32 است، مولدی فشرده و 32 بیتی به قلم تامی اتینگر؛ آن را میتوان از ثابت شاخصش، 0x6d2b79f5، شناخت که در هر بار برداشتِ عدد به حالت افزوده میشود. 2 سریع است، در چند خط جا میگیرد و، مهمتر از همه، اصلاً تصادفی نیست: دنبالهای ریاضی و ثابت است که صرفاً بههمریخته به نظر میرسد. نقطهٔ شروعی به آن بدهید و تا ابد همان جریان اعداد را تولید میکند. مولد سپس آن جریان را میخواند تا تصمیم بگیرد هر چیز را کجا بگذارد.
حالت روزانه بر همین قطعیت تکیه میکند تا کاری اجتماعی انجام دهد. بذر آن تصادفی نیست، بلکه از تقویم ساخته میشود. بازی تاریخ امروز را به وقت جهانی میگیرد، آن را در رشتهای کوتاه مانند "contraption:2026-7-28" مینویسد و آن متن را از یک تابع درهمسازی میگذراند تا به یک عدد 32 بیتی فروکاسته شود. 1
این تابع درهمسازی FNV-1a است، آمیزندهای شناختهشده و غیررمزنگارانه: از یک مقدار آغازین ثابت، یعنی عدد دهدهی 2166136261 یا 0x811c9dc5، شروع میکند و برای هر نویسه، آن حرف را با یک «یای انحصاری» (XOR) در عدد میآمیزد و سپس حاصل را در عدد اول FNV، یعنی 16777619، ضرب میکند. 3 نتیجه عددی است که برای یک روز معین ثابت است و از روزی به روز دیگر بهشدت متفاوت، چنانکه تغییر یک نویسه در تاریخ، بذر را بهکلی پراکنده میکند. چون تقویم برای همه یکی است، بذر هم یکی است و پازل هم. دو غریبه در دو سوی جهان حالت روزانه را باز میکنند و با زمینی یکسان روبهرو میشوند، و همین دقیقاً چیزی است که مقایسهٔ امتیازها را معنادار میکند.
چالش روزانه از آن رو منصفانه است که نه سروری مرحلهٔ یکسانی را برای همه میفرستد، بلکه نسخهٔ هر کس بهطور مستقل همان مرحله را از همان تاریخ دوباره محاسبه میکند.
هندسهٔ تصادفی آسان است؛ هندسهٔ تصادفیِ خوب آسان نیست. مولدی که صرفاً یک هدف و چند سکو را پراکنده میکند، گاهی مرحلهای میسازد که در آن توپ، رهاشده از بالا، بهسادگی و خودبهخود مستقیم درون هدف میافتد. این پازل نیست، یک میانپرده است. از این رو Contraption پیش از پذیرفتن یک دنیای نامزد، آزمونی خاموش را اجرا میکند که کد آن را preSolved مینامد: مرحله را بدون هیچ قطعهٔ گذاشتهشدهای شبیهسازی میکند و بررسی میکند که آیا توپِ تنها، فقط با گرانش، به هدف میرسد یا نه. اگر برسد، مرحله دور انداخته میشود و مولد بار دیگر قرعه میزند. 1
این وارونگیِ ظریفی است در شیوهٔ معمول اندیشیدن به یک موتور فیزیک. همان تابع simulate() که ماشین شما را به اجرا درمیآورد، در زمان تولید به درون برگردانده میشود تا دشواری خودِ مرحله را ممیزی کند. موتور هم داور راهحل شماست و هم بازرس کیفیت پازل.
رد کردن مرحلهٔ بیش از حد آسان تنها نیمی از کار است. خطر دیگر مرحلهٔ ناممکن است، هدفی که در جایی پنهان شده که هیچ چیدمانی از قطعات به آن نمیرسد. Contraption با حلکنندهٔ کوچکِ جستوجوی فراگیری به نام plausiblySolvable در برابر این خطر محافظت میکند. این حلکننده هوشمندانه فکر نمیکند. فقط امتحان میکند. 1
بهطور مشخص، یک رمپ واحد را روی شبکهای از موقعیتها در سراسر زمین جابهجا میکند و در هر نقطه، آن را با چهار شیب متفاوت میآزماید. برای هر یک از این جایگذاریهای آزمایشی، شبیهسازی کامل را اجرا میکند و میپرسد: آیا آن یک رمپ توپ را به خانه رساند؟ به محض آنکه یکی از جایگذاریها موفق شود، مرحله حلشدنی اعلام میشود و به دست شما میرسد. اگر پس از پایان کل جستوجو هیچکدام کار نکند، مولد ترجیح میدهد مرحله را کنار بگذارد و بذر تازهای را بیازماید.
| پارامتر جستوجو | بازه | معنا |
|---|---|---|
| رمپ X | 15 → 85، گام 14 | ستونها در عرض زمین |
| رمپ Y | 30 → 120، گام 18 | ردیفها در طول زمین |
| زاویههای آزمودهشده | 4 | ±0.45 و ±0.8 رادیان |
| آزمون بهازای هر جایگذاری | 1 شبیهسازی کامل | آیا توپ به هدف میرسد؟ |
ارزش دارد دربارهٔ آنچه این آزمون ثابت میکند صادق باشیم، چون کد نیز دربارهٔ آن صادق است: توضیحِ درون کد آن را «بررسی باورپذیریِ ارزان … نه فراگیر» مینامد. مرحلهای که از این آزمون میگذرد، قطعاً دستکم یک راهحل خامِ تکرمپی دارد. مرحلهای که رد میشود ممکن است همچنان با یک فن، یک چرخدنده، یا رمپی زیرکانهتر که شبکه هرگز نیازموده حلشدنی باشد، پس مولد شکست را دلیل ناممکن بودن نمیگیرد. نخستین دنیای غیرپیشپاافتادهای را که یافته به عنوان پشتیبان نگه میدارد و اگر 40 تلاش بگذرد و راهحل تمیز تکقطعهای پیدا نشود، به جای آنکه تا ابد در حلقه بماند، همان پشتیبان را تحویل میدهد. نتیجه تضمینی عملگرایانه است: هرگز بردی مفت، تقریباً همیشه مسیری واقعی به درون، و هرگز انتظاری بیپایان برای مرحلهٔ «بینقص». 1
یک گام عقب بروید و خواهید دید که مرحلهساز Contraption نمونهای پاکیزه از الگویی بسیار کهن و بسیار عام در حل مسئله است: تولید و آزمون. نامزدی را بهطور تصادفی پیشنهاد کنید؛ آن را در برابر الزامات خود بسنجید؛ اگر قبول شد نگهش دارید، اگر رد شد دورش بیندازید و نامزد دیگری پیشنهاد کنید. این همان حلقهای است که پشت محتوای رویهای در بازیهای بیشمار، پشت بخش بزرگی از محاسبات تکاملی و، با اندکی اغماض، پشت خودِ انتخاب طبیعی قرار دارد: جهش پیشنهاد میدهد، محیط میآزماید، بازماندگان میمانند. 4
آنچه نسخهٔ Contraption را زیبا میکند این است که آزمون، جانشینی ارزان برای بازیپذیری نیست، بلکه خودِ بازیپذیری است. مولد با شمردن سکوها یا اندازهگیری فاصلهها تخمین نمیزند که یک مرحله منصفانه است یا نه. مرحله را به معنای واقعی کلمه بازی میکند، دو بار: یک بار خالی، تا مطمئن شود مفت نیست، و یک بار با یک رمپِ کاوشگر، تا مطمئن شود مسیری وجود دارد. همان فیزیک قطعیای که راهحل شما را داوری خواهد کرد، همان فیزیکی است که پازل را وارسی کرده است. هیچ «اعتبارسنج مرحلهٔ» جداگانهای وجود ندارد که بتواند از قواعد واقعی فاصله بگیرد، چون تنها یک مجموعه قاعده هست که برای همه چیز به کار میرود.
و چون همه چیز قطعی است، این ممیزی از هر دو سو از شانس بری است. بذر روزانه نمیتواند دسیسه کند تا به یک بازیکن زمینی آسانتر از دیگری بدهد، و نمیتواند به کسی زمینی ناعادلانه بدهد، چون مرحله پیش از آنکه چالش شود، از پیش از آزمونِ بازیشدن، به دست خود بازی و در برابر خودش، جان به در برده است.