Rishabh Banga
Published © CC BY-NC-SA

Indian States Trivia

Test your knowledge of the states of India. Just ask Alexa to open Indian States Trivia.

IntermediateWork in progress2 hours767
Indian States Trivia

Things used in this project

Story

Read more

Code

index.js

JavaScript
'use strict';
const Alexa = require('alexa-sdk');

var APP_ID = undefined;

//This function returns a descriptive sentence about your data.  Before a user starts a quiz, they can ask about a specific data element,
//like "Delhi."  The skill will speak the sentence from this function, pulling the data values from the appropriate record in your data.
function getSpeechDescription(item)
{
  var sentence = "The capital of " + item.State_UT_Name + " is " + item.State_UT_Capital + ", and the abbreviation for " + item.State_UT_Name + " is <break strength='strong'/><say-as interpret-as='spell-out'>" + item.State_UT_Abbreviation + "</say-as>.  I've added " + item.State_UT_Name + " to your Alexa app.  Which other state or union territory would you like to know about?";
  return sentence;
}

//We have provided two ways to create your quiz questions.  The default way is to phrase all of your questions like: "What is X of Y?"
//If this approach doesn't work for your data, take a look at the commented code in this function.  You can write a different question
//structure for each property of your data.
function getQuestion(counter, property, item)
{
    return "Here is your " + counter + "th question.  What is the " + formatCasing(property) + " of "  + item.State_UT_Name + "?";

    /*
    switch(property)
    {
        case "City":
            return "Here is your " + counter + "th question.  In what city do the " + item.League + "'s "  + item.Mascot + " play?";
        break;
        case "Sport":
            return "Here is your " + counter + "th question.  What sport do the " + item.City + " " + item.Mascot + " play?";
        break;
        case "HeadCoach":
            return "Here is your " + counter + "th question.  Who is the head coach of the " + item.City + " " + item.Mascot + "?";
        break;
        default:
            return "Here is your " + counter + "th question.  What is the " + formatCasing(property) + " of the "  + item.Mascot + "?";
        break;
    }
    */
}

//This is the function that returns an answer to your user during the quiz.  Much like the "getQuestion" function above, you can use a
//switch() statement to create different responses for each property in your data.  For example, when this quiz has an answer that includes
//a state abbreviation, we add some SSML to make sure that Alexa spells that abbreviation out (instead of trying to pronounce it.)
function getAnswer(property, item)
{
    switch(property)
    {
        case "Abbreviation":
            return "The " + formatCasing(property) + " of " + item.State_UT_Name + " is <say-as interpret-as='spell-out'>" + item[property] + "</say-as>. "
        break;
        default:
            return "The " + formatCasing(property) + " of " + item.State_UT_Name + " is " + item[property] + ". "
        break;
    }
}

//This is a list of positive speechcons that this skill will use when a user gets a correct answer.  For a full list of supported
//speechcons, go here: https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/speechcon-reference
var speechConsCorrect = ["Booya", "All righty", "Bam", "Bazinga", "Bingo", "Boom", "Bravo", "Cha Ching", "Cheers", "Dynomite", 
"Hip hip hooray", "Hurrah", "Hurray", "Huzzah", "Oh dear.  Just kidding.  Hurray", "Kaboom", "Kaching", "Oh snap", "Phew", 
"Righto", "Way to go", "Well done", "Whee", "Woo hoo", "Yay", "Wowza", "Yowsa"];

//This is a list of negative speechcons that this skill will use when a user gets an incorrect answer.  For a full list of supported
//speechcons, go here: https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/speechcon-reference
var speechConsWrong = ["Argh", "Aw man", "Blarg", "Blast", "Boo", "Bummer", "Darn", "D'oh", "Dun dun dun", "Eek", "Honk", "Le sigh",
"Mamma mia", "Oh boy", "Oh dear", "Oof", "Ouch", "Ruh roh", "Shucks", "Uh oh", "Wah wah", "Whoops a daisy", "Yikes"];

