Los juegos de azar necesitan una fuente de aleatoriedad. El vocabulario random de Factor proporciona una palabra genérica, random, que se adapta a lo que le pases, además de ayudas para barajar y tomar muestras, y una forma de hacer que la aleatoriedad sea reproducible para los tests.
inline
Algunas de las tareas de este ejercicio definen una palabra que toma una quotation (un bloque [ … ]) como argumento y la ejecuta. Factor tiene una regla firme al respecto: una palabra que hace call a una quotation que recibió como argumento debe declararse inline, lo que se escribe poniendo inline justo después del ; de cierre.
inline le indica al compilador que inserte el cuerpo de la palabra en cada punto de llamada en lugar de compilarlo una sola vez por su cuenta.
Aquí tienes una palabra pequeña que apila 10 y luego ejecuta la quotation que recibió:
USING: kernel math prettyprint ;
: with-ten ( quot -- ) 10 swap call ; inline
Su efecto de pila, ( quot -- ), no nombra ninguna salida, y sin embargo, si la llamas con dos quotations de efectos distintos, produce resultados diferentes, todos los cuales vuelven al llamador:
[ 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 (en random) es genérico respecto a su argumento:
random ( obj -- elt )
n, devuelve un número entero aleatorio en [0, n):USING: random ;
6 random . ! 4 (a value from 0 to 5)
{ "rock" "paper" "scissors" } random . ! "paper"
Para lanzar un dado normal, desplazas el rango una unidad hacia arriba: random de 6 da de 0 a 5, así que 6 random 1 + da de 1 a 6.
Para reunir un número fijo de extracciones aleatorias, repite una quotation con replicate (en sequences):
replicate ( n quot -- seq )
USING: random sequences ;
3 [ 6 random 1 + ] replicate . ! { 4 1 6 } (three dice)
randomize: barajar in siturandomize (en random) devuelve la secuencia con sus elementos en un orden aleatorio:
randomize ( seq -- randomized )
{ 1 2 3 4 5 } randomize . ! { 3 1 5 2 4 }
Baraja in situ y devuelve la misma secuencia, así que haz clone primero si necesitas conservar el orden original.
sample: varios elementos distintossample (en random) extrae n elementos distintos de una secuencia, como repartir una mano de cartas, sin repetir nunca una carta:
sample ( seq n -- seq' )
{ 10 20 30 40 50 } 3 sample . ! { 40 10 30 }
Pedir más elementos de los que contiene la secuencia es un error.
De forma predeterminada, random extrae de un generador global con semilla tomada del reloj del sistema, así que cada ejecución es distinta. Para los tests, o siempre que quieras una partida que puedas volver a jugar, vincula un generador con una semilla fija.
<mersenne-twister> (en random.mersenne-twister) construye un generador a partir de una semilla entera, y with-random (en random) ejecuta una quotation con ese generador 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
Todo lo que hay dentro de la quotation (random, randomize, sample) extrae del generador con semilla, así que la misma semilla reproduce siempre el mismo resultado.
Una palabra que toma una quotation como argumento y la ejecuta a través de with-random entra dentro de la regla de Marcar una palabra como inline: with-random acaba haciendo call a esa quotation, así que ese envoltorio debe marcarse como inline.
Llevas los juegos de azar del salón recreativo del paseo marítimo. Los jugadores tiran dados, la máquina de pinzas atrapa un premio y la mesa de cartas necesita que se barajen las cartas y se repartan las manos; todo ello impulsado por la aleatoriedad. Al final de la noche, también quieres una función de repetición para poder volver a ejecutar una partida en disputa desde la misma semilla.
Define roll-die para que reciba el número de caras y devuelva una tirada en el rango de 1 a sides, ambos inclusive.
6 roll-die .
! => 4 (some value from 1..6)
Define pick-prize para que reciba una secuencia de premios y devuelva uno de ellos al azar.
{ "teddy" "goldfish" "keyring" } pick-prize .
! => "goldfish"
Define shuffle-deck para que reciba una baraja (una secuencia) y la devuelva con las cartas en un orden aleatorio.
{ 1 2 3 4 5 } shuffle-deck .
! => { 3 1 5 2 4 }
Define deal-hand para que reciba una baraja y una cantidad n, y devuelva n cartas distintas de la baraja.
{ 10 20 30 40 50 } 3 deal-hand .
! => { 40 10 30 }
Define play-seeded para que reciba una semilla y una cita, y ejecute la cita con un generador inicializado con ese entero como semilla, de modo que la misma semilla reproduzca siempre el mismo resultado. El resultado de la cita debe devolverse a quien la llama.
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
Regístrate en Exercism para aprender y dominar Factor con 47 conceptos163 ejercicios y mentoría humana real, todo gratis.