Kolja Lubitz
Published © GPL3+

Make Me an Omelette

Make me an omelette is a speech adventure. You are in a Kitchen and your quest is to make an omelette.

BeginnerShowcase (no instructions)1 hour591
Make Me an Omelette

Things used in this project

Hardware components

Amazon Echo
Amazon Alexa Amazon Echo
×1
Echo Dot
Amazon Alexa Echo Dot
×1
Amazon Tap
Amazon Alexa Amazon Tap
×1

Software apps and online services

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

Story

Read more

Schematics

walk through

Complete list of actions to complete the game.

Code

Make me an Omlett

Python
#!/usr/bin/python
# -*- coding: utf-8 -*-

"""
Make me an omelette. A Amazon Alexa Skill Game implementet as a AWS Lamda function.
You are in a virtual kitchen and your goal is to cook a omelette.

author: Kolja Lubitz
e-mail: pinguin999@gmail.com 
"""

from __future__ import print_function

#Lebewesesn
#Es könnte ein kleiner Troll in der Vorratskammer sein


#Verbesserungsmöglichkeit:
#Beim Raumwechsel wird der aktuelle Raum mit seinem Status in die DB geladen
#Der neue Raum wird aus der DB und den Session Informationen zusammen gesetzt und in die Session geladen
#Alle Operationen arbeiten dann auf der Session
#Look at sollte auch inventory bekommen und dann den inhalt vorlesen
#Merge Use und use_object zu einem Intend
#der cupboard ist Verschlossen wo ist der Schlüssel?
#Bei Counter events sollte obj und room nicht übergeben werden
#Event für zwischensequenzen. Das event wird immer angesprochen und muss selber checken ob es sich ausführt.
#Event types: all all_move all_use ...
#Raumverbindungen machen kein sinn. Man sollte immer von überall nach überall kommen können. Sonst müsste man dem spieler immer sagen wo man hin kann.

rooms = {"rooms": [\
    {"name": "kitchen", "objects": ["table", "fridge", "cupboard", "oven"]},
    {"name": "storeroom", "objects": ["cupboard"]},
]}

# Es fehlen noch die sätze für:
#Kann ich nicht aufheben
#Die description sollte optional eine Liste sein damit immer mal was anderes als antwort gegeben wird
#Die auflistung im inventar. Example: I have a recipe, eggs and a table.


objects = {"objects": [\
    {"name": "table", "description": "A dining table. Please put the final omelette on the table.", "collectable": False}, \
    {"name": "recipe", "description": "omelette recipe. For an omelette you need eggs, salt, pepper, and grated cheese. Mix all and fry it in a pan with a little bit oil", "collectable": False}, \
    {"name": "fridge", "description": "The fridge. Maybe you have some eggs and cheese in the fridge.", "collectable": False}, \
    {"name": "cupboard", "description": "A cupboard", "collectable": False}, \
    {"name": "eggs", "description": "Yea eggs. You need the aggs for the omelette.", "collectable": True}, \
    {"name": "salt", "description": "The salt. Do not put to much salt into the omelette.", "collectable": True}, \
    {"name": "pepper", "description": "The pepper. With the pepper your omelette get this special taste.", "collectable": True}, \
    {"name": "oil", "description": "The Oil. You need the oil to get your omelette crusty.", "collectable": True}, \
    {"name": "cheese", "description": "Delicious cheese. Every omelette needs cheese.", "collectable": True}, \
    {"name": "cheese grater", "description": "The cheese grater is needed to get the cheese into small peaces.", "collectable": True}, \
    {"name": "grated cheese", "description": "This cheese is nicely grated", "collectable": False}, \
    {"name": "pan", "description": "The pan. Fry the raw omelette in pan.", "collectable": True}, \
    {"name": "pasta", "description": "The pasta, Ohh this item is from an other game.", "collectable": False}, \
    {"name": "cookbook", "description": "The cookbook. In the cookbook you can find a lot of recipes. But you only have the ingredients for omelette.", "collectable": False}, \
    {"name": "stove", "description": "Use the stove if you have all ingredients for your omelette.", "collectable": False}, \
    {"name": "oven", "description": "On this oven I can fry my omelette.", "collectable": False}, \
    {"name": "omelette", "description": "Wow this omelette looks very delicious.", "collectable": False}, \
]}

