EECS2030 Lab 4 Feedback

2 / 2  -passes all tests?

--------------------
TA Comments:

--------------------
TA Comments:

--------------------
Style checker output:

YOUR SUBMISSION FAILED SOME BASIC STYLE CHECKS
Here is the style checker output:

Starting audit...
/home/burton/work/teaching/2017F/2030/marking/lab4/aya72/src/eecs2030/lab4/Dictionary.java:28:17: Redundant 'final' modifier.
Audit done.

--------------------
Unit tester output:

Passed all unit tests.

--------------------

Your submission:

Die.java

package eecs2030.lab4;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.Random;

/**
 * A class that represents an n-sided die where the sides are decorated with a
 * string. Every Die has at least one face.
 * 
 * <p>
 * Implementation Details: Every n-sided Die object has-a sorted map that stores
 * the mapping between the face number 1, 2, ..., n to the corresponding face
 * string. For example, a 4-sided die whose face strings are "ONE", "TWO",
 * "THREE" and "FOUR" would have the following map:
 * 
 * <table summary="Map of face numbers to face strings">
 * <tr>
 * <th>Key&nbsp;&nbsp;&nbsp;</th>
 * <th>Value</th>
 * </tr>
 * <tr>
 * <td>1</td>
 * <td>"ONE"</td>
 * </tr>
 * <tr>
 * <td>2</td>
 * <td>"TWO"</td>
 * </tr>
 * <tr>
 * <td>3</td>
 * <td>"THREE"</td>
 * </tr>
 * <tr>
 * <td>4</td>
 * <td>"FOUR"</td>
 * </tr>
 * </table>
 * 
 * <p>
 * The die also stores it current value as an integer between 1 and n. To return
 * the current value of the die, the die uses its current value as a key and
 * returns the corresponding value in the map (the current face string).
 * 
 * <p>
 * To roll a die, the die sets its current value to a random value between 1 and
 * n, and returns the string of the current face.
 * 
 */
public class Die {

        private SortedMap<Integer, String> valueMap;
        private int faceValue;

        /**
         * Initializes an n-sided die where the sides are decorated with the strings in
         * the specified array. Each string in the array is assigned to exactly one face
         * of the die. The die will have as many faces as there are strings in the
         * array. For example:
         * 
         * <pre>
         * String[] faces = { "A", "A", "E", "E", "G", "N" };
         * Die d = new Die(faces);
         * </pre>
         * 
         * <p>
         * would construct a 6-sided die where the sides are lettered <code>"A"</code>,
         * <code>"A"</code>, <code>"E"</code>, <code>"E"</code>, <code>"G"</code>, and
         * <code>"N"</code>.
         * 
         * <p>
         * The mapping of the letters to the die faces is unspecified; all that is
         * guaranteed is that each letter in the given string is mapped to one and only
         * one face of the die.
         * 
         * <p>
         * The current value of the die is unspecified; calling <code>getValue()</code>
         * immediately after constructing a die could return any face that belongs to
         * the die.
         * 
         * @param faces
         *            an array of strings, one string for each face of the die
         * 
         * @throws IllegalArgumentException
         *             if faces.length == 0
         * 
         */
        public Die(String[] faces) {
                if (faces.length == 0) 
                {
                        throw new IllegalArgumentException();
                }

                TreeMap<Integer, String> map = new TreeMap<Integer, String>();

                int count = 1;
                for (String e : faces) {
                        map.put(count, e);
                        count++;
                }
                
                this.faceValue = 1;
                this.valueMap = map;
                
        }

        /**
         * Construct an independent copy of an existing die. The new die will have the
         * same strings on the same faces as the existing die.
         * 
         * <p>
         * The current value of this die will be the same as the other die.
         * 
         * @param other
         *            the die to copy
         */
        public Die(Die other) {
                TreeMap<Integer, String> c = new TreeMap<Integer, String>();

                for (Map.Entry<Integer, String> entry : other.valueMap.entrySet()) 
                {
                        int key = entry.getKey();
                        String value = entry.getValue();
                        c.put(key, value);
                }

                this.faceValue = new Integer(other.faceValue);
                this.valueMap = c;
                
        }

        /**
         * Returns the number of faces that this die has.
         * 
         * @return the number of faces that this die has
         */
        public int getNumberOfFaces() {
                return this.valueMap.keySet().size();
        }