//This is the welcome message for when a user starts the skill without a specific intent.
var WELCOME_MESSAGE = "Welcome to the India States Quiz Game!  You can ask me about any of the thirty-six states and union territories,  and their capitals, or you can ask me to start a quiz.  What would you like to do?";  

//This is the message a user will hear when they start a quiz.
var START_QUIZ_MESSAGE = "OK.  I will ask you 10 questions about India.";

//This is the message a user will hear when they try to cancel or stop the skill, or when they finish a quiz.
var EXIT_SKILL_MESSAGE = "Thank you for playing the India Quiz Game!  Let's play again soon!";

//This is the message a user will hear after they ask (and hear) about a specific data element.
var REPROMPT_SPEECH = "Which other state or capital would you like to know about?";

//This is the message a user will hear when they ask Alexa for help in your skill.
var HELP_MESSAGE = "I know lots of things about India.  You can ask me about a state or a capital, and I'll tell you what I know.  You can also test your knowledge by asking me to start a quiz.  What would you like to do?";


//This is the response a user will receive when they ask about something we weren't expecting.  For example, say "pizza" to your
//skill when it starts.  This is the response you will receive.
function getBadAnswer(item) { return "I'm sorry. " + item + " is not something I know very much about in this skill. " + HELP_MESSAGE; }

//This is the message a user will receive after each question of a quiz.  It reminds them of their current score.
function getCurrentScore(score, counter) { return "Your current score is " + score + " out of " + counter + ". "; }

//This is the message a user will receive after they complete a quiz.  It tells them their final score.
function getFinalScore(score, counter) { return "Your final score is " + score + " out of " + counter + ". "; }

//These next four values are for the Alexa cards that are created when a user asks about one of the data elements.
//This only happens outside of a quiz.

//If you don't want to use cards in your skill, set the USE_CARDS_FLAG to false.  If you set it to true, you will need an image for each
//item in your data.
var USE_CARDS_FLAG = true;

//This is what your card title will be.  For our example, we use the name of the state the user requested.
function getCardTitle(item) { return item.State_UT_Name;}

//This is the small version of the card image.  We use our data as the naming convention for our images so that we can dynamically
//generate the URL to the image.  The small image should be 720x400 in dimension.
function getSmallImage(item) { return "https://m.media-amazon.com/images/G/01/mobile-apps/dex/alexa/alexa-skills-kit/tutorials/quiz-game/state_flag/720x400/" + item.Abbreviation + "._TTH_.png"; }

//This is the large version of the card image.  It should be 1200x800 pixels in dimension.
function getLargeImage(item) { return "https://m.media-amazon.com/images/G/01/mobile-apps/dex/alexa/alexa-skills-kit/tutorials/quiz-game/state_flag/1200x800/" + item.Abbreviation + "._TTH_.png"; }

