Writing A Word Memory Game In Elm - Part 5: More Randomness And More Game
Tags: elm
Published: 2019-05-31 12:26:33

---
title: Writing A Word Memory Game In Elm - Part 5: More Randomness And More Game
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 5 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](https://dev.to/mickeyvip/writing-a-word-memory-game-in-elm-part-4-spicing-things-up-with-randomness-58ei)
* Part 5 - More Randomness And More Game

---

Playing with the same sentence all the time is pretty boring. The actual game needs to have many sentences to choose from. For example:

```elm
sentences : List String
sentences =
    [ "Two wrongs don't make a right."
    , "The pen is mightier than the sword."
    , "When in Rome, do as the Romans."
    , "Keep your friends close and your enemies closer."
    , "You can't make an omelet without breaking a few eggs."
    , "The grass is always greener on the other side of the hill."
    , "You can lead a horse to water, but you can't make him drink."
    , "If you want something done right, you have to do it yourself."
    ]
```

We can simplify the sentences by removing all the punctuation:

```elm
sentences : List String
sentences =
    [ "Two wrongs don't make a right"
    , "The pen is mightier than the sword"
    , "When in Rome do as the Romans"
    , "Keep your friends close and your enemies closer"
    , "You can't make an omelet without breaking a few eggs"
    , "The grass is always greener on the other side of the hill"
    , "You can lead a horse to water but you can't make him drink"
    , "If you want something done right you have to do it yourself"
    ]
```

To choose a sentence at random we can use [`elm/Random`](https://package.elm-lang.org/packages/elm/random/latest/) library to generate a random number from 0 to the length of our `sentences` list and take a sentence at this index (need to convert the `List` into an `Array` to use an index).

Or we can use [`elm-community/random-extra/Random-Extra#sample/`](https://package.elm-lang.org/packages/elm-community/random-extra/latest/Random-Extra#sample) that will choose an element uniformly at random. We already have `Random-Extra` so let's use it:

```elm
import Random.Extra as Random

-- omitted

chooseSentence : List String -> Cmd Msg
chooseSentence sentences_ =
    Random.sample sentences_
        |> Random.map (Maybe.withDefault "")
        |> Random.generate SentenceChosen
```

In `SentenceChosen` handler we can call `chooseWords` command and continue as it was before.

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

We need also to introduce a new state `Initialising` for modeling the game start:

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

Now let's implement the `SentenceChosen` branch of `update` function:

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

-- omitted

        SentenceChosen sentenceString ->
            case model of
                Initializing ->
                    let
                        sentence : Words
                        sentence =
                            generateSentence sentenceString
                    in
                    ( Started (StateStarted sentenceString), chooseWords sentence )

                Started _ ->
                    ( model, Cmd.none )

                Playing _ ->
                    ( model, Cmd.none )

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

We practically copied the code from the `init` function. And `init` itself becomes very short:

```elm
init : () -> ( Model, Cmd Msg )
init _ =
    ( Initializing, chooseSentence sentences )
```

We set the current state of the game to `Initializing` and invoke `chooseSentence` command by passing it the list of sentences.

The compiler informs us about non exhaustive `case`s for `GameState` in the `update` function, so let's address that:

```elm
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        WordChanged index wordString ->
            let
                model_ =
                    case model of
                        Started { sentence } ->
                            
-- omitted

                        Initializing ->
                            model

                        Started _ ->
                            model

                        Win _ ->
                            model
            in
            ( model_, Cmd.none )
        
-- omitted
        
        WordsChosen sortIndexes ->
            let
                model_ =
                    case model of
                        Started { currentSentence } ->
                            let
                                sentence : Words
                                sentence =
                                    generateSentence currentSentence

-- omitted

                            Playing (StatePlaying sentence_)

                        Initializing ->
                            model
                        
                        Playing _ ->
                            model

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

We made a couple of changes here:

1. The first branch was `Playing`, now it's `Started` and we added a calculation of `sentence` inside the `let` block.
2. The 3rd branch was `Started`, now it's `Playing`.

Thus the flow is more correct:

1. Initialiazing - choose random sentence
2. Started - choose random words
3. Playing
4. Win

Now the `view` function. Let's add a `viewInitilizing` view:

```elm
viewInitializing : Html msg
viewInitializing =
    p []
        [ text "Initializing..." ]
```

and call it from `view` function:

```elm
view : Model -> Html Msg
view model =
    let
        currentView =
            case model of
                Initializing ->
                    viewInitializing

                Playing { sentence } ->
                    viewGame sentence

                Started { currentSentence } ->
                    viewStarted currentSentence

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

The game compiles and now each time a new game is starting - it picks a random sentence!

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

Stay tuned for Part 6 where we will add a difficulty level and a countdown for the sentence preview.