I giochi basati sul caso hanno bisogno di una fonte di casualità. Il vocabolario random di Factor fornisce un'unica parola generica, random, che si adatta a qualunque cosa le passi, più alcune funzioni ausiliarie per mescolare ed estrarre campioni, e un modo per rendere la casualità riproducibile per i test.
inline
Alcuni dei compiti di questo esercizio definiscono una parola che accetta come argomento una quotation (un blocco [ … ]) e la esegue. Factor ha una regola ferrea in proposito: una parola che fa call su una quotation ricevuta come argomento deve essere dichiarata inline, scrivendo inline subito dopo il ; di chiusura.
inline dice al compilatore di inserire il corpo della parola in ogni punto di chiamata, invece di compilarlo una volta da solo.
Ecco una piccola parola che mette 10 sullo stack e poi esegue la quotation che le è stata passata:
USING: kernel math prettyprint ;
: with-ten ( quot -- ) 10 swap call ; inline
Il suo effetto stack, ( quot -- ), non nomina alcun output, eppure chiamandola con due quotation di effetti diversi si ottengono risultati diversi, che ritornano tutti al chiamante:
[ 1 + ] with-ten . ! => 11 (quotation ( n -- n ): one value back)
[ dup 2 * ] with-ten . . ! => 20
! => 10 (quotation ( n -- n n ): two values back)
random: un elementorandom (in random) è generica rispetto al suo argomento:
random ( obj -- elt )
n, restituisce un intero casuale in [0, n):USING: random ;
6 random . ! 4 (a value from 0 to 5)
{ "rock" "paper" "scissors" } random . ! "paper"
Per tirare un dado normale basta spostare l'intervallo di uno: random di 6 dà da 0 a 5, quindi 6 random 1 + dà da 1 a 6.
Per raccogliere un numero fisso di estrazioni casuali, ripeti una quotation con replicate (in sequences):
replicate ( n quot -- seq )
USING: random sequences ;
3 [ 6 random 1 + ] replicate . ! { 4 1 6 } (three dice)
randomize: mescolare sul postorandomize (in random) restituisce la sequenza con gli elementi in ordine casuale:
randomize ( seq -- randomized )
{ 1 2 3 4 5 } randomize . ! { 3 1 5 2 4 }
Mescola sul posto e restituisce la stessa sequenza, quindi fai prima clone se devi conservare l'ordine originale.
sample: più elementi distintisample (in random) estrae n elementi distinti da una sequenza, come servire una mano di carte, mai la stessa carta due volte:
sample ( seq n -- seq' )
{ 10 20 30 40 50 } 3 sample . ! { 40 10 30 }
Chiedere più elementi di quanti ne contenga la sequenza è un errore.
Per impostazione predefinita, random pesca da un generatore globale inizializzato con l'orologio di sistema, quindi ogni esecuzione è diversa. Per i test, o ogni volta che vuoi un gioco che puoi rigiocare, associa un generatore a un seme fisso.
<mersenne-twister> (in random.mersenne-twister) costruisce un generatore a partire da un seme intero, e with-random (in random) esegue una quotation con quel generatore installato:
<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
Tutto ciò che sta dentro la quotation, random, randomize, sample, pesca dal generatore inizializzato con il seme, quindi lo stesso seme riproduce sempre lo stesso risultato.
Una parola che accetta una quotation come argomento e la esegue tramite with-random rientra nella regola di Contrassegnare una parola come inline: with-random finisce per fare call su quella quotation, quindi un wrapper del genere deve essere contrassegnato inline.
Gestisci i giochi di fortuna nella sala giochi sul lungomare. I giocatori lanciano i dadi, la macchina artiglio afferra un premio, e il tavolo da gioco ha bisogno del mazzo mescolato e delle mani distribuite: tutto alimentato dalla casualità. Alla fine della serata vuoi anche una funzionalità di "replay", così una partita contestata può essere rieseguita partendo dallo stesso seme.
Definisci roll-die in modo che prenda il numero di facce e restituisca un lancio nell'intervallo da 1 a sides (estremi inclusi).
6 roll-die .
! => 4 (some value from 1..6)
Definisci pick-prize in modo che prenda una sequenza di premi e ne restituisca uno a caso.
{ "teddy" "goldfish" "keyring" } pick-prize .
! => "goldfish"
Definisci shuffle-deck in modo che prenda un mazzo (una sequenza) e lo restituisca con le carte in ordine casuale.
{ 1 2 3 4 5 } shuffle-deck .
! => { 3 1 5 2 4 }
Definisci deal-hand in modo che prenda un mazzo e un numero n, e restituisca n carte distinte dal mazzo.
{ 10 20 30 40 50 } 3 deal-hand .
! => { 40 10 30 }
Definisci play-seeded in modo che prenda un seme e una quotation, ed esegua la quotation con un generatore inizializzato da quell'intero, così che lo stesso seme riproduca sempre lo stesso risultato. Il risultato della quotation va restituito al chiamante.
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
Iscriviti a Exercism per imparare e padroneggiare Factor con 47 concetti163 esercizi e il mentoring di persone reali, tutto gratis.