diff options
| author | bculkin2442 <bjculkin@mix.wvu.edu> | 2017-02-16 14:25:07 -0500 |
|---|---|---|
| committer | bculkin2442 <bjculkin@mix.wvu.edu> | 2017-02-16 14:25:07 -0500 |
| commit | f43f4f79e2b90a637b1eaef34cd8d10b69333db6 (patch) | |
| tree | e2ae543d92f0be24227a9d996544b7e53f90f49c /BJC-Utils2/src/main/java/bjc/utils | |
| parent | 56c8e9e2147fe375313172905e6a5261a8cfb601 (diff) | |
Double-sided tapes and tape changers
Diffstat (limited to 'BJC-Utils2/src/main/java/bjc/utils')
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(); + } +} |
