diff --git a/completedwork/core_programming/02_classbased_design/Workspace/Lab10_HashStackIterator/.classpath b/completedwork/core_programming/02_classbased_design/Workspace/Lab10_HashStackIterator/.classpath
new file mode 100644
index 0000000..8e3d409
--- /dev/null
+++ b/completedwork/core_programming/02_classbased_design/Workspace/Lab10_HashStackIterator/.classpath
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/completedwork/core_programming/02_classbased_design/Workspace/Lab10_HashStackIterator/.project b/completedwork/core_programming/02_classbased_design/Workspace/Lab10_HashStackIterator/.project
new file mode 100644
index 0000000..b75612c
--- /dev/null
+++ b/completedwork/core_programming/02_classbased_design/Workspace/Lab10_HashStackIterator/.project
@@ -0,0 +1,17 @@
+
+
+ Lab10_HashStackIterator
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/completedwork/core_programming/02_classbased_design/Workspace/Lab10_HashStackIterator/.settings/org.eclipse.core.resources.prefs b/completedwork/core_programming/02_classbased_design/Workspace/Lab10_HashStackIterator/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..99f26c0
--- /dev/null
+++ b/completedwork/core_programming/02_classbased_design/Workspace/Lab10_HashStackIterator/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/=UTF-8
diff --git a/completedwork/core_programming/02_classbased_design/Workspace/Lab10_HashStackIterator/.settings/org.eclipse.jdt.core.prefs b/completedwork/core_programming/02_classbased_design/Workspace/Lab10_HashStackIterator/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..e71285a
--- /dev/null
+++ b/completedwork/core_programming/02_classbased_design/Workspace/Lab10_HashStackIterator/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,11 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=11
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=11
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
+org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
+org.eclipse.jdt.core.compiler.release=enabled
+org.eclipse.jdt.core.compiler.source=11
diff --git a/completedwork/core_programming/02_classbased_design/Workspace/Lab10_HashStackIterator/src/Deque.java b/completedwork/core_programming/02_classbased_design/Workspace/Lab10_HashStackIterator/src/Deque.java
new file mode 100644
index 0000000..17a4fe9
--- /dev/null
+++ b/completedwork/core_programming/02_classbased_design/Workspace/Lab10_HashStackIterator/src/Deque.java
@@ -0,0 +1,170 @@
+interface IPred {
+ boolean apply(T t);
+}
+
+class MatchToData implements IPred {
+ T match;
+ MatchToData(T match) {
+ this.match = match;
+ }
+ public boolean apply(T t) {
+ return t.equals(match);
+ }
+}
+
+abstract class ANode {
+ ANode next;
+ ANode prev;
+ ANode(ANode next, ANode prev) {
+ this.next = next;
+ this.prev = prev;
+ }
+ // inserts this node between before and after nodes
+ void insertBetween(ANode next, ANode prev) {
+ if (prev == null || next == null) {
+ throw new IllegalArgumentException("Cannot assign next or prev to null");
+ }
+ prev.next = this;
+ this.prev = prev;
+ this.next = next;
+ next.prev = this;
+ }
+ // inserts this node after provided node
+ void insertAfter(ANode prev) {
+ this.insertBetween(prev.next, prev);
+ }
+ // inserts this node before provided node
+ void insertBefore(ANode next) {
+ this.insertBetween(next, next.prev);
+ }
+ int size() {
+ if (this.next == null) {
+ return 0;
+ } else {
+ return this.next.sizeHelper(0);
+ }
+ }
+ abstract void remove();
+ abstract int sizeHelper(int cnt);
+ abstract ANode find(IPred p);
+ abstract T getData();
+}
+
+class Sentinel extends ANode {
+ Sentinel(ANode next, ANode prev) {
+ super(next, prev);
+ }
+ Sentinel() {
+ this(null, null);
+ this.insertBetween(this, this);
+ }
+ int sizeHelper(int cnt) {
+ return cnt;
+ }
+ ANode removeNext() {
+ if (this.next == this) {
+ throw new RuntimeException("Cannot remove item from empty list");
+ }
+ ANode r = this.next;
+ this.next.remove();
+ return r;
+ }
+ ANode removePrev() {
+ if (this.next == this) {
+ throw new RuntimeException("Cannot remove item from empty list");
+ }
+ ANode r = this.prev;
+ this.prev.remove();
+ return r;
+ }
+ void remove() {
+ throw new RuntimeException("Cannot remove sentinel node");
+ }
+ ANode find(IPred p) {
+ return this;
+ }
+ T getData() {
+ throw new RuntimeException("Sentinels have no data");
+ }
+}
+
+class Node extends ANode {
+ T data;
+ Node(T data, ANode next, ANode prev) {
+ super(next, prev);
+ this.data = data;
+ this.insertBetween(prev, next);
+ }
+ Node(T data) {
+ super(null, null);
+ this.data = data;
+ }
+ int sizeHelper(int cnt) {
+ return this.next.sizeHelper(cnt + 1);
+ }
+ void remove() {
+ this.prev.next = this.next;
+ this.next.prev = this.prev;
+ }
+ ANode find(IPred pred) {
+ if (pred.apply(this.data)) {
+ return this;
+ } else {
+ return this.next.find(pred);
+ }
+ }
+ T getData() {
+ return this.data;
+ }
+}
+
+class Deque {
+ Sentinel header;
+ Deque(Sentinel header) {
+ this.header = header;
+ }
+ Deque() {
+ this(new Sentinel());
+ }
+ // returns the number of nodes in a list Deque, not including the header node
+ int size() {
+ return this.header.size(); //
+ }
+ // inserts node n at the front of the list.
+ void addAtHead(Node n) {
+ n.insertAfter(this.header);
+ }
+ // inserts node n at the end of the list.
+ void addAtTail(Node n) {
+ n.insertBefore(this.header);
+ }
+ // returns and removes the first node from this Deque.
+ // Throw a RuntimeException if an attempt is made to remove
+ // from an empty list.
+ ANode removeFromHead() {
+ return this.header.removeNext();
+ }
+ // returns and removes the last node from this Deque.
+ // Throw a RuntimeException if an attempt is made to remove
+ // from an empty list.
+ ANode removeFromTail() {
+ return this.header.removePrev();
+ }
+ // returns the first node in this Deque where the predicate returns true
+ // if nothing is found return header
+ ANode find(IPred p) {
+ // start at first node so when we hit sentinel we return sentinel
+ return this.header.next.find(p);
+ }
+ // removes the given node from this Deque
+ // If the given node is the Sentinel header, the method does nothing
+ void removeNode(Node n) {
+ ANode found = this.find(new MatchToData(n.data));
+ // we dont want to remove the sentinel node
+ if (found instanceof Sentinel) {
+ return;
+ }
+ found.remove();
+ }
+
+}
diff --git a/completedwork/core_programming/02_classbased_design/Workspace/Lab10_HashStackIterator/src/ListOfLists.java b/completedwork/core_programming/02_classbased_design/Workspace/Lab10_HashStackIterator/src/ListOfLists.java
new file mode 100644
index 0000000..676490f
--- /dev/null
+++ b/completedwork/core_programming/02_classbased_design/Workspace/Lab10_HashStackIterator/src/ListOfLists.java
@@ -0,0 +1,102 @@
+import tester.Tester;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+public class ListOfLists implements Iterable {
+ ArrayList> contents;
+ ListOfLists(ArrayList> contents) {
+ this.contents = contents;
+ }
+ ListOfLists() {
+ this(new ArrayList>());
+ }
+ // adds a new empty ArrayList to the end of the list-of-lists.
+ void addNewList() {
+ this.contents.add(new ArrayList());
+ }
+ // adds the provided object to the end of the ArrayList at the
+ // provided index in teh list-of-lists. If the index is invalid,
+ // this method should throw an IndexOutOfBoundsException with a
+ // suitable message.
+ void add(int index, T object) {
+ this.contents.get(index).add(object);
+ }
+ ArrayList get(int index) {
+ if (index < 0 && index > this.contents.size()) {
+ throw new IndexOutOfBoundsException("Bad Index Value");
+ }
+ return this.contents.get(index);
+ }
+ public int size() {
+ return this.contents.size();
+ }
+ @Override
+ public Iterator iterator() {
+ return new ListIterator(this);
+ }
+}
+
+class ListIterator implements Iterator {
+ ListOfLists listofList;
+ Iterator currentSubListIter;
+ int nextIndex;
+ ListIterator(ListOfLists listofList) {
+ this.listofList = listofList;
+ this.nextIndex = 0;
+ this.currentSubListIter = listofList.get(nextIndex).iterator();
+ this.nextIndex++;
+ }
+ public boolean hasNext() {
+ return nextIndex < listofList.size() && currentSubListIter.hasNext();
+ }
+ public T next() {
+ if (!currentSubListIter.hasNext()) {
+ this.currentSubListIter = listofList.get(nextIndex).iterator();
+ this.nextIndex++;
+ }
+ return currentSubListIter.next();
+ }
+ public void remove() {
+ throw new UnsupportedOperationException("Remove Action Unsupported.");
+ }
+}
+
+class LofLExamples {
+ void testListOfLists(Tester t) {
+ ListOfLists lol = new ListOfLists();
+ t.checkExpect(lol.contents.size(), 0);
+ //add 3 lists
+ lol.addNewList();
+ lol.addNewList();
+ lol.addNewList();
+ t.checkExpect(lol.contents.size(), 3);
+
+ //add elements 1,2,3 in first list
+ t.checkExpect(lol.contents.get(0).size(), 0);
+ lol.add(0, 1);
+ lol.add(0, 2);
+ lol.add(0, 3);
+ t.checkExpect(lol.contents.get(0).size(), 3);
+
+ //add elements 4,5,6 in second list
+ t.checkExpect(lol.contents.get(1).size(), 0);
+ lol.add(1, 4);
+ lol.add(1, 5);
+ lol.add(1, 6);
+ t.checkExpect(lol.contents.get(1).size(), 3);
+
+ //add elements 7,8,9 in third list
+ t.checkExpect(lol.contents.get(2).size(), 0);
+ lol.add(2, 7);
+ lol.add(2, 8);
+ lol.add(2, 9);
+ t.checkExpect(lol.contents.get(0).size(), 3);
+
+ //iterator should return elements in order 1,2,3,4,5,6,7,8,9
+ int number = 1;
+ for (Integer num : lol) {
+ t.checkExpect(num, number);
+ number = number + 1;
+ }
+ }
+}
diff --git a/completedwork/core_programming/02_classbased_design/Workspace/Lab10_HashStackIterator/src/Runner.java b/completedwork/core_programming/02_classbased_design/Workspace/Lab10_HashStackIterator/src/Runner.java
new file mode 100644
index 0000000..a5b740b
--- /dev/null
+++ b/completedwork/core_programming/02_classbased_design/Workspace/Lab10_HashStackIterator/src/Runner.java
@@ -0,0 +1,51 @@
+import java.util.Objects;
+import tester.Tester;
+
+class Runner {
+ int age;
+ String name;
+
+ Runner(int age, String name) {
+ this.age = age;
+ this.name = name;
+ }
+
+ public boolean equals(Object obj) {
+ if (!(obj instanceof Runner)) {
+ return false;
+ }
+ Runner rObj = (Runner) obj;
+ return this.name.equals(rObj.name) && this.age == rObj.age;
+ }
+
+ public int hashCode() {
+ return Objects.hash(this.name, this.age);
+ }
+}
+
+class RunnerExamples {
+ Runner amy;
+ Runner bob;
+ Runner cale;
+ Runner dave;
+ Runner stillBob;
+ Runner notBob;
+ void init() {
+ amy = new Runner(50, "amy");
+ bob = new Runner(40, "bob");
+ cale = new Runner(30, "cale");
+ dave = new Runner(20, "dave");
+
+ stillBob = new Runner(40, "bob");
+ notBob = new Runner(20, "bob");
+ }
+ void testHashEquality(Tester t) {
+ init();
+ t.checkExpect(this.bob.equals(this.bob), true);
+ t.checkExpect(this.bob.equals(this.stillBob), true);
+ t.checkExpect(this.bob.equals(this.notBob), false);
+ t.checkExpect(this.bob.hashCode(), this.stillBob.hashCode());
+ t.checkExpect(this.amy.hashCode(), new Runner(50, "amy").hashCode());
+ t.checkExpect(this.bob.hashCode() == this.notBob.hashCode(), false);
+ }
+}
diff --git a/completedwork/core_programming/02_classbased_design/Workspace/Lab10_HashStackIterator/src/Stack.java b/completedwork/core_programming/02_classbased_design/Workspace/Lab10_HashStackIterator/src/Stack.java
new file mode 100644
index 0000000..c1898e8
--- /dev/null
+++ b/completedwork/core_programming/02_classbased_design/Workspace/Lab10_HashStackIterator/src/Stack.java
@@ -0,0 +1,112 @@
+import tester.Tester;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+class Stack {
+ Deque contents;
+
+ Stack(Deque contents) {
+ this.contents = contents;
+ }
+ Stack() {
+ this.contents = new Deque();
+ }
+
+ //adds an item to the stack
+ void push(T item) {
+ this.contents.addAtHead(new Node(item));
+ }
+ // returns true if contents are empty
+ boolean isEmpty() {
+ if (contents.size() == 0) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+ //removes and returns the top of the stack
+ T pop() {
+ return this.contents.removeFromHead().getData();
+ }
+}
+
+class Utils {
+ // Using loops and one or more stacks, define the method that reverses an ArrayList:
+ ArrayList reverse(ArrayList source) {
+ ArrayList response = new ArrayList();
+ Stack intermediate = new Stack();
+ int size = 0;
+ for (T item : source) {
+ intermediate.push(item);
+ size++;
+ }
+ for (int i = 0; i < size; i++) {
+ response.add(i, intermediate.pop());
+ }
+ return response;
+ }
+}
+
+class StackExamples {
+ Stack s0;
+ Stack s1;
+ Deque dqAns;
+
+ Runner amy;
+ Runner bob;
+ Runner cale;
+ Runner dave;
+ Runner stillBob;
+ Runner notBob;
+ void init() {
+ amy = new Runner(50, "amy");
+ bob = new Runner(40, "bob");
+ cale = new Runner(30, "cale");
+ dave = new Runner(20, "dave");
+ stillBob = new Runner(40, "bob");
+ notBob = new Runner(20, "bob");
+
+ s0 = new Stack();
+ s1 = new Stack();
+ dqAns = new Deque();
+ }
+ void testPush(Tester t) {
+ init();
+ t.checkExpect(s1.contents.header.next, s1.contents.header);
+ s1.push(dave);
+ t.checkExpect(s1.contents.header.next,
+ new Node(dave, dqAns.header, dqAns.header));
+ s1.push(cale);
+ t.checkExpect(s1.contents.header.next,
+ new Node(cale, dqAns.header, dqAns.header.prev));
+ }
+ void testIsEmpty(Tester t) {
+ init();
+ t.checkExpect(s0.isEmpty(), true);
+ t.checkExpect(s1.isEmpty(), true);
+ s1.push(dave);
+ t.checkExpect(s1.isEmpty(), false);
+ }
+ void testPop(Tester t) {
+ init();
+ t.checkException(
+ new RuntimeException("Cannot remove item from empty list"),
+ s1,
+ "pop");
+ s1.push(dave);
+ t.checkExpect(s1.pop(), dave);
+ s1.push(dave);
+ s1.push(cale);
+ s1.push(bob);
+ s1.push(amy);
+ t.checkExpect(s1.pop(), amy);
+ t.checkExpect(s1.pop(), bob);
+ t.checkExpect(s1.pop(), cale);
+ t.checkExpect(s1.pop(), dave);
+ }
+ void testReverseArrayList(Tester t) {
+ ArrayList fwd = new ArrayList(Arrays.asList(amy, bob, cale, dave));
+ ArrayList rev = new ArrayList(Arrays.asList(dave, cale, bob, amy));
+ t.checkExpect(new Utils().reverse(fwd), rev);
+ }
+}
diff --git a/completedwork/core_programming/02_classbased_design/Workspace/Lab10_HashStackIterator/src/StringCreator.java b/completedwork/core_programming/02_classbased_design/Workspace/Lab10_HashStackIterator/src/StringCreator.java
new file mode 100644
index 0000000..65bf5e8
--- /dev/null
+++ b/completedwork/core_programming/02_classbased_design/Workspace/Lab10_HashStackIterator/src/StringCreator.java
@@ -0,0 +1,54 @@
+import tester.Tester;
+
+class StringCreator {
+ String contents;
+ Stack actions;
+ StringCreator() {
+ contents = "";
+ actions = new Stack();
+ }
+
+ String getString() {
+ return contents;
+ }
+ void add(char item) {
+ this.actions.push(this.contents);
+ this.contents = this.contents + item;
+ }
+ void remove() {
+ this.actions.push(this.contents);
+ this.contents = this.contents.substring(0, this.contents.length() - 1);
+ }
+ void undo() {
+ if (!this.actions.isEmpty()) {
+ this.contents = this.actions.pop();
+ }
+ }
+}
+
+class StringExamples {
+ void testRun(Tester t) {
+ StringCreator creator = new StringCreator();
+ t.checkExpect(creator.getString(), "");
+ creator.add('c');
+ creator.add('d');
+ t.checkExpect(creator.getString(), "cd");
+ creator.add('e');
+ t.checkExpect(creator.getString(), "cde");
+ creator.remove();
+ creator.remove();
+ t.checkExpect(creator.getString(), "c");
+ creator.undo(); //undoes the removal of 'd'
+ t.checkExpect(creator.getString(), "cd");
+ creator.undo(); //undoes the removal of 'e'
+ creator.undo(); //undoes the addition of 'e'
+ t.checkExpect(creator.getString(), "cd");
+ creator.add('a');
+ t.checkExpect(creator.getString(), "cda");
+ creator.undo(); //undoes the addition of 'a'
+ creator.undo(); //undoes the addition of 'd'
+ creator.undo(); //undoes the addition of 'c'
+ t.checkExpect(creator.getString(), "");
+ creator.undo(); //no effect, there is nothing to undo
+ }
+}