summaryrefslogtreecommitdiff
path: root/BJC-Utils2/src
diff options
context:
space:
mode:
Diffstat (limited to 'BJC-Utils2/src')
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/esodata/DoubleTape.java197
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/esodata/SingleTape.java183
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/esodata/Tape.java177
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/esodata/TapeChanger.java296
4 files changed, 784 insertions, 69 deletions
diff --git a/BJC-Utils2/src/main/java/bjc/utils/esodata/DoubleTape.java b/BJC-Utils2/src/main/java/bjc/utils/esodata/DoubleTape.java
new file mode 100644
index 0000000..410acf6
--- /dev/null
+++ b/BJC-Utils2/src/main/java/bjc/utils/esodata/DoubleTape.java
@@ -0,0 +1,197 @@
+package bjc.utils.esodata;
+
+import java.util.ArrayList;
+
+/**
+ * Double-sided tape is essentially two tapes stuck together with a shared cursor.
+ *
+ * The main way a double-sided tape differs is that it can be flipped, allowing access to
+ * another set of data.
+ *
+ * However, there is only one cursor, and the position of the cursor on one side is the inverse
+ * of the position on the other side.
+ *
+ * When one side is extended, a null will be inserted into the inactive side regardless of the
+ * auto-extension policy of the tape. The policy will still be respected for the active side.
+ *
+ * All operations that refer to the tape refer to the currently active side of the tape, except for flip.
+ *
+ * Flip refers to the entire tape for 'obvious' reasons.
+ *
+ * @param T The element type of the tape.
+ * @author bjculkin
+ */
+public class DoubleTape<T> implements Tape<T> {
+ private Tape<T> front;
+ private Tape<T> back;
+
+ /**
+ * Create a new empty double-sided tape that doesn't autoextend.
+ */
+ public DoubleTape() {
+ this(false);
+ }
+
+ /**
+ * Create a new empty double-sided tape that follows the specified auto-extension policy.
+ *
+ * @param autoExtnd Whether or not to auto-extend the tape to the right
+ * w/ nulls.
+ */
+ public DoubleTape(boolean autoExtnd) {
+ front = new SingleTape<>(autoExtnd);
+ back = new SingleTape<>(autoExtnd);
+ }
+
+ /**
+ * Get the item the tape is currently on.
+ *
+ * @return The item the tape is on.
+ */
+ public T item() {
+ return front.item();
+ }
+
+ /**
+ * Set the item the tape is currently on.
+ *
+ * @param itm The new value for the tape item.
+ */
+ public void item(T itm) {
+ front.item(itm);
+ }
+
+ /**
+ * Get the current number of elements in the tape.
+ *
+ * @return The current number of elements in the tape.
+ */
+ public int size() {
+ return front.size();
+ }
+
+ /**
+ * Insert an element before the current item.
+ *
+ * @param itm The item to add.
+ */
+ public void insertBefore(T itm) {
+ front.insertBefore(itm);
+ back.insertAfter(null);
+ }
+
+ /**
+ * Insert an element after the current item.
+ */
+ public void insertAfter(T itm) {
+ front.insertAfter(itm);
+ back.insertBefore(itm);
+ }
+
+ /**
+ * Remove the current element.
+ *
+ * Also moves the cursor back one step if possible to maintain
+ * relative position, and removes the corresponding item from the non-active side
+ *
+ * @return The removed item from the active side.
+ */
+ public T remove() {
+ back.remove();
+
+ return front.remove();
+ }
+
+ /**
+ * Move the cursor to the left-most position.
+ */
+ public void first() {
+ front.first();
+ back.last();
+ }
+
+ /**
+ * Move the cursor the right-most position.
+ */
+ public void last() {
+ front.last();
+ back.first();
+ }
+
+ /**
+ * Move the cursor one space left.
+ *
+ * The cursor can't go past zero.
+ *
+ * @return True if the cursor was moved left.
+ */
+ public boolean left() {
+ return left(1);
+ }
+
+ /**
+ * Move the cursor the specified amount left.
+ *
+ * The cursor can't go past zero.
+ * Attempts to move the cursor by amounts that would exceed zero
+ * don't move the cursor at all.
+ *
+ * @param amt The amount to attempt to move the cursor left.
+ *
+ * @return True if the cursor was moved left.
+ */
+ public boolean left(int amt) {
+ boolean succ = front.left(amt);
+
+ if(succ) back.right(amt);
+
+ return succ;
+ }
+
+
+ /**
+ * Move the cursor one space right.
+ *
+ * Moving the cursor right will auto-extend the tape if that is enabled.
+ *
+ * @return Whether the cursor was moved right.
+ */
+ public boolean right() {
+ return right(1);
+ }
+
+ /**
+ * Move the cursor the specified amount right.
+ *
+ * Moving the cursor right will auto-extend the tape if that is enabled.
+ *
+ * @param amt The amount to move the cursor right by.
+ *
+ * @return Whether the cursor was moved right.
+ */
+ public boolean right(int amt) {
+ boolean succ = front.right(amt);
+
+ if(succ) back.left(amt);
+
+ return succ;
+ }
+
+ /**
+ * Flips the tape.
+ *
+ * The active side becomes inactive, and the inactive side becomes active.
+ */
+ public void flip() {
+ Tape<T> tmp = front;
+
+ front = back;
+
+ back = tmp;
+ }
+
+ @Override
+ public boolean isDoubleSided() {
+ return true;
+ }
+}
diff --git a/BJC-Utils2/src/main/java/bjc/utils/esodata/SingleTape.java b/BJC-Utils2/src/main/java/bjc/utils/esodata/SingleTape.java
new file mode 100644
index 0000000..0e0deb2
--- /dev/null
+++ b/BJC-Utils2/src/main/java/bjc/utils/esodata/SingleTape.java
@@ -0,0 +1,183 @@
+package bjc.utils.esodata;
+
+import java.util.ArrayList;
+
+/**
+ * A tape is a one-dimensional array that can only be accessed in one position at a time.
+ *
+ * A tape is essentially a 1D array with a cursor attached to it, and you can only
+ * affect elements at that cursor. The size of the array is theoretically unbounded
+ * to the right, but in practice bounded by available memory.
+ *
+ * You can choose whether or not you want the tape to automatically extend itself to the
+ * right with null elements by specifiying its auto-extension policy.
+ *
+ * @param T The element type of the tape.
+ * @author bjculkin
+ */
+public class SingleTape<T> implements Tape<T> {
+ protected ArrayList<T> backing;
+ protected int pos;
+
+ protected boolean autoExtend;
+
+ /**
+ * Create a new empty tape that doesn't autoextend.
+ */
+ public SingleTape() {
+ this(false);
+ }
+
+ /**
+ * Create a new empty tape that follows the specified auto-extension policy.
+ *
+ * @param autoExtnd Whether or not to auto-extend the tape to the right
+ * w/ nulls.
+ */
+ public SingleTape(boolean autoExtnd) {
+ autoExtend = autoExtnd;
+
+ backing = new ArrayList<>();
+ }
+
+ /**
+ * Get the item the tape is currently on.
+ *
+ * @return The item the tape is on.
+ */
+ public T item() {
+ return backing.get(pos);
+ }
+
+ /**
+ * Set the item the tape is currently on.
+ *
+ * @param itm The new value for the tape item.
+ */
+ public void item(T itm) {
+ backing.set(pos, itm);
+ }
+
+ /**
+ * Get the current number of elements in the tape.
+ *
+ * @return The current number of elements in the tape.
+ */
+ public int size() {
+ return backing.size();
+ }
+
+ /**
+ * Insert an element before the current item.
+ *
+ * @param itm The item to add.
+ */
+ public void insertBefore(T itm) {
+ backing.add(pos, itm);
+ }
+
+ /**
+ * Insert an element after the current item.
+ */
+ public void insertAfter(T itm) {
+ if(pos == (backing.size() - 1)) backing.add(itm);
+ else backing.add(pos+1, itm);
+ }
+
+ /**
+ * Remove the current element.
+ *
+ * Also moves the cursor back one step if possible to maintain
+ * relative position.
+ *
+ * @return The removed item.
+ */
+ public T remove() {
+ T res = backing.remove(pos);
+ if(pos != 0) pos -= 1;
+ return res;
+ }
+
+ /**
+ * Move the cursor to the left-most position.
+ */
+ public void first() {
+ pos = 0;
+ }
+
+ /**
+ * Move the cursor the right-most position.
+ */
+ public void last() {
+ pos = backing.size() - 1;
+ }
+
+ /**
+ * Move the cursor one space left.
+ *
+ * The cursor can't go past zero.
+ *
+ * @return True if the cursor was moved left.
+ */
+ public boolean left() {
+ return left(1);
+ }
+
+ /**
+ * Move the cursor the specified amount left.
+ *
+ * The cursor can't go past zero.
+ * Attempts to move the cursor by amounts that would exceed zero
+ * don't move the cursor at all.
+ *
+ * @param amt The amount to attempt to move the cursor left.
+ *
+ * @return True if the cursor was moved left.
+ */
+ public boolean left(int amt) {
+ if((pos - amt) < 0) return false;
+
+ pos -= amt;
+ return true;
+ }
+
+ /**
+ * Move the cursor one space right.
+ *
+ * Moving the cursor right will auto-extend the tape if that is enabled.
+ *
+ * @return Whether the cursor was moved right.
+ */
+ public boolean right() {
+ return right(1);
+ }
+
+ /**
+ * Move the cursor the specified amount right.
+ *
+ * Moving the cursor right will auto-extend the tape if that is enabled.
+ *
+ * @param amt The amount to move the cursor right by.
+ *
+ * @return Whether the cursor was moved right.
+ */
+ public boolean right(int amt) {
+ if((pos + amt) >= (backing.size() - 1)) {
+ if(autoExtend) {
+ while((pos + amt) >= (backing.size() - 1)) {
+ backing.add(null);
+ }
+ } else {
+ return false;
+ }
+ }
+
+ pos += amt;
+ return true;
+ }
+
+ @Override
+ public boolean isDoubleSided() {
+ return false;
+ }
+}
diff --git a/BJC-Utils2/src/main/java/bjc/utils/esodata/Tape.java b/BJC-Utils2/src/main/java/bjc/utils/esodata/Tape.java
index 9d50b63..d08feb1 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/esodata/Tape.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/esodata/Tape.java
@@ -2,73 +2,112 @@ package bjc.utils.esodata;
import java.util.ArrayList;
-public class Tape<T> {
- private ArrayList<T> backing;
- private int pos;
-
- public Tape() {
- backing = new ArrayList<>();
- }
-
- public T item() {
- return backing.get(pos);
- }
-
- public int size() {
- return backing.size();
- }
-
- public void item(T itm) {
- backing.set(pos, itm);
- }
-
- public void append(T itm) {
- backing.add(itm);
- }
-
- // Add an item before the current
- public void insert(T itm) {
- backing.add(pos, itm);
- }
-
- public T remove() {
- if(pos != 0) pos -= 1;
- return backing.remove(pos);
- }
-
- public void first() {
- pos = 0;
- }
-
- public void last() {
- pos = backing.size() - 1;
- }
-
- public boolean left() {
- if(pos == 0) return false;
-
- pos -= 1;
- return true;
- }
-
- public boolean left(int amt) {
- if((pos - amt) < 0) return false;
-
- pos -= amt;
- return true;
- }
-
- public boolean right() {
- if(pos == (backing.size() - 1)) return false;
-
- pos += 1;
- return true;
- }
-
- public boolean right(int amt) {
- if((pos + amt) >= (backing.size() - 1)) return false;
-
- pos += amt;
- return true;
- }
+/**
+ * Interface for something that acts like a tape.
+ *
+ * A tape is essentially a 1D array with a cursor attached to it, and you can only
+ * affect elements at that cursor. The size of the array is theoretically unbounded
+ * to the right, but in practice bounded by available memory.
+ *
+ * @param T The element type of the tape.
+ * @author bjculkin
+ */
+public interface Tape<T> {
+ /**
+ * Get the item the tape is currently on.
+ *
+ * @return The item the tape is on.
+ */
+ T item();
+
+ /**
+ * Set the item the tape is currently on.
+ *
+ * @param itm The new value for the tape item.
+ */
+ void item(T itm);
+
+ /**
+ * Get the current number of elements in the tape.
+ *
+ * @return The current number of elements in the tape.
+ */
+ int size();
+
+ /**
+ * Insert an element before the current item.
+ *
+ * @param itm The item to add.
+ */
+ void insertBefore(T itm);
+
+ /**
+ * Insert an element after the current item.
+ */
+ void insertAfter(T itm);
+
+ /**
+ * Remove the current element.
+ *
+ * Also moves the cursor back one step if possible to maintain
+ * relative position.
+ *
+ * @return The removed item.
+ */
+ T remove();
+
+ /**
+ * Move the cursor to the left-most position.
+ */
+ void first();
+
+ /**
+ * Move the cursor the right-most position.
+ */
+ void last();
+
+ /**
+ * Move the cursor one space left.
+ *
+ * The cursor can't go past zero.
+ *
+ * @return True if the cursor was moved left.
+ */
+ boolean left();
+
+ /**
+ * Move the cursor the specified amount left.
+ *
+ * The cursor can't go past zero.
+ * Attempts to move the cursor by amounts that would exceed zero
+ * don't move the cursor at all.
+ *
+ * @param amt The amount to attempt to move the cursor left.
+ *
+ * @return True if the cursor was moved left.
+ */
+ boolean left(int amt);
+
+ /**
+ * Move the cursor one space right.
+ *
+ * @return Whether the cursor was moved right.
+ */
+ boolean right();
+
+ /**
+ * Move the cursor the specified amount right.
+ *
+ * @param amt The amount to move the cursor right by.
+ *
+ * @return Whether the cursor was moved right.
+ */
+ boolean right(int amt);
+
+ /**
+ * Is this tape double sided?
+ *
+ * @return Whether or not this tape is double-sided.
+ */
+ boolean isDoubleSided();
}
diff --git a/BJC-Utils2/src/main/java/bjc/utils/esodata/TapeChanger.java b/BJC-Utils2/src/main/java/bjc/utils/esodata/TapeChanger.java
new file mode 100644
index 0000000..1a07cbb
--- /dev/null
+++ b/BJC-Utils2/src/main/java/bjc/utils/esodata/TapeChanger.java
@@ -0,0 +1,296 @@
+package bjc.utils.esodata;
+
+/**
+ * A tape changer is essentially a tape of tapes.
+ *
+ * It has a current tape that you can do operations to, but also operations to add/remove other tapes.
+ *
+ * If there is no tape currently loaded into the changer, all the methods will either return null/false.
+ *
+ * @param T The element type of the tapes.
+ */
+public class TapeChanger<T> implements Tape<T> {
+ private Tape<Tape<T>> tapes;
+ private Tape<T> currentTape;
+
+ /**
+ * Create a new empty tape changer.
+ */
+ public TapeChanger() {
+ tapes = new SingleTape<>();
+ }
+
+ /**
+ * Create a new tape changer with the specified tapes.
+ *
+ * The first tape in the list will be mounted.
+ *
+ * @param taps The tapes to put in this tape changer.
+ */
+ public TapeChanger(Tape<T> current, Tape<T>... others) {
+ this();
+
+ tapes.insertBefore(current);
+
+ for(Tape<T> tp : others) {
+ tapes.insertAfter(others);
+ tapes.right();
+ }
+
+ tapes.first();
+ currentTape = tapes.item();
+ }
+
+ /**
+ * Get the item the tape is currently on.
+ *
+ * @return The item the tape is on.
+ */
+ public T item() {
+ if(currentTape == null) return false;
+
+ return currentTape.item();
+ }
+
+ /**
+ * Set the item the tape is currently on.
+ *
+ * @param itm The new value for the tape item.
+ */
+ public void item(T itm) {
+ if(currentTape == null) return;
+
+ currentTape.item(itm);
+ }
+
+ /**
+ * Get the current number of elements in the tape.
+ *
+ * @return The current number of elements in the tape.
+ */
+ public int size() {
+ if(currentTape == null) return 0;
+
+ return currentTape.size();
+ }
+
+ /**
+ * Insert an element before the current item.
+ *
+ * @param itm The item to add.
+ */
+ public void insertBefore(T itm) {
+ if(currentTape == null) return;
+
+ currentTape.insertBefore(itm);
+ }
+
+ /**
+ * Insert an element after the current item.
+ */
+ public void insertAfter(T itm) {
+ if(currentTape == null) return;
+
+ currentTape.insertAfter(itm);
+ }
+
+ /**
+ * Remove the current element.
+ *
+ * Also moves the cursor back one step if possible to maintain
+ * relative position, and removes the corresponding item from the non-active side
+ *
+ * @return The removed item from the active side.
+ */
+ public T remove() {
+ if(currentTape == null) return null;
+
+ return currentTape.remove();
+ }
+
+ /**
+ * Move the cursor to the left-most position.
+ */
+ public void first() {
+ if(currentTape == null) return;
+
+ currentTape.first();
+ }
+
+ /**
+ * Move the cursor the right-most position.
+ */
+ public void last() {
+ if(currentTape == null) return;
+
+ currentTape.last();
+ }
+
+ /**
+ * Move the cursor one space left.
+ *
+ * The cursor can't go past zero.
+ *
+ * @return True if the cursor was moved left.
+ */
+ public boolean left() {
+ return left(1);
+ }
+
+ /**
+ * Move the cursor the specified amount left.
+ *
+ * The cursor can't go past zero.
+ * Attempts to move the cursor by amounts that would exceed zero
+ * don't move the cursor at all.
+ *
+ * @param amt The amount to attempt to move the cursor left.
+ *
+ * @return True if the cursor was moved left.
+ */
+ public boolean left(int amt) {
+ if(currentTape == null) return false;
+
+ return currentTape.left(amt);
+ }
+
+
+ /**
+ * Move the cursor one space right.
+ *
+ * Moving the cursor right will auto-extend the tape if that is enabled.
+ *
+ * @return Whether the cursor was moved right.
+ */
+ public boolean right() {
+ return right(1);
+ }
+
+ /**
+ * Move the cursor the specified amount right.
+ *
+ * Moving the cursor right will auto-extend the tape if that is enabled.
+ *
+ * @param amt The amount to move the cursor right by.
+ *
+ * @return Whether the cursor was moved right.
+ */
+ public boolean right(int amt) {
+ if(currentTape == null) return;
+
+ return currentTape.right(amt);
+ }
+
+ /**
+ * Flips the tape.
+ *
+ * The active side becomes inactive, and the inactive side becomes active.
+ *
+ * If the current tape is not double-sided, does nothing.
+ */
+ public void flip() {
+ if(currentTape == null) return;
+
+ if(currentTape.isDoubleSided()) {
+ ((DoubleTape<T>)currentTape).flip();
+ }
+ }
+
+ @Override
+ public boolean isDoubleSided() {
+ if(currentTape == null) return;
+
+ return currentTape.isDoubleSided();
+ }
+
+ /**
+ * Check if a tape is currently loaded.
+ *
+ * @return Whether or not a tape is loaded.
+ */
+ public boolean isLoaded() {
+ return currentTape != null;
+ }
+
+ /**
+ * Move to the next tape in the changer.
+ *
+ * Attempting to load a tape that isn't there won't eject the current tape.
+ *
+ * @return Whether or not the next tape was loaded.
+ */
+ public boolean nextTape() {
+ boolean succ = tapes.right();
+
+ if(succ) currentTape = tapes.item();
+
+ return succ;
+ }
+
+ /**
+ * Move to the previous tape in the changer.
+ *
+ * Attempting to load a tape that isn't there won't eject the current tape.
+ *
+ * @return Whether or not the previous tape was loaded.
+ */
+ public boolean prevTape() {
+ boolean succ = tapes.left();
+
+ if(succ) currentTape = tapes.item();
+
+ return succ;
+ }
+
+ /**
+ * Inserts a tape into the tape changer.
+ *
+ * Any currently loaded tape is ejected, and becomes the previous tape.
+ *
+ * The specified tape is loaded.
+ *
+ * @param The tape to insert and load.
+ */
+ public void insertTape(Tape<T> tp) {
+ tapes.insertAfter(tp);
+ tapes.right();
+
+ currentTape = tapes.item();
+ }
+
+ /**
+ * Removes the current tape.
+ *
+ * Does nothing if there is not a tape loaded.
+ *
+ * Loads the previous tape, if there is one.
+ *
+ * @return The removed tape.
+ */
+ public Tape<T> removeTape() {
+ if(currentTape == null) return null;
+
+ Tape<T> tp = tapes.remove();
+ currentTape = tapes.item();
+
+ return tp;
+ }
+
+ /**
+ * Ejects the current tape.
+ *
+ * Does nothing if no tape is loaded.
+ */
+ public void eject() {
+ currentTape = null;
+ }
+
+ /**
+ * Get how many tapes are currently in the changer.
+ *
+ * @return How many tapes are currently in the changer.
+ */
+ public int tapeCount() {
+ return tapes.size();
+ }
+}