Md. Khairul Alam
Published © GPL3+

Word's Largest and Smallest

Alexa based quiz game about world's largest and smallest facts.

EasyProtip1 hour276

Things used in this project

Hardware components

Amazon Echo
Amazon Alexa Amazon Echo
×1

Software apps and online services

Alexa Skills Kit
Amazon Alexa Alexa Skills Kit
AWS Lambda
Amazon Web Services AWS Lambda

Story

Read more

Code

Utterances

Tex
AnswerIntent the answer is {Answer}
AnswerIntent my answer is {Answer}
AnswerIntent is it {Answer}
AnswerIntent {Answer} is my answer
AnswerIntent correct is my answer {Answer}
AnswerIntent I know it is {Answer}
AnswerIntent {Answer} is the correct answer
AnswerIntent definitely it is {Answer}
AnswerOnlyIntent {Answer}

 

AMAZON.StartOverIntent start game
AMAZON.StartOverIntent start new quiz
AMAZON.StartOverIntent new game
AMAZON.StartOverIntent new quiz
AMAZON.StartOverIntent start
AMAZON.StartOverIntent start new game

 

DontKnowIntent i don't know
DontKnowIntent i don't know the right answer
DontKnowIntent don't know
DontKnowIntent skip
DontKnowIntent go next
DontKnowIntent ask me next question
DontKnowIntent i don't know that
DontKnowIntent who knows
DontKnowIntent i don't know this question
DontKnowIntent i don't know that one
DontKnowIntent dunno

Lambda function

