Software apps and online services | ||||||
| ||||||
| ||||||
| ||||||
|
Amazon Alexa is an amazing voice controlled interactive service which can be used to build fun and interactive games. We wanted to make a great game which not only is fun to play with, but also increases knowledge at the same time. And so we came up with UK Treasure Hunt. Learn Geography and interesting facts about many cities of United Kingdom while finding your treasure.This interesting treasure game can be enjoyed by all age groups and can be played individually or with family or friends together.
In UK Treasure Hunt, you need to follow the treasure trail across various UK Cities and find the treasure before the time runs out. You get clues to determine your next city in the trail and based on that, you need to decide your trail. Any incorrect answer will throw you off the trail!
Ahoy Treasure Hunters, welcome aboard! Hope you enjoy the game!
The Game PitchYou have stumbled upon a treasure map in your attic. No wait, in fact, it's a collection of loads of treasure maps for a number of lost and hidden treasures across the whole of United Kingdom..!
And now, you are on a mission. To find the treasures, follow the trail and be a treasure trail blazer! Embark on a journey across the UK moving from one city to another as per the trail and find the lost treasure!
But there is a glitch, like there always is, in all good things in life! The treasure maps only points you to the starting location. And from there, you are on your own. But worry not, to find your treasure, there are the good guys across the world, the helpers we call them, who will guide you on your trail.
But they do not make your task as easy as it seems. They only talk cryptic and provide you with clues which point you to your next destination. It's your decision to identify the next location. And moreover, they may also show you some Pictures of the place to help you identify it easily! But, beware... Make a wrong guess and the trail may go cold and the treasure will be lost forever.
In fact, there is another glitch. As soon as you start the trail, the bad guys get a sniff of what you are upto and they try to find the treasure themselves. So, you need to find the treasure fast, under the stipulated time, to prevent the treasure falling in the hands of the wrong guys!
And as you collect more and more treasures, you move up the level to become a treasure trail blazer!
On the trail now, Treasure Hunter...!
How To PlayWhen you start the game, you are at the start location as per the Treasure Map and you need to find the treasure in 2 days.Time flies as you ask for help or fly to the next destination on the treasure trail.
You have the option to Ask up to 3 Helpers for clues to deduce your next location. You can guess the location by asking 1 Helper or you may need to ask all 3.. If you are asking more helpers, remember, that you are losing your precious time!
Alexa will ask you, if you want to further ask for help or fly to next destination. If you say, Fly to next Destination, you are given 4 options , i.e. cities. Based on the clues you have got, you decide your next location. Make a wrong decision, and you will lose the trail and you will have to go back.
When you arrive at your Next Location in the trail, the game logic will determine the next steps:
* If you have reached the Treasure, you Win and move up on next level!
* If you have exceeded the time limit, you Lose!
* And if this is just another city in your trail, you get the option to ask for Clues to determine your next location.
At any point of time during game play, say, Alexa, Help. And Alexa will assist you as to what needs to be done next!
ArchitectureUK Treasure Hunt is an Amazon Alexa Skill build using the Alexa-SDK. The backend is a Node.JS function hosted on AWS Lambda. The app uses Amazon DynamoDB to store the session attributes so that user has a seamless experience in playing the game. The entire game is built using State Models, to drive the user in the right manner so that he can earn his treasure...! To make the game more interesting and interactive, we have used Speechcons provided by Alexa Skill Kit.
To provide the Picture Hints to user, to deduce the City, Flickr Public API are used.
How to BuildThere are multiple tutorials and developer docs available to build Alexa skill using Node.JS, hosted on AWS Lamdba.
Please follow this link to setup the skill in Amazon Developer Console.
1. Setting up Alexa Skill
From the guide, follow Step 1. Set up Your Alexa Skill in the Developer Portal of this guide. Intent Schema and Sample Utterances for the skill are provided in the code section below.
2. Seting up AWS Lambda
From the guide, follow Step 2. Create Your Skill Logic Using AWS Lambda of this guide. The index.js and package.json are given at the code section below to setup the Lambda zip file. Refer to Alexa Skills Kit SDK for Node.js for details.
3. Setup the Constant.js
This file contains the keys for your application. Change the values of the below keys:
1. App Id
2. Flickr API Key
3. Flickr API Secret
4.Linking Lambda to skill
From the guide, follow Step 3. Add Your Lambda Function to Your Skill.
5. Test the skill
From the guide, follow Step 4. Test Your Skill based on the steps mentioned in the guide.
VUI DiagramPlease enable the skill from this location on Amazon Echo Skill Store.
{
"name": "UKTreasureHunt",
"version": "1.0.0",
"description": "UKTreasureHunt.",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [
"alexa",
"skill",
"UK Treasure Hunt"
],
"author": "Khyati",
"license": "Apache-2.0",
"dependencies": {
"alexa-sdk": "^1.0.9",
"flickrapi": "^0.6.0",
"moment": "^2.18.1"
}
}
"use strict";
var questions = require("./questions");
var constants = require('./constants');
var gamelogic = require('./gamelogic');
var moment = require('moment');
var flickrObj = null;
var Flickr = require("flickrapi"),
flickrOptions = {
api_key: constants.apiKey,
secret: constants.apiSecret,
user_id: constants.userId,
requestOptions: {
timeout: 2000,
/* other default options accepted by request.defaults */
}
};
Flickr.tokenOnly(flickrOptions, function (error, flickr) {
flickrObj = flickr;
});
var languageString = {
"en": {
"translation": {
"GAME_NAME": "U.K. Treasure Hunt", // Be sure to change this for your skill.
"HELP_MESSAGE": "I will ask you %s 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. ",
"REPEAT_QUESTION_MESSAGE": "To repeat the last question, say, repeat. ",
"ASK_MESSAGE_START": "Would you like to start playing?",
"HELP_REPROMPT": "To give an answer to a question, respond with the number of the answer. ",
"STOP_MESSAGE": "Are you sure you want to stop the trail?",
"CANCEL_MESSAGE": "Okies, We will hunt the treasure some other time. <say-as interpret-as='interjection'>ta ta</say-as>.",
"NO_MESSAGE": "Ok, we\'ll play another time. Goodbye!",
"TRIVIA_UNHANDLED": "Try saying a number between 1 and %s",
"HELP_UNHANDLrighED": "Say yes to continue, or no to end the game.",
"START_UNHANDLED": "Say start to start a new treasure trail.",
"NEW_GAME_MESSAGE": "<say-as interpret-as='interjection'>Ahoy</say-as>, %s. Welcome to %s. ",
"WELCOME_MESSAGE": "Find precious lost treasures from across the U.K.! " +
"Find your treasure before stipulated time. Here is your first trail. ",
"NEXT_TRAIL_MESSAGE": "Here is your next trail. ",
"ANSWER_CORRECT_MESSAGE": "correct. ",
"ANSWER_WRONG_MESSAGE": "wrong. ",
"CORRECT_ANSWER_MESSAGE": "The correct answer is %s: %s. ",
"ANSWER_IS_MESSAGE": "That answer is ",
"TELL_QUESTION_MESSAGE": "Question %s. %s ",
"GAME_OVER_MESSAGE": "You got %s out of %s questions correct. Thank you for playing!",
"SCORE_IS_MESSAGE": "Your score is %s. ",
"UNHANDLED_CLUE": "Sorry, I did not get that. You need to select one of the three helpers to get your clue. ",
"UNHANDLED_DECIDE": "Sorry, I did not get that.",
"UNHANDLED_FLY": "Sorry, that's not a valid destination.",
"DECIDE_PROMPT": "Alright, then, %s. Now, do you wish to Ask for Clue further or Fly to Next Destination?",
"DECIDE_REPROMPT": "Please say Ask to ask for further Clues or say, Fly to look for destinations?",
"START_MESSAGE": "Your current location is %s. And your treasure trail will lead you to %s. Right now, it is %s and " +
"You have 2 days to fetch your treasure. Find your next destination by asking for clues. You can ask %s, %s or %s. Whom do you wish to ask?",
"ASK_MESSAGE": "Right now, It is %s. " +
"You can ask %s, %s or %s. Whom do you wish to ask?",
"ASK_UNHANDLED_MESSAGE":
"You can ask %s, %s or %s. Whom do you wish to ask?",
"ASK_UNHANDLED_MESSAGE_PROMPT":
"For example, You can say, Please ask %s. Whom do you wish to ask?",
"FLY_MESSAGE": "You have the option to fly to %s. " +
" Where to next, %s?",
"NEW_DEST_MESSAGE": "<say-as interpret-as='interjection'>tick-tock. tick-tock. tick-tock.</say-as>You have arrived. Welcome to %s and right now, it is %s. Now, do you wish to Ask for Clue further or Fly to Next Destination?",
"HELP_START" : "Help asked, and here it is. U.K. Treasure Hunt is a game where you need to follow the trail across cities of U.K. At each stage, you will get the help of three helpers whom you can ask for clues. The clue will point to your next destination and then, you need to choose that destination out of the provided options and fly there. Again ask for clues for next destination, and so on until you reach the treasure. You need to reach the treasure in a stipulated time and so, make sure you do not reach to an incorrect City or spend time asking for more clues! Happy Treasure Hunting!",
"HELP_DECIDE" : "Help asked, and here it is. At any stage of the game, you can either ask helpers for clues or fly to your next destination. You can ask upto three helpers for clues, which will point you to your next destination. So, to ask for clues, Please say, I want to ask. And to fly to your next destination, Please say, I want to fly.",
"HELP_FLY" : "Help asked, and here it is. Once you have asked Helpers for clues, you will have to deduce which city those clues point to. You can then fly to that city to continue your trail. You will get option of three to four cities and out of those select the one where the clues lead to. For example, to fly to America, please say, Fly to America.",
"HELP_CLUE" : "Help asked, and here it is. To complete your trail, you need to identify your next location. To help you do that, you can ask upto three helpers for clues. You may figure out the location based on one clue or you can ask other helpers as well. For example, to ask banker for clue, Please say, Ask Banker.",
}
}
};
var Alexa = require("alexa-sdk");
exports.handler = function(event, context, callback) {
var alexa = Alexa.handler(event, context);
alexa.appId = constants.appId;
alexa.resources = languageString;
alexa.dynamoDBTableName = constants.dynamoDBTableName;
alexa.registerHandlers(newSessionHandlers, startStateHandlers
, clueStateHandlers, flyStateHandlers, decideStateHandlers
, helpStateHandlers
);
alexa.execute();
};
var newSessionHandlers = {
'NewSession': function () {
console.log('New Sessioon 1');
var that = this;
if (Object.keys(this.attributes).length === 0) {
console.log('New Session');
this.attributes['level'] = 'Treasure Hunter';
this.attributes['trail'] = [];
this.attributes['history'] = [];
this.attributes['score'] = 0;
this.attributes['newuser'] = 0;
}
that.handler.state = constants.states.START_MODE;
that.emitWithState("StartGame", true);
// result is Flickr's response
},
"LaunchIntent": function () {
console.log('Launch Req 1');
if (Object.keys(this.attributes).length === 0) {
console.log('New Session');
this.attributes['level'] = 'Treasure Hunter';
this.attributes['trail'] = [];
this.attributes['history'] = [];
this.attributes['score'] = 0;
this.attributes['newuser'] = 0;
}
this.handler.state = constants.states.START_MODE;
this.emitWithState("StartGame", true);
},
"LaunchRequest": function () {
console.log('Launch Req 1');
if (Object.keys(this.attributes).length === 0) {
console.log('New Session');
this.attributes['level'] = 'Treasure Hunter';
this.attributes['trail'] = [];
this.attributes['history'] = [];
this.attributes['score'] = 0;
this.attributes['newuser'] = 0;
}
this.handler.state = constants.states.START_MODE;
this.emitWithState("StartGame", true);
},
"AMAZON.StartOverIntent": function () {
this.handler.state = constants.states.START_MODE;
this.emitWithState("StartGame", true);
},
"AMAZON.HelpIntent": function() {
this.handler.state = constants.states.HELP_MODE;
this.emitWithState("helpTheUser", constants.states.START_MODE);
},
"Unhandled": function () {
var speechOutput = this.t("START_UNHANDLED");
this.emit(":ask", speechOutput, speechOutput);
}
};
var startStateHandlers = Alexa.CreateStateHandler(constants.states.START_MODE, {
"StartGame": function (newGame) {
console.log('Start Mode: Start Game');
var speechOutput = newGame ? this.t("NEW_GAME_MESSAGE", this.attributes['level'], this.t("GAME_NAME")) : "";
if (this.attributes['newuser'] == 0)
{
speechOutput += this.t("WELCOME_MESSAGE");
}
else
{
speechOutput += this.t("NEXT_TRAIL_MESSAGE");
}
var currentCountry = gamelogic.getStartCountry();
var currentTime = moment();
var data = questions.data;
var helper = questions.helper;
var endTime = moment();
endTime.add(2, 'd');
var trail = gamelogic.buildTreasureTrail(currentCountry);
var treasure = getRandomTreasure();
var repromptText = this.t("START_MESSAGE", data[currentCountry].country, treasure,
currentTime.format("Do MMMM h A"), helper[trail[0].helper[0]].helper,
helper[trail[0].helper[1]].helper, helper[trail[0].helper[2]].helper);
speechOutput += repromptText;
Object.assign(this.attributes, {
"speechOutput": repromptText,
"repromptText": repromptText,
"currentCountry": currentCountry,
"currentTime": currentTime,
"currentStep": 0,
"rightStep": 0,
"newuser": 1,
"trail": trail,
"treasure": treasure,
"endTime": endTime,
"startCountry": currentCountry,
"currentState": constants.states.CLUE_MODE,
"isRightTrack": true
});
this.handler.state = constants.states.CLUE_MODE;
this.emit(":askWithCard", speechOutput, repromptText, this.t("GAME_NAME"), getCardString(repromptText));
},
"LaunchIntent": function () {
console.log('Launch Req start');
if (Object.keys(this.attributes).length === 0) {
console.log('New Session');
this.attributes['level'] = 'Treasure Hunter';
this.attributes['trail'] = [];
this.attributes['history'] = [];
this.attributes['score'] = 0;
this.attributes['newuser'] = 0;
}
this.handler.state = constants.states.START_MODE;
this.emitWithState("StartGame", true);
},
"LaunchRequest": function () {
console.log('Launch Req start');
if (Object.keys(this.attributes).length === 0) {
console.log('New Session');
this.attributes['level'] = 'Treasure Hunter';
this.attributes['trail'] = [];
this.attributes['history'] = [];
this.attributes['score'] = 0;
this.attributes['newuser'] = 0;
}
this.handler.state = constants.states.START_MODE;
this.emitWithState("StartGame", true);
},
"AMAZON.HelpIntent": function() {
this.handler.state = constants.states.HELP_MODE;
this.emitWithState("helpTheUser", constants.states.START_MODE);
}
});
var clueStateHandlers = Alexa.CreateStateHandler(constants.states.CLUE_MODE, {
"AskIntent": function () {
Object.assign(this.attributes, {
"askedCancel": false
});
handleUserClue.call(this);
},
"LaunchIntent": function () {
console.log('Launch CLue 1');
if (Object.keys(this.attributes).length === 0) {
console.log('New Session');
this.attributes['level'] = 'Treasure Hunter';
this.attributes['trail'] = [];
this.attributes['history'] = [];
this.attributes['score'] = 0;
this.attributes['newuser'] = 0;
}
this.handler.state = constants.states.START_MODE;
this.emitWithState("StartGame", true);
},
"LaunchRequest": function () {
console.log('Launch CLue 1');
if (Object.keys(this.attributes).length === 0) {
console.log('New Session');
this.attributes['level'] = 'Treasure Hunter';
this.attributes['trail'] = [];
this.attributes['history'] = [];
this.attributes['score'] = 0;
this.attributes['newuser'] = 0;
}
this.handler.state = constants.states.START_MODE;
this.emitWithState("StartGame", true);
},
"AMAZON.StartOverIntent": function () {
Object.assign(this.attributes, {
"askedCancel": false
});
this.handler.state = constants.states.START_MODE;
this.emitWithState("StartGame", false);
},
"AMAZON.RepeatIntent": function () {
Object.assign(this.attributes, {
"askedCancel": false
});
this.emit(":ask", this.attributes["speechOutput"], this.attributes["repromptText"]);
},
"AMAZON.HelpIntent": function () {
Object.assign(this.attributes, {
"askedCancel": false
});
this.handler.state = constants.states.HELP_MODE;
this.emitWithState("helpTheUser", constants.states.CLUE_MODE);
},
"AMAZON.NoIntent": function() {
Object.assign(this.attributes, {
"askedCancel": false
});
if (this.attributes["speechOutput"] && this.attributes["repromptText"]) {
this.emitWithState("AMAZON.RepeatIntent");
} else {
this.handler.state = constants.states.START_MODE;
this.emitWithState("StartGame", false);
}
},
"AMAZON.CancelIntent": function () {
this.handler.state = constants.states.START_MODE;
this.emit(":tell", this.t("CANCEL_MESSAGE"));
},
"AMAZON.YesIntent": function () {
if(this.attributes['askedCancel'])
{
var speechOutput = this.t("CANCEL_MESSAGE");
this.handler.state = constants.states.START_MODE;
this.emit(":tell", speechOutput);
}
else
{
this.emitWithState("Unhandled");
}
},
"AMAZON.StopIntent": function () {
Object.assign(this.attributes, {
"askedCancel": true
});
var speechOutput = this.t("STOP_MESSAGE");
this.emit(":ask", speechOutput, speechOutput);
},
"Unhandled": function () {
Object.assign(this.attributes, {
"askedCancel": false
});
var data = questions.data;
var helper = questions.helper;
var currentStep = this.attributes['currentStep'];
var trail = this.attributes['trail'];
var currentCountry = this.attributes['currentCountry'];
var currentTime = moment(this.attributes['currentTime']);
var speechText = this.t("UNHANDLED_CLUE") + this.t("ASK_UNHANDLED_MESSAGE",
helper[trail[0].helper[0]].helper,
helper[trail[0].helper[1]].helper, helper[trail[0].helper[2]].helper);
var repromptText = this.t("ASK_UNHANDLED_MESSAGE_PROMPT",
helper[trail[0].helper[0]].helper);
Object.assign(this.attributes, {
"speechOutput": speechText,
"repromptText": repromptText
});
this.emit(":askWithCard", speechText, repromptText, this.t("GAME_NAME"), getCardString(speechText));
},
"SessionEndedRequest": function () {
this.handler.state = constants.states.START_MODE;
this.emit(':saveState', true);
console.log("Session ended in trivia state: " + this.event.request.reason);
}
});
function handleUserClue() {
var answerSlotValid = isHelperSlotValid(this.event.request.intent);
if(!answerSlotValid)
{
this.emitWithState("Unhandled");
return;
}
else
{
var currentTime = moment(this.attributes['currentTime']);
currentTime.add(2, 'h');
Object.assign(this.attributes, {
"currentTime": currentTime
});
//check if gameover
if (checkIfGameOver.call(this))
{
var repromptText = getTimeOutText.call(this);
repromptText = repromptText.clue.replace('%s', currentTime.format("Do MMMM h A"));
this.emit(":tellWithCard", repromptText, repromptText, this.t("GAME_NAME"), getCardString(repromptText));
return;
}
// check if back
var thisNote = this.event.request.intent.slots.Helper.value.toLowerCase().trim();
thisNote = thisNote.replace(/[^a-zA-Z]/gi, '');
if (thisNote === 'back') {
this.handler.state = constants.states.DECIDE_MODE;
var speechOutput = this.t("DECIDE_PROMPT", this.attributes['level']);
var repromptText = this.t("DECIDE_REPROMPT");
Object.assign(this.attributes, {
"speechOutput": speechOutput,
"repromptText": repromptText
});
this.emit(":askWithCard", speechOutput, repromptText, this.t("GAME_NAME"), getCardString(repromptText));
return;
}
else
{
var currentStep = this.attributes['currentStep'];
var rightStep = this.attributes['rightStep'];
var clue = '';
if (currentStep == rightStep)
clue = getHelperClue.call(this, this.event.request.intent);
else
clue = getIncorrectClue.call(this).clue;
var helperNAme = getHelper.call(this, this.event.request.intent);
console.log('Clue: ' + clue);
if(clue !== '')
{
this.handler.state = constants.states.DECIDE_MODE;
var speechOutput = 'The ' + helperNAme + ' says, ' + clue + '. ' + this.t("DECIDE_PROMPT", this.attributes['level']);
var repromptText = this.t("DECIDE_REPROMPT");
Object.assign(this.attributes, {
"speechOutput": speechOutput,
"repromptText": repromptText
});
var that = this;
var trivia = this.attributes['trail'];
var country = trivia[this.attributes['currentStep']].country;
var randPage = getRandomNumber(0, 5);
var randPerPage = getRandomNumber(0, 30);
Flickr.tokenOnly(flickrOptions, function (error, flickr) {
// we can now use "flickr" as our API object,
// but we can only call public methods and access public data
console.log("Token Recd: " + questions.data[country].country);
flickr.photos.search({
tags: questions.data[country].country,
extras: "url_l", //"url_l,license,owner_name",
licenses: "0,7",
safe_search: 1,
//is_commons: true,
page: randPage,
per_page: randPerPage
}, function (err, result) {
console.log('Err: ' + err);
var photo = "";
if (!err) {
try {
var l = result.photos.photo.length;
if (l > 0)
{
var randNo = getRandomNumber(0, l);
console.log(randNo);
photo = result.photos.photo[randNo].url_l;
console.log(photo);
}
}
catch(e)
{
photo = "";
}
}
if (photo !== "")
that.emit(":askWithCard", speechOutput, repromptText, that.t("GAME_NAME"), getCardString(speechOutput),
{ largeImageUrl: photo, smallImageUrl: photo });
else
that.emit(":askWithCard", speechOutput, repromptText, that.t("GAME_NAME"), getCardString(speechOutput));
});
});
}
else
{
this.emitWithState("Unhandled");
}
}
}
}
var decideStateHandlers = Alexa.CreateStateHandler(constants.states.DECIDE_MODE, {
"DecideIntent": function () {
Object.assign(this.attributes, {
"askedCancel": false
});
handleUserDecide.call(this);
},
"LaunchIntent": function () {
console.log('Launch Decide 1');
if (Object.keys(this.attributes).length === 0) {
console.log('New Session');
this.attributes['level'] = 'Treasure Hunter';
this.attributes['trail'] = [];
this.attributes['history'] = [];
this.attributes['score'] = 0;
this.attributes['newuser'] = 0;
}
this.handler.state = constants.states.START_MODE;
this.emitWithState("StartGame", true);
},
"LaunchRequest": function () {
console.log('Launch Decide 1');
if (Object.keys(this.attributes).length === 0) {
console.log('New Session');
this.attributes['level'] = 'Treasure Hunter';
this.attributes['trail'] = [];
this.attributes['history'] = [];
this.attributes['score'] = 0;
this.attributes['newuser'] = 0;
}
this.handler.state = constants.states.START_MODE;
this.emitWithState("StartGame", true);
},
"AMAZON.StartOverIntent": function () {
Object.assign(this.attributes, {
"askedCancel": false
});
this.handler.state = constants.states.START_MODE;
this.emitWithState("StartGame", false);
},
"AMAZON.RepeatIntent": function () {
Object.assign(this.attributes, {
"askedCancel": false
});
this.emit(":ask", this.attributes["speechOutput"], this.attributes["repromptText"]);
},
"AMAZON.HelpIntent": function () {
Object.assign(this.attributes, {
"askedCancel": false
});
this.handler.state = constants.states.HELP_MODE;
this.emitWithState("helpTheUser", constants.states.DECIDE_MODE);
},
"AMAZON.NoIntent": function () {
Object.assign(this.attributes, {
"askedCancel": false
});
if (this.attributes["speechOutput"] && this.attributes["repromptText"]) {
this.emitWithState("AMAZON.RepeatIntent");
} else {
this.handler.state = constants.states.START_MODE;
this.emitWithState("StartGame", false);
}
},
"AMAZON.CancelIntent": function () {
this.handler.state = constants.states.START_MODE;
this.emit(":tell", this.t("CANCEL_MESSAGE"));
},
"AMAZON.YesIntent": function () {
if(this.attributes['askedCancel'])
{
var speechOutput = this.t("CANCEL_MESSAGE");
this.handler.state = constants.states.START_MODE;
this.emit(":tell", speechOutput);
}
else
{
this.emitWithState("Unhandled");
}
},
"AMAZON.StopIntent": function () {
Object.assign(this.attributes, {
"askedCancel": true
});
var speechOutput = this.t("STOP_MESSAGE");
this.emit(":ask", speechOutput, speechOutput);
},
"Unhandled": function () {
Object.assign(this.attributes, {
"askedCancel": false
});
this.emit(":ask", this.t("UNHANDLED_DECIDE") + ' ' + this.attributes["repromptText"], this.attributes["repromptText"]);
},
"SessionEndedRequest": function () {
this.emit(':saveState', true);
console.log("Session ended in trivia state: " + this.event.request.reason);
}
});
function handleUserDecide() {
var answerSlotValid = isDecideSlotValid(this.event.request.intent);
console.log('Ans: ' + answerSlotValid);
if (answerSlotValid === '') {
this.emitWithState("Unhandled");
return;
}
else {
if(answerSlotValid == 'fly')
{
this.handler.state = constants.states.FLY_MODE;
var data = questions.data;
// generate list of countries and ask user
var sh = [];
var currentStep = this.attributes['currentStep'];
var rightStep = this.attributes['rightStep'];
if (currentStep == rightStep)
sh = getCountryList.call(this);
else
sh = getCountryListIncorrect.call(this);
var cntName = '';
for (var x = 0 ; x < sh.length ; x++) {
var n = data[sh[x]].country;
cntName += n;
if (x == sh.length - 1)
cntName += '';
else if (x == sh.length - 2)
cntName += ' or ';
else
cntName += ', ';
}
console.log('--------=========-----------');
console.log(JSON.stringify(cntName));
var repromptText = this.t("FLY_MESSAGE", cntName, this.attributes['level']);
Object.assign(this.attributes, {
"speechOutput": repromptText,
"repromptText": repromptText,
"flyOptions": sh
});
this.emit(":askWithCard", repromptText, repromptText, this.t("GAME_NAME"), getCardString(repromptText));
}
else if(answerSlotValid == 'ask')
{
this.handler.state = constants.states.CLUE_MODE;
// get list of current helpers and send
var data = questions.data;
var helper = questions.helper;
var currentStep = this.attributes['currentStep'];
var trail = this.attributes['trail'];
var currentCountry = this.attributes['currentCountry'];
var currentTime = moment(this.attributes['currentTime']);
var repromptText = this.t("ASK_MESSAGE",
currentTime.format("Do MMMM h A"), helper[trail[currentStep].helper[0]].helper,
helper[trail[currentStep].helper[1]].helper, helper[trail[currentStep].helper[2]].helper);
Object.assign(this.attributes, {
"speechOutput": repromptText,
"repromptText": repromptText
});
this.emit(":askWithCard", repromptText, repromptText, this.t("GAME_NAME"), getCardString(repromptText));
}
}
}
var flyStateHandlers = Alexa.CreateStateHandler(constants.states.FLY_MODE, {
"FlyIntent": function () {
console.log('FlyIntent');
Object.assign(this.attributes, {
"askedCancel": false
});
handleUserFly.call(this);
},
"LaunchIntent": function () {
console.log('Launch Fly 1');
if (Object.keys(this.attributes).length === 0) {
console.log('New Session');
this.attributes['level'] = 'Treasure Hunter';
this.attributes['trail'] = [];
this.attributes['history'] = [];
this.attributes['score'] = 0;
this.attributes['newuser'] = 0;
}
this.handler.state = constants.states.START_MODE;
this.emitWithState("StartGame", true);
},
"LaunchRequest": function () {
console.log('Launch Fly 1');
if (Object.keys(this.attributes).length === 0) {
console.log('New Session');
this.attributes['level'] = 'Treasure Hunter';
this.attributes['trail'] = [];
this.attributes['history'] = [];
this.attributes['score'] = 0;
this.attributes['newuser'] = 0;
}
this.handler.state = constants.states.START_MODE;
this.emitWithState("StartGame", true);
},
"AMAZON.StartOverIntent": function () {
Object.assign(this.attributes, {
"askedCancel": false
});
this.handler.state = constants.states.START_MODE;
this.emitWithState("StartGame", false);
},
"AMAZON.RepeatIntent": function () {
Object.assign(this.attributes, {
"askedCancel": false
});
this.emit(":ask", this.attributes["speechOutput"], this.attributes["repromptText"]);
},
"AMAZON.HelpIntent": function () {
Object.assign(this.attributes, {
"askedCancel": false
});
this.handler.state = constants.states.HELP_MODE;
this.emitWithState("helpTheUser", constants.states.DECIDE_MODE);
},
"AMAZON.NoIntent": function () {
Object.assign(this.attributes, {
"askedCancel": false
});
if (this.attributes["speechOutput"] && this.attributes["repromptText"]) {
this.emitWithState("AMAZON.RepeatIntent");
} else {
this.handler.state = constants.states.START_MODE;
this.emitWithState("StartGame", false);
}
},
"AMAZON.CancelIntent": function () {
this.handler.state = constants.states.START_MODE;
this.emit(":tell", this.t("CANCEL_MESSAGE"));
},
"AMAZON.YesIntent": function () {
if(this.attributes['askedCancel'])
{
var speechOutput = this.t("CANCEL_MESSAGE");
this.handler.state = constants.states.START_MODE;
this.emit(":tell", speechOutput);
}
else
{
this.emitWithState("Unhandled");
}
},
"AMAZON.StopIntent": function () {
Object.assign(this.attributes, {
"askedCancel": true
});
var speechOutput = this.t("STOP_MESSAGE");
this.emit(":ask", speechOutput, speechOutput);
},
"Unhandled": function () {
Object.assign(this.attributes, {
"askedCancel": false
});
console.log('UnahnIntent');
this.emit(":ask", this.t("UNHANDLED_FLY") + ' ' + this.attributes["repromptText"], this.attributes["repromptText"]);
},
"SessionEndedRequest": function () {
this.emit(':saveState', true);
console.log("Session ended in trivia state: " + this.event.request.reason);
}
});
function handleUserFly() {
var answerSlotValid = isDestinationSlotValid.call(this, this.event.request.intent);
console.log('>>> ' + answerSlotValid);
if (!answerSlotValid) {
this.emitWithState("Unhandled");
return;
}
else {
var currentTime = moment(this.attributes['currentTime']);
var timeAdd = getRandomNumber(4, 8);
currentTime.add(timeAdd, 'h');
// check if time over
Object.assign(this.attributes, {
"currentTime": currentTime
});
if (checkIfGameOver.call(this))
{
var repromptText = getTimeOutText.call(this);
repromptText = repromptText.clue.replace('%s', currentTime.format("Do MMMM h A"));
this.emit(":tellWithCard", repromptText, repromptText, this.t("GAME_NAME"), getCardString(repromptText));
return;
}
// check if back
var thisNote = this.event.request.intent.slots.Destination.value.toLowerCase().trim();
thisNote = thisNote.replace(/[^a-zA-Z]/gi, '');
console.log('NOTES: ' + thisNote);
if (thisNote === 'back') {
this.handler.state = constants.states.DECIDE_MODE;
var speechOutput = this.t("DECIDE_PROMPT", this.attributes['level']);
var repromptText = this.t("DECIDE_REPROMPT");
Object.assign(this.attributes, {
"speechOutput": speechOutput,
"repromptText": repromptText
});
this.emit(":askWithCard", speechOutput, repromptText, this.t("GAME_NAME"), getCardString(repromptText));
return;
}
else {
var destination = getDestination.call(this, this.event.request.intent);
console.log('Destination: ' + JSON.stringify(destination));
var currentStep = this.attributes['currentStep'];
var rightStep = this.attributes['rightStep'];
var trail = this.attributes['trail'];
var currentCountry = this.attributes['currentCountry'];
var currentTime = moment(this.attributes['currentTime']);
var isRightTrack = destination[0].countryId == trail[rightStep].country;
if (rightStep == 0 && rightStep != currentStep)
{
isRightTrack = destination[0].countryId == this.attributes['startCountry'];
}
console.log('>> ' + rightStep + ' ' + currentStep)
console.log('>>> ' + isRightTrack + ' ' + destination[0].countryId + ' : ' + trail[rightStep].country);
if (isRightTrack)
{
if (destination[0].countryId == this.attributes['startCountry'])
rightStep = 0;
for (var tt = 0 ; tt < trail.length ; tt++) {
console.log('>>>>>> ' + tt + ' ' + destination[0].countryId + ' : ' + trail[tt].country);
if (trail[tt].country == destination[0].countryId) {
rightStep = tt + 1;
break;
}
}
}
if (rightStep == 5) {
// game over
var winText = getWinText.call(this);
console.log(">>> " + questions.data[trail[rightStep - 1].country] + ' ' + winText);
var score = this.attributes['score'];
var level = this.attributes['level'];
var left = 0;
var lastLevel = level;
var addLevelText = true;
score = score + 1;
if (score < 5)
{
level = questions.level[0].level;
left = 5 - score;
}
else if (score < 10)
{
level = questions.level[1].level;
left = 10 - score;
}
else if (score < 15)
{
level = questions.level[2].level;
left = 15 - score;
}
else if (score < 20)
{
level = questions.level[3].level;
left = 20 - score;
}
else if (score < 25)
{
level = questions.level[4].level;
left = 25 - score;
}
else
{
addLevelText = false;
}
Object.assign(this.attributes, {
"score": score,
"level": level
});
console.log('>>' + score + ' ' + level);
var repromptText = winText.clue.replace('%s', questions.data[trail[rightStep - 1].country].country);
repromptText += ' The ' + this.attributes['treasure'] + ' is all yours! ';
if (addLevelText)
{
if (level === lastLevel) {
repromptText += ' You have completed ' + score + ' Trails successfully! And, your current rank is ' +
level + '. ' + left + ' more trails until your next promotion! Happy Treasure Hunting!<say-as interpret-as="interjection">ta ta</say-as>';
}
else
{
repromptText += ' <say-as interpret-as="interjection">woo hoo</say-as>. You have earned a promotion. Your current rank is ' + level + '. And, you have completed ' + score +
' Trails successfully! ' + left + ' more trails until your next promotion! Happy Treasure Hunting!<say-as interpret-as="interjection">ta ta</say-as>';
}
}
this.emit(":tellWithCard", repromptText, this.t("GAME_NAME"), getCardString(repromptText));
return;
}
else {
currentStep++;
console.log('curr: ' + currentStep + ' : right ' + rightStep + ' ' + isRightTrack);
if (isRightTrack) {
currentStep = rightStep;
}
this.handler.state = constants.states.DECIDE_MODE;
currentCountry = trail[rightStep].country;
var repromptText = this.t("NEW_DEST_MESSAGE", destination[0].country,
currentTime.format("Do MMMM h A"));
Object.assign(this.attributes, {
"speechOutput": repromptText,
"repromptText": repromptText,
"currentTime": currentTime,
"currentStep": currentStep,
"isRightTrack": isRightTrack,
"rightStep": rightStep,
"currentCountry": currentCountry
});
this.emit(":askWithCard", repromptText, repromptText, this.t("GAME_NAME"), getCardString(repromptText));
}
}
}
}
var helpStateHandlers = Alexa.CreateStateHandler(constants.states.HELP_MODE, {
"helpTheUser": function (state) {
Object.assign(this.attributes, {
"askedCancel": false
});
this.attributes["currentState"] = state;
this.handler.state = state;
var speechOutput = this.t("HELP_MESSAGE");
if(state == constants.states.START_MODE)
{
speechOutput = this.t("HELP_START");
}
else if(state == constants.states.CLUE_MODE)
{
speechOutput = this.t("HELP_CLUE");
}
else if(state == constants.states.DECIDE_MODE)
{
speechOutput = this.t("HELP_DECIDE");
}
else if(state == constants.states.FLY_MODE)
{
speechOutput = this.t("HELP_FLY");
}
this.emit(":ask", speechOutput + ' Now, ' + this.attributes['speechOutput'], speechOutput + ' Now, ' + this.attributes['repromptText']);
},
"AMAZON.StartOverIntent": function () {
Object.assign(this.attributes, {
"askedCancel": false
});
this.handler.state = constants.states.START_MODE;
this.emitWithState("StartGame", false);
},
"AMAZON.RepeatIntent": function () {
Object.assign(this.attributes, {
"askedCancel": false
});
this.emitWithState("helpTheUser", this.handler.state);
},
"AMAZON.HelpIntent": function () {
Object.assign(this.attributes, {
"askedCancel": false
});
this.emitWithState("helpTheUser", this.handler.state);
},
"AMAZON.YesIntent": function () {
if (this.attributes['askedCancel']) {
var speechOutput = this.t("CANCEL_MESSAGE");
this.handler.state = constants.states.START_MODE;
this.emit(":tell", speechOutput);
}
else {
this.emitWithState("Unhandled");
}
},
"AMAZON.StopIntent": function () {
Object.assign(this.attributes, {
"askedCancel": true
});
var speechOutput = this.t("STOP_MESSAGE");
this.emit(":ask", speechOutput, speechOutput);
},
"AMAZON.NoIntent": function () {
Object.assign(this.attributes, {
"askedCancel": false
});
if (this.attributes["speechOutput"] && this.attributes["repromptText"]) {
this.emitWithState("AMAZON.RepeatIntent");
} else {
this.handler.state = constants.states.START_MODE;
this.emitWithState("StartGame", false);
}
},
"AMAZON.CancelIntent": function () {
this.handler.state = constants.states.START_MODE;
this.emit(":tell", this.t("CANCEL_MESSAGE"));
},
"Unhandled": function () {
Object.assign(this.attributes, {
"askedCancel": false
});
var speechOutput = this.t("HELP_UNHANDLED");
this.emit(":ask", speechOutput, speechOutput);
},
...
This file has been truncated, please download it to see its full contents.
"use strict";
var questionCount = 7; // The number of questions available per city.
module.exports =
{
buildTreasureTrail : function (startCountry) {
return buildTrail(startCountry);
},
getStartCountry : function() {
return getRandomCountry([]);
}
};
var start = function()
{
debugger;
var cnt = getRandomCountry([]);
var trail = buildTrail(cnt);
document.getElementById('dd').innerHTML = 'Staring > ' + cnt + '<br/><br/>Trail:<br/><br/>' + JSON.stringify(trail);
}
var buildTrail = function (startCountry)
{
debugger;
var trail = [];
var country = [];
var helpers = [];
country.push(startCountry);
for (var i = 0 ; i < 5 ; i++) {
var cnt = getRandomCountry(country);
country.push(cnt);
var helper = getRandomHelper(helpers);
for(var x = 0 ; x < helper.length ; x++)
helpers.push(helper[x]);
var clue = getRandomClues(cnt);
trail.push({
'country': cnt,
'helper': helper,
'clue': clue
});
}
return trail;
}
var getRandomNumber = function(min, max)
{
return Math.floor(Math.random()*(max-min)+min);
}
var getRandomCountry = function(cnt)
{
var cntFound = false;
var cntName = 'Not Found';
var data = questions.data;
var id = [];
for (var i = 0 ; i < data.length ; i++) {
var thisId = getRandomNumber(0, data.length);
while (id.filter(function (e) { return e == thisId }).length > 0)
{
thisId = getRandomNumber(0, data.length);
}
id.push(thisId);
var thisCountry = data[thisId];
if (cnt.filter(function (e) { return e == thisCountry.countryId }).length == 0) {
cntName = thisCountry.countryId;
break;
}
}
return cntName;
}
var getRandomHelper = function (helper) {
var cntFound = 0;
var cntName = [];
var data = questions.helper;
var id = [];
for(var i = 0 ; i < data.length ; i ++)
{
var thisId = getRandomNumber(0, data.length);
while (id.filter(function (e) { return e === thisId }).length > 0) {
thisId = getRandomNumber(0, data.length);
}
id.push(thisId);
var thisHelper = data[thisId];
if (helper.filter(function (e) { return e == thisHelper.helperId }).length == 0) {
// if (helper.indexOf(thisHelper) == -1) {
//Not In the array!
cntName.push(thisHelper.helperId);
cntFound++;
if(cntFound >= 3)
break;
}
}
return cntName;
}
var getRandomClues = function (cnt) {
var data = questions.data;
var id = [];
var clues = [];
var thisCountry = data.filter(function (e) { return e.countryId == cnt });
if (thisCountry.length > 0) {
for(var i = 1 ; i <= questionCount ; i++)
{
var thisId = getRandomNumber(0, questionCount);
while (id.filter(function (e) { return e == thisId }).length > 0) {
thisId = getRandomNumber(0, questionCount);
}
id.push(thisId);
clues.push(thisId);
//clues.push(thisCountry[0]["q" + thisId]);
if(clues.length >= 3)
{
break;
}
}
}
return clues;
}
var questions = {
data: [
{ 'countryId': 0, 'country': 'India', 'q0': 'q0', 'q1': 'q1', 'q2': 'q2', 'q3': 'q3', 'q4': 'q4', 'q5': 'q5', 'q6': 'q6' },
{ 'countryId': 1, 'country': 'America', 'q0': 'q0', 'q1': 'q1', 'q2': 'q2', 'q3': 'q3', 'q4': 'q4', 'q5': 'q5', 'q6': 'q6' },
{ 'countryId': 2, 'country': 'United Kingdom', 'q0': 'q0', 'q1': 'q1', 'q2': 'q2', 'q3': 'q3', 'q4': 'q4', 'q5': 'q5', 'q6': 'q6' },
{ 'countryId': 3, 'country': 'Algeria', 'q0': 'q0', 'q1': 'q1', 'q2': 'q2', 'q3': 'q3', 'q4': 'q4', 'q5': 'q5', 'q6': 'q6' },
{ 'countryId': 4, 'country': 'Egypt', 'q0': 'q0', 'q1': 'q1', 'q2': 'q2', 'q3': 'q3', 'q4': 'q4', 'q5': 'q5', 'q6': 'q6' },
{ 'countryId': 5, 'country': 'Kuwait', 'q0': 'q0', 'q1': 'q1', 'q2': 'q2', 'q3': 'q3', 'q4': 'q4', 'q5': 'q5', 'q6': 'q6' },
{ 'countryId': 6, 'country': 'Singapore', 'q0': 'q0', 'q1': 'q1', 'q2': 'q2', 'q3': 'q3', 'q4': 'q4', 'q5': 'q5', 'q6': 'q6' },
{ 'countryId': 7, 'country': 'Australia', 'q0': 'q0', 'q1': 'q1', 'q2': 'q2', 'q3': 'q3', 'q4': 'q4', 'q5': 'q5', 'q6': 'q6' },
{ 'countryId': 8, 'country': 'Sri Lanka', 'q0': 'q0', 'q1': 'q1', 'q2': 'q2', 'q3': 'q3', 'q4': 'q4', 'q5': 'q5', 'q6': 'q6' },
{ 'countryId': 9, 'country': 'China', 'q0': 'q0', 'q1': 'q1', 'q2': 'q2', 'q3': 'q3', 'q4': 'q4', 'q5': 'q5', 'q6': 'q6' },
],
helper:
[
{ 'helperId': 0 , 'helper': 'banker'},
{ 'helperId': 1 , 'helper': 'historian'},
{ 'helperId': 2 , 'helper': 'librarian'},
{ 'helperId': 3 , 'helper': 'teacher'},
{ 'helperId': 4 , 'helper': 'doctor'},
{ 'helperId': 5 , 'helper': 'shopkeeper'},
{ 'helperId': 6 , 'helper': 'police'},
{ 'helperId': 7 , 'helper': 'artist'},
{ 'helperId': 8 , 'helper': 'traveller'},
{ 'helperId': 9 , 'helper': 'architect'},
{ 'helperId': 10 , 'helper': 'hotelier'},
{ 'helperId': 11 , 'helper': 'manager'},
{ 'helperId': 12 , 'helper': 'pilot'},
{ 'helperId': 13 , 'helper': 'businessman'},
{ 'helperId': 14, 'helper': 'professor' }
]
};
"use strict";
module.exports = Object.freeze({
//Amazon Alexa Skill App Id
appId: '',
//Flickr API Key
apiKey: '',
//Flickr API Secret
apiSecret: '',
//Flicker User ID
userId: '',
// DynamoDB Table name
dynamoDBTableName: 'UKTreasureHuntTable',
states : {
START_MODE : '',
CLUE_MODE: '_CLUE_MODE',
DECIDE_MODE: '_DECIDE_MODE',
FLY_MODE: '_FLY_MODE',
HELP_MODE: '_HELP_MODE'
},
appname: 'U.K. Treasure Hunt'
});
DecideIntent I want to {Decision}
DecideIntent {Decision} for Clue further
DecideIntent {Decision} to Next Destination
DecideIntent I want to {Decision} for Clue Further
DecideIntent I want to {Decision} for Clue
DecideIntent I want to {Decision} to Next Destination
AskIntent I want to ask {Helper}
AskIntent Ask {Helper}
AskIntent Please Ask {Helper}
FlyIntent I want to fly to {Destination}
FlyIntent Fly to {Destination}
FlyIntent To {Destination}
FlyIntent Next {Destination}
FlyIntent Next destination is {Destination}
FlyIntent Take me to {Destination}
FlyIntent Fly me to {Destination}
LaunchIntent Launch Lost Treasure
LaunchIntent Ask U.K. Treasure Hunt to start a new trail
LaunchIntent Tell U.K. Treasure Hunt to start a new trail
LaunchIntent Open U.K. Treasure Hunt
LaunchIntent Start U.K. Treasure Hunt
{
"intents": [
{
"slots": [
{
"name": "Decision",
"type": "DECIDE"
}
],
"intent": "DecideIntent"
},
{
"slots": [
{
"name": "Helper",
"type": "HELPER"
}
],
"intent": "AskIntent"
},
{
"slots": [
{
"name": "Destination",
"type": "COUNTRY"
}
],
"intent": "FlyIntent"
},
{
"intent": "LaunchIntent"
},
{
"intent": "AMAZON.StartOverIntent"
},
{
"intent": "AMAZON.RepeatIntent"
},
{
"intent": "AMAZON.HelpIntent"
},
{
"intent": "AMAZON.StopIntent"
},
{
"intent": "AMAZON.CancelIntent"
},
{
"intent": "AMAZON.YesIntent"
},
{
"intent": "AMAZON.NoIntent"
}
]
}
Comments