Things used in this project

Hardware components:
Echo
Amazon Alexa Amazon Echo
×1
Software apps and online services:
Dp image kit 02
Amazon Alexa Alexa Skills Kit

Code

index.jsJavaScript
Custom language tweaks from the trivia template, including individual result messages based on your success.
/**
 Copyright 2014-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.

 Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance with the License. A copy of the License is located at

 http://aws.amazon.com/apache2.0/

 or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
 */

/**
 * This sample shows how to create a simple Trivia skill with a multiple choice format. The skill
 * supports 1 player at a time, and does not support games across sessions.
 */

'use strict';

/**
 * When editing your questions pay attention to your punctuation. Make sure you use question marks or periods.
 * Make sure the first answer is the correct one. Set at least 4 answers, any extras will be shuffled in.
 */
var questions = [
    {
        "Ragnarok": [
            "Olaf",
            "LeBlanc",
            "Caitlyn",
            "Lee Sin"
        ]
    },
    {
        "Chum the Waters": [
            "Fizz",
            "Leona",
            "Akali",
            "Hecarim"
        ]
    },
    {
        "Infinite Duress": [
            "Warwick",
            "siever",
            "Graves",
            "Gangplank"
        ]
    },
    {
        "Unstoppable Onslaught": [
            "Sion",
            "Orianna",
            "Vladimir",
            "Garen"
        ]
    },
    {
        "Depth Charge": [
            "Nautilus",
            "Fiora",
            "reneckton",
            "noonoo"
        ]
    },
    {
        "Glacial Storm": [
            
            "Anivia"
        ]
    },
    {
        "Upgrade": [
            "Heimerdinger",
            "seh jew awni",
            "Kassadin",
            "Viktor"
        ]
    },
    {
        "Diplomatic Immunity": [
            
            "Poppy"
        ]
    },
    {
        "On the Hunt": [
            "siever",
            "Ezreal",
            "Ziggs",
            "Skarner"
        ]
    },
    {
        "Spider Form": [
            "Elise",
            "Zac",
            "Amumu",
            "Wukong"
        ]
    },
    {
        "Death Mark": [
            "Zed",
            "Ahri",
            "Aurelion Sol",
            "Kog'Maw"
        ]
    },
    {
        "Hallucinate": [
            "Shaco",
            "Bard",
            "cuhlista",
            "Lissandra"
        ]
    },
    {
        "Cataclysm": [
            "Jarvan the Fourth",
            "ren gahr",
            "jahnna",
            "Karthus"
        ]
    },
    {
        "Super Mega Death Rocket!": [
            "Jinx",
            "gahlio",
            "Talon",
            "Warwick"
        ]
    },
    {
        "Agony's Embrace": [
            "ehvelynn",
            "Fizz",
            "Karma",
            "Blitzcrank"
        ]
    },
    {
        "Summon: Tibbers": [
            "Annie",
            "Teemo",
            "Singed",
            "Jarvan the Fourth"
        ]
    },
    {
        "Massacre": [
            "a a trox",
            "Annie",
            "Heimerdinger",
            "Maokai"
        ]
    },
    {
        "Transcendant Blades": [
            "Irelia",
            "Jhin",
            "Taric",
            "Tahm Kench"
        ]
    },
    {
        "Stand United": [
            "Shen",
            "Jax",
            "Dr. Mundo",
            "Twisted Fate"
        ]
    },
    {
        "Curse of the Sad Mummy": [
            "Amumu",
            "Shaco",
            "Veigar",
            "Shen"
        ]
    },
    {
        "Thrill of the Hunt": [
            "ren gahr",
            "Braum",
            "tryndumere",
            "Xerath"
        ]
    },
    {
        "Fate's Call": [
            "cuhlista",
            "Master Yi",
            "oohdeer",
            "a a trox"
        ]
    },
    {
        "Hemoplague": [
            "Vladimir",
            "Brand",
            "Zilean",
            "Cassiopeia"
        ]
    },
    {
        "Chaos Storm": [
            "Viktor",
            "Swain",
            "Yorick",
            "Vayne"
        ]
    },
    {
        "Tempered Fate": [
            "Bard",
            "kha zix",
            "Rammus",
            "Thresh"
        ]
    },
    {
        "Hyper-Kinetic Position Reverser": [
            "ur got",
            "Sona",
            "Kindred",
            "Fiddlesticks"
        ]
    },
    {
        "Sadism": [
            "Dr. Mundo",
            "Ryze",
            "Kayle",
            "Zed"
        ]
    },
    {
        "Children of the Grave": [
            "Mordekaiser",
            "Varus",
            "Pantheon",
            "Morgana"
        ]
    },
    {
        "Mimic": [
            "LeBlanc",
            "cho gath",
            "Diana",
            "Nami"
        ]
    },
    {
        "Glacial Fissue": [
            "Braum",
            "Jayce",
            "Draven",
            "Gnar"
        ]
    },
    {
        "Undying Rage": [
            "tryndumere",
            "Malzahar",
            "Trundle",
            "Vi"
        ]
    },
    {
        "Bullet Time": [
            "Miss Fortune",
            "Soraka",
            "Yasuo",
            "Quinn"
        ]
    },
    {
        "Vengeful Maelstrom": [
            "Maokai",
            "Jinx",
            "Malphite",
            "Sion"
        ]
    },
    {
        "Cyclone": [
            "Wukong",
            "wrecksai",
            "Katarina",
            "Nocturne"
        ]
    },
    {
        "Aspect of the Cougar": [
            "nid alee",
            "Zyra",
            "Poppy",
            "Shyvana"
        ]
    },
    {
        "Shadow Assault": [
            "Talon",
            "Lux",
            "ur got",
            "Xin Zhao"
        ]
    },
    {
        "Static Field": [
            "Blitzcrank",
            "Corki",
            "nid alee",
            "Mordekaiser"
        ]
    },
    {
        "Unbreakable Will": [
            "Alistar",
            "Lulu",
            "Irelia",
            "Ashe"
        ]
    },
    {
        "Soul Shackles": [
            "Morgana",
            "Kennen",
            "Tristana",
            "Lucian"
        ]
    },
    {
        "Ravenous Flock": [
            "Swain",
            "nah suss",
            "Ekko",
            "Nautilus"
        ]
    },
    {
        "Idol of Durand": [
            "gahlio",
            "Anivia",
            "Gragas",
            "ehvelynn"
        ]
    },
    {
        "Wish": [
            "Soraka",
            "Miss Fortune",
            "Olaf",
            "Riven"
        ]
    },
    {
        "Desperate Power": [
            "Ryze",
            "Elise",
            "Alistar",
            "Syndra"
        ]
    },
    {
        "Dragon's Rage": [
            "Lee Sin",
            "Rumble",
            "Azir",
            "vel cause"
        ]
    },
    {
        "Ace in the Hole": [
            "Caitlyn",
            "Swain",
            "Master Yi",
            "Kog'Maw"
        ]
    },
    {
        "Tremors": [
            "Rammus",
            "Heimerdinger",
            "Soraka",
            "Cassiopeia"
        ]
    },
    {
        "Omen of Death": [
            "Yorick",
            "Xerath",
            "Syndra",
            "vel cause"
        ]
    },
    {
        "Collateral Damage": [
            "Graves",
            "Fizz",
            "Shyvana",
            "Thresh"
        ]
    },
    {
        "Transform: Mercury Cannon": [
            "Jayce",
            "Gnar",
            "Sion",
            "Yasuo"
        ]
    },
    {
        "The Culling": [
            "Lucian",
            "Kindred",
            "Nautilus",
            "Jayce"
        ]
    },
    {
        "Lifeform Disintegration Ray": [
            "vel cause",
            "cho gath",
            "Nocturne",
            "Bard"
        ]
    },
    {
        "Grand Skyfall": [
            "Pantheon",
            "nah suss",
            "Irelia",
            "cuhlista"
        ]
    },
    {
        "Thunder Claws": [
            "Volibear",
            "Orianna",
            "ur got",
            "Varus"
        ]
    },
    {
        "Missile Barrage": [
            "Corki",
            "Zyra",
            "Gragas",
            "LeBlanc"
        ]
    },
    {
        "Final Spark": [
            "Lux",
            "Garen",
            "Olaf",
            "Kennen"
        ]
    },
    {
        "Primordial Burst": [
            "Veigar",
            "Talon",
            "Karthus",
            "kha zix"
        ]
    },
    {
        "Subjugate": [
            "Trundle",
            "Elise",
            "oohdeer",
            "Lucian"
        ]
    },
    {
        "Riftwalk": [
            "Kassadin",
            "Caitlyn",
            "ren gahr",
            "Aurelion Sol"
        ]
    },
    {
        "Highlander": [
            "Master Yi",
            "tryndumere",
            "Miss Fortune",
            "Vayne"
        ]
    },
    {
        "Impale": [
            "Skarner",
            "Zac",
            "siever",
            "Jhin"
        ]
    },
    {
        "Chronoshift": [
            "Zilean",
            "Nami",
            "Shen",
            "nid alee"
        ]
    },
    {
        "Curtain Call": [
            "Jhin",
            "Brand",
            "Jinx",
            "noonoo"
        ]
    },
    {
        "Slicing Maelstrom": [
            "Kennen",
            "Malzahar",
            "Malphite",
            "Ezreal"
        ]
    },
    {
        "Lamb's Respite": [
            "Kindred",
            "gahlio",
            "Teemo",
            "Trundle"
        ]
    },
    {
        "Dragon's Descent": [
            "Shyvana",
            "Twisted Fate",
            "Kassadin",
            "Twitch"
        ]
    },
    {
        "Solar Flare": [
            "Leona",
            "Karma",
            "Skarner",
            "Mordekaiser"
        ]
    },
    {
        "Requiem": [
            "Karthus",
            "Veigar",
            "Katarina",
            "seh jew awni"
        ]
    },
    {
        "Assault and Battery": [
            "Vi",
            "Lulu",
            "Annie",
            "Ahri"
        ]
    },
    {
        "Grandmaster's Might": [
            "Jax",
            "Morgana",
            "Corki",
            "Lee Sin"
        ]
    },
    {
        "Crescendo": [
            "Sona",
            "Gangplank",
            "Jax",
            "Taric"
        ]
    },
    {
        "Final Hour": [
            "Vayne",
            "Braum",
            "Jarvan the Fourth",
            "Vi"
        ]
    },
    {
        "Demacian Justice": [
            "Garen",
            "Kayle",
            "Rumble",
            "Rammus"
        ]
    },
    {
        "Gnar!": [
            "Gnar",
            "Amumu",
            "ehvelynn",
            "Darius"
        ]
    },
    {
        "Tag Team": [
            "Quinn",
            "Tahm Kench",
            "Akali",
            "Shaco"
        ]
    },
    {
        "Nether Grasp": [
            "Malzahar",
            "Azir",
            "Xin Zhao",
            "jahnna"
        ]
    },
    {
        "Noxious Trap": [
            "Teemo",
            "Wukong",
            "Draven",
            "Yorick"
        ]
    },
    {
        "Frozen Tomb": [
            "Lissandra",
            "wrecksai",
            "Graves",
            "Fiddlesticks"
        ]
    },
    {
        "Abyssal Voyage": [
            "Tahm Kench",
            "Tristana",
            "reneckton",
            "Blitzcrank"
        ]
    },
    {
        "Void Rush": [
            "wrecksai",
            "Pantheon",
            "Vladimir",
            "Riven"
        ]
    },
    {
        "Unleashed Power": [
            "Syndra",
            "Lissandra",
            "a a trox",
            "Zilean"
        ]
    },
    {
        "Arcane Barrage": [
            "Xerath",
            "Ryze",
            "Dr. Mundo",
            "Maokai"
        ]
    },
    {
        "Glacial Prison": [
            "seh jew awni",
            "Singed",
            "Leona",
            "Volibear"
        ]
    },
    {
        "Shadow Dance": [
            "Akali",
            "Fiora",
            "Alistar",
            "Hecarim"
        ]
    },
    {
        "Spirit Rush": [
            "Ahri",
            "Zed",
            "Ashe",
            "Anivia"
        ]
    },
    {
        "Phoenix Stance": [
            "oohdeer",
            "Diana",
            "Sona",
            "Ziggs"
        ]
    },
    {
        "Chain of Corruption": [
            "Varus",
            "Ekko",
            "Viktor",
            "Poppy"
        ]
    },
    {
        "The Equalizer": [
            "Rumble",
            "Lux",
            "Quinn",
            "Warwick"
        ]
    },
    {
        "Let's Bounce!": [
            "Zac",
            "Fizz",
            "Olaf",
            "Pantheon"
        ]
    },
    {
        "Emperor's Divide": [
            "Azir",
            "Cassiopeia",
            "Thresh",
            "Caitlyn"
        ]
    },
    {
        "Dominus": [
            "reneckton",
            "Syndra",
            "Karthus",
            "Wukong"
        ]
    },
    {
        "Explosive Cask": [
            "Gragas",
            "Nautilus",
            "Quinn",
            "nid alee"
        ]
    },
    {
        "Rat-Ta-Tat-Tat": [
            "Twitch",
            "Ahri",
            "Jinx",
            "Yasuo"
        ]
    },
    {
        "Death Lotus": [
            "Katarina",
            "Jarvan the Fourth",
            "Akali",
            "Yorick"
        ]
    },
    {
        "The Box": [
            "Thresh",
            "Gangplank",
            "kha zix",
            "siever"
        ]
    },
    {
        "Command: Shockwave": [
            "Orianna",
            "LeBlanc",
            "Amumu",
            "Trundle"
        ]
    },
    {
        "Unstoppable Force": [
            "Malphite",
            "Draven",
            "ehvelynn",
            "Warwick"
        ]
    },
    {
        "Crescent Sweep": [
            "Xin Zhao",
            "vel cause",
            "Sion",
            "Taric"
        ]
    },
    {
        "Fury of the Sands": [
            "nah suss",
            "Kennen",
            "Teemo",
            "Kassadin"
        ]
    },
    {
        "Intervention": [
            "Kayle",
            "Gnar",
            "Irelia",
            "Xin Zhao"
        ]
    },
    {
        "Noxian Guillotine": [
            "Darius",
            "Tahm Kench",
            "Shaco",
            "Soraka"
        ]
    },
    {
        "Feast": [
            "cho gath",
            "Katarina",
            "Viktor",
            "Leona"
        ]
    },
    {
        "Chronobreak": [
            "Ekko",
            "Lulu",
            "Lee Sin",
            "Kog'Maw"
        ]
    },
    {
        "Blade of the Exile": [
            "Riven",
            "Corki",
            "Poppy",
            "Garen"
        ]
    },
    {
        "Grand Challenge": [
            "Fiora",
            "Miss Fortune",
            "Sona",
            "Orianna"
        ]
    },
    {
        "Monsoon": [
            "jahnna",
            "Graves",
            "Talon",
            "Rumble"
        ]
    },
    {
        "Tidal Wave": [
            "Nami",
            "reneckton",
            "Twitch",
            "Vladimir"
        ]
    },
    {
        "Trueshot Barrage": [
            "Ezreal",
            "Elise",
            "Riven",
            "nah suss"
        ]
    },
    {
        "Mega Inferno Bomb": [
            "Ziggs",
            "Diana",
            "wrecksai",
            "Zed"
        ]
    },
    {
        "Wild Growth": [
            "Lulu",
            "Jhin",
            "Kayle",
            "Dr. Mundo"
        ]
    },
    {
        "Paranoia": [
            "Nocturne",
            "Bard",
            "Ryze",
            "Fiddlesticks"
        ]
    },
    {
        "Radiance": [
            "Taric",
            "Ezreal",
            "Darius",
            "seh jew awni"
        ]
    },
    {
        "Insanity Potion": [
            "Singed",
            "cuhlista",
            "Shyvana",
            "Twisted Fate"
        ]
    },
    {
        "Whirling Death": [
            "Draven",
            "Jayce",
            "oohdeer",
            "Maokai"
        ]
    },
    {
        "Last Breath": [
            "Yasuo",
            "tryndumere",
            "Annie",
            "Shen"
        ]
    },
    {
        "Crowstorm": [
            "Fiddlesticks",
            "Ziggs",
            "Azir",
            "Brand"
        ]
    },
    {
        "Cannon Barrage": [
            "Gangplank",
            "Zac",
            "noonoo",
            "Swain"
        ]
    },
    {
        "Buster Shot": [
            "Tristana",
            "Nocturne",
            "Heimerdinger",
            "Mordekaiser"
        ]
    },
    {
        "Enchanted Crystal Arrow": [
            "Ashe",
            "Skarner",
            "Master Yi",
            "Aurelion Sol"
        ]
    },
    {
        "Onslaught of Shadows": [
            "Hecarim",
            "Karma",
            "Rammus",
            "Tristana"
        ]
    },
    {
        "Voice of Light": [
            "Aurelion Sol",
            "Fiora",
            "Kindred",
            "Lissandra"
        ]
    },
    {
        "Void Assault": [
            "kha zix",
            "Malzahar",
            "Lux",
            "Vi"
        ]
    },
    {
        "Living Artillery": [
            "Kog'Maw",
            "Malphite",
            "Singed",
            "jahnna"
        ]
    },
    {
        "Mantra": [
            "Karma",
            "gahlio",
            "Anivia",
            "Veigar"
        ]
    },
    {
        "Stranglethorns": [
            "Zyra",
            "Varus",
            "Blitzcrank",
            "Zilean"
        ]
    },
    {
        "Destiny": [
            "Twisted Fate",
            "Zyra",
            "Jax",
            "Nami"
        ]
    },
    {
        "Petrifying Gaze": [
            "Cassiopeia",
            "Ashe",
            "Volibear",
            "a a trox"
        ]
    },
    {
        "Lunar Rush": [
            "Diana",
            "Ekko",
            "Braum",
            "Vayne"
        ]
    },
    {
        "Pyroclasm": [
            "Brand",
            "Lucian",
            "Xerath",
            "Gragas"
        ]
    },
    {
        "Absolute Zero": [
            "noonoo",
            "Morgana",
            "Hecarim",
            "ur got"
        ]
    }
];