combinations = { "combinations": [\
    {"in": ["cheese", "cheese grater"], "out": "grated cheese"},\
]}

# Events 
# A event hast two speech_outs one for sucsess and fail.

events = { "events": [\
    {"object": "fridge", "room": "kitchen", "event_name": "", "event":"open_fridge", "sucsess": "Oh I found eggs and cheese. I will take them with me.", "fail": ""},\
    {"object": "cupboard", "room": "kitchen", "event_name": "", "event":"open_cupboard_kitchen", "sucsess": "Oh I found a pan. I will take it with me.", "fail": ""},\
    {"object": "cupboard", "room": "storeroom", "event_name": "", "event":"open_cupboard_storeroom", "sucsess": "There is a old cookbook and a pack of pasta. I don't need that stuff to cook an omelette. Maybe thats part of an other game... But there is also a cheese grater that looks handy. I will take it with me.", "fail": "There is a old cookbook and a pack of pasta. I don't need that stuff to cook an omelette. Maybe thats part of an other game..."},\
    {"object": "", "room": "", "event_name": "look_at_table", "event":"look_at_table", "sucsess": "Oh, there is also salt and pepper ", "fail": "And yes, I already have the salt and pepper."},\
    {"object": "", "room": "", "event_name": "combine_tabele_omelette", "event":"finish_game", "sucsess": "You made it. You master the game. Now you can exit the game by saying 'exit game' or you can stay in the game and continue exploring it.", "fail": "Oh no the omelette ist still raw."},\
    {"object": "", "room": "", "event_name": "combine_omelette_table", "event":"finish_game", "sucsess": "You made it. You master the game. Now you can exit the game by saying 'exit game' or you can stay in the game and continue exploring it.", "fail": "Oh no the omelette ist still raw."},\
    {"object": "", "room": "", "event_name": "combine_pan_oven", "event":"cook", "sucsess": "You are cooking an omelette.", "fail": "I still need ingredients, look in your recipe how to cook a omelette."},\
    {"object": "", "room": "", "event_name": "combine_oven_pen", "event":"cook", "sucsess": "You are cooking an omelette.", "fail": "I still need ingredients, look in your recipe how to cook a omelette."},\
]}

def lambda_handler(event, context):
    """ Route the incoming request based on type (LaunchRequest, IntentRequest,
    etc.) The JSON body of the request is provided in the event parameter.
    """
    #print("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.ec0546ac-0d52-407c-af91-8da82b083c60"):
    #    raise ValueError("Invalid Application ID")

    if event['request'] == None or event['session'] == None:
        session_attributes = session['attributes']
        should_end_session = False
        
        speech_output = "Sorry I don't understnd what do you try to do."
        reprompt_text = "Sorry I don't understnd what do you try to do."
        
        return build_response(session_attributes, build_speechlet_response(
            intent['name'], speech_output, reprompt_text, should_end_session))
    
    if event['session']['new']:
        on_session_started({'requestId': event['request']['requestId']},
                           event['session'])

    if event['request']['type'] == "LaunchRequest":
        return on_launch(event['request'], event['session'])
    elif event['request']['type'] == "IntentRequest":
        return on_intent(event['request'], event['session'])
    elif event['request']['type'] == "SessionEndedRequest":
        return on_session_ended(event['request'], event['session'])
        



def on_session_started(session_started_request, session):
    """ Called when the session starts """

    print("on_session_started requestId=" + session_started_request['requestId']
          + ", sessionId=" + session['sessionId'])


def on_launch(launch_request, session):
    """ Called when the user launches the skill without specifying what they
    want
    """

    print("on_launch requestId=" + launch_request['requestId'] +
          ", sessionId=" + session['sessionId'])
    # Dispatch to your skill's launch
    return get_welcome_response()


