mirror of https://github.com/deavmi/niknaks
Compare commits
12 Commits
5f66b99434
...
9610689e14
Author | SHA1 | Date |
---|---|---|
Tristan B. Velloza Kildaire | 9610689e14 | |
Tristan B. Velloza Kildaire | 0525bfb95e | |
Tristan B. Velloza Kildaire | c3287bf474 | |
Tristan B. Velloza Kildaire | 6b91fb0f20 | |
Tristan B. Velloza Kildaire | b83cadce82 | |
Tristan B. Velloza Kildaire | c8eacc75a6 | |
Tristan B. Velloza Kildaire | a448fe3665 | |
Tristan B. Velloza Kildaire | 293e3960e1 | |
Tristan B. Velloza Kildaire | fb61d42b5c | |
Tristan B. Velloza Kildaire | 83c3894c9a | |
Tristan B. Velloza Kildaire | 92d753f3c1 | |
Tristan B. Velloza Kildaire | 236d857c49 |
|
@ -23,9 +23,9 @@ version(unittest)
|
|||
{
|
||||
import std.functional : toDelegate;
|
||||
|
||||
private void DebugTouch(T)(Tree!(T) node)
|
||||
private void DebugTouch(T)(Graph!(T) node)
|
||||
{
|
||||
writeln("Touching tree node ", node);
|
||||
writeln("Touching graph node ", node);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -611,9 +611,23 @@ unittest
|
|||
destroy(map);
|
||||
}
|
||||
|
||||
/**
|
||||
* A visitation stratergy
|
||||
* which always returns
|
||||
* `true`
|
||||
*/
|
||||
public template Always(T)
|
||||
{
|
||||
public bool Always(Tree!(T) treeNode)
|
||||
/**
|
||||
* Whatever graph node is
|
||||
* provided always accept
|
||||
* a visitation to it
|
||||
*
|
||||
* Params:
|
||||
* treeNode = the node
|
||||
* Returns: `true` always
|
||||
*/
|
||||
public bool Always(Graph!(T) treeNode)
|
||||
{
|
||||
version(unittest)
|
||||
{
|
||||
|
@ -631,33 +645,33 @@ public template Always(T)
|
|||
public template Nothing(T)
|
||||
{
|
||||
/**
|
||||
* Consumes a tree node
|
||||
* Consumes a graph node
|
||||
* and does zilch with it
|
||||
*
|
||||
* Params:
|
||||
* treeNode = the node
|
||||
*/
|
||||
public void Nothing(Tree!(T));
|
||||
public void Nothing(Graph!(T));
|
||||
}
|
||||
|
||||
/**
|
||||
* The inclusion stratergy which
|
||||
* will be called upon the tree
|
||||
* will be called upon the graph
|
||||
* node prior to it being visited
|
||||
* during a dfs operation.
|
||||
*
|
||||
* It is a predicate to determine
|
||||
* whether or not the tree node
|
||||
* whether or not the graph node
|
||||
* in concern should be recursed
|
||||
* upon.
|
||||
*/
|
||||
public template InclusionStratergy(T)
|
||||
{
|
||||
public alias InclusionStratergy = bool delegate(Tree!(T) item);
|
||||
public alias InclusionStratergy = bool delegate(Graph!(T) item);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is called on a tree node
|
||||
* This is called on a graph node
|
||||
* as part of the first action
|
||||
* that takes place during the
|
||||
* visitation of said node during
|
||||
|
@ -665,22 +679,63 @@ public template InclusionStratergy(T)
|
|||
*/
|
||||
public template TouchStratergy(T)
|
||||
{
|
||||
public alias TouchStratergy = void delegate(Tree!(T) item);
|
||||
public alias TouchStratergy = void delegate(Graph!(T) item);
|
||||
}
|
||||
|
||||
// TODO: Technically this is a graph
|
||||
public class Tree(T)
|
||||
/**
|
||||
* A graph of nodes.
|
||||
*
|
||||
* These nodes are comprised of
|
||||
* two components. The first of
|
||||
* which is their associated value
|
||||
* of type `T`, then the second
|
||||
* are their children nodes
|
||||
* (if any). The latter are of
|
||||
* type `Graph!(T)` and therefore
|
||||
* when constructing one such node
|
||||
* it can also be added as a child
|
||||
* of another node, therefore
|
||||
* allowing you to build your
|
||||
* graph as you see fit.
|
||||
*
|
||||
* Some notable functionality,
|
||||
* other than the obvious,
|
||||
* is the pluggable dfs method
|
||||
* which let's you perform
|
||||
* a recursive search on
|
||||
* the graph, parameterized
|
||||
* by two stratergies. The first
|
||||
* is the so-called `TouchStratergy`
|
||||
* which specifies the function
|
||||
* to be called on the current node
|
||||
* when `dfs` is called on it -
|
||||
* this is the first thing that
|
||||
* is done. The other parameter
|
||||
* is the `VisitationStratergy`
|
||||
* which is a predicate that
|
||||
* will be called BEFORE
|
||||
* entering the dfs (recursing)
|
||||
* of a candidate child node.
|
||||
* With this things like trees
|
||||
* can be built or rather
|
||||
* _derived_ from a graph.
|
||||
* This is infact what the visitation
|
||||
* tree type does.
|
||||
*
|
||||
* See_Also: `VisitationTree`
|
||||
*/
|
||||
public class Graph(T)
|
||||
{
|
||||
private T value;
|
||||
private Tree!(T)[] children;
|
||||
private Graph!(T)[] children;
|
||||
|
||||
/**
|
||||
* Constructs a new tree with
|
||||
* Constructs a new graph with
|
||||
* the given value to set
|
||||
*
|
||||
* Params:
|
||||
* value = the value of
|
||||
* this tree node
|
||||
* this graph node
|
||||
*/
|
||||
this(T value)
|
||||
{
|
||||
|
@ -688,7 +743,7 @@ public class Tree(T)
|
|||
}
|
||||
|
||||
/**
|
||||
* Creates a new tree without
|
||||
* Creates a new graph without
|
||||
* associating any value with
|
||||
* itself
|
||||
*/
|
||||
|
@ -698,7 +753,7 @@ public class Tree(T)
|
|||
}
|
||||
|
||||
/**
|
||||
* Sets the tree node's
|
||||
* Sets the graph node's
|
||||
* associated value
|
||||
*
|
||||
* Params:
|
||||
|
@ -710,7 +765,7 @@ public class Tree(T)
|
|||
}
|
||||
|
||||
/**
|
||||
* Appends another tree node
|
||||
* Appends another graph node
|
||||
* to the array of children
|
||||
* of this node's
|
||||
*
|
||||
|
@ -718,24 +773,24 @@ public class Tree(T)
|
|||
* node = the tree node
|
||||
* to append
|
||||
*/
|
||||
public void appendNode(Tree!(T) node)
|
||||
public void appendNode(Graph!(T) node)
|
||||
{
|
||||
this.children ~= node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a given tree node
|
||||
* Removes a given graph node
|
||||
* from th array of children
|
||||
* of thie node's
|
||||
*
|
||||
* Params:
|
||||
* node = the tree node to
|
||||
* node = the graph node to
|
||||
* remove
|
||||
* Returns: `true` if the node
|
||||
* was found and then removed,
|
||||
* otherwise `false`
|
||||
*/
|
||||
public bool removeNode(Tree!(T) node)
|
||||
public bool removeNode(Graph!(T) node)
|
||||
{
|
||||
bool found = false;
|
||||
size_t idx;
|
||||
|
@ -758,19 +813,34 @@ public class Tree(T)
|
|||
return false;
|
||||
}
|
||||
|
||||
private static bool isTreeNodeType(E)()
|
||||
/**
|
||||
* Checks if the given type is
|
||||
* that of a graph node
|
||||
*
|
||||
* Returns: `true` if so, `false`
|
||||
* otherwise
|
||||
*/
|
||||
private static bool isGraphNodeType(E)()
|
||||
{
|
||||
return __traits(isSame, E, Tree!(T));
|
||||
return __traits(isSame, E, Graph!(T));
|
||||
}
|
||||
|
||||
private static bool isTreeValueType(E)()
|
||||
/**
|
||||
* Checks if the given type is
|
||||
* that of a graph node's value
|
||||
* type
|
||||
*
|
||||
* Returns: `true` if so, `false`
|
||||
* otherwise
|
||||
*/
|
||||
private static bool isGraphValueType(E)()
|
||||
{
|
||||
return __traits(isSame, E, T);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a slice of the requested
|
||||
* type. This is either `Tree!(T)`
|
||||
* type. This is either `Graph!(T)`
|
||||
* or `T` itself, therefore returning
|
||||
* an array of either
|
||||
*
|
||||
|
@ -778,24 +848,22 @@ public class Tree(T)
|
|||
* type of children
|
||||
*/
|
||||
public E[] opSlice(E)()
|
||||
if(isTreeNodeType!(E) || isTreeValueType!(E))
|
||||
if(isGraphNodeType!(E) || isGraphValueType!(E))
|
||||
{
|
||||
// If the children as tree nodes is requested
|
||||
static if(isTreeNodeType!(E))
|
||||
// If the children as graph nodes is requested
|
||||
static if(isGraphNodeType!(E))
|
||||
{
|
||||
return this.children;
|
||||
}
|
||||
// If the children as values themselves is requested
|
||||
else static if(isTreeValueType!(E))
|
||||
else static if(isGraphValueType!(E))
|
||||
{
|
||||
T[] slice;
|
||||
foreach(Tree!(T) tnode; this.children)
|
||||
foreach(Graph!(T) tnode; this.children)
|
||||
{
|
||||
slice ~= tnode.value;
|
||||
}
|
||||
return slice;
|
||||
// import std.algorithm.iteration : map;
|
||||
// return map!(getValue)(this.children)[];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -815,10 +883,10 @@ public class Tree(T)
|
|||
* at the given index.
|
||||
*
|
||||
* The type `E` can be specified
|
||||
* as either `Tree!(T)` or `T`
|
||||
* as either `Graph!(T)` or `T`
|
||||
* which will hence return a node
|
||||
* from the children array at the
|
||||
* given index of that tyope (either
|
||||
* given index of that type (either
|
||||
* the child node or the child node's
|
||||
* value).
|
||||
*
|
||||
|
@ -827,15 +895,15 @@ public class Tree(T)
|
|||
* Returns: the type `E`
|
||||
*/
|
||||
public E opIndex(E)(size_t idx)
|
||||
if(isTreeNodeType!(E) || isTreeValueType!(E))
|
||||
if(isGraphNodeType!(E) || isGraphValueType!(E))
|
||||
{
|
||||
// If the cjild as a tree node is requested
|
||||
static if(isTreeNodeType!(E))
|
||||
// If the child as a graph node is requested
|
||||
static if(isGraphNodeType!(E))
|
||||
{
|
||||
return this.children[idx];
|
||||
}
|
||||
// If the child as a value itself is requested
|
||||
else static if(isTreeValueType!(E))
|
||||
else static if(isGraphValueType!(E))
|
||||
{
|
||||
return this.children[idx].value;
|
||||
}
|
||||
|
@ -855,6 +923,55 @@ public class Tree(T)
|
|||
return opIndex!(T)(idx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number
|
||||
* of children attached
|
||||
* to this node
|
||||
*
|
||||
* Returns: the count
|
||||
*/
|
||||
@property
|
||||
public size_t length()
|
||||
{
|
||||
return this.children.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number
|
||||
* of children attached
|
||||
* to this node
|
||||
*
|
||||
* Returns: the count
|
||||
*/
|
||||
public size_t opDollar()
|
||||
{
|
||||
return this.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a depth first search
|
||||
* on the graph by firstly calling
|
||||
* the `TouchStratergy` on the current
|
||||
* node and then iterating over all
|
||||
* of its children and only recursing
|
||||
* on each of them if the `InclusionStratergy`
|
||||
* allows it.
|
||||
*
|
||||
* The touch stratergy is called
|
||||
* as part of the first line of code
|
||||
* in the call to the dfs on a
|
||||
* given graph node.
|
||||
*
|
||||
* Note that is you don't have a good
|
||||
* inclusion stratergy and touch startergy
|
||||
* then you may have a stack overflow
|
||||
* occur if your graph has cycles
|
||||
*
|
||||
* Params:
|
||||
* strat = the `InclusionStratergy`
|
||||
* touch = the `TouchStratergy`
|
||||
* Returns: a `T[]`
|
||||
*/
|
||||
public T[] dfs
|
||||
(
|
||||
InclusionStratergy!(T) strat = toDelegate(&Always!(T)),
|
||||
|
@ -878,7 +995,7 @@ public class Tree(T)
|
|||
// Touch
|
||||
touch(this); // root[x]
|
||||
|
||||
foreach(Tree!(T) child; this.children) // subtree[x],
|
||||
foreach(Graph!(T) child; this.children) // subtree[x],
|
||||
{
|
||||
if(strat(child))
|
||||
{
|
||||
|
@ -906,27 +1023,36 @@ public class Tree(T)
|
|||
return collected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation
|
||||
* of this node and its value
|
||||
*
|
||||
* Returns: a `string`
|
||||
*/
|
||||
public override string toString()
|
||||
{
|
||||
return format("TreeNode [val: %s]", this.value);
|
||||
return format("GraphNode [val: %s]", this.value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test out usage of the tree
|
||||
* Test out usage of the `Graph!(T)`
|
||||
*/
|
||||
unittest
|
||||
{
|
||||
Tree!(string) treeOfStrings = new Tree!(string)("Top");
|
||||
Graph!(string) treeOfStrings = new Graph!(string)("Top");
|
||||
|
||||
Tree!(string) subtree_1 = new Tree!(string)("1");
|
||||
Tree!(string) subtree_2 = new Tree!(string)("2");
|
||||
Tree!(string) subtree_3 = new Tree!(string)("3");
|
||||
Graph!(string) subtree_1 = new Graph!(string)("1");
|
||||
Graph!(string) subtree_2 = new Graph!(string)("2");
|
||||
Graph!(string) subtree_3 = new Graph!(string)("3");
|
||||
|
||||
treeOfStrings.appendNode(subtree_1);
|
||||
treeOfStrings.appendNode(subtree_2);
|
||||
treeOfStrings.appendNode(subtree_3);
|
||||
|
||||
assert(treeOfStrings.opIndex!(Graph!(string))(0) == subtree_1);
|
||||
assert(treeOfStrings.opIndex!(Graph!(string))(1) == subtree_2);
|
||||
assert(treeOfStrings.opIndex!(Graph!(string))(2) == subtree_3);
|
||||
|
||||
InclusionStratergy!(string) strat = toDelegate(&Always!(string));
|
||||
TouchStratergy!(string) touch = toDelegate(&DebugTouch!(string));
|
||||
|
@ -940,7 +1066,7 @@ unittest
|
|||
assert(result[3] == "Top");
|
||||
|
||||
|
||||
auto i = treeOfStrings.opSlice!(Tree!(string))();
|
||||
auto i = treeOfStrings.opSlice!(Graph!(string))();
|
||||
writeln("Siblings: ", i);
|
||||
assert(i[0] == subtree_1);
|
||||
assert(i[1] == subtree_2);
|
||||
|
@ -956,7 +1082,7 @@ unittest
|
|||
}
|
||||
|
||||
/**
|
||||
* A kind-of a tree which has the ability
|
||||
* A kind-of a graph which has the ability
|
||||
* to linearize all of its nodes which
|
||||
* results in performing a depth first
|
||||
* search resulting in the collection of
|
||||
|
@ -976,7 +1102,7 @@ unittest
|
|||
* relations can be flattened into an
|
||||
* array.
|
||||
*/
|
||||
public class VisitationTree(T) : Tree!(T)
|
||||
public class VisitationTree(T) : Graph!(T)
|
||||
{
|
||||
private bool visisted;
|
||||
|
||||
|
@ -1005,12 +1131,12 @@ public class VisitationTree(T) : Tree!(T)
|
|||
* The inclusion startergy
|
||||
*
|
||||
* Params:
|
||||
* tnode = the tree node
|
||||
* tnode = the graph node
|
||||
* Returns: `true` if not
|
||||
* yet visited or incompatible
|
||||
* node type
|
||||
*/
|
||||
private static bool _shouldVisit(Tree!(T) tnode)
|
||||
private static bool _shouldVisit(Graph!(T) tnode)
|
||||
{
|
||||
VisitationTree!(T) vnode = cast(VisitationTree!(T))tnode;
|
||||
return vnode && !vnode.isVisited();
|
||||
|
@ -1020,12 +1146,12 @@ public class VisitationTree(T) : Tree!(T)
|
|||
* The touching stratergy
|
||||
*
|
||||
* Only works on compatible
|
||||
* tree nodes
|
||||
* graph nodes
|
||||
*
|
||||
* Params:
|
||||
* tnode = the tree node
|
||||
*/
|
||||
private static void _touch(Tree!(T) tnode)
|
||||
private static void _touch(Graph!(T) tnode)
|
||||
{
|
||||
VisitationTree!(T) vnode = cast(VisitationTree!(T))tnode;
|
||||
if(vnode)
|
||||
|
|
Loading…
Reference in New Issue