// Route the incoming request based on type (LaunchRequest, IntentRequest,
// etc.) The JSON body of the request is provided in the event parameter.
exports.handler = function (event, context) {
    try {
        console.log("event.session.application.applicationId=" + event.session.application.applicationId);

        /**
         * Uncomment this if statement and populate with your skill's application ID to
         * prevent someone else from configuring a skill that sends requests to this function.
         */

     if (event.session.application.applicationId !== "amzn1.echo-sdk-ams.app.d923812e-8c0f-49dc-8a36-a1fc2b44ddb5") {
         context.fail("Invalid Application ID");
      }

        if (event.session.new) {
            onSessionStarted({requestId: event.request.requestId}, event.session);
        }

        if (event.request.type === "LaunchRequest") {
            onLaunch(event.request,
                event.session,
                function callback(sessionAttributes, speechletResponse) {
                    context.succeed(buildResponse(sessionAttributes, speechletResponse));
                });
        } else if (event.request.type === "IntentRequest") {
            onIntent(event.request,
                event.session,
                function callback(sessionAttributes, speechletResponse) {
                    context.succeed(buildResponse(sessionAttributes, speechletResponse));
                });
        } else if (event.request.type === "SessionEndedRequest") {
            onSessionEnded(event.request, event.session);
            context.succeed();
        }
    } catch (e) {
        context.fail("Exception: " + e);
    }
};