//=========================================================================================================================================
//TODO: Replace this data with your own.
//=========================================================================================================================================
var data = [
                {State_UT_Name: "Andaman and Nicober Islands",  State_UT_Capital: "Port Blair" , State_UT_Abbreviation: "AN"},
                {State_UT_Name: "Chandigarh",  State_UT_Capital: "Chandigarh", State_UT_Abbreviation: "CH"},
                {State_UT_Name: "Dadra and Nagar Haveli", State_UT_Capital: "Silvassa", State_UT_Abbreviation: "DN"},
                {State_UT_Name: "Daman and Diu",  State_UT_Capital: "Daman", State_UT_Abbreviation: "DD"},
                {State_UT_Name: "Delhi",  State_UT_Capital: "Delhi", State_UT_Abbreviation: "DL"},
                {State_UT_Name: "Lakshadweep",  State_UT_Capital: "Kavaratti", State_UT_Abbreviation: "LD"},
                {State_UT_Name: "Puducherry",  State_UT_Capital: "Puducherry", State_UT_Abbreviation: "PY"},
                {State_UT_Name: "Andhra Pradesh",  State_UT_Capital: "Hyderabad", State_UT_Abbreviation: "AP"},
                {State_UT_Name: "Arunachal Pradesh",  State_UT_Capital: "Itanagar", State_UT_Abbreviation: "AR"},
                {State_UT_Name: "Assam",  State_UT_Capital: "Dispur", State_UT_Abbreviation: "AS"},
                {State_UT_Name: "Bihar",  State_UT_Capital: "Patna", State_UT_Abbreviation: "BR"},
                {State_UT_Name: "Chhattisgarh",  State_UT_Capital: "Naya Raipur", State_UT_Abbreviation: "CT"},
                {State_UT_Name: "Goa",  State_UT_Capital: "Panaji", State_UT_Abbreviation: "GA"},
                {State_UT_Name: "Gujarat",  State_UT_Capital: "Gandhinagar", State_UT_Abbreviation: "GJ"},
                {State_UT_Name: "Haryana",  State_UT_Capital: "Chandigarh", State_UT_Abbreviation: "HR"},
                {State_UT_Name: "Himachal Pradesh",  State_UT_Capital: "Shimla", State_UT_Abbreviation: "HP"},
                {State_UT_Name: "Jammu and Kashmir",  State_UT_Capital: "Srinagar during Summer and Jammu during Winter", State_UT_Abbreviation: "JK"},
                {State_UT_Name: "Jharkhand",  State_UT_Capital: "Ranchi", State_UT_Abbreviation: "JH"},
                {State_UT_Name: "Karnataka",  State_UT_Capital: "Bengaluru", State_UT_Abbreviation: "KA"},
                {State_UT_Name: "Kerala",  State_UT_Capital: "Thiruvananthapuram", State_UT_Abbreviation: "KL"},
                {State_UT_Name: "Madhya Pradesh",  State_UT_Capital: "Bhopal", State_UT_Abbreviation: "MP"},
                {State_UT_Name: "Maharashtra",  State_UT_Capital: "Mumbai", State_UT_Abbreviation: "MH"},
                {State_UT_Name: "Manipur",  State_UT_Capital: "Imphal", State_UT_Abbreviation: "MN"},
                {State_UT_Name: "Meghalaya",  State_UT_Capital: "Shillong", State_UT_Abbreviation: "ML"},
                {State_UT_Name: "Mizoram",  State_UT_Capital: "Aizawl", State_UT_Abbreviation: "MZ"},
                {State_UT_Name: "Nagaland",  State_UT_Capital: "Kohima", State_UT_Abbreviation: "NL"},
                {State_UT_Name: "Odisha",  State_UT_Capital: "Bhubaneswar", State_UT_Abbreviation: "OR"},
                {State_UT_Name: "Punjab",  State_UT_Capital: "Chandigarh", State_UT_Abbreviation: "PB"},
                {State_UT_Name: "Rajasthan",  State_UT_Capital: "Jaipur", State_UT_Abbreviation: "RJ"},
                {State_UT_Name: "Sikkim",  State_UT_Capital: "Gangtok", State_UT_Abbreviation: "SK"},
                {State_UT_Name: "Tamil Nadu",  State_UT_Capital: "Chennai", State_UT_Abbreviation: "TN"},
                {State_UT_Name: "Telangana",  State_UT_Capital: "Hyderabad", State_UT_Abbreviation: "TG"},
                {State_UT_Name: "Tripura",  State_UT_Capital: "Agartala", State_UT_Abbreviation: "TR"},
                {State_UT_Name: "Uttar Pradesh",  State_UT_Capital: "Dehradun", State_UT_Abbreviation: "UP"},
                {State_UT_Name: "Uttarakhand",  State_UT_Capital: "Lucknow", State_UT_Abbreviation: "UT"},
                {State_UT_Name: "West Bengal",  State_UT_Capital: "Kolkata", State_UT_Abbreviation: "WB"}
           ];

//=========================================================================================================================================
//Editing anything below this line might break your skill.  
//=========================================================================================================================================

var counter = 0;

var states = {
    START: "_START",
    QUIZ: "_QUIZ"
};

