Os jogos de azar precisam de uma fonte de aleatoriedade. O vocabulário random do Factor fornece uma palavra genérica, random, que se adapta ao que lhe passares, além de ajudantes para baralhar e amostrar, e uma forma de tornar a aleatoriedade reproduzível para os testes.
inline
Algumas tarefas deste exercício definem uma palavra que recebe uma citação (um bloco [ … ]) como argumento e a executa. O Factor tem uma regra firme sobre isso: uma palavra que faz call a uma citação que recebeu como argumento tem de ser declarada inline, o que se escreve colocando inline logo a seguir ao ; de fecho.
inline diz ao compilador para inserir o corpo da palavra em cada local de chamada, em vez de o compilar uma única vez isoladamente.
Eis uma palavra pequena que coloca 10 na pilha e depois executa a citação que lhe foi passada:
USING: kernel math prettyprint ;
: with-ten ( quot -- ) 10 swap call ; inline
O seu efeito na pilha, ( quot -- ), não nomeia nenhuma saída, mas chamá-la com duas citações de efeitos diferentes produz resultados diferentes, que regressam todos a quem chama:
[ 1 + ] with-ten . ! => 11 (quotation ( n -- n ): one value back)
[ dup 2 * ] with-ten . . ! => 20
! => 10 (quotation ( n -- n n ): two values back)
random: um elementorandom (em random) é genérico em relação ao seu argumento:
random ( obj -- elt )
n, devolve um inteiro aleatório em [0, n):USING: random ;
6 random . ! 4 (a value from 0 to 5)
{ "rock" "paper" "scissors" } random . ! "paper"
Para lançar um dado normal, deslocas o intervalo uma unidade para cima: random de 6 dá 0 a 5, por isso 6 random 1 + dá 1 a 6.
Para recolher um número fixo de sorteios aleatórios, repete uma citação com replicate (em sequences):
replicate ( n quot -- seq )
USING: random sequences ;
3 [ 6 random 1 + ] replicate . ! { 4 1 6 } (three dice)
randomize: baralhar no lugarrandomize (em random) devolve a sequência com os seus elementos numa ordem aleatória:
randomize ( seq -- randomized )
{ 1 2 3 4 5 } randomize . ! { 3 1 5 2 4 }
Baralha no lugar e devolve a mesma sequência, portanto faz clone primeiro se precisares de manter a ordem original.
sample: vários elementos distintossample (em random) retira n elementos distintos de uma sequência, como distribuir uma mão de cartas, nunca a mesma carta duas vezes:
sample ( seq n -- seq' )
{ 10 20 30 40 50 } 3 sample . ! { 40 10 30 }
Pedir mais elementos do que os que a sequência contém é um erro.
Por predefinição, random retira valores de um gerador global com semente do relógio do sistema, por isso cada execução é diferente. Para os testes, ou sempre que quiseres um jogo que possas reproduzir, associa um gerador com uma semente fixa.
<mersenne-twister> (em random.mersenne-twister) constrói um gerador a partir de uma semente inteira, e with-random (em random) executa uma citação com esse gerador instalado:
<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
Tudo o que está dentro da citação (random, randomize, sample) retira valores do gerador com semente, por isso a mesma semente reproduz sempre o mesmo resultado.
Uma palavra que recebe uma citação como argumento e a executa através de with-random cai na regra de Marcar uma palavra como inline: with-random acaba por fazer call a essa citação, por isso uma palavra dessas tem de ser marcada como inline.
Geres os jogos de azar na arcada do passadiço à beira-mar. Os jogadores lançam os dados, a máquina de garras apanha um prémio e a mesa de cartas precisa que se baralhe o baralho e se distribuam as mãos: tudo alimentado pelo acaso. No fim da noite, também queres uma funcionalidade de «replay», para que um jogo contestado possa ser executado outra vez a partir da mesma semente.
Define roll-die de modo a receber o número de lados e devolver um lançamento no intervalo de 1 a sides, inclusive.
6 roll-die .
! => 4 (some value from 1..6)
Define pick-prize de modo a receber uma sequência de prémios e devolver um deles ao acaso.
{ "teddy" "goldfish" "keyring" } pick-prize .
! => "goldfish"
Define shuffle-deck de modo a receber um baralho (uma sequência) e devolvê-lo com as cartas numa ordem aleatória.
{ 1 2 3 4 5 } shuffle-deck .
! => { 3 1 5 2 4 }
Define deal-hand de modo a receber um baralho e um número n, e devolver n cartas distintas do baralho.
{ 10 20 30 40 50 } 3 deal-hand .
! => { 40 10 30 }
Define play-seeded de modo a receber uma semente e uma quotation, e executar a quotation com um gerador inicializado a partir desse número inteiro, para que a mesma semente reproduza sempre o mesmo resultado. O resultado da quotation deve ser devolvido a quem a chamou.
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
Inscreve-te no Exercism para aprenderes e dominares Factor com 47 conceitos163 exercícios, e mentoria humana real, tudo grátis.