Veamos ahora cómo implementar la funcionalidad para escoger de forma aleatoria cuál es la palabra que el jugador tiene que adivinar. Para ello disponemos de un diccionario words, que es simplemente una lista de palabras localizada en el archivo com/example/package.scala.
La implementación es la siguiente:
import zio.random._
lazy val chooseWord: URIO[Random, Word] =
for {
index <- nextIntBounded(words.length)
word <- ZIO.fromOption(words.lift(index).flatMap(Word.make)).orDieWith(_ => new Error("Boom!"))
} yield word
Como podemos ver, estamos usando la función nextIntBounded del módulo zio.random. Esta función retorna un efecto que genera números enteros aleatorios entre 0 y un límite dado, en este caso el límite es la longitud del diccionario. Una vez que tenemos el entero aleatorio, obtenemos la palabra correspondiente del diccionario, con la expresión words.lift(index).flatMap(Word.make), que retorna un Option[Word], que es convertido a un efecto ZIO usando el método ZIO.fromOption, este efecto:
Si lo pensamos detenidamente, ¿puede haber algún caso en que la obtención de alguna palabra del diccionario falle? No realmente, porque el efecto chooseWord nunca intentará obtener una palabra cuyo índice esté fuera del rango de la longitud del diccionario, y por otro lado todas las palabras del diccionario están predefinidas y no son vacías. Por tanto, podemos descartar sin ningún problema el caso erróneo, usando el método ZIO#orDieWith, el cual retorna un nuevo efecto que no puede fallar y, en caso de que sí fallara, eso significaría que hay algún defecto serio en nuestra aplicación (por ejemplo que alguna de nuestras palabras predefinidas sea vacía cuando no debería serlo) y por lo tanto ésta debería fallar inmediatamente con la excepción provista.
Al final, chooseWord es un efecto de tipo URIO[Random, Word], lo que significa que: