diff --git a/src/chatbot.cpp b/src/chatbot.cpp index 41d1f0c1f..d89622e06 100644 --- a/src/chatbot.cpp +++ b/src/chatbot.cpp @@ -1,148 +1,200 @@ -#include -#include #include #include +#include +#include +#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 EdgeDist; - std::vector levDists; // format is - - 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 EdgeDist; + std::vector levDists; // format is - // 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 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)); + // select a random node answer (if several answers should exist) + 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)); - // 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; } \ No newline at end of file diff --git a/src/chatbot.h b/src/chatbot.h index 0367a93f8..0615a5016 100644 --- a/src/chatbot.h +++ b/src/chatbot.h @@ -1,47 +1,56 @@ #ifndef CHATBOT_H_ #define CHATBOT_H_ -#include #include +#include class GraphNode; // forward declaration class ChatLogic; // forward declaration -class ChatBot -{ +class ChatBot { private: - // data handles (owned) - wxBitmap *_image; // avatar image + // data handles (owned) + wxBitmap *_image; // avatar image + + // data handles (not owned) + GraphNode *_currentNode; + GraphNode *_rootNode; + ChatLogic *_chatLogic; - // data handles (not owned) - GraphNode *_currentNode; - GraphNode *_rootNode; - ChatLogic *_chatLogic; + // proprietary functions + int ComputeLevenshteinDistance(std::string s1, std::string s2); - // proprietary functions - int ComputeLevenshteinDistance(std::string s1, std::string s2); + void swap(ChatBot &other); public: - // constructors / destructors - ChatBot(); // constructor WITHOUT memory allocation - ChatBot(std::string filename); // constructor WITH memory allocation - ~ChatBot(); - - //// STUDENT CODE - //// - - //// - //// EOF STUDENT CODE - - // getters / setters - void SetCurrentNode(GraphNode *node); - void SetRootNode(GraphNode *rootNode) { _rootNode = rootNode; } - void SetChatLogicHandle(ChatLogic *chatLogic) { _chatLogic = chatLogic; } - ChatLogic* GetChatLogicHandle() { return _chatLogic; } - wxBitmap *GetImageHandle() { return _image; } - - // communication - void ReceiveMessageFromUser(std::string message); + // constructors / destructors + ChatBot(); // constructor WITHOUT memory allocation + ChatBot(std::string filename); // constructor WITH memory allocation + ~ChatBot(); + + //// STUDENT CODE + //// + // copy ctr + ChatBot(const ChatBot &source); + // copy assignment + ChatBot &operator=(const ChatBot &source); + // move ctr + ChatBot(ChatBot &&source); + // move assignment + ChatBot &operator=(ChatBot &&source); + + //// + //// EOF STUDENT CODE + + // getters / setters + void SetCurrentNode(GraphNode *node); + void SetRootNode(GraphNode *rootNode) { _rootNode = rootNode; } + void SetChatLogicHandle(ChatLogic *chatLogic) { _chatLogic = chatLogic; } + ChatLogic *GetChatLogicHandle() { return _chatLogic; } + wxBitmap *GetImageHandle() { return _image; } + + // communication + void ReceiveMessageFromUser(std::string message); }; #endif /* CHATBOT_H_ */ diff --git a/src/chatgui.cpp b/src/chatgui.cpp index 6637e562b..21ea351f8 100644 --- a/src/chatgui.cpp +++ b/src/chatgui.cpp @@ -1,10 +1,10 @@ -#include -#include -#include -#include +#include "chatgui.h" #include "chatbot.h" #include "chatlogic.h" -#include "chatgui.h" +#include +#include +#include +#include // size of chatbot window const int width = 414; @@ -16,88 +16,87 @@ IMPLEMENT_APP(ChatBotApp); std::string dataPath = "../"; std::string imgBasePath = dataPath + "images/"; -bool ChatBotApp::OnInit() -{ - // create window with name and show it - ChatBotFrame *chatBotFrame = new ChatBotFrame(wxT("Udacity ChatBot")); - chatBotFrame->Show(true); +bool ChatBotApp::OnInit() { + // create window with name and show it + ChatBotFrame *chatBotFrame = new ChatBotFrame(wxT("Udacity ChatBot")); + chatBotFrame->Show(true); - return true; + return true; } // wxWidgets FRAME -ChatBotFrame::ChatBotFrame(const wxString &title) : wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(width, height)) -{ - // create panel with background image - ChatBotFrameImagePanel *ctrlPanel = new ChatBotFrameImagePanel(this); - - // create controls and assign them to control panel - _panelDialog = new ChatBotPanelDialog(ctrlPanel, wxID_ANY); - - // create text control for user input - int idTextXtrl = 1; - _userTextCtrl = new wxTextCtrl(ctrlPanel, idTextXtrl, "", wxDefaultPosition, wxSize(width, 50), wxTE_PROCESS_ENTER, wxDefaultValidator, wxTextCtrlNameStr); - Connect(idTextXtrl, wxEVT_TEXT_ENTER, wxCommandEventHandler(ChatBotFrame::OnEnter)); - - // create vertical sizer for panel alignment and add panels - wxBoxSizer *vertBoxSizer = new wxBoxSizer(wxVERTICAL); - vertBoxSizer->AddSpacer(90); - vertBoxSizer->Add(_panelDialog, 6, wxEXPAND | wxALL, 0); - vertBoxSizer->Add(_userTextCtrl, 1, wxEXPAND | wxALL, 5); - ctrlPanel->SetSizer(vertBoxSizer); - - // position window in screen center - this->Centre(); +ChatBotFrame::ChatBotFrame(const wxString &title) + : wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(width, height)) { + // create panel with background image + ChatBotFrameImagePanel *ctrlPanel = new ChatBotFrameImagePanel(this); + + // create controls and assign them to control panel + _panelDialog = new ChatBotPanelDialog(ctrlPanel, wxID_ANY); + + // create text control for user input + int idTextXtrl = 1; + _userTextCtrl = new wxTextCtrl(ctrlPanel, idTextXtrl, "", wxDefaultPosition, + wxSize(width, 50), wxTE_PROCESS_ENTER, + wxDefaultValidator, wxTextCtrlNameStr); + Connect(idTextXtrl, wxEVT_TEXT_ENTER, + wxCommandEventHandler(ChatBotFrame::OnEnter)); + + // create vertical sizer for panel alignment and add panels + wxBoxSizer *vertBoxSizer = new wxBoxSizer(wxVERTICAL); + vertBoxSizer->AddSpacer(90); + vertBoxSizer->Add(_panelDialog, 6, wxEXPAND | wxALL, 0); + vertBoxSizer->Add(_userTextCtrl, 1, wxEXPAND | wxALL, 5); + ctrlPanel->SetSizer(vertBoxSizer); + + // position window in screen center + this->Centre(); } -void ChatBotFrame::OnEnter(wxCommandEvent &WXUNUSED(event)) -{ - // retrieve text from text control - wxString userText = _userTextCtrl->GetLineText(0); +void ChatBotFrame::OnEnter(wxCommandEvent &WXUNUSED(event)) { + // retrieve text from text control + wxString userText = _userTextCtrl->GetLineText(0); - // add new user text to dialog - _panelDialog->AddDialogItem(userText, true); + // add new user text to dialog + _panelDialog->AddDialogItem(userText, true); - // delete text in text control - _userTextCtrl->Clear(); + // delete text in text control + _userTextCtrl->Clear(); - // send user text to chatbot - _panelDialog->GetChatLogicHandle()->SendMessageToChatbot(std::string(userText.mb_str())); + // send user text to chatbot + _panelDialog->GetChatLogicHandle()->SendMessageToChatbot( + std::string(userText.mb_str())); } BEGIN_EVENT_TABLE(ChatBotFrameImagePanel, wxPanel) EVT_PAINT(ChatBotFrameImagePanel::paintEvent) // catch paint events END_EVENT_TABLE() -ChatBotFrameImagePanel::ChatBotFrameImagePanel(wxFrame *parent) : wxPanel(parent) -{ -} +ChatBotFrameImagePanel::ChatBotFrameImagePanel(wxFrame *parent) + : wxPanel(parent) {} -void ChatBotFrameImagePanel::paintEvent(wxPaintEvent &evt) -{ - wxPaintDC dc(this); - render(dc); +void ChatBotFrameImagePanel::paintEvent(wxPaintEvent &evt) { + wxPaintDC dc(this); + render(dc); } -void ChatBotFrameImagePanel::paintNow() -{ - wxClientDC dc(this); - render(dc); +void ChatBotFrameImagePanel::paintNow() { + wxClientDC dc(this); + render(dc); } -void ChatBotFrameImagePanel::render(wxDC &dc) -{ - // load backgroud image from file - wxString imgFile = imgBasePath + "sf_bridge.jpg"; - wxImage image; - image.LoadFile(imgFile); - - // rescale image to fit window dimensions - wxSize sz = this->GetSize(); - wxImage imgSmall = image.Rescale(sz.GetWidth(), sz.GetHeight(), wxIMAGE_QUALITY_HIGH); - _image = wxBitmap(imgSmall); - - dc.DrawBitmap(_image, 0, 0, false); +void ChatBotFrameImagePanel::render(wxDC &dc) { + // load backgroud image from file + wxString imgFile = imgBasePath + "sf_bridge.jpg"; + wxImage image; + image.LoadFile(imgFile); + + // rescale image to fit window dimensions + wxSize sz = this->GetSize(); + wxImage imgSmall = + image.Rescale(sz.GetWidth(), sz.GetHeight(), wxIMAGE_QUALITY_HIGH); + _image = wxBitmap(imgSmall); + + dc.DrawBitmap(_image, 0, 0, false); } BEGIN_EVENT_TABLE(ChatBotPanelDialog, wxPanel) @@ -105,112 +104,118 @@ EVT_PAINT(ChatBotPanelDialog::paintEvent) // catch paint events END_EVENT_TABLE() ChatBotPanelDialog::ChatBotPanelDialog(wxWindow *parent, wxWindowID id) - : wxScrolledWindow(parent, id) -{ - // sizer will take care of determining the needed scroll size - _dialogSizer = new wxBoxSizer(wxVERTICAL); - this->SetSizer(_dialogSizer); + : wxScrolledWindow(parent, id) { + // sizer will take care of determining the needed scroll size + _dialogSizer = new wxBoxSizer(wxVERTICAL); + this->SetSizer(_dialogSizer); - // allow for PNG images to be handled - wxInitAllImageHandlers(); + // allow for PNG images to be handled + wxInitAllImageHandlers(); - //// STUDENT CODE - //// + //// STUDENT CODE + //// - // create chat logic instance - _chatLogic = new ChatLogic(); + // create chat logic instance + _chatLogic = std::make_unique(); - // pass pointer to chatbot dialog so answers can be displayed in GUI - _chatLogic->SetPanelDialogHandle(this); + // pass pointer to chatbot dialog so answers can be displayed in GUI + _chatLogic->SetPanelDialogHandle(this); - // load answer graph from file - _chatLogic->LoadAnswerGraphFromFile(dataPath + "src/answergraph.txt"); + // load answer graph from file + _chatLogic->LoadAnswerGraphFromFile(dataPath + "src/answergraph.txt"); - //// - //// EOF STUDENT CODE + //// + //// EOF STUDENT CODE } -ChatBotPanelDialog::~ChatBotPanelDialog() -{ - //// STUDENT CODE - //// +ChatBotPanelDialog::~ChatBotPanelDialog() { + //// STUDENT CODE + //// - delete _chatLogic; + // delete _chatLogic; - //// - //// EOF STUDENT CODE + //// + //// EOF STUDENT CODE } -void ChatBotPanelDialog::AddDialogItem(wxString text, bool isFromUser) -{ - // add a single dialog element to the sizer - ChatBotPanelDialogItem *item = new ChatBotPanelDialogItem(this, text, isFromUser); - _dialogSizer->Add(item, 0, wxALL | (isFromUser == true ? wxALIGN_LEFT : wxALIGN_RIGHT), 8); - _dialogSizer->Layout(); - - // make scrollbar show up - this->FitInside(); // ask the sizer about the needed size - this->SetScrollRate(5, 5); - this->Layout(); - - // scroll to bottom to show newest element - int dx, dy; - this->GetScrollPixelsPerUnit(&dx, &dy); - int sy = dy * this->GetScrollLines(wxVERTICAL); - this->DoScroll(0, sy); +void ChatBotPanelDialog::AddDialogItem(wxString text, bool isFromUser) { + // add a single dialog element to the sizer + ChatBotPanelDialogItem *item = + new ChatBotPanelDialogItem(this, text, isFromUser); + _dialogSizer->Add( + item, 0, wxALL | (isFromUser == true ? wxALIGN_LEFT : wxALIGN_RIGHT), 8); + _dialogSizer->Layout(); + + // make scrollbar show up + this->FitInside(); // ask the sizer about the needed size + this->SetScrollRate(5, 5); + this->Layout(); + + // scroll to bottom to show newest element + int dx, dy; + this->GetScrollPixelsPerUnit(&dx, &dy); + int sy = dy * this->GetScrollLines(wxVERTICAL); + this->DoScroll(0, sy); } -void ChatBotPanelDialog::PrintChatbotResponse(std::string response) -{ - // convert string into wxString and add dialog element - wxString botText(response.c_str(), wxConvUTF8); - AddDialogItem(botText, false); +void ChatBotPanelDialog::PrintChatbotResponse(std::string response) { + // convert string into wxString and add dialog element + wxString botText(response.c_str(), wxConvUTF8); + AddDialogItem(botText, false); } -void ChatBotPanelDialog::paintEvent(wxPaintEvent &evt) -{ - wxPaintDC dc(this); - render(dc); +void ChatBotPanelDialog::paintEvent(wxPaintEvent &evt) { + wxPaintDC dc(this); + render(dc); } -void ChatBotPanelDialog::paintNow() -{ - wxClientDC dc(this); - render(dc); +void ChatBotPanelDialog::paintNow() { + wxClientDC dc(this); + render(dc); } -void ChatBotPanelDialog::render(wxDC &dc) -{ - wxImage image; - image.LoadFile(imgBasePath + "sf_bridge_inner.jpg"); +void ChatBotPanelDialog::render(wxDC &dc) { + wxImage image; + image.LoadFile(imgBasePath + "sf_bridge_inner.jpg"); - wxSize sz = this->GetSize(); - wxImage imgSmall = image.Rescale(sz.GetWidth(), sz.GetHeight(), wxIMAGE_QUALITY_HIGH); + wxSize sz = this->GetSize(); + wxImage imgSmall = + image.Rescale(sz.GetWidth(), sz.GetHeight(), wxIMAGE_QUALITY_HIGH); - _image = wxBitmap(imgSmall); - dc.DrawBitmap(_image, 0, 0, false); + _image = wxBitmap(imgSmall); + dc.DrawBitmap(_image, 0, 0, false); } -ChatBotPanelDialogItem::ChatBotPanelDialogItem(wxPanel *parent, wxString text, bool isFromUser) - : wxPanel(parent, -1, wxPoint(-1, -1), wxSize(-1, -1), wxBORDER_NONE) -{ - // retrieve image from chatbot - wxBitmap *bitmap = isFromUser == true ? nullptr : ((ChatBotPanelDialog*)parent)->GetChatLogicHandle()->GetImageFromChatbot(); - - // create image and text - _chatBotImg = new wxStaticBitmap(this, wxID_ANY, (isFromUser ? wxBitmap(imgBasePath + "user.png", wxBITMAP_TYPE_PNG) : *bitmap), wxPoint(-1, -1), wxSize(-1, -1)); - _chatBotTxt = new wxStaticText(this, wxID_ANY, text, wxPoint(-1, -1), wxSize(150, -1), wxALIGN_CENTRE | wxBORDER_NONE); - _chatBotTxt->SetForegroundColour(isFromUser == true ? wxColor(*wxBLACK) : wxColor(*wxWHITE)); - - // create sizer and add elements - wxBoxSizer *horzBoxSizer = new wxBoxSizer(wxHORIZONTAL); - horzBoxSizer->Add(_chatBotTxt, 8, wxEXPAND | wxALL, 1); - horzBoxSizer->Add(_chatBotImg, 2, wxEXPAND | wxALL, 1); - this->SetSizer(horzBoxSizer); - - // wrap text after 150 pixels - _chatBotTxt->Wrap(150); - - // set background color - this->SetBackgroundColour((isFromUser == true ? wxT("YELLOW") : wxT("BLUE"))); +ChatBotPanelDialogItem::ChatBotPanelDialogItem(wxPanel *parent, wxString text, + bool isFromUser) + : wxPanel(parent, -1, wxPoint(-1, -1), wxSize(-1, -1), wxBORDER_NONE) { + // retrieve image from chatbot + wxBitmap *bitmap = isFromUser == true ? nullptr + : ((ChatBotPanelDialog *)parent) + ->GetChatLogicHandle() + ->GetImageFromChatbot(); + + // create image and text + _chatBotImg = new wxStaticBitmap( + this, wxID_ANY, + (isFromUser ? wxBitmap(imgBasePath + "user.png", wxBITMAP_TYPE_PNG) + : *bitmap), + wxPoint(-1, -1), wxSize(-1, -1)); + _chatBotTxt = + new wxStaticText(this, wxID_ANY, text, wxPoint(-1, -1), wxSize(150, -1), + wxALIGN_CENTRE | wxBORDER_NONE); + _chatBotTxt->SetForegroundColour(isFromUser == true ? wxColor(*wxBLACK) + : wxColor(*wxWHITE)); + + // create sizer and add elements + wxBoxSizer *horzBoxSizer = new wxBoxSizer(wxHORIZONTAL); + horzBoxSizer->Add(_chatBotTxt, 8, wxEXPAND | wxALL, 1); + horzBoxSizer->Add(_chatBotImg, 2, wxEXPAND | wxALL, 1); + this->SetSizer(horzBoxSizer); + + // wrap text after 150 pixels + _chatBotTxt->Wrap(150); + + // set background color + this->SetBackgroundColour((isFromUser == true ? wxT("YELLOW") : wxT("BLUE"))); } diff --git a/src/chatgui.h b/src/chatgui.h index 503c59790..1192b2201 100644 --- a/src/chatgui.h +++ b/src/chatgui.h @@ -1,99 +1,96 @@ #ifndef CHATGUI_H_ #define CHATGUI_H_ +#include + #include class ChatLogic; // forward declaration // middle part of the window containing the dialog between user and chatbot -class ChatBotPanelDialog : public wxScrolledWindow -{ +class ChatBotPanelDialog : public wxScrolledWindow { private: - // control elements - wxBoxSizer *_dialogSizer; - wxBitmap _image; + // control elements + wxBoxSizer *_dialogSizer; + wxBitmap _image; - //// STUDENT CODE - //// + //// STUDENT CODE + //// - ChatLogic *_chatLogic; + std::unique_ptr _chatLogic; - //// - //// EOF STUDENT CODE + //// + //// EOF STUDENT CODE public: - // constructor / destructor - ChatBotPanelDialog(wxWindow *parent, wxWindowID id); - ~ChatBotPanelDialog(); + // constructor / destructor + ChatBotPanelDialog(wxWindow *parent, wxWindowID id); + ~ChatBotPanelDialog(); - // getter / setter - ChatLogic *GetChatLogicHandle() { return _chatLogic; } + // getter / setter + ChatLogic *GetChatLogicHandle() { return _chatLogic.get(); } - // events - void paintEvent(wxPaintEvent &evt); - void paintNow(); - void render(wxDC &dc); + // events + void paintEvent(wxPaintEvent &evt); + void paintNow(); + void render(wxDC &dc); - // proprietary functions - void AddDialogItem(wxString text, bool isFromUser = true); - void PrintChatbotResponse(std::string response); + // proprietary functions + void AddDialogItem(wxString text, bool isFromUser = true); + void PrintChatbotResponse(std::string response); - DECLARE_EVENT_TABLE() + DECLARE_EVENT_TABLE() }; // dialog item shown in ChatBotPanelDialog -class ChatBotPanelDialogItem : public wxPanel -{ +class ChatBotPanelDialogItem : public wxPanel { private: - // control elements - wxStaticBitmap *_chatBotImg; - wxStaticText *_chatBotTxt; + // control elements + wxStaticBitmap *_chatBotImg; + wxStaticText *_chatBotTxt; public: - // constructor / destructor - ChatBotPanelDialogItem(wxPanel *parent, wxString text, bool isFromUser); + // constructor / destructor + ChatBotPanelDialogItem(wxPanel *parent, wxString text, bool isFromUser); }; // frame containing all control elements -class ChatBotFrame : public wxFrame -{ +class ChatBotFrame : public wxFrame { private: - // control elements - ChatBotPanelDialog *_panelDialog; - wxTextCtrl *_userTextCtrl; + // control elements + ChatBotPanelDialog *_panelDialog; + wxTextCtrl *_userTextCtrl; - // events - void OnEnter(wxCommandEvent &WXUNUSED(event)); + // events + void OnEnter(wxCommandEvent &WXUNUSED(event)); public: - // constructor / desctructor - ChatBotFrame(const wxString &title); + // constructor / desctructor + ChatBotFrame(const wxString &title); }; // control panel for background image display -class ChatBotFrameImagePanel : public wxPanel -{ - // control elements - wxBitmap _image; +class ChatBotFrameImagePanel : public wxPanel { + // control elements + wxBitmap _image; public: - // constructor / desctructor - ChatBotFrameImagePanel(wxFrame *parent); + // constructor / desctructor + ChatBotFrameImagePanel(wxFrame *parent); - // events - void paintEvent(wxPaintEvent &evt); - void paintNow(); - void render(wxDC &dc); + // events + void paintEvent(wxPaintEvent &evt); + void paintNow(); + void render(wxDC &dc); - DECLARE_EVENT_TABLE() + DECLARE_EVENT_TABLE() }; // wxWidgets app that hides main() -class ChatBotApp : public wxApp -{ +class ChatBotApp : public wxApp { public: - // events - virtual bool OnInit(); + // events + virtual bool OnInit(); }; #endif /* CHATGUI_H_ */ diff --git a/src/chatlogic.cpp b/src/chatlogic.cpp index 79c58ef41..be8996e36 100644 --- a/src/chatlogic.cpp +++ b/src/chatlogic.cpp @@ -1,249 +1,254 @@ +#include #include -#include #include -#include #include +#include #include -#include +#include -#include "graphedge.h" -#include "graphnode.h" #include "chatbot.h" #include "chatlogic.h" +#include "graphedge.h" +#include "graphnode.h" +ChatLogic::ChatLogic() { + //// STUDENT CODE + //// -ChatLogic::ChatLogic() -{ - //// STUDENT CODE - //// - - // create instance of chatbot - _chatBot = new ChatBot("../images/chatbot.png"); + // create instance of chatbot + // _chatBot = new ChatBot("../images/chatbot.png"); - // add pointer to chatlogic so that chatbot answers can be passed on to the GUI - _chatBot->SetChatLogicHandle(this); + // add pointer to chatlogic so that chatbot answers can be passed on to the + // GUI + // _chatBot->SetChatLogicHandle(this); - //// - //// EOF STUDENT CODE + //// + //// EOF STUDENT CODE } -ChatLogic::~ChatLogic() -{ - //// STUDENT CODE - //// +ChatLogic::~ChatLogic() { + //// STUDENT CODE + //// - // delete chatbot instance - delete _chatBot; + // delete chatbot instance + // delete _chatBot; - // delete all nodes - for (auto it = std::begin(_nodes); it != std::end(_nodes); ++it) - { - delete *it; - } + // delete all nodes + // for (auto it = std::begin(_nodes); it != std::end(_nodes); ++it) { + // delete *it; + // } - // delete all edges - for (auto it = std::begin(_edges); it != std::end(_edges); ++it) - { - delete *it; - } + // delete all edges + // for (auto it = std::begin(_edges); it != std::end(_edges); ++it) + // { + // delete *it; + // } - //// - //// EOF STUDENT CODE + //// + //// EOF STUDENT CODE } 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::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()); - } +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)); + } - // 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") - { - //// STUDENT CODE - //// - - // check if node with this ID exists already - auto newNode = std::find_if(_nodes.begin(), _nodes.end(), [&id](GraphNode *node) { return node->GetID() == id; }); - - // create new element if ID does not yet exist - if (newNode == _nodes.end()) - { - _nodes.emplace_back(new GraphNode(id)); - newNode = _nodes.end() - 1; // get iterator to last element - - // add all answers to current node - AddAllTokensToElement("ANSWER", tokens, **newNode); - } - - //// - //// EOF STUDENT CODE - } - - // 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); }); - auto childNode = std::find_if(_nodes.begin(), _nodes.end(), [&childToken](GraphNode *node) { return node->GetID() == std::stoi(childToken->second); }); - - // create new edge - GraphEdge *edge = new GraphEdge(id); - edge->SetChildNode(*childNode); - edge->SetParentNode(*parentNode); - _edges.push_back(edge); - - // find all keywords for current node - AddAllTokensToElement("KEYWORD", tokens, *edge); - - // store reference in child node and parent node - (*childNode)->AddEdgeToParentNode(edge); - (*parentNode)->AddEdgeToChildNode(edge); - } - - //// - //// EOF STUDENT CODE - } - } - else - { - std::cout << "Error: ID missing. Line is ignored!" << std::endl; - } + // 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") { + //// STUDENT CODE + //// + + // check if node with this ID exists already + auto newNode = + std::find_if(_nodes.begin(), _nodes.end(), + [&id](std::unique_ptr &node) { + return node->GetID() == id; + }); + + // create new element if ID does not yet exist + if (newNode == _nodes.end()) { + _nodes.emplace_back(std::make_unique(id)); + newNode = _nodes.end() - 1; // get iterator to last element + + // add all answers to current node + AddAllTokensToElement("ANSWER", tokens, **newNode); } - } // 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) - { - rootNode = *it; // assign current node to root - } - else - { - std::cout << "ERROR : Multiple root nodes detected" << std::endl; + //// + //// EOF STUDENT CODE + } + + // 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 parentNodeItr = std::find_if( + _nodes.begin(), _nodes.end(), + [&parentToken](std::unique_ptr &node) { + return node->GetID() == std::stoi(parentToken->second); + }); + auto childNodeItr = std::find_if( + _nodes.begin(), _nodes.end(), + [&childToken](std::unique_ptr &node) { + return node->GetID() == std::stoi(childToken->second); + }); + + // create new edge + auto edge = std::make_unique(id); + edge->SetChildNode((*childNodeItr).get()); + edge->SetParentNode((*parentNodeItr).get()); + // _edges.push_back(edge); + + // find all keywords for current node + AddAllTokensToElement("KEYWORD", tokens, *edge); + + // store reference in child node and parent node + (*childNodeItr)->AddEdgeToParentNode(edge.get()); + (*parentNodeItr)->AddEdgeToChildNode(std::move(edge)); } + + //// + //// EOF STUDENT CODE + } + } 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) { + rootNode = (*it).get(); // assign current node to root + } else { + std::cout << "ERROR : Multiple root nodes detected" << std::endl; + } } + } - // add chatbot to graph root node - _chatBot->SetRootNode(rootNode); - rootNode->MoveChatbotHere(_chatBot); - - //// - //// EOF STUDENT CODE -} + // add chatbot to graph root node + ChatBot chatBot("../images/chatbot.png"); + SetChatbotHandle(&chatBot); + chatBot.SetRootNode(rootNode); + chatBot.SetChatLogicHandle(this); + rootNode->MoveChatbotHere(std::move(chatBot)); -void ChatLogic::SetPanelDialogHandle(ChatBotPanelDialog *panelDialog) -{ - _panelDialog = panelDialog; + //// + //// EOF STUDENT CODE } -void ChatLogic::SetChatbotHandle(ChatBot *chatbot) -{ - _chatBot = chatbot; +void ChatLogic::SetPanelDialogHandle(ChatBotPanelDialog *panelDialog) { + _panelDialog = panelDialog; } -void ChatLogic::SendMessageToChatbot(std::string message) -{ - _chatBot->ReceiveMessageFromUser(message); +void ChatLogic::SetChatbotHandle(ChatBot *chatbot) { _chatBot = chatbot; } + +void ChatLogic::SendMessageToChatbot(std::string message) { + _chatBot->ReceiveMessageFromUser(message); } -void ChatLogic::SendMessageToUser(std::string message) -{ - _panelDialog->PrintChatbotResponse(message); +void ChatLogic::SendMessageToUser(std::string message) { + _panelDialog->PrintChatbotResponse(message); } -wxBitmap *ChatLogic::GetImageFromChatbot() -{ - return _chatBot->GetImageHandle(); +wxBitmap *ChatLogic::GetImageFromChatbot() { + return _chatBot->GetImageHandle(); } diff --git a/src/chatlogic.h b/src/chatlogic.h index e70b0713e..1fa0e2b0d 100644 --- a/src/chatlogic.h +++ b/src/chatlogic.h @@ -1,54 +1,54 @@ #ifndef CHATLOGIC_H_ #define CHATLOGIC_H_ -#include -#include #include "chatgui.h" +#include +#include // forward declarations class ChatBot; class GraphEdge; class GraphNode; -class ChatLogic -{ +class ChatLogic { private: - //// STUDENT CODE - //// + //// STUDENT CODE + //// - // data handles (owned) - std::vector _nodes; - std::vector _edges; + // data handles (owned) + std::vector> _nodes; + // std::vector _edges; - //// - //// EOF STUDENT CODE + //// + //// EOF STUDENT CODE - // data handles (not owned) - GraphNode *_currentNode; - ChatBot *_chatBot; - ChatBotPanelDialog *_panelDialog; + // data handles (not owned) + GraphNode *_currentNode; + ChatBot *_chatBot; + ChatBotPanelDialog *_panelDialog; - // proprietary type definitions - typedef std::vector> tokenlist; + // proprietary type definitions + typedef std::vector> tokenlist; - // proprietary functions - template - void AddAllTokensToElement(std::string tokenID, tokenlist &tokens, T &element); + // 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); - void SendMessageToUser(std::string message); - wxBitmap *GetImageFromChatbot(); + // 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); + void SendMessageToUser(std::string message); + wxBitmap *GetImageFromChatbot(); }; #endif /* CHATLOGIC_H_ */ \ No newline at end of file diff --git a/src/graphnode.cpp b/src/graphnode.cpp index 65f56060b..29e56f64b 100644 --- a/src/graphnode.cpp +++ b/src/graphnode.cpp @@ -1,60 +1,48 @@ -#include "graphedge.h" #include "graphnode.h" +#include "graphedge.h" -GraphNode::GraphNode(int id) -{ - _id = id; -} - -GraphNode::~GraphNode() -{ - //// STUDENT CODE - //// +GraphNode::GraphNode(int id) { _id = id; } - delete _chatBot; +GraphNode::~GraphNode() { + //// STUDENT CODE + //// + // warm-up task + // delete _chatBot; - //// - //// EOF STUDENT CODE + //// + //// EOF STUDENT CODE } -void GraphNode::AddToken(std::string token) -{ - _answers.push_back(token); -} +void GraphNode::AddToken(std::string token) { _answers.push_back(token); } -void GraphNode::AddEdgeToParentNode(GraphEdge *edge) -{ - _parentEdges.push_back(edge); +void GraphNode::AddEdgeToParentNode(GraphEdge *edge) { + _parentEdges.push_back(edge); } -void GraphNode::AddEdgeToChildNode(GraphEdge *edge) -{ - _childEdges.push_back(edge); +void GraphNode::AddEdgeToChildNode(std::unique_ptr edge) { + _childEdges.push_back(std::move(edge)); } //// STUDENT CODE //// -void GraphNode::MoveChatbotHere(ChatBot *chatbot) -{ - _chatBot = chatbot; - _chatBot->SetCurrentNode(this); +void GraphNode::MoveChatbotHere(ChatBot chatbot) { + _chatBot = std::move(chatbot); + _chatBot.SetCurrentNode(this); } -void GraphNode::MoveChatbotToNewNode(GraphNode *newNode) -{ - newNode->MoveChatbotHere(_chatBot); - _chatBot = nullptr; // invalidate pointer at source +void GraphNode::MoveChatbotToNewNode(GraphNode *newNode) { + newNode->MoveChatbotHere(std::move(_chatBot)); + // _chatBot = nullptr; // invalidate pointer at source } //// //// EOF STUDENT CODE -GraphEdge *GraphNode::GetChildEdgeAtIndex(int index) -{ - //// STUDENT CODE - //// +GraphEdge *GraphNode::GetChildEdgeAtIndex(int index) { + //// STUDENT CODE + //// - return _childEdges[index]; + return (_childEdges[index]).get(); - //// - //// EOF STUDENT CODE + //// + //// EOF STUDENT CODE } \ No newline at end of file diff --git a/src/graphnode.h b/src/graphnode.h index ba3910d20..605d83935 100644 --- a/src/graphnode.h +++ b/src/graphnode.h @@ -1,60 +1,60 @@ #ifndef GRAPHNODE_H_ #define GRAPHNODE_H_ -#include -#include #include "chatbot.h" - +#include +#include +#include // forward declarations class GraphEdge; -class GraphNode -{ +class GraphNode { private: - //// STUDENT CODE - //// + //// STUDENT CODE + //// - // data handles (owned) - std::vector _childEdges; // edges to subsequent nodes + // data handles (owned) + std::vector> + _childEdges; // edges to subsequent nodes - // data handles (not owned) - std::vector _parentEdges; // edges to preceding nodes - ChatBot *_chatBot; + // data handles (not owned) + std::vector _parentEdges; // edges to preceding nodes + ChatBot _chatBot; - //// - //// EOF STUDENT CODE + //// + //// EOF STUDENT CODE - // proprietary members - int _id; - std::vector _answers; + // proprietary members + int _id; + std::vector _answers; public: - // constructor / destructor - GraphNode(int id); - ~GraphNode(); + // 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(); } + // 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); + // proprietary functions + void AddToken(std::string token); // add answers to list + void AddEdgeToParentNode(GraphEdge *edge); + void AddEdgeToChildNode(std::unique_ptr edge); - //// STUDENT CODE - //// + //// STUDENT CODE + //// - void MoveChatbotHere(ChatBot *chatbot); + void MoveChatbotHere(ChatBot chatbot); - //// - //// EOF STUDENT CODE + //// + //// EOF STUDENT CODE - void MoveChatbotToNewNode(GraphNode *newNode); + void MoveChatbotToNewNode(GraphNode *newNode); }; #endif /* GRAPHNODE_H_ */ \ No newline at end of file