commit dcb054ff9f1404113597e9a3d348803cb2d70ef3 Author: Kyle Isom Date: Tue Jun 30 16:01:47 2026 -0700 Initial import. diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..ab1f416 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,10 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Ignored default folder with query files +/queries/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/.idea/cpp-membot.iml b/.idea/cpp-membot.iml new file mode 100644 index 0000000..4c94235 --- /dev/null +++ b/.idea/cpp-membot.iml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..a29048d --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..6e0f5de --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..8306744 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 0000000..4cdeda4 --- /dev/null +++ b/CODEOWNERS @@ -0,0 +1 @@ +* @udacity/public-content-admin diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..92a11d3 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,46 @@ +Copyright © 2012 - 2020, Udacity, Inc. + +Udacity hereby grants you a license in and to the Educational Content, including +but not limited to homework assignments, programming assignments, code samples, +and other educational materials and tools (as further described in the Udacity +Terms of Use), subject to, as modified herein, the terms and conditions of the +Creative Commons Attribution-NonCommercial- NoDerivs 3.0 License located at +http://creativecommons.org/licenses/by-nc-nd/4.0 and successor locations for +such license (the "CC License") provided that, in each case, the Educational +Content is specifically marked as being subject to the CC License. + +Udacity expressly defines the following as falling outside the definition of +"non-commercial": +(a) the sale or rental of (i) any part of the Educational Content, (ii) any + derivative works based at least in part on the Educational Content, or (iii) + any collective work that includes any part of the Educational Content; +(b) the sale of access or a link to any part of the Educational Content without + first obtaining informed consent from the buyer (that the buyer is aware + that the Educational Content, or such part thereof, is available at the + Website free of charge); +(c) providing training, support, or editorial services that use or reference the + Educational Content in exchange for a fee; +(d) the sale of advertisements, sponsorships, or promotions placed on the + Educational Content, or any part thereof, or the sale of advertisements, + sponsorships, or promotions on any website or blog containing any part of + the Educational Material, including without limitation any "pop-up + advertisements"; +(e) the use of Educational Content by a college, university, school, or other + educational institution for instruction where tuition is charged; and +(f) the use of Educational Content by a for-profit corporation or non-profit + entity for internal professional development or training. + +THE SERVICES AND ONLINE COURSES (INCLUDING ANY CONTENT) ARE PROVIDED "AS IS" AND +"AS AVAILABLE" WITH NO REPRESENTATIONS OR WARRANTIES OF ANY KIND, EITHER +EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. YOU +ASSUME TOTAL RESPONSIBILITY AND THE ENTIRE RISK FOR YOUR USE OF THE SERVICES, +ONLINE COURSES, AND CONTENT. WITHOUT LIMITING THE FOREGOING, WE DO NOT WARRANT +THAT (A) THE SERVICES, WEBSITES, CONTENT, OR THE ONLINE COURSES WILL MEET YOUR +REQUIREMENTS OR EXPECTATIONS OR ACHIEVE THE INTENDED PURPOSES, (B) THE WEBSITES +OR THE ONLINE COURSES WILL NOT EXPERIENCE OUTAGES OR OTHERWISE BE UNINTERRUPTED, +TIMELY, SECURE OR ERROR-FREE, (C) THE INFORMATION OR CONTENT OBTAINED THROUGH +THE SERVICES, SUCH AS CHAT ROOM SERVICES, WILL BE ACCURATE, COMPLETE, CURRENT, +ERROR- FREE, COMPLETELY SECURE OR RELIABLE, OR (D) THAT DEFECTS IN OR ON THE +SERVICES OR CONTENT WILL BE CORRECTED. YOU ASSUME ALL RISK OF PERSONAL INJURY, +INCLUDING DEATH AND DAMAGE TO PERSONAL PROPERTY, SUSTAINED FROM USE OF SERVICES. diff --git a/README.md b/README.md new file mode 100644 index 0000000..1ca739d --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +# README Template + +Below is a template provided for use when building your README file for students. + +See [this README](https://github.com/udacity/cpp-c3-starter/blob/main/starter/README.md) diff --git a/starter/CMakeLists.txt b/starter/CMakeLists.txt new file mode 100644 index 0000000..df623db --- /dev/null +++ b/starter/CMakeLists.txt @@ -0,0 +1,8 @@ +cmake_minimum_required(VERSION 3.11.3) + +set(CMAKE_CXX_STANDARD 17) + +project(Membot) + +set(PROJECT_SRCS src/main_cli.cpp src/chatlogic.cpp src/chatbot.cpp src/graphedge.cpp src/graphnode.cpp) +add_executable(membot ${PROJECT_SRCS}) diff --git a/starter/MemoryManagement_FinalProject.code-workspace b/starter/MemoryManagement_FinalProject.code-workspace new file mode 100644 index 0000000..534366c --- /dev/null +++ b/starter/MemoryManagement_FinalProject.code-workspace @@ -0,0 +1,87 @@ +{ + "folders": [ + { + "path": "." + } + ], + "settings": { + "files.associations": { + "__bit_reference": "cpp", + "__config": "cpp", + "__debug": "cpp", + "__functional_base": "cpp", + "__hash_table": "cpp", + "__locale": "cpp", + "__mutex_base": "cpp", + "__nullptr": "cpp", + "__split_buffer": "cpp", + "__string": "cpp", + "__threading_support": "cpp", + "__tuple": "cpp", + "algorithm": "cpp", + "array": "cpp", + "atomic": "cpp", + "bitset": "cpp", + "cctype": "cpp", + "chrono": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "complex": "cpp", + "condition_variable": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "deque": "cpp", + "exception": "cpp", + "optional": "cpp", + "string_view": "cpp", + "fstream": "cpp", + "functional": "cpp", + "initializer_list": "cpp", + "iomanip": "cpp", + "ios": "cpp", + "iosfwd": "cpp", + "iostream": "cpp", + "istream": "cpp", + "iterator": "cpp", + "limits": "cpp", + "list": "cpp", + "locale": "cpp", + "memory": "cpp", + "mutex": "cpp", + "new": "cpp", + "numeric": "cpp", + "ostream": "cpp", + "queue": "cpp", + "random": "cpp", + "ratio": "cpp", + "sstream": "cpp", + "stdexcept": "cpp", + "streambuf": "cpp", + "string": "cpp", + "system_error": "cpp", + "thread": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "typeinfo": "cpp", + "unordered_map": "cpp", + "utility": "cpp", + "vector": "cpp", + "hash_map": "cpp", + "*.tcc": "cpp", + "memory_resource": "cpp", + "cinttypes": "cpp", + "future": "cpp", + "__errc": "cpp", + "__node_handle": "cpp", + "stack": "cpp", + "bit": "cpp" + } + } +} \ No newline at end of file diff --git a/starter/README.md b/starter/README.md new file mode 100644 index 0000000..0a929ee --- /dev/null +++ b/starter/README.md @@ -0,0 +1,44 @@ +# CPPND: Memory Management Chatbot + +This is the project for the Memory Management course in the Udacity C++ Nanodegree Program. + +# High-level Objectives +> [!IMPORTANT] +> _See the Project Rubric for a full list of requirements._ + +In this project, you'll apply your skills to: +1. **Analyze problems**, and +2. **Then modify the program** using the advanced concepts taught in this course + +**To complete the project:** +1. **Find each `TODO`** located in the project's files. `TODO`s are located either: + - To the side, if the fix is for a single line of code + - Above the code, if the fix is for multiple lines of code. These also have a `END OF TODO` comment at the end of the relevant blocks of code. +3. **Analyze the relevant code to determine what needs to be fixed** + - Generally, the `TODO`s don't provide instructions or guidance. This is so you can practice identifying and implementing appropriate fixes. +4. **Implement the appropriate fix** + - Your fixes need to use the advanced concepts taught in this course + +# Project Setup +## 1. Install Dependencies +> [!NOTE] +> If you're using Udacity Workspace, these dependencies are already installed + +* cmake >= 3.11 + * All OSes: [click here for installation instructions](https://cmake.org/install/) +* make >= 4.1 (Linux, Mac), 3.81 (Windows) + * Linux: make is installed by default on most Linux distros + * Mac: [install Xcode command line tools to get make](https://developer.apple.com/xcode/features/) + * Windows: [Click here for installation instructions](http://gnuwin32.sourceforge.net/packages/make.htm) +* gcc/g++ >= 5.4 + * Linux: gcc / g++ is installed by default on most Linux distros + * Mac: same deal as make - [install Xcode command line tools](https://developer.apple.com/xcode/features/) + * Windows: recommend using [MinGW](http://www.mingw.org/) + +## 2. Compile, build, and Run +> [!WARNING] +> **Until you finished the `TODO`s, the code will compile** (`cmake ..`) **but not build** (`make`) + +In the top level directory of this project, run the following: + +`mkdir build && cd build && cmake .. && make && ./membot` diff --git a/starter/src/answergraph.txt b/starter/src/answergraph.txt new file mode 100644 index 0000000..11c4d1c --- /dev/null +++ b/starter/src/answergraph.txt @@ -0,0 +1,29 @@ + +// define all graph nodes + + + + + + + + + + + + + + + + + +// connect nodes with edges + + + + + + + + + \ No newline at end of file diff --git a/starter/src/chatbot.cpp b/starter/src/chatbot.cpp new file mode 100644 index 0000000..716fa0d --- /dev/null +++ b/starter/src/chatbot.cpp @@ -0,0 +1,134 @@ +#include +#include +#include +#include + +#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 EdgeDist; + std::vector levDists; + std::vector 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 answers = _currentNode->GetAnswers(); + std::mt19937 generator(int(std::time(0))); + std::uniform_int_distribution 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; +} \ No newline at end of file diff --git a/starter/src/chatbot.h b/starter/src/chatbot.h new file mode 100644 index 0000000..3283142 --- /dev/null +++ b/starter/src/chatbot.h @@ -0,0 +1,42 @@ +#ifndef CHATBOT_H_ +#define CHATBOT_H_ + +#include + +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_ */ \ No newline at end of file diff --git a/starter/src/chatlogic.cpp b/starter/src/chatlogic.cpp new file mode 100644 index 0000000..ed615f1 --- /dev/null +++ b/starter/src/chatlogic.cpp @@ -0,0 +1,225 @@ +#include +#include +#include +#include +#include +#include +#include + +#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 +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 &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 &pair) { return pair.first == "TYPE"; }); + if (type != tokens.end()) + { + // check for id + auto idToken = std::find_if(tokens.begin(), tokens.end(), [](const std::pair &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 &pair) { return pair.first == "PARENT"; }); + auto childToken = std::find_if(tokens.begin(), tokens.end(), [](const std::pair &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(); +} diff --git a/starter/src/chatlogic.h b/starter/src/chatlogic.h new file mode 100644 index 0000000..51b066c --- /dev/null +++ b/starter/src/chatlogic.h @@ -0,0 +1,49 @@ +#ifndef CHATLOGIC_H_ +#define CHATLOGIC_H_ + +#include +#include +#include +// #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 _nodes; // TODO + + // data handles (not owned) + GraphNode *_currentNode; + ChatBot *_chatBot; + ChatBotPanelDialog *_panelDialog; + + // proprietary type definitions + typedef std::vector> tokenlist; + + // proprietary functions + template + 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_ */ \ No newline at end of file diff --git a/starter/src/graphedge.cpp b/starter/src/graphedge.cpp new file mode 100644 index 0000000..9c976e3 --- /dev/null +++ b/starter/src/graphedge.cpp @@ -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); +} \ No newline at end of file diff --git a/starter/src/graphedge.h b/starter/src/graphedge.h new file mode 100644 index 0000000..16112bc --- /dev/null +++ b/starter/src/graphedge.h @@ -0,0 +1,36 @@ +#ifndef GRAPHEDGE_H_ +#define GRAPHEDGE_H_ + +#include +#include + +class GraphNode; // forward declaration + +class GraphEdge +{ +private: + // data handles (not owned) + GraphNode *_childNode; + GraphNode *_parentNode; + + // proprietary members + int _id; + std::vector _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 GetKeywords() { return _keywords; } + + // proprietary functions + void AddToken(std::string token); +}; + +#endif /* GRAPHEDGE_H_ */ \ No newline at end of file diff --git a/starter/src/graphnode.cpp b/starter/src/graphnode.cpp new file mode 100644 index 0000000..350540e --- /dev/null +++ b/starter/src/graphnode.cpp @@ -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 +} \ No newline at end of file diff --git a/starter/src/graphnode.h b/starter/src/graphnode.h new file mode 100644 index 0000000..ae389f5 --- /dev/null +++ b/starter/src/graphnode.h @@ -0,0 +1,54 @@ +#ifndef GRAPHNODE_H_ +#define GRAPHNODE_H_ + +#include +#include +#include +#include "chatbot.h" + +// forward declarations +class GraphEdge; + +class GraphNode +{ +private: + + //// TODO + + // data handles (owned) + std::vector _childEdges; // edges to subsequent nodes + + // data handles (not owned) + std::vector _parentEdges; // edges to preceding nodes + ChatBot *_chatBot; + + //// End of TODO + + + // proprietary members + int _id; + std::vector _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 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_ */ diff --git a/starter/src/main_cli.cpp b/starter/src/main_cli.cpp new file mode 100644 index 0000000..7259bcd --- /dev/null +++ b/starter/src/main_cli.cpp @@ -0,0 +1,35 @@ +// CLI-only main for membot. Does not require wxWidgets or GUI code. +#define GUI_APP 0 +#include +#include +#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; +} \ No newline at end of file