/**
 * Called when the session starts.
 */
function onSessionStarted(sessionStartedRequest, session) {
    console.log("onSessionStarted requestId=" + sessionStartedRequest.requestId
        + ", sessionId=" + session.sessionId);

    // add any session init logic here
}

/**
 * Called when the user invokes the skill without specifying what they want.
 */
function onLaunch(launchRequest, session, callback) {
    console.log("onLaunch requestId=" + launchRequest.requestId
        + ", sessionId=" + session.sessionId);

    getWelcomeResponse(callback);
}

/**
 * Called when the user specifies an intent for this skill.
 */
function onIntent(intentRequest, session, callback) {
    console.log("onIntent requestId=" + intentRequest.requestId
        + ", sessionId=" + session.sessionId);

    var intent = intentRequest.intent,
        intentName = intentRequest.intent.name;

    // handle yes/no intent after the user has been prompted
    if (session.attributes && session.attributes.userPromptedToContinue) {
        delete session.attributes.userPromptedToContinue;
        if ("AMAZON.NoIntent" === intentName) {
            handleFinishSessionRequest(intent, session, callback);
        } else if ("AMAZON.YesIntent" === intentName) {
            handleRepeatRequest(intent, session, callback);
        }
    }

    // dispatch custom intents to handlers here
    if ("AnswerIntent" === intentName) {
        handleAnswerRequest(intent, session, callback);
    } else if ("AnswerOnlyIntent" === intentName) {
        handleAnswerRequest(intent, session, callback);
    } else if ("DontKnowIntent" === intentName) {
        handleAnswerRequest(intent, session, callback);
    } else if ("AMAZON.YesIntent" === intentName) {
        handleAnswerRequest(intent, session, callback);
    } else if ("AMAZON.NoIntent" === intentName) {
        handleAnswerRequest(intent, session, callback);
    } else if ("AMAZON.StartOverIntent" === intentName) {
        getWelcomeResponse(callback);
    } else if ("AMAZON.RepeatIntent" === intentName) {
        handleRepeatRequest(intent, session, callback);
    } else if ("AMAZON.HelpIntent" === intentName) {
        handleGetHelpRequest(intent, session, callback);
    } else if ("AMAZON.StopIntent" === intentName) {
        handleFinishSessionRequest(intent, session, callback);
    } else if ("AMAZON.CancelIntent" === intentName) {
        handleFinishSessionRequest(intent, session, callback);
    } else {
        throw "Invalid intent";
    }
}

/**
 * Called when the user ends the session.
 * Is not called when the skill returns shouldEndSession=true.
 */
function onSessionEnded(sessionEndedRequest, session) {
    console.log("onSessionEnded requestId=" + sessionEndedRequest.requestId
        + ", sessionId=" + session.sessionId);

    // Add any cleanup logic here
}

// ------- Skill specific business logic -------

var ANSWER_COUNT = 4;
var GAME_LENGTH = 5;
var CARD_TITLE = "League Ability Trivia";

function getWelcomeResponse(callback) {
    var sessionAttributes = {},
        speechOutput = "Welcome to League Ability Trivia, summoner. You'll guess the champion for " + GAME_LENGTH.toString()
            + " different abilities. Just say the number of the answer.",
        shouldEndSession = false,

        gameQuestions = populateGameQuestions(),
        correctAnswerIndex = Math.floor(Math.random() * (ANSWER_COUNT)), // Generate a random index for the correct answer, from 0 to 3
        roundAnswers = populateRoundAnswers(gameQuestions, 0, correctAnswerIndex),

        currentQuestionIndex = 0,
        spokenQuestion = Object.keys(questions[gameQuestions[currentQuestionIndex]])[0],
        repromptText = "Ability 1. " + spokenQuestion + " ",

        i, j;

    for (i = 0; i < ANSWER_COUNT; i++) {
        repromptText += (i+1).toString() + ". " + roundAnswers[i] + ". "
    }
    speechOutput += repromptText;
    sessionAttributes = {
        "speechOutput": repromptText,
        "repromptText": repromptText,
        "currentQuestionIndex": currentQuestionIndex,
        "correctAnswerIndex": correctAnswerIndex + 1,
        "questions": gameQuestions,
        "score": 0,
        "correctAnswerText":
            questions[gameQuestions[currentQuestionIndex]][Object.keys(questions[gameQuestions[currentQuestionIndex]])[0]][0]
    };
    callback(sessionAttributes,
        buildSpeechletResponse(CARD_TITLE, speechOutput, repromptText, shouldEndSession));
}

function populateGameQuestions() {
    var gameQuestions = [];
    var indexList = [];
    var index = questions.length;

    if (GAME_LENGTH > index){
        throw "Invalid Game Length.";
    }

    for (var i = 0; i < questions.length; i++){
        indexList.push(i);
    }

    // Pick GAME_LENGTH random questions from the list to ask the user, make sure there are no repeats.
    for (var j = 0; j < GAME_LENGTH; j++){
        var rand = Math.floor(Math.random() * index);
        index -= 1;

        var temp = indexList[index];
        indexList[index] = indexList[rand];
        indexList[rand] = temp;
        gameQuestions.push(indexList[index]);
    }

    return gameQuestions;
}

function populateRoundAnswers(gameQuestionIndexes, correctAnswerIndex, correctAnswerTargetLocation) {
    // Get the answers for a given question, and place the correct answer at the spot marked by the
    // correctAnswerTargetLocation variable. Note that you can have as many answers as you want but
    // only ANSWER_COUNT will be selected.
    var answers = [],
        answersCopy = questions[gameQuestionIndexes[correctAnswerIndex]][Object.keys(questions[gameQuestionIndexes[correctAnswerIndex]])[0]],
        temp, i;

    var index = answersCopy.length;

    if (index < ANSWER_COUNT){
        throw "Not enough answers for question.";
    }

    // Shuffle the answers, excluding the first element.
    for (var j = 1; j < answersCopy.length; j++){
        var rand = Math.floor(Math.random() * (index - 1)) + 1;
        index -= 1;

        var temp = answersCopy[index];
        answersCopy[index] = answersCopy[rand];
        answersCopy[rand] = temp;
    }

    // Swap the correct answer into the target location
    for (i = 0; i < ANSWER_COUNT; i++) {
        answers[i] = answersCopy[i];
    }
    temp = answers[0];
    answers[0] = answers[correctAnswerTargetLocation];
    answers[correctAnswerTargetLocation] = temp;
    return answers;
}

