بازیهای شانسی به منبعی از تصادف نیاز دارند. واژگان random در Factor یک «واژه»ی جنریک به اسم random در اختیارتان میگذارد که با هرچه به آن بدهید سازگار میشود، بههمراه ابزارهایی برای درهمریختن و نمونهگیری، و راهی برای تکرارپذیر کردن تصادف برای تستها.
inline
برخی از کارهای این تمرین واژهای را تعریف میکنند که یک «کوتیشن» (یک بلوک [ … ]) را به عنوان آرگومان میگیرد و آن را اجرا میکند. Factor یک قانون محکم در این مورد دارد: واژهای که کوتیشنی را که به عنوان آرگومان گرفته است با call فراخوانی میکند باید inline اعلام شود، که با گذاشتن inline بلافاصله بعد از ; پایانی نوشته میشود.
inline به کامپایلر میگوید که بدنهی واژه را بهجای کامپایل یکباره و مستقل آن، در هر محل فراخوانی جایگذاری کند.
این یک واژهی کوچک است که 10 را روی پشته میگذارد و بعد کوتیشنی را که گرفته است اجرا میکند:
USING: kernel math prettyprint ;
: with-ten ( quot -- ) 10 swap call ; inline
اثر پشتهی آن، ( quot -- )، هیچ خروجیای را نام نمیبرد، اما فراخوانی آن با دو کوتیشن با اثرهای متفاوت نتایج متفاوتی تولید میکند که همهشان به فراخوانیکننده برمیگردند:
[ 1 + ] with-ten . ! => 11 (quotation ( n -- n ): one value back)
[ dup 2 * ] with-ten . . ! => 20
! => 10 (quotation ( n -- n n ): two values back)
random: یک عنصرrandom (در random) نسبت به آرگومانش جنریک است:
random ( obj -- elt )
n به آن بدهید، یک عدد صحیح تصادفی در بازهی [0, n) برمیگرداند:USING: random ;
6 random . ! 4 (a value from 0 to 5)
{ "rock" "paper" "scissors" } random . ! "paper"
برای انداختن یک تاس معمولی، بازه را یک واحد بالا میبرید: random با 6 عدد ۰ تا ۵ را میدهد، پس 6 random 1 + عدد ۱ تا ۶ را میدهد.
برای جمع کردن تعداد ثابتی قرعهکشی تصادفی، یک کوتیشن را با replicate (در sequences) تکرار کنید:
replicate ( n quot -- seq )
USING: random sequences ;
3 [ 6 random 1 + ] replicate . ! { 4 1 6 } (three dice)
randomize: درهمریختن در جاrandomize (در random) دنباله را با عناصری در ترتیب تصادفی برمیگرداند:
randomize ( seq -- randomized )
{ 1 2 3 4 5 } randomize . ! { 3 1 5 2 4 }
این کار در جا درهم میریزد و همان دنباله را برمیگرداند، پس اگر میخواهید ترتیب اصلی را نگه دارید، اول clone کنید.
sample: چند عنصر متمایزsample (در random) تعداد n عنصر متمایز از یک دنباله بیرون میکشد، مثل پخش کردن یک دست ورق که هیچ ورقی دوبار نمیآید:
sample ( seq n -- seq' )
{ 10 20 30 40 50 } 3 sample . ! { 40 10 30 }
درخواست عناصر بیشتر از آنچه دنباله در خود دارد، خطاست.
بهطور پیشفرض random از یک مولد سراسری که از ساعت سیستم دانه میگیرد استفاده میکند، بنابراین هر اجرا متفاوت است. برای تستها (یا هر زمان که بازیای میخواهید که بتوانید دوباره اجرایش کنید)، یک مولد را با یک دانهی ثابت مقید کنید.
<mersenne-twister> (در random.mersenne-twister) یک مولد از یک دانهی عدد صحیح میسازد، و with-random (در random) یک کوتیشن را با آن مولد نصبشده اجرا میکند:
<mersenne-twister> ( seed -- rnd )
with-random ( rnd quot -- )
USING: random random.mersenne-twister ;
42 <mersenne-twister> [ 6 random 1 + ] with-random .
! always the same value for seed 42
هر چیزی داخل کوتیشن (random، randomize، sample) از مولد دانهدار بیرون میکشد، بنابراین دانهی یکسان همیشه نتیجهی یکسان تولید میکند.
واژهای که یک کوتیشن را به عنوان آرگومان میگیرد و آن را از with-random میگذراند، زیر قانونِ علامتگذاری یک واژه با inline قرار میگیرد: with-random در نهایت آن کوتیشن را call میکند، پس چنین پوششی باید inline علامتگذاری شود.
شما در سالن بازی کنار دریا، بازیهای شانسی را اداره میکنید. مشتریها تاس میاندازند، دستگاه چنگک یک جایزه را برمیدارد و میز کارت هم باید دستهکارتش بُر بخورد و دستها پخش شوند. همهی اینها با تصادف کار میکنند. آخر شب هم میخواهید قابلیت «بازپخش» را داشته باشید تا بتوان یک بازی مورد اختلاف را با همان دانه دوباره اجرا کرد.
roll-die را تعریف کنید تا تعداد وجهها را بگیرد و عددی در بازهی 1 تا sides (شامل هر دو سر) برگرداند.
6 roll-die .
! => 4 (some value from 1..6)
pick-prize را تعریف کنید تا یک دنباله از جایزهها بگیرد و یکی از آنها را بهصورت تصادفی برگرداند.
{ "teddy" "goldfish" "keyring" } pick-prize .
! => "goldfish"
shuffle-deck را تعریف کنید تا یک دستهکارت (یک دنباله) بگیرد و آن را با کارتهایی در ترتیب تصادفی برگرداند.
{ 1 2 3 4 5 } shuffle-deck .
! => { 3 1 5 2 4 }
deal-hand را تعریف کنید تا یک دستهکارت و یک تعداد n بگیرد و n کارت متمایز را از دستهکارت برگرداند.
{ 10 20 30 40 50 } 3 deal-hand .
! => { 40 10 30 }
play-seeded را تعریف کنید تا یک دانه و یک quotation بگیرد و quotation را با مولدی اجرا کند که با آن عدد صحیح دانهبندی شده است، تا همان دانه همیشه همان نتیجه را تولید کند. نتیجهی quotation باید به فراخوانکننده برگردانده شود.
42 [ 6 roll-die ] play-seeded .
! => the same value every time for seed 42
! Same seed, same game:
99 [ 5 deal-hand ] play-seeded 99 [ 5 deal-hand ] play-seeded = .
! => t