Trilhas
/
Factor
Factor
/
Exercícios
/
Jogos do calçadão
Jogos do calçadão

Jogos do calçadão

Exercício de aprendizagem

Introdução

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.

Marcar uma palavra como 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.

  • A quotation de quem chama é costurada diretamente, então tudo o que a quotation deixa na pilha flui de volta para quem chamou, mesmo que o próprio efeito de pilha da palavra não declare nenhuma saída.

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 elemento

random (de random) é genérica em relação ao seu argumento:

random ( obj -- elt )
  • Dado um inteiro n, ela retorna um inteiro aleatório em [0, n):
USING: random ;

6 random .    ! 4   (a value from 0 to 5)
  • Dada uma sequência, ela retorna um elemento aleatório:
{ "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.

Sortear vários valores

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 lugar

randomize (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 distintos

sample (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.

Aleatoriedade reproduzível

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.

Instruções

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.

1. Rolar um dado

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)

2. Pegar um prêmio

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"

3. Embaralhar o baralho

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 }

4. Distribuir uma mão

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 }

5. Repetir a partir de uma semente

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
Editar via GitHub O link abre em uma nova janela ou aba
Factor Exercism

Tudo pronto para começar Jogos do calçadão?

Crie sua conta no Exercism para aprender e dominar Factor com 47 conceitos163 exercícios e mentoria humana de verdade, tudo de graça.