function handleAnswerRequest(intent, session, callback) {
    var speechOutput = "";
    var sessionAttributes = {};
    var gameInProgress = session.attributes && session.attributes.questions;
    var answerSlotValid = isAnswerSlotValid(intent);
    var userGaveUp = intent.name === "DontKnowIntent";

    if (!gameInProgress) {
        // If the user responded with an answer but there is no game in progress, ask the user
        // if they want to start a new game. Set a flag to track that we've prompted the user.
        sessionAttributes.userPromptedToContinue = true;
        speechOutput = "There is no game in progress. Do you want to start a new game? ";
        callback(sessionAttributes,
            buildSpeechletResponse(CARD_TITLE, speechOutput, speechOutput, false));
    } else if (!answerSlotValid && !userGaveUp) {
        // If the user provided answer isn't a number > 0 and < ANSWER_COUNT,
        // return an error message to the user. Remember to guide the user into providing correct values.
        var reprompt = session.attributes.speechOutput;
        var speechOutput = "Your answer must be a number between 1 and " + ANSWER_COUNT + ". " + reprompt;
        callback(session.attributes,
            buildSpeechletResponse(CARD_TITLE, speechOutput, reprompt, false));
    } else {
        var gameQuestions = session.attributes.questions,
            correctAnswerIndex = parseInt(session.attributes.correctAnswerIndex),
            currentScore = parseInt(session.attributes.score),
            currentQuestionIndex = parseInt(session.attributes.currentQuestionIndex),
            correctAnswerText = session.attributes.correctAnswerText;

        var speechOutputAnalysis = "";

        if (answerSlotValid && parseInt(intent.slots.Answer.value) == correctAnswerIndex) {
            currentScore++;
            speechOutputAnalysis = "correct. ";
        } else {
            if (!userGaveUp) {
                speechOutputAnalysis = "wrong. "
            }
            speechOutputAnalysis += "The correct champion is " + correctAnswerIndex + ": " + correctAnswerText + ". ";
        }
        // if currentQuestionIndex is 4, we've reached 5 questions (zero-indexed) and can exit the game session
        if (currentQuestionIndex == GAME_LENGTH - 1) {
            speechOutput = userGaveUp ? "" : "That champion is ";
            speechOutput += speechOutputAnalysis + "You finished the game ";
            if (currentScore.toString() == 0) {
                speechOutput += "without a single kill. Better luck next time, summoner.";
            }
            else if (currentScore.toString() == 1) {
                speechOutput += "with a single kill. I'm sure you can do better, summoner.";
            }
            else if (currentScore.toString() == 2) {
                speechOutput += "with a double kill. Your support would be proud.";
            }
            else if (currentScore.toString() == 3) {
                speechOutput += "with a triple kill. Way to clean up!";
            }
            else if (currentScore.toString() == 4) {
                speechOutput += "with a quadra kill. So close. Go for the penta!";
            }
            else if (currentScore.toString() == 5) {
                speechOutput += "with a penta kill. You're going to hit challenger in no time!";
            }
            callback(session.attributes,
                buildSpeechletResponse(CARD_TITLE, speechOutput, "", true));
        } else {
            currentQuestionIndex += 1;
            var spokenQuestion = Object.keys(questions[gameQuestions[currentQuestionIndex]])[0];
            // Generate a random index for the correct answer, from 0 to 3
            correctAnswerIndex = Math.floor(Math.random() * (ANSWER_COUNT));
            var roundAnswers = populateRoundAnswers(gameQuestions, currentQuestionIndex, correctAnswerIndex),

                questionIndexForSpeech = currentQuestionIndex + 1,
                repromptText = "Ability " + questionIndexForSpeech.toString() + ". " + spokenQuestion + " ";
            for (var i = 0; i < ANSWER_COUNT; i++) {
                repromptText += (i+1).toString() + ". " + roundAnswers[i] + ". "
            }
            speechOutput += userGaveUp ? "" : "That champion is ";
            speechOutput += speechOutputAnalysis + "Your score is " + currentScore.toString() + ". " + repromptText;

            sessionAttributes = {
                "speechOutput": repromptText,
                "repromptText": repromptText,
                "currentQuestionIndex": currentQuestionIndex,
                "correctAnswerIndex": correctAnswerIndex + 1,
                "questions": gameQuestions,
                "score": currentScore,
                "correctAnswerText":
                    questions[gameQuestions[currentQuestionIndex]][Object.keys(questions[gameQuestions[currentQuestionIndex]])[0]][0]
            };
            callback(sessionAttributes,
                buildSpeechletResponse(CARD_TITLE, speechOutput, repromptText, false));
        }
    }
}

