Move the APL document design to the Tic-Tac-Toe skill’s backend
In the backend of your Tic-Tac-Toe skill, there’s the CaptureMoveIntentHandler
which captures the user’s move, calculates and responds with a move by Alexa, or checks if the game has an outcome. Assuming that you name the previously defined APL document as BoardDocument.json
, you must reference it at the top of your index.js file as a const
(for example, boardDocument
).
const boardDocument = require('./documents/BoardDocument.json');
The backend of your Tic-Tac-Toe skill also contains a global object to store some data. This object contains, among other things, the status of the board in a 2D array:
var sessionAttributes = {
"boardStatus" : [[state.EMPTY,state.EMPTY,state.EMPTY],[state.EMPTY,state.EMPTY,state.EMPTY], [state.EMPTY,state.EMPTY,state.EMPTY]],
"winsUser": 0,
"winsAlexa": 0,
"levelOfDifficulty": difficulty.INTERMEDIATE,
"markAlexa": mark.O,
"markUser": mark.X
};
In your CaptureMoveIntentHandler
handler, you must check which marker (cross or circle) the user selects and map the boardStatus
property (2D array) against the right image (X or O). The following steps show the process:
Step 1. To update the board, check if the device of the user renders APL:
// Update board
if (Alexa.getSupportedInterfaces(handlerInput.requestEnvelope)['Alexa.Presentation.APL']) {
...
}
Step 2. Inside that if-statement, assign all current markers from the boardStatus
array to the image URLs depending on the user’s marker selection (X or O):
// Assign markers to image URLs
var boardDisplay = [["","","",],["","","",],["","","",]];
for (var i=0; i<3; i++) {
for (var j=0; j<3; j++) {
if (sessionAttributes.boardStatus[i][j] === state.ALEXA && sessionAttributes.markAlexa === mark.X ||
sessionAttributes.boardStatus[i][j] === state.USER && sessionAttributes.markUser === mark.X) {
boardDisplay[i][j] = "https://d3j5530a0cofat.cloudfront.net/adlc/cross.png";
}
else if (sessionAttributes.boardStatus[i][j] === state.ALEXA && sessionAttributes.markAlexa === mark.O ||
sessionAttributes.boardStatus[i][j] === state.USER && sessionAttributes.markUser === mark.O) {
boardDisplay[i][j] = "https://d3j5530a0cofat.cloudfront.net/adlc/circle.png";
}
}
}
Step 3. Implement a new directive for the boardDocument
const, and pull the image URL values for each position of the board. You saw this action performed in the data-source object in the previous section.
handlerInput.responseBuilder.addDirective({
type: 'Alexa.Presentation.APL.RenderDocument',
document: boardDocument,
datasources: {
"frameData": {
"topRow": [
{
"marker": boardDisplay[0][0]
},
{
"marker": boardDisplay[0][1]
},
{
"marker": boardDisplay[0][2]
}
],
"centerRow": [
{
"marker": boardDisplay[1][0]
},
{
"marker": boardDisplay[1][1]
},
{
"marker": boardDisplay[1][2]
}
],
"bottomRow": [
{
"marker": boardDisplay[2][0]
},
{
"marker": boardDisplay[2][1]
},
{
"marker": boardDisplay[2][2]
}
]
}
}
});
Putting all of these pieces of code together, the following example shows how the part of your backend code that updates the board should look:
// Update board
if (Alexa.getSupportedInterfaces(handlerInput.requestEnvelope)['Alexa.Presentation.APL']) {
// Assign markers to image URLs
var boardDisplay = [["","","",],["","","",],["","","",]];
for (var i=0; i<3; i++) {
for (var j=0; j<3; j++) {
if (sessionAttributes.boardStatus[i][j] === state.ALEXA && sessionAttributes.markAlexa === mark.X ||
sessionAttributes.boardStatus[i][j] === state.USER && sessionAttributes.markUser === mark.X) {
boardDisplay[i][j] = "https://d3j5530a0cofat.cloudfront.net/adlc/cross.png";
}
else if (sessionAttributes.boardStatus[i][j] === state.ALEXA && sessionAttributes.markAlexa === mark.O ||
sessionAttributes.boardStatus[i][j] === state.USER && sessionAttributes.markUser === mark.O) {
boardDisplay[i][j] = "https://d3j5530a0cofat.cloudfront.net/adlc/circle.png";
}
}
}
handlerInput.responseBuilder.addDirective({
type: 'Alexa.Presentation.APL.RenderDocument',
document: boardDocument,
datasources: {
"frameData": {
"topRow": [
{
"marker": boardDisplay[0][0]
},
{
"marker": boardDisplay[0][1]
},
{
"marker": boardDisplay[0][2]
}
],
"centerRow": [
{
"marker": boardDisplay[1][0]
},
{
"marker": boardDisplay[1][1]
},
{
"marker": boardDisplay[1][2]
}
],
"bottomRow": [
{
"marker": boardDisplay[2][0]
},
{
"marker": boardDisplay[2][1]
},
{
"marker": boardDisplay[2][2]
}
]
}
}
});
}