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 </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 </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 </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;
}
}