const handlers = {
     "LaunchRequest": function() {
        this.handler.state = states.START;
        this.emitWithState("Start");
     },
    "QuizIntent": function() {
        this.handler.state = states.QUIZ;
        this.emitWithState("Quiz");
    },
    "AnswerIntent": function() {
        this.handler.state = states.START;
        this.emitWithState("AnswerIntent");
    },
    "AMAZON.HelpIntent": function() {
        this.emit(":ask", HELP_MESSAGE, HELP_MESSAGE);
    },
    "Unhandled": function() {
        this.handler.state = states.START;
        this.emitWithState("Start");
    }
};

var startHandlers = Alexa.CreateStateHandler(states.START,{
    "Start": function() {
        this.emit(":ask", WELCOME_MESSAGE, HELP_MESSAGE);
    },
    "AnswerIntent": function() {
        var item = getItem(this.event.request.intent.slots);

        if (item[Object.getOwnPropertyNames(data[0])[0]] != undefined)
        {
            if (USE_CARDS_FLAG)
            {
                var imageObj = {smallImageUrl: getSmallImage(item), largeImageUrl: getLargeImage(item)};
                this.emit(":askWithCard", getSpeechDescription(item), REPROMPT_SPEECH, getCardTitle(item), getTextDescription(item), imageObj);
            }
            else
            {
                this.emit(":ask", getSpeechDescription(item), REPROMPT_SPEECH);
            }
        }
        else
        {
            this.emit(":ask", getBadAnswer(item), getBadAnswer(item));
            
        }
    },
    "QuizIntent": function() {
        this.handler.state = states.QUIZ;
        this.emitWithState("Quiz");
    },
    "AMAZON.StopIntent": function() {
        this.emit(":tell", EXIT_SKILL_MESSAGE);
    },
    "AMAZON.CancelIntent": function() {
        this.emit(":tell", EXIT_SKILL_MESSAGE);
    },
    "AMAZON.HelpIntent": function() {
        this.emit(":ask", HELP_MESSAGE, HELP_MESSAGE);
    },
    "Unhandled": function() {
        this.emitWithState("Start");
    }
});


var quizHandlers = Alexa.CreateStateHandler(states.QUIZ,{
    "Quiz": function() {
        this.attributes["response"] = "";
        this.attributes["counter"] = 0;
        this.attributes["quizscore"] = 0;
        this.emitWithState("AskQuestion");
    },
    "AskQuestion": function() {
        if (this.attributes["counter"] == 0)
        {
            this.attributes["response"] = START_QUIZ_MESSAGE + " ";
        }

        var random = getRandom(0, data.length-1);
        var item = data[random];

        var propertyArray = Object.getOwnPropertyNames(item);
        var property = propertyArray[getRandom(1, propertyArray.length-1)];

        this.attributes["quizitem"] = item;
        this.attributes["quizproperty"] = property;
        this.attributes["counter"]++;

        var question = getQuestion(this.attributes["counter"], property, item);
        var speech = this.attributes["response"] + question;

        this.emit(":ask", speech, question);
    },
    "AnswerIntent": function() {
        var response = "";
        var item = this.attributes["quizitem"];
        var property = this.attributes["quizproperty"]

        var correct = compareSlots(this.event.request.intent.slots, item[property]);

        if (correct)
        {
            response = getSpeechCon(true);
            this.attributes["quizscore"]++;
        }
        else
        {
            response = getSpeechCon(false);
        }

        response += getAnswer(property, item);

        if (this.attributes["counter"] < 10)
        {
            response += getCurrentScore(this.attributes["quizscore"], this.attributes["counter"]);
            this.attributes["response"] = response;
            this.emitWithState("AskQuestion");
        }
        else
        {
            response += getFinalScore(this.attributes["quizscore"], this.attributes["counter"]);
            this.emit(":tell", response + " " + EXIT_SKILL_MESSAGE);
        }
    },
    "AMAZON.StartOverIntent": function() {
        this.emitWithState("Quiz");
    },
    "AMAZON.StopIntent": function() {
        this.emit(":tell", EXIT_SKILL_MESSAGE);
    },
    "AMAZON.CancelIntent": function() {
        this.emit(":tell", EXIT_SKILL_MESSAGE);
    },
    "AMAZON.HelpIntent": function() {
        this.emit(":ask", HELP_MESSAGE, HELP_MESSAGE);
    },
    "Unhandled": function() {
        this.emitWithState("AnswerIntent");
    }
});

