Design choice regarding manipulation of main loop from treegraph - c++

I'm creating a simple game for programming practice on bigger projects and am currently stuck at a crossroad.
The game uses a treegraph structure to store all the entities of the game, all extending from the base class called TreeNode that implements some basic functions such as attaching and detaching children from themselves as well as their position in the 2D world.
My problem is that I want to create a sort of "Action Node" that upon collision with the player allows various events to take place, such as changing the song being played, trigger a pause with subsequent dialogue, ending the stage etc etc.
My question is, how would i implement this in a decent way that doesn't beat my efforts of code isolation to a bloody pulp? I was thinking of making a new class with a std::function member that i can program to do what i want it to do, but that way would mean completely breaking code encapsulation by handing it a reference to my master class that contains ALL data in the entire game.
Collision is currently implemented something like this:
std::vector<std::pair<&TreeNode, &TreeNode>> vCollision;
MasterNode.checkCollision(vCollision);
checkCollision gets called with a reference to the vector, invokes collision checks recursively on the rest of the graph and fills the vector with pairs of different entities that have collided. (this is in the update loop.)
I also need to figure out a way to be able to call said std::function from this list since pointers to the base class wont have access to members of derived classes.

A tree structure is a container that can be used with different data types. Because of this, it is a good candidate for templates.
Since you have your tree working, factor out the data type to a template parameter.
For example, given a node:
struct Tree_Node
{
struct Tree_Node * left_subtree;
struct Tree_Node * right_subtree;
Some_Data_Type node_data;
};
You can factor out the data type using templates:
template <class Node_Data_Type>
struct Tree_Node
{
struct Tree_Node * left_subtree;
struct Tree_Node * right_subtree;
Node_Data_Type node_data;
};
You would declare a tree node as:
struct Player_Data;
Struct Moves_Data;
struct Tree_Node<Player_Data>; // For a tree of Player_Data
struct Tree_Node<Moves_Data>; // For a tree of Moves_Data
An alternative is to use inheritance for the node data.
struct Node_Data_Base
{
virtual bool is_equal(Node_Data_Base * p_node) const = 0;
virtual bool is_less(Node_Data_Base * p_node) const = 0;
bool operator==(Node_Data_Base * p_node) const
{
return is_equal(p_node); // Dispatch to child.
}
bool operator<(Node_Data_Base * p_node) const
{
return is_less(p_node); // dispatch to child.
}
};
struct Tree_Node_Inheritance
{
struct Tree_Node * left_subtree;
struct Tree_Node * right_subtree;
Node_Data_Base * p_data;
};
Also, review the std::map data type.

Related

Create special binary search tree using C++

