Initial import.

This commit is contained in:
2026-06-30 16:01:47 -07:00
commit dcb054ff9f
21 changed files with 899 additions and 0 deletions

225
starter/src/chatlogic.cpp Normal file
View 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();
}