(TL;DR: Skip to the bold.)
I am trying to build a computer simulation of a modified Hydra -- in this version, each Hydra head can have more Hydra heads coming out of it. I figured this was very node-like, and so I first built a general-purpose Node
class. Each Node
object has an ArrayList<Node>
of children
, each of which (being a Node
also) can have its own children
.
While the structure of the Hydra's heads is the same as Node
, the behavior is different. (Eg. A Node
should be able to simply remove its child, whereas removing a head from a Hydra needs to also regrow some heads.) So I built HydraNode extends Node
and added methods like cutHead()
(which removes a head (node) but then adds clones). A Hydra
is the "body" and has HydraNode
s for heads.
The problem is, because all of the child nodes are stored as an ArrayList<Node>
, I can do
Hydra hydra = new Hydra(1,1,1) // Makes a Hydra with 3 levels (1 head, which has 1 head, which has 1 head).
Node nodeAtLevel1 = hydra.getChildren.get(0); // Has to be declared as Node, not HydraNode, because getChildren() is a Node method, and returns an ArrayList<Node> of children.
, but each of its children are actually nodes. This leads to the problem in main()
, where I try running nodeAtLevel1.cutHead()
but can't, because cutHead()
is a HydraNode
method.
In the case where an object contains itself, how can I add functionality to the class? Extending the object into a subclass
doesn't seem to work, because retrieving the contained object will return an object of type superclass
, not subclass
. And I can't cast it downward. What can I do?
Node.java
public class Node {
// Member variables
private ArrayList<Node> children = new ArrayList<>(); // Holds "children" nodes.
private int hierarchyLevel; // Where in the hierarchy is it?
private int childCount = 0; //How many "child" nodes does this node have?
// Constructors
public Node(int hierarchyLevel) {this.hierarchyLevel = hierarchyLevel}
public Node(int hierarchyLevel, int... nodesPerLevel) {this(hierarchyLevel;} //Adds children to this node, eg. {1,2,1} adds 1 child node at lvl 1, 2 children at lvl 2, each with 1 child of their own at level 3.
// Methods
public ArrayList<Node> getChildren() {return children;}
public void addChild() {} // Adds a child directly to this node
public void removeChild(int i) {}
public Node getCopy() {} //Returns a clone of this Node and all its child nodes.
public String toString() {} // Eg. Node at Level ___ has ____ children.
}
HydraNode.java (the heads)
public class HydraNode extends Node {
// Constructors
public HydraNode(int hierarchyLevel) { // Just call super, bc this is essentially a Node structure that just acts a little differently.
super(hierarchyLevel);
}
public HydraNode(int hierarchyLevel, int... nodesPerLevel) {
super(hierarchyLevel, nodesPerLevel);
// Methods
public void cutHead() {} // Cutting a Level 1 head, which is attached to the body (level 0), does not regrow. However, any other cut will multiply that branch's parent x3.
}
Hydra.java
public class Hydra {
// MAIN method
public static void main(String[] args) {
Hydra hydra = new Hydra(1,1,1);
Node head2 = hydra.body.getChildren().get(0).getChildren().get(0);
System.out.println(head2.toString()); // >> Node at Level 2 has 1 child node.
//head2.cutHead(); // Doesn't work because cutHead() is a HydraNode method, not a Node method.
}
// Member Variables
public static int regrowFactor = 2; // Every time a head is cut off, the hydra clones the remaining branches. In the original video, the hydra forms two new clones.
HydraNode body;
// Constructors
public Hydra() {
body = new HydraNode(0); // the body is just a new Node at level 0
}
public Hydra(int... headsPerLevel) {
body = new HydraNode(0, headsPerLevel);
}
}