Τα παιχνίδια τύχης χρειάζονται μια πηγή τυχαιότητας. Το vocabulary random του Factor (random) παρέχει μια γενική λέξη, τη random, που προσαρμόζεται σε ό,τι της δώσεις, καθώς και βοηθητικές λέξεις για ανακάτεμα και δειγματοληψία, και έναν τρόπο να κάνεις την τυχαιότητα αναπαραγώγιμη για τα tests.
inline
Μερικές από τις εργασίες αυτής της άσκησης ορίζουν μια λέξη που παίρνει ως όρισμα ένα quotation (ένα μπλοκ [ … ]) και το εκτελεί. Ο Factor έχει έναν σταθερό κανόνα γι' αυτό: μια λέξη που κάνει call σε ένα quotation που πήρε ως όρισμα πρέπει να δηλωθεί inline, γράφεται δηλαδή βάζοντας το inline αμέσως μετά το τελικό ;.
Το inline λέει στον μεταγλωττιστή να παρεμβάλει το σώμα της λέξης σε κάθε σημείο κλήσης, αντί να το μεταγλωττίσει μία φορά από μόνο του.
Ορίστε μια μικρή λέξη που βάζει το 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", ώστε ένα αμφισβητούμενο παιχνίδι να μπορεί να ξανατρέξει από τον ίδιο σπόρο.
Όρισε τη 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
Γράψου στο Exercism για να μάθεις και να κατακτήσεις Factor με 47 έννοιες163 ασκήσεις και πραγματική καθοδήγηση από ανθρώπους, όλα δωρεάν.