def on_intent(intent_request, session):
    """ Called when the user specifies an intent for this skill """

    print("on_intent requestId=" + intent_request['requestId'] +
          ", sessionId=" + session['sessionId'])

    try:
        session['attributes']['event_counter']
    except:
        session['attributes'] = {"room": "kitchen", "inventory": ["recipe"], "event_counter": {"welcome": 1} }

    intent = intent_request['intent']
    intent_name = intent_request['intent']['name']

    # Dispatch to your skill's intent handlers
    if intent_name == "move":
        return move(intent, session)
    elif intent_name == "look_around":
        return look_around(intent, session)
    elif intent_name == "look_at":
        return look_at(intent, session)
    elif intent_name == "pick_up":
        return pick_up(intent, session)
    elif intent_name == "use":
        return use(intent, session)
    elif intent_name == "inventory":
        return inventory(intent, session)
    elif intent_name == "combine":
        return combine(intent, session)
    elif intent_name == "use_object":
        return use_object(intent, session)
    elif intent_name == "AMAZON.HelpIntent":
        return get_help_response(intent, session)
    elif intent_name == "AMAZON.CancelIntent" or intent_name == "AMAZON.StopIntent":
        return handle_session_end_request()
    else:
        raise ValueError("Invalid intent")


def on_session_ended(session_ended_request, session):
    """ Called when the user ends the session.

    Is not called when the skill returns should_end_session=true
    """
    print("on_session_ended requestId=" + session_ended_request['requestId'] +
          ", sessionId=" + session['sessionId'])
    # add cleanup logic here
    #TODO Save session to DB

# --------------------------------- Events -------------------------------------
#Salz und Pfeffer stehen auf dem Tisch. Um die nehmen zu können muss man einmal look at auf den Tisch aufgerufen haben.

def open_fridge(intent, session, obj, room):
    if not "cheese" in session['attributes']['inventory'] and not "grated cheese" in session['attributes']['inventory']:
        session['attributes']['inventory'].append("cheese")
    if not "eggs" in session['attributes']['inventory']:
        session['attributes']['inventory'].append("eggs")
    return True
    

def open_cupboard_kitchen(intent, session, obj, room):
    if not "pan" in session['attributes']['inventory']:
        session['attributes']['inventory'].append("pan")
    return True
    
    
def open_cupboard_storeroom(intent, session, obj, room):
    if not "cheese grater" in session['attributes']['inventory']:
        session['attributes']['inventory'].append("cheese grater")
        return True
    return False
    
def look_at_table(intent, session, obj, room):
    if not "salt" in session['inventory'] and not "pepper" in session['inventory']:Complete list of actions to complete the game.
        session['inventory'].append("salt")
        session['inventory'].append("pepper")
        return True
    return False
    
def finish_game(intent, session, obj, room):
    
    return True
    
def cook(intent, session, obj, room):
    if "salt" in session['inventory'] \
        and "pepper" in session['inventory'] \
        and "eggs" in session['inventory'] \
        and "pan" in session['inventory'] \
        and "grated cheese" in session['inventory']:
        session['inventory'].append("omelette")
        session['inventory'].remove("salt")
        session['inventory'].remove("pepper")
        session['inventory'].remove("eggs")
        session['inventory'].remove("pan")
        session['inventory'].remove("grated cheese")
        return True
    return False

# ---------------------------------- Logic -------------------------------------

def is_object_in_room(room_in, obj_in):
    for room in rooms['rooms']:
        if (room['name']) == room_in:
            for obj in room['objects']:
                if (obj) == obj_in:
                    return True
    return False
    
    
def is_object_in_inventory(inventory, obj_in):
    for obj in inventory:
        if obj == obj_in:
            return True
    return False
    
def object_description(obj_in):
    for obj in objects['objects']:
        if (obj['name']) == obj_in:
            return obj['description']
    return None
    
def is_object_collectable(room_in, obj_in):
    if is_object_in_room(room_in, obj_in):
        for obj in objects['objects']:
            if (obj['name']) == obj_in: 
                if obj['collectable'] == True:
                    return True
    return False