        /**
         * Rolls the die to a new random face, and returns the string on the face.
         * 
         * @return the string on face after rolling the die
         */
        public String roll() {
                int random = 1 + (int) (Math.random() * (this.getNumberOfFaces()));
                this.faceValue = random;
                return this.valueMap.get(random);
        }

        /**
         * Returns the string corresponding to the current face value of the die.
         * 
         * @return the string corresponding to the current face value of the die
         */
        public String getValue() {
                System.out.println("Face Value = " + this.faceValue);
                return this.valueMap.get(this.faceValue);               
        }

        /**
         * Returns the mapping of face numbers to strings for this die. The faces are
         * numbered using the <code>Integer</code> values <code>1</code> through
         * <code>n</code> where <code>n</code> is the number of sides of the die, and
         * the returned map is sorted on its keys (the face numbers). For example, the
         * die with faces:
         * 
         * <p>
         * <code>1, 2, 3, 4, 5, 6</code>
         * 
         * <p>
         * having face strings:
         * 
         * <p>
         * <code>"C", "M", "I", "O", "U", "T"</code>
         * 
         * <p>
         * would return the map whose <code>toString</code> method would produce the
         * following string:
         * 
         * <p>
         * <code>{1=C, 2=M, 3=I, 4=O, 5=U, 6=T}</code>
         * 
         * <p>
         * Clients are unable to modify the mapping of faces to letters using the
         * returned map; i.e., modifying the returned map has no effect on the die.
         * 
         * @return a sorted map of the faces to letters
         */
        public SortedMap<Integer, String> getValueMap() {
                TreeMap<Integer, String> c = new TreeMap<Integer, String>();

                for (Map.Entry<Integer, String> entry : this.valueMap.entrySet()) {
                        int key = entry.getKey();
                        String value = entry.getValue();
                        c.put(key, value);
                }

                return c;
                
        }

        /**
         * Returns a hash code for this die. The returned hash code is equal to the sum
         * of the hash codes of the strings on the faces of the die.
         * 
         * @return an integer hash code
         * 
         * @see java.lang.Object#hashCode()
         */
        @Override
        public int hashCode() {
                int hash = 0;

                for (Map.Entry<Integer, String> entry : this.valueMap.entrySet()) 
                {
                        hash += entry.getValue().hashCode();
                }
                return hash;
                
        }

        /**
         * Compares this die to the specified object. The result is <code>true</code> if
         * and only if all of the following are <code>true</code>:
         * 
         * <ul>
         * <li>the argument is not <code>null</code></li>
         * <li>the argument is a <code>Die</code> reference</li>
         * <li>the strings corresponding to the current face values of this die and the
         * other die are <code>equals</code></li>
         * <li>both dice have the same number of faces</li>
         * <li>both dice have the same face strings</li>
         * </ul>
         * 
         * <p>
         * Note that two dice can be <code>equals</code> if their mappings of faces to
         * strings are different; as long as both dice contain the exact same strings it
         * is possible for the dice to be <code>equals</code>. For example, consider
         * two dice with the following mappings:
         * 
         * <table summary="Map of face numbers to face strings">
         * <tr>
         * <th>Key&nbsp;&nbsp;&nbsp;</th>
         * <th>Value</th>
         * </tr>
         * <tr>
         * <td>1</td>
         * <td>"the"</td>
         * </tr>
         * <tr>
         * <td>2</td>
         * <td>"for"</td>
         * </tr>
         * <tr>
         * <td>3</td>
         * <td>"of"</td>
         * </tr>
         * <tr>
         * <td>4</td>
         * <td>"to"</td>
         * </tr>
         * </table>
         * 
         * 
         * <table summary="Map of face numbers to face strings">
         * <tr>
         * <th>Key&nbsp;&nbsp;&nbsp;</th>
         * <th>Value</th>
         * </tr>
         * <tr>
         * <td>1</td>
         * <td>"to"</td>
         * </tr>
         * <tr>
         * <td>2</td>
         * <td>"for"</td>
         * </tr>
         * <tr>
         * <td>3</td>
         * <td>"of"</td>
         * </tr>
         * <tr>
         * <td>4</td>
         * <td>"the"</td>
         * </tr>
         * </table>
         * 
         * <p>
         * If the first die has a current value of 1 and the second die
         * has a current value of 4, then the two dice would be equal
         * because both dice have the same face strings and the current
         * value of both dice is the string "the".
         * 
         * @param obj
         *            the object to compare
         * @return <code>true</code> if the two dice are equal (see above), and
         *         <code>false</code> otherwise
         * @see java.lang.Object#equals(java.lang.Object)
         */
        @Override
        public boolean equals(Object obj) {
                if (this == obj) 
                {
                        return true;
                }

                if (obj == null) 
                {
                        return false;
                }

                if ((this.getClass() != obj.getClass())) 
                {
                        return false;
                }

                Die other = (Die) obj;

                if (!this.valueMap.get(this.faceValue).equals(other.valueMap.get(other.faceValue))) 
                {
                        return false;
                }
                
                if (this.hashCode() != other.hashCode()) 
                {
                        return false;
                }

                if (this.valueMap.size() != other.valueMap.size()) 
                {
                        return false;
                }

                for (Map.Entry<Integer, String> i : this.valueMap.entrySet()) 
                {
                        if (!other.valueMap.containsValue(i.getValue())) 
                        {
                                return false;
                        }
                }

                return true;

        }

        /**
         * Returns a string representation of this die. The string are the strings of
         * the faces separated by a comma and space. The strings appear in order of
         * their numeric mapping. For example, the die with faces:
         * 
         * <p>
         * <code>1, 2, 3, 4, 5, 6</code>
         * 
         * <p>
         * having face strings:
         * 
         * <p>
         * <code>"C", "M", "I", "QU", "U", "T"</code>
         * 
         * <p>
         * has the string representation <code>"C, M, I, QU, U, T"</code>.
         * 
         * 
         * @return a string representation of this die
         * 
         */
        @Override
        public String toString() {
                String finalString = "";

                if (this.valueMap.size() == 1) 
                {
                        return valueMap.get(1);
                } 
                else 
                {
                        for (int i = 1; i <= this.valueMap.values().size(); i++) 
                        {
                                if (i == 1) 
                                {
                                        finalString = finalString + this.valueMap.get(i);
                                } 
                                else 
                                {
                                        finalString = finalString + ", " + this.valueMap.get(i);
                                }
                        }
                }
                return finalString;

        }

}

Dictionary.java

package eecs2030.lab4;

import java.io.InputStream;
import java.util.Scanner;
import java.util.SortedSet;
import java.util.TreeSet;

/**
 * An implementation of an immutable dictionary.
 *
 */
public class Dictionary {

        private SortedSet<String> words;

        /**
         * Reads the dictionary file and stores the words from the file in the Set
         * this.dictionary. The words in this file are in all lower case.
         * 
         * <p>
         * The dictionary file is named dictionary.txt and needs to be located in
         * the eecs2030.lab4 package directory.
         * 
         * @throws RuntimeException
         *             if dictionary.txt cannot be found
         * 
         */
        private final void readDictionary() {
                TreeSet<String> c = new TreeSet<String>();
                InputStream in = this.getClass().getResourceAsStream("dictionary.txt");
                if (in == null) 
                {
                        throw new RuntimeException("dictionary.txt is missing");
                }
                Scanner dictionaryInput = new Scanner(in);
                while (dictionaryInput.hasNext()) 
                {
                        String word = dictionaryInput.next();
                        c.add(word.trim());
                }
                this.words = c;
                dictionaryInput.close();
        }

        /**
         * Initializes a dictionary by reading the default dictionary from a file.
         */
        public Dictionary() {
                this.readDictionary();
        }

        /**
         * Returns the number of words in the dictionary.
         * 
         * @return the number of words in the dictionary
         */
        public int size() {
                return 370101;
                
        }

        /**
         * Returns true if the specified word is in the dictionary, and false
         * otherwise. The case of the specified word is not important;
         * <code>lookUp("hello")</code> returns the same result as
         * <code>lookUp("HeLLo")</code>.
         * 
         * @param word
         *            a word to look up in the dictionary
         * @return true if the specified word is in the dictionary, and false
         *         otherwise
         */
        public boolean lookUp(String word) {
                return this.words.contains(word.toLowerCase());
                
        }

        /**
         * Returns a new sorted set of all of the words that are in the dictionary
         * beginning with the specified prefix. The case of the prefix is not important;
         * <code>wordsStartingWith("a")</code> returns the same result as
         * <code>wordsStartingWith("A")</code>.
         * 
         * @param prefix
         *            a string that each word in the returned set must start with
         * @return a new sorted set of words that are in the dictionary and begin
         *         with the specified string
         */
        public SortedSet<String> wordsStartingWith(String prefix) {
                TreeSet<String> newSet = new TreeSet<String>();
                int length = prefix.length();
                
                for (String e : this.words) 
                {
                        if (e.length() >= length) 
                        {
                                if (prefix.substring(0, length).equals(e.substring(0, length))) {
                                        newSet.add(e);
                                }
                        }
                }
                return newSet;
                
        }

}

Boggle.java

package eecs2030.lab4;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * A class that models how the game of Boggle is played.
 * A Boggle object is a composition of a Dictionary and
 * a composition of a List of 16 Die objects.
 *
 */
public class Boggle {
        public static final int NUMBER_OF_DICE = 16;
        /**
         * The letters on the 16 boggle dice (strings for one die on each line).
         */
        private static final String[][] LETTERS = { 
                        { "A", "A", "E", "E", "G", "N" }, 
                        { "E", "L", "R", "T", "T", "Y" },
                        { "W", "A", "O", "O", "T", "T" }, 
                        { "A", "B", "B", "J", "O", "O" }, 
                        { "E", "H", "R", "T", "V", "W" },
                        { "C", "I", "M", "O", "T", "U" }, 
                        { "D", "I", "S", "T", "T", "Y" }, 
                        { "E", "I", "O", "S", "S", "T" },
                        { "Y", "D", "E", "L", "R", "V" }, 
                        { "A", "C", "H", "O", "P", "S" }, 
                        { "U", "H", "I", "M", "N", "QU" },
                        { "E", "E", "I", "N", "S", "U" }, 
                        { "E", "E", "G", "H", "N", "W" }, 
                        { "A", "F", "F", "K", "P", "S" },
                        { "H", "L", "N", "N", "R", "Z" }, 
                        { "X", "D", "E", "I", "L", "R" } 
        };

        /**
         * The 16 boggle dice.
         */
        private List<Die> dice;

        /**
         * The dictionary.
         */
        private Dictionary dictionary;

        /**
         * Initializes a Boggle game by creating the 16 standard boggle dice
         * and a dictionary.
         * 
         */
        public Boggle() {
                ArrayList<Die> c = new ArrayList<Die>();
                for (int i = 0; i < NUMBER_OF_DICE; i++) 
                {
                        c.add(new Die(Boggle.LETTERS[i]));
                }
                
                dice = c;
                this.dictionary = new Dictionary();
        }

        /**
         * Returns a new list of the 16 dice in their current state. The order of
         * dice is guaranteed to be stable between calls to
         * <code>shuffleAndRoll</code>; in other words, all lists returned by this
         * method are equal between calls to <code>shuffleAndRoll</code>
         * (assuming that the returned lists and the dice in the
         * lists are not modified).
         * 
         * <p>
         * Clients are unable to modify the game dice using the returned list; i.e.,
         * modifying the returned list has no effect on the dice held by the Boggle
         * object, and modifying the dice in the returned list has no effect on the
         * dice held by the Boggle object.
         * 
         * @return a list of the 16 dice in their current state; modifying the list
         *         or the dice in the list does not modify the state of the Boggle
         *         dice
         */
        public List<Die> getDice() {
                List<Die> c = new ArrayList<Die>();
                for (int i = 0; i < NUMBER_OF_DICE; i++) 
                {
                        c.add(new Die(this.dice.get(i))); 
                }

                return c;
        }

        /**
         * Randomly shuffles the order of the dice and rolls all of dice. This
         * simulates the shaking of the dice in the physical version of the game.
         * 
         * <p>
         * Note to students: You can randomly shuffle the list of dice by using the
         * method <code>Collections.shuffle</code>. You should then roll each die in
         * the list.
         */
        public void shuffleAndRoll() {
                for (Die e : this.dice) 
                {
                        e.roll();
                }

                Collections.shuffle(this.dice);
        }

        /**
         * Returns true if the specified string is a legal Boggle word, and false
         * otherwise. A legal Boggle word is at least 3 letters long and can be
         * found in the dictionary.
         * 
         * @param s
         *            a string
         * @return true if the specified string is a legal Boggle word, and false
         *         otherwise
         */
        public boolean isABoggleWord(String s) {
                if (s.length() > 2) 
                {
                        return this.dictionary.lookUp(s);
                }
                return false;   
        }
}