• ¶

    Game example

    This example illustrates how to use the Unitag Engine API to create a tiny game (try it here).

    Goal

    The player is invited to guess a secret number, which is initially chosen randomly and then stored in a cookie until the end of the game. Upon each attempt, the server indicates whether the secret number is higher or lower than the user’s guess.

  • ¶

    Implementation

    The raw JSON document can be found here.

    {
  • ¶

    Define the URL that will be used to access this operation. The resulting URL has the following form: http://e.unitag.io/r/{YOUR PATH HERE}.

        "url": "{YOUR PATH HERE}",
  • ¶

    Mark this operation as published. This is needed to make it publicly available.

        "state": "PUBLISHED",
  • ¶

    Define the global input values:

    1. Load the continue value. The result is a boolean which indicates whether a cookie named secret has been sent by the user agent.

    2. Once continue is loaded, use its value to compute the secret value. The result is the secret number: either the previous one which is restored from the secret cookie, or a new one which is chosen randomly.

    Both continue and secret are implicit data connectors. Their values are computed using an expression langage delimited by a markup syntax: <((...))>. The expression language by itself is largely inspired by JavaScript expressions.

    Here are the encountered specificities:

    • params.cookie exposes the cookies sent by the user agent
    • io allows to access the already computed input values
    • $randomInt returns a random integer between the given bounds
        "input": {
            "continue": "<(('secret' in params.cookie))>",
            "$then": {
                "secret": "<((io.continue ? params.cookie.secret : $randomInt(0, 1000)))>"
            }
        },
  • ¶

    Define the default entry point of this operation.

        "index": {
  • ¶

    Define a local input value, guess, which is computed using some more specificities of the expression language:

    • params.url exposes the query string parameters.
    • The | operator allows to chain functions by prepending the result of its left operand to the arguments of its right operand. For instance, this expression is equivalent to $parse($get(params.url, 'guess')).
    • A function always starts by $, and can be called without parentheses if no argument is needed.
    • $get allows to extract an attribute without checking its existence: if params.url.guess does not exists, we obtain null.
    • $parse allows to parse any JSON string. Here, it is used to cast a string into a number.
            "input": {
                "guess": "<((params.url | $get('guess') | $parse))>"
            },
  • ¶

    Check if the guess parameter is set.

            "if": "<((io.guess != null))>",
  • ¶

    If the guess parameter is set, check if the secret number has been found.

            "then": {
                "if": "<((io.guess == io.secret))>",
  • ¶

    If the secret number has been found, remove the secret cookie and send a congratulation message.

                "then": {
                    "trigger": {
                        "cookie": {"key": "secret", "age": 0}
                    },
                    "response": "Congratulations! The secret number was <((io.secret))>."
                },
  • ¶

    If the secret number has not been found, set the secret cookie and send a JSON response containing an hint.

                "else": {
                    "trigger": {
                        "cookie": {"key": "secret", "value": "<((io.secret))>", "age": 300000}
                    },
                    "response": {
                        "body": {
                            "newGame": "<((!io.continue))>",
                            "hint": "<(((io.guess > io.secret) ? 'LESS' : 'MORE'))>"
                        }
                    }
                }
            },
  • ¶

    If the guess parameter is not set, send a usage message.

            "else": {
                "response": "Try to guess the secret number with ?guess={YOUR ATTEMPT}"
            }
        }
    }
  • ¶

    Go further

    If you wish to experiment by yourself, you may consider adding the following features:

    1. Add another entry point which displays directly the secret number.
    2. Protect this entry point by an hardcoded password.
    3. Check the credentials against a CSV file (whitelist) instead the hardcoded password.
    4. Display a nicer GUI using U.me rendering.