Initial import.
This commit is contained in:
29
starter/src/answergraph.txt
Normal file
29
starter/src/answergraph.txt
Normal file
@@ -0,0 +1,29 @@
|
||||
|
||||
// define all graph nodes
|
||||
<TYPE:NODE><ID:0><ANSWER:Welcome! My name is MemBot. You can ask me about things related to memory management in C++. Possible topics are 'pointers' and 'the C++ memory model'. What would you like to talk about?>
|
||||
|
||||
<TYPE:NODE><ID:1><ANSWER:Great! Let's talk about pointers. In computer science, a pointer is a special value whose meaning is a memory address. This address can contain either data, such as variables or objects, but also program codes (instructions). By dereferencing the pointer it is possible to access the data or the code. Among other things, pointers are used to manage dynamic memory. Other topics around pointers you can ask about are 'smart pointers' and 'nullptr'>
|
||||
|
||||
<TYPE:NODE><ID:2><ANSWER:When instantiating variables, programmers can choose wether to do this on the heap, on the stack or in static memory. Do you want to know more about those two concepts? Simply ask me about 'heap', 'stack' or 'static'.>
|
||||
|
||||
<TYPE:NODE><ID:3><ANSWER:A smart pointer is an object that behaves like a pointer, i.e. it must support pointer operations such as dereferencing or indirect access. In addition to these properties, the smart pointer handles resources better. In concrete terms, this means that it takes care not to cause a memory leak. A smart pointer exists in various flavors, which are unique_ptr, shared_ptr and weak_ptr. There are no more topics in this section, starting over!>
|
||||
|
||||
<TYPE:NODE><ID:4><ANSWER:The value nullptr can be assigned to pointers of any type. This turns the pointer into a null pointer that does not point to a memory location. The nullptr keyword can be used to test if a pointer or handle reference is null before the reference is used. There are no more topics in this section, starting over!>
|
||||
|
||||
<TYPE:NODE><ID:5><ANSWER:Local variables declared as part of a function are stored on the stack. Also, the stack is the place where function parameters are stored. Further, the stack is used for storing the return address of the calling functions, and it keeps the register contents and return address when an interrupt service routine is called. -- There are no more topics in this section, starting over!>
|
||||
|
||||
<TYPE:NODE><ID:6><ANSWER:Heap memory, also known as dynamic memory, is an alternative to local stack memory. Local memory is allocated automatically on function call and it is deallocated automatically when a function exits. Heap memory is different. The programmer explicitly requests the allocation of a memory block of a particular size, and the block continues to be allocated until the programmer explicitly requests that it be deallocated. -- There are no more topics in this section, starting over!>
|
||||
|
||||
<TYPE:NODE><ID:7><ANSWER:Static memory persists throughout the entire life of the program, and is usually used to store things like global variables, or variables created with the static clause. -- There are no more topics in this section, starting over!>
|
||||
|
||||
|
||||
// connect nodes with edges
|
||||
<TYPE:EDGE><ID:0><PARENT:0><CHILD:1><KEYWORD:pointer><KEYWORD:smart pointer>
|
||||
<TYPE:EDGE><ID:1><PARENT:0><CHILD:2><KEYWORD:memory model><KEYWORD:heap><KEYWORD:stack>
|
||||
|
||||
<TYPE:EDGE><ID:2><PARENT:1><CHILD:3><KEYWORD:unique pointer><KEYWORD:shared pointer><KEYWORD:weak pointer>
|
||||
<TYPE:EDGE><ID:3><PARENT:1><CHILD:4><KEYWORD:NULL><KEYWORD:null pointer><KEYWORD:nullptr>
|
||||
|
||||
<TYPE:EDGE><ID:4><PARENT:2><CHILD:5><KEYWORD:stack><KEYWORD:stack memory><KEYWORD:local variable storage>
|
||||
<TYPE:EDGE><ID:5><PARENT:2><CHILD:6><KEYWORD:heap><KEYWORD:heap memory><KEYWORD:dynamic storage>
|
||||
<TYPE:EDGE><ID:6><PARENT:2><CHILD:7><KEYWORD:static><KEYWORD:static memory><KEYWORD:global variable storage>
|
||||
134
starter/src/chatbot.cpp
Normal file
134
starter/src/chatbot.cpp
Normal file
@@ -0,0 +1,134 @@
|
||||
#include <iostream>
|
||||
#include <random>
|
||||
#include <algorithm>
|
||||
#include <ctime>
|
||||
|
||||
#include "chatlogic.h"
|
||||
#include "graphnode.h"
|
||||
#include "graphedge.h"
|
||||
#include "chatbot.h"
|
||||
|
||||
// constructor WITHOUT memory allocation
|
||||
ChatBot::ChatBot()
|
||||
{
|
||||
std::cerr << ">>> Rule of Five Component: ChatBot Default Constructor <<<" << std::endl;
|
||||
_chatLogic = nullptr;
|
||||
_rootNode = nullptr;
|
||||
}
|
||||
|
||||
// TODO the following:
|
||||
// TODO: add copy constructor
|
||||
// TODO: add copy assignment operator
|
||||
// TODO: add move constructor
|
||||
// TODO: add move assignment operator
|
||||
// END OF TODO
|
||||
|
||||
ChatBot::~ChatBot()
|
||||
{
|
||||
std::cerr << ">>> Rule of Five Component: ChatBot Destructor <<<" << std::endl;
|
||||
}
|
||||
|
||||
void ChatBot::ReceiveMessageFromUser(std::string message)
|
||||
{
|
||||
typedef std::pair<GraphEdge *, int> EdgeDist;
|
||||
std::vector<EdgeDist> levDists;
|
||||
std::vector<GraphEdge *> keywordMatches;
|
||||
std::string userInputLower = message;
|
||||
std::transform(userInputLower.begin(), userInputLower.end(), userInputLower.begin(), ::tolower);
|
||||
// First, check for direct keyword containment (case-insensitive)
|
||||
for (size_t i = 0; i < _currentNode->GetNumberOfChildEdges(); ++i)
|
||||
{
|
||||
GraphEdge *edge = _currentNode->GetChildEdgeAtIndex(i);
|
||||
for (auto keyword : edge->GetKeywords())
|
||||
{
|
||||
std::string keywordLower = keyword;
|
||||
std::transform(keywordLower.begin(), keywordLower.end(), keywordLower.begin(), ::tolower);
|
||||
if (userInputLower.find(keywordLower) != std::string::npos) {
|
||||
keywordMatches.push_back(edge);
|
||||
break; // Only need one keyword match per edge
|
||||
}
|
||||
}
|
||||
}
|
||||
GraphNode *newNode = nullptr;
|
||||
if (!keywordMatches.empty()) {
|
||||
// If multiple matches, pick the first (or could add more logic)
|
||||
newNode = keywordMatches[0]->GetChildNode();
|
||||
} else {
|
||||
// Fall back to Levenshtein distance
|
||||
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);
|
||||
}
|
||||
}
|
||||
if (levDists.size() > 0)
|
||||
{
|
||||
std::sort(levDists.begin(), levDists.end(), [](const EdgeDist &a, const EdgeDist &b) { return a.second < b.second; });
|
||||
newNode = levDists.at(0).first->GetChildNode();
|
||||
}
|
||||
else
|
||||
{
|
||||
newNode = _rootNode;
|
||||
}
|
||||
}
|
||||
_currentNode->MoveChatbotToNewNode(newNode);
|
||||
}
|
||||
|
||||
void ChatBot::SetCurrentNode(GraphNode *node)
|
||||
{
|
||||
_currentNode = node;
|
||||
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));
|
||||
_chatLogic->SendMessageToUser(answer);
|
||||
// If the answer contains the reset message, reset to root and print the root answer
|
||||
if (answer.find("There are no more topics in this section, starting over!") != std::string::npos) {
|
||||
if (_currentNode != _rootNode) {
|
||||
_currentNode->MoveChatbotToNewNode(_rootNode);
|
||||
// The move will call SetCurrentNode on the root node, which will print the welcome message.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int ChatBot::ComputeLevenshteinDistance(std::string s1, std::string s2)
|
||||
{
|
||||
std::transform(s1.begin(), s1.end(), s1.begin(), ::toupper);
|
||||
std::transform(s2.begin(), s2.end(), s2.begin(), ::toupper);
|
||||
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;
|
||||
return result;
|
||||
}
|
||||
42
starter/src/chatbot.h
Normal file
42
starter/src/chatbot.h
Normal file
@@ -0,0 +1,42 @@
|
||||
#ifndef CHATBOT_H_
|
||||
#define CHATBOT_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
class GraphNode; // forward declaration
|
||||
class ChatLogic; // forward declaration
|
||||
|
||||
class ChatBot
|
||||
{
|
||||
private:
|
||||
// data handles (not owned)
|
||||
GraphNode *_currentNode;
|
||||
GraphNode *_rootNode;
|
||||
ChatLogic *_chatLogic;
|
||||
|
||||
// proprietary functions
|
||||
int ComputeLevenshteinDistance(std::string s1, std::string s2);
|
||||
|
||||
public:
|
||||
// constructors / destructors
|
||||
ChatBot(); // constructor
|
||||
ChatBot(std::string filename); // constructor (filename is ignored in CLI)
|
||||
~ChatBot();
|
||||
|
||||
// TODO the following:
|
||||
// TODO: add copy constructor
|
||||
// TODO: add copy assignment operator
|
||||
// TODO: add move constructor
|
||||
// TODO: add move assignment operator
|
||||
// END OF TODO
|
||||
|
||||
// getters / setters
|
||||
void SetCurrentNode(GraphNode *node);
|
||||
void SetRootNode(GraphNode *rootNode) { _rootNode = rootNode; }
|
||||
void SetChatLogicHandle(ChatLogic *chatLogic) { _chatLogic = chatLogic; }
|
||||
|
||||
// communication
|
||||
void ReceiveMessageFromUser(std::string message);
|
||||
};
|
||||
|
||||
#endif /* CHATBOT_H_ */
|
||||
225
starter/src/chatlogic.cpp
Normal file
225
starter/src/chatlogic.cpp
Normal file
@@ -0,0 +1,225 @@
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <iterator>
|
||||
#include <tuple>
|
||||
#include <algorithm>
|
||||
|
||||
#include "graphedge.h"
|
||||
#include "graphnode.h"
|
||||
#include "chatbot.h"
|
||||
#include "chatlogic.h"
|
||||
|
||||
ChatLogic::ChatLogic()
|
||||
{
|
||||
_chatBot = new ChatBot();
|
||||
_chatBot->SetChatLogicHandle(this);
|
||||
}
|
||||
|
||||
ChatLogic::~ChatLogic()
|
||||
{
|
||||
|
||||
delete _chatBot;
|
||||
|
||||
// delete all nodes
|
||||
for (auto it = std::begin(_nodes); it != std::end(_nodes); ++it)
|
||||
{
|
||||
delete *it;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void ChatLogic::AddAllTokensToElement(std::string tokenID, tokenlist &tokens, T &element)
|
||||
{
|
||||
// find all occurences for current node
|
||||
auto token = tokens.begin();
|
||||
while (true)
|
||||
{
|
||||
token = std::find_if(token, tokens.end(), [&tokenID](const std::pair<std::string, std::string> &pair) { return pair.first == tokenID;; });
|
||||
if (token != tokens.end())
|
||||
{
|
||||
element.AddToken(token->second); // add new keyword to edge
|
||||
token++; // increment iterator to next element
|
||||
}
|
||||
else
|
||||
{
|
||||
break; // quit infinite while-loop
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ChatLogic::LoadAnswerGraphFromFile(std::string filename)
|
||||
{
|
||||
// load file with answer graph elements
|
||||
std::ifstream file(filename);
|
||||
|
||||
// check for file availability and process it line by line
|
||||
if (file)
|
||||
{
|
||||
// loop over all lines in the file
|
||||
std::string lineStr;
|
||||
while (getline(file, lineStr))
|
||||
{
|
||||
// extract all tokens from current line
|
||||
tokenlist tokens;
|
||||
while (lineStr.size() > 0)
|
||||
{
|
||||
// extract next token
|
||||
int posTokenFront = lineStr.find("<");
|
||||
int posTokenBack = lineStr.find(">");
|
||||
if (posTokenFront < 0 || posTokenBack < 0)
|
||||
break; // quit loop if no complete token has been found
|
||||
std::string tokenStr = lineStr.substr(posTokenFront + 1, posTokenBack - 1);
|
||||
|
||||
// extract token type and info
|
||||
int posTokenInfo = tokenStr.find(":");
|
||||
if (posTokenInfo != std::string::npos)
|
||||
{
|
||||
std::string tokenType = tokenStr.substr(0, posTokenInfo);
|
||||
std::string tokenInfo = tokenStr.substr(posTokenInfo + 1, tokenStr.size() - 1);
|
||||
|
||||
// add token to vector
|
||||
tokens.push_back(std::make_pair(tokenType, tokenInfo));
|
||||
}
|
||||
|
||||
// remove token from current line
|
||||
lineStr = lineStr.substr(posTokenBack + 1, lineStr.size());
|
||||
}
|
||||
|
||||
// process tokens for current line
|
||||
auto type = std::find_if(tokens.begin(), tokens.end(), [](const std::pair<std::string, std::string> &pair) { return pair.first == "TYPE"; });
|
||||
if (type != tokens.end())
|
||||
{
|
||||
// check for id
|
||||
auto idToken = std::find_if(tokens.begin(), tokens.end(), [](const std::pair<std::string, std::string> &pair) { return pair.first == "ID"; });
|
||||
if (idToken != tokens.end())
|
||||
{
|
||||
// extract id from token
|
||||
int id = std::stoi(idToken->second);
|
||||
|
||||
// node-based processing
|
||||
if (type->second == "NODE")
|
||||
{
|
||||
// check if node with this ID exists already
|
||||
auto newNode = std::find_if(_nodes.begin(), _nodes.end(), [&id](GraphNode *node) { return node->GetID() == id; }); // TODO
|
||||
|
||||
// create new element if ID does not yet exist
|
||||
if (newNode == _nodes.end())
|
||||
{
|
||||
_nodes.emplace_back(new GraphNode(id)); // TODO
|
||||
newNode = _nodes.end() - 1; // get iterator to last element
|
||||
|
||||
// add all answers to current node
|
||||
AddAllTokensToElement("ANSWER", tokens, **newNode);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// edge-based processing
|
||||
if (type->second == "EDGE")
|
||||
{
|
||||
//// STUDENT CODE
|
||||
////
|
||||
|
||||
// find tokens for incoming (parent) and outgoing (child) node
|
||||
auto parentToken = std::find_if(tokens.begin(), tokens.end(), [](const std::pair<std::string, std::string> &pair) { return pair.first == "PARENT"; });
|
||||
auto childToken = std::find_if(tokens.begin(), tokens.end(), [](const std::pair<std::string, std::string> &pair) { return pair.first == "CHILD"; });
|
||||
|
||||
if (parentToken != tokens.end() && childToken != tokens.end())
|
||||
{
|
||||
// get iterator on incoming and outgoing node via ID search
|
||||
auto parentNode = std::find_if(_nodes.begin(), _nodes.end(), [&parentToken](GraphNode *node) { return node->GetID() == std::stoi(parentToken->second); }); // TODO
|
||||
auto childNode = std::find_if(_nodes.begin(), _nodes.end(), [&childToken](GraphNode *node) { return node->GetID() == std::stoi(childToken->second); }); // TODO
|
||||
|
||||
// TODO: create new edge
|
||||
GraphEdge *edge = new GraphEdge(id);
|
||||
edge->SetChildNode(*childNode);
|
||||
edge->SetParentNode(*parentNode);
|
||||
//_edges.push_back(edge);
|
||||
// END OF TODO
|
||||
|
||||
// find all keywords for current node
|
||||
AddAllTokensToElement("KEYWORD", tokens, *edge);
|
||||
|
||||
// TODO: store reference in child node and parent node
|
||||
(*childNode)->AddEdgeToParentNode(edge); // TODO: add non-owning reference
|
||||
(*parentNode)->AddEdgeToChildNode(edge); // TODO: transfer ownership to parent node
|
||||
// END OF TODO
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Error: ID missing. Line is ignored!" << std::endl;
|
||||
}
|
||||
}
|
||||
} // eof loop over all lines in the file
|
||||
|
||||
file.close();
|
||||
|
||||
} // eof check for file availability
|
||||
else
|
||||
{
|
||||
std::cout << "File could not be opened!" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
//// STUDENT CODE
|
||||
////
|
||||
|
||||
// identify root node
|
||||
GraphNode *rootNode = nullptr;
|
||||
for (auto it = std::begin(_nodes); it != std::end(_nodes); ++it)
|
||||
{
|
||||
// search for nodes which have no incoming edges
|
||||
if ((*it)->GetNumberOfParents() == 0)
|
||||
{
|
||||
|
||||
if (rootNode == nullptr)
|
||||
{
|
||||
// assign current node to root
|
||||
rootNode = *it; // TODO: assign current node to root
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "ERROR : Multiple root nodes detected" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: add chatbot to graph root node
|
||||
_chatBot->SetRootNode(rootNode);
|
||||
rootNode->moveChatbotHere(_chatBot);
|
||||
// END OF TODO
|
||||
|
||||
}
|
||||
|
||||
#ifdef GUI_APP
|
||||
void ChatLogic::SetPanelDialogHandle(ChatBotPanelDialog *panelDialog)
|
||||
{
|
||||
_panelDialog = panelDialog;
|
||||
}
|
||||
|
||||
void ChatLogic::SendMessageToUser(std::string message)
|
||||
{
|
||||
_panelDialog->PrintChatbotResponse(message);
|
||||
}
|
||||
#else
|
||||
void ChatLogic::SetPanelDialogHandle(ChatBotPanelDialog *panelDialog) {}
|
||||
void ChatLogic::SendMessageToUser(std::string message) {}
|
||||
|
||||
void ChatLogic::SetChatbotHandle(ChatBot *chatbot) {
|
||||
_chatBot = chatbot;
|
||||
}
|
||||
|
||||
void ChatLogic::SendMessageToChatbot(std::string message) {
|
||||
if (_chatBot) {
|
||||
_chatBot->ReceiveMessageFromUser(message);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bool ChatLogic::IsGraphLoaded() const {
|
||||
return !_nodes.empty();
|
||||
}
|
||||
49
starter/src/chatlogic.h
Normal file
49
starter/src/chatlogic.h
Normal file
@@ -0,0 +1,49 @@
|
||||
#ifndef CHATLOGIC_H_
|
||||
#define CHATLOGIC_H_
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
// #include "chatgui.h" // Removed for CLI decoupling
|
||||
|
||||
// forward declarations
|
||||
class ChatBot;
|
||||
class GraphEdge;
|
||||
class GraphNode;
|
||||
class ChatBotPanelDialog; // Forward declaration for GUI compatibility (deprecated)
|
||||
|
||||
class ChatLogic
|
||||
{
|
||||
private:
|
||||
// data handles (owned)
|
||||
std::vector<GraphNode *> _nodes; // TODO
|
||||
|
||||
// data handles (not owned)
|
||||
GraphNode *_currentNode;
|
||||
ChatBot *_chatBot;
|
||||
ChatBotPanelDialog *_panelDialog;
|
||||
|
||||
// proprietary type definitions
|
||||
typedef std::vector<std::pair<std::string, std::string>> tokenlist;
|
||||
|
||||
// proprietary functions
|
||||
template <typename T>
|
||||
void AddAllTokensToElement(std::string tokenID, tokenlist &tokens, T &element);
|
||||
|
||||
public:
|
||||
// constructor / destructor
|
||||
ChatLogic();
|
||||
~ChatLogic();
|
||||
|
||||
// getter / setter
|
||||
void SetPanelDialogHandle(ChatBotPanelDialog *panelDialog);
|
||||
void SetChatbotHandle(ChatBot *chatbot);
|
||||
|
||||
// proprietary functions
|
||||
void LoadAnswerGraphFromFile(std::string filename);
|
||||
void SendMessageToChatbot(std::string message);
|
||||
virtual void SendMessageToUser(std::string message);
|
||||
bool IsGraphLoaded() const;
|
||||
};
|
||||
|
||||
#endif /* CHATLOGIC_H_ */
|
||||
22
starter/src/graphedge.cpp
Normal file
22
starter/src/graphedge.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
#include "graphnode.h"
|
||||
#include "graphedge.h"
|
||||
|
||||
GraphEdge::GraphEdge(int id)
|
||||
{
|
||||
_id = id;
|
||||
}
|
||||
|
||||
void GraphEdge::SetChildNode(GraphNode *childNode)
|
||||
{
|
||||
_childNode = childNode;
|
||||
}
|
||||
|
||||
void GraphEdge::SetParentNode(GraphNode *parentNode)
|
||||
{
|
||||
_parentNode = parentNode;
|
||||
}
|
||||
|
||||
void GraphEdge::AddToken(std::string token)
|
||||
{
|
||||
_keywords.push_back(token);
|
||||
}
|
||||
36
starter/src/graphedge.h
Normal file
36
starter/src/graphedge.h
Normal file
@@ -0,0 +1,36 @@
|
||||
#ifndef GRAPHEDGE_H_
|
||||
#define GRAPHEDGE_H_
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
class GraphNode; // forward declaration
|
||||
|
||||
class GraphEdge
|
||||
{
|
||||
private:
|
||||
// data handles (not owned)
|
||||
GraphNode *_childNode;
|
||||
GraphNode *_parentNode;
|
||||
|
||||
// proprietary members
|
||||
int _id;
|
||||
std::vector<std::string> _keywords; // list of topics associated with this edge
|
||||
|
||||
|
||||
public:
|
||||
// constructor / desctructor
|
||||
GraphEdge(int id);
|
||||
|
||||
// getter / setter
|
||||
int GetID() { return _id; }
|
||||
void SetChildNode(GraphNode *childNode);
|
||||
void SetParentNode(GraphNode *parentNode);
|
||||
GraphNode *GetChildNode() { return _childNode; }
|
||||
std::vector<std::string> GetKeywords() { return _keywords; }
|
||||
|
||||
// proprietary functions
|
||||
void AddToken(std::string token);
|
||||
};
|
||||
|
||||
#endif /* GRAPHEDGE_H_ */
|
||||
46
starter/src/graphnode.cpp
Normal file
46
starter/src/graphnode.cpp
Normal file
@@ -0,0 +1,46 @@
|
||||
#include "chatbot.h"
|
||||
#include "graphedge.h"
|
||||
#include "graphnode.h"
|
||||
|
||||
GraphNode::GraphNode(int id)
|
||||
{
|
||||
_id = id;
|
||||
}
|
||||
|
||||
GraphNode::~GraphNode()
|
||||
{
|
||||
// leave as-is
|
||||
}
|
||||
|
||||
void GraphNode::AddToken(std::string token)
|
||||
{
|
||||
_answers.push_back(token);
|
||||
}
|
||||
|
||||
void GraphNode::AddEdgeToParentNode(GraphEdge *edge)
|
||||
{
|
||||
_parentEdges.push_back(edge);
|
||||
}
|
||||
|
||||
void GraphNode::AddEdgeToChildNode(GraphEdge* edge)
|
||||
{
|
||||
_childEdges.push_back(edge); // TODO
|
||||
}
|
||||
|
||||
|
||||
void GraphNode::moveChatbotHere(ChatBot* chatbot)
|
||||
{
|
||||
_chatBot = chatbot;
|
||||
_chatBot->SetCurrentNode(this);
|
||||
}
|
||||
|
||||
void GraphNode::MoveChatbotToNewNode(GraphNode *newNode)
|
||||
{
|
||||
newNode->moveChatbotHere(std::move(_chatBot)); // TODO
|
||||
}
|
||||
|
||||
|
||||
GraphEdge *GraphNode::GetChildEdgeAtIndex(int index)
|
||||
{
|
||||
return _childEdges[index]; // TODO
|
||||
}
|
||||
54
starter/src/graphnode.h
Normal file
54
starter/src/graphnode.h
Normal file
@@ -0,0 +1,54 @@
|
||||
#ifndef GRAPHNODE_H_
|
||||
#define GRAPHNODE_H_
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include "chatbot.h"
|
||||
|
||||
// forward declarations
|
||||
class GraphEdge;
|
||||
|
||||
class GraphNode
|
||||
{
|
||||
private:
|
||||
|
||||
//// TODO
|
||||
|
||||
// data handles (owned)
|
||||
std::vector<GraphEdge *> _childEdges; // edges to subsequent nodes
|
||||
|
||||
// data handles (not owned)
|
||||
std::vector<GraphEdge *> _parentEdges; // edges to preceding nodes
|
||||
ChatBot *_chatBot;
|
||||
|
||||
//// End of TODO
|
||||
|
||||
|
||||
// proprietary members
|
||||
int _id;
|
||||
std::vector<std::string> _answers;
|
||||
|
||||
public:
|
||||
// constructor / destructor
|
||||
GraphNode(int id);
|
||||
~GraphNode();
|
||||
|
||||
// getter / setter
|
||||
int GetID() { return _id; }
|
||||
int GetNumberOfChildEdges() { return _childEdges.size(); }
|
||||
GraphEdge *GetChildEdgeAtIndex(int index);
|
||||
std::vector<std::string> GetAnswers() { return _answers; }
|
||||
int GetNumberOfParents() { return _parentEdges.size(); }
|
||||
|
||||
// proprietary functions
|
||||
void AddToken(std::string token); // add answers to list
|
||||
void AddEdgeToParentNode(GraphEdge *edge);
|
||||
void AddEdgeToChildNode(GraphEdge *edge); // TODO
|
||||
|
||||
void moveChatbotHere(ChatBot *newNode); // TODO
|
||||
|
||||
void MoveChatbotToNewNode(GraphNode *newNode);
|
||||
};
|
||||
|
||||
#endif /* GRAPHNODE_H_ */
|
||||
35
starter/src/main_cli.cpp
Normal file
35
starter/src/main_cli.cpp
Normal file
@@ -0,0 +1,35 @@
|
||||
// CLI-only main for membot. Does not require wxWidgets or GUI code.
|
||||
#define GUI_APP 0
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include "chatlogic.h"
|
||||
|
||||
// Simple CLI version of SendMessageToUser
|
||||
class ChatLogicCLI : public ChatLogic {
|
||||
public:
|
||||
void SendMessageToUser(std::string message) override {
|
||||
std::cout << "Bot: " << message << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
int main() {
|
||||
ChatLogicCLI chatLogic;
|
||||
chatLogic.LoadAnswerGraphFromFile("../src/answergraph.txt");
|
||||
// Check if the root node was loaded (basic check for file load success)
|
||||
// If the file could not be opened, exit gracefully
|
||||
// (Assume that if no nodes are loaded, the file was not found or empty)
|
||||
if (!chatLogic.IsGraphLoaded()) {
|
||||
std::cerr << "Error: Could not load answer graph. Exiting." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
std::string userInput;
|
||||
std::cout << "Type 'quit' to exit at anytime." << std::endl;
|
||||
while (true) {
|
||||
std::cout << "You: ";
|
||||
std::getline(std::cin, userInput);
|
||||
if (userInput == "quit") break;
|
||||
chatLogic.SendMessageToChatbot(userInput);
|
||||
}
|
||||
std::cout << "Goodbye!" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user