I want to create a Binary search tree which has special Nodes. There should be three classes of Nodes, Internal Node, External Node and Root node, each inheriting a common parent Node and each type of node will have some unique function. Is it possible to create such a BST. The problem I am facing is suppose the first node I insert into the tree becomes the root node. The next node I insert will become External Node. Now if I insert another node then the external node has to become a internal node and the new node will become the external node. Also I cannot find a way to navigate through the tree from one node to another as the nodes will be of different types. Can a tree of this type be created. If yes then give me some suggestions of how this can be done.
If I understand correctly, you're worried about how objects in one class - External - need to become objects of another class - Internal. This, when C++ is a statically-typed language: Types (including the classes of objects) are determined at compile-time. Right?
Well, you can achieve this in at least one of two ways:
When an External node becomes Internal, delete the External node and replace it with an Internal node, properly initialized (e.g. to point at the new External node).
Give up on External and Internal being discrete types, and just check for children and parents to determine the node type dynamically.
Some more relevant reading material on these matters:
(Programming language) type systems in this Wikipedia page.
This SO question: What is duck typing?
The Circle-vs-Eclipse problem, and specifically the desire to stretch circles into ellipses.
You could use basic inheritance some type enum and recursive calls.
This could be a starting point:
enum NodeType
{
eRoot,
eInternal,
eExternal
};
class BinaryNode
{
public:
virtual NodeType GetType() = 0;
virtual void UpdateTree() = 0;
protected:
BinaryNode* ChildLeft;
BinaryNode* ChildRight;
BinaryNode* Parent;
};
class ExternalNode : public BinaryNode
{
NodeType GetType() override { return eExternal; }
void UpdateTree() override
{
//... Replace node instances here(e.g. delete this node and construct the correct new one given this sub tree. call new InternalNode(this) for example)
// Call this towards the parent node so the tree will be transformed accordingly
}
}
class InternalNode : public BinaryNode
{
NodeType GetType() override { return eInternal; }
void UpdateTree() override { //... }
}
class RootNode : public BinaryNode
{
NodeType GetType() override { return eRoot; }
void UpdateTree() override { //... }
}
This is just to give you an idea where to start. You can check the node type at runtime via GetType() and do some checks based on that.
Be aware that this kind of transformation is not particularly fast.
If you want this to be fast, don't use different types and virtual function calls and pointers.
Place your binary tree inside an array and use binary indexing, so at a given index "n" use 2*n+1 to get the left child and 2*n+2 to get the right child. Then use some flags (root, external, internal etc.) to determine which functions you want to call on the binary node. I wouldn't use inheritance like in my code example to be fast or more readable. In fact, deciding externally what functions to call on a node can be much more readable and less error-prone.

Combine two base class instances into a derived one

I have the following classes I used to define a tree structure with a number of specific nodes
class TreeNode
{
std::vector<TreeNode*> children;
}
class BTNode: public virtual TreeNode
{
virtual bool loadAttributes(XML) = 0;
virtual BTState tick() = 0;
void otherFunction1() { used by all the different nodes}
void otherFunction2() { also used by all the node types }
}
There are a couple of specific implementations of the BTNode class that can be saved and loaded from XML files:
class BTSpecificNodeOne: public BTNode
{
bool loadAttributes(XML) { load node specific data from XML }
BTState tick() { specific implementation goes here }
}
class BTSpecificNodeTwo: public BTNode
{
bool loadAttributes(XML) { load node specific data from XML }
BTState tick() { specific implementation goes here }
}
etc.
I also have a genetic algorithm that optimises this tree structure based on a common tree node genome type:
class TreeNodeGenome: public virtual TreeNode
{
bool load(XML);
TreeNodeGenome* crossover(TreeNodeGenome* other);
virtual void mutate() = 0;
}
Furthermore, to have the node specific implementation used within the genome
class BTSpecificNodeGenomeOne: public BTSpecificNode, public TreeNodeGenome
{
void mutate() { node specific implementation }
}
class BTSpecificNodeGenomeTwo: public BTSpecificNode, public TreeNodeGenome
{
void mutate() { node specific implementation }
}
etc.
I'd like to be able to save and load the results of the optimisation to/from an XML file.
The implementations of BTSpecificNodeOne, BTSpecificNodeTwo, etc. already have a save/load function that I use for saving the results, but loading them is a bit more tricky.
The load function of the BTNode class rebuilds the tree (from XML) based on the BTNode class (nodes may create children that are also loaded recursively). In order to use it again in the genetic algorithm, I need the nodes to derive from the TreeNodeGenome class as well.
I can rebuild a TreeNodeGenome structure based only on the information contained in TreeNode, but I'm not sure how to "merge" these two trees together.
I know that I could pretty much copy the load functions into the BTSpecificNodeGenomeOne, BTSpecificNodeGenomeTwo, etc. classes but I was wondering if there is a simpler/cleaner way to do it?
EDIT: Apparently what I'd like to do is a bit unclear from my previous post.
I have implemented a Behaviour Tree(BT) class, which uses a number of different nodes deriving from BTNode: Selector, Sequence, different condition and action nodes. The BT itself is saved in an XML format and can be loaded via BTNode::loadAttributes().
In addition to this, I have a genetic algorithm that can optimise tree structures. TreeNodeGenome implements the genetic operators of the different nodes to be used during evolution.
During evolution I use BTSpecificNodeGenomeOne, BTSpecificNodeGenomeTwo nodes that implement both the different BT nodes and the genetic operators from TreeNodeGenome. TreeNodeGenome requires only the structure of the tree already encoded in the TreeNode base class and the node specific implementations of the mutation operator. As the BT and an evolvable tree structure are two conceptually different things, I'd like to keep them separate.
My question is: I have the BTNode::loadAttributes() function implemented for all BTNodes already, which load the BT from an XML file. This function creates its children as BTNodes, which are not evolvable. If I want to use the loaded tree in evolution, I need to somehow "merge" it with a TreeNodeGenome object.
I can do this by reimplementing the loadAttributes function in each derived BTSpecificNodeGenome, but I was wondering if there was a cleaner/simpler way to do this?

C++ tree/forest structure for nodes of different class types

\\while implementing a solution found with casting over a a common baseclass
\\ with virtal members.
\\i found out about univeral references, because that is a other question i created a new one:
https://stackoverflow.com/questions/29590429/c-is-it-possible-to-use-universal-references-for-a-tree-forest-with-nodes-that
please refer also to this original question.
I want to organize the hierarchical tree structure of objects with different types.
The solution should do its work at compile time, so i found out that i have to do this with templates at best without any casting.
after some try's that are in the editlog and had some fundamental flaws.
i found a way to split it up in two classes
forest that stores all the nodes and does give them two coordinates the indexnumbers in the vector< vector <...> >
node a template < T > that stores the T Object and the relationship to the other nodes
my idea does not yet have a way to access the memberfunctions of the Objects stored inside the node class, without breaking the unique_pointer that secures the resourcemanagement.
and i would like to know how to ensure typesafty when accessing a object inside the node class.
there may be errors inside the code, i'm quite sure that it will not compile, the question is about the concept.
Questions are inside the comments.
verion 4:
class Forest
{
public:
template<typename T>
{friend class Node<T>;} \\every Node<T> should have access to the forest
Forest();
~Forest();
Forest(const Forest&)=delete; \\does not make any sense to copy or assign the forest to another forest.
Forest operator=(const Forest&)=delete;
int insertroot() \\every tree has a void nullptr seed/root so that the forest does not need to be templatet, returns the treenumber
{ \\implementation
if(this->Nodes.size()==0)
{
std::vector<std::unique_ptr<Node<void> > > h0;
h0.push_back(std::unique_ptr<Node<void>(new Node<void>(nullptr));
this->Nodes.push_back(h0);
}else
{
this->Nodes[0].push_back(std::unique_ptr<Node<void>(new Node<void>(nullptr,this)));
}
return this->Nodes[0].size()-1;
}
Node<void>* getroot(int i) \\ to later allow access to the children and the Objects inside them
{
if(Nodes.size>0){
if((i>0)&(i<Nodes[0].size()))
{
return Nodes[0][i].get();
}
}
private:
std::vector<std::vector<unique_ptr<Node<void> > > nodes; \\is it possible to fill this vector with any Node<T>? its a vector*2 to a unique_ptr to a classpointer with a member pointer to any class. from what i read about templates they create a extra class for every type, so basicly the unique_ptr have a different type and i cannot store different types in a vector without casting?
}
template<typename T>
class Node
{
public:
Node(T n,Forest * Fo) \\ every Node is in the forest and has access to the other nodes and forest information
:object(std::unique_ptr(n)),F(Fo)
{
if(n==nullptr)
{
this->lvl=0;
this->place=F->Node[0].size();
this->parent=-1;
}
}
~Node();
Node(const Node&)=delete;
Node operator=(const Node&)=delete;
T getObject(){return object.get();} \\how does the compiler know the type? see getchild
template<typename C>
{
Node<C> * getchild(int){} \\not yet exsisting implementation of get child[int] how do i teach the compiler what int responds to what type?
\\when i understand templates correct then Node<C> are different Classes for every C??
addChild(C c)
{
Node * n=new Node(c,this->F);
n->parent=this->place;
n->lvl=this->lvl+1
if(F->nodes.size()<=n->lvl)
{
n->place=0;
h0=std::vector<unique_ptr<Node<C>> >;
h0.push_back(unique_ptr<Node<C>(n))
F->Nodes.push_back(h0); \\are vector<uniptrNode<C> > and vector<uniptrNode<void>> compatible?
}else
{
n->place=F->nodes[n->lvl].size();
F->Nodes[n->lvl].push_back(unique_ptr<Node<C> >(n));
}
this->children.push_back(c->place);
}
}
private:
int parent,place,lvl;
std::vector<int> children;
unique_ptr<T> object;
Forest * F;
}
does anyone know a way to implement a container like this?
maybe there is some abstract type type i did not find out about, so do that i can add a method type getnodetype(int) or checknodetype(int,type), could i assign this with auto nodex=y->getObject()? But then how does the compiler know what methodes nodex has and does not has?
EDIT: i removed the original Post because v4 is very close to a working solution version 1-3 should be in the editlog
I think you need something like boost.any or QVariant.

class/struct design; inheritance vs forward declaration

I'm having trouble understanding when/if single/multiple inheritance should be used vs forward declaration & I'd like to get a better understanding of it in the following example. If someone could point me in the right direction, or explain differences between them, it would be much appreciatd.
Following is sample of data structure I'm dealing with;
There exists 1 Parent, 1 SubParent & many different Children types. ie there's many Children per SubParent per Parent. Some Children need access to other Children objects. Children will use similar functions to each other ie ParseSelf/Display/Save/Edit. If Children get changed (ie Edit/Save), also need to update data in SubParent, Parent & possibly other Children.
I'm wanting to know what would be best way to implement something like this? I've come up with two alternatives below. If more clarification/information is needed please let me know.
class SubParent;
class Children;
class Parent
{
...
int iParent;
SubParent *pSubParent;
};
class SubParent
{
...
int iSubParent;
std::list<Children> childrenList;
};
class Children
{
...
int iChild;
int ChildType;
char *pData;
};
versus;
class Parent
{
...
int iParent;
};
class SubParent : public Parent
{
...
int iSubParent;
};
class Children : public SubParent
{
...
int iChild;
int ChildType;
char *pData;
};
Thank you.
EDIT:
Main job of Parent; maintains information about file ie location of SubParent, SubParent size, total size of all data including self.
Main job of SubParent; contains information about Children ie size & location of Children.
Both Parent/SubParent don't really do much else except keep these items upto date.
I would recommend going with the first approach, with the following changes:
Add a member in SubParent that points to the Parent. This will allow you traverse the objects both ways.
class SubParent
{
...
int iSubParent;
Parent* parent;
std::list<Children> childrenList;
};
You should keep a list of Children* in SubParent instead of a list of Chilren if you are going to have different types of Children. If Children will never have any sub-classes, having a list of Children is good enough.
Add a pointer to the SubParent in Children. Again, that will allow you to traverse the objects both ways. Given a Children, you would be able to access its siblings through that pointer.
class Children
{
...
int iChild;
int ChildType;
SubParent* subParent;
char *pData;
};

Front-end/Back-end design: how to absolutely dissociate the back-end from the front-end?

My question is: (is the above|what is) the right way to create a non intrusive front-end?
I am explaining my problem with a simplified example.
I have a back-end implementing a binary tree:
// Back-end
struct Node
{
Label label;
Node* r, l;
};
I would like now to implement the front-end to print the tree graphically. So my idea is to extend the back-end with graphical properties by wrapping it :
// Front-end
struct Drawable
{
uint x, y;
};
class Visitor;
template <class T> struct GNode : public Drawable
{
T* wrapped;
template <class V> void accept(V& v); // v.visit(*this);
}
There is a problem now to create a visitor printing the binary tree:
struct Visitor
{
void visit(GNode<Node>& n)
{
// print the label and a circle around it: ok.
if (n.wrapped.l) // l is a Node, not a GNode, I can't use the visitor on it
// Problem: how to call this visitor on the node's left child?
// the same with n.wrapped.r
};
};
As explained in comments, the back-end does not use my extended class.
Writing GNode "is-a" Node is not a solution neither since I would have to put the accept() method in the Node class as virtual and override it in GNode but I can't modify the back-end. Then, someone could say too that there is no need to declare accept() in the back-end, downcasting Node* to GNode* would work. Yes it works, but it downcasts...
In my case, I have ~10 kinds of nodes (it is a graph), so I am looking for something elegant, flexible, with as few lines of code as possible (hence the wrapper template idea) :)
Thank you very much.
To absolutely disassociate code is impossible. They have to talk. If you really want to enforce decoupling to the maximal extent, some sort of IPC/RPC mechanism should be used and have two different programs.
That said -- I don't like visitor patterns.
You have a Graphical object, which is linked against a Behaving object. Maybe there are rules between behavior and the graphics, e.g., boundaries can't overlap.
You can do your entity relationship whatevers between the Graphicals and the Behaves, that's a biz logic question...
You will need some thungus that holds your drawing context (img, screen, buffer).
class DrawingThungus {
void queue_for_render(Graphical*);
void render();
};
Your Graphical will have either an inheritance or a composition relationship with behaves.
At any rate, they will have the interface needed to do Drawing.
//abstract base class class Graphical {
get_x();
get_y();
get_icon();
get_whatever();
};
If you are finding that your Render is becoming case-based depending on the kind of Graphical, I suggest pushing the cases over to the Graphical, and refactoring to have a get_primitives_list(), wherein the needed primitives are returned for Graphical to return (I am presuming that at some level, you have core primitives, lines, circles, arcs, labels, etc).
I have always found that OO analysis lends itself to wasting mental energy and should be done only enough for the task at hand. YAGNI is a tremendous principle.
If your wrapper class (GNode) didn't have to maintain any state across visits (i.e., it only had one field - the wrapped Node object), you could use a pointer or a reference to the wrapped object instead of a copy, and then you would be able to wrap any node at runtime.
But even if you do maintain state (the x,y coordinates), don't you really just infer it from the wrapped object? In that case, wouldn't it be better to separate your visited class from the inferred data? For instance, consider this implementation:
// This is an adapter pattern, so you might want to call it VisitorAdapter if you
// like naming classes after patterns.
template typename<T>
class VisitorAcceptor
{
private:
T& wrapped;
public:
VisitorAcceptor(T& obj)
{
wrapped = obj;
}
template <typename VisitorT>
void accept(VisitorT& v)
{
v.visit(wrapped);
}
};
struct GNode
{
uint x, y;
shared_ptr<GNode> l,r; // use your favourite smart pointer here
template <typename VisitorT>
void accept(VisitorT& v)
}
// You don't have to call a visitor implementation 'Visitor'. It's better to name
// it according to its function, which is, I guess, calculating X,Y coordinates.
{
shared_ptr<GNode> visit(Node& n)
{
shared_ptr<GNode> gnode = new GNode;
// calculate x,y
gnode->x = ...
gnode->y = ...
if (n.l)
gnode->l = VisitorAdapter(n.r).accept(*this);
if (n.r)
gnode->r = VisitorAdapter(n.l).accept(*this);
};
};
Now you can have a different visitor for drawing:
struct GNodeDrawer
{
void visit(GNode& gnode)
{
// print the label and a circle around it: ok.
if (n.r)
visit(n.l);
if (n.r)
visit(n.r);
};
};
Of course, if you don't need all the extensibility the visitor pattern offers, you can throw it away altogether and just walk the the tree recursively with XYCalculator.visit calling itself.
Personally, I would make a drawing class with overloaded functions (one for each node type) rather than trying to hook into the existing structure with some sort of complicated inheritance solution.
I finally found an "elegant" solution with the decorator design pattern.
This pattern is used to extend an object without changing its interface.
GNode decorates/extends Node:
template <class T> struct GNode : public T, public Drawable
{
virtual void accept(Visitor& v); // override Node::accept()
}
As you can see, it requires a little change in the back-end structure:
struct Node
{
Label label;
Node* r, l;
virtual void accept(Visitor& v);
};
That's it ! GNode is-a Node. We can now create a binary tree of GNodes and visit it thanks to the virtual method accept() in the back-end structure.
In the case when we absolutely follow my question, i.e. we can't modify the back-end and it doesn't have the virtual entry point presented above, we can add features to GNode mapping the Node it wraps to itself. So that a visitor visiting GNodes (that can only have access to its sons) can find the GNodes of its sons. Yes, this is the virtual keyword job with the above solution! But we never know if someone would be in this case for real.
As a conclusion to all this: the way you express a problem always influences the way to resolve it.