diff --git a/src/edu/caltech/cs2/datastructures/ArrayDeque.java b/src/edu/caltech/cs2/datastructures/ArrayDeque.java new file mode 100644 index 0000000000000000000000000000000000000000..eed9ee5159f7602b3174311531e177f7c7953166 --- /dev/null +++ b/src/edu/caltech/cs2/datastructures/ArrayDeque.java @@ -0,0 +1,169 @@ +package edu.caltech.cs2.datastructures; + + +import edu.caltech.cs2.interfaces.IDeque; +import edu.caltech.cs2.interfaces.IQueue; +import edu.caltech.cs2.interfaces.IStack; + +import java.util.Iterator; + +public class ArrayDeque<E> implements IDeque<E>, IQueue<E>, IStack<E> { + private E[] data; + private int size; + private static final int DEFAULT_CAPACITY = 10; + private static final int DEFAULT_GROWTH = 2; + + public ArrayDeque() { + this(DEFAULT_CAPACITY); + } + + public ArrayDeque(int initialCapacity) { + this.data = (E[]) new Object[initialCapacity]; + this.size = 0; + } + + @Override + public void addFront(E e) { + resize(); + if (this.size > 0) { + System.arraycopy(this.data, 0, this.data, 1, this.size); + } + this.data[0] = e; + this.size++; + } + + @Override + public void addBack(E e) { + resize(); + this.data[this.size] = e; + this.size++; + } + + @Override + public E removeFront() { + resize(); + if (this.size == 0){ + return null; + } + E e = this.data[0]; + System.arraycopy(this.data, 1, this.data, 0, this.size - 1); + this.size--; + return e; + } + + @Override + public E removeBack() { + resize(); + if (this.size == 0){ + return null; + } + E e = this.data[this.size - 1]; + this.size--; + return e; + } + + @Override + public boolean enqueue(E e) { + addFront(e); + return true; + } + + @Override + public E dequeue() { + if (this.data[0] == null){ + return null; + } else { + return removeBack(); + } + } + + @Override + public boolean push(E e) { + addBack(e); + return true; + } + + @Override + public E pop() { + if (this.data[0] == null){ + return null; + } else { + return removeBack(); + } + } + + @Override + public E peekFront() { + if (this.size == 0){ + return null; + } + return this.data[0]; + } + + @Override + public E peekBack() { + if (this.size == 0){ + return null; + } + return this.data[this.size - 1]; + } + + @Override + public E peek() { + return peekBack(); + } + + @Override + public Iterator<E> iterator() { + return new ArrayDequeIterator(); + } + + @Override + public int size() { + return this.size; + } + + private class ArrayDequeIterator implements Iterator<E> { + private int idx = 0; + + @Override + public boolean hasNext() { + return this.idx < ArrayDeque.this.size; + } + + @Override + public E next() { + E element = ArrayDeque.this.data[this.idx]; + this.idx++; + return element; + } + } + + // from lecture notes + private void resize() { + if (this.size == this.data.length) { + E[] newData = (E[])new Object[this.data.length * DEFAULT_GROWTH]; + System.arraycopy(this.data, 0, newData, 0, this.size); + this.data = newData; + } + } + + @Override + public String toString() { + if (this.size == 0) { + return "[]"; + } + else { + StringBuilder resultSB = new StringBuilder(); + resultSB.append("["); + for (int i = 0; i < this.size; i++) { + resultSB.append(this.data[i]).append(", "); + } + String result = resultSB.toString(); + result = result.substring(0, result.length() - 2); + return result + "]"; + } + + } +} + diff --git a/src/edu/caltech/cs2/datastructures/ChainingHashDictionary.java b/src/edu/caltech/cs2/datastructures/ChainingHashDictionary.java new file mode 100644 index 0000000000000000000000000000000000000000..11d8374ba06422db5c1069c2089079fedb795158 --- /dev/null +++ b/src/edu/caltech/cs2/datastructures/ChainingHashDictionary.java @@ -0,0 +1,156 @@ +package edu.caltech.cs2.datastructures; + +import edu.caltech.cs2.interfaces.ICollection; +import edu.caltech.cs2.interfaces.IDictionary; + +import java.util.Iterator; +import java.util.function.Supplier; + +public class ChainingHashDictionary<K, V> implements IDictionary<K, V> { + // chain, supplier<idict> + //int size, capacity, double load factor (1) + //array of dictionary data + private Supplier<IDictionary<K, V>> chain; + private IDictionary<K,V>[] data; + private double loadFactor = 1.0; + private int size; + private int capacity = 17; + + public ChainingHashDictionary(Supplier<IDictionary<K, V>> chain) { + this.chain = chain; + this.data = new IDictionary[capacity]; + this.size = 0; + for (int i = 0; i < data.length; i++){ + this.data[i] = chain.get(); + } + } + + /** + * @param key + * @return value corresponding to key + */ + @Override + public V get(K key) { + // V val = this.data[index].get(key); + IDictionary<K,V> chain = this.data[Math.abs((key.hashCode() % capacity + capacity) % capacity)]; + if (chain == null || key == null) { + return null; + } + return chain.get(key); + } + + @Override + public V remove(K key) { + int index = (key.hashCode() % capacity + capacity) % capacity; + IDictionary<K,V> chain = this.data[index]; + V val = chain.remove(key); + if (val == null) { + return null; + } else { + this.size--; + this.data[index] = chain; + } + return val; + } + + @Override + public V put(K key, V value) { + if (this.size/this.data.length > this.loadFactor) { + rehash(); + } + V val = null; + int index = Math.abs((key.hashCode() % capacity + capacity) % capacity); + IDictionary<K,V> chain = this.data[index]; + if (chain == null) { + chain = this.chain.get(); + } + if (chain.get(key) != null) { + val = chain.get(key); + } else { + this.size++; + } + this.data[index] = chain; + chain.put(key, value); + return val; + } + + public void rehash(){ + //make bigger array + //copy items over + //this.data = new Arr + IDictionary<K,V>[] arr = new IDictionary[(this.data.length * 2) + 1]; + for (IDictionary<K,V> chain : this.data){ + if (chain != null) { + for (K key : chain.keys()) { + int idx = Math.abs((key.hashCode() % arr.length + arr.length) % arr.length); + IDictionary<K, V> data = arr[idx]; + if (data == null) { + data = this.chain.get(); + } + arr[idx] = data; + data.put(key, chain.get(key)); + } + } + } + this.data = arr; + this.capacity = arr.length; + } + + @Override + public boolean containsKey(K key) { + + return (this.get(key) != null); + } + + /** + * @param value + * @return true if the HashDictionary contains a key-value pair with + * this value, and false otherwise + */ + @Override + public boolean containsValue(V value) { + return this.values().contains(value); + } + + /** + * @return number of key-value pairs in the HashDictionary + */ + @Override + public int size() { + return this.size; + } + + @Override + public ICollection<K> keys() { + ICollection<K> keys = new ArrayDeque<>(); + for (IDictionary<K,V> dict : this.data){ + if (dict != null) { + for (K key : dict.keys()) { + keys.add(key); + } + } + } + return keys; + } + + @Override + public ICollection<V> values() { + ICollection<V> values = new ArrayDeque<>(); + for (IDictionary<K, V> dict: this.data){ + if (dict != null) { + for (V value : dict.values()) { + values.add(value); + } + } + } + return values; + } + + /** + * @return An iterator for all entries in the HashDictionary + */ + @Override + public Iterator<K> iterator() { + return this.keys().iterator(); + } +} diff --git a/src/edu/caltech/cs2/datastructures/LinkedDeque.java b/src/edu/caltech/cs2/datastructures/LinkedDeque.java new file mode 100644 index 0000000000000000000000000000000000000000..3fd9a6aa7a7602b73ace66447654bcffddcb15a2 --- /dev/null +++ b/src/edu/caltech/cs2/datastructures/LinkedDeque.java @@ -0,0 +1,202 @@ +package edu.caltech.cs2.datastructures; + + +import edu.caltech.cs2.interfaces.IDeque; +import edu.caltech.cs2.interfaces.IQueue; +import edu.caltech.cs2.interfaces.IStack; + +import java.util.Iterator; + +public class LinkedDeque<E> implements IDeque<E>, IQueue<E>, IStack<E> { + private Node<E> head; + private int size; + private Node<E> tail; + + public LinkedDeque(){ + this.head = null; + this.tail = null; + this.size = 0; + } + + private static class Node<E> { + public final E data; + public Node<E> next; + public Node<E> prev; + + public Node(E data) { + this(data, null, null); + } + + public Node(E data, Node<E> next, Node<E> prev) { + this.data = data; + this.next = next; + this.prev = prev; + } + } + + @Override + public void addFront(E e) { + if (this.size == 0){ + Node<E> tempNode = new Node<>(e); + this.tail = tempNode; + this.head = tempNode; + } else { + Node<E> tempHead = new Node<>(e, this.head, null); + // previous is this head + this.head.prev = tempHead; + //switch node + this.head = tempHead; + } + this.size++; + } + + @Override + public void addBack(E e) { + if (this.size == 0){ + this.head = new Node<>(e); + this.tail = this.head; + } else { + Node<E> tempTail = new Node<>(e, null, this.tail); + this.tail.next = tempTail; + this.tail = tempTail; + } + this.size++; + } + + @Override + public E removeFront() { + if (this.size == 0) { + return null; + } + E tempHead = this.head.data; + this.head = this.head.next; + if (this.head != null) { + this.head.prev = null; + } + this.size--; + if (this.size == 0) { + this.tail = this.head; + } + return tempHead; + } + + @Override + public E removeBack() { + if (this.size == 0) { + return null; + } + E tempHead = this.tail.data; + this.tail = this.tail.prev; + if (this.tail != null) { + this.tail.next = null; + } + this.size--; + if (this.size == 0) { + this.head = this.tail; + } + return tempHead; + } + + @Override + public boolean enqueue(E e) { + addFront(e); + return true; + } + + @Override + public E dequeue() { + if (this.head == null || this.tail == null){ + return null; + } else { + return removeBack(); + } + } + + @Override + public boolean push(E e) { + addBack(e); + return true; + } + + @Override + public E pop() { + if (this.head == null || this.tail == null){ + return null; + } else { + return removeBack(); + } + } + + @Override + public E peekFront() { + if (this.size == 0){ + return null; + } + return this.head.data; + } + + @Override + public E peekBack() { + if (this.size == 0) { + return null; + } + return this.tail.data; + } + + @Override + public E peek() { + return peekBack(); + } + + @Override + public Iterator<E> iterator() { + return new LinkedDequeIterator(); + } + + @Override + public int size() { + return this.size; + } + + @Override + public String toString(){ + String returnStatement = ""; + if (this.size == 0) { + return "[]"; + } + else { + returnStatement += "["; + Node<E> tempNode = this.head; + for (int i = 0; i < this.size; i++){ + returnStatement += tempNode.data.toString(); + returnStatement += ", "; + tempNode = tempNode.next; + } + returnStatement = returnStatement.substring(0, returnStatement.length() - 2); + returnStatement += "]"; + return returnStatement; + } + + + } + + private class LinkedDequeIterator implements Iterator<E> { + private Node<E> currNode = null; + + public LinkedDequeIterator(){ + this.currNode = LinkedDeque.this.head; + } + + @Override + public boolean hasNext() { + return this.currNode != null; + } + + @Override + public E next() { + E element = currNode.data; + this.currNode = currNode.next; + return element; + } + } +} diff --git a/src/edu/caltech/cs2/datastructures/MinFourHeap.java b/src/edu/caltech/cs2/datastructures/MinFourHeap.java new file mode 100644 index 0000000000000000000000000000000000000000..5ac5b85a862b7a146a4c6bcbe54f46f90e724d7d --- /dev/null +++ b/src/edu/caltech/cs2/datastructures/MinFourHeap.java @@ -0,0 +1,154 @@ +package edu.caltech.cs2.datastructures; + +import edu.caltech.cs2.interfaces.IDictionary; +import edu.caltech.cs2.interfaces.IPriorityQueue; + +import java.util.Iterator; + +public class MinFourHeap<E> implements IPriorityQueue<E> { + + private static final int DEFAULT_CAPACITY = 10; + private static final int GROWTH_FACTOR = 2; + private int size; + private PQElement<E>[] data; + private IDictionary<E, Integer> keyToIndexMap; + + /** + * Creates a new empty heap with DEFAULT_CAPACITY. + */ + public MinFourHeap() { + this.size = 0; + this.data = new PQElement[DEFAULT_CAPACITY]; + this.keyToIndexMap = new ChainingHashDictionary<>(MoveToFrontDictionary::new); + } + + @Override + public void increaseKey(PQElement<E> key) { + if (!this.keyToIndexMap.containsKey(key.data)) { + throw new IllegalArgumentException("Can't modify a nonexistent element!"); + } + if (key.priority > this.data[this.keyToIndexMap.get(key.data)].priority) { + this.data[this.keyToIndexMap.get(key.data)] = key; + percDown(this.keyToIndexMap.get(key.data)); + } + } + + @Override + public void decreaseKey(PQElement<E> key) { + if (!this.keyToIndexMap.containsKey(key.data)) { + throw new IllegalArgumentException("Can't modify a nonexistent element!"); + } + else if (key.priority < this.data[this.keyToIndexMap.get(key.data)].priority) { + this.data[this.keyToIndexMap.get(key.data)] = key; + percUp(this.keyToIndexMap.get(key.data)); + } + } + + @Override + public boolean enqueue(PQElement<E> epqElement) { + if (this.keyToIndexMap.containsKey(epqElement.data)) { + throw new IllegalArgumentException("This key is already in MinFourHeap!"); + } + else if (this.size >= this.data.length) { + PQElement<E>[] temp = new PQElement[this.size * GROWTH_FACTOR]; + System.arraycopy(this.data, 0, temp, 0, this.size); + this.data = temp; + } + this.data[this.size] = epqElement; + this.keyToIndexMap.put(epqElement.data, this.size); + this.size++; + percUp(this.size - 1); + return true; + } + + @Override + public PQElement<E> dequeue() { + if (this.size == 0) { + return null; + } + else if (this.size == 1) { + PQElement<E> root = this.data[0]; + this.size--; + this.keyToIndexMap.remove(root.data); + this.data[0] = null; + return root; + } + PQElement<E> root = this.data[0]; + this.size--; + this.keyToIndexMap.remove(root.data); + this.data[0] = this.data[this.size]; + this.keyToIndexMap.put(this.data[0].data, 0); + percDown(0); + return root; + } + + @Override + public PQElement<E> peek() { + if (this.size == 0) { + throw new IllegalArgumentException("Empty array, nothing to peek!"); + } + return data[0]; + } + + @Override + public int size() { + return this.size; + } + + @Override + public Iterator<PQElement<E>> iterator() { + return null; + } + + private boolean hasChild (int index, int childNum) { + int childIndex = ((4 * index) + childNum); + return (childIndex < this.size && childIndex > 0); + } + + private void percUp(int idx) { + while ((idx - 1) / 4 >= 0 && this.data[(idx - 1) / 4].priority > this.data[idx].priority) { + int parentidx = (idx - 1) / 4; + PQElement temp = data[parentidx]; + data[parentidx] = data[idx]; + data[idx] = temp; + int temp2 = this.keyToIndexMap.get(data[parentidx].data); + this.keyToIndexMap.put(data[parentidx].data, this.keyToIndexMap.get(data[idx].data)); + this.keyToIndexMap.put(data[idx].data, temp2); + idx = (idx - 1) / 4;; + } + } + + private void percDown(int idx) { + while (hasChild(idx, 1)) { + int parentidx = 0; + int minchildIndex = ((4 * idx) + 1); + if (minchildIndex >= this.size) { + minchildIndex = 1; + } + double min = this.data[minchildIndex].priority; + int minChildIndex = minchildIndex; + int childNum = 2; + while (hasChild(idx, childNum) && childNum <= 4) { + int childIndex = ((4 * idx) + childNum); + if(this.data[childIndex].priority < min) { + min = this.data[childIndex].priority; + minChildIndex = childIndex; + } + childNum++; + } + parentidx = minChildIndex; + PQElement smallestChild = this.data[parentidx]; + if (smallestChild.priority < this.data[idx].priority) { + PQElement temp = data[parentidx]; + data[parentidx] = data[idx]; + data[idx] = temp; + int temp2 = this.keyToIndexMap.get(data[parentidx].data); + this.keyToIndexMap.put(data[parentidx].data, this.keyToIndexMap.get(data[idx].data)); + this.keyToIndexMap.put(data[idx].data, temp2); + } else { + break; + } + idx = parentidx; + } + } +} \ No newline at end of file diff --git a/src/edu/caltech/cs2/datastructures/MoveToFrontDictionary.java b/src/edu/caltech/cs2/datastructures/MoveToFrontDictionary.java new file mode 100644 index 0000000000000000000000000000000000000000..fa6fad3f513c5b6b3afb4efe5e0d16004a3d94b2 --- /dev/null +++ b/src/edu/caltech/cs2/datastructures/MoveToFrontDictionary.java @@ -0,0 +1,186 @@ +package edu.caltech.cs2.datastructures; + +import edu.caltech.cs2.interfaces.ICollection; +import edu.caltech.cs2.interfaces.IDictionary; + +import java.util.Iterator; + +public class MoveToFrontDictionary<K, V> implements IDictionary<K,V> { + //keep track global head <Node <K, V> + //dictionary nodes have K key, V value + //Node<K,V> next + private Node<K, V> head; + private int size; + + public MoveToFrontDictionary() { + this.head = null; + this.size = 0; + } + + private static class Node<K, V> { + public K key; + public V value; + public Node<K, V> next; + + public Node(K key, V value) { + + this(key, value, null); + } + + public Node(K key, V value, Node<K, V> next){ + this.key = key; + this.value = value; + this.next = next; + } + } + + @Override + public V remove(K key) { + //call get() on key + //head = head.next + if (this.head == null){ + return null; + } + if (!this.containsKey(key)){ + return null; + } + if (this.head.key.equals(key)){ + V value = this.head.value; + this.head = this.head.next; + this.size --; + return value; + } + Node<K, V> current = this.head; + Node<K, V> prev = null; + while (current != null && !current.key.equals(key)){ + prev = current; + current = current.next; + } + if (current == null) { + return null; + } + prev.next = current.next; + this.size--; + return current.value; + } + + @Override + public V put(K key, V value) { + //save head node as oldHead + //Head = new Node(key, val) + //head.next = old.head (???) + V oldHead = this.remove(key); + Node<K, V> node = new Node<K, V>(key, value); + if (this.head != null){ + node.next = this.head; + } + this.head = node; + this.size++; + return oldHead; + } + + @Override + public boolean containsKey(K key) { + return this.keys().contains(key); + } + + @Override + public boolean containsValue(V value) { + return this.values().contains(value); + } + + @Override + public int size() { + return this.size; + } + + @Override + public ICollection<K> keys() { + ICollection<K> deq = new ArrayDeque<>(); + + if (this.head == null) { + return deq; + } + + Node<K, V> current = this.head; + + while (current != null) { + deq.add(current.key); + + current = current.next; + } + + return deq; + } + + @Override + public ICollection<V> values() { + + ICollection<V> deq = new ArrayDeque<>(); + + if (this.head == null){ + return deq; + } + Node<K, V> current = this.head; + while (current != null) { + deq.add(current.value); + + current = current.next; + } + + return deq; + + } + + public V get(K key) { + if (this.head == key){ + return this.head.value; + } + else { + Node<K, V> curr = this.head; + while (curr != null) { + if (curr.key.equals(key)){ + V val = curr.value; + /* + //rather than use put, directly change the pointers of the node being accessed + Node<K, V> nxtNode = curr.next; + nxtNode.next = this.head; + this.head = nxtNode; + //previous node + //create a new node at front of list with the node that is being accessed + */ + this.put(key, val); + return val; + } + curr = curr.next; + } + } + return null; + } + + @Override + public Iterator<K> iterator() { + return new MoveToFrontIterator(this); + } + + private class MoveToFrontIterator implements Iterator<K>{ + //take linkeddeque iterator + private Node<K, V> currNode = null; + + public MoveToFrontIterator(MoveToFrontDictionary dict){ + this.currNode = dict.head; + } + + @Override + public boolean hasNext() { + return this.currNode != null; + } + + @Override + public K next() { + K element = currNode.key; + this.currNode = currNode.next; + return element; + } + } +} diff --git a/src/edu/caltech/cs2/interfaces/IDictionary.java b/src/edu/caltech/cs2/interfaces/IDictionary.java new file mode 100644 index 0000000000000000000000000000000000000000..97892446efe78293b1546f1b112d586c104801bf --- /dev/null +++ b/src/edu/caltech/cs2/interfaces/IDictionary.java @@ -0,0 +1,112 @@ +package edu.caltech.cs2.interfaces; + +import edu.caltech.cs2.datastructures.LinkedDeque; + +public interface IDictionary<K, V> extends Iterable<K> { + + public static class Entry<K, V> { + public final K key; + public V value; + + public Entry(K key) { + this(key, null); + } + + public Entry(K key, V value) { + this.key = key; + this.value = value; + } + } + + /** + * Returns the value to which the specified key is mapped, + * or {@code null} if this map contains no mapping for the key. + */ + public V get(K key); + + /** + * Removes the mapping for the specified key from this map if present. + * + * @param key key whose mapping is to be removed from the map + * @return the previous value associated with {@code key}, or + * {@code null} if there was no mapping for {@code key}. + */ + public V remove(K key); + + /** + * Associates the specified value with the specified key in this map. + * If the map previously contained a mapping for the key, the old + * value is replaced. + * + * @param key key with which the specified value is to be associated + * @param value value to be associated with the specified key + * @return the previous value associated with {@code key}, or + * {@code null} if there was no mapping for {@code key}. + */ + public V put(K key, V value); + + /** + * Returns {@code true} if this map contains a mapping for the + * specified key. + * + * @param key The key whose presence in this map is to be tested + * @return {@code true} if this map contains a mapping for the specified + * key. + */ + public boolean containsKey(K key); + + /** + * Returns {@code true} if this map maps one or more keys to the + * specified value. + * + * @param value value whose presence in this map is to be tested + * @return {@code true} if this map maps one or more keys to the + * specified value + */ + public boolean containsValue(V value); + + /** + * Returns the number of key-value mappings in this map. + * + * @return the number of key-value mappings in this map + */ + public int size(); + + + /** + * Returns {@code true} if this map contains no key-value mappings. + * + * @return {@code true} if this map contains no key-value mappings + */ + default public boolean isEmpty() { + return this.size() == 0; + } + + /** + * Returns a {@link ICollection} of the keys contained in this map. + * + * @return a collection of the keys contained in this map + */ + public ICollection<K> keys(); + + /** + * Returns a {@link ICollection} of the values contained in this map + * which does not contain duplicates. + * + * @return a collection of the values contained in this map + */ + public ICollection<V> values(); + + default public ICollection<Entry<K, V>> entrySet() { + IDeque<Entry<K, V>> entries = new LinkedDeque<>(); + for (K key : keys()) { + entries.add(new Entry(key, this.get(key))); + } + return entries; + } + + @SuppressWarnings("unchecked cast") + default ISet<K> keySet() { + return ISet.getBackingSet((IDictionary<K, Object>)this); + } +} diff --git a/src/edu/caltech/cs2/interfaces/IPriorityQueue.java b/src/edu/caltech/cs2/interfaces/IPriorityQueue.java new file mode 100644 index 0000000000000000000000000000000000000000..d0c0bf81f7b039f4545a0e2f2563d224e683c534 --- /dev/null +++ b/src/edu/caltech/cs2/interfaces/IPriorityQueue.java @@ -0,0 +1,50 @@ +package edu.caltech.cs2.interfaces; + +/** + * This interface represents a Priority Queue - a data structure that is very similar to a queue but + * stores values in ascending order. + * @param <E> Element type + */ +public interface IPriorityQueue<E> extends IQueue<IPriorityQueue.PQElement<E>> { + public static class PQElement<E> { + public final E data; + public final double priority; + + public PQElement(E data, double priority) { + this.data = data; + this.priority = priority; + } + + @Override + public int hashCode() { + return this.data.hashCode(); + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof PQElement)) { + return false; + } + return this.data.equals(((PQElement)o).data); + } + + @Override + public String toString() { + return "(" + this.data + ", " + this.priority + ")"; + } + } + + + /** + * Increase the priority of the key at idx + * @param key - the new key with the new priority + */ + public void increaseKey(PQElement<E> key); + + /** + * Decrease the priority of the key at idx + * @param key - the new key with the new priority + */ + public void decreaseKey(PQElement<E> key); + +} \ No newline at end of file diff --git a/src/edu/caltech/cs2/interfaces/ISet.java b/src/edu/caltech/cs2/interfaces/ISet.java new file mode 100644 index 0000000000000000000000000000000000000000..61e179ec8509f79aa3a56e90d8caa7f20917b7f6 --- /dev/null +++ b/src/edu/caltech/cs2/interfaces/ISet.java @@ -0,0 +1,114 @@ +package edu.caltech.cs2.interfaces; + + +import java.util.Iterator; + +public class ISet<E> implements Iterable<E> { + + private IDictionary<E, Object> internalDictionary; + + protected ISet(IDictionary<E, Object> dict) { + this.internalDictionary = dict; + } + + public static <E> ISet<E> getBackingSet(IDictionary<E, Object> dict) { + return new ISet<E>(dict); + } + + /** + * Returns the number of elements in this set (its cardinality). If this + * set contains more than {@code Integer.MAX_VALUE} elements, returns + * {@code Integer.MAX_VALUE}. + * + * @return the number of elements in this set (its cardinality) + */ + public int size() { + return this.internalDictionary.size(); + } + + /** + * Returns {@code true} if this set contains no elements. + * + * @return {@code true} if this set contains no elements + */ + public boolean isEmpty() { + return this.internalDictionary.isEmpty(); + } + + /** + * Returns {@code true} if this set contains the specified element. + * More formally, returns {@code true} if and only if this set + * contains an element {@code e} such that + * {@code Objects.equals(o, e)}. + * + * @param e element whose presence in this set is to be tested + * @return {@code true} if this set contains the specified element + */ + public boolean contains(E e) { + return this.internalDictionary.containsKey(e); + } + + /** + * Returns an iterator over the elements in this set. The elements are + * returned in no particular order (unless this set is an instance of some + * class that provides a guarantee). + * + * @return an iterator over the elements in this set + */ + @Override + public Iterator<E> iterator() { + return this.internalDictionary.iterator(); + } + + + // Modification Operations + + /** + * Adds the specified element to this set if it is not already present + * (optional operation). More formally, adds the specified element + * {@code e} to this set if the set contains no element {@code e2} + * such that + * {@code Objects.equals(e, e2)}. + * If this set already contains the element, the call leaves the set + * unchanged and returns {@code false}. In combination with the + * restriction on constructors, this ensures that sets never contain + * duplicate elements. + * + * @param e element to be added to this set + * @return {@code true} if this set did not already contain the specified + * element + */ + public boolean add(E e) { + return this.internalDictionary.put(e, new Object()) == null; + } + + + /** + * Removes the specified element from this set if it is present + * (optional operation). More formally, removes an element {@code e} + * such that + * {@code Objects.equals(o, e)}, if + * this set contains such an element. Returns {@code true} if this set + * contained the element (or equivalently, if this set changed as a + * result of the call). (This set will not contain the element once the + * call returns.) + * + * @param e object to be removed from this set, if present + * @return {@code true} if this set contained the specified element + */ + public boolean remove(E e) { + return this.internalDictionary.remove(e) != null; + } + + @Override + public String toString() { + StringBuilder b = new StringBuilder(); + for (E e : this) { + b.append(e + ", "); + } + if (b.length() > 0) { + b.delete(b.length() - 2, b.length()); + } + return "[" + b.toString() + "]"; + } +} diff --git a/src/edu/caltech/cs2/project08/bots/AlphaBetaSearcher.java b/src/edu/caltech/cs2/project08/bots/AlphaBetaSearcher.java index bad0e66f80b4307549c6db03d70ee17d221c956d..b65ef6b0d5a6db0568388f96bd82a5be1e0cee8a 100644 --- a/src/edu/caltech/cs2/project08/bots/AlphaBetaSearcher.java +++ b/src/edu/caltech/cs2/project08/bots/AlphaBetaSearcher.java @@ -1,5 +1,7 @@ package edu.caltech.cs2.project08.bots; +import edu.caltech.cs2.datastructures.ArrayDeque; +import edu.caltech.cs2.interfaces.IDeque; import edu.caltech.cs2.project08.game.Board; import edu.caltech.cs2.project08.game.Evaluator; import edu.caltech.cs2.project08.game.Move; @@ -12,6 +14,21 @@ public class AlphaBetaSearcher<B extends Board> extends AbstractSearcher<B> { } private static <B extends Board> BestMove alphaBeta(Evaluator<B> evaluator, B board, int depth) { - return null; + ArrayDeque<Move> nextBoards = (ArrayDeque<Move>) board.getMoves(); + BestMove bestMove = null; + if (depth == 0 || nextBoards.isEmpty()) { + int score = evaluator.eval(board); + bestMove = new BestMove(score); + } else { + for (Move nextBoard : nextBoards) { + BestMove move = alphaBeta(evaluator, board, depth - 1); + move.negate(); + if (bestMove == null || move.score > bestMove.score) { + bestMove = new BestMove(nextBoard, move.score); + } + } + } + + return bestMove; } } \ No newline at end of file diff --git a/src/edu/caltech/cs2/project08/bots/MinimaxSearcher.java b/src/edu/caltech/cs2/project08/bots/MinimaxSearcher.java index 874e3fa5d68f0269e54daae733878e38c64dddc0..c0c121b5acd818b7421e3262ff228502a0bf776a 100644 --- a/src/edu/caltech/cs2/project08/bots/MinimaxSearcher.java +++ b/src/edu/caltech/cs2/project08/bots/MinimaxSearcher.java @@ -1,5 +1,9 @@ package edu.caltech.cs2.project08.bots; +import edu.caltech.cs2.datastructures.ArrayDeque; +import edu.caltech.cs2.project08.board.ArrayBoard; +import edu.caltech.cs2.project08.bots.AbstractSearcher; +import edu.caltech.cs2.project08.bots.BestMove; import edu.caltech.cs2.project08.game.Board; import edu.caltech.cs2.project08.game.Evaluator; import edu.caltech.cs2.project08.game.Move; @@ -12,6 +16,24 @@ public class MinimaxSearcher<B extends Board> extends AbstractSearcher<B> { } private static <B extends Board> BestMove minimax(Evaluator<B> evaluator, B board, int depth) { - return null; + if (depth == 0 || board.isGameOver()) { + return new BestMove(null, evaluator.eval(board)); + } + ArrayDeque<Move> legalMoves = (ArrayDeque<Move>) board.getMoves(); + if (legalMoves.isEmpty()) { + return new BestMove(null, evaluator.eval(board)); + } + BestMove bestMove = null; + for (Move move : legalMoves) { + board.makeMove(move); + BestMove response = minimax(evaluator, board, depth - 1); + response.negate(); + int value = response.score; + if (bestMove == null || value > bestMove.score) { + bestMove = new BestMove(move, value); + } + } + + return bestMove; } } \ No newline at end of file