Dyota's blog

Hangman

Hangman

Recently, I was lucky enough to have been assigned a project to make a game using Power Apps. The app was to be the companion to a "Amazing Race" style of game, where teams of contestants race from one station to another. The location of each successive station are hidden within rhyming clues. When the right answer is entered into the app, the team is granted with the location of the next station.

A blank text input field may have been daunting, and doesn't provide any indication for minor variations, like capitalisations or plurals.

The mechanic I settled on was to make a "hangman" type of indicator. Above the text field are a number of underscores (_), equal to the number of letters in the answer. When the nth letter in the answer field is equal to the nth letter of the answer, the _ turns into a ✔. If it's wrong, the _ turns into a ✘.

How did I do it? Read on and find out!

Spoilers

If you're itching to see the whole thing, here it is in its original implementation:

Concat(
    ForAll(
        Sequence(Len(vAnswer)),
        If(
            Value > Len(tiAnswer.Text),
            "_ ",
            If(
                Mid(tiAnswer.Text, Value, 1) = Mid(vAnswer, Value, 1),
                "✔",
                "✘"
            )
        )
    ), 
    Value, 
    ""
)

Scenario

Let's pretend that we have a clue, and the answer for it is "ferry". We see an input field, and five underscores, separated by spaces.

_ _ _ _ _

|___________________________|

Let's also say that our answer is stored in some variable called vAnswer, and our text input control is called tiAnswer. Our output is called lAnswer

Let's look at these one by one.

Core check

What we want to do is compare strings. Is the first letter of tiAnswer.Text the same as the first letter of vAnswer?

The way to check for this is to say...

Mid(tiAnswer.Text, nthletter, 1) = Mid(vAnswer, nthletter, 1)

If it's right, then tick; if it's wrong, then cross.

If(
    Mid(tiAnswer.Text, Value, 1) = Mid(vAnswer, Value, 1),
    "✔",
    "✘"
)

We are going to repeat this check for however many letters are in vAnswer. Let's frame the loop.

Loops!

The Sequence() function goes really well with ForAll(). We are going to use this one-two combo right now, and set up a loop over Len(vAnswer).

ForAll(
    Sequence(Len(vAnswer)),
    ...
)

We can combine the core check with this loop right now. Let's see what happens. Remembers to use Value for nthletter.

ForAll(
    Sequence(Len(vAnswer)),
    If(
        Mid(tiAnswer.Text, Value, 1) = Mid(vAnswer, Value, 1),
        "✔",
        "✘"
    )
)

What we will get here, is that the output will render a ✘ for every false letter we get. It will look someting like this:

✔ ✔ ✘ ✘ ✘

|_fe________________________|

You'll notice that it will render a ✘, even for the letters that we haven't typed in yet. It would be a bit nicer if they rendered _ instead, right? Let's put another condition around the core check.

Rendering underscores for untyped letters

Here, if the nth letter of vAnswer is a higher number than the length of what's been typed into tiAnswer, we will render a _.

If(
    Value > Len(tiAnswer.Text),
    "_ ",
    If(
        Mid(tiAnswer.Text, Value, 1) = Mid(vAnswer, Value, 1),
        "✔",
        "✘"
    )
)

So, to integrate this again into the for loop:

ForAll(
    Sequence(Len(vAnswer)),
    If(
        Value > Len(tiAnswer.Text),
        "_ ",
        If(
            Mid(tiAnswer.Text, Value, 1) = Mid(vAnswer, Value, 1),
            "✔",
            "✘"
        )
    )
)

Finishing up

Remember that a ForAll(), when it outputs a table, will output a table with one column called Value. Let's concetenate all of this to render our final output for lAnswer.

Concat(
    ForAll(
        Sequence(Len(vAnswer)),
        If(
            Value > Len(tiAnswer.Text),
            "_ ",
            If(
                Mid(tiAnswer.Text, Value, 1) = Mid(vAnswer, Value, 1),
                "✔",
                "✘"
            )
        )
    ), 
    Value, 
    ""
)

#powerapps