def handle_event(intent, session, event, obj = None, room = None):
    event_handler = None
    try:
        #print (locals())
        #print ("------------------")
        #print (globals())
        event_handler = globals().get(event['event'])
    except AttributeError:
        raise NotImplementedError("Event '{}' is not implemented.".format(event_name))

    if event_handler(intent, session, obj, room):
        return event["sucsess"]
    else:
        return event["fail"]
    
def use_object_in_room(intent, session, obj, room):
    for event in events['events']:
        if event['object'] == obj and event['room'] == room:
            return handle_event(intent, session, event, obj, room)
    return False
    
def event_counter(intent, session, action, value = ''):
    event_value = action + '_' + value
    #print(intent)
    #print(session)
    #print(event_value)
    try:
        session['event_counter'][event_value] = int(session['event_counter'][event_value]) + 1
    except KeyError:
        session['event_counter'][event_value] = 1
    for event in events['events']:
        if event['event_name'] == event_value:
            return handle_event(intent, session, event)
    return ""
            

def get_event_count(session, event, value = ''):
    try:
        return session['event_counter'][event + '_' + value]
    except KeyError:
        return 0


# --------------- Functions that control the skill's behavior ------------------

def get_welcome_response():
    """ Init the session with start room and inventory items."""

    session_attributes = {"room": "kitchen", "inventory": ["recipe"], "event_counter": {"welcome": 1} }
    card_title = "Welcome to 'Make me an omelette'."Complete list of actions to complete the game.
    speech_output = "Welcome to make me an omelette. " \
                    "You are in a kitchen and your quest is to make an omeltt. " \
                    "You should look around to learn more about the enviroment, "\
                    "you can also move to the storeroom by saying 'move to storeroom' or back by saying 'move to kitchen'. " \
                    "Please command all aktions until you fullfill the quest. The game will not ask you every time for your next step."
    # If the user either does not reply to the welcome message or says something
    # that is not understood, they will be prompted again with this text.
    reprompt_text = "Welcome to make me a omelette."
    should_end_session = False
    return build_response(session_attributes, build_speechlet_response(
        card_title, speech_output, reprompt_text, should_end_session))


def get_help_response(intent, session):
    card_title = "How to play"
    speech_output = "'Make me an omelette' is a speach adventure game. In this game your quest is to make an omelette and place it at the dining table in the kitchen. " \
                    "You are in a kitchen and next to the kitchen is a storeroom. If you want to learn more about your envirement just say 'look around'. " \
                    "If you are not sure how to cook an omelette just look at the recipe in your inventory, by saying 'look at recipe'. " \
                    
    # Setting this to true ends the session and exits the skill.
    should_end_session = False
    return build_response({}, build_speechlet_response(
        card_title, speech_output, None, should_end_session))


def handle_session_end_request():
    card_title = "Game End"
    speech_output = "Thank you for playing 'Make me an omelette'. At the moment there" \
                    " is no possibility to save the game, so you have to start from the beginning next time."
    # Setting this to true ends the session and exits the skill.
    should_end_session = True
    return build_response({}, build_speechlet_response(
        card_title, speech_output, None, should_end_session))


def move(intent, session):
    session_attributes = session['attributes']
    if 'value' in intent['slots']['room']:Complete list of actions to complete the game.
        event_speech = event_counter(intent, session_attributes, "move", intent['slots']['room']['value'])
    else:
        event_speech = event_counter(intent, session_attributes, "move", 'None')
    should_end_session = False
    if 'room' in intent['slots']:
        room = intent['slots']['room']['value']
        session_attributes['room'] = room
        speech_output = "You are moving to the  " + room + "."
        reprompt_text = "You can move to an other room by saying, " \
                        "move to, plus the rooms name?"
    else:
        speech_output = "I'm not sure where you want to go. " \
                        "Here are only the kitchen and the storeroom."
        reprompt_text = "I'm not sure wher you want to go. " \
                        "You can move to an other room by saying, " \
                        "move to, plus the rooms name?"

    return build_response(session_attributes, build_speechlet_response(
        'Move', speech_output, reprompt_text, should_end_session))