JavaScript
/**
 * 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 = [
    {
        "Which is the Largest Airport of the World?": [
			"King Fahd International Airport",
			"Denver International Airport",
			"Shanghai Pudong International Airport",
			"Hartsfield Jackson Atlanta International"
        ]
    },
    {
        "Which is the Highest Airport of the World?": [
			"Daocheng Yading Airport, China",
			"Qamdo Bamda Airport, China",
			"El Alto International Airport, Bolivia",
			"San Luis Airport, Colombia"
        ]
    },
    {
        "What is the Tallest Animal of the world?": [
			"Giraffes",
			"Brown Bear",
			"African Bush Elephant",
			"Polar Bear "
        ]
    },
    {
        "What is the Largest Animal of the world?": [
			"Blue Whale",
			"African Bush Elephant",
			"Elephant seal",
			"Saltwater crocodile"
        ]
    },
	{
        "What is the Largest Reptile of the world?": [
			"Saltwater Crocodile",
			"Chinese giant salamander",
			"South American anaconda",
			"Gharial"
        ]
    },
	{
        "What is the Largest Bird of the world?": [
			"Ostrich",
			"Southern cassowary",
			"Emu",
			"Emperor penguin"
        ]
    },
	 {
        "What is the Largest Land Animal of the world?": [
			"African elephant",
			"Brown bear",
			"White rhinoceros",
			"Water buffalo"
        ]
    },
    {
        "Which is the largest bay of the world?": [
			"Bay of Bengal",
			"Bay of Flags",
			"Magdalena Bay",
			"Hudson Bay"
        ]
    },
    {
        "Which is the Fastest Bird on Earth?": [
			"Peregrine falcon",
			"Golden eagle",
			"Swift",
			"Frigatebird"
        ]
    },
    {
        "Which is the Largest Snake?": [
			"Green anaconda",
			"Burmese python",
			"Yellow anaconda",
			"Indian python"
        ]
    },
    {
        "Which is the Smallest Bird?": [
			"Bee hummingbird",
			"Weebill ",
			"Goldcrest",
			"American Goldfinch"
        ]
    },
    {
        "Which is the Longest Bridge in the world?": [
			"Danyang–Kunshan Grand Bridge, China",
			"Changhua-Kaohsiung Viaduct, Taiwan",
			"Beijing Grand Bridge",
			"Manchac Swamp Bridge"
        ]
    },
    {
        "Which is the Tallest Building of world?": [
			"Burj Khalifa",
			"Tokyo Skytree",
			"432 Park Avenue",
			"Petronas Twin Towers"
        ]
    },
    {
        "Which is the Longest Canal of the world?": [
			"Grand Canal, China",
			"Qaraqum Canal, Russia",
			"Eurasia Canal, Russia",
			"Suez Canal, Egypt"
        ]
    },
    {
        "Which is the Largest Cemetry of the world?": [
			"Wadi Al-Salam",
			"Calverton National Cemetery",
			"Abraham Lincoln National Cemetery",
			"Rookwood Cemetery"
        ]
    },
    {
        "Which is the Largest Church of the world?": [
			"St. Peter's Basilica",
			"First Family Church",
			"Milan Cathedral",
			"Hagia Sophia"
        ]
    },
    {
        "Which are the Largest Continent?": [
			"Asia",
			"Africa",
			"North America",
			"South America"
        ]
    },
    {
        "Which is the largest Country by Area?": [
			"Russia",
			"Canada",
			"United States of America",
			"China"
        ]
    },
    {
        "Which is Smallest Country by Area?": [
			"Vatican City",
			"Monaco",
			"Nauru",
			"Tuvalu"
        ]
    },
    {
        "Which is the Highest City of the world?": [
			"La Rinconada, Peru",
			"Tuiwa, Tibet",
			"Amdo, Tibet",
			"Mina Pirquitas"
        ]
    },
    {
        "Which are the Most populous Cities of the world (population and density?": [
			"Shanghai",
			"Karachi",
			"Delhi",
			"Dhaka"
        ]
    },
	{
        "Which is the largest desert of the world?": [
			"Antarctica",
			"Arctic",
			"Sahara",
			"Arabian Desert"
        ]
    },
    {
        "Which coutry has the Largest Army?": [
			"China",
			"United States",
			"India",
			"Pakistan"
        ]
    },
    {
        "Which is the Largest Island?": [
			"Greenland",
			"New Guinea",
			"Baffin Island",
			"South Island"
        ]
    },
	{
        "Which is the Highest Mountain?": [
			"Mount Everest",
			"K2",
			"Nanga Parbat",
			"Ngadi Chuli"
        ]
    },
	{
        "Which is World’s Highest Waterfall?": [
			"Angel Falls",
			"Tugela Falls",
			"Yumbilla Falls",
			"Browne Falls"
        ]
    },
    {
        "Which is the Largest Library of the world?": [
			"British Library",
			"Library of Congress",
			"New York Public Library",
			"Library and Archives Canada"
        ]
    },
    {
        "Which is the Largest Mosque of World?": [
			"Masjid al-Haram",
			"Al-Masjid al-Nabawi",
			"Moscow Cathedral Mosque",
			"Al Fateh Mosque"
        ]
    },
    {
        "Which is the Largest Museum in the world?": [
			"Louvre",
			"State Hermitage Museum",
			"Vatican Museums",
			"Tokyo National Museum"
        ]
    },
    {
        "Which is Largest Ocean of the world?": [
			"The Pacific Ocean",
			"The Atlantic Ocean",
			"The Indian Ocean",
			"The Southern Ocean"
        ]
    },
    {
        "Which is the Biggest Palace?": [
			"Palace of the Parliament",
			"Hofburg Palace",
			"Louvre Palace",
			"Forbidden City"
        ]
    },
	{
        "Which is the Longest River?": [
			"Nile – Kagera",
			"Amazon",
			"Congo",
			"Niger"
        ]
    },
    {
        "Which is the Largest Dam on river?": [
			"Tarbela Dam",
			"Fort Peck Dam",
			"Atatürk Dam",
			"Mangla Dam"
        ]
    },
    {
        "Which is the Largest Sea on Earth?": [
			"The South China Sea",
			"The Caribbean Sea",
			"The Mediterranean Sea",
			"The Bearing Sea"
        ]
    },
	{
        "Which is the largest Stadium by capacity?": [
			"Rungrado 1st of May Stadium",
			"Michigan Stadium",
			"Beaver Stadium",
			"Tiger Stadium"
        ]
    },
    {
        "Which is the Longest Epic?": [
			"Mahabharata",
			"Faramarz Nama",
			"Book of Dede Korkut",
			"Ramayana"
        ]
    }
];

// 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.ask.skill.d48fc4cf-e8e2-4bab-a999-d951f34dafa5") {
            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;  // 4 options
var GAME_LENGTH = 10;  //ask 10 questions
var CARD_TITLE = "Capitals and Countries"; // Be sure to change this for your skill.

function getWelcomeResponse(callback) {
    var sessionAttributes = {},
        speechOutput = "World leargest and smallest. I will ask you " + GAME_LENGTH.toString()
            + " questions, try to get as many right as you can. Just say the number of the answer. Let's begin. ",
        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 = "Question 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 = "Do you want to start a new quiz? ";
        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 answer 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 answer is ";
            speechOutput += speechOutputAnalysis + "You got " + currentScore.toString() + " out of "
                + GAME_LENGTH.toString() + " questions correct. Thank you for playing!";
            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 = "Question " + questionIndexForSpeech.toString() + ". " + spokenQuestion + " ";
            for (var i = 0; i < ANSWER_COUNT; i++) {
                repromptText += (i+1).toString() + ". " + roundAnswers[i] + ". "
            }
            speechOutput += userGaveUp ? "" : "That answer 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 ask you " + GAME_LENGTH + " multiple choice questions. Respond with the number of the answer. "
        + "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
    };
}

Intent Schema

JSON
{

  "intents": [

    {

      "intent": "AnswerIntent",

      "slots": [

        {

          "name": "Answer",

          "type": "LIST_OF_ANSWERS"

        }

      ]

    },

    {

      "intent": "AnswerOnlyIntent",

      "slots": [

        {

          "name": "Answer",

          "type": "LIST_OF_ANSWERS"

        }

      ]

    },

    {

      "intent": "DontKnowIntent"

    },

    {

      "intent": "AMAZON.StartOverIntent"

    },

    {

      "intent": "AMAZON.RepeatIntent"

    },

    {

      "intent": "AMAZON.HelpIntent"

    },

    {

      "intent": "AMAZON.YesIntent"

    },

    {

      "intent": "AMAZON.NoIntent"

    },

    {

      "intent": "AMAZON.StopIntent"

    },

    {

      "intent": "AMAZON.CancelIntent"

    }

  ]

}

LIST_OF_ANSWERS

Plain text
1
2
3
4

Credits

Md. Khairul Alam

Md. Khairul Alam

30 projects • 293 followers
Engineer, developer, maker, and hacker.

Comments

Add projectSign up / Login