C++ console application; time optimised queue in a dental clinic situation - c++

I'm trying to solve a queue problem that is required in my assignment.
The details are as follows :
- I am asked to create an automate robust queuing sub-system (note that the each dental clinic has 2 doctors and 4 dentist chairs, 1 x-ray machine on its premise)
- Time-optimised algorithm (different type of treatment). For example, tooth decay would require 30 minutes, checkup would be only 15 minutes, etc.
- Every clinic expected about ~20 and ~15 patients in the morning and afternoon per day respectively.
- The clinic timing is 8am – 12pm, 2pm – 6pm
Upon asking my lecturer, he said that I would need 2 queues(for each doctor), x-ray machines would be an instant process and requires no time at all and in the end of the day, when comparing these 2 queues, the difference of the total duration would be almost equal.
I have been trying to solve this problem but to no avail. Can someone explain how these would be solved?
EDIT :
I have created the queue implementation and a Visit class that is supposed to be enqueued into the queue. What I need to figure out is the algorithm on how to schedule all these visits such that the queues will be time-efficient.
Visit.h
#ifndef Visit_H
#define Visit_H
#include "MC.h"
#include "Doctor.h"
#include "Assistant.h"
#include "Condition.h"
#include "Medicine.h"
#include "Treatment.h"
class Visit
{
private:
std::string date;
std::string time;
double duration;
Staff staff;
MC mc;
bool xRayStatus;
List<Treatment> treatmentList;
List<Condition> conditionList;
List<Medicine> medicineList;
public:
Visit();
Visit(std::string, std::string, double);
std::string getDate();
void addStaff(Staff);
Staff getStaff();
void setMC(MC);
MC getMC();
void addXRay();
bool getXRayStatus();
void addCondition(Condition c);
void addMedicine(Medicine m);
void addTreatment(Treatment t);
List<Treatment> getTreatmentList();
List<Medicine> getMedicineList();
List<Condition> getConditionList();
};
#endif
Visit.cpp
#ifndef Visit_CPP
#define Visit_CPP
#include "Visit.h"
Visit::Visit()
{
}
Visit::Visit(std::string d, std::string t, double dur)
{
date = d;
time = t;
duration = dur;
}
std::string Visit::getDate()
{
return date;
}
void Visit::addStaff(Staff s)
{
staff = s;
}
Staff Visit::getStaff()
{
return staff;
}
void Visit::setMC(MC m)
{
mc = m;
}
MC Visit::getMC()
{
return mc;
}
void Visit::addXRay()
{
xRayStatus = true;
}
bool Visit::getXRayStatus()
{
return xRayStatus;
};
void Visit::addCondition(Condition c)
{
conditionList.add(c);
}
void Visit::addMedicine(Medicine m)
{
medicineList.add(m);
}
void Visit::addTreatment(Treatment t)
{
treatmentList.add(t);
}
List<Treatment> Visit::getTreatmentList()
{
return treatmentList;
}
List<Medicine> Visit::getMedicineList()
{
return medicineList;
}
List<Condition> Visit::getConditionList()
{
return conditionList;
};
#endif
Queue.h
//Queue.h - - Specification of Queue ADT (implemented using Pointers)
#include<string>
#include<iostream>
#include "Visit.h"
using namespace std;
typedef Visit ItemType;
class Queue
{
private:
struct Node
{
ItemType item; // item
Node *next; // pointer pointing to next item
};
Node *frontNode; // point to the first item
Node *backNode; // point to the first item
public:
// constructor
Queue();
//destructor
~Queue();
// check if the queue is empty
bool isEmpty();
// enqueue item at the back of queue
bool enqueue(ItemType& newItem);
// dequeue item from front of queue
bool dequeue();
// dequeue and retrieve item from front of queue
bool dequeue(ItemType& item);
// retrieve item from front of queue
void getFront(ItemType& item);
};
Queue.cpp
/** #file Queue.cpp */
#include <cstddef> // for NULL
#include <iostream>
#include <new> // for bad_alloc
#include "Queue.h" // header file
using namespace std;
Queue::Queue()
{
backNode = NULL;
frontNode = NULL;
} // end default constructor
Queue::~Queue()
{
while (!isEmpty())
dequeue();
} // end destructor
bool Queue::isEmpty()
{
return backNode == NULL;
} // end isEmpty
bool Queue::enqueue(ItemType& item)
{
// create a new node
Node *newNode = new Node;
newNode->item = item;
newNode->next = NULL;
// insert the new node
if (isEmpty())
// insertion into empty queue
frontNode = newNode;
else
// insertion into nonempty queue
backNode->next = newNode;
backNode = newNode; // new node is at back
return true;
} // end enqueue
bool Queue::dequeue()
{
if(!isEmpty())
{ // queue is not empty; remove front
Node *temp = frontNode;
if (frontNode == backNode) // special case?
{ // yes, one node in queue
frontNode = NULL;
backNode = NULL;
}
else
frontNode = frontNode->next;
temp->next = NULL;
delete temp;
temp = NULL;
return true;
} // end if
else
{
cout << "empty queue, cannot dequeue" << endl;
return false;
}
} // end dequeue
bool Queue::dequeue(ItemType& item)
{
if (!isEmpty())
{ // queue is not empty; retrieve front
item = frontNode->item;
dequeue(); // delete front
return true;
} // end if
else
{
cout << "empty queue, cannot dequeue" << endl;
return false;
}
} // end dequeue
void Queue::getFront(ItemType& item)
{
if (!isEmpty())
// queue is not empty; retrieve front
item = frontNode->item;
else
cout << "empty queue, cannot getFront" << endl;
} // end getFront
// End of implementation file.

You need to think of the assignment as an event driven system.
One queue would contain events that need to be handled.
If we have an event class like so:
struct Event
{
virtual bool execute_if_time(const Time& t) = 0;
};
We could have a vector of pointers to events:
typedef std::vector< boost::smart_ptr<Event> > Event_Container;
Event_Container events;
There would be a scheduler loop:
while (1)
{
Time t = now();
for (Event_Container::iterator iter = events.begin();
iter != events.end();
++it)
{
(*iter)->exeute_if_time(t);
}
sleep(/* some duration */)
}
The scheduler would execute events in the container at periodic intervals.
Note: this is only one scheme, as there are many others that would suffice.
The rest of the code is left as an exercise for the reader.

Related

Decision tree- delete from a specific node

I have a decision tree that includes node and answer that leads us to another nodes. Answers begin with ":" and nodes are the rest.
I have to do a function that delete a subtree from a specific node. For example If I want to delete node "brand?", I want that after that the tree will print from car-color? to blue-is-beautiful
I don't success doing this deletion in the right way because I think I have to delete also the answer red and don't know how to do that.
class Answer
{
public:
string ans;
Node* son;
Answer(string s, Node* p) { ans = s; son = p; }
};
class Node
{
public:
Node(string v) { isLeaf = true; value = v; }
list<Answer*> answersList;
string value;
bool isLeaf;
};
void Tree::del(Node* t)
{
if (t->isLeaf)
return;
for (list<Answer*>::iterator it = t->answersList.begin(); it != t->answersList.end(); it++)
{
del((*it)->son);
delete((*it));
*it = NULL;
}
if (t)
{
delete t;
t = NULL;
}
}
Now having understood the problems (highly restrictive requirements and what is causing your code to fail), I now have an answer for you.
The issue is, that you need to remove the node you've deleted from the collection it is stored in.
For this purpose, you need to use an alternate version of your search to detect, which child has the value you are looking for.
Due to the requirement of 'not adding any additional functions', there are two ways to go about this.
One is to employ recursion using an anonymous function, the other is 'check the child prior to diving into it'.
The following code fragment uses a DIY-Lambda-Functor, which employs the recursion method.
void Tree::deletefromNode(string val)
{
bool didFindValue = false;
std::function<bool (Node *, const string &)> functor;
class Functor
{
public:
Functor(Tree *owner, bool &didFindValue) : owner(owner), didFindValue(didFindValue)
{
}
bool deleteFromNode(Node *node, const string &value)
{
bool foundMatch = false;
if (node)
{
foundMatch = (node->value == value);
if (!foundMatch)
{
for (list<Answer*>::iterator it = node->answersList.begin(); it != node->answersList.end();)
{
Node *childNode = (*it)->son;
if (deleteFromNode(childNode, value))
{
owner->del(childNode);
it = node->answersList.erase(it);
didFindValue = true;
}
else
it++;
}
}
}
return foundMatch;
}
private:
Tree *owner;
bool &didFindValue;
};
Functor(this, didFindValue).deleteFromNode(root, val);
if (didFindValue)
cout << "Value not found" << endl;
}

Implementing Circular Array Queue

I am to implement a Circular Array Queue But I a having logical errors and I am not getting the correct result. I need help implementing bool dequeue() in ArrayQueueP4.h. I doubt if it is correct.
.
I have tried different solutions as well as search through previous questions on stack overflow and online yet it did not give me any ideas on what I am looking for
#ifndef ARRAY_QUEUE_P4_
#define ARRAY_QUEUE_P4_
#include "QueueInterface.h"
#include "PrecondViolatedExcept.h"
template<class ItemType>
class ArrayQueueP4 : public QueueInterface<ItemType>
{
private:
static const int DEFAULT_CAPACITY = 50;
ItemType items[DEFAULT_CAPACITY + 1]; // Array of queue items
int front; // Index to front of queue
int back; // Index to back of queue
public:
ArrayQueueP4() : front(DEFAULT_CAPACITY),
back(DEFAULT_CAPACITY) {};
// Copy constructor and destructor supplied by compiler
bool isEmpty() const;
bool enqueue(const ItemType& newEntry);
bool dequeue();
/** #throw PrecondViolatedExcept if queue is empty. */
ItemType peekFront() const;
};
ArrayQueueP4.h is the header file for ArrayQueueP4.cpp
#include "ArrayQueueP4.h";
#include "PrecondViolatedExcept.h";
using namespace std;
template <class ItemType>
bool ArrayQueueP4 <ItemType>::isEmpty() const {
return (front == back);
}
template <class ItemType>
bool ArrayQueueP4 <ItemType>::enqueue(const ItemType& newEntry) {
if (!isEmpty())
back = (back + 1) % DEFAULT_CAPACITY;
items[back] = newEntry;
back++;
return true;
}
template<class ItemType>
bool ArrayQueueP4 <ItemType> ::dequeue() {
bool result = false;
if (!isEmpty()) {
front = (front + 1) % DEFAULT_CAPACITY;
front--;
result = true;
}
return result;
}
template<class ItemType>
ItemType ArrayQueueP4<ItemType>::peekFront() const {
if (isEmpty())
throw PrecondViolatedExcept("peekFront() called with an empty queue.");
else
return items[front];
}
HERE is my main file main.cpp to test my code
#include <iostream>
#include "ArrayQueueP4.cpp";
using namespace std;
int main() {
ArrayQueueP4<int> AP;
AP.enqueue(1);
AP.enqueue(2);
AP.enqueue(3);
/*LinkedQueueP1<int> LP;
LP.enqueue(1);
LP.enqueue(2);*/
cout << "PEEK FRONT: " << AP.peekFront();
//cout << "PEEK FRONT: " << LP.peekFront();
system("pause");
return 0;
}
Based on my main program file, the output supposed to now 1 when I call the enqueue function. But instead of getting 2 as my answer, I am getting -858993460 as my result when I delete the first item using dequeue(). I do not know if that is how Queues behave but isn't the second number supposed to be the next first item in line when I delete the first number?
According to your description, your front and back defines a range, such that front is the first element available in the queue, and back is the "pass-the-end" index. Then according to those definition the code should look like this:
template <class ItemType>
bool ArrayQueueP4 <ItemType>::enqueue(const ItemType& newEntry) {
// Check if queue is full
if ((back + 1) % (DEFAULT_CAPACITY + 1) == front) return false;
// Append element at one-pass-end position
items[back] = newEntry;
// Update the one-pass-end index (back)
// All your modulo operation should be dealing with DEFAULT_CAPACITY + 1
// because that is the size of your array
back = (back + 1) % (DEFAULT_CAPACITY + 1);
return true;
}
template<class ItemType>
bool ArrayQueueP4 <ItemType> ::dequeue() {
// Dequeue fail if the queue is empty
if (isEmpty()) return false;
front = (front + 1) % (DEFAULT_CAPACITY + 1);
return true;
}
Also, as a reminder, your code does not take resource management in to account (although it works for most types and doesn't seem to make any mistakes). When an item is dequeued, it's corresponding resources should be released. As an exercise, think about the scenario where ItemType is std::unique_ptr (or std::shared_ptr). This is probably not what your teacher wants, but it is a good practice.

Virtual Functions Polymorphism and Inheritance

I know the title sucks... but I have no clue what actual issue I have got at my hands...
I have defined a base class for linked lists and a specialized class that inherits the base class.
Base:
list.h
#ifndef LIST_H
#define LIST_H
#include <string>
#include "../../declarations.h"
#include "element.h"
class List: public Element{
/*
* #brief is a generic list class, designed to be inherited by more
* specialised list emulating classes.
*/
public: // methods
/// generates empty list.
List(){
init();
cout << "defining List" << endl;
}
/// Removes first list element
bool remove_first(){
if (!is_empty()){
Element* newFirst = first;
delete first;
first = newFirst->next;
return true;
}
else{
std::cerr << "list already empty" << endl;
return false;
}
}
/// removes last list element
bool remove_last(){
// store length fo list in min_len for switch
unsigned int min_len = 0;
if (!is_empty()){
if ((first->next) != 0){
min_len = 2;
}
else {
min_len = 1;
}
}
// as switch doesn't allow for comparisons, map any value greater
// 1 to 2 if (min_len>1) min_len = 2;
switch (min_len){
case (2):{
// Iterate over list, always look two elements ahead.
// If the next element points to 0 you have found your new last
// element (the current next to last one). Delete current-> next
// to remove the last element and let the new last one point to
// zero.
Element* current = first;
while((current->next)->next != 0){
current = (current->next);
}
delete (current->next);
current->next = 0;
return true;
}
// if the list contaisn only one element use remove_first()
// as the logic for that case is already present there
case (1): return remove_first();
case (0):{
std::cerr << "list already empty" << endl;
return false;
}
}
}
// Declare several virtual functions for appending elements
// that get defined in the iheriting classes.
virtual void append_front(int i){};
virtual void append_front(char c){};
virtual void append_front(std::string s){};
virtual void append_back(int i){};
virtual void append_back(char c){};
virtual void append_back(std::string s){};
/// todo
std::string head(){}
/// returns length of list
unsigned length(){
unsigned counter = 0;
Element* current = first;
while(current != 0) {
++counter;
current = current->next;
}
return counter;
}
/// determines whether list is empty
bool is_empty(){
return first == 0;
}
// printing depends on type of list, so this method gets defined in
// inheriting class
virtual void print(){};
private: // methods
void init(){
// initialise empty list with a NULL pointer
first = 0;
}
protected: // data members
/// points to first list element or zero, if list is empty
Element* first;
};
#endif
Derived:
transitionsList.h
#ifndef TRANSITION_LIST_H
#define TRANSITION_LIST_H
#include "../../../generic/list.h"
#include "../../elements/transition/transition.h"
class TransitionList: public List {
public:
void append_front(char c){
// generate list element and store in pointer e
Element* e;
e = new Transition();
// store parameter c in the object *e points to
e->set_content(c);
// Either list is empty. In thet case object at &e becomes first
// list element and also the last.
// Or list wasn't empty and e->next points to the current first, then
// object *e points to becomes first.
if (is_empty()) {
first = e;
e->next = 0;
}
else {
e->next = first;
first = e;
}
}
void append_back(char c){
if (is_empty()) {
append_front(c);
}
else {
Element* e;
e = new Transition();
e->set_content(c);
e->next = 0;
// Go through the list until you find the last element, let it
// then ppint to the new last element.
Element* current = first;
while(current->next != 0) {
current = current->next;
}
current->next = e;
}
}
void print(){
cout << "[";
// go through the list, starting with first element
Element* current = first;
// as long as the last list element is not the current one, keep
// printing elements.
while (current != 0) {
cout << " " << current->get_content();
// let current be the next of current current, to move
// through the list
current = current->next;
} // while
cout << " ]";
}
};
#endif
These two depend on a few other classes:
element.h:
#ifndef ELEMENT_H
#define ELEMENT_H
#include "../../declarations.h"
class State;
class Element{
/*
* #brief is a generic list element class, designed to be inherited by
* more specialised list element classes.
*/
public:
Element(){}
virtual ~Element(){}
virtual void set_content(int i){};
virtual void set_content(char c){};
virtual void set_content(std::string s){};
virtual char get_content() = 0;
Element* next; ///< is the pointer to the next transition in the list
};
#endif
state.h:
#ifndef STATE_H
#define STATE_H
#include "../../declarations.h"
class List;
class State{
/**
* #brief is a class emulating a trie state
*/
public: // methods
State(){
cout << "defining State" << endl;
init();
}
private: // methods
void init(){
}
private: // variables
// Pointer required due to forward declarations
List* transitions; ///< is the list of states dominated by THIS.
// count stores how often the word the current path codes for has been
// found in the training data.
int count; ///< is the number of occurances of some word in this path.
};
#endif
and transition.h
#ifndef TRANSITION_H
#define TRANSITION_H
#include "../../../generic/element.h"
#include "../../state.h"
typedef char cont;
class Transition: public Element {
public:
void set_content(cont c){
content = c;
};
cont get_content(){
return content;
};
State* successor;
Transition* next; ///< is the pointer to the next transition in the list
protected:
cont content; ///< is the character this transition codes for
};
#endif
When I now run this cpp-file:
list_test.cpp:
#include "transitionList.h"
int main(){
TransitionList* derivedList;
List *baseList = &derivedList;
}
I get the error:
list_test2.cpp:5:8: error: cannot initialize a variable of type 'List *' with an rvalue of type 'TransitionList **'
Which I don't understand, because I am under the (apparently phony) impression, that this would be analogous to what I saw in this tutorial:
https://youtu.be/DudHooleNVg?t=4m59s
Where is
int main(){
TransitionList* derivedList;
List *baseList = &derivedList;
}
not analogous to
int main(){
Ninja* n;
Enemy *enemy1 = &n;
}
:/ Very confused.

how to convert this code from Dijkstra to Astar?

So I have a project of which I want to switch to Astar due to speed reasons.
But C++ is not my strongest point. Could anyone help me (or tell me how to do the..) converting the algorythm from Dijkstra to Astar?
I found this Astar implementation:
http://code.google.com/p/a-star-algorithm-implementation/
But I don't know how to use it with my existing code.
Here is the graph file which got the algorithm:
#include "Graph.h"
#include <iostream>
#include <algorithm>
#include <stack>
Graph::Graph(void)
{
}
Graph::~Graph(void)
{
while(!mNodes.empty())
{
delete mNodes.back();
mNodes.pop_back();
}
}
void Graph::addNode(int name, bool exists, Node** NodeID )
{
Node* pStart = NULL;
mNodes.push_back(new Node(name,exists));
std::vector<Node*>::iterator itr;
itr = mNodes.begin()+mNodes.size()-1;
pStart = (*itr);
if(exists == true)pStart->DoesExist_yes();
*NodeID = pStart;
}
void Graph::connect_oneway(Node* pFirst, Node* pSecond, int moveCost)
{
if(pFirst != NULL && pSecond != NULL)
{
pFirst->createEdge(pSecond, moveCost);
}
}
#define MAX_NODES (32768)
#define MAX_CONNECTIONS (5)
#include <time.h>
int * Graph::findPath_r(Node* pStart, Node* pEnd)
{
int *arr = new int[MAX_NODES+2];
for (int i=0; i<MAX_NODES; i++)
arr[i] = -1;
arr[0] = 0;
if(pStart == pEnd)
{
return arr;
}
std::vector<Node*> openList;
openList.push_back(pStart);
Node* pCurrNode = NULL;
while(!openList.empty())
{
//Get best node from open list (lowest F value).
//Since we sort the list at the end of the previous loop we know
//the front node is the best
pCurrNode = openList.front();
//Exit if we're are the goal
if(pCurrNode == pEnd)
break;
//Remove the node from the open list and place it in the closed
openList.erase(openList.begin());
pCurrNode->setClosed(true); //We use a flag instead of a list for speed
//Test all of the edge nodes from the current node
std::vector<Edge*>* pEdges = pCurrNode->getEdges();
Node* pEdgeNode = NULL;
for(std::vector<Edge*>::iterator i = pEdges->begin(); i != pEdges->end(); ++i)
{
pEdgeNode = (*i)->pNode;
//If it's closed we've already analysed it
if(!pEdgeNode->getClosed() && pCurrNode->DoesExist() == true)
{
if(!inList(pEdgeNode,&openList))
{
openList.push_back(pEdgeNode);
pEdgeNode->setGCost(pCurrNode->getGCost()+(*i)->moveCost);
pEdgeNode->calcFCost();
pEdgeNode->setParent(pCurrNode);
}
else
{
//If this is a better node (lower G cost)
if(pEdgeNode->getGCost() > pCurrNode->getGCost()+(*i)->moveCost)
{
pEdgeNode->setGCost(pCurrNode->getGCost()+(*i)->moveCost);
pEdgeNode->calcFCost();
pEdgeNode->setParent(pCurrNode);
}
}
}
}
//Place the lowest F cost item in the open list at the top, so we can
//access it easily next iteration
std::sort(openList.begin(), openList.end(), Graph::compareNodes);
}
//Make sure we actually found a path
if(pEnd->getParent() != NULL)
{
//Output the path
//Use a stack because it is LIFO
std::stack<Node*> path;
while(pCurrNode != NULL)
{
path.push(pCurrNode);
pCurrNode = pCurrNode->getParent();
}
int counter = 0;
arr[1] = 0;
while(!path.empty())
{
arr[counter+2] = path.top()->getName();
counter++;
arr[1] += path.top()->getGCost();
path.pop();
}
arr[0] = counter;
return arr;
}
return arr;
}
bool Graph::inList(Node* pNode, std::vector<Node*>* pList)
{
for(std::vector<Node*>::iterator i = pList->begin(); i != pList->end(); ++i)
{
if((*i) == pNode)
{
return true;
}
}
return false;
}
bool Graph::compareNodes(Node* pFirst, Node* pSecond)
{
return pFirst->getFCost() < pSecond->getFCost();
}
void Graph::reset(void)
{
for(std::vector<Node*>::iterator i = mNodes.begin(); i != mNodes.end(); ++i)
{
(*i)->reset();
}
}
The function for finding the path is this one:
Graph::findPath_r
What I really want to do is preserve the edges (because they decide if the road is both or one-way).
Here are the other files:
Graph.h
#ifndef _GRAPH_H_
#define _GRAPH_H
#include "Node.h"
class Graph
{
public:
Graph(void);
~Graph(void);
//void addNode(int name, bool exists);
void addNode(int name, bool exists, Node** NodeID );
void connect_oneway(int ppFirst, int ppSecond, int moveCost);
void connect_oneway(Node* pFirst, Node* pSecond, int moveCost);
//int * findPath_r(int start, int end);
int * findPath_r(Node* pStart, Node* pEnd);
void reset(void);
private:
void findNodesx(int firstName, Node** ppFirstNode);
bool inList(Node* pNode, std::vector<Node*>* pList);
static bool compareNodes(Node* pFirst, Node* pSecond);
std::vector<Node*> mNodes;
};
#endif
Node.h
#ifndef _NODE_H_
#define _NODE_H_
#include <string>
#include <vector>
//Forward declare Node so Edge can see it
class Node;
struct Edge
{
Edge(Node* node, int cost) : pNode(node), moveCost(cost){}
Node* pNode;
int moveCost;
};
class Node
{
public:
Node(void);
Node(int name, bool exists);
~Node(void);
void createEdge(Node* pTarget, int moveCost);
void setGCost(int cost);
void setClosed(bool closed);
void setParent(Node* pParent);
int getGCost(void);
int getFCost(void);
bool getClosed(void);
Node* getParent(void);
int getName(void);
bool DoesExist(void);
bool DoesExist_yes(void);
std::vector<Edge*>* getEdges(void);
void calcFCost(void);
void reset(void);
private:
int mGCost;
int mTotal;
bool mClosed;
Node* mpParent;
int mName;
bool mHeur;
std::vector<Edge*> mEdges;
};
#endif
Node.cpp
#include "Node.h"
Node::Node(void)
{
}
Node::Node(/*const std::string&*/int name, bool exists) : mGCost(0), mTotal(0), mClosed(false), mpParent(NULL), mName(name), mHeur(exists)
{
}
Node::~Node(void)
{
while(!mEdges.empty())
{
delete mEdges.back();
mEdges.pop_back();
}
}
int Node::getName(void)
{
return mName;
}
void Node::createEdge(Node* pTarget, int moveCost)
{
mEdges.push_back(new Edge(pTarget, moveCost));
}
void Node::setClosed(bool closed)
{
mClosed = closed;
}
bool Node::getClosed(void)
{
return mClosed;
}
std::vector<Edge*>* Node::getEdges(void)
{
return &mEdges;
}
int Node::getGCost(void)
{
return mGCost;
}
void Node::setGCost(int cost)
{
mGCost = cost;
}
void Node::calcFCost(void)
{
mTotal = mGCost;
}
void Node::setParent(Node* pParent)
{
mpParent = pParent;
}
int Node::getFCost(void)
{
return mTotal;
}
bool Node::DoesExist(void)
{
return mHeur;
}
bool Node::DoesExist_yes(void)
{
mHeur = true;
return true;
}
Node* Node::getParent(void)
{
return mpParent;
}
void Node::reset(void)
{
mGCost = 0;
mTotal = 0;
mClosed = false;
mpParent = NULL;
}
You mentioned a library on GoogleCode. It is node clear what you want to do with, and I think the best is to write your implementation yourself.
First, you should know that Dijsktra is a special case of A*. In A*, you have an heuristic, named h; A* = possible implementation of Dijsktra when h is the null function.
Then, about your implementation, let's start with Node. It will need the following functions:
constructor, destructor
create/get edge
set/get parent
set/is closed (for speed)
set/get GCost
set/get FCost
set/is obstacle (name way more descriptive than 'DoesExist')
set/get position
reset
// optional method:
get name
Hopefully, this part of your code won't change a lot. The heuristic code will be placed in the pathfinder. The Edge class is left untouched.
Now the big one: Graph. You won't need to delete any of your public methods.
You will need a heuristic method. For the implementation which will be described, you will need an admissible consistent heuristic:
it must not over-estimate the distance to the goal (admissible)
it must be monotone (consistent)
The general case signature is int getHCost(Node* node);. If you always return 0, you will have a Dijsktra algorithm, which is not what you want. Here we will take the euclidiean distance between the node and the goal. Slower to compute than manhattan distance, but better results. You can change this afterwards.
int getHCost(Node* node, Note* goal);
This implies you must place your nodes in the 3d space. Note that the heuristic is a heuristic, ie, an estimation of the distance.
I won't write the code. I will write some pseudo-code adapted to your situation. The original pseudocode is located on the Wikipedia A* page. This pseudo-code is your findPath_r function:
function A*(start,goal)
set all nodes to not closed // The set of nodes already evaluated.
openset = {start} // The set of tentative nodes to be evaluated, initially containing the start node
start.gcost = 0 // Cost from start along best known path.
// Estimated total cost from start to goal through y.
start.fcost = start.gcost + getHCost(start, goal)
while openset is not empty
current = the node in openset having the lowest f_cost (usually the first if you use a sorted list)
if current == goal
return construct_path(goal)
remove current from openset
current.closed = true
for each neighbor in (node connected by edge in current.edges) // Here is the condition for one-way edges
if neighbor.closed or neighbor.obstacle
continue
gcost = current.gcost + dist_between(current,neighbor) // via edge distance
if neighbor not in openset
add neighbor to openset
neighbor.parent = current
neighbor.gcost = gcost
neighbor.fcost = neighbor.gcost + getHCost(neighbor, goal)
else if gcost < neighbor.gcost
neighbor.parent = current
neighbor.gcost = gcost
neighbor.fcost = neighbor.gcost + getHCost(neighbor, goal)
update neighbor position in openset
return failure
function construct_path(current_node)
std::vector<Node*> path
while current_node != 0
path.push_front(current_node)
current_node = current_node.parent
return path
The implementation above use one-way edges.
You were able to write Dijsktra algorithm in C++, so writing this pseudocode in C++ shouldn't be a problem.
Second part, performances. First, measure ;).
I have some hints that can improve performances:
use a memory pool for allocation deallocation
use an intrusive list for the open list (you can also make it auto-sorted with this technique)
I advise you to read A* for beginners, which is a useful reading, even if you don't use tilemap.

