Διαδρομές
/
Factor
Factor
/
Ασκήσεις
/
Παιχνίδια στην προβλήτα
Παιχνίδια στην προβλήτα

Παιχνίδια στην προβλήτα

Άσκηση εκμάθησης

Εισαγωγή

Τα παιχνίδια τύχης χρειάζονται μια πηγή τυχαιότητας. Το vocabulary random του Factor (random) παρέχει μια γενική λέξη, τη random, που προσαρμόζεται σε ό,τι της δώσεις, καθώς και βοηθητικές λέξεις για ανακάτεμα και δειγματοληψία, και έναν τρόπο να κάνεις την τυχαιότητα αναπαραγώγιμη για τα tests.

Σημειώνοντας μια λέξη ως inline

Μερικές από τις εργασίες αυτής της άσκησης ορίζουν μια λέξη που παίρνει ως όρισμα ένα quotation (ένα μπλοκ [ … ]) και το εκτελεί. Ο Factor έχει έναν σταθερό κανόνα γι' αυτό: μια λέξη που κάνει call σε ένα quotation που πήρε ως όρισμα πρέπει να δηλωθεί inline, γράφεται δηλαδή βάζοντας το inline αμέσως μετά το τελικό ;.

Το inline λέει στον μεταγλωττιστή να παρεμβάλει το σώμα της λέξης σε κάθε σημείο κλήσης, αντί να το μεταγλωττίσει μία φορά από μόνο του.

  • Το quotation του καλούντος ενσωματώνεται απευθείας, οπότε ό,τι αφήνει το quotation στη στοίβα επιστρέφει πίσω στον καλούντα, ακόμη κι αν το stack effect της ίδιας της λέξης δεν δηλώνει καμία έξοδο.

Ορίστε μια μικρή λέξη που βάζει το 10 στη στοίβα και μετά εκτελεί το quotation που της δόθηκε:

USING: kernel math prettyprint ;

: with-ten ( quot -- ) 10 swap call ; inline

Το stack effect της, ( quot -- ), δεν δηλώνει καμία έξοδο. Κι όμως, όταν την καλέσεις με δύο quotations που έχουν διαφορετικά effects, παράγει διαφορετικά αποτελέσματα, που όλα επιστρέφουν πίσω στον καλούντα:

[ 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.

Εξαγωγή πολλών τιμών

Για να συλλέξεις έναν σταθερό αριθμό τυχαίων τιμών, επανάλαβε ένα quotation με το 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 τραβά από μια καθολική γεννήτρια που παίρνει σπόρο από το ρολόι του συστήματος, οπότε κάθε εκτέλεση διαφέρει. Για τα tests, ή όποτε θέλεις ένα παιχνίδι που να μπορείς να ξαναπαίξεις, δέσε μια γεννήτρια με έναν σταθερό σπόρο.

Το <mersenne-twister> (στο random.mersenne-twister) χτίζει μια γεννήτρια από έναν ακέραιο σπόρο, και το with-random (στο random) εκτελεί ένα quotation με αυτή τη γεννήτρια εγκατεστημένη:

<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

Ό,τι βρίσκεται μέσα στο quotation, τα random, randomize, sample, τραβά από τη γεννήτρια με τον σπόρο, οπότε ο ίδιος σπόρος αναπαράγει πάντα το ίδιο αποτέλεσμα.

Μια λέξη που παίρνει ως όρισμα ένα quotation και το εκτελεί μέσω του with-random εμπίπτει στον κανόνα από το Σημειώνοντας μια λέξη inline: το with-random καταλήγει να κάνει call σε αυτό το quotation, οπότε ένα τέτοιο wrapper πρέπει να σημειωθεί ως inline.

Οδηγίες

Διευθύνεις τα παιχνίδια τύχης στην αίθουσα παιχνιδιών του παραλιακού πεζόδρομου. Οι παίκτες ρίχνουν ζάρια, το μηχάνημα με τη δαγκάνα αρπάζει ένα βραβείο, και το τραπέζι με τις κάρτες θέλει την τράπουλά του ανακατεμένη και τα χέρια μοιρασμένα, όλα με τη δύναμη της τυχαιότητας. Στο τέλος της βραδιάς θέλεις επίσης μια λειτουργία "replay", ώστε ένα αμφισβητούμενο παιχνίδι να μπορεί να ξανατρέξει από τον ίδιο σπόρο.

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 ασκήσεις και πραγματική καθοδήγηση από ανθρώπους, όλα δωρεάν.