المسارات
/
Factor
Factor
/
التمارين
/
ألعاب الممشى البحري
ألعاب الممشى البحري

ألعاب الممشى البحري

تمرين تعلّمي

مقدمة

تحتاج ألعاب الحظّ إلى مصدر للعشوائية. توفّر مفردات 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 تعطي من 0 إلى 5، لذا يعطي 6 random 1 + من 1 إلى 6.

سحب عدة قيم

لجمع عدد ثابت من السحبات العشوائية، كرّر اقتباسًا باستخدام 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.

التعليمات

أنت تدير ألعاب الحظ في صالة الألعاب على ممشى الشاطئ. يرمي اللاعبون النرد، وتلتقط آلة المخالب جائزة، وتحتاج طاولة البطاقات إلى خلط رزمتها وتوزيع الأيدي. كل ذلك يعمل بالعشوائية. وفي نهاية الليلة تريد أيضًا ميزة "إعادة التشغيل" حتى يمكن تشغيل لعبة متنازع عليها مرة أخرى من البذرة نفسها.

1. ارمِ حجر النرد

عرّف roll-die بحيث تأخذ عدد الأوجه وتُرجع رمية في النطاق من 1 إلى sides (شاملًا الطرفين).

6 roll-die .
! => 4   (some value from 1..6)

2. التقط جائزة

عرّف pick-prize بحيث تأخذ متتالية من الجوائز وتُرجع واحدة منها عشوائيًا.

{ "teddy" "goldfish" "keyring" } pick-prize .
! => "goldfish"

3. اخلط الرزمة

عرّف shuffle-deck بحيث تأخذ رزمة (متتالية) وتُرجعها وقد رُتّبت بطاقاتها بترتيب عشوائي.

{ 1 2 3 4 5 } shuffle-deck .
! => { 3 1 5 2 4 }

4. وزّع يدًا

عرّف deal-hand بحيث تأخذ رزمة وعددًا n، وتُرجع n من البطاقات المختلفة من الرزمة.

{ 10 20 30 40 50 } 3 deal-hand .
! => { 40 10 30 }

5. أعِد التشغيل من بذرة

عرّف 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
تعديل عبر GitHub يفتح الرابط في نافذة أو علامة تبويب جديدة
Factor Exercism

مستعد لبدء ألعاب الممشى البحري؟

سجّل في Exercism لتتعلّم وتتقن Factor عبر 47 مفهومًا163 تمرينًا، وإرشاد بشري حقيقي، وكل ذلك مجانًا.