DEV Community

Cover image for Writing A Word Memory Game In Elm - Part 1: Setting Up an Elm Application With Parcel
Mickey
Mickey

Posted on • Edited on

Writing A Word Memory Game In Elm - Part 1: Setting Up an Elm Application With Parcel

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


Preface

One of the most effective ways to learn is by doing. I was looking for a project to improve my Elm skills and a friend gave me an excellent idea -- to write a word memory game.

Note: this series of posts reflects my personal learning experience, any constructive feedback is welcome.

The Memory Game

There is a sentence which the player can read. Several words are then taken out and the player must reconstruct the sentence from memory.

For example, the sentence is:

If you want something done right, you have to do it yourself.

And with several words removed:

If --- want something ---- right, you ---- to do it yourself."

Game in action

The game is pretty simple, but there are many ways it can be be extended:

  • The missing words can be presented to the user in-place (as a dropdown), or near the sentence as a list
  • Each time the player guesses the correct word, they can be informed straight away or find out the result only when all the words are used
  • At the beginning of the game the sentence is visible to the player for several seconds only
  • Etc

Starting the Project

To make the development cycle easier I chose to use Parcel bundler, which supports Elm out of the box since v1.10.0 and HMR since v1.11.0.

Let's create a project folder, for example word-memory-game, cd into it and initialise the NPM project:

$ npm init -y
Enter fullscreen mode Exit fullscreen mode

The -y option will accept all defaults and create package.json file.

Let's install the Parcel bundler locally (it can also be installed globally):

$ npm i -D parcel-bundler
Enter fullscreen mode Exit fullscreen mode

Following Parcel's Getting Started let's add index.html:

<!doctype html>
<html>
<body>
    <script src="./index.js"></script>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

and index.js:

console.log('Words Memory Game started');
Enter fullscreen mode Exit fullscreen mode

Also let's add the following lines to the scripts section of package.json:

"scripts": {
    "dev": "parcel index.html",
    "build": "parcel build index.html"
}
Enter fullscreen mode Exit fullscreen mode

In order to start the development server let's run:

$ npm run dev
Enter fullscreen mode Exit fullscreen mode

and navigate to http://localhost:1234

Parcel bundler has loaded our application

In order to host our Elm application in a page let's add

<div id="app"></div>
Enter fullscreen mode Exit fullscreen mode

to index.html:

<!-- index.html -->

<!doctype html>
<html>
<body>
    <div id="app"></div>
    <script src="./index.js"></script>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

Let's create src folder and add Main.elm to it:

module Main exposing (main)

import Html

main =
    Html.text "Words Memory Game"
Enter fullscreen mode Exit fullscreen mode

and change index.js to:

import { Elm } from "./src/Main.elm";

Elm.Main.init({
  node: document.getElementById("app")
});
Enter fullscreen mode Exit fullscreen mode

After we save all the files, Parcel will automatically initialise an Elm project (including creating elm.json file), install needed dependencies and reload. We can also reload the page manually to clear all the previous errors from the console.

Main.elm loaded and working

Now let's make our Elm skeleton a real Elm application by adding Msg, Model, view and update, as well as updating main:

module Main exposing (main)

import Browser
import Html exposing (Html)


type alias Model =
    { sentence : String
    }


initialModel : Model
initialModel =
    { sentence = "The pen is mightier than the sword" }


type Msg
    = NoOp


update : Msg -> Model -> Model
update msg model =
    case msg of
        NoOp ->
            model


view : Model -> Html msg
view model =
    Html.text model.sentence


main : Program () Model Msg
main =
    Browser.sandbox
        { init = initialModel
        , update = update
        , view = view
        }

Enter fullscreen mode Exit fullscreen mode

Great! We have our basic "Hello, World!".

I personally like my applications to look nice, so let's add the popular Bulma CSS framework in our index.html (or we can install it locally and import it) and a meta tag that Bulma recommends:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <title>Words Memory Game</title>
        <link
            rel="stylesheet"
            href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.2/css/bulma.min.css"
        />
    </head>
    <body>
        <div id="app" class="section"></div>
        <script src="./index.js"></script>
    </body>
</html>

Enter fullscreen mode Exit fullscreen mode

Now in Main.elm let's update our view function to show a title and a sentence in a nice box:

