diff --git a/ss2010/gdi2/java/Project3/.classpath b/ss2010/gdi2/java/Project3/.classpath new file mode 100644 index 00000000..b10b8d9b --- /dev/null +++ b/ss2010/gdi2/java/Project3/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/ss2010/gdi2/java/Project3/.project b/ss2010/gdi2/java/Project3/.project new file mode 100644 index 00000000..b2ee4de7 --- /dev/null +++ b/ss2010/gdi2/java/Project3/.project @@ -0,0 +1,17 @@ + + + Project3 + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/ss2010/gdi2/java/Project3/.settings/org.eclipse.jdt.core.prefs b/ss2010/gdi2/java/Project3/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000..9aeceb46 --- /dev/null +++ b/ss2010/gdi2/java/Project3/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,12 @@ +#Sat Jun 05 18:13:09 CEST 2010 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.6 +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.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/ss2010/gdi2/java/Project3/quizdb.txt b/ss2010/gdi2/java/Project3/quizdb.txt new file mode 100644 index 00000000..8ac0ba66 --- /dev/null +++ b/ss2010/gdi2/java/Project3/quizdb.txt @@ -0,0 +1,9 @@ +Is it a mammal? +Is it bigger than a tiger? +Does it have stripes? +Zevra +elephant +mouse +Does it live underwater? +trout +robin diff --git a/ss2010/gdi2/java/Project3/src/BinaryTree.java b/ss2010/gdi2/java/Project3/src/BinaryTree.java new file mode 100644 index 00000000..392722d2 --- /dev/null +++ b/ss2010/gdi2/java/Project3/src/BinaryTree.java @@ -0,0 +1,26 @@ +import java.util.List; + +/** + * A simple generic interface for binary trees to be used by the Quiz class. + * + * @param The type of the data held in nodes of the tree. + */ +public interface BinaryTree { + + /** + * Initiates a new search from the root of this binary tree. This method + * can be implemented by creating an anonymous class of type BinaryTreeSearch, + * similar to many Iterator implementations. + * + * @return A new object of type BinaryTreeSearch. + */ + public BinaryTreeSearch binaryTreeSearch(); + + /** + * Produces a pre-order traversal sequence for this tree. + * + * @return A list of data objects in pre-order. + */ + public List preorder(); + +} diff --git a/ss2010/gdi2/java/Project3/src/BinaryTreeSearch.java b/ss2010/gdi2/java/Project3/src/BinaryTreeSearch.java new file mode 100644 index 00000000..2c57d495 --- /dev/null +++ b/ss2010/gdi2/java/Project3/src/BinaryTreeSearch.java @@ -0,0 +1,67 @@ +/** + * Interface for a generic search in a binary tree. A binary tree search is + * initiated at the root of a tree and maintains the information which node + * is the current node. + * + * The tree is searched by moving down from the current node to its left or + * right child. The tree can be modified at the current node by setting the + * data or adding new children with new data. + * + * @param The type of the data held in nodes of the tree. + */ +public interface BinaryTreeSearch { + + /** + * The data stored at the current node. + * + * @return The data at the current node. + */ + public A getData(); + + /** + * Checks whether the current node is a leaf node. + * + * @return True if the search arrived at a leaf node. + */ + public boolean isLeaf(); + + /** + * Checks whether the current node has a left child. + * + * @return True if the current node has a left child. + */ + public boolean hasLeftChild(); + + /** + * Checks whether the current node has a right child. + * + * @return True if the current node has a right child. + */ + public boolean hasRightChild(); + + /** + * Moves down to the left child. + * + * @throws NoSuchElementException if the current node has no left child. + */ + public void nextLeftChild(); + + /** + * Moves down to the right child. + * + * @throws NoSuchElementException if the current node has no right child. + */ + public void nextRightChild(); + + /** + * Replaces the current node and creates new children initialized to hold the + * provided data. If the data for a child is null, does not create the + * corresponding child. + * + * @param data The data for the current node. + * @param leftData The data for the new left child. + * @param rightData The data for the new right child. + */ + public void setNode(A data, A leftData, A rightData); + +} diff --git a/ss2010/gdi2/java/Project3/src/LinkedBinaryTree.java b/ss2010/gdi2/java/Project3/src/LinkedBinaryTree.java new file mode 100644 index 00000000..582571d1 --- /dev/null +++ b/ss2010/gdi2/java/Project3/src/LinkedBinaryTree.java @@ -0,0 +1,405 @@ +import java.io.Serializable; +import java.util.*; + +/** + * A binary tree in linked representation. Tree nodes are stored as objects consisting of + * pointers to their left and right child and to their associated data. + * + * @param The type of the data held in nodes of the tree. + */ +public class LinkedBinaryTree implements BinaryTree { + + /** + * NodeClass + * + * @param + */ + private class LinkedNode { + + /** + * Data of the Node + */ + private Datatype m_data = null; + + /** + * Left Child; another node or null + */ + private LinkedNode m_leftchild = null; + + /** + * Right Child; another node or null + */ + private LinkedNode m_rightchild = null; + + /** + * Constructor for a Leaf + * @param data Data of the Leaf + */ + public LinkedNode(Datatype data) + { + this.m_data = data; + } + + /** + * Constructor of a node with childs + * + * @param data Data of the Node + * @param leftchild Data of left child + * @param rightchild Data of right child + */ + public LinkedNode(Datatype data, LinkedNode leftchild, LinkedNode rightchild) + { + this.m_data = data; + this.m_leftchild = leftchild; + this.m_rightchild = rightchild; + } + + /** + * @return stored Data + */ + public Datatype getData() { + return m_data; + } + + /** + * Set Data of the Node + * + * @param data + */ + public void setData(Datatype data) { + m_data = data; + } + + /** + * @return Left Child (can be null) + */ + public LinkedNode getLeftChild() { + return m_leftchild; + } + + /** + * Sets Left Child + * + * @param leftchild Data + */ + public void setLeftChild(LinkedNode leftchild) { + m_leftchild = leftchild; + } + + /** + * @return Right Child (can be null) + */ + public LinkedNode getRightChild() { + return m_rightchild; + } + + /** + * Sets Right Child + * + * @param rightchild Data + */ + public void setRightChild(LinkedNode rightchild) { + m_rightchild = rightchild; + } + } + + /** + * Rootnode + */ + private LinkedNode root = null; + + /** + * Clones a Serializable Data object + * @param src + * @return cloned dataobject + */ + public static Serializable cloneSerializable(Serializable src) + { + try { + java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream(); + java.io.ObjectOutputStream oos = new java.io.ObjectOutputStream(baos); + oos.writeObject(src); + oos.flush(); + oos.close(); + java.io.ByteArrayInputStream bais = new + java.io.ByteArrayInputStream(baos.toByteArray()); + java.io.ObjectInputStream ois = new java.io.ObjectInputStream(bais); + Object dest = ois.readObject(); + ois.close(); + return (Serializable)dest; + } catch (Throwable th) { + return src; + } + } + + /** + * Definition of a Questionmark + */ + public static final String QUESTIONMARK = "?"; + + /** + * Create a tree from a given animal game preorder. + * + * param The type of the data held in nodes of the tree. + * @param preorder The preorder to build the tree from. + * @return A new LinkedBinaryTree corresponding to the provided preorder. + */ + public static LinkedBinaryTree createFromPreorder(List preorder) { + + //Clone of preorder + List preordercopy = new ArrayList(); + + //Clone preorder + for(int i=0;i result = new LinkedBinaryTree(); + + //Sets Root, calculated by recursiv_createFormPreorder + result.setRoot(result.recursiv_createFromPreorder(preordercopy)); + + //Preorder was empty or not valid + if(result.getRoot() == null) { + throw new UnsupportedOperationException(); + } + + //Return constructed Tree + return result; + } + + /** + * Create tree from Preorder recursiv nonstatic and with A-Parameter + * + * A must implement contains-function + * + * @param preorder + * @return Created Node or null + */ + private LinkedNode recursiv_createFromPreorder(List preorder) + { + //check if there is data to parse + if( preorder.size() < 1){ + return null; + } + + //create new node for data + LinkedNode node = new LinkedNode(preorder.get(0)); + preorder.remove(0); + + + //call recursiv if not an answer but a question + if(node.getData().toString().endsWith(QUESTIONMARK)) { + node.setLeftChild(recursiv_createFromPreorder(preorder)); + node.setRightChild(recursiv_createFromPreorder(preorder)); + } + + //return node created + return node; + } + + /** + * Create a pre-order traversal sequence for this tree. + * + * @return The pre-order sequence for this tree. + */ + @Override + public List preorder() { + + return recursiv_preorder(root); + } + + /** + * Creates preorder from Tree, recursiv! + * + * @param node Node to start from + * @return preorderlist + */ + private List recursiv_preorder(LinkedNode node){ + + //resultlist + List result = new ArrayList(); + + //still a node left? + if(node != null) + { + //add node data + result.add(node.getData()); + //add all left child data + result.addAll(recursiv_preorder(node.getLeftChild())); + //add all right child data + result.addAll(recursiv_preorder(node.getRightChild())); + } + + //return List + return result; + } + + /** + * @return root node or null + */ + private LinkedNode getRoot() { + return this.root; + } + + /** + * Sets root node + * + * @param root New Rootnode + */ + private void setRoot(LinkedNode root) { + this.root = root; + } + + /** + * @return Retrurns a BinaryTreeSearch Object + */ + @Override + public BinaryTreeSearch binaryTreeSearch() { + // Create anonymous class implementing BinaryTreeSearch + return new BinaryTreeSearch() { + + /** + * Current Node is initialized with root + */ + private LinkedNode currentNode = root; + + /** + * Return Data of current Node + */ + @Override + public A getData() { + + //check if element is ok. + if( currentNode == null || + currentNode.getData() == null) { + throw new NoSuchElementException(); + } + + //return data + return currentNode.getData(); + } + + /** + * Is CurrentNode a Leaf + */ + @Override + public boolean isLeaf() { + + //check if element is ok. + if( currentNode == null || + currentNode.getData() == null) { + throw new NoSuchElementException(); + } + + //check if there is left and right data, if not its a leaf + if( currentNode.getLeftChild() == null && + currentNode.getRightChild() == null) + { + return true; + } + + //not a leaf + return false; + } + + /** + * Moves CurrentNode Pointer to Left Child + */ + @Override + public void nextLeftChild() { + + //check if element is ok. + if( currentNode == null || + currentNode.getLeftChild() == null) { + throw new NoSuchElementException(); + } + + //set current node to left child + currentNode = currentNode.getLeftChild(); + } + + /** + * Moves CurrentNode Pointer to Right Child + */ + @Override + public void nextRightChild() { + + //check if element is ok. + if( currentNode == null || + currentNode.getRightChild() == null) { + throw new NoSuchElementException(); + } + + //sets current node to right child + currentNode = currentNode.getRightChild(); + } + + /** + * Sets current Node + * + * @param data Nodedata + * @param leftData Left Child data + * @param rightData Right child data + */ + @Override + public void setNode(A data, A leftData, A rightData) { + + //check datainput + if(data == null){ + throw new UnsupportedOperationException(); + } + + //subnodes + LinkedNode left = new LinkedNode(leftData); + LinkedNode right = new LinkedNode(rightData); + + //is root null? if yes create new node + if(currentNode == null) + { + root = new LinkedNode(data,left,right); + currentNode = root; + } else + { + //set currentNode to new data + currentNode.setData(data); + currentNode.setLeftChild(left); + currentNode.setRightChild(right); + } + } + + /** + * @return Returns true if there is a left Child + */ + @Override + public boolean hasLeftChild() { + //check if element is ok. + if( currentNode != null && + currentNode.getLeftChild() != null) { + return true; + } + + //no left child + return false; + } + + /** + * @return Returns true if there is a Right Child + */ + @Override + public boolean hasRightChild() { + //check if element is ok. + if( currentNode != null && + currentNode.getRightChild() != null) { + return true; + } + + //no right child + return false; + } + }; + } + +} diff --git a/ss2010/gdi2/java/Project3/src/Quiz.java b/ss2010/gdi2/java/Project3/src/Quiz.java new file mode 100644 index 00000000..6521881a --- /dev/null +++ b/ss2010/gdi2/java/Project3/src/Quiz.java @@ -0,0 +1,215 @@ +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + +/** + * A simple guessing game, where the user thinks of an animal, and the computer + * tries to guess it by asking a series of Yes/No questions. If it fails to guess + * it, the user provides new information for the computer to learn. An example round: + * Q: Computer, A: User + * + * Q: "Please think of an animal. I will try to find out what it is by asking you some yes/no questions." + * Q: "Is it a mammal? (Y/N)" + * A: "Y" + * Q: "Is it bigger than a tiger? (Y/N)" + * A: "Y" + * Q: "You were thinking of an elephant. Am I right? (Y/N)" + * A: "N" + * Q: "You win. What is the answer?" + * A: "whale" + * Q: "Please provide a yes/no question that distinguishes a whale from a elephant." + * A: "Does it live in the sea?" + * Q: "Does a whale live in the sea? (Y/N)" + * A: "Y" + * + * The next time the user thinks of a whale, the computer will guess it correctly: + * + * Q: "Please think of an animal. I will try to find out what it is by asking you some yes/no questions." + * Q: "Is it a mammal? (Y/N)" + * A: "Y" + * Q: "Is it bigger than a tiger? (Y/N)" + * A: "Y" + * Q: "Does it live in the sea? (Y/N)" + * A: "Y" + * Q: "You were thinking of a whale. Am I right? (Y/N)" + * A: "Y" + * Q: "I knew it!" + * + */ +public class Quiz { + + /** + * The main method for interactive playing. Initializes a tree and starts game rounds + * until the user wants to quit. Finally saves learned data if the user agrees. + * + * @param args Command line arguments not used. + */ + public static void main(String[] args) + { + // Text file containing a pre-order of old questions/animals + String filename = "quizdb.txt"; + + // Attempt to load the file. If it does not exist, initializes a default tree. + BinaryTree tree = load(filename); + + // Provides user-interactive I/O + QuizIoAdapter ioAdapter = new UserIoAdapter(); + + // Initiializes a quiz object + Quiz quiz = new Quiz(tree, ioAdapter); + + // Run the quiz until the user answers "N" to "Play again?" + do { + quiz.run(); + } while (ioAdapter.askYesNo("Play again?")); + + // Should we save the tree? + if (ioAdapter.askYesNo("Save any data I learned?")){ + save(filename, tree); + } + + ioAdapter.tell("Goodbye."); + } + + /** + * Load the pre-order of an old tree from a text database. + * + * @param filename The name of the text database. + * @return A binary tree corresponding to the pre-order in the file or a + * default tree if reading the file failed. + */ + public static BinaryTree load(String filename) { + + List preorder; + + try { + BufferedReader reader = new BufferedReader(new FileReader(filename)); + preorder = new LinkedList(); + while (reader.ready()) { + preorder.add(reader.readLine()); + } + reader.close(); + + } catch (IOException e) { + System.out.println(e.getClass().getSimpleName() + ": " + e.getMessage()); + System.out.println("Could not read input file " + filename + ", using default tree!"); + + // Default preorder + preorder = Arrays.asList("Is it a mammal?", "Is it bigger than a tiger?", "elephant", + "mouse", "Does it live underwater?", "trout", "robin"); + } + + // Invoke a methods to construct pre-order conversion for one of the two tree types + //return SequentialBinaryTree.createFromPreorder(preorder); + return LinkedBinaryTree.createFromPreorder(preorder); + } + + /** + * Saves the pre-order of a tree to a text database. + * + * @param filename The name of the text database. + * @param tree The tree to save. + */ + @SuppressWarnings("CallToThreadDumpStack") + public static void save(String filename, BinaryTree tree) { + + List strings = tree.preorder(); + + try { + BufferedWriter writer = new BufferedWriter(new FileWriter(filename)); + + for (String line : strings) { + writer.write(line); + writer.newLine(); + } + writer.close(); + + } catch (IOException e) { + e.printStackTrace(); + System.out.println("Could not write output file " + filename + "!"); + } + } + + // I/O can be either interactive (UserIoAdapter if run by main) or automatic (UnitTestIoAdapter if run by unit tests) + private QuizIoAdapter ioAdapter; + + // The binary tree containing questions and animals + private BinaryTree tree; + + /** + * Initialize a new quiz. + * + * @param tree A binary tree of strings containing questions and animals. + * @param ioAdapter The I/O adapter for this quiz. + */ + public Quiz(BinaryTree tree, QuizIoAdapter ioAdapter) { + this.ioAdapter = ioAdapter; + this.tree = tree; + } + + /** + * The main method running the quiz + */ + public void run() + { + //Introduction + ioAdapter.tell("Please think of an animal. I will try to find out what it is by asking you some yes/no questions."); + + //the treesearch + BinaryTreeSearch current = tree.binaryTreeSearch(); + + //Ask Question till leaf + while (!current.isLeaf()){ + if(ioAdapter.askYesNo(current.getData())){ + current.nextLeftChild(); + } else { + current.nextRightChild(); + } + } + + //Is it right answer? + if (!ioAdapter.askYesNo("You were thinking of a " + current.getData() + ". Am I right?")) + { + //Ask for Animal & new question + boolean b = true; + String newanimal = ioAdapter.askString("You win. What is the answer?"); + String newquestion = ""; + String modnewquestion = ""; + + //Ask for Question to distinguish newanimal from old. + while(b) + { + newquestion = ioAdapter.askString("Please provide a yes/no question that distinguishes a " + newanimal + " from a " + current.getData() + "."); + modnewquestion = newquestion.replace(" it ", " a " + newanimal + " "); + + //Question needs to contain '?' and ' it ' + if(modnewquestion.equals(newquestion) || !newquestion.contains("?")) + { + ioAdapter.tell("I could not understand your question. Please make sure it contains an ' it ' and a questionmark '?' !"); + } else + { + b = false; + } + } + + //Ask new question and set Node + if(ioAdapter.askYesNo(modnewquestion)) { + current.setNode(newquestion, newanimal, current.getData()); + } else { + current.setNode(newquestion, current.getData(), newanimal); + } + } else + { + //Guessed right + ioAdapter.tell("I won!"); + return; + } + + } + +} diff --git a/ss2010/gdi2/java/Project3/src/QuizIoAdapter.java b/ss2010/gdi2/java/Project3/src/QuizIoAdapter.java new file mode 100644 index 00000000..59b3b7a6 --- /dev/null +++ b/ss2010/gdi2/java/Project3/src/QuizIoAdapter.java @@ -0,0 +1,28 @@ +/** + * Interface for providing IO to the quiz game. + */ +public interface QuizIoAdapter { + + /** + * Ask the user or test system a yes/no question. + * + * @param question The question to ask. + * @return True if the answer was "Y", false if it was "N". + */ + public boolean askYesNo(String question); + + /** + * Ask the user a general question. + * + * @param question The question to ask. + * @return The answer given to the question. + */ + public String askString(String question); + + /** + * Output a message. + * + * @param message The message to output. + */ + public void tell(String message); +} diff --git a/ss2010/gdi2/java/Project3/src/SequentialBinaryTree.java b/ss2010/gdi2/java/Project3/src/SequentialBinaryTree.java new file mode 100644 index 00000000..a2125dbc --- /dev/null +++ b/ss2010/gdi2/java/Project3/src/SequentialBinaryTree.java @@ -0,0 +1,306 @@ +import java.io.Serializable; +import java.util.*; + +/** + * A binary tree in sequential representation. It is maintained as an array such that + * the left child of the node with index i is located at index 2i and the right child + * is located at index 2i + 1 (see lecture slide set 7). The root is at index 1. + * + * @param The type of the data held in nodes of the tree. + */ +public class SequentialBinaryTree implements BinaryTree { + + /** + * Vector with data. + * Position zero is also used, but index is starting with 1 not with 0 + */ + @SuppressWarnings("UseOfObsoleteCollectionType") + private Vector nodes = new Vector(); + + /** + * Definition of a Questionmark + */ + public static final String QUESTIONMARK = "?"; + + /** + * Check if position is a Node + * + * @param pos Position starting with 1. + * @return true if its a node + */ + private boolean isANode(int pos) { + if( pos > 0 && + nodes.size() >= pos && + nodes.get(pos-1) != null ){ + return true; + } + + return false; + } + + /** + * Sets a Node + * + * @param pos Position starting with 1 + * @param data Data + * @return true if successfull + */ + private boolean setANode(int pos, A data) { + if(pos <= 0){ + return false; + } + + if(nodes.size() < pos) { + nodes.setSize(pos); + } + + nodes.set(pos-1,data); + return true; + } + + /** + * Get A Node + * + * @param pos Position starting with 1 + * @return Data or null if not existant + */ + private A getANode(int pos) { + if( pos <= 0 || + nodes.size() < pos){ + return null; + } + + return nodes.get(pos-1); + } + + /** + * Insert a Node + * + * @param pos Position + * @param data Data + * @return true if successfull + */ + private boolean insertANode(int pos, A data) { + if(!isANode(pos)) { + return setANode(pos,data); + } + + return false; + } + + /** + * Clones a Serializable Data object + * @param src + * @return cloned dataobject + */ + public static Serializable cloneSerializable(Serializable src) + { + try { + java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream(); + java.io.ObjectOutputStream oos = new java.io.ObjectOutputStream(baos); + oos.writeObject(src); + oos.flush(); + oos.close(); + java.io.ByteArrayInputStream bais = new + java.io.ByteArrayInputStream(baos.toByteArray()); + java.io.ObjectInputStream ois = new java.io.ObjectInputStream(bais); + Object dest = ois.readObject(); + ois.close(); + return (Serializable)dest; + } catch (Throwable th) { + return src; + } + } + + /** + * Create a tree from a given animal game preorder. + * + * param The type of the data held in nodes of the tree. + * @param preorder The preorder to build the tree from. + * @return A new SequentialBinaryTree corresponding to the provided preorder. + */ + public static SequentialBinaryTree createFromPreorder(List preorder) { + + List preordercopy = new ArrayList(); + + for(int i=0;i result = new SequentialBinaryTree(); + + result.recursiv_createFromPreorder(preordercopy,1); + + return result; + } + + /** + * Create tree from Preorder recursiv nonstatic and with A-Parameter + * + * A must implement contains-function + * + * @param preorder + * @param index Current index in Array + */ + public void recursiv_createFromPreorder(List preorder, int index) + { + //still data to process? + if( preorder.size() < 1){ + return; + } + + //data + A s = preorder.get(0); + + //insert node + insertANode(index, s); + + //remove added element + preorder.remove(0); + + //is a question? + if(s.toString().contains(QUESTIONMARK)){ + recursiv_createFromPreorder(preorder,2*index); + recursiv_createFromPreorder(preorder,2*index+1); + } + } + + /** + * Create a pre-order traversal sequence for this tree. + * + * @return The pre-order sequence for this tree. + */ + @Override + public List preorder() { + return recursiv_preorder(1); //root + } + + /** + * Creates preorder from Tree, recursiv! + * + * @param index Current Position in Array + * @return preorderlist + */ + private List recursiv_preorder(int index){ + + //result list + List result = new ArrayList(); + + //check input data + if( index > 0 && + index <= nodes.size()&& + isANode(index)) + { + //add data + result.add(getANode(index)); + result.addAll(recursiv_preorder(2*index)); + result.addAll(recursiv_preorder(2*index+1)); + } + + //return list + return result; + } + + /** + * @return Retrurns a BinaryTreeSearch Object + */ + @Override + public BinaryTreeSearch binaryTreeSearch() { + // Create anonymous class implementing BinaryTreeSearch + return new BinaryTreeSearch() { + + /** + * Current Index + */ + private int index = 1; //root + + /** + * Return Data of current Node + */ + @Override + public A getData() { + if(!isANode(index)) { + throw new NoSuchElementException(); + } + + return getANode(index); + } + + /** + * Is Current Node a Leaf + */ + @Override + public boolean isLeaf() { + + if( isANode(index) && + !isANode(2*index) && + !isANode(2*index+1)){ + return true; + } + + return false; + } + + /** + * Move index-pointer to left child of current node + */ + @Override + public void nextLeftChild() { + if( isANode(index) && + isANode(2*index)) { + index *= 2; + return; + } + + throw new NoSuchElementException(); + } + + /** + * Move index-pointer to right child of current node + */ + @Override + public void nextRightChild() { + if( isANode(index)&& + isANode(2*index +1)){ + index = 2*index +1; + return; + } + + throw new NoSuchElementException(); + } + + /** + * Set current Node + * + * @param data Data of node + * @param leftData Data of left Subnode + * @param rightData Data of right Subnode + */ + @Override + public void setNode(A data, A leftData, A rightData) { + + setANode(index,data); + setANode(2*index,leftData); + setANode(2*index+1,rightData); + } + + /** + * Does current Node has a left child? + */ + @Override + public boolean hasLeftChild() { + return isANode(2*index); + } + + /** + * Does current Node has a right child? + */ + @Override + public boolean hasRightChild() { + return isANode(2*index+1); + } + }; + } + +} diff --git a/ss2010/gdi2/java/Project3/src/UserIoAdapter.java b/ss2010/gdi2/java/Project3/src/UserIoAdapter.java new file mode 100644 index 00000000..cd81e879 --- /dev/null +++ b/ss2010/gdi2/java/Project3/src/UserIoAdapter.java @@ -0,0 +1,44 @@ +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; + +/** + * Interactive I/O for the quiz. + */ +public class UserIoAdapter implements QuizIoAdapter { + + private BufferedReader inputReader; + + public UserIoAdapter() { + inputReader = new BufferedReader(new InputStreamReader(System.in)); + } + + @Override + public String askString(String question) { + tell(question); + try { + return inputReader.readLine(); + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } + + @Override + public boolean askYesNo(String question) { + String answer = askString(question + " (Y/N)").toUpperCase(); + + while (!answer.startsWith("Y") && !answer.startsWith("N")) + { + answer = askString("Please answer Y or N: ").toUpperCase( ); + } + + return answer.startsWith("Y"); + } + + @Override + public void tell(String message) { + System.out.println(message); + } + +} diff --git a/ss2010/gdi2/java/Project3/tests/QuizTest.java b/ss2010/gdi2/java/Project3/tests/QuizTest.java new file mode 100644 index 00000000..24fd9281 --- /dev/null +++ b/ss2010/gdi2/java/Project3/tests/QuizTest.java @@ -0,0 +1,207 @@ +import static org.junit.Assert.*; + +import java.util.Arrays; +import java.util.List; +import java.util.NoSuchElementException; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + + +public class QuizTest { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + private BinaryTree constructFromPreorder(boolean linkedTree, List preorder) { + if (linkedTree) + return LinkedBinaryTree.createFromPreorder(preorder); + else + return SequentialBinaryTree.createFromPreorder(preorder); + } + + @Test + public void linkedTreeTestCreateFromPreorderAndBinarySearch() { + testCreateFromPreorderAndBinarySearch(true); + } + + @Test + public void linkedTreeTestBinarySearchAndConstructPreorder() { + testBinarySearchAndConstructPreorder(true); + } + + @Test + public void linkedTreeCreateFromAndBuildPreorder() { + testCreateFromAndBuildPreorder(true); + } + + @Test + public void linkedTreeBinaryTreeSearch() { + testBinaryTreeSearch(true); + } + + + @Test + public void sequentialTreeTestCreateFromPreorderAndBinarySearch() { + testCreateFromPreorderAndBinarySearch(false); + } + + @Test + public void sequentialTreeTestBinarySearchAndConstructPreorder() { + testBinarySearchAndConstructPreorder(false); + } + + @Test + public void sequentialTreeCreateFromAndBuildPreorder() { + testCreateFromAndBuildPreorder(false); + } + + @Test + public void sequentialTreeBinaryTreeSearch() { + testBinaryTreeSearch(false); + } + + public void testCreateFromPreorderAndBinarySearch(boolean linkedTree) { + List preorder = Arrays.asList("Is it a mammal?", "Is it bigger than a tiger?", "Elephant", + "Mouse", "Does it live underwater?", "Trout", "Robin"); + + BinaryTree tree = constructFromPreorder(linkedTree, preorder); + + BinaryTreeSearch search = tree.binaryTreeSearch(); + assertEquals("Is it a mammal?", search.getData()); + search.nextRightChild(); + assertEquals("Does it live underwater?", search.getData()); + search.nextRightChild(); + assertEquals("Robin", search.getData()); + } + + public void testBinarySearchAndConstructPreorder(boolean linkedTree) { + BinaryTree tree = linkedTree ? new LinkedBinaryTree() : new SequentialBinaryTree(); + + BinaryTreeSearch search = tree.binaryTreeSearch(); + search.setNode("Is it a mammal?", "d1", "d2"); + search.nextLeftChild(); + search.setNode("Is it bigger than a tiger?", "Elephant", "Mouse"); + search = tree.binaryTreeSearch(); + search.nextRightChild(); + search.setNode("Does it live underwater?", "Trout", "Robin"); + + List preorder = Arrays.asList("Is it a mammal?", "Is it bigger than a tiger?", "Elephant", + "Mouse", "Does it live underwater?", "Trout", "Robin"); + assertEquals(preorder, tree.preorder()); + } + + public void testCreateFromAndBuildPreorder(boolean linkedTree) { + List preorder = Arrays.asList("Is it a mammal?", "Is it bigger than a tiger?", "Elephant", + "Mouse", "Does it live underwater?", "Trout", "Robin"); + BinaryTree tree = constructFromPreorder(linkedTree, preorder); + assertEquals(preorder, tree.preorder()); + } + + public void testBinaryTreeSearch(boolean linkedTree) { + BinaryTree tree = linkedTree ? new LinkedBinaryTree() : new SequentialBinaryTree(); + BinaryTreeSearch search = tree.binaryTreeSearch(); + search.setNode(2, 5, 15); + search.nextLeftChild(); + search.setNode(5, -5, -8); + search = tree.binaryTreeSearch(); + search.nextRightChild(); + search.setNode(15, 2, -5); + search.nextLeftChild(); + search.setNode(2, -20, -10); + + search = tree.binaryTreeSearch(); + assertEquals(2, search.getData().intValue()); + search.nextLeftChild(); + assertEquals(5, search.getData().intValue()); + search.nextRightChild(); + assertEquals(-8, search.getData().intValue()); + + search = tree.binaryTreeSearch(); + search.nextLeftChild(); + search.nextRightChild(); + try { + search.nextLeftChild(); + assertTrue("Expected NoSuchElementException!", false); + } catch (NoSuchElementException e) { + } + } + + + @Test + public void quizTestLinkedRunSuccess() { + testRunSuccess(true); + } + + @Test + public void quizTestSequentialRunSuccess() { + testRunSuccess(false); + } + + @Test + public void quizTestLinkedRunLearn() { + testRunLearn(true); + } + + @Test + public void quizTestSequentialRunLearn() { + testRunLearn(false); + } + + public void testRunSuccess(boolean linkedTree) { + List preorder = Arrays.asList("Is it a mammal?", "Is it bigger than a tiger?", "elephant", + "mouse", "Does it live underwater?", "trout", "robin"); + + UnitTestIoAdapter ioAdapter = new UnitTestIoAdapter(); + + Quiz quiz = new Quiz(constructFromPreorder(linkedTree, preorder), ioAdapter); + + ioAdapter.queueYesNoQuestion("a mammal"); + ioAdapter.queueAnswer(true); + ioAdapter.queueYesNoQuestion("bigger than a tiger"); + ioAdapter.queueAnswer(true); + ioAdapter.queueYesNoQuestion("elephant"); + ioAdapter.queueAnswer(true); + quiz.run(); + } + + public void testRunLearn(boolean linkedTree) { + List preorder = Arrays.asList("Is it a mammal?", "Is it bigger than a tiger?", "elephant", + "mouse", "Does it live underwater?", "trout", "robin"); + + UnitTestIoAdapter ioAdapter = new UnitTestIoAdapter(); + + Quiz quiz = new Quiz(constructFromPreorder(linkedTree, preorder), ioAdapter); + + ioAdapter.queueYesNoQuestion("a mammal"); + ioAdapter.queueAnswer(true); + ioAdapter.queueYesNoQuestion("bigger than a tiger"); + ioAdapter.queueAnswer(true); + ioAdapter.queueYesNoQuestion("elephant"); + ioAdapter.queueAnswer(false); + ioAdapter.queueAnswer("whale"); + ioAdapter.queueAnswer("Does it live underwater?"); + ioAdapter.queueYesNoQuestion("?"); + ioAdapter.queueAnswer(true); + + quiz.run(); + + // Next round + ioAdapter.queueYesNoQuestion("a mammal"); + ioAdapter.queueAnswer(true); + ioAdapter.queueYesNoQuestion("bigger than a tiger"); + ioAdapter.queueAnswer(true); + ioAdapter.queueYesNoQuestion("underwater"); + ioAdapter.queueAnswer(true); + ioAdapter.queueYesNoQuestion("whale"); + ioAdapter.queueAnswer(true); + + quiz.run(); + } +} diff --git a/ss2010/gdi2/java/Project3/tests/UnitTestIoAdapter.java b/ss2010/gdi2/java/Project3/tests/UnitTestIoAdapter.java new file mode 100644 index 00000000..9c2e679f --- /dev/null +++ b/ss2010/gdi2/java/Project3/tests/UnitTestIoAdapter.java @@ -0,0 +1,53 @@ +import static org.junit.Assert.*; +import java.util.Deque; +import java.util.LinkedList; + +/** + * Pseudo I/O for the unit-testing the quiz. + */ +public class UnitTestIoAdapter implements QuizIoAdapter { + + private Deque answerStrings; + private Deque answerBools; + private Deque questions; + + public UnitTestIoAdapter() { + answerStrings = new LinkedList(); + answerBools = new LinkedList(); + questions = new LinkedList(); + } + + public void queueAnswer(String answer) { + answerStrings.add(answer); + } + + public void queueAnswer(boolean answer) { + answerBools.add(answer); + } + + public void queueYesNoQuestion(String question) { + questions.add(question); + } + + @Override + public String askString(String question) { + System.out.println(question); + System.out.println(answerStrings.getFirst()); + return answerStrings.removeFirst(); + } + + @Override + public boolean askYesNo(String question) { + System.out.println(question); + assertTrue(question + " should contain " + questions.getFirst(), + question.contains(questions.removeFirst())); + System.out.println(answerBools.getFirst() ? "Y" : "N"); + return answerBools.removeFirst(); + } + + @Override + public void tell(String message) { + System.out.println(message); + } + +}