Jogos de azar precisam de uma fonte de aleatoriedade. O vocabulário random do Factor fornece uma palavra genérica, random, que se adapta a tudo o que você passar para ela, além de auxiliares para embaralhar e coletar amostras, e uma forma de tornar a aleatoriedade reproduzível para os testes.
inline
Algumas tarefas deste exercício definem uma palavra que recebe uma quotation (um bloco [ … ]) como argumento e a executa. O Factor tem uma regra firme sobre isso: uma palavra que faz call numa quotation que recebeu como argumento precisa ser declarada inline, o que se escreve colocando inline logo depois do ; de fechamento.
inline diz ao compilador para inserir o corpo da palavra em cada ponto de chamada em vez de compilá-lo uma única vez, isoladamente.
Veja uma palavra pequena que empilha 10 e depois executa a quotation que recebeu:
USING: kernel math prettyprint ;
: with-ten ( quot -- ) 10 swap call ; inline
O efeito de pilha dela, ( quot -- ), não nomeia nenhuma saída, mas chamá-la com duas quotations de efeitos diferentes produz resultados diferentes, todos fluindo de volta para quem chamou:
[ 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 (de random) é genérica em relação ao seu argumento:
random ( obj -- elt )
n, ela retorna um inteiro aleatório em [0, n):USING: random ;
6 random . ! 4 (a value from 0 to 5)
{ "rock" "paper" "scissors" } random . ! "paper"
Para rolar um dado comum, você desloca o intervalo em uma unidade: random com 6 dá de 0 a 5, então 6 random 1 + dá de 1 a 6.
Para coletar um número fixo de sorteios aleatórios, repita uma quotation com replicate (de sequences):
replicate ( n quot -- seq )
USING: random sequences ;
3 [ 6 random 1 + ] replicate . ! { 4 1 6 } (three dice)
randomize: embaralhar no lugarrandomize (de random) retorna a sequência com os elementos em ordem aleatória:
randomize ( seq -- randomized )
{ 1 2 3 4 5 } randomize . ! { 3 1 5 2 4 }
Ela embaralha no lugar e retorna a mesma sequência, então use clone antes se precisar manter a ordem original.
sample: vários elementos distintossample (de random) sorteia 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 a sequência tem é um erro.
Por padrão, random sorteia de um gerador global cuja semente vem do relógio do sistema, então cada execução é diferente. Para testes, ou sempre que você quiser um jogo que possa repetir, associe um gerador a uma semente fixa.
<mersenne-twister> (de random.mersenne-twister) constrói um gerador a partir de uma semente inteira, e with-random (de random) executa uma quotation 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 dentro da quotation (random, randomize, sample) sorteia do gerador com semente, então a mesma semente sempre reproduz o mesmo resultado.
Uma palavra que recebe uma quotation como argumento e a executa por meio de with-random cai na regra de Marcar uma palavra como inline: with-random acaba fazendo call nessa quotation, então esse tipo de wrapper precisa ser marcado como inline.
Você comanda os jogos de azar do fliperama no calçadão à beira-mar. Os apostadores rolam os dados, a máquina de garra pega um prêmio, e a mesa de cartas precisa do baralho embaralhado e das mãos distribuídas, tudo movido por aleatoriedade. No fim da noite, você também quer um recurso de "replay", para que um jogo disputado possa ser rodado de novo a partir da mesma semente.
Defina roll-die para receber o número de lados e retornar um lançamento no intervalo de 1 a sides (inclusive).
6 roll-die .
! => 4 (some value from 1..6)
Defina pick-prize para receber uma sequência de prêmios e retornar um deles de forma aleatória.
{ "teddy" "goldfish" "keyring" } pick-prize .
! => "goldfish"
Defina shuffle-deck para receber um baralho (uma sequência) e retorná-lo com as cartas em ordem aleatória.
{ 1 2 3 4 5 } shuffle-deck .
! => { 3 1 5 2 4 }
Defina deal-hand para receber um baralho e uma contagem n, e retornar n cartas distintas do baralho.
{ 10 20 30 40 50 } 3 deal-hand .
! => { 40 10 30 }
Defina play-seeded para receber uma semente e uma quotation, e rodar a quotation com um gerador semeado a partir desse inteiro, de modo que a mesma semente sempre reproduza o mesmo resultado. O resultado da quotation deve ser retornado 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
Crie sua conta no Exercism para aprender e dominar Factor com 47 conceitos163 exercícios e mentoria humana de verdade, tudo de graça.