-
Notifications
You must be signed in to change notification settings - Fork 681
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
723 additions
and
667 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} |
Oops, something went wrong.