Why isn't this typedef working

This code works if the 7th line down says "typedef char ItemType" but instead I made it typedef to the EventInfo object. The MSVS compiler says some really weird things...
error C2146: syntax error : missing ';' before identifier 'ItemType'
error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
But I don't understand why it works correctly when it is a char.
I know this is a lot of code but the typedef is on the 7th line. I included the whole thing because I don't know what to expect.
#include <iostream>
#include <cstdlib>
#include <fstream>
using namespace std;
const int MaxQueueSize = 8; // Queue Struct can hold up to 8
typedef EventInfo ItemType; // the queue's data type !DOES NOT COMPILE
enum EventType {Arrival, Depart};
class EventInfo
{
public:
EventInfo() : eTime(0), aTime(0), minutes(0) {}
int eventTime();
int duration();
void ScheduleEvent(int eTime, int duration);
bool compare(int eTime);
private:
int eTime; //either the arrival time of the next customer or the departure time of the customer currently at the teller window
int aTime; //either the service time for the arriving customer or the wait time for the customer at the teller window
float minutes;
};
int EventInfo::eventTime()
{
return this->eTime;
}
int EventInfo::duration()
{
return this->aTime;
}
void EventInfo::ScheduleEvent(int eTime, int duration)
{
this->eTime = eTime;
this->aTime = duration;
}
bool EventInfo::compare(int eTime)
{
return (eTime == this->eTime);
}
///////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////
//////////////////////////
////////////////
class CPPQueue
{
public:
CPPQueue() : front(0), rear(0), count(0) { };
ItemType item[MaxQueueSize];
bool IsEmpty() const;
bool IsFull() const;
void Enqueue(ItemType newItem);
void PrintQ();
void PrintQueueInfo();
ItemType Dequeue();
int Count();
private:
int front, rear;
int count;
};
bool CPPQueue::IsEmpty() const
{
return (this->count == 0);
}
bool CPPQueue::IsFull() const
{
return (this->count == MaxQueueSize);
}
void CPPQueue::Enqueue(ItemType newItem)
{
if(this->count == MaxQueueSize)
{
cerr << "Error! Queue is full, cannot enqueue item.\n" << endl;
exit(1);
}
this->item[this->rear] = newItem;
this->rear++;
if (this->rear == MaxQueueSize)
{
this->rear = 0; // adjustment for circular queue
}
this->count++;
}
ItemType CPPQueue::Dequeue()
{
ItemType theItem;
if(this->count == 0)
{
cerr << "Error! Queue is empty, cannot dequeue item.\n" << endl;
exit(1);
}
theItem = this->item[this->front ];
this->front++;
if (this->front == MaxQueueSize)
{
this->front = 0; // adjustment for circular queue
}
this->count--;
return theItem;
}
// Function PrintQ() prints the contents of the queue without changing
// the queue. Printing starts at the "front" index and stops before we
// get to the "rear" index. A decrementing counter controls the loop.
//
void CPPQueue::PrintQ()
{
int i;
int qindex = this->front;
for(i = this->count; i > 0; i--)
{
cout << this->item[qindex] ;
qindex = (++qindex) % MaxQueueSize; // adjustment for circular queue
if(i > 1)
cout << ", ";
}
}
// Helper function for the main program below.
void CPPQueue::PrintQueueInfo()
{
cout << "The queue contains: ";
PrintQ();
cout << endl;
}
int CPPQueue::Count()
{
return this->count;
}
enum TellerStatus {Idle, Busy};
class Teller
{
public:
Teller() : status(Idle), idleTime(0), totalIdleTime(0) {}
void changeStatus(TellerStatus status);
TellerStatus getStatus(void);
private:
TellerStatus status;
int idleTime; //!
int totalIdleTime; //!!
};
void Teller::changeStatus(TellerStatus status)
{
this->status = status;
}
TellerStatus Teller::getStatus()
{
return this->status;
}
class Bank
{
public:
Bank() : Clock(0.0) {}
void RunSimulation();
private:
EventInfo Event[2]; // array of two events - next arrival and next departure
CPPQueue WaitLine; // the customer wait line [with max size = 8]
float Clock; // to keep track of Current Bank Time
Teller theTeller; // the single teller in the bank
ifstream myfile;
void ProcessArrival(), ProcessDeparture(), PrintHeader(), PrintReportLine(), PrintStatsReport();
};
void Bank::RunSimulation()
{
}
void Bank::ProcessArrival()
{
int a, b;
string filename, x;
filename = "P3Data1.txt";
myfile.open(filename);
while (myfile >> a >> b)
{
Event[1].ScheduleEvent(a, b);
WaitLine.Enqueue(Event);
}
}
int main()
{
Bank myBank;
myBank.RunSimulation();
}
The name EventInfo is only usable from its point of declaration forward. Your typedef is too early, and the compiler doesn't yet know what a EventInfo is.
You can move the typedef below the class definition, or you can tell the compiler that EventInfo is a class:
typedef class EventInfo ItemType;
In C++, unlike in Java, you can only use names that have been declared earlier in the file. So just change the order:
class EventInfo { /* ... */ };
typedef EventInfo ItemType;
In fact, it's enough to just declare the class, if you don't want to define it just yet: class EventInfo;
Put the typedef after the class definition. You can't do typedef for unknown types.
First you need to forward declare class EventInfo;
Otherwise your typedef has no idea of what EventInfo is.
THen you have various problems, e.g. you need to overload << for EventInfo class etc.