Building the Interface

Basic Requirements

The experience playing the game (as with all pages) should be as smooth as possible. If we consider this, there’s pretty much only two ways we could build the interface for a game in Ampscript:

  • hyperlinks everywhere
  • forms with submit buttons everywhere

Both options are fairly easy, but I chose do it with forms, as it’s more elegant – links would force us to pass the game state as URL parameters visible in the address bar and when we hover over a link in our browsers.

Using forms allows us to use method="POST" which conveniently hides from the player all parameters passed between page submits.

Sections

The interface should have the following parts basic parts:

  • The game board where players can select their next move
  • A section showing the game state
    • if somebody won
    • if the game ended in a draw
    • which player moves now
  • A button starting a new round

Reading the Current Game State

set @playerTurn = RequestParameter('playerTurn')
set @firstPlayer = RequestParameter('firstPlayer')
set @fields = RequestParameter('fields')

IF Empty(@playerTurn)   THEN set @playerTurn = "X" ENDIF
IF Empty(@firstPlayer)  THEN set @firstPlayer = IIF(Random(1,2) == 1, "X", "O") ENDIF
IF Empty(@fields)       THEN set @fields = "123456789" ENDIF

Each time when you enter the page we are using the RequestParameter() function to check for the following variables and assign default values if needed:

  • @playerTurn – which players turn is it, if the value is empty, we give this turn to player X
  • @firstPlayer – which player started the current round, the default value is selected randomly
  • @fields – the representation of the board as a string, if it’s empty we assign an empty board: 123456789 where no players has made a move.

Then we build the @verification string as described in the previous section to determine if the game has ended.

Building the board

/* Field Display: START*/
FOR @i = 1 TO 9 DO

    IF 
        Substring(@fields, @i, 1) == "X"
        THEN
            ]%% 
            <div>
                <input type="submit" class="f x" value="X" disabled>
            </div>
            %%[
    ELSEIF 
        Substring(@fields, @i, 1) == "O"
        THEN
            ]%% 
            <div>
                <input type="submit" class="f o" value="O" disabled>
            </div>
            %%[
    ELSEIF 
        Substring(@fields, @i, 1) != "X"
        AND
        Substring(@fields, @i, 1) != "O"
        AND
        IndexOf(@state, "Win") > 0
        THEN
            ]%% 
            <div>
                <input type="submit" class="f" value=" " disabled>
            </div>
            %%[
    ELSE 
        ]%%
            <div>
                <form method="POST" action="%%=RedirectTo(@url)=%%">
                    <input type="hidden" name="fields" value="%%=v(Replace(@fields, @i, @playerTurn))=%%">
                    <input type="hidden" name="playerTurn" value="%%=v(@nextPlayer)=%%">
                    <input type="hidden" name="firstPlayer" value="%%=v(@firstPlayer)=%%">
                    <input type="submit" class="f" value="%%=v(@playerTurn)=%%">
                </form>
            </div>
        %%[
    ENDIF

    IF MOD(@i, 3) == 0
        THEN ]%% <br> %%[
        ENDIF   

NEXT @i

Yes, this section is large, but it’s fairly simple:

  • We start a loop that will go from 1 to 9
  • In each iteration we extract a substring from the @fields string to see what a given character at that position contains:
    • if it’s an X or O, we put this character inside of a disabled input button, so that the players can’t select this move again
    • if it’s not one of the above and we concluded that the game has ended (IndexOf(@state, "Win") > 0) then we output a disabled empty field
    • if none of the above conditions is true, we output a small form for each available and playable field:
    <div>
        <form method="POST" action="%%=RedirectTo(@url)=%%">
            <input type="hidden" name="fields" value="%%=v(Replace(@fields, @i, @playerTurn))=%%">
            <input type="hidden" name="playerTurn" value="%%=v(@nextPlayer)=%%">
            <input type="hidden" name="firstPlayer" value="%%=v(@firstPlayer)=%%">
            <input type="submit" class="f" value="%%=v(@playerTurn)=%%">
        </form>

What does this mean?

It means that we can have up to 9 forms if it’s our turn to make the first move. The four hidden fields are the core of our game – with them we can allow the game to make moves by selecting one of the fields.

Let’s consider an example of what is contained in the fields inputs when we are about to make the first move on the board:

X234567891X345678912X456789
123X567891234X678912345X789
123456X891234567X912345678X

By clicking the button, we submit the 3 values with a HTTP Post request to our page and we can again read the game state as we did already in a step before this.

Showing the Game State

<div class="results %%=v(@stateClass)=%%">
    <div>%%=v(@state)=%%</div>
</div>

This <div> uses two variables you have seen already a couple of times before:

  • @state – this is the text displayed to the player telling
    • if somebody won
    • if the game ended in a draw
    • which player moves now or what game mode this is
  • @stateClass is just the name of the CSS class that will change the background-color to the one corresponding to the winning player

Resetting the Board

<!-- Reset the board -->
<form method="POST" action="%%=RedirectTo(@url)=%%">
    <input type="submit" class="newGame" value="New Round">
    <input type="hidden" name="fields" value="123456789">
    <input type="hidden" name="playerTurn" value="%%=v(@nextPlayer)=%%">
    <input type="hidden" name="firstPlayer" value="%%=v(@firstPlayer)=%%">
</form>

When we hit the New Round button the following happens:

  • we reset the board to the default state with no field taken by any player
  • we assign who will start the game – it will be the other player from the one hitting the button
  • @firstPlayer is used to change the order