Writing A Word Memory Game In Elm - Part 4: Spicing Things Up With Randomness
Tags: elm
Published: 2019-04-25 13:12:09

---
title: Writing A Word Memory Game In Elm - Part 4: Spicing Things Up With Randomness
published: true
description: A tutorial for writing a nice word memory game in Elm
tags: elm
series: Writing A Word Memory Game In Elm
cover_image: https://thepracticaldev.s3.amazonaws.com/i/zijfhkxcnplbo93mv7if.png
---

This is part 4 of the series "Writing A Word Memory Game In Elm", find:

* [Part 1: Setting Up an Elm Application With Parcel](https://dev.to/mickeyvip/writing-a-word-memory-game-inelm---part-1-setting-up-an-elm-application-with-parcel-1ppk)
* [Part 2: Modeling And Building a Basic Word Memory Game](https://dev.to/mickeyvip/writing-a-word-memory-game-inelm---part-2-modeling-and-building-a-basic-word-memory-game-583g)
* [Part 3: Rethinking the Model](https://dev.to/mickeyvip/writing-a-word-memory-game-in-elm-part-3-rethinking-the-model-2ajp)
* Part 4: Spicing Things Up With Randomness
* [Part 5 - More Randomness And More Game](https://dev.to/mickeyvip/writing-a-word-memory-game-in-elm-part-5-more-randomness-and-more-game-1i37)

---

Choosing the same words every time is pretty boring. Let's make our game choose random words each time.

Randomness is a side effect and does not fit into functional programming concepts, since generating a random number returns something different each time.

In order to make our application handle side effects we need to upgrade it from `Browser.sandbox` to `Browser.element` which will add *commands* and *subscriptions* for interacting with the outside world.

Let's change our `main` definition to use `Browser.element`:

```elm
main : Program () Model Msg
main =
    Browser.element
        { view = view
        , init = init
        , update = update
        , subscriptions = subscriptions
        }

```

There are now several changes we need to make in order for our current application to compile:

* `init` expects a function instead of `Model`, so we'll add the `init` function
* `subscriptions` expects a function that we'll add
* `update` returns a `Tuple` `(Model, Cmd Msg)` instead of a `Model`

Let's follow the compiler and fix the errors.

We'll start by adding the `subscriptions` function. We actually will not need subscriptions for now, so we can return `Sub.none`, meaning *no subscriptions*:

```elm
---- SUBSCRIPTIONS ----


subscriptions : Model -> Sub Msg
subscriptions model =
    Sub.none

```  

Now `update` - let's change the signature to 

```elm
update : Msg -> Model -> ( Model, Cmd Msg )
``` 

and return the expected tuple (last line):

```elm
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        WordChanged index wordString ->
            let
                updateWord : Int -> Word -> Word
                updateWord wordIndex word =
                    case word of
                        HiddenWrd hiddenWord ->
                            if wordIndex == index then
                                HiddenWrd
                                    { hiddenWord
                                        | playerChoice = PlayerChoice wordString
                                    }

                            else
                                word

                        _ ->
                            word

                newSentence : Words
                newSentence =
                    List.indexedMap updateWord model.sentence
            in
            ( { model | sentence = newSentence }, Cmd.none )
```

The last one is the `init` function. It takes `flags` which we will not be using and can just ignore by declaring the first argument as a unit type `()`. It returns a `Tuple` `(Model, Cmd Msg)` similar to `update`. We will use our `initialModel` and `Cmd.none` meaning *no commands to run*:

```elm
init : () -> ( Model, Cmd Msg )
init _ =
    ( initialModel, Cmd.none )
```

This should make the application compile and the game should function as before.

The current progress is saved in the repo under a Tag v3.0:
https://github.com/mickeyvip/words-memory-game/tree/v3.0.

How do we choose random words from the list of words? Elm guide has an example of `Random` usage: https://guide.elm-lang.org/effects/random.html, and [`elm/random`](https://package.elm-lang.org/packages/elm/random/latest/Random) package has a nice API for generating random numbers.

I have found that `Random.list` might be useful: we can produce 3 random values from `0` to the length of `words` and take words at those indexes.

```elm
indexes : Int -> Int -> Random.Generator (List Int)
indexes quantity listLength =
    Random.list quantity (Random.int 0 (listLength - 1))
```

Unfortunately, it may produces a list with repeated values. We can overcome this problem by, for example, keeping generating new random values until we have the required number of unique values. But in a search for simpler or "already made" solution I have found [elm-community/random-extra](https://package.elm-lang.org/packages/elm-community/random-extra/latest/) package, which, as `elm/random` documentation says, may some day be merged with `elm/random`. 

`elm-community/random-extra` has `Random.List` module which exposes a [`shuffle`](https://package.elm-lang.org/packages/elm-community/random-extra/latest/Random-List#shuffle) function which, as its name states, shuffles a list. So we can apply it on our list of words and take the first 3. Sounds simple enough.

Let's install it (stop the app if it is running):

```bash
$ elm install elm-community/random-extra
```

Accept the installation prompt by hitting `y` (or "enter").

We also need to have `elm/random` as a direct dependency, while up until now had been installed as an indirect dependency. When we install it, Elm installer will prompt us to move it from indirect to direct dependencies. Choose 'y':

```bash
$ elm install elm/random
I found it in your elm.json file, but in the "indirect" dependencies.
Should I move it into "direct" dependencies for more general use? [Y/n]:
Dependencies loaded from local cache.
Dependencies ready!
```

As wee see in the documentation, calling `shuffle` produces a `Generator (List a)`, which is only a description of what we want to do. To actually execute the `Generator` we need to call `Random.generate` which in turn produces a `Command`, as described in the `Random` example in the Elm guide we saw earlier.

What we can do is take a list of indexes `[0, 1, 2, 3...]`, shuffle this list and take the first 3 indexes. Those will be the indexes of the hidden words; their placement in the new list will be the `sortKey`s.

Let's add a function that will produce a `Command`:

```elm
import Random
import Random.List

--- COMMANDS ----


chooseWords : Words -> Cmd Msg
chooseWords chosenSentence =
    List.range 0 (List.length chosenSentence - 1)
        |> Random.List.shuffle
        |> Random.map (List.take 3)
        |> Random.map (List.indexedMap Tuple.pair)
        |> Random.generate WordsChosen
```

The `List.range 0 (List.length chosenSentence - 1)` will give us the `[0, 1, 2, 3, 4, 5, 6]` (since we have 7 words in our sentence). 
The `shuffle` will reorder the list.
The `List.take 3` will take first 3 items from the reordered list.
The `List.indexedMap Tuple.pair` will map the list of word indexes to a `List` of `Tuple`s where the first index is the `sortKey` and the second index is the index of the word. For example `[(0, 1), (1, 6), (2, 3)]`.
Then we execute the command by calling `Random.generate` and passing it the new message `WordsChosen`.

To manipulate the result of the `Random` we use `Random.map` - similar to `map` of other types.

Let's add a new message, `WordsChosen`, that gets a list of chosen indexes:

```elm
type Msg
    = WordChanged Int String
    | WordsChosen (List (Int, Int))
```

Now the compiler will guide us to handle the new message in the `update` function:

```elm
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of

        -- omitted

        WordsChosen sortIndexes ->
```

I didn't find any easier way to update the sentence so what I did is as follows: `List.indexMap` the current sentence, so we have a word index and a word.

```elm
        WordsChosen sortIndexes ->
            let
                sentence =
                    List.indexedMap
                        (\wordIndex word ->

-- omitted

                    model.sentence
            in
            ( { model | sentence = sentence }, Cmd.none )
```

Look if there is a `sortIndex` pair for a current word (`wordIndex` equals the second member of the `Tuple`):

```elm
-- omitted
                sentence =
                    List.indexedMap
                        (\wordIndex word ->
                            let
                                hiddenIndex =
                                    List.filter
                                        (\( _, originalWordIndex ) ->
                                            originalWordIndex == wordIndex
                                        )
                                        sortIndexes

-- omitted
``` 

If `hiddenIndex` is not empty, we need to replace current word with `HiddenWord`, and the `sortKey` will be the first member of the `Tuple`. Else we need to leave the current word as is:

```elm
-- omitted

                                newWord =
                                    case List.head hiddenIndex of
                                        Just ( sortKey, _ ) ->
                                            HiddenWrd
                                                { sortKey = sortKey
                                                , answer = Answer (wordToString word)
                                                , playerChoice = PlayerChoice ""
                                                }

                                        Nothing ->
                                            word
-- omitted
```

Here is the full code for the `WordsChosen` message handler:

```elm
        WordsChosen sortIndexes ->
            let
                sentence =
                    List.indexedMap
                        (\wordIndex word ->
                            let
                                hiddenIndex =
                                    List.filter
                                        (\( _, originalWordIndex ) ->
                                            originalWordIndex == wordIndex
                                        )
                                        sortIndexes

                                newWord =
                                    case List.head hiddenIndex of
                                        Just ( sortKey, _ ) ->
                                            HiddenWrd
                                                { sortKey = sortKey
                                                , answer = Answer (wordToString word)
                                                , playerChoice = PlayerChoice ""
                                                }

                                        Nothing ->
                                            word
                            in
                            newWord
                        )
                        model.sentence
            in
            ( { model | sentence = sentence }, Cmd.none )
```

Let's also set all the words as `SentenceWord`:

```elm
initialModel : Model
initialModel =
    { sentence =
        [ SentenceWrd "The"
        , SentenceWrd "pen"
        , SentenceWrd "is"
        , SentenceWrd "mightier"
        , SentenceWrd "than"
        , SentenceWrd "the"
        , SentenceWrd "sword"
        ]
    }
```

We also need to update our `init` function to execute the `chooseWords` command:

```elm
init : () -> ( Model, Cmd Msg )
init _ =
    ( initialModel, chooseWords initialModel.sentence )
```

Refresh the page - we should see our game is working and each refresh makes it choose different words!

Let's add a nice "New Game" button so we don't need to refresh the page for a new game:

```elm
view : Model -> Html Msg
view model =
    main_ [ class "section" ]
        [ div [ class "container" ]
            [ viewTitle
            , div [ class "box" ]
                [ p
                    [ class "has-text-centered" ]
                    [ viewOriginalSentence model.sentence
                    , viewSentence model.sentence
                    ]
                , viewHiddenWords (hiddenWords model.sentence)
-- new code
                , div [ class "is-clearfix" ]
                    [ button
                        [ class "button is-info is-pulled-right"
                        , onClick NewGame
                        ]
                        [ text "New Game" ]
                    ]
                ]
            ]
        ]
```


Let's add `NewGame` message:

```elm
type Msg
    = WordChanged Int String
    | WordsChosen (List ( Int, Int ))
    | NewGame
```

And handle it in the `update` function:

```elm
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of

        -- omitted

        NewGame ->
            ( initialModel, chooseWords initialModel.sentence )
```

And after the page is refreshed, we can click "New Game" to restart the game.

The current progress is saved in the repo under a Tag v4.0 https://github.com/mickeyvip/words-memory-game/tree/v4.0.

# Indicating Winning

It would be a good time to show the player that the sentence is correct.

After each change, we can check if every `HiddenWord` has a `playerChoice` that is equal to `answer`. If it is the case - we can render the "You Win" view.

Let's add a function that will check if there is a win:

```elm
isWin : Words -> Bool
isWin sentence =
    List.all
        (\word ->
            case word of
                SentenceWrd _ ->
                    True

                HiddenWrd { answer, playerChoice } ->
                    answerToString answer == playerChoiceToString playerChoice
        )
        sentence
```

`List.all` will return `True` if for all of its members the predicate function returns `True`. If the word is `SentenceWrd`, there is nothing to check and we just return `True`. If the word is `HiddenWrd`, we return the result of comparing `answer` and `playerChoice`.

We can shorten `isWin`: we only interested in `HiddenWord`s and we already have a function that takes a `Words` and returns `List HiddenWord`, which is `hiddenWords`. Let's use it:

```elm
isWin : Words -> Bool
isWin sentence =
    List.all
        (\{ answer, playerChoice } ->
            answerToString answer == playerChoiceToString playerChoice
        )
        (hiddenWords sentence)
```

And if `isWin` handles `HiddenWord`s only, we don't need to send it `Words` at all:

```elm
isWin : List HiddenWord -> Bool
isWin hiddenWordList =
    List.all
        (\{ answer, playerChoice } ->
            answerToString answer == playerChoiceToString playerChoice
        )
        hiddenWordList
```

That looks much better.

We can get even fancier and remove the argument altogether and use currying ability of Elm, similar to how JSON decoders are declared:

```elm
isWin : List HiddenWord -> Bool
isWin =
    List.all
        (\{ answer, playerChoice } ->
            answerToString answer == playerChoiceToString playerChoice
        )
```

We are now returning a function that waits for `List HiddenWord` argument. This can be a little confusing for newcomers (like myself) though.

When the player wins, let's show the sentence and the "You Win!" message, and hide the sentence with drop-downs and the list of words. To make this easier we can refactor the main `view` to show `viewGame` or `viewWin` views depending on whether the `win` is `True` or `False`:

```elm
view : Model -> Html Msg
view model =
    let
        win : Bool
        win =
            isWin <| hiddenWords model.sentence


        currentView : Html Msg
        currentView =
            if win then
                viewWin model.sentence

            else
                viewGame model.sentence
    in
    main_ [ class "section" ]
        [ div [ class "container" ]
            [ viewTitle
            , div [ class "box" ]
                [ currentView ]
            ]
        ]


viewGame : Words -> Html Msg
viewGame sentence =
    div []
        [ viewSentence sentence
        , viewHiddenWords (hiddenWords sentence)
        ]


viewWin : Words -> Html Msg
viewWin sentence =
    div []
        [ div [ class "notification is-primary" ]
            [ h3 [ class "title is-3 has-text-centered" ] [ text "You Win!" ]
            ]
        , h4
            [ class "title is-4 has-text-centered" ]
            [ viewOriginalSentence sentence ]
        , div [ class "is-clearfix" ]
            [ button
                [ class "button is-info is-pulled-right"
                , onClick NewGame
                ]
                [ text "New Game" ]
            ]
        ]
```

This should be pretty straightforward and need no explanation. On the `viewWin` view we have a "You Win!" message, the sentence and the "New Game" button. I have also added `is-big` class to the title to make it bigger. On the `viewGame` view we show the game as before.

![Game in progress](https://thepracticaldev.s3.amazonaws.com/i/mu094vyli9nvzcahabyh.png)

![win](https://thepracticaldev.s3.amazonaws.com/i/wuarnag7khdji308en44.png)


The current progress is saved in the repo under a Tag v5.0 https://github.com/mickeyvip/words-memory-game/tree/v5.0.

# Generating `Sentence` Automatically

Until now we had manually set `sentence`, but in the actual game there will be many sentences as `String`s and we want to be able to generate `sentence` from them.

How can we do it? We can use [`String.words`](https://package.elm-lang.org/packages/elm/core/latest/String#words). That will return a list of words that we can turn into what we need.

Let's first change our `Model` to have `currentSentence : String`, set it to _"The pen is mightier than the sword"_ and set `sentence` to be an empty list:

```elm
type alias Model =
    { currentSentence : String
    , sentence : Words
    }


initialModel : Model
initialModel =
    { currentSentence = "The pen is mightier than the sword"
    , sentence = []
    }
```

Now we'll add a `generateSentence` function that will generate the `sentence` with the help of `getWords`:

```elm
getWords : String -> List String
getWords sentence =
    sentence
        |> String.words

generateSentence : String -> List Word
generateSentence sentenceString =
    sentenceString
        |> String.words
        |> List.map SentenceWrd
```

Let's update our `init` function to invoke `generateSentence`:

```elm
init : () -> ( Model, Cmd Msg )
init _ =
    let
        sentence : Words
        sentence =
            generateSentence initialModel.currentSentence

        model : Model
        model =
            { initialModel | sentence = sentence }
    in
    ( model, chooseWords sentence )
```

The game should work as before, only now the generating of the `sentence` is automatic.

However, when winning the game and clicking "New Game" we see an empty box. This is because we reset the model to `initialModel` which has `sentence` set to `[]`. Let's change the `update` function to call `init` that generates the `sentence` and executes `chooseWords` command:

```elm
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of

        -- omitted
        NewGame ->
            init ()
```

And now we can start a new game!


# Refactoring `Model` Into Game States

We again got to a state that can get out of sync. The `currentSentence` is needed only for generating the `sentence` and we have to set `sentence` to `[]` at the beginning of each game because it is on our `Model`, but actually it is not needed for the first step.

Let's redefine our `Model` so it has 2 states:

1. `Started` - will have only the `currentSentence : String`  
2. `Playing` - will have only the `sentence : Words`

The game will start in `Started` state and call `generateSentence`. After that the state will be changed to `Playing`.

```elm
type alias StateStarted =
    { currentSentence : String }


type alias StatePlaying =
    { sentence : Words
    }


type GameState
    = Started StateStarted
    | Playing StatePlaying
```

Now let's update our `Model` to be of type `GameState`:

```elm
type alias Model =
    GameState
```

Our `initialModel` can be set to:

```elm
initialModel : Model
initialModel =
    Started (StateStarted "The pen is mightier than the sword")
```

No unnecessary `sentence` in the initial state!

The `init` function becomes a little bit more verbose:

```elm
init : () -> ( Model, Cmd Msg )
init _ =
    let
        ( model, cmd ) =
            case initialModel of
                Started { currentSentence } ->
                    let
                        sentence : Words
                        sentence =
                            generateSentence currentSentence
                    in
                    ( Playing (StatePlaying sentence), chooseWords sentence )

                Playing _ ->
                    ( initialModel, Cmd.none )
    in
    ( model, cmd )
```

We now need to pattern match our `Model` to know in which game state the game is right now. If it's in `Started` state, we will generate the `sentence` and execute `chooseWords`. In the other case (which at this point should not happen), we will return the `initialModel` as is and not execute any command.

In the `update` function we also need to take the game state into account:

```elm
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        WordChanged index wordString ->
            let
                model_ =
                    case model of
                        Playing { sentence } ->
                            let
                                updateWord : Int -> Word -> Word
                                updateWord wordIndex word =
                                    case word of
                                        HiddenWrd hiddenWord ->
                                            if wordIndex == index then
                                                HiddenWrd
                                                    { hiddenWord
                                                        | playerChoice = PlayerChoice wordString
                                                    }

                                            else
                                                word

                                        _ ->
                                            word

                                newSentence : Words
                                newSentence =
                                    List.indexedMap updateWord sentence
                            in
                            Playing (StatePlaying newSentence)

                        Started _ ->
                            model
            in
            ( model_, Cmd.none )

-- omitted

```

This change should be pretty straightforward: if the game is in `Playing` state - extract the `sentence` from the state, update it and return `Playing` state with the updated `newSentence`, otherwise - leave the `model` as is.


The same thing for `WordsChosen`:

```elm
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of

-- omitted

        WordsChosen sortIndexes ->
            let
                model_ =
                    case model of
                        Playing { sentence } ->
                            let
                                sentence_ =
                                    List.indexedMap
                                        (\wordIndex word ->
                                            let
                                                hiddenIndex =
                                                    List.filter
                                                        (\( _, originalWordIndex ) ->
                                                            originalWordIndex == wordIndex
                                                        )
                                                        sortIndexes

                                                newWord =
                                                    case List.head hiddenIndex of
                                                        Just ( sortKey, _ ) ->
                                                            HiddenWrd
                                                                { sortKey = sortKey
                                                                , answer = Answer (wordToString word)
                                                                , playerChoice = PlayerChoice ""
                                                                }

                                                        Nothing ->
                                                            word
                                            in
                                            newWord
                                        )
                                        sentence
                            in
                            Playing (StatePlaying sentence_)

                        Started _ ->
                            model
            in
            ( model_, Cmd.none )
```

The `view` has to be updated also:

```elm
view : Model -> Html Msg
view model =
    let
        currentView =
            case model of
                Playing { sentence } ->
                    let
                        win : Bool
                        win =
                            isWin <| hiddenWords sentence
                    in
                    if win then
                        viewWin sentence

                    else
                        viewGame sentence

                Started { currentSentence } ->
                    viewStarted currentSentence
    in
    main_ [ class "section" ]
        [ div [ class "container" ]
            [ viewTitle
            , div [ class "box" ]
                [ currentView ]
            ]
        ]
```

When the game state is `Started` - we will render `viewStarted` view that will just show the current sentence:

```elm
viewStarted : String -> Html msg
viewStarted currentSentence =
    p []
        [ text currentSentence ]
```

Although we will not see it, since the game goes into `Playing` state after the `init` function, but we will use it in the future.

Now the game compiles and works as before, while the `Model` is much better designed.

It actually looks logical to have another playing state - `Win`. Thus the logic of winning will reside in the `update` function and not in the `view` like it is now, which feels odd.

```elm
type alias StateWin =
    { currentSentence : String
    }


type GameState
    = Started StateStarted
    | Playing StatePlaying
    | Win StateWin
```

The `init`:

```elm
init : () -> ( Model, Cmd Msg )
init _ =
    let
        ( model, cmd ) =
            case initialModel of
                Started { currentSentence } ->
                    let
                        sentence : Words
                        sentence =
                            generateSentence currentSentence
                    in
                    ( Playing (StatePlaying sentence), chooseWords sentence )

                Playing _ ->
                    ( initialModel, Cmd.none )

                Win _ ->
                    ( initialModel, Cmd.none )
    in
    ( model, cmd )
```

Then `update`:

```elm
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        WordChanged index wordString ->
            let
                model_ =
                    case model of
                        Playing { sentence } ->
                            let
                                updateWord : Int -> Word -> Word
                                updateWord wordIndex word =
                                    case word of
                                        HiddenWrd hiddenWord ->
                                            if wordIndex == index then
                                                HiddenWrd
                                                    { hiddenWord
                                                        | playerChoice = PlayerChoice wordString
                                                    }

                                            else
                                                word

                                        _ ->
                                            word

                                newSentence : Words
                                newSentence =
                                    List.indexedMap updateWord sentence

                                isWin_ =
                                    isWin (hiddenWords newSentence)
                            in
                            if isWin_ then
                                Win (StateWin (sentenceToString newSentence))

                            else
                                Playing (StatePlaying newSentence)

                        Started _ ->
                            model

                        Win _ ->
                            model
            in
            ( model_, Cmd.none )

        WordsChosen sortIndexes ->
            let
                model_ =
                    case model of
                        Playing { sentence } ->

-- omitted

                        Win _ ->
                            model
            in
            ( model_, Cmd.none )


```

We added the winning check to the `Playing` case. If there is a winning, we will change the state to `Win`. If the game is in `Win` state already - just return current `model` similarly to `Started` case.

We added `sentenceToString` function that converts `Words` to `String`:

```elm
sentenceToString : Words -> String
sentenceToString sentence =
    sentence
        |> List.map wordToString
        |> String.join " "
```

An we can reuse it in `viewOriginalSentence`:

```elm
viewOriginalSentence : Words -> Html Msg
viewOriginalSentence words =
    p
        [ class "has-text-centered" ]
        [ text <| sentenceToString words ]
```

The `view` is now much simpler:

```elm
view : Model -> Html Msg
view model =
    let
        currentView =
            case model of
                Playing { sentence } ->
                    viewGame sentence

                Started { currentSentence } ->
                    viewStarted currentSentence

                Win { currentSentence } ->
                    viewWin currentSentence
    in

--- omitted

```

Now we see that we need to refactor `viewWin` to accept `String` and not `Words`:

```elm
viewWin : String -> Html Msg
viewWin sentence =
    div []
        [ div [ class "notification is-primary" ]
            [ h3 [ class "title is-3 has-text-centered" ] [ text "You Win!" ]
            ]
        , h4
            [ class "title is-4 has-text-centered" ]
            [ p
                [ class "has-text-centered" ]
                [ text sentence ]
            ]
        , div [ class "is-clearfix" ]
            [ button
                [ class "button is-info is-pulled-right"
                , onClick NewGame
                ]
                [ text "New Game" ]
            ]
        ]
```

And there is no need for `viewOriginalSentence`, since we just use the same code that generates HTML inside `viewWin, so just delete it.

The game should compile and work as before, but now we have a 3 specific game states with data relevant to each state.

The current progress is saved in the repo under a Tag v6.0 https://github.com/mickeyvip/words-memory-game/tree/v6.0.

Stay tuned for the upcoming post, where we will have more sentences to choose from for each new game!