function compareSlots(slots, value)
{
    for (var slot in slots)
    {
        if (slots[slot].value != undefined)
        {
            if (slots[slot].value.toString().toLowerCase() == value.toString().toLowerCase())
            {
                return true;
            }
        }
    }
    return false;
}

function getRandom(min, max)
{
    return Math.floor(Math.random() * (max-min+1)+min);
}

function getRandomSymbolSpeech(symbol)
{
    return "<say-as interpret-as='spell-out'>" + symbol + "</say-as>";
}

function getItem(slots)
{
    var propertyArray = Object.getOwnPropertyNames(data[0]);
    var value;
    
    for (var slot in slots)
    {
        if (slots[slot].value !== undefined)
        {
            value = slots[slot].value;
            for (var property in propertyArray)
            {
                var item = data.filter(x => x[propertyArray[property]].toString().toLowerCase() === slots[slot].value.toString().toLowerCase());
                if (item.length > 0)
                {
                    return item[0];
                }
            }
        }
    }
    return value;
}

function getSpeechCon(type)
{
    var speechCon = "";
    if (type) return "<say-as interpret-as='interjection'>" + speechConsCorrect[getRandom(0, speechConsCorrect.length-1)] + "! </say-as><break strength='strong'/>";
    else return "<say-as interpret-as='interjection'>" + speechConsWrong[getRandom(0, speechConsWrong.length-1)] + " </say-as><break strength='strong'/>";    
}

function formatCasing(key)
{
    key = key.split(/(?=[A-Z])/).join(" ");
    return key;
}

function getTextDescription(item)
{
    var text = "";
    
    for (var key in item)
    {
        text += formatCasing(key) + ": " + item[key] + "\n";
    }
    return text;
}

exports.handler = (event, context) => {
    const alexa = Alexa.handler(event, context);
    alexa.appId = APP_ID;
    alexa.registerHandlers(handlers, startHandlers, quizHandlers);
    alexa.execute();
};

Intent Schema

JSON
Used in conjunction with Custom Slots - IN_STATE_UT, IN_CITY and IN_ABBR
{
  "intents": [
    {
      "slots": [
        {
          "name": "State_UT_Name",
          "type": "IN_STATE_UT"
        },
        {
          "name": "State_UT_Capital",
          "type": "IN_CITY"
        },
        {
          "name": "State_UT_Abbreviation",
          "type": "IN_ABBR"
        }
      ],
      "intent": "AnswerIntent"
    },
    {
      "intent": "QuizIntent"
    },
    {
      "intent": "AMAZON.StopIntent"
    },
    {
      "intent": "AMAZON.CancelIntent"
    },
    {
      "intent": "AMAZON.StartOverIntent"
    },
    {
      "intent": "AMAZON.HelpIntent"
    }
  ]
}

Sample Utterances

Textile
These are what people say to interact with your skill. Type or paste in all the ways that people can invoke the intents.

Up to 3 of these will be used as Example Phrases, which are hints to users.
AnswerIntent {State_UT_Name}
AnswerIntent {State_UT_Capital}
AnswerIntent {State_UT_Abbreviation}

AnswerIntent tell me about {State_UT_Name}
AnswerIntent tell me about {State_UT_Capital}
AnswerIntent tell me about {State_UT_Abbreviation}

AnswerIntent what do you know about {State_UT_Name}
AnswerIntent what do you know about {State_UT_Capital}
AnswerIntent what do you know about {State_UT_Abbreviation}

AnswerIntent {State_UT_Name} information
AnswerIntent {State_UT_Capital} information
AnswerIntent {State_UT_Abbreviation} information

QuizIntent start a quiz
QuizIntent start a quiz game
QuizIntent and start a quiz
QuizIntent and quiz me
QuizIntent for a quiz
QuizIntent a quiz

Credits

Rishabh Banga

Rishabh Banga

12 projects • 135 followers
Intel Software Innovator | Microsoft Certified Professional | IoT Evangelist

Comments