diff --git a/src/main/java/baritone/builder/utils/com/github/btrekkie/red_black_node/RedBlackNode.java b/src/main/java/baritone/builder/utils/com/github/btrekkie/red_black_node/RedBlackNode.java deleted file mode 100644 index 5c952961c..000000000 --- a/src/main/java/baritone/builder/utils/com/github/btrekkie/red_black_node/RedBlackNode.java +++ /dev/null @@ -1,1411 +0,0 @@ -/* - * This file was originally written by btrekkie under the MIT license, which is compatible with the LGPL license for this usage within Baritone - * https://github.com/btrekkie/RedBlackNode/blob/master/src/main/java/com/github/btrekkie/red_black_node/RedBlackNode.java - */ - -package baritone.builder.utils.com.github.btrekkie.red_black_node; - -import java.lang.reflect.Array; -import java.util.*; - -/** - * A node in a red-black tree ( https://en.wikipedia.org/wiki/Red%E2%80%93black_tree ). Compared to a class like Java's - * TreeMap, RedBlackNode is a low-level data structure. The internals of a node are exposed as public fields, allowing - * clients to directly observe and manipulate the structure of the tree. This gives clients flexibility, although it - * also enables them to violate the red-black or BST properties. The RedBlackNode class provides methods for performing - * various standard operations, such as insertion and removal. - *

- * Unlike most implementations of binary search trees, RedBlackNode supports arbitrary augmentation. By subclassing - * RedBlackNode, clients can add arbitrary data and augmentation information to each node. For example, if we were to - * use a RedBlackNode subclass to implement a sorted set, the subclass would have a field storing an element in the set. - * If we wanted to keep track of the number of non-leaf nodes in each subtree, we would store this as a "size" field and - * override augment() to update this field. All RedBlackNode methods (such as "insert" and remove()) call augment() as - * necessary to correctly maintain the augmentation information, unless otherwise indicated. - *

- * The values of the tree are stored in the non-leaf nodes. RedBlackNode does not support use cases where values must be - * stored in the leaf nodes. It is recommended that all of the leaf nodes in a given tree be the same (black) - * RedBlackNode instance, to save space. The root of an empty tree is a leaf node, as opposed to null. - *

- * For reference, a red-black tree is a binary search tree satisfying the following properties: - *

- * - Every node is colored red or black. - * - The leaf nodes, which are dummy nodes that do not store any values, are colored black. - * - The root is black. - * - Both children of each red node are black. - * - Every path from the root to a leaf contains the same number of black nodes. - * - * @param The type of node in the tree. For example, we might have - * "class FooNode extends RedBlackNode>". - * @author Bill Jacobs - */ -public abstract class RedBlackNode> implements Comparable { - /** - * A Comparator that compares Comparable elements using their natural order. - */ - private static final Comparator> NATURAL_ORDER = new Comparator>() { - @Override - public int compare(Comparable value1, Comparable value2) { - return value1.compareTo(value2); - } - }; - - /** - * The parent of this node, if any. "parent" is null if this is a leaf node. - */ - public N parent; - - /** - * The left child of this node. "left" is null if this is a leaf node. - */ - public N left; - - /** - * The right child of this node. "right" is null if this is a leaf node. - */ - public N right; - - /** - * Whether the node is colored red, as opposed to black. - */ - public boolean isRed; - - /** - * Sets any augmentation information about the subtree rooted at this node that is stored in this node. For - * example, if we augment each node by subtree size (the number of non-leaf nodes in the subtree), this method would - * set the size field of this node to be equal to the size field of the left child plus the size field of the right - * child plus one. - *

- * "Augmentation information" is information that we can compute about a subtree rooted at some node, preferably - * based only on the augmentation information in the node's two children and the information in the node. Examples - * of augmentation information are the sum of the values in a subtree and the number of non-leaf nodes in a subtree. - * Augmentation information may not depend on the colors of the nodes. - *

- * This method returns whether the augmentation information in any of the ancestors of this node might have been - * affected by changes in this subtree since the last call to augment(). In the usual case, where the augmentation - * information depends only on the information in this node and the augmentation information in its immediate - * children, this is equivalent to whether the augmentation information changed as a result of this call to - * augment(). For example, in the case of subtree size, this returns whether the value of the size field prior to - * calling augment() differed from the size field of the left child plus the size field of the right child plus one. - * False positives are permitted. The return value is unspecified if we have not called augment() on this node - * before. - *

- * This method may assume that this is not a leaf node. It may not assume that the augmentation information stored - * in any of the tree's nodes is correct. However, if the augmentation information stored in all of the node's - * descendants is correct, then the augmentation information stored in this node must be correct after calling - * augment(). - */ - public boolean augment() { - return false; - } - - /** - * Throws a RuntimeException if we detect that this node locally violates any invariants specific to this subclass - * of RedBlackNode. For example, if this stores the size of the subtree rooted at this node, this should throw a - * RuntimeException if the size field of this is not equal to the size field of the left child plus the size field - * of the right child plus one. Note that we may call this on a leaf node. - *

- * assertSubtreeIsValid() calls assertNodeIsValid() on each node, or at least starts to do so until it detects a - * problem. assertNodeIsValid() should assume the node is in a tree that satisfies all properties common to all - * red-black trees, as assertSubtreeIsValid() is responsible for such checks. assertNodeIsValid() should be - * "downward-looking", i.e. it should ignore any information in "parent", and it should be "local", i.e. it should - * only check a constant number of descendants. To include "global" checks, such as verifying the BST property - * concerning ordering, override assertSubtreeIsValid(). assertOrderIsValid is useful for checking the BST - * property. - */ - public void assertNodeIsValid() { - - } - - /** - * Returns whether this is a leaf node. - */ - public boolean isLeaf() { - return left == null; - } - - /** - * Returns the root of the tree that contains this node. - */ - public N root() { - @SuppressWarnings("unchecked") - N node = (N) this; - while (node.parent != null) { - node = node.parent; - } - return node; - } - - /** - * Returns the first node in the subtree rooted at this node, if any. - */ - public N min() { - if (isLeaf()) { - return null; - } - @SuppressWarnings("unchecked") - N node = (N) this; - while (!node.left.isLeaf()) { - node = node.left; - } - return node; - } - - /** - * Returns the last node in the subtree rooted at this node, if any. - */ - public N max() { - if (isLeaf()) { - return null; - } - @SuppressWarnings("unchecked") - N node = (N) this; - while (!node.right.isLeaf()) { - node = node.right; - } - return node; - } - - /** - * Returns the node immediately before this in the tree that contains this node, if any. - */ - public N predecessor() { - if (!left.isLeaf()) { - N node; - for (node = left; !node.right.isLeaf(); node = node.right) ; - return node; - } else if (parent == null) { - return null; - } else { - @SuppressWarnings("unchecked") - N node = (N) this; - while (node.parent != null && node.parent.left == node) { - node = node.parent; - } - return node.parent; - } - } - - /** - * Returns the node immediately after this in the tree that contains this node, if any. - */ - public N successor() { - if (!right.isLeaf()) { - N node; - for (node = right; !node.left.isLeaf(); node = node.left) ; - return node; - } else if (parent == null) { - return null; - } else { - @SuppressWarnings("unchecked") - N node = (N) this; - while (node.parent != null && node.parent.right == node) { - node = node.parent; - } - return node.parent; - } - } - - /** - * Performs a left rotation about this node. This method assumes that !isLeaf() && !right.isLeaf(). It calls - * augment() on this node and on its resulting parent. However, it does not call augment() on any of the resulting - * parent's ancestors, because that is normally the responsibility of the caller. - * - * @return The return value from calling augment() on the resulting parent. - */ - public boolean rotateLeft() { - if (isLeaf() || right.isLeaf()) { - throw new IllegalArgumentException("The node or its right child is a leaf"); - } - N newParent = right; - right = newParent.left; - @SuppressWarnings("unchecked") - N nThis = (N) this; - if (!right.isLeaf()) { - right.parent = nThis; - } - newParent.parent = parent; - parent = newParent; - newParent.left = nThis; - if (newParent.parent != null) { - if (newParent.parent.left == this) { - newParent.parent.left = newParent; - } else { - newParent.parent.right = newParent; - } - } - augment(); - return newParent.augment(); - } - - /** - * Performs a right rotation about this node. This method assumes that !isLeaf() && !left.isLeaf(). It calls - * augment() on this node and on its resulting parent. However, it does not call augment() on any of the resulting - * parent's ancestors, because that is normally the responsibility of the caller. - * - * @return The return value from calling augment() on the resulting parent. - */ - public boolean rotateRight() { - if (isLeaf() || left.isLeaf()) { - throw new IllegalArgumentException("The node or its left child is a leaf"); - } - N newParent = left; - left = newParent.right; - @SuppressWarnings("unchecked") - N nThis = (N) this; - if (!left.isLeaf()) { - left.parent = nThis; - } - newParent.parent = parent; - parent = newParent; - newParent.right = nThis; - if (newParent.parent != null) { - if (newParent.parent.left == this) { - newParent.parent.left = newParent; - } else { - newParent.parent.right = newParent; - } - } - augment(); - return newParent.augment(); - } - - /** - * Performs red-black insertion fixup. To be more precise, this fixes a tree that satisfies all of the requirements - * of red-black trees, except that this may be a red child of a red node, and if this is the root, the root may be - * red. node.isRed must initially be true. This method assumes that this is not a leaf node. The method performs - * any rotations by calling rotateLeft() and rotateRight(). This method is more efficient than fixInsertion if - * "augment" is false or augment() might return false. - * - * @param augment Whether to set the augmentation information for "node" and its ancestors, by calling augment(). - */ - public void fixInsertionWithoutGettingRoot(boolean augment) { - if (!isRed) { - throw new IllegalArgumentException("The node must be red"); - } - boolean changed = augment; - if (augment) { - augment(); - } - - RedBlackNode node = this; - while (node.parent != null && node.parent.isRed) { - N parent = node.parent; - N grandparent = parent.parent; - if (grandparent.left.isRed && grandparent.right.isRed) { - grandparent.left.isRed = false; - grandparent.right.isRed = false; - grandparent.isRed = true; - - if (changed) { - changed = parent.augment(); - if (changed) { - changed = grandparent.augment(); - } - } - node = grandparent; - } else { - if (parent.left == node) { - if (grandparent.right == parent) { - parent.rotateRight(); - node = parent; - parent = node.parent; - } - } else if (grandparent.left == parent) { - parent.rotateLeft(); - node = parent; - parent = node.parent; - } - - if (parent.left == node) { - boolean grandparentChanged = grandparent.rotateRight(); - if (augment) { - changed = grandparentChanged; - } - } else { - boolean grandparentChanged = grandparent.rotateLeft(); - if (augment) { - changed = grandparentChanged; - } - } - - parent.isRed = false; - grandparent.isRed = true; - node = parent; - break; - } - } - - if (node.parent == null) { - node.isRed = false; - } - if (changed) { - for (node = node.parent; node != null; node = node.parent) { - if (!node.augment()) { - break; - } - } - } - } - - /** - * Performs red-black insertion fixup. To be more precise, this fixes a tree that satisfies all of the requirements - * of red-black trees, except that this may be a red child of a red node, and if this is the root, the root may be - * red. node.isRed must initially be true. This method assumes that this is not a leaf node. The method performs - * any rotations by calling rotateLeft() and rotateRight(). This method is more efficient than fixInsertion() if - * augment() might return false. - */ - public void fixInsertionWithoutGettingRoot() { - fixInsertionWithoutGettingRoot(true); - } - - /** - * Performs red-black insertion fixup. To be more precise, this fixes a tree that satisfies all of the requirements - * of red-black trees, except that this may be a red child of a red node, and if this is the root, the root may be - * red. node.isRed must initially be true. This method assumes that this is not a leaf node. The method performs - * any rotations by calling rotateLeft() and rotateRight(). - * - * @param augment Whether to set the augmentation information for "node" and its ancestors, by calling augment(). - * @return The root of the resulting tree. - */ - public N fixInsertion(boolean augment) { - fixInsertionWithoutGettingRoot(augment); - return root(); - } - - /** - * Performs red-black insertion fixup. To be more precise, this fixes a tree that satisfies all of the requirements - * of red-black trees, except that this may be a red child of a red node, and if this is the root, the root may be - * red. node.isRed must initially be true. This method assumes that this is not a leaf node. The method performs - * any rotations by calling rotateLeft() and rotateRight(). - * - * @return The root of the resulting tree. - */ - public N fixInsertion() { - fixInsertionWithoutGettingRoot(true); - return root(); - } - - /** - * Returns a Comparator that compares instances of N using their natural order, as in N.compareTo. - */ - @SuppressWarnings({"rawtypes", "unchecked"}) - private Comparator naturalOrder() { - Comparator comparator = (Comparator) NATURAL_ORDER; - return (Comparator) comparator; - } - - /** - * Inserts the specified node into the tree rooted at this node. Assumes this is the root. We treat newNode as a - * solitary node that does not belong to any tree, and we ignore its initial "parent", "left", "right", and isRed - * fields. - *

- * If it is not efficient or convenient to find the location for a node using a Comparator, then you should manually - * add the node to the appropriate location, color it red, and call fixInsertion(). - * - * @param newNode The node to insert. - * @param allowDuplicates Whether to insert newNode if there is an equal node in the tree. To check whether we - * inserted newNode, check whether newNode.parent is null and the return value differs from newNode. - * @param comparator A comparator indicating where to put the node. If this is null, we use the nodes' natural - * order, as in N.compareTo. If you are passing null, then you must override the compareTo method, because the - * default implementation requires the nodes to already be in the same tree. - * @return The root of the resulting tree. - */ - public N insert(N newNode, boolean allowDuplicates, Comparator comparator) { - if (parent != null) { - throw new IllegalArgumentException("This is not the root of a tree"); - } - @SuppressWarnings("unchecked") - N nThis = (N) this; - if (isLeaf()) { - newNode.isRed = false; - newNode.left = nThis; - newNode.right = nThis; - newNode.parent = null; - newNode.augment(); - return newNode; - } - if (comparator == null) { - comparator = naturalOrder(); - } - - N node = nThis; - int comparison; - while (true) { - comparison = comparator.compare(newNode, node); - if (comparison < 0) { - if (!node.left.isLeaf()) { - node = node.left; - } else { - newNode.left = node.left; - newNode.right = node.left; - node.left = newNode; - newNode.parent = node; - break; - } - } else if (comparison > 0 || allowDuplicates) { - if (!node.right.isLeaf()) { - node = node.right; - } else { - newNode.left = node.right; - newNode.right = node.right; - node.right = newNode; - newNode.parent = node; - break; - } - } else { - newNode.parent = null; - return nThis; - } - } - newNode.isRed = true; - return newNode.fixInsertion(); - } - - /** - * Moves this node to its successor's former position in the tree and vice versa, i.e. sets the "left", "right", - * "parent", and isRed fields of each. This method assumes that this is not a leaf node. - * - * @return The node with which we swapped. - */ - private N swapWithSuccessor() { - N replacement = successor(); - boolean oldReplacementIsRed = replacement.isRed; - N oldReplacementLeft = replacement.left; - N oldReplacementRight = replacement.right; - N oldReplacementParent = replacement.parent; - - replacement.isRed = isRed; - replacement.left = left; - replacement.right = right; - replacement.parent = parent; - if (parent != null) { - if (parent.left == this) { - parent.left = replacement; - } else { - parent.right = replacement; - } - } - - @SuppressWarnings("unchecked") - N nThis = (N) this; - isRed = oldReplacementIsRed; - left = oldReplacementLeft; - right = oldReplacementRight; - if (oldReplacementParent == this) { - parent = replacement; - parent.right = nThis; - } else { - parent = oldReplacementParent; - parent.left = nThis; - } - - replacement.right.parent = replacement; - if (!replacement.left.isLeaf()) { - replacement.left.parent = replacement; - } - if (!right.isLeaf()) { - right.parent = nThis; - } - return replacement; - } - - /** - * Performs red-black deletion fixup. To be more precise, this fixes a tree that satisfies all of the requirements - * of red-black trees, except that all paths from the root to a leaf that pass through the sibling of this node have - * one fewer black node than all other root-to-leaf paths. This method assumes that this is not a leaf node. - */ - private void fixSiblingDeletion() { - RedBlackNode sibling = this; - boolean changed = true; - boolean haveAugmentedParent = false; - boolean haveAugmentedGrandparent = false; - while (true) { - N parent = sibling.parent; - if (sibling.isRed) { - parent.isRed = true; - sibling.isRed = false; - if (parent.left == sibling) { - changed = parent.rotateRight(); - sibling = parent.left; - } else { - changed = parent.rotateLeft(); - sibling = parent.right; - } - haveAugmentedParent = true; - haveAugmentedGrandparent = true; - } else if (!sibling.left.isRed && !sibling.right.isRed) { - sibling.isRed = true; - if (parent.isRed) { - parent.isRed = false; - break; - } else { - if (changed && !haveAugmentedParent) { - changed = parent.augment(); - } - N grandparent = parent.parent; - if (grandparent == null) { - break; - } else if (grandparent.left == parent) { - sibling = grandparent.right; - } else { - sibling = grandparent.left; - } - haveAugmentedParent = haveAugmentedGrandparent; - haveAugmentedGrandparent = false; - } - } else { - if (sibling == parent.left) { - if (!sibling.left.isRed) { - sibling.rotateLeft(); - sibling = sibling.parent; - } - } else if (!sibling.right.isRed) { - sibling.rotateRight(); - sibling = sibling.parent; - } - sibling.isRed = parent.isRed; - parent.isRed = false; - if (sibling == parent.left) { - sibling.left.isRed = false; - changed = parent.rotateRight(); - } else { - sibling.right.isRed = false; - changed = parent.rotateLeft(); - } - haveAugmentedParent = haveAugmentedGrandparent; - haveAugmentedGrandparent = false; - break; - } - } - - // Update augmentation info - N parent = sibling.parent; - if (changed && parent != null) { - if (!haveAugmentedParent) { - changed = parent.augment(); - } - if (changed && parent.parent != null) { - parent = parent.parent; - if (!haveAugmentedGrandparent) { - changed = parent.augment(); - } - if (changed) { - for (parent = parent.parent; parent != null; parent = parent.parent) { - if (!parent.augment()) { - break; - } - } - } - } - } - } - - /** - * Removes this node from the tree that contains it. The effect of this method on the fields of this node is - * unspecified. This method assumes that this is not a leaf node. This method is more efficient than remove() if - * augment() might return false. - *

- * If the node has two children, we begin by moving the node's successor to its former position, by changing the - * successor's "left", "right", "parent", and isRed fields. - */ - public void removeWithoutGettingRoot() { - if (isLeaf()) { - throw new IllegalArgumentException("Attempted to remove a leaf node"); - } - N replacement; - if (left.isLeaf() || right.isLeaf()) { - replacement = null; - } else { - replacement = swapWithSuccessor(); - } - - N child; - if (!left.isLeaf()) { - child = left; - } else if (!right.isLeaf()) { - child = right; - } else { - child = null; - } - - if (child != null) { - // Replace this node with its child - child.parent = parent; - if (parent != null) { - if (parent.left == this) { - parent.left = child; - } else { - parent.right = child; - } - } - child.isRed = false; - - if (child.parent != null) { - N parent; - for (parent = child.parent; parent != null; parent = parent.parent) { - if (!parent.augment()) { - break; - } - } - } - } else if (parent != null) { - // Replace this node with a leaf node - N leaf = left; - N parent = this.parent; - N sibling; - if (parent.left == this) { - parent.left = leaf; - sibling = parent.right; - } else { - parent.right = leaf; - sibling = parent.left; - } - - if (!isRed) { - RedBlackNode siblingNode = sibling; - siblingNode.fixSiblingDeletion(); - } else { - while (parent != null) { - if (!parent.augment()) { - break; - } - parent = parent.parent; - } - } - } - - if (replacement != null) { - replacement.augment(); - for (N parent = replacement.parent; parent != null; parent = parent.parent) { - if (!parent.augment()) { - break; - } - } - } - - // Clear any previously existing links, so that we're more likely to encounter an exception if we attempt to - // access the removed node - parent = null; - left = null; - right = null; - isRed = true; - } - - /** - * Removes this node from the tree that contains it. The effect of this method on the fields of this node is - * unspecified. This method assumes that this is not a leaf node. - *

- * If the node has two children, we begin by moving the node's successor to its former position, by changing the - * successor's "left", "right", "parent", and isRed fields. - * - * @return The root of the resulting tree. - */ - public N remove() { - if (isLeaf()) { - throw new IllegalArgumentException("Attempted to remove a leaf node"); - } - - // Find an arbitrary non-leaf node in the tree other than this node - N node; - if (parent != null) { - node = parent; - } else if (!left.isLeaf()) { - node = left; - } else if (!right.isLeaf()) { - node = right; - } else { - return left; - } - - removeWithoutGettingRoot(); - return node.root(); - } - - /** - * Returns the root of a perfectly height-balanced subtree containing the next "size" (non-leaf) nodes from - * "iterator", in iteration order. This method is responsible for setting the "left", "right", "parent", and isRed - * fields of the nodes, and calling augment() as appropriate. It ignores the initial values of the "left", "right", - * "parent", and isRed fields. - * - * @param iterator The nodes. - * @param size The number of nodes. - * @param height The "height" of the subtree's root node above the deepest leaf in the tree that contains it. Since - * insertion fixup is slow if there are too many red nodes and deleteion fixup is slow if there are too few red - * nodes, we compromise and have red nodes at every fourth level. We color a node red iff its "height" is equal - * to 1 mod 4. - * @param leaf The leaf node. - * @return The root of the subtree. - */ - private static > N createTree( - Iterator iterator, int size, int height, N leaf) { - if (size == 0) { - return leaf; - } else { - N left = createTree(iterator, (size - 1) / 2, height - 1, leaf); - N node = iterator.next(); - N right = createTree(iterator, size / 2, height - 1, leaf); - - node.isRed = height % 4 == 1; - node.left = left; - node.right = right; - if (!left.isLeaf()) { - left.parent = node; - } - if (!right.isLeaf()) { - right.parent = node; - } - - node.augment(); - return node; - } - } - - /** - * Returns the root of a perfectly height-balanced tree containing the specified nodes, in iteration order. This - * method is responsible for setting the "left", "right", "parent", and isRed fields of the nodes (excluding - * "leaf"), and calling augment() as appropriate. It ignores the initial values of the "left", "right", "parent", - * and isRed fields. - * - * @param nodes The nodes. - * @param leaf The leaf node. - * @return The root of the tree. - */ - public static > N createTree(Collection nodes, N leaf) { - int size = nodes.size(); - if (size == 0) { - return leaf; - } - - int height = 0; - for (int subtreeSize = size; subtreeSize > 0; subtreeSize /= 2) { - height++; - } - - N node = createTree(nodes.iterator(), size, height, leaf); - node.parent = null; - node.isRed = false; - return node; - } - - /** - * Concatenates to the end of the tree rooted at this node. To be precise, given that all of the nodes in this - * precede the node "pivot", which precedes all of the nodes in "last", this returns the root of a tree containing - * all of these nodes. This method destroys the trees rooted at "this" and "last". We treat "pivot" as a solitary - * node that does not belong to any tree, and we ignore its initial "parent", "left", "right", and isRed fields. - * This method assumes that this node and "last" are the roots of their respective trees. - *

- * This method takes O(log N) time. It is more efficient than inserting "pivot" and then calling concatenate(last). - * It is considerably more efficient than inserting "pivot" and all of the nodes in "last". - */ - public N concatenate(N last, N pivot) { - // If the black height of "first", where first = this, is less than or equal to that of "last", starting at the - // root of "last", we keep going left until we reach a black node whose black height is equal to that of - // "first". Then, we make "pivot" the parent of that node and of "first", coloring it red, and perform - // insertion fixup on the pivot. If the black height of "first" is greater than that of "last", we do the - // mirror image of the above. - - if (parent != null) { - throw new IllegalArgumentException("This is not the root of a tree"); - } - if (last.parent != null) { - throw new IllegalArgumentException("\"last\" is not the root of a tree"); - } - - // Compute the black height of the trees - int firstBlackHeight = 0; - @SuppressWarnings("unchecked") - N first = (N) this; - for (N node = first; node != null; node = node.right) { - if (!node.isRed) { - firstBlackHeight++; - } - } - int lastBlackHeight = 0; - for (N node = last; node != null; node = node.right) { - if (!node.isRed) { - lastBlackHeight++; - } - } - - // Identify the children and parent of pivot - N firstChild = first; - N lastChild = last; - N parent; - if (firstBlackHeight <= lastBlackHeight) { - parent = null; - int blackHeight = lastBlackHeight; - while (blackHeight > firstBlackHeight) { - if (!lastChild.isRed) { - blackHeight--; - } - parent = lastChild; - lastChild = lastChild.left; - } - if (lastChild.isRed) { - parent = lastChild; - lastChild = lastChild.left; - } - } else { - parent = null; - int blackHeight = firstBlackHeight; - while (blackHeight > lastBlackHeight) { - if (!firstChild.isRed) { - blackHeight--; - } - parent = firstChild; - firstChild = firstChild.right; - } - if (firstChild.isRed) { - parent = firstChild; - firstChild = firstChild.right; - } - } - - // Add "pivot" to the tree - pivot.isRed = true; - pivot.parent = parent; - if (parent != null) { - if (firstBlackHeight < lastBlackHeight) { - parent.left = pivot; - } else { - parent.right = pivot; - } - } - pivot.left = firstChild; - if (!firstChild.isLeaf()) { - firstChild.parent = pivot; - } - pivot.right = lastChild; - if (!lastChild.isLeaf()) { - lastChild.parent = pivot; - } - - // Perform insertion fixup - return pivot.fixInsertion(); - } - - /** - * Concatenates the tree rooted at "last" to the end of the tree rooted at this node. To be precise, given that all - * of the nodes in this precede all of the nodes in "last", this returns the root of a tree containing all of these - * nodes. This method destroys the trees rooted at "this" and "last". It assumes that this node and "last" are the - * roots of their respective trees. This method takes O(log N) time. It is considerably more efficient than - * inserting all of the nodes in "last". - */ - public N concatenate(N last) { - if (parent != null || last.parent != null) { - throw new IllegalArgumentException("The node is not the root of a tree"); - } - if (isLeaf()) { - return last; - } else if (last.isLeaf()) { - @SuppressWarnings("unchecked") - N nThis = (N) this; - return nThis; - } else { - N node = last.min(); - last = node.remove(); - return concatenate(last, node); - } - } - - /** - * Splits the tree rooted at this node into two trees, so that the first element of the return value is the root of - * a tree consisting of the nodes that were before the specified node, and the second element of the return value is - * the root of a tree consisting of the nodes that were equal to or after the specified node. This method is - * destructive, meaning it does not preserve the original tree. It assumes that this node is the root and is in the - * same tree as splitNode. It takes O(log N) time. It is considerably more efficient than removing all of the - * nodes at or after splitNode and then creating a new tree from those nodes. - * - * @param The node at which to split the tree. - * @return An array consisting of the resulting trees. - */ - public N[] split(N splitNode) { - // To split the tree, we accumulate a pre-split tree and a post-split tree. We walk down the tree toward the - // position where we are splitting. Whenever we go left, we concatenate the right subtree with the post-split - // tree, and whenever we go right, we concatenate the pre-split tree with the left subtree. We use the - // concatenation algorithm described in concatenate(Object, Object). For the pivot, we use the last node where - // we went left in the case of a left move, and the last node where we went right in the case of a right move. - // - // The method uses the following variables: - // - // node: The current node in our walk down the tree. - // first: A node on the right spine of the pre-split tree. At the beginning of each iteration, it is the black - // node with the same black height as "node". If the pre-split tree is empty, this is null instead. - // firstParent: The parent of "first". If the pre-split tree is empty, this is null. Otherwise, this is the - // same as first.parent, unless first.isLeaf(). - // firstPivot: The node where we last went right, i.e. the next node to use as a pivot when concatenating with - // the pre-split tree. - // advanceFirst: Whether to set "first" to be its next black descendant at the end of the loop. - // last, lastParent, lastPivot, advanceLast: Analogous to "first", firstParent, firstPivot, and advanceFirst, - // but for the post-split tree. - if (parent != null) { - throw new IllegalArgumentException("This is not the root of a tree"); - } - if (isLeaf() || splitNode.isLeaf()) { - throw new IllegalArgumentException("The root or the split node is a leaf"); - } - - // Create an array containing the path from the root to splitNode - int depth = 1; - N parent; - for (parent = splitNode; parent.parent != null; parent = parent.parent) { - depth++; - } - if (parent != this) { - throw new IllegalArgumentException("The split node does not belong to this tree"); - } - RedBlackNode[] path = new RedBlackNode[depth]; - for (parent = splitNode; parent != null; parent = parent.parent) { - depth--; - path[depth] = parent; - } - - @SuppressWarnings("unchecked") - N node = (N) this; - N first = null; - N firstParent = null; - N last = null; - N lastParent = null; - N firstPivot = null; - N lastPivot = null; - while (!node.isLeaf()) { - boolean advanceFirst = !node.isRed && firstPivot != null; - boolean advanceLast = !node.isRed && lastPivot != null; - if ((depth + 1 < path.length && path[depth + 1] == node.left) || depth + 1 == path.length) { - // Left move - if (lastPivot == null) { - // The post-split tree is empty - last = node.right; - last.parent = null; - if (last.isRed) { - last.isRed = false; - lastParent = last; - last = last.left; - } - } else { - // Concatenate node.right and the post-split tree - if (node.right.isRed) { - node.right.isRed = false; - } else if (!node.isRed) { - lastParent = last; - last = last.left; - if (last.isRed) { - lastParent = last; - last = last.left; - } - advanceLast = false; - } - lastPivot.isRed = true; - lastPivot.parent = lastParent; - if (lastParent != null) { - lastParent.left = lastPivot; - } - lastPivot.left = node.right; - if (!lastPivot.left.isLeaf()) { - lastPivot.left.parent = lastPivot; - } - lastPivot.right = last; - if (!last.isLeaf()) { - last.parent = lastPivot; - } - last = lastPivot.left; - lastParent = lastPivot; - lastPivot.fixInsertionWithoutGettingRoot(false); - } - lastPivot = node; - node = node.left; - } else { - // Right move - if (firstPivot == null) { - // The pre-split tree is empty - first = node.left; - first.parent = null; - if (first.isRed) { - first.isRed = false; - firstParent = first; - first = first.right; - } - } else { - // Concatenate the post-split tree and node.left - if (node.left.isRed) { - node.left.isRed = false; - } else if (!node.isRed) { - firstParent = first; - first = first.right; - if (first.isRed) { - firstParent = first; - first = first.right; - } - advanceFirst = false; - } - firstPivot.isRed = true; - firstPivot.parent = firstParent; - if (firstParent != null) { - firstParent.right = firstPivot; - } - firstPivot.right = node.left; - if (!firstPivot.right.isLeaf()) { - firstPivot.right.parent = firstPivot; - } - firstPivot.left = first; - if (!first.isLeaf()) { - first.parent = firstPivot; - } - first = firstPivot.right; - firstParent = firstPivot; - firstPivot.fixInsertionWithoutGettingRoot(false); - } - firstPivot = node; - node = node.right; - } - - depth++; - - // Update "first" and "last" to be the nodes at the proper black height - if (advanceFirst) { - firstParent = first; - first = first.right; - if (first.isRed) { - firstParent = first; - first = first.right; - } - } - if (advanceLast) { - lastParent = last; - last = last.left; - if (last.isRed) { - lastParent = last; - last = last.left; - } - } - } - - // Add firstPivot to the pre-split tree - N leaf = node; - if (first == null) { - first = leaf; - } else { - firstPivot.isRed = true; - firstPivot.parent = firstParent; - if (firstParent != null) { - firstParent.right = firstPivot; - } - firstPivot.left = leaf; - firstPivot.right = leaf; - firstPivot.fixInsertionWithoutGettingRoot(false); - for (first = firstPivot; first.parent != null; first = first.parent) { - first.augment(); - } - first.augment(); - } - - // Add lastPivot to the post-split tree - lastPivot.isRed = true; - lastPivot.parent = lastParent; - if (lastParent != null) { - lastParent.left = lastPivot; - } - lastPivot.left = leaf; - lastPivot.right = leaf; - lastPivot.fixInsertionWithoutGettingRoot(false); - for (last = lastPivot; last.parent != null; last = last.parent) { - last.augment(); - } - last.augment(); - - @SuppressWarnings("unchecked") - N[] result = (N[]) Array.newInstance(getClass(), 2); - result[0] = first; - result[1] = last; - return result; - } - - /** - * Returns the lowest common ancestor of this node and "other" - the node that is an ancestor of both and is not the - * parent of a node that is an ancestor of both. Assumes that this is in the same tree as "other". Assumes that - * neither "this" nor "other" is a leaf node. This method may return "this" or "other". - *

- * Note that while it is possible to compute the lowest common ancestor in O(P) time, where P is the length of the - * path from this node to "other", the "lca" method is not guaranteed to take O(P) time. If your application - * requires this, then you should write your own lowest common ancestor method. - */ - public N lca(N other) { - if (isLeaf() || other.isLeaf()) { - throw new IllegalArgumentException("One of the nodes is a leaf node"); - } - - // Compute the depth of each node - int depth = 0; - for (N parent = this.parent; parent != null; parent = parent.parent) { - depth++; - } - int otherDepth = 0; - for (N parent = other.parent; parent != null; parent = parent.parent) { - otherDepth++; - } - - // Go up to nodes of the same depth - @SuppressWarnings("unchecked") - N parent = (N) this; - N otherParent = other; - if (depth <= otherDepth) { - for (int i = otherDepth; i > depth; i--) { - otherParent = otherParent.parent; - } - } else { - for (int i = depth; i > otherDepth; i--) { - parent = parent.parent; - } - } - - // Find the LCA - while (parent != otherParent) { - parent = parent.parent; - otherParent = otherParent.parent; - } - if (parent != null) { - return parent; - } else { - throw new IllegalArgumentException("The nodes do not belong to the same tree"); - } - } - - /** - * Returns an integer comparing the position of this node in the tree that contains it with that of "other". Returns - * a negative number if this is earlier, a positive number if this is later, and 0 if this is at the same position. - * Assumes that this is in the same tree as "other". Assumes that neither "this" nor "other" is a leaf node. - *

- * The base class's implementation takes O(log N) time. If a RedBlackNode subclass stores a value used to order the - * nodes, then it could override compareTo to compare the nodes' values, which would take O(1) time. - *

- * Note that while it is possible to compare the positions of two nodes in O(P) time, where P is the length of the - * path from this node to "other", the default implementation of compareTo is not guaranteed to take O(P) time. If - * your application requires this, then you should write your own comparison method. - */ - @Override - public int compareTo(N other) { - if (isLeaf() || other.isLeaf()) { - throw new IllegalArgumentException("One of the nodes is a leaf node"); - } - - // The algorithm operates as follows: compare the depth of this node to that of "other". If the depth of - // "other" is greater, keep moving up from "other" until we find the ancestor at the same depth. Then, keep - // moving up from "this" and from that node until we reach the lowest common ancestor. The node that arrived - // from the left child of the common ancestor is earlier. The algorithm is analogous if the depth of "other" is - // not greater. - if (this == other) { - return 0; - } - - // Compute the depth of each node - int depth = 0; - RedBlackNode parent; - for (parent = this; parent.parent != null; parent = parent.parent) { - depth++; - } - int otherDepth = 0; - N otherParent; - for (otherParent = other; otherParent.parent != null; otherParent = otherParent.parent) { - otherDepth++; - } - - // Go up to nodes of the same depth - if (depth < otherDepth) { - otherParent = other; - for (int i = otherDepth - 1; i > depth; i--) { - otherParent = otherParent.parent; - } - if (otherParent.parent != this) { - otherParent = otherParent.parent; - } else if (left == otherParent) { - return 1; - } else { - return -1; - } - parent = this; - } else if (depth > otherDepth) { - parent = this; - for (int i = depth - 1; i > otherDepth; i--) { - parent = parent.parent; - } - if (parent.parent != other) { - parent = parent.parent; - } else if (other.left == parent) { - return -1; - } else { - return 1; - } - otherParent = other; - } else { - parent = this; - otherParent = other; - } - - // Keep going up until we reach the lowest common ancestor - while (parent.parent != otherParent.parent) { - parent = parent.parent; - otherParent = otherParent.parent; - } - if (parent.parent == null) { - throw new IllegalArgumentException("The nodes do not belong to the same tree"); - } - if (parent.parent.left == parent) { - return -1; - } else { - return 1; - } - } - - /** - * Throws a RuntimeException if the RedBlackNode fields of this are not correct for a leaf node. - */ - private void assertIsValidLeaf() { - if (left != null || right != null || parent != null || isRed) { - throw new RuntimeException("A leaf node's \"left\", \"right\", \"parent\", or isRed field is incorrect"); - } - } - - /** - * Throws a RuntimeException if the subtree rooted at this node does not satisfy the red-black properties, excluding - * the requirement that the root be black, or it contains a repeated node other than a leaf node. - * - * @param blackHeight The required number of black nodes in each path from this to a leaf node, including this and - * the leaf node. - * @param visited The nodes we have reached thus far, other than leaf nodes. This method adds the non-leaf nodes in - * the subtree rooted at this node to "visited". - */ - private void assertSubtreeIsValidRedBlack(int blackHeight, Set> visited) { - @SuppressWarnings("unchecked") - N nThis = (N) this; - if (left == null || right == null) { - assertIsValidLeaf(); - if (blackHeight != 1) { - throw new RuntimeException("Not all root-to-leaf paths have the same number of black nodes"); - } - return; - } else if (!visited.add(new Reference(nThis))) { - throw new RuntimeException("The tree contains a repeated non-leaf node"); - } else { - int childBlackHeight; - if (isRed) { - if ((!left.isLeaf() && left.isRed) || (!right.isLeaf() && right.isRed)) { - throw new RuntimeException("A red node has a red child"); - } - childBlackHeight = blackHeight; - } else if (blackHeight == 0) { - throw new RuntimeException("Not all root-to-leaf paths have the same number of black nodes"); - } else { - childBlackHeight = blackHeight - 1; - } - - if (!left.isLeaf() && left.parent != this) { - throw new RuntimeException("left.parent != this"); - } - if (!right.isLeaf() && right.parent != this) { - throw new RuntimeException("right.parent != this"); - } - RedBlackNode leftNode = left; - RedBlackNode rightNode = right; - leftNode.assertSubtreeIsValidRedBlack(childBlackHeight, visited); - rightNode.assertSubtreeIsValidRedBlack(childBlackHeight, visited); - } - } - - /** - * Calls assertNodeIsValid() on every node in the subtree rooted at this node. - */ - private void assertNodesAreValid() { - assertNodeIsValid(); - if (left != null) { - RedBlackNode leftNode = left; - RedBlackNode rightNode = right; - leftNode.assertNodesAreValid(); - rightNode.assertNodesAreValid(); - } - } - - /** - * Throws a RuntimeException if the subtree rooted at this node is not a valid red-black tree, e.g. if a red node - * has a red child or it contains a non-leaf node "node" for which node.left.parent != node. (If parent != null, - * it's okay if isRed is true.) This method is useful for debugging. See also assertSubtreeIsValid(). - */ - public void assertSubtreeIsValidRedBlack() { - if (isLeaf()) { - assertIsValidLeaf(); - } else { - if (parent == null && isRed) { - throw new RuntimeException("The root is red"); - } - - // Compute the black height of the tree - Set> nodes = new HashSet>(); - int blackHeight = 0; - @SuppressWarnings("unchecked") - N node = (N) this; - while (node != null) { - if (!nodes.add(new Reference(node))) { - throw new RuntimeException("The tree contains a repeated non-leaf node"); - } - if (!node.isRed) { - blackHeight++; - } - node = node.left; - } - - assertSubtreeIsValidRedBlack(blackHeight, new HashSet>()); - } - } - - /** - * Throws a RuntimeException if we detect a problem with the subtree rooted at this node, such as a red child of a - * red node or a non-leaf descendant "node" for which node.left.parent != node. This method is useful for - * debugging. RedBlackNode subclasses may want to override assertSubtreeIsValid() to call assertOrderIsValid. - */ - public void assertSubtreeIsValid() { - assertSubtreeIsValidRedBlack(); - assertNodesAreValid(); - } - - /** - * Throws a RuntimeException if the nodes in the subtree rooted at this node are not in the specified order or they - * do not lie in the specified range. Assumes that the subtree rooted at this node is a valid binary tree, i.e. it - * has no repeated nodes other than leaf nodes. - * - * @param comparator A comparator indicating how the nodes should be ordered. - * @param start The lower limit for nodes in the subtree, if any. - * @param end The upper limit for nodes in the subtree, if any. - */ - private void assertOrderIsValid(Comparator comparator, N start, N end) { - if (!isLeaf()) { - @SuppressWarnings("unchecked") - N nThis = (N) this; - if (start != null && comparator.compare(nThis, start) < 0) { - throw new RuntimeException("The nodes are not ordered correctly"); - } - if (end != null && comparator.compare(nThis, end) > 0) { - throw new RuntimeException("The nodes are not ordered correctly"); - } - RedBlackNode leftNode = left; - RedBlackNode rightNode = right; - leftNode.assertOrderIsValid(comparator, start, nThis); - rightNode.assertOrderIsValid(comparator, nThis, end); - } - } - - /** - * Throws a RuntimeException if the nodes in the subtree rooted at this node are not in the specified order. - * Assumes that this is a valid binary tree, i.e. there are no repeated nodes other than leaf nodes. This method is - * useful for debugging. RedBlackNode subclasses may want to override assertSubtreeIsValid() to call - * assertOrderIsValid. - * - * @param comparator A comparator indicating how the nodes should be ordered. If this is null, we use the nodes' - * natural order, as in N.compareTo. - */ - public void assertOrderIsValid(Comparator comparator) { - if (comparator == null) { - comparator = naturalOrder(); - } - assertOrderIsValid(comparator, null, null); - } -} - diff --git a/src/main/java/baritone/builder/utils/com/github/btrekkie/red_black_node/Reference.java b/src/main/java/baritone/builder/utils/com/github/btrekkie/red_black_node/Reference.java deleted file mode 100644 index 5c079f743..000000000 --- a/src/main/java/baritone/builder/utils/com/github/btrekkie/red_black_node/Reference.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * This file was originally written by btrekkie under the MIT license, which is compatible with the LGPL license for this usage within Baritone - * https://github.com/btrekkie/RedBlackNode/blob/master/src/main/java/com/github/btrekkie/red_black_node/Reference.java - */ - -package baritone.builder.utils.com.github.btrekkie.red_black_node; - -/** - * Wraps a value using reference equality. In other words, two references are equal only if their values are the same - * object instance, as in ==. - * - * @param The type of value. - */ -class Reference { - /** - * The value this wraps. - */ - private final T value; - - public Reference(T value) { - this.value = value; - } - - public boolean equals(Object obj) { - if (!(obj instanceof Reference)) { - return false; - } - Reference reference = (Reference) obj; - return value == reference.value; - } - - @Override - public int hashCode() { - return System.identityHashCode(value); - } -} - diff --git a/src/test/java/com/github/btrekkie/arbitrary_order_collection/ArbitraryOrderCollection.java b/src/test/java/com/github/btrekkie/arbitrary_order_collection/ArbitraryOrderCollection.java deleted file mode 100644 index 90374ca52..000000000 --- a/src/test/java/com/github/btrekkie/arbitrary_order_collection/ArbitraryOrderCollection.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.github.btrekkie.arbitrary_order_collection; - -import java.util.Comparator; - -/** - * Provides objects ordered in an arbitrary, but consistent fashion, through the createValue() method. To determine the - * relative order of two values, use ArbitraryOrderValue.compareTo. We may only compare values on which we have not - * called "remove" that were created in the same ArbitraryOrderCollection instance. Note that despite the name, - * ArbitraryOrderCollection does not implement Collection. - */ -/* We implement an ArbitraryOrderCollection using a red-black tree. We order the nodes arbitrarily. - */ -public class ArbitraryOrderCollection { - /** - * The Comparator for ordering ArbitraryOrderNodes. - */ - private static final Comparator NODE_COMPARATOR = new Comparator() { - @Override - public int compare(ArbitraryOrderNode node1, ArbitraryOrderNode node2) { - return 0; - } - }; - - /** - * The root node of the tree. - */ - private ArbitraryOrderNode root = new ArbitraryOrderNode(); - - /** - * Adds and returns a new value for ordering. - */ - public ArbitraryOrderValue createValue() { - ArbitraryOrderNode node = new ArbitraryOrderNode(); - root = root.insert(node, true, NODE_COMPARATOR); - return new ArbitraryOrderValue(node); - } - - /** - * Removes the specified value from this collection. Assumes we obtained the value by calling createValue() on this - * instance of ArbitraryOrderCollection. After calling "remove" on a value, we may no longer compare it to other - * values. - */ - public void remove(ArbitraryOrderValue value) { - root = value.node.remove(); - } -} diff --git a/src/test/java/com/github/btrekkie/arbitrary_order_collection/ArbitraryOrderNode.java b/src/test/java/com/github/btrekkie/arbitrary_order_collection/ArbitraryOrderNode.java deleted file mode 100644 index 517ddfcee..000000000 --- a/src/test/java/com/github/btrekkie/arbitrary_order_collection/ArbitraryOrderNode.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.github.btrekkie.arbitrary_order_collection; - -import baritone.builder.utils.com.github.btrekkie.red_black_node.RedBlackNode; - -/** - * A node in an ArbitraryOrderCollection tree. See ArbitraryOrderCollection. - */ -class ArbitraryOrderNode extends RedBlackNode { - -} diff --git a/src/test/java/com/github/btrekkie/arbitrary_order_collection/ArbitraryOrderValue.java b/src/test/java/com/github/btrekkie/arbitrary_order_collection/ArbitraryOrderValue.java deleted file mode 100644 index 160c4ee75..000000000 --- a/src/test/java/com/github/btrekkie/arbitrary_order_collection/ArbitraryOrderValue.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.github.btrekkie.arbitrary_order_collection; - -/** - * A value in an ArbitraryOrderCollection. To determine the relative order of two values in the same collection, call - * compareTo. - */ -public class ArbitraryOrderValue implements Comparable { - /** - * The node that establishes this value's relative position. - */ - final ArbitraryOrderNode node; - - ArbitraryOrderValue(ArbitraryOrderNode node) { - this.node = node; - } - - @Override - public int compareTo(ArbitraryOrderValue other) { - return node.compareTo(other.node); - } -} diff --git a/src/test/java/com/github/btrekkie/arbitrary_order_collection/test/ArbitraryOrderCollectionTest.java b/src/test/java/com/github/btrekkie/arbitrary_order_collection/test/ArbitraryOrderCollectionTest.java deleted file mode 100644 index ad36a5c62..000000000 --- a/src/test/java/com/github/btrekkie/arbitrary_order_collection/test/ArbitraryOrderCollectionTest.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.github.btrekkie.arbitrary_order_collection.test; - -import com.github.btrekkie.arbitrary_order_collection.ArbitraryOrderCollection; -import com.github.btrekkie.arbitrary_order_collection.ArbitraryOrderValue; -import org.junit.Test; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -public class ArbitraryOrderCollectionTest { - /** - * Tests ArbitraryOrderCollection. - */ - @Test - public void test() { - ArbitraryOrderCollection collection = new ArbitraryOrderCollection(); - List values1 = new ArrayList(5); - ArbitraryOrderValue value = collection.createValue(); - assertEquals(0, value.compareTo(value)); - values1.add(value); - for (int i = 0; i < 4; i++) { - values1.add(collection.createValue()); - } - Collections.sort(values1); - List values2 = new ArrayList(10); - for (int i = 0; i < 10; i++) { - value = collection.createValue(); - values2.add(value); - } - for (int i = 0; i < 5; i++) { - collection.remove(values2.get(2 * i)); - } - assertEquals(0, values1.get(0).compareTo(values1.get(0))); - assertTrue(values1.get(0).compareTo(values1.get(1)) < 0); - assertTrue(values1.get(1).compareTo(values1.get(0)) > 0); - assertTrue(values1.get(4).compareTo(values1.get(2)) > 0); - assertTrue(values1.get(0).compareTo(values1.get(4)) < 0); - - collection = new ArbitraryOrderCollection(); - values1 = new ArrayList(1000); - for (int i = 0; i < 1000; i++) { - value = collection.createValue(); - values1.add(value); - } - for (int i = 0; i < 500; i++) { - collection.remove(values1.get(2 * i)); - } - values2 = new ArrayList(500); - for (int i = 0; i < 500; i++) { - values2.add(values1.get(2 * i + 1)); - } - for (int i = 0; i < 500; i++) { - values2.get(0).compareTo(values2.get(i)); - } - Collections.sort(values2); - for (int i = 0; i < 500; i++) { - collection.createValue(); - } - for (int i = 0; i < 499; i++) { - assertTrue(values2.get(i).compareTo(values2.get(i + 1)) < 0); - assertTrue(values2.get(i + 1).compareTo(values2.get(i)) > 0); - } - for (int i = 1; i < 500; i++) { - assertEquals(0, values2.get(i).compareTo(values2.get(i))); - assertTrue(values2.get(0).compareTo(values2.get(i)) < 0); - assertTrue(values2.get(i).compareTo(values2.get(0)) > 0); - } - } -} diff --git a/src/test/java/com/github/btrekkie/interval_tree/IntervalTree.java b/src/test/java/com/github/btrekkie/interval_tree/IntervalTree.java deleted file mode 100644 index aa0204517..000000000 --- a/src/test/java/com/github/btrekkie/interval_tree/IntervalTree.java +++ /dev/null @@ -1,65 +0,0 @@ -package com.github.btrekkie.interval_tree; - -/** - * An interval tree data structure, which supports adding or removing an interval and finding an arbitrary interval that - * contains a specified value. - */ -/* The interval tree is ordered in ascending order of the start an interval, with ties broken by the end of the - * interval. Each node is augmented with the maximum ending value of an interval in the subtree rooted at the node. - */ -public class IntervalTree { - /** - * The root node of the tree. - */ - private IntervalTreeNode root = IntervalTreeNode.LEAF; - - /** - * Adds the specified interval to this. - */ - public void addInterval(IntervalTreeInterval interval) { - root = root.insert(new IntervalTreeNode(interval), true, null); - } - - /** - * Removes the specified interval from this, if it is present. - * - * @param interval The interval. - * @return Whether the interval was present. - */ - public boolean removeInterval(IntervalTreeInterval interval) { - IntervalTreeNode node = root; - while (!node.isLeaf()) { - if (interval.start < node.interval.start) { - node = node.left; - } else if (interval.start > node.interval.start) { - node = node.right; - } else if (interval.end < node.interval.end) { - node = node.left; - } else if (interval.end > node.interval.end) { - node = node.right; - } else { - root = node.remove(); - return true; - } - } - return false; - } - - /** - * Returns an aribtrary IntervalTreeInterval in this that contains the specified value. Returns null if there is no - * such interval. - */ - public IntervalTreeInterval findInterval(double value) { - IntervalTreeNode node = root; - while (!node.isLeaf()) { - if (value >= node.interval.start && value <= node.interval.end) { - return node.interval; - } else if (value <= node.left.maxEnd) { - node = node.left; - } else { - node = node.right; - } - } - return null; - } -} diff --git a/src/test/java/com/github/btrekkie/interval_tree/IntervalTreeInterval.java b/src/test/java/com/github/btrekkie/interval_tree/IntervalTreeInterval.java deleted file mode 100644 index 182eb37c6..000000000 --- a/src/test/java/com/github/btrekkie/interval_tree/IntervalTreeInterval.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.github.btrekkie.interval_tree; - -/** - * An inclusive range of values [start, end]. Two intervals are equal if they have the same starting and ending values. - */ -public class IntervalTreeInterval { - /** - * The smallest value in the range. - */ - public final double start; - - /** - * The largest value in the range. - */ - public final double end; - - public IntervalTreeInterval(double start, double end) { - if (start > end) { - throw new IllegalArgumentException("The end of the range must be at most the start"); - } - this.start = start; - this.end = end; - } - - public boolean equals(Object obj) { - if (!(obj instanceof IntervalTreeInterval)) { - return false; - } - IntervalTreeInterval interval = (IntervalTreeInterval) obj; - return start == interval.start && end == interval.end; - } -} diff --git a/src/test/java/com/github/btrekkie/interval_tree/IntervalTreeNode.java b/src/test/java/com/github/btrekkie/interval_tree/IntervalTreeNode.java deleted file mode 100644 index c39417e7e..000000000 --- a/src/test/java/com/github/btrekkie/interval_tree/IntervalTreeNode.java +++ /dev/null @@ -1,76 +0,0 @@ -package com.github.btrekkie.interval_tree; - -import baritone.builder.utils.com.github.btrekkie.red_black_node.RedBlackNode; - -/** - * A node in an IntervalTree. See the comments for the implementation of IntervalTree. Its compareTo method orders - * nodes as suggested in the comments for the implementation of IntervalTree. - */ -class IntervalTreeNode extends RedBlackNode { - /** - * The dummy leaf node. - */ - public static final IntervalTreeNode LEAF = new IntervalTreeNode(); - - /** - * The interval stored in this node. - */ - public IntervalTreeInterval interval; - - /** - * The maximum ending value of an interval in the subtree rooted at this node. - */ - public double maxEnd; - - public IntervalTreeNode(IntervalTreeInterval interval) { - this.interval = interval; - maxEnd = interval.end; - } - - /** - * Constructs a new dummy leaf node. - */ - private IntervalTreeNode() { - interval = null; - maxEnd = Double.NEGATIVE_INFINITY; - } - - @Override - public boolean augment() { - double newMaxEnd = Math.max(interval.end, Math.max(left.maxEnd, right.maxEnd)); - if (newMaxEnd == maxEnd) { - return false; - } else { - maxEnd = newMaxEnd; - return true; - } - } - - @Override - public void assertNodeIsValid() { - double expectedMaxEnd; - if (isLeaf()) { - expectedMaxEnd = Double.NEGATIVE_INFINITY; - } else { - expectedMaxEnd = Math.max(interval.end, Math.max(left.maxEnd, right.maxEnd)); - } - if (maxEnd != expectedMaxEnd) { - throw new RuntimeException("The node's maxEnd does not match that of the children"); - } - } - - @Override - public int compareTo(IntervalTreeNode other) { - if (interval.start != interval.end) { - return Double.compare(interval.start, other.interval.start); - } else { - return Double.compare(interval.end, other.interval.end); - } - } - - @Override - public void assertSubtreeIsValid() { - super.assertSubtreeIsValid(); - assertOrderIsValid(null); - } -} diff --git a/src/test/java/com/github/btrekkie/interval_tree/test/IntervalTreeTest.java b/src/test/java/com/github/btrekkie/interval_tree/test/IntervalTreeTest.java deleted file mode 100644 index 5af2bd6d2..000000000 --- a/src/test/java/com/github/btrekkie/interval_tree/test/IntervalTreeTest.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.github.btrekkie.interval_tree.test; - -import com.github.btrekkie.interval_tree.IntervalTree; -import com.github.btrekkie.interval_tree.IntervalTreeInterval; -import org.junit.Test; - -import static org.junit.Assert.*; - -public class IntervalTreeTest { - /** - * Tests IntervalTree. - */ - @Test - public void test() { - IntervalTree tree = new IntervalTree(); - assertNull(tree.findInterval(0.5)); - assertNull(tree.findInterval(-1)); - tree.addInterval(new IntervalTreeInterval(5, 7)); - tree.addInterval(new IntervalTreeInterval(42, 48)); - tree.addInterval(new IntervalTreeInterval(-1, 2)); - tree.addInterval(new IntervalTreeInterval(6, 12)); - tree.addInterval(new IntervalTreeInterval(21, 23)); - assertTrue(tree.removeInterval(new IntervalTreeInterval(-1, 2))); - assertFalse(tree.removeInterval(new IntervalTreeInterval(-1, 2))); - tree.addInterval(new IntervalTreeInterval(-6, -2)); - assertEquals(new IntervalTreeInterval(6, 12), tree.findInterval(8)); - assertNull(tree.findInterval(0)); - assertEquals(new IntervalTreeInterval(21, 23), tree.findInterval(21)); - assertEquals(new IntervalTreeInterval(42, 48), tree.findInterval(48)); - IntervalTreeInterval interval = tree.findInterval(6.5); - assertTrue(new IntervalTreeInterval(5, 7).equals(interval) || new IntervalTreeInterval(6, 12).equals(interval)); - - tree = new IntervalTree(); - for (int i = 0; i < 500; i++) { - tree.addInterval(new IntervalTreeInterval(2 * i, 2 * i + 1)); - } - for (int i = 0; i < 250; i++) { - tree.removeInterval(new IntervalTreeInterval(4 * i + 2, 4 * i + 3)); - } - assertNull(tree.findInterval(123.5)); - assertEquals(new IntervalTreeInterval(124, 125), tree.findInterval(124.5)); - assertEquals(new IntervalTreeInterval(776, 777), tree.findInterval(776)); - assertEquals(new IntervalTreeInterval(0, 1), tree.findInterval(0.5)); - assertEquals(new IntervalTreeInterval(996, 997), tree.findInterval(997)); - } -} diff --git a/src/test/java/com/github/btrekkie/red_black_node/test/RedBlackNodeTest.java b/src/test/java/com/github/btrekkie/red_black_node/test/RedBlackNodeTest.java deleted file mode 100644 index b487e54fe..000000000 --- a/src/test/java/com/github/btrekkie/red_black_node/test/RedBlackNodeTest.java +++ /dev/null @@ -1,174 +0,0 @@ -package com.github.btrekkie.red_black_node.test; - -import org.junit.Test; - -import java.util.Comparator; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -/** - * Tests RedBlackNode. Most of the testing for RedBlackNode takes place in TreeListTest, IntervalTreeTest, - * SubArrayMinTest, and ArbitraryOrderCollectionTest, which test realistic use cases of RedBlackNode. TreeListTest - * tests most of the RedBlackNode methods, while IntervalTreeTest tests the "insert" method, SubArrayMinTest tests - * "lca", ArbitraryOrderCollectionTest tests compareTo, and RedBlackNodeTest tests assertSubtreeIsValid() and - * assertOrderIsValid. - */ -public class RedBlackNodeTest { - /** - * Returns whether the subtree rooted at the specified node is valid, as in TestRedBlackNode.assertSubtreeIsValid(). - */ - private boolean isSubtreeValid(TestRedBlackNode node) { - try { - node.assertSubtreeIsValid(); - return true; - } catch (RuntimeException exception) { - return false; - } - } - - /** - * Returns whether the nodes in the subtree rooted at the specified node are ordered correctly, as in - * TestRedBlackNode.assertOrderIsValid. - * - * @param comparator A comparator indicating how the nodes should be ordered. If this is null, we use the nodes' - * natural ordering, as in TestRedBlackNode.compare. - */ - private boolean isOrderValid(TestRedBlackNode node, Comparator comparator) { - try { - node.assertOrderIsValid(null); - return true; - } catch (RuntimeException exception) { - return false; - } - } - - /** - * Tests RedBlackNode.assertSubtreeIsValid() and RedBlackNode.assertOrderIsValid. - */ - @Test - public void testAssertIsValid() { - // Create a perfectly balanced tree of height 3 - TestRedBlackNode node0 = new TestRedBlackNode(0); - TestRedBlackNode node1 = new TestRedBlackNode(1); - TestRedBlackNode node2 = new TestRedBlackNode(2); - TestRedBlackNode node3 = new TestRedBlackNode(3); - TestRedBlackNode node4 = new TestRedBlackNode(4); - TestRedBlackNode node5 = new TestRedBlackNode(5); - TestRedBlackNode node6 = new TestRedBlackNode(6); - node0.parent = node1; - node0.left = TestRedBlackNode.LEAF; - node0.right = TestRedBlackNode.LEAF; - node1.parent = node3; - node1.left = node0; - node1.right = node2; - node1.isRed = true; - node2.parent = node1; - node2.left = TestRedBlackNode.LEAF; - node2.right = TestRedBlackNode.LEAF; - node3.left = node1; - node3.right = node5; - node4.parent = node5; - node4.left = TestRedBlackNode.LEAF; - node4.right = TestRedBlackNode.LEAF; - node5.parent = node3; - node5.left = node4; - node5.right = node6; - node5.isRed = true; - node6.parent = node5; - node6.left = TestRedBlackNode.LEAF; - node6.right = TestRedBlackNode.LEAF; - - node3.left = node3; - node3.right = node3; - node3.parent = node3; - assertFalse(isSubtreeValid(node3)); - node3.left = node1; - node3.right = node5; - node3.parent = null; - - node0.parent = node3; - assertFalse(isSubtreeValid(node3)); - node0.parent = node1; - - node1.right = node0; - assertFalse(isSubtreeValid(node3)); - node1.right = node2; - - node5.isRed = false; - assertFalse(isSubtreeValid(node3)); - assertTrue(isSubtreeValid(node5)); - node5.isRed = true; - - node3.isRed = true; - assertFalse(isSubtreeValid(node3)); - assertTrue(isSubtreeValid(node5)); - node3.isRed = false; - - node0.isRed = true; - node2.isRed = true; - node4.isRed = true; - node6.isRed = true; - assertFalse(isSubtreeValid(node3)); - node0.isRed = false; - node2.isRed = false; - node4.isRed = false; - node6.isRed = false; - - TestRedBlackNode.LEAF.isRed = true; - assertFalse(isSubtreeValid(node3)); - TestRedBlackNode.LEAF.isRed = false; - - TestRedBlackNode.LEAF.isValid = false; - assertFalse(isSubtreeValid(node3)); - assertFalse(isSubtreeValid(TestRedBlackNode.LEAF)); - TestRedBlackNode.LEAF.isValid = true; - - node1.isValid = false; - assertFalse(isSubtreeValid(node3)); - node1.isValid = true; - - node3.value = 2; - node2.value = 3; - assertFalse(isOrderValid(node3, null)); - assertFalse( - isOrderValid(node3, new Comparator() { - @Override - public int compare(TestRedBlackNode node1, TestRedBlackNode node2) { - return node1.value - node2.value; - } - })); - node3.value = 3; - node2.value = 2; - - node2.value = 4; - node4.value = 2; - assertFalse(isOrderValid(node3, null)); - node2.value = 2; - node4.value = 4; - - node0.value = 1; - node1.value = 0; - assertFalse(isOrderValid(node3, null)); - node0.value = 0; - node1.value = 1; - - // Do all of the assertions for which the tree is supposed to be valid at the end, to make sure we didn't make a - // mistake undoing any of the modifications - assertTrue(isSubtreeValid(node3)); - assertTrue(isSubtreeValid(node1)); - assertTrue(isSubtreeValid(node0)); - assertTrue(isSubtreeValid(TestRedBlackNode.LEAF)); - assertTrue(isOrderValid(node3, null)); - assertTrue(isOrderValid(node1, null)); - assertTrue(isOrderValid(node0, null)); - assertTrue(isOrderValid(TestRedBlackNode.LEAF, null)); - assertTrue( - isOrderValid(node3, new Comparator() { - @Override - public int compare(TestRedBlackNode node1, TestRedBlackNode node2) { - return node1.value - node2.value; - } - })); - } -} diff --git a/src/test/java/com/github/btrekkie/red_black_node/test/TestRedBlackNode.java b/src/test/java/com/github/btrekkie/red_black_node/test/TestRedBlackNode.java deleted file mode 100644 index 781f8a85b..000000000 --- a/src/test/java/com/github/btrekkie/red_black_node/test/TestRedBlackNode.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.github.btrekkie.red_black_node.test; - -import baritone.builder.utils.com.github.btrekkie.red_black_node.RedBlackNode; - -/** - * A RedBlackNode for RedBlackNodeTest. - */ -class TestRedBlackNode extends RedBlackNode { - /** - * The dummy leaf node. - */ - public static final TestRedBlackNode LEAF = new TestRedBlackNode(); - - /** - * The value stored in this node. "value" is unspecified if this is a leaf node. - */ - public int value; - - /** - * Whether this node is considered valid, as in assertNodeIsValid(). - */ - public boolean isValid = true; - - public TestRedBlackNode(int value) { - this.value = value; - } - - /** - * Constructs a new dummy leaf node. - */ - private TestRedBlackNode() { - - } - - @Override - public void assertNodeIsValid() { - if (!isValid) { - throw new RuntimeException("isValid is false"); - } - } - - @Override - public int compareTo(TestRedBlackNode other) { - return value - other.value; - } -} diff --git a/src/test/java/com/github/btrekkie/sub_array_min/SubArrayMin.java b/src/test/java/com/github/btrekkie/sub_array_min/SubArrayMin.java deleted file mode 100644 index 7c8e1c4ba..000000000 --- a/src/test/java/com/github/btrekkie/sub_array_min/SubArrayMin.java +++ /dev/null @@ -1,99 +0,0 @@ -package com.github.btrekkie.sub_array_min; - -/** - * A list of integers. SubArrayMin provides the ability to quickly determine the minimum value in a given sublist. - */ -/* We implement SubArrayMin using a red-black tree augmented by subtree size and minimum value. Using the subtree size - * augmentation, we can find the node at a given index. - */ -public class SubArrayMin { - /** - * The root node. - */ - private SubArrayMinNode root = SubArrayMinNode.LEAF; - - /** - * Appends the specified value to the end of the list. - */ - public void add(int value) { - SubArrayMinNode newNode = new SubArrayMinNode(value); - newNode.left = SubArrayMinNode.LEAF; - newNode.right = SubArrayMinNode.LEAF; - if (root.isLeaf()) { - root = newNode; - newNode.augment(); - } else { - SubArrayMinNode node = root.max(); - node.right = newNode; - newNode.parent = node; - newNode.isRed = true; - root = newNode.fixInsertion(); - } - } - - /** - * Returns the node for the element with the specified index. Assumes "index" is in the range [0, root.size). - */ - private SubArrayMinNode getNode(int index) { - if (index < 0 || index >= root.size) { - throw new IndexOutOfBoundsException("Index " + index + " is not in the range [0, " + root.size + ")"); - } - int rank = index; - SubArrayMinNode node = root; - while (rank != node.left.size) { - if (rank < node.left.size) { - node = node.left; - } else { - rank -= node.left.size + 1; - node = node.right; - } - } - return node; - } - - /** - * Returns the minimum value in the subarray starting at index startIndex and ending at index endIndex - 1, - * inclusive. Assumes startIndex < endIndex, and assumes this contains indices startIndex and endIndex - 1. - */ - public int min(int startIndex, int endIndex) { - if (startIndex >= endIndex) { - throw new IllegalArgumentException("The start index must be less than the end index"); - } - SubArrayMinNode start = getNode(startIndex); - SubArrayMinNode end = getNode(endIndex - 1); - SubArrayMinNode lca = start.lca(end); - - int min = Math.min(lca.value, Math.min(start.value, end.value)); - if (start != lca) { - if (start.right.min < min) { - min = start.right.min; - } - for (SubArrayMinNode node = start; node.parent != lca; node = node.parent) { - if (node.parent.left == node) { - if (node.parent.value < min) { - min = node.parent.value; - } - if (node.parent.right.min < min) { - min = node.parent.right.min; - } - } - } - } - if (end != lca) { - if (end.left.min < min) { - min = end.left.min; - } - for (SubArrayMinNode node = end; node.parent != lca; node = node.parent) { - if (node.parent.right == node) { - if (node.parent.value < min) { - min = node.parent.value; - } - if (node.parent.left.min < min) { - min = node.parent.left.min; - } - } - } - } - return min; - } -} diff --git a/src/test/java/com/github/btrekkie/sub_array_min/SubArrayMinNode.java b/src/test/java/com/github/btrekkie/sub_array_min/SubArrayMinNode.java deleted file mode 100644 index 6ff1b155a..000000000 --- a/src/test/java/com/github/btrekkie/sub_array_min/SubArrayMinNode.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.github.btrekkie.sub_array_min; - -import baritone.builder.utils.com.github.btrekkie.red_black_node.RedBlackNode; - -/** - * A node in a SubArrayMin object. See the comments for the implementation of that class. - */ -class SubArrayMinNode extends RedBlackNode { - /** - * The dummy leaf node. - */ - public static final SubArrayMinNode LEAF = new SubArrayMinNode(); - - /** - * The element stored in the node. The value is unspecified if this is a leaf node. - */ - public final int value; - - /** - * The number of elements in the subtree rooted at this node. - */ - public int size; - - /** - * The minimum element in the subtree rooted at this node. This is Integer.MAX_VALUE if this is a leaf node. - */ - public int min; - - public SubArrayMinNode(int value) { - this.value = value; - } - - private SubArrayMinNode() { - value = 0; - min = Integer.MAX_VALUE; - } - - @Override - public boolean augment() { - int newSize = left.size + right.size + 1; - int newMin = Math.min(value, Math.min(left.min, right.min)); - if (newSize == size && newMin == min) { - return false; - } else { - size = newSize; - min = newMin; - return true; - } - } - - @Override - public void assertNodeIsValid() { - int expectedSize; - int expectedMin; - if (isLeaf()) { - expectedSize = 0; - expectedMin = Integer.MAX_VALUE; - } else { - expectedSize = left.size + right.size + 1; - expectedMin = Math.min(value, Math.min(left.min, right.min)); - } - if (size != expectedSize || min != expectedMin) { - throw new RuntimeException("The node's size or minimum value does not match that of the children"); - } - } -} diff --git a/src/test/java/com/github/btrekkie/sub_array_min/test/SubArrayMinTest.java b/src/test/java/com/github/btrekkie/sub_array_min/test/SubArrayMinTest.java deleted file mode 100644 index 95266b387..000000000 --- a/src/test/java/com/github/btrekkie/sub_array_min/test/SubArrayMinTest.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.github.btrekkie.sub_array_min.test; - -import com.github.btrekkie.sub_array_min.SubArrayMin; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; - -public class SubArrayMinTest { - /** - * Tests SubArrayMin. - */ - @Test - public void test() { - SubArrayMin sam = new SubArrayMin(); - sam.add(12); - sam.add(42); - sam.add(-3); - sam.add(16); - sam.add(5); - sam.add(8); - sam.add(4); - assertEquals(-3, sam.min(0, 7)); - assertEquals(12, sam.min(0, 2)); - assertEquals(-3, sam.min(2, 4)); - assertEquals(12, sam.min(0, 1)); - assertEquals(5, sam.min(3, 6)); - assertEquals(4, sam.min(4, 7)); - - sam = new SubArrayMin(); - for (int i = 0; i < 1000; i++) { - sam.add(-Integer.bitCount(i)); - } - assertEquals(0, sam.min(0, 1)); - assertEquals(-4, sam.min(0, 30)); - assertEquals(-9, sam.min(0, 1000)); - assertEquals(-9, sam.min(123, 777)); - assertEquals(-8, sam.min(777, 888)); - assertEquals(-6, sam.min(777, 788)); - assertEquals(-9, sam.min(900, 1000)); - } -}