view : Model -> Html msg
view model =
    main_ [ class "section" ]
        [ div [ class "container" ]
            [ viewTitle
            , div [ class "box" ]
                [ p
                    [ class "has-text-centered" ]
                    [ text model.sentence ]
                ]
            ]
        ]


viewTitle : Html msg
viewTitle =
    h1 [ class "title has-text-centered" ]
        [ text "Words Memory Game" ]


Enter fullscreen mode Exit fullscreen mode

Don't forget to import Html and Html.Attributes functions:

import Html exposing (Html, div, h1, main_, p, text)
import Html.Attributes exposing (class)

Enter fullscreen mode Exit fullscreen mode

Now our application looks nicer:

Nice looking application

Another touch that I want to add to our game is the ability to show pretty icons. Therefore let's add a link to Font Awesome web font in our index.html:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <title>Words Memory Game</title>
        <link
            rel="stylesheet"
            href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.2/css/bulma.min.css"
        />
        <link
            rel="stylesheet"
            href="https://use.fontawesome.com/releases/v5.7.1/css/regular.css"
            integrity="sha384-IG162Tfx2WTn//TRUi9ahZHsz47lNKzYOp0b6Vv8qltVlPkub2yj9TVwzNck6GEF"
            crossorigin="anonymous"
        />
        <link
            rel="stylesheet"
            href="https://use.fontawesome.com/releases/v5.7.1/css/fontawesome.css"
            integrity="sha384-4aon80D8rXCGx9ayDt85LbyUHeMWd3UiBaWliBlJ53yzm9hqN21A+o1pqoyK04h+"
            crossorigin="anonymous"
        />
    </head>
    <body>
        <div id="app" class="section"></div>
        <script src="./index.js"></script>
    </body>
</html>

Enter fullscreen mode Exit fullscreen mode

Now we are all set up for the next steps, read about them in the upcoming posts.

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

Top comments (9)

Collapse
 
perty profile image
Per Lundholm

I understand that you are in the process of learning Elm. You do not need to use Parcel, there is a command "elm init" that sets up an initial directory. Also there is various other options, like elm-app that creates a service worker. You should also be familiar with elm-live, which is nice when trying things out.

An alternative to HTML and CSS is elm-ui, but if you have a CSS framework that you know, of course start there.

Collapse
 
mickeyvip profile image
Mickey • Edited

Hi Per.

Thank you for your comment.

Yes I am learning Elm and I am aware of the elm init, create-elm-app (if this is what you meant by elm-app) and elm-live.

Here I wanted a very lightweight setup that will give me a nice development experience.

elm init would mean manually compiling each time.
elm-live - manually refreshing the page.
create-elm-app - setting up a lot of things that I don't need.

So I decided to go for parcel-bundler - zero config, automatically setting up the Elm project and giving me a development server + hot module reload.

Regarding elm-ui - I am planning to dig into it deeper, but for this small project I wanted to be focused on more Elm core things. I am thinking of eventually converting this project to use elm-ui, but not just now.

Collapse
 
antonrich profile image
Anton

I went with the parcel as well. But I have an empty page. If I have an error in the compiler the parcel tells me about it. So that means it's working. But the page is still empty.

A note on elm-live. You don't have to manually update the page it is automatic.

Thread Thread
 
mickeyvip profile image
Mickey

Hi, Anton.

Sorry to hear the Parcel didn't work for you.

It is hard to understand what is wrong without seeing your code. Can you share it so I can take a look?

Also, you're right about the elm-live. My mistake.

Thread Thread
 
antonrich profile image
Anton

Actually, it works. I figured what the problem was. The problem was with my Russian government blocking the Elm. Parcel wanted to download some packages. I turned on vpn and it worked.

I knew there was something strange about it. Because the code didn't have a mistake. And when I for example purposefully introduce a mistake the parcel/elm would show it to me in the browser.

Thread Thread
 
mickeyvip profile image
Mickey

It's great you figured that out!

Collapse
 
antonrich profile image
Anton • Edited

It's working with elm-live though:

https://thepracticaldev.s3.amazonaws.com/i/t21q08ymdym8qqcl5pwc.png

Collapse
 
mickeyvip profile image
Mickey

Unfortunately the link seems to be broken.

Collapse
 
antonrich profile image
Anton

Seems to have been a dev.to issue.
The screenshot basically shows that it runs with elm-live.