diff --git a/deque/src/deque/Main.java b/deque/src/deque/Main.java index 1eaf481..be044bf 100644 --- a/deque/src/deque/Main.java +++ b/deque/src/deque/Main.java @@ -4,15 +4,141 @@ import tester.Tester; class Examples { + Deque mtDeque; + + Deque exampleDeque; Sentinel exampleSentinel; + Deque oneTwo; + Node one; + Node two; + void init() { + mtDeque = new Deque(); + exampleSentinel = new Sentinel(); + exampleDeque = new Deque(exampleSentinel); + + Node n1 = new Node("abc"); + Node n2 = new Node("bcd"); + Node n3 = new Node("def"); + + exampleSentinel.assign(n3, n1); + n1.assign(exampleSentinel, n2); + n2.assign(n1, n3); + n3.assign(n2, exampleSentinel); + + one = new Node(1); + two = new Node(2); + + oneTwo = new Deque(); + + oneTwo.header.assign(two, one); + one.assign(oneTwo.header, two); + two.assign(one, oneTwo.header); } - void testSentinel(Tester t) { + void testDequeSize(Tester t) { init(); - t.checkExpect(exampleSentinel.nxt, exampleSentinel); + t.checkExpect(mtDeque.size(), 0); + t.checkExpect(exampleDeque.size(), 3); + } + + void testDequeAddAtHead(Tester t) { + init(); + + t.checkExpect(mtDeque.addAtHead(2).addAtHead(1), oneTwo); + } + + void testDequeAddAtTail(Tester t) { + init(); + + t.checkExpect(mtDeque.addAtTail(1).addAtTail(2), oneTwo); + } + + void testDequeRemoveFromHead(Tester t) { + init(); + + Deque justTwo = new Deque().addAtHead(2); + t.checkExpect(oneTwo.removeFromHead(), justTwo); + t.checkException( + new UnsupportedOperationException( + "Can't remove a `Sentinel` node." + ), + mtDeque, + "removeFromHead" + ); + } + + void testDequeRemoveFromTail(Tester t) { + init(); + + Deque justOne = new Deque().addAtHead(1); + t.checkExpect(oneTwo.removeFromTail(), justOne); + t.checkException( + new UnsupportedOperationException( + "Can't remove a `Sentinel` node." + ), + mtDeque, + "removeFromTail" + ); + } + + void testDequeFind(Tester t) { + init(); + + t.checkExpect(oneTwo.find(new isTwo()), two); + t.checkExpect( + oneTwo.find(new isTwoThousandOneHundredFortyFive()), + oneTwo.header + ); + t.checkExpect(mtDeque.find(new isTwo()), mtDeque.header); + } +} + +class Deque { + + ANode header; + + Deque() { + this.header = new Sentinel(); + } + + Deque(Sentinel sentinel) { + this.header = sentinel; + } + + // Get number of `Node`s in the list (not counting `Sentinel`s). + int size() { + return this.header.sz(); + } + + // Add an element to the 'head' of the list. + Deque addAtHead(T thing) { + this.header.addAtHead(thing); + return this; + } + + // Add an element to the 'head' of the list. + Deque addAtTail(T thing) { + this.header.addAtTail(thing); + return this; + } + + // Remove the first element in the list. + Deque removeFromHead() { + this.header.removeFromHead(); + return this; + } + + // Remove the last element in the list. + Deque removeFromTail() { + this.header.removeFromTail(); + return this; + } + + ANode find(IPred question) { + return this.header.find(question); } } @@ -27,23 +153,75 @@ abstract class ANode { this.pre = pre; } - void assignNode(ANode nxt, ANode pre) { + void setNxt(ANode nxt) { + this.nxt = nxt; + } + + void setPre(ANode pre) { + this.pre = pre; + } + + void assign(ANode pre, ANode nxt) { + this.setPre(pre); + this.setNxt(nxt); + } + + // Get the size of a list, not including the `Sentinel`. + int sz() { throw new UnsupportedOperationException( - "Can't call assignNode() on non-Node." + "Can't call `sz()` on non-`Sentinel` node." ); } -} -class Deque { + int szHelper() { + return 1 + this.nxt.szHelper(); + } - Sentinel sentinel; + void addAtHead(T thing) { + throw new UnsupportedOperationException( + "Can't call `addAtHead()` on non-`Sentinel` node." + ); + } - Deque(Sentinel sentinel) { - this.sentinel = sentinel; + void addAtTail(T thing) { + throw new UnsupportedOperationException( + "Can't call `addAtTail()` on non-`Sentinel` node." + ); + } + + void removeFromHead() { + throw new UnsupportedOperationException( + "Can't call `removeHead()` on non-`Sentinel` node." + ); + } + + void removeFromTail() { + throw new UnsupportedOperationException( + "Can't call `removeTail()` on non-`Sentinel` node." + ); + } + + // Set surrounding nodes to pass over this one. + void remove() { + this.nxt.setPre(this.pre); + this.pre.setNxt(this.nxt); + this.nxt = null; + this.pre = null; + } + + ANode find(IPred question) { + throw new UnsupportedOperationException( + "Can't call `find()` on non-`Sentinel` node." + ); + } + + ANode findHelper(IPred question) { + return this; } } -class Sentinel extends ANode> { +// The sentinel of the list, linking its head and tail. +class Sentinel extends ANode { Sentinel() { // To create an empty list, this Sentinel points to itself. @@ -51,9 +229,44 @@ class Sentinel extends ANode> { this.nxt = this; this.pre = this; } + + int sz() { + return this.nxt.szHelper(); + } + + int szHelper() { + return 0; + } + + void addAtHead(T thing) { + new Node(thing, this, this.nxt); + } + + void addAtTail(T thing) { + new Node(thing, this.pre, this); + } + + void removeFromHead() { + this.nxt.remove(); + } + + void removeFromTail() { + this.pre.remove(); + } + + void remove() { + throw new UnsupportedOperationException( + "Can't remove a `Sentinel` node." + ); + } + + ANode find(IPred question) { + return this.nxt.findHelper(question); + } } -class Node extends ANode> { +// A node in the list. +class Node extends ANode { T val; @@ -62,14 +275,39 @@ class Node extends ANode> { this.val = val; } - Node(T val, ANode nxt, ANode pre) { + Node(T val, ANode pre, ANode nxt) { this(val); - this.assignNode(nxt, pre); + if (nxt == null || pre == null) throw new IllegalArgumentException( + "Can't construct node with defunct fields." + ); + + this.nxt = nxt; + this.pre = pre; + + nxt.setPre(this); + pre.setNxt(this); } - void assignNode(ANode nxt, ANode pre) { - throw new UnsupportedOperationException( - "Can't call assignNode() on non-Node." - ); + ANode findHelper(IPred question) { + return question.ask(this.val) ? this : this.nxt.findHelper(question); + } +} + +// A predicate. +interface IPred { + boolean ask(T thing); +} + +class isTwo implements IPred { + + public boolean ask(Integer n) { + return n == 2; + } +} + +class isTwoThousandOneHundredFortyFive implements IPred { + + public boolean ask(Integer n) { + return n == 2145; } } diff --git a/mastermind/.classpath b/mastermind/.classpath index 3d02881..91fefed 100644 --- a/mastermind/.classpath +++ b/mastermind/.classpath @@ -6,7 +6,7 @@ - - + +