Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

task 1 - 5 #37

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
282 changes: 167 additions & 115 deletions src/chatbot.cpp
Original file line number Diff line number Diff line change
@@ -1,148 +1,200 @@
#include <iostream>
#include <random>
#include <algorithm>
#include <ctime>
#include <iostream>
#include <random>

#include "chatbot.h"
#include "chatlogic.h"
#include "graphnode.h"
#include "graphedge.h"
#include "chatbot.h"
#include "graphnode.h"

// constructor WITHOUT memory allocation
ChatBot::ChatBot()
{
// invalidate data handles
_image = nullptr;
_chatLogic = nullptr;
_rootNode = nullptr;
ChatBot::ChatBot() {
// invalidate data handles
_image = NULL;
_rootNode = nullptr;
_chatLogic = nullptr;
}

// constructor WITH memory allocation
ChatBot::ChatBot(std::string filename)
{
std::cout << "ChatBot Constructor" << std::endl;

// invalidate data handles
_chatLogic = nullptr;
_rootNode = nullptr;

// load image into heap memory
_image = new wxBitmap(filename, wxBITMAP_TYPE_PNG);
ChatBot::ChatBot(std::string filename) {
std::cout << "ChatBot Constructor" << std::endl;

// invalidate data handles
_chatLogic = nullptr;
_rootNode = nullptr;

// load image into heap memory
_image = new wxBitmap(filename, wxBITMAP_TYPE_PNG);
}

ChatBot::~ChatBot()
{
std::cout << "ChatBot Destructor" << std::endl;
ChatBot::~ChatBot() {
std::cout << "ChatBot Destructor" << std::endl;

// deallocate heap memory
if(_image != NULL) // Attention: wxWidgets used NULL and not nullptr
{
delete _image;
_image = NULL;
}
// deallocate heap memory
if (_image != NULL) // Attention: wxWidgets used NULL and not nullptr
{
delete _image;
_image = NULL;
}
}

//// STUDENT CODE
////

// copy ctr
ChatBot::ChatBot(const ChatBot &source) {
std::cout << "copy ctor @ChatBot" << std::endl;

_image = new wxBitmap(*source._image);
_rootNode = source._rootNode;
_chatLogic = source._chatLogic;
}

// copy assignment
ChatBot &ChatBot::operator=(const ChatBot &source) {
std::cout << "copy assignment @ChatBot" << std::endl;
if (this == &source) {
return *this;
}
delete _image;
_image = new wxBitmap(*source._image);
_rootNode = source._rootNode;
_chatLogic = source._chatLogic;

return *this;
}

// move ctr
ChatBot::ChatBot(ChatBot &&source) {
std::cout << "move ctor @ChatBot" << std::endl;
_image = source._image;
_rootNode = source._rootNode;
_chatLogic = source._chatLogic;
source._image = NULL;
source._rootNode = nullptr;
source._chatLogic = nullptr;
}

// move assignment
ChatBot &ChatBot::operator=(ChatBot &&source) {
std::cout << "move assignment @ChatBot" << std::endl;
// if (this == &source) {
// return *this;
// }
// delete _image;
// _image = source._image;
// _rootNode = source._rootNode;
// _chatLogic = source._chatLogic;
// reset();
// swap(source);
// source._image = NULL;
// source._rootNode = nullptr;
// source._chatLogic = nullptr;
ChatBot tmp(std::move(source));
swap(tmp);

return *this;
}

void ChatBot::swap(ChatBot &other) {
std::swap(_image, other._image);
std::swap(_rootNode, other._rootNode);
std::swap(_chatLogic, other._chatLogic);
}

////
//// EOF STUDENT CODE

void ChatBot::ReceiveMessageFromUser(std::string message)
{
// loop over all edges and keywords and compute Levenshtein distance to query
typedef std::pair<GraphEdge *, int> EdgeDist;
std::vector<EdgeDist> levDists; // format is <ptr,levDist>

for (size_t i = 0; i < _currentNode->GetNumberOfChildEdges(); ++i)
{
GraphEdge *edge = _currentNode->GetChildEdgeAtIndex(i);
for (auto keyword : edge->GetKeywords())
{
EdgeDist ed{edge, ComputeLevenshteinDistance(keyword, message)};
levDists.push_back(ed);
}
}
void ChatBot::ReceiveMessageFromUser(std::string message) {
// loop over all edges and keywords and compute Levenshtein distance to query
typedef std::pair<GraphEdge *, int> EdgeDist;
std::vector<EdgeDist> levDists; // format is <ptr,levDist>

// select best fitting edge to proceed along
GraphNode *newNode;
if (levDists.size() > 0)
{
// sort in ascending order of Levenshtein distance (best fit is at the top)
std::sort(levDists.begin(), levDists.end(), [](const EdgeDist &a, const EdgeDist &b) { return a.second < b.second; });
newNode = levDists.at(0).first->GetChildNode(); // after sorting the best edge is at first position
}
else
{
// go back to root node
newNode = _rootNode;
for (size_t i = 0; i < _currentNode->GetNumberOfChildEdges(); ++i) {
GraphEdge *edge = _currentNode->GetChildEdgeAtIndex(i);
for (auto keyword : edge->GetKeywords()) {
EdgeDist ed{edge, ComputeLevenshteinDistance(keyword, message)};
levDists.push_back(ed);
}

// tell current node to move chatbot to new node
_currentNode->MoveChatbotToNewNode(newNode);
}

// select best fitting edge to proceed along
GraphNode *newNode;
if (levDists.size() > 0) {
// sort in ascending order of Levenshtein distance (best fit is at the top)
std::sort(levDists.begin(), levDists.end(),
[](const EdgeDist &a, const EdgeDist &b) {
return a.second < b.second;
});
newNode = levDists.at(0).first->GetChildNode(); // after sorting the best
// edge is at first position
} else {
// go back to root node
newNode = _rootNode;
}

// tell current node to move chatbot to new node
_currentNode->MoveChatbotToNewNode(newNode);
}

void ChatBot::SetCurrentNode(GraphNode *node)
{
// update pointer to current node
_currentNode = node;
void ChatBot::SetCurrentNode(GraphNode *node) {
// update pointer to current node
_currentNode = node;

// select a random node answer (if several answers should exist)
std::vector<std::string> answers = _currentNode->GetAnswers();
std::mt19937 generator(int(std::time(0)));
std::uniform_int_distribution<int> dis(0, answers.size() - 1);
std::string answer = answers.at(dis(generator));
// select a random node answer (if several answers should exist)
std::vector<std::string> answers = _currentNode->GetAnswers();
std::mt19937 generator(int(std::time(0)));
std::uniform_int_distribution<int> dis(0, answers.size() - 1);
std::string answer = answers.at(dis(generator));

// send selected node answer to user
_chatLogic->SendMessageToUser(answer);
_chatLogic->SetChatbotHandle(this);
// send selected node answer to user
_chatLogic->SendMessageToUser(answer);
}

int ChatBot::ComputeLevenshteinDistance(std::string s1, std::string s2)
{
// convert both strings to upper-case before comparing
std::transform(s1.begin(), s1.end(), s1.begin(), ::toupper);
std::transform(s2.begin(), s2.end(), s2.begin(), ::toupper);

// compute Levenshtein distance measure between both strings
const size_t m(s1.size());
const size_t n(s2.size());

if (m == 0)
return n;
if (n == 0)
return m;

size_t *costs = new size_t[n + 1];

for (size_t k = 0; k <= n; k++)
costs[k] = k;

size_t i = 0;
for (std::string::const_iterator it1 = s1.begin(); it1 != s1.end(); ++it1, ++i)
{
costs[0] = i + 1;
size_t corner = i;

size_t j = 0;
for (std::string::const_iterator it2 = s2.begin(); it2 != s2.end(); ++it2, ++j)
{
size_t upper = costs[j + 1];
if (*it1 == *it2)
{
costs[j + 1] = corner;
}
else
{
size_t t(upper < corner ? upper : corner);
costs[j + 1] = (costs[j] < t ? costs[j] : t) + 1;
}

corner = upper;
}
int ChatBot::ComputeLevenshteinDistance(std::string s1, std::string s2) {
// convert both strings to upper-case before comparing
std::transform(s1.begin(), s1.end(), s1.begin(), ::toupper);
std::transform(s2.begin(), s2.end(), s2.begin(), ::toupper);

// compute Levenshtein distance measure between both strings
const size_t m(s1.size());
const size_t n(s2.size());

if (m == 0)
return n;
if (n == 0)
return m;

size_t *costs = new size_t[n + 1];

for (size_t k = 0; k <= n; k++)
costs[k] = k;

size_t i = 0;
for (std::string::const_iterator it1 = s1.begin(); it1 != s1.end();
++it1, ++i) {
costs[0] = i + 1;
size_t corner = i;

size_t j = 0;
for (std::string::const_iterator it2 = s2.begin(); it2 != s2.end();
++it2, ++j) {
size_t upper = costs[j + 1];
if (*it1 == *it2) {
costs[j + 1] = corner;
} else {
size_t t(upper < corner ? upper : corner);
costs[j + 1] = (costs[j] < t ? costs[j] : t) + 1;
}

corner = upper;
}
}

int result = costs[n];
delete[] costs;
int result = costs[n];
delete[] costs;

return result;
return result;
}
Loading