Sunday, September 25, 2022

C++ Program for Tree Iterator

Problem

Given n-ary (n children per node) tree, write a C++ iterator to iterate over all the nodes.

Solution

Iterator Interface

One of the potential interface is as follows:

/**
* If there are more children to be traversed in the current layer
* @param index
* @return True if there are children yet to be traversed, false otherwise
*/
virtual bool hasMoreChildren(int index);

/**
* Move to child at index in a layer
* @param index
*/
virtual void moveToChildAt(int index);

/**
* Print the current node
* @param index
*/
virtual void printNode();

Implementation

For implementing the iterator, we will use a stack to keep track of the node being traversed in the tree.

private:
Node* mCurrentNode = nullptr;
std::stack<Node*> mNodeStack;
};

The mCurrentNode and mNodeStack are used in the implementation as follows:

C++ Code

bool TreeIterator::hasMoreChildren(int index) {
if (mNodeStack.empty()) return false;
mCurrentNode = mNodeStack.top();
// If no children, return false.
if (mCurrentNode->children().empty()) {
mNodeStack.pop();
if (!mNodeStack.empty()) {
mCurrentNode = mNodeStack.top();
}
return false;
}
auto it = mCurrentNode->children().begin();
it += index;
// If all children in this layer are traversed, return false.
if (it == mCurrentNode->children().end()) {
mNodeStack.pop();
if (!mNodeStack.empty()) {
mCurrentNode = mNodeStack.top();
}
return false;
}
// There are more children to be drawn, return true
return true;
}

void TreeIterator::moveToChildAt(int index) {
if (mCurrentNode->children().empty()) {
// No children, nothing to do in current layer
return;
}
auto it = mCurrentNode->children().begin();
it += index;
if (it == mCurrentNode->children().end()) {
// All children visited once, nothing to do in current layer
return;
}
mNodeStack.push(*it);
mCurrentNode = mNodeStack.top();
}

void TreeIterator::printNode() {
cout << mCurrentNode->data() << endl;
}

Using the iterator

/**
* Recursively traverse the tree hierarchy
*/
void traverse() {
int i = 0;
while (hasChildren(i)) {
moveToChildAt(i);
traverse();
i++;
}
}

int main() {
TreeIterator *it;
it->traverse();
}

Explanation

The above code is a recursively traverses the children of each node in the tree. The stack maintains the current node at the top and the index passed from the traverse() method determines how many children of a particular node have been visited.

Alternate Solutions

Alternate solutions may use the following approach.

Visitor Pattern

Yet to write a working code, but this approach would mark a node as visited once it has been traversed to keep track of which child of a particular node should be visited next.

Parent Tracking

This requires modifying the tree node to contain a pointer to the parent node so that the mCurrentNode can be moved to the parent when all the children of a particular node are visited.

Python code to find the time difference between all occurrences of a pair of events in a log file

from datetime import datetime
import re

def parse_file(filename, expression1, expression2):
    lines = tuple(open(filename, 'r'))
    expression1Found = False
    expression2Found = False
    pattern = '(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1]) (2[0-3]|[01][0-9]):[0-5][0-9]:[0-5][0-9].[0-9][0-9][0-9]'

    for line in lines:
        if expression1 in line:
            timeString1 = re.search(pattern, line).group()
            expression1Found = True
        if expression2 in line:
            timeString2 = re.search(pattern, line).group()
            expression2Found = True

        if expression1Found and expression2Found:
            timePattern = '%m-%d %H:%M:%S.%f'
            epoch = datetime(1970, 1, 1)
            time1 = (datetime.strptime(timeString1, timePattern) - epoch)
            time2 = (datetime.strptime(timeString2, timePattern) - epoch)
            if int((time2 - time1).total_seconds() * 1000) > 1:
                print(int((time2 - time1).total_seconds() * 1000))

            # Reset and start searching for the next pair of occurrences of expression1 and expression2
            expression1Found = False
            expression2Found = False

if __name__ == "__main__":
    parse_file('filepath', 'even1', 'event2')

Sunday, June 27, 2021

Automatic Train Controller System Code

TrainController class starts two infinite loops in separate threads:
  1. User Override Control Loop
  2. Automatic Control Loop

In this post, the Train class contains a few characteristics such as distance travelled from Origin and its speed, which can be abstracted into a separate class and can be handled in a more centralized manner inside TrainController class.

Also a few more features such as directionality of train movement and maximum distance from origin will be introduced.

Code
package com.example.lib;

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class TrainController {
    private final List mTrains = new ArrayList<>();
    private final List mManuallyStoppedTrains = new ArrayList<>();
    private final InstructionParser mInstructionParser = new InstructionParser();
    public static void main(String[] args) {
        final TrainController trainController = new TrainController();
        trainController.createAndStartTrains(5);
         // This is the main controller loop.
         // 1. It monitors the distance between the pairs of trains and sends stop and start signals appropriately.
         // 2. This is run in a separate thread so that the user input can be captured in the main thread.
        Runnable controllerRunnable = new Runnable() {
            @Override
            public void run() {
                while (true) {
                    trainController.checkAndControlTrains();
                }
            }
        };
        Thread controllerThread = new Thread(controllerRunnable);
        controllerThread.start();
        trainController.printAllCommands();
        // Accept user input in a loop.
        while (true) {
            Scanner scanner = new Scanner(System.in);
            int option = scanner.nextInt();
            trainController.executeOption(option);
            System.out.println("Waiting for the next input");
        }
    }

    public void printAllCommands() {
        System.out.println("Choose from the below options");
        System.out.println("1. Start 5 trains");
        System.out.println("2. Get status of all trains");
        System.out.println("3. Stop all trains");
        System.out.println("4. Start all trains");
        System.out.println("5. Exit");
        System.out.println("6. Control individual train");
        System.out.println("7. Print all commands");
    }

    public void executeOption(final int option) {
        switch (option) {
            case 1:
                createAndStartTrains(5);
                break;
            case 2:
                printCurrentStateOfAllTrains();
                break;
            case 3:
                stopAllTrains();
                break;
            case 4:
                startAllTrains();
                break;
            case 5:
                stopAllTrains();
                System.exit(0);
            case 6:
                String instruction = System.console().readLine();
                System.out.println("Instruction received: " + instruction);
                if (instruction.toLowerCase().split(" ").length == 2) {
                    try {
                        int index = mInstructionParser.getIndex(instruction);
                        switch (instruction.toLowerCase().split(" ")[0]) {
                            case "start":
                                startTrain(index);
                                break;
                            case "stop":
                                stopTrain(index);
                                break;
                        }
                    } catch (IllegalArgumentException e) {
                        // Do nothing.
                    }
                }
                break;
            case 7:
                printAllCommands();
                break;
        }
    }

    /**
     * Initialize trains with different speeds and start them on different threads.
     * @param count of trains to start
     */
    public void createAndStartTrains(final int count) {
        final String trainName = "Train ";
        for (int i = 0; i < count; i++) {
            Train train = new Train(trainName + i, i * 1000);
            mTrains.add(train);
            train.startTrain();
        }
    }

    /**
     * Checks that the distance between successive trains is more than 1000 units.
     * Whenever the distance between successive trains is less than 1000 units, it calls {@link Train#stopTrain()} on the rear train.
     * Whenever the distance between successive trains is more than 1000 units, it calls {@link Train#startTrain()} on the rear train.
     */
    private void checkAndControlTrains() {
        // Loop to stop a train if it is within 1000 units of the train ahead of it.
        for (int i = 0; i < mTrains.size() - 1; i++) {
            if (mTrains.get(i + 1).getDistance() - mTrains.get(i).getDistance() - 3 * mTrains.get(i).getSpeed() <= 1000) {
                mTrains.get(i).stopTrain();
            }
        }
        // Loop to start a train if it is more than 1000 units away from the train ahead of it and it was not stopped manually.
        for (int i = 0; i < mTrains.size() - 1; i++) {
            if (mTrains.get(i + 1).getDistance() - mTrains.get(i).getDistance() - mTrains.get(i).getSpeed() > 1000) {
                Train train = mTrains.get(i);
                if (!mManuallyStoppedTrains.contains(train) && !train.isRunning()) {
                    train.startTrain();
                }
            }
        }
    }

    private void printCurrentStateOfAllTrains() {
        if (mTrains.size() == 0) {
            System.out.println("No train is in running state");
            return;
        }
        System.out.println("Printing status of all trains");
        for (Train train : mTrains) {
            train.printCurrentState();
        }
    }

    private void stopAllTrains() {
        for (Train train : mTrains) {
            train.stopTrain();
        }
    }

    private void startAllTrains() {
        for (Train train : mTrains) {
            train.startTrain();
        }
    }

    /**
     * Stop the train with the provided index.
     * @param trainIndex the index of the train to stop
     */
    private void stopTrain(int trainIndex) {
        // First add the train to the list of manually stopped trains. Otherwise the checkAndControl loop will start the train again.
        mManuallyStoppedTrains.add(mTrains.get(trainIndex));
        mTrains.get(trainIndex).stopTrain();
    }

    /**
     * Start the train with the provided index safely.
     * This checks if the train ahead is more than 1000 units ahead before starting the train.
     * @param trainIndex the index of the train to start
     */
    private void startTrain(int trainIndex) {
        if (trainIndex < mTrains.size() - 1) {
            if (mTrains.get(trainIndex + 1).getDistance() - mTrains.get(trainIndex).getDistance() <= 1000) {
                System.out.println("Cannot start train " + trainIndex + " since the train ahead is within 1000");
                return;
            }
            System.out.println("Starting train " + trainIndex + " since the train ahead is more than 1000");
        }
        // First remove the train from the list of manually stopped trains. Otherwise the checkAndControl loop will not start the train again.
        mManuallyStoppedTrains.remove(mTrains.get(trainIndex));
        mTrains.get(trainIndex).startTrain();
    }

    private static class InstructionParser {
        public int getIndex(final String instruction) {
            String lowerCaseInstruction = instruction.toLowerCase();
            if (!lowerCaseInstruction.startsWith("start") &&
                    !lowerCaseInstruction.startsWith("stop")) {
                System.out.println("Invalid instruction");
                throw new IllegalArgumentException("Invalid instruction provided. Cannot proceed");
            }
            return Integer.parseInt(lowerCaseInstruction.split(" ")[1]);
        }
    }

    private static class Train extends Thread {
        private final int mSpeed;
        private boolean mIsRunning;
        private int mDistance = 0;
        private int dummyLooper = 0;
        private boolean mIsInitialized;

        public Train(String name, int speed) {
            super(name);
            mSpeed = speed;
        }

        @Override
        public void run() {
            while (true) {
                dummyLooper++; // dummyLooper is just to keep this thread from becoming No-op when mIsRunning is false.
                while (mIsRunning) {
                    dummyLooper = 0;
                    try {
                        // The train runs at mSpeed units per second.
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    mDistance += mSpeed;
                }
                if (dummyLooper > 0) {
                    mIsRunning = false;
                }
            }
        }

        public int getDistance() {
            return mDistance;
        }

        public int getSpeed() {
            return mSpeed;
        }

        public boolean isRunning() {
            return mIsRunning;
        }

        /**
         * Sets the mIsRunning to true starts this thread.
         */
        public void startTrain() {
            mIsRunning = true;
            // Calling start always causes {@link IllegalThreadStateException}. Hence mIsInitialized is used as a check.
            if (!mIsInitialized) {
                mIsInitialized = true;
                start();
            }
        }

        public void stopTrain() {
            mIsRunning = false;
        }

        public void printCurrentState() {
            if (mIsRunning) {
                System.out.println(getName() + " is running and has reached " + mDistance);
            } else {
                System.out.println(getName() + " is stopped and has reached " + mDistance);
            }
        }
    }
}

Saturday, January 25, 2020

Introduction to Template and Function Pointer in C++



#include <iostream>

using namespace std;

template<typename T>
bool ascending(T a, T b) {
    return a > b;
}

template<typename T>
bool descending(T a, T b) {
    return a < b;
}

template<typename T>
void sort(T *p, int size, bool (*f)(T a, T b)) {
    for (int i = 0; i < size; i++) {
        for(int j = i; j < size; j++) {
            if (f(p[i], p[j])) {
                swap(p[i], p[j]);
            }
        }
    }
}

template<typename T>
void swap(T *a, T *b) {
    T temp = *a;
    *a = *b;
    *b = temp;
}

template<typename T>
void print(T* q, int size) {
    for(int i = 0; i < size; i++) {
        cout<<q[i]<<" ";
    }
    cout<<endl;
}

void expSwap(int *a, int *b) {
    int t = *a;
    *a = *b;
    *b = t;
}

int main()
{
    int i = 10, j = 20;
    expSwap(&i, &j);
    cout<<i<<" "<<j<<endl;
    int a = 0, b = 1;
    swap(a, b);
    cout<<a<<" "<<b<<endl;
    double c = 1.05, d = 2.05;
    swap(c, d);
    cout<<c<<" "<<d<<endl;
    int A[] = {5, 1, 2, 3, 4};
    print(A, 5);
    sort(A, 5, ascending);
    print(A, 5);
    sort(A, 5, descending);
    print(A, 5);
    char C[] = {'e', 'a', 'b', 'c', 'd'};
    print(C, 5);
    sort(C, 5, ascending);
    print(C, 5);
    sort(C, 5, descending);
    print(C, 5);
    double D[] = {5.05, 1.01, 2.02, 3.03, 4.04};
    print(D, 5);
    sort(D, 5, ascending);
    print(D, 5);
    sort(D, 5, descending);
    print(D, 5);
    return 0;
}

Saturday, June 2, 2018

Alexa Skill Shopping List- Python

The following Python code asks for user consent to access the Alexa Shopping List.
Once permission is granted in the companion app, the skill can get the items in customer's Shopping List and add items to the Shopping List.
def build_speechlet_response(title, output, reprompt_text, should_end_session):
    return {
        'outputSpeech': {
            'type': 'PlainText',
            'text': output
        },
        'card': {
            'type': 'Simple',
            'title': "SessionSpeechlet - " + title,
            'content': "SessionSpeechlet - " + output
        },
        'reprompt': {
            'outputSpeech': {
                'type': 'PlainText',
                'text': reprompt_text
            }
        },
        'shouldEndSession': should_end_session
    }

def build_permissions_consent_response(title, output, reprompt_text, should_end_session):
    return {
        'outputSpeech': {
            'type': 'PlainText',
            'text': output
        },
        'card': {
            'type': 'AskForPermissionsConsent',
            'permissions': [
           "read::alexa:household:list",
     "write::alexa:household:list"
     ]
        },
        '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
    }

def handle_get_shopping_list_intent(intent, session, context):
    session_attributes = {}
    if "attributes" in session and "userInfo" in session["attributes"]:
        session_attributes["userInfo"] = session["attributes"]["userInfo"]
    card_title = "Get Shopping List Intent"
    reprompt_text = "Please ask me product question"
    should_end_session = False
    try:
        url = "https://api.amazonalexa.com:443/v2/householdlists/"
        request = urllib2.Request(url, \
                  headers = {"Authorization": "Bearer " + context["System"]["apiAccessToken"]})
        response = json.loads(urllib2.urlopen(request).read())
        alexaList = response["lists"]
        shoppingList = {}
        for item in response["lists"]:
            print(item)
            if item["name"] == "Alexa shopping list":
                shoppingList = item
        print(shoppingList)
        url = "https://api.amazonalexa.com:443"
        for item in shoppingList["statusMap"]:
            if item["status"] == "active":
                url += item["href"]
        request = urllib2.Request(url, \
                  headers = {"Authorization": "Bearer " + context["System"]["apiAccessToken"]})
        response = json.loads(urllib2.urlopen(request).read())
        print(response)
        if len(response["items"]) == 0:
            speech_output = "Currently there are no items in your Alexa Shopping List"
        else:
            item_set = Set([])
            speech_output = "Currently the following items are in your Alexa Shopping List: "
            for i in range(0, len(response["items"])):
                item_set.add(response["items"][i]["value"])
            for item in item_set:
                speech_output += item + ", "
    except urllib2.HTTPError as err:
        if err.code == 403:
            speech_output = "Please grant shopping list permissions to this skill in your Alexa app."
            return build_response({}, build_permissions_consent_response(
        card_title, speech_output, reprompt_text, should_end_session))
        else:
            speech_output = "Something went wrong while getting your shopping list"
    except:
        speech_output = "Something went wrong while getting your shopping list"
    return build_response({}, build_speechlet_response(
        card_title, speech_output, reprompt_text, should_end_session))

def handle_add_shopping_list_intent(intent, session, context):
    session_attributes = {}
    if "attributes" in session and "userInfo" in session["attributes"]:
        session_attributes["userInfo"] = session["attributes"]["userInfo"]
    card_title = "Add to Shopping List Intent"
    reprompt_text = "Please ask me product question"
    should_end_session = False
    if "value" not in intent["slots"]["product"]:
        return build_response(session_attributes, build_speechlet_response_with_directive_nointent())
    product_name = intent["slots"]["product"]["value"]
    product_name = spell_check(product_name)
    try:
        url = "https://api.amazonalexa.com:443/v2/householdlists/"
        request = urllib2.Request(url, \
                  headers = {"Authorization": "Bearer " + context["System"]["apiAccessToken"]})
        response = json.loads(urllib2.urlopen(request).read())
        alexaList = response["lists"]
        shoppingList = {}
        for item in response["lists"]:
            print(item)
            if item["name"] == "Alexa shopping list":
                shoppingList = item
        print(shoppingList)
        url = "https://api.amazonalexa.com:443"
        for item in shoppingList["statusMap"]:
            if item["status"] == "active":
                href = item["href"].replace("active", "items")
                url += href
        print(url)
        data = {"value": product_name, "status": "active"}
        #data = urllib.urlencode(data)
        request = urllib2.Request(url)
        headers = {"Authorization": "Bearer " + context["System"]["apiAccessToken"], "Content-Type": "application/json"}
        request.add_header("Content-Type", "application/json")
        request.add_header("Authorization", "Bearer " + context["System"]["apiAccessToken"])
        result = urllib2.urlopen(request, json.dumps(data))
        response = json.loads(result.read())
        print(response)
        if result.getcode() >= 200 and result.getcode() < 300:
            speech_output = product_name + " is added to your Alexa Shopping List"
        else:
            speech_output = "Something went wrong while adding " + product_name + " to your Shopping List"
    except urllib2.HTTPError as err:
        if err.code == 403:
            speech_output = "Please grant shopping list permissions to this skill in your Alexa app."
            return build_response({}, build_permissions_consent_response(
        card_title, speech_output, reprompt_text, should_end_session))
        else:
            speech_output = "Something went wrong while adding " + product_name + " to your shopping list"
    except:
        speech_output = "Something went wrong while adding " + product_name + " to your Shopping List"
    return build_response({}, build_speechlet_response(
        card_title, speech_output, reprompt_text, should_end_session))

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

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

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

    # Dispatch to your skill's intent handlers
    if intent_name == "GetShoppingListIntent":
        return handle_get_shopping_list_intent(intent, session, context)
    elif intent_name == "AddToShoppingList":
        return handle_add_shopping_list_intent(intent, session, context)


# --------------- Main handler ------------------

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.[unique-value-here]"):
    #     raise ValueError("Invalid Application ID")

    

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


Alexa Skill Account Linking- Python

For setting up account linking in Alexa Skill, follow the steps here.
Once setup is done, and intent handler needs to be implemented in the Python code: 

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

def build_user_authentication_response():
    return {
        "version": "1.0",
        "response": {
            "outputSpeech": {
                "type": "PlainText",
                "text": " Please use the companion app to authenticate on Amazon to start using this skill"
            },
            "card": {
                "type": "LinkAccount"
            },
            "shouldEndSession": false
        },
        "sessionAttributes": {}
    }

# --------------- Method that gets called when there is an intent request ----------------------

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

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

    intent = intent_request['intent']
    intent_name = intent_request['intent']['name']
    if intent_name == "SayHello":
        return build_user_authentication_response()


# --------------- Main handler ------------------

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.[unique-value-here]"):
    #     raise ValueError("Invalid Application ID")

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

This will open a Login with Amazon screen where customers can sign in using their Amazon Account Credentials. Once logged-in successfully, the account is linked and next time onwards the user token comes as part of the session request.

Sample Request after Account Linking:

{
    "version": "1.0",
    "session": {
        "new": true,
        "sessionId": "session-id",
        "application": {
            "applicationId": "application-id"
        },
        "user": {
            "userId": "user-id",
            "accessToken": "access-token",
            "permissions": {
                "consentToken": "consent-token"
            }
        }
    },
    "context": {
        "AudioPlayer": {
            "playerActivity": "IDLE"
        },
        "Display": {},
        "System": {
            "application": {
                "applicationId": "application-id"
            },
            "user": {
                "userId": "user-id",
                "accessToken": "access-token",
                "permissions": {
                    "consentToken": "consent-token"
                }
            },
            "device": {
                "deviceId": "device-id",
                "supportedInterfaces": {
                    "AudioPlayer": {},
                    "Display": {
                        "templateVersion": "1.0",
                        "markupVersion": "1.0"
                    }
                }
            },
            "apiEndpoint": "https://api.eu.amazonalexa.com",
            "apiAccessToken": "api-access-token"
        }
    },
    "request": {
        "type": "LaunchRequest",
        "requestId": "request-id",
        "timestamp": "2018-06-03T05:22:36Z",
        "locale": "en-US",
        "shouldLinkResultBeReturned": false
    }
}