def look_around(intent, session):
    session_attributes = session['attributes']
    event_counter(intent, session_attributes, "look_around")
    should_end_session = False
    
    items = "You can see "
    for room in rooms['rooms']:
        if (room['name']) == session_attributes['room']:
            objects = room['objects']
            
    for obj in objects[:-1]:
        items += obj + " "
    if len(objects) > 1:
        items += "and " + objects[-1:][0]
    else:
        items += objects[-1:][0]
    
    
    speech_output = "You are in the " + session_attributes['room'] + ". " + items
    reprompt_text = "Say where am I to learn more about your enviroment."
    
    return build_response(session_attributes, build_speechlet_response(
        'Look around', speech_output, reprompt_text, should_end_session))


def look_at(intent, session):
    session_attributes = session['attributes']
    if 'value' in intent['slots']['object']:
        event_speech = event_counter(intent, session_attributes, "look_at", intent['slots']['object']['value'])
    else:
        event_speech = event_counter(intent, session_attributes, "look_at", 'None')
    should_end_session = False
    
    if 'object' in intent['slots'] and 'value' in intent['slots']['pick_up']:
        obj = intent['slots']['object']['value']
        if is_object_in_room(session_attributes['room'], obj) or is_object_in_inventory(session_attributes['inventory'], obj):
            discription = object_description( obj)
            if discription:
                speech_output = discription + " " + event_speech
            else:
                speech_output = "I have no idea what that is, jet?"
        else:
            speech_output = "There is no " + obj + " here."
        reprompt_text = "You can look at all objects in the room you are in and the objects in your inventory."
    else:
        speech_output = "I'm not sure where you want to look at. " \
                        "Please try again."
        reprompt_text = "I'm not sure where you want to look at. " \
                        "You can look at all objects in the room you are in and the objects in your inventory by saying, " \
                        "look at, plus the objects name?"
    
    return build_response(session_attributes, build_speechlet_response(
        'Look at', speech_output, reprompt_text, should_end_session))


def pick_up(intent, session):
    session_attributes = session['attributes']
    if 'value' in intent['slots']['object']:
        event_counter(intent, session_attributes, "pick_up", intent['slots']['object']['value'])
    else:
        event_counter(intent, session_attributes, "pick_up", 'None')
    should_end_session = False
    
    if 'object' in intent['slots'] and 'value' in intent['slots']['object']:
        obj = intent['slots']['object']['value']
        if is_object_collectable(session_attributes['room'], obj):
            session_attributes['inventory'].append(obj)
            speech_output = "I put that to good ues."
        else:
            speech_output = "I can not take " + obj + " with me."
        reprompt_text = "You can pick up objects in the room you are in."
    else:
        speech_output = "I'm not sure what you want to pick up. " \
                        "Please try again."
        reprompt_text = "I'm not sure what you want to pick up. " \
                        "You can pick up all objects in the room you are in by saying: " \
                        "'pick up plus the objects name'"
    
    return build_response(session_attributes, build_speechlet_response(
        'Pick up', speech_output, reprompt_text, should_end_session))


def use(intent, session):
    session_attributes = session['attributes']
    if 'value' in intent['slots']['object']:
        event_counter(intent, session_attributes, "use", intent['slots']['object']['value'])
    else:
        event_counter(intent, session_attributes, "use", 'None')
    should_end_session = False
    
    if 'object' in intent['slots'] and 'value' in intent['slots']['object']:
        obj = intent['slots']['object']['value']
        room = session_attributes['room']
        if is_object_in_room(room, obj) or is_object_in_inventory(session_attributes['inventory'], obj):
            speech_output = use_object_in_room(intent, session, obj, room)
        else:
            speech_output = "I can not find " + obj + " here."
        reprompt_text = "You can use all objects in the room you are in."
    else:
        speech_output = "I'm not sure what you want to use. " \
                        "Please try again."
        reprompt_text = "I'm not sure what you want to use. " \
                        "You can use all objects in the room you are in by saying, " \
                        "use, plus the objects name?"
    
    return build_response(session_attributes, build_speechlet_response(
        'Use', speech_output, reprompt_text, should_end_session))Complete list of actions to complete the game.

def inventory(intent, session):
    session_attributes = session['attributes']
    if 'value' in intent['slots']['status']:
        event_counter(intent, session_attributes, "inventory", intent['slots']['status']['value'])
    else:
        event_counter(intent, session_attributes, "inventory", 'None')
    should_end_session = False
    
    #if 'status' in intent['slots']:
        #status = intent['slots']['status']['value']
        #if status == 'open':
    speech_output = "I have a "
    inventory = session_attributes['inventory']
    for obj in inventory[:-1]:
        speech_output += obj + " "
    if len(inventory) > 1:
        speech_output += "and " + inventory[-1:][0]
    else:
        speech_output += inventory[-1:][0]
    speech_output = speech_output + "."

    reprompt_text = speech_output
    return build_response(session_attributes, build_speechlet_response(
        'Inventory', speech_output, reprompt_text, should_end_session)) 
        
    
def combine(intent, session):
    session_attributes = session['attributes']
    should_end_session = False
    
    speech_output = "Please tell me which objects you like to combine."
    reprompt_text = "Please tell me which objects you like to combine."
    
    if 'objectone' in intent['slots'] and 'objecttwo' in intent['slots'] and 'value' in intent['slots']['objectone'] and 'value' in intent['slots']['objectone']:
        objectone = intent['slots']['objectone']['value']
        objecttwo = intent['slots']['objecttwo']['value']
        #TODO Sort combine values nach alphabet damit das event eindeutig ist
        event_speech = event_counter(intent, session_attributes, "combine", objectone + "_" + objecttwo) 
        
        if event_speech == "":
            speech_output = "I can not combind " + objectone + " with " + objecttwo + "."
            reprompt_text = "I'm not sure how to combind " + objectone + " with " + objecttComplete list of actions to complete the game.wo + "."
        else:
            speech_output = event_speech
            reprompt_text = event_speech
        
        if (is_object_in_room(session_attributes['room'], objectone) \
           or is_object_in_inventory(session_attributes['inventory'], objectone)) \
           and (is_object_in_room(session_attributes['room'], objecttwo) \
           or is_object_in_inventory(session_attributes['inventory'], objecttwo)):
            for combination in combinations['combinations']:
                if objectone in combination['in'] and objecttwo in combination['in']:
                    session_attributes['inventory'].remove(objectone)
                    session_attributes['inventory'].remove(objecttwo)
                    session_attributes['inventory'].append(combination['out'])

                    speech_output = "I now have " + combination['out'] + "."
                    reprompt_text = "I now have " + combination['out'] + "."
    
    return build_response(session_attributes, build_speechlet_response(
        'Combine', speech_output, reprompt_text, should_end_session))


# --------------- Helpers that build all of the responses ----------------------


def build_speechlet_response(title, output, reprompt_text, should_end_session):
    return {
        'outputSpeech': {
            'type': 'PlainText',
            'text': output
        },
        'card': {
            'type': 'Simple',
            'title': title,Complete list of actions to complete the game.
            'content': output
        },
        'reprompt': {
            'outputSpeech': {
                'type': 'PlainText',
                'text': reprompt_text
            }
        },
        'shouldEndSession': should_end_session
    }


def build_response(session_attributes, speechlet_response):
    return {
        'version': '1.0',
        'sessionAttributes': session_attributes,
        'response': speechlet_response
    }
    
    
# -----------------------------Test --------------------------------------------

def test():
    #Custom Slot Types
    print("OBJECTS")
    for obj in objects["objects"]:
        print (obj["name"])

    print ("")
    print ("ROOMS")
    for room in rooms["rooms"]:
        print (room["name"])

    print("") #Only 'open' as an INVENTORYSTATUS
    print("INVENTORYSTATUS")
    print("open")


if __name__ == "__main__":
    test()

Credits

Kolja Lubitz

Kolja Lubitz

1 project • 0 followers

Comments

Add projectSign up / Login