HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavascriptMinor

Another JavaScript Stack Exchange chat bot

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
chatstackjavascriptexchangebotanother

Problem

I've been inspired by @SirPython's SirAlfred JavaScript chat bot, so I went and made my own. This one is slightly different though, in the fact that it can accept input in a more lenient way. For example, here's a "conversation" with the bot:

sudo make me a sandwich bot
BOT: It will be done master.
sudo make me a sandwich bot
BOT: Yes sir.
Hello there bot.
BOT: Hello there.
Goodbye bot.
BOT: Goodbye.


Essentially, instead of directly checking the contents of the string, it removes all non-alphanumeric characters, excluding spaces, and then splits on a space. It then checks to see if this split array contains certain words, and then outputs a message based on those words.

`/**
* This is a small utility function used to
* determine if an array contains a certain
* value.
* @param {array} array - The array to check for the element in.
* @param {generic} value - The value to check for.
* @returns {boolean}
*/
function arrayContains(array, value) {
return array.indexOf(value) > -1;
}

/**
* Select a random element from the array.
* @param {array} array - The array to select from.
*/
function randomArrayElement(array) {
return array[Math.floor(Math.random() * array.length)];
}

/**
* This error is thrown when sendMessage
* is called and the message length
* exceeds 400 characters.
* @constructor
* @param {string} message - The error's message.
*/
function InvalidMessageLength(message) {
this.message = message;
this.name = "InvalidMessageLength";
}

/**
* Post a message to the room.
* @param {string} messageString - The string to be posted.
*/
function sendMessage(messageString) {
if(messageString.length - 1

Finally, in order to run this, you need to open up inspect element on your browser. While in a Stack Exchange chat room, copy-paste the above source into the JavaScript console, and then hit enter.

Solution

if(arrayContains(lastMessage, "hello") && arrayContains(lastMessage, "bot")) {
    sendMessage(BOT_TEXT + RANDOM_REPLIES.helloGreeting());
}
else if(arrayContains(lastMessage, "goodbye") && arrayContains(lastMessage, "bot")) {
    sendMessage(BOT_TEXT + RANDOM_REPLIES.goodbyeGreeting());
}
else if(arrayContains(lastMessage, "sudo") && arrayContains(lastMessage, "bot")) {
    sendMessage(BOT_TEXT + RANDOM_REPLIES.sudoCommand());
}


What's the difference between these three lines? The keyword being searched for and the method being called.

Just two values? Seems like the perfect job for a map/object!

I'm assuming that you aren't going to only have these three commands for your chat bot; you're probably going to want to add more in the future.

Let's use a map/object (as I stated above) to store these commands and their keywords and functions:

var commands = {
    "hello": function() { [hello greeting] },
    "goodbye": function() { [goodbye greeting] },
    "sudo": function() { [sudo command] }
};


Now, going back to the main function, all we have to do now is iterate through the map/object and check if the key value with the keyword that you were originally passing into arrayContains.

Here is what that looks like:

var lastMessage = getLastPostedMessage().toLowerCase().replace(/[^a-zA-Z\d\s:]/g, "").split(" ");

if(arrayContains(lastMessage, "bot")) {
    for(var command in commands) {
        if(arrayContains(lastMessage, command)) {
            sendMessage(BOT_TEXT + commands[command]());
        }
    }
}


Note: I moved the arrayContains outside of the loop because you don't want to unnecessarily check if the message is a command if it isn't even addressing the bot. Credit to 3Doubloons.

I just realized this, but your RANDOM_REPLIES object could be used instead of creating that new commands map/object that I recommended. The only thing you'd have to change in that object would be the keys; you'd have to change those to the keywords.

Code Snippets

if(arrayContains(lastMessage, "hello") && arrayContains(lastMessage, "bot")) {
    sendMessage(BOT_TEXT + RANDOM_REPLIES.helloGreeting());
}
else if(arrayContains(lastMessage, "goodbye") && arrayContains(lastMessage, "bot")) {
    sendMessage(BOT_TEXT + RANDOM_REPLIES.goodbyeGreeting());
}
else if(arrayContains(lastMessage, "sudo") && arrayContains(lastMessage, "bot")) {
    sendMessage(BOT_TEXT + RANDOM_REPLIES.sudoCommand());
}
var commands = {
    "hello": function() { [hello greeting] },
    "goodbye": function() { [goodbye greeting] },
    "sudo": function() { [sudo command] }
};
var lastMessage = getLastPostedMessage().toLowerCase().replace(/[^a-zA-Z\d\s:]/g, "").split(" ");

if(arrayContains(lastMessage, "bot")) {
    for(var command in commands) {
        if(arrayContains(lastMessage, command)) {
            sendMessage(BOT_TEXT + commands[command]());
        }
    }
}

Context

StackExchange Code Review Q#95792, answer score: 6

Revisions (0)

No revisions yet.