function handleRepeatRequest(intent, session, callback) {
    // Repeat the previous speechOutput and repromptText from the session attributes if available
    // else start a new game session
    if (!session.attributes || !session.attributes.speechOutput) {
        getWelcomeResponse(callback);
    } else {
        callback(session.attributes,
            buildSpeechletResponseWithoutCard(session.attributes.speechOutput, session.attributes.repromptText, false));
    }
}

function handleGetHelpRequest(intent, session, callback) {
    // Provide a help prompt for the user, explaining how the game is played. Then, continue the game
    // if there is one in progress, or provide the option to start another one.

    // Set a flag to track that we're in the Help state.
    session.attributes.userPromptedToContinue = true;

    // Do not edit the help dialogue. This has been created by the Alexa team to demonstrate best practices.

    var speechOutput = "I will name " + GAME_LENGTH + " abilities. Respond with the number of the correct champion. "
        + "For example, say one, two, three, or four. To start a new game at any time, say, start game. "
        + "To repeat the last question, say, repeat. "
        + "Would you like to keep playing?",
        repromptText = "To give an answer to a question, respond with the number of the answer . "
        + "Would you like to keep playing?";
        var shouldEndSession = false;
    callback(session.attributes,
        buildSpeechletResponseWithoutCard(speechOutput, repromptText, shouldEndSession));
}

function handleFinishSessionRequest(intent, session, callback) {
    // End the session with a "Good bye!" if the user wants to quit the game
    callback(session.attributes,
        buildSpeechletResponseWithoutCard("Good bye!", "", true));
}

function isAnswerSlotValid(intent) {
    var answerSlotFilled = intent.slots && intent.slots.Answer && intent.slots.Answer.value;
    var answerSlotIsInt = answerSlotFilled && !isNaN(parseInt(intent.slots.Answer.value));
    return answerSlotIsInt && parseInt(intent.slots.Answer.value) < (ANSWER_COUNT + 1) && parseInt(intent.slots.Answer.value) > 0;
}

// ------- Helper functions to build responses -------


function buildSpeechletResponse(title, output, repromptText, shouldEndSession) {
    return {
        outputSpeech: {
            type: "PlainText",
            text: output
        },
        card: {
            type: "Simple",
            title: title,
            content: output
        },
        reprompt: {
            outputSpeech: {
                type: "PlainText",
                text: repromptText
            }
        },
        shouldEndSession: shouldEndSession
    };
}

function buildSpeechletResponseWithoutCard(output, repromptText, shouldEndSession) {
    return {
        outputSpeech: {
            type: "PlainText",
            text: output
        },
        reprompt: {
            outputSpeech: {
                type: "PlainText",
                text: repromptText
            }
        },
        shouldEndSession: shouldEndSession
    };
}

function buildResponse(sessionAttributes, speechletResponse) {
    return {
        version: "1.0",
        sessionAttributes: sessionAttributes,
        response: speechletResponse
    };
}

Credits

B4464179fc4a51373e1c38b21fd0a576
Steven Li
1 project • 0 followers
Contact

Replications

Did you replicate this project? Share it!

I made one

Love this project? Think it could be improved? Tell us what you think!

Give feedback

Comments

Sign up / LoginProjectsPlatformsTopicsContestsLiveAppsBetaBlog