I am trying to wrap my head around Junit testing and have read examples and what not, but still finding it difficult to understand how and what to test. Below is the Class with methods that I am creating my test cases from (as well as my test case Class).
import java.util.Iterator;
/**
* The Probability class understands the likelihood that something will happen.
* <p>
* (c) Copyright Fred George 2008. All right reserved. Adapted and used for
* educational purposes with permission from Fred George.
* </p>
*
* #author Fred George
*/
public class Probability {
/** Value of receiver. */
private final double value;
/** Cannot happen. */
private static final double IMPOSSIBLE_VALUE = 0.0;
/** Will happen. */
private static final double CERTAIN_VALUE = 1.0;
/** Instance that represents outcome that will happen. */
public static final Probability CERTAIN = new Probability(CERTAIN_VALUE);
/**
* Answer a new instance of the receiver with the specified value as the
* likelihood that it occurs.
*
* #param valueAsFraction
* value between 0.0 and 1.0
* #throws
*/
public Probability(final double valueAsFraction) {
if (valueAsFraction < IMPOSSIBLE_VALUE || valueAsFraction > CERTAIN_VALUE) {
throw new IllegalArgumentException("Specified value of "
+ valueAsFraction + " is not between 0.0 and 1.0");
}
value = valueAsFraction;
}
/**
* Answer the liklihood that the receiver will occur and the specified other
* Probability will occur.
*
* #return "and" of receiver and other Probability
* #param other
* Probability being and'ed to receiver
*/
public final Probability and(final Probability other) {
return new Probability(this.value * other.value);
}
/**
* Answer the value of the receiver as a scaled double between 0.0
* (impossible) to 1.0 (certain).
* <p>
* This method is modeled after those in Double, Integer, and the rest of
* the wrapper classes.
*
* #return value of receiver as double between 0.0 and 1.0
*/
public final double doubleValue() {
return value;
}
/**
* Answer true if the receiver has the same value as the other (assuming
* other is a Probability).
*
* #return true if receiver's value equals other's value
* #param other
* Object (assumed to be Probability) to compare
*/
public final boolean equals(final Object other) {
if (!(other instanceof Probability)) {
return false;
}
return this.value == ((Probability) other).value;
}
/**
* Answers with a hashcode for the receiver.
* #return the hash
*/
public final int hashCode() {
return (new Double(this.value)).hashCode();
}
/**
* Answer true if the combined likelihoods of the specified Collection of
* Probabilities sums to certain (100%).
*
* #return true if combined likelihoods is 100%
* #param probabilities
* Collection of likelihoods to sum
*/
public static final boolean isTotalCertain(final java.util.Collection probabilities) {
double sum = 0;
for (Iterator i = probabilities.iterator(); i.hasNext();) {
sum += ((Probability) i.next()).value;
}
return sum == CERTAIN_VALUE;
}
/**
* Answer the liklihood that the receiver will not occur.
*
* #return "not" of receiver
*/
public final Probability not() {
return new Probability(CERTAIN_VALUE - value);
}
/**
* Answer the liklihood that the receiver will occur or the specified other
* Probability will occur, or both.
*
* #return "or" of receiver and other Probability
* #param other
* Probability being or'ed to receiver
*/
public final Probability or(final Probability other) {
return this.not().and(other.not()).not(); // DeMorgan's Law
}
/** Multiplier from double to percentage. */
private static final int PERCENTAGE_MULTIPLIER = 100;
/**
* Answers a String representation of the receiver suitable for debugging.
*
* #return String representation of the receiver
*/
public final String toString() {
int percentage = (int) (value * PERCENTAGE_MULTIPLIER);
return percentage + "%";
}
}
And here is what I've attempted for some of the test cases. I haven't tried them all, but am stuck on the "equals" method.
package edu.psu.ist.probability;
import edu.psu.ist.decision.Decision;
import junit.framework.TestCase;
import junit.framework.*;
public class ProbabilityTest extends TestCase {
private Probability p1;
private Probability p2;
private Probability p3;
private Decision d1;
protected void setUp() {
p1 = new Probability(.6);
p2 = new Probability(.7);
p3 = new Probability(.6);
d1 = new Decision("No decision made");
}
public void testHashCode() {
fail("Not yet implemented");
}
public void testProbability() {
assertEquals(p1.doubleValue(), .6);
try{
p1 = p3;
//get here, bad
fail("Should raise an IllegalArgumentException");
}catch (IllegalArgumentException e){
//good!
}
}
public void testAnd() {
assertEquals((p1.and(p2)).doubleValue(), .42);
}
public void testDoubleValue() {
assertEquals(p1.doubleValue(), .6);
}
public void testEqualsObject() {
assertEquals(p1, p3);
//assertEquals(p1, p2);
assertTrue(!p1.equals(p2));
assertTrue(p1.equals(p3));
/*Probability p1 = new Probability (.7);
Probability p2 = new Probability (.6);
Decision d1 = new Decision();
boolean TRUE = p1.equals(p2);
boolean FALSE = p1.equals(d1);
try {
p1.equals(p2);
p1.equals(d1);
p1.equals(null);
} catch (NullPointerException ex){
// exception should be thrown
}
// assertEquals("Return true if theses values are the same",p1.doubleValue(), p2.doubleValue());
// assertEquals("Return false if not equal", p1.doubleValue(), d1.equals(p1.doubleValue()));
// assertNotSame("Objects are not the same", p1, d1);
*/
}
public void testIsTotalCertain() {
fail("Not yet implemented");
}
public void testNot() {
fail("Not yet implemented");
}
public void testOr() {
fail("Not yet implemented");
}
public void testToString() {
fail("Not yet implemented");
}
}
Maybe someone can shed some light that will help me understand this process more clearly.
You've chosen a somewhat hairy first step, comparing floating point numbers can be non-intuitive. You want to make sure you use the assertXXX methods with a delta:
double x = 1.3;
double y = 13.0 / 10.0;
double acceptable_difference = 0.05;
assertEquals(x,y, acceptable_difference);
That should return true as you're unlikely to make your value match.
In terms of writing your tests just think what you want to make sure of, being careful to test the boundary conditions, like if one Probability is 0.
Speaking of floating point I bet you could find uses of not that get you below 0.0, if ever so slightly. That's something to take a look at.
In your particular case, the code seems straight forward for the most part. Try to focus on testing the behavior of the code.
Here are some test scenarios for equals method.
Pass in a non-Probability object
String test = "foo";
assertTrue(!p1.equals(test));
Should the test pass? Should the test expect an exception?
Pass in null
assertTrue(!p1.equals(null));
Should the test pass? Should the test expect an exception?
Related
public class FillInQuestion extends Question {
public FillInQuestion(String sentence, DifficultyLevel diff) {
super(parseQ(sentence), parseA(sentence), diff);
}
/**
* Takes a sentence string and replace the answer surrounded by a specific patterb with a blank
*
* #param sentence
* #return finalquestion the question with a blank
* #throws IllegalAArgumentException if format is not met
*/
**private static String parseQ(String sentence){
int startindex = sentence.indexOf("_-");
int endindex = sentence.indexOf("-_");
if (startindex == -1 || endindex == -1 || endindex <= (startindex + 2)) {
throw new IllegalArgumentException("Fill in Question does not contain the correct format");
}
String answer = sentence.substring(startindex+2, endindex);
String finalquestion = sentence.replace("_-" + answer + "-_", "_________");
return finalquestion;**
}
/**
*
* #param sentence
* #return selected answer from a string
*/
private static String parseA(String sentence) {
int startindex = sentence.indexOf("_-");
int endindex = sentence.indexOf("-_");
return sentence.substring(startindex+2, endindex);
}
/**Creates a copy of FillinQuestion
*
* #return a copy of FillinQuestion
*
*/
#Override
public Question copy(){
return new FillInQuestion(this.getQuestion(), this.getDifficulty());
}
}
public class QuizManager {
/**
* Asks users for questions, take in user input and then have a score system
*
* #param questions ArrayList of Questions
* #throws Exception
*/
public static void giveQuiz(ArrayList<Question> questions) throws Exception {
Scanner s = new Scanner(System.in);
int score = 0;
if (questions.isEmpty()) { //Throws exception in the case of empty arraylist
throw new Exception("Questions Not Found Empty Quiz");
}
for (Question q : questions) {
System.out.println(q.displayQuestion());
System.out.print("Your answer: ");
String userAnswer = s.nextLine();
if (q.checkAnswer(userAnswer)) {
score++;
}
}
System.out.println("You scored " + score + " out of " + questions.size() + ".");
}
public static void main(String[] args) {
QuizMaker quizMaker = new QuizMaker("General Pop Quiz"); // New Object
//Questions
quizMaker.add(new Question("When did World War I started?", "1914", Question.DifficultyLevel.EASY));
quizMaker.add(new Question("How many fundamental states of matter are there? (State the number only)", "4", Question.DifficultyLevel.EASY));
quizMaker.add(new Question("Which three numbers have the same answer whether they are added or multiplied together?", "1, 2 and 3", Question.DifficultyLevel.MEDIUM));
quizMaker.add(new Question("How many wonders of the world are there (Numbers Only)", "7", Question.DifficultyLevel.EASY));
quizMaker.add(new Question("What is the capital city of Australia", "Canberra", Question.DifficultyLevel.MEDIUM));
quizMaker.add(new Question("What is the largest capital city in North America?", "Mexico City", Question.DifficultyLevel.HARD));
quizMaker.add(new Question("Who was the first person to create the first gasoline-powered car?", "Karl Benz", Question.DifficultyLevel.HARD));
quizMaker.add(new Question("State a palindrome number between 10 and 20", "11", Question.DifficultyLevel.EASY));
quizMaker.add(new Question("\n\nString str1 = \"InterviewBit\";\n"
+ "String str2 = \"InterviewBit\";\n"
+ " \n"
+ "System.out.println(str1 == str2);\n\nWhat will the code print?", "True", Question.DifficultyLevel.HARD));
quizMaker.add(new Question("I’m tall when I’m young, and I’m short when I’m old. What am I?", "Candle", Question.DifficultyLevel.MEDIUM));
**quizMaker.add(new FillInQuestion("The color _-white-_ is the most common color found on flags.", Question.DifficultyLevel.EASY));**
//quizMaker.add(new NumericQuestion("VALUE OF PI?", 3.14, 0.01, Question.DifficultyLevel.EASY));
ArrayList<Question> allQuestions = quizMaker.createQuiz();
ArrayList<Question> hardQuestions = quizMaker.createQuiz(Question.DifficultyLevel.HARD);
//Exception Handling
try {
System.out.println("Full Quiz for : ");
giveQuiz(allQuestions);
System.out.println("\nHard Quiz: ");
giveQuiz(hardQuestions);
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
public class QuizMaker {
private String name;
private ArrayList<Question> pool;
/**
* Constructor with name as an instance
*
* #param name the name of the QuizMaker instance
*/
public QuizMaker(String name) {
this.name = name;
this.pool = new ArrayList<>();
}
/*
* Question is copied into the pool
*
* #param q Question q that will be added to the pool
*/
public void add(Question q) {
this.pool.add(q.copy());
}
/*
* #return the name of the QuizMaker Instance
*/
public String getName() {
return name;
}
/**
* Sets the name of the QuizMaker instance.
*
* #param name the new name of the QuizMaker instance
*/
public void setName(String name) {
this.name = name;
}
/**
* Creates quiz from the question pool
*
* #return an ArrayList of Question objects representing the quiz
*/
public ArrayList<Question> createQuiz() {
ArrayList<Question> quiz = new ArrayList<>();
for (Question q : pool) {
quiz.add(q.copy());
}
return quiz;
}
/**
* Creates a specific difficulty quiz from pool of questions
*
* #param difficulty the difficulty level of the questions
* #return an ArrayList of Question with the specific difficulty
*/
public ArrayList<Question> createQuiz(Question.DifficultyLevel difficulty) {
ArrayList<Question> quiz = new ArrayList<>();
for (Question q : pool) {
if (q.getDifficulty() == difficulty) {
quiz.add(q.copy());
}
}
return quiz;
}
}
public class Question {
/*
* Enum class representing the difficulty of the question
*/
public enum DifficultyLevel {
EASY, MEDIUM , HARD;
}
//Instance values
private String question;
private String answer;
private DifficultyLevel difficulty;
/**
* Constructs a question with the given question text, answer, and difficulty level.
*
* #param question the question string
* #param answer the answer string
* #param difficulty the difficulty level of the question
*/
public Question(String question, String answer, DifficultyLevel difficulty) {
this.question = question;
this.answer = answer;
this.difficulty = difficulty;
}
/**
* Constructs a new question with the given question and answer, and default difficulty level of `EASY`.
*
* #param question the question string
* #param answer the answer string
*/
public Question(String question, String answer) {
this.question = question;
this.answer = answer;
this.difficulty = DifficultyLevel.EASY;
}
/**
*
*
* #return question string
*/
public String getQuestion() {
return question;
}
/**
* Set Given Question
* #param question
*/
public void setQuestion(String question) {
this.question = question;
}
/**
*
* #return answer string
*/
public String getAnswer() {
return answer;
}
/**Set the answer
*
* #param answer from given answer
*/
public void setAnswer(String answer) {
this.answer = answer;
}
/**
*
* #return difficulty ENUM difficulty level
*/
public DifficultyLevel getDifficulty() {
return difficulty;
}
/**
* Set difficulty level
* #param difficulty
*/
public void setDifficulty(DifficultyLevel difficulty) {
this.difficulty = difficulty;
}
/**
*
* #param userInput the user's answer
* #return a boolean whether the answer is true or not
*/
public boolean checkAnswer(String userInput) {
if(userInput.equalsIgnoreCase(getAnswer())) {
return true;
}else
return false;
}
/**Displays the question and the difficulty level of the question
*
* #return whole question and its difficulty
*/
public String displayQuestion() {
return "Question: " + this.getQuestion() + "\nDifficulty: " + this.getDifficulty();
}
/**
* #return the string summary
*/
public String toString() {
return "Question: " + question + ", Answer: " + answer + ", Difficulty Level: " + difficulty;
}
/**Creates a new question with the same question, answer and difficulty
*
* #return a copy of the question
*/
public Question copy() {
return new Question(this.getQuestion(), this.getAnswer(), this.getDifficulty());
}
}
I expected to the code I bolded to run smoothly without throwing the exception I implemented. It shouldn't happen since the format is correct. I don't know what I did wrong but basically o parseQ(“The sky is _-blue-_”) should return “The sky is _________” but I tried with the method but it only throws the exception. Also I am not allowed to use regex patterns.
Need to do a java calculator which works with batches. It must take an operation and then, for the next ones, just use the result of the previous operation as the first value of its new operation.
public class Calculator {
/**
* Public constructor of the calculator.
*/
**public Calculator () {/*...*/}**
/**
* Clean the internal state of the calculator
*/
**public void cleanOperations () { /*...*/ }**
/**
* Add a new operation to the internal state of the calculator.
* It is worth mentioning that the calculator behaves in an accumulative way ,
* thus only first operation has two operands.
* The rest of computations work with the accumulated value and only an extra
* new operand. Second input value must be ignored if the operation does not
* correspond to the first one.
*
* #param operation operation to add , as string , "+", "-", "*", "/".
* #param values Operands of the new operation (one or two operands ).
* Uses the varargs feature.
* https :// docs.oracle.com/javase /8/ docs/technotes/guides/language/varargs.html
* #throws IllegalArgumentException If the operation does not exist.
*/
**public void addOperation(String operation , float ... values) { /*...*/ }**
/**
* Execute the set of operations of the internal state of the calculator.
* Once execution is finished , internal state (operands and operations)
* is restored (EVEN if exception occurs ).
* This calculator works with "Batches" of operations.
* #return result of the execution
* #throws ArithmeticException If the operation returns an invalid value
* (division by zero)
*/
**public float executeOperations () { /*...*/ }**
/**
* Current internal state of calculator is printed
* FORMAT:
* "[{+/ -/"/"/*}] value1_value2 [{+/ -/"/"/*}] value1 [{+/ -/"/"/*}] value1 {...}"
* #return String of the internal state of the calculator
*/
#Override
public String toString () { /* ... */ }
}
SOME TEST IT SHOULD PASS:
// Add operations, calculate internal state representation (string pattern) and execute them as a single batch
calculator.addOperation("+", 4.5f, 6.8f);
calculator.addOperation("-", 3.1f);
calculator.addOperation("/", 6f);
assertEquals("[STATE:[+]4.5_6.8[-]3.1[/]6.0]", calculator.toString());
result = calculator.executeOperations();
assertEquals("[STATE:]", calculator.toString()); // state is restored
assertEquals(1.366f, result, EPSILON);//EPSILON = 0.01f
As you can see it must work by doing the first operation with 2 values but the next ones using the value stores from the one before and then execute with the operator and the value, the new operation.
Are you looking for this?
public class Calculator {
private String operation;
private float[] values;
private float answer;
/**
* Public constructor of the calculator.
*/
public Calculator() {
}
/**
* Clean the internal state of the calculator
*/
public void cleanOperations() {
operation = null;
values = null;
answer = 0;
}
/**
* Add a new operation to the internal state of the calculator.
* It is worth mentioning that the calculator behaves in an accumulative way ,
* thus only first operation has two operands.
* The rest of computations work with the accumulated value and only an extra
* new operand. Second input value must be ignored if the operation does not
* correspond to the first one.
*
* #param operation operation to add , as string , "+", "-", "*", "/".
* #param values Operands of the new operation (one or two operands ).
* Uses the varargs feature.
* https :// docs.oracle.com/javase /8/ docs/technotes/guides/language/varargs.html
* #throws IllegalArgumentException If the operation does not exist.
*/
public void addOperation(String operation, float... values) {
if (!(operation.equals("+") || operation.equals("-") || operation.equals("*") || operation.equals("/"))) {
throw new IllegalArgumentException(operation + " is not a valid operator. ( '+', '-', '*', '/')");
}
this.operation = operation;
this.values = values;
}
/**
* Execute the set of operations of the internal state of the calculator.
* Once execution is finished , internal state (operands and operations)
* is restored (EVEN if exception occurs ).
* This calculator works with "Batches" of operations.
*
* #return result of the execution
* #throws ArithmeticException If the operation returns an invalid value
* (division by zero)
*/
public float executeOperations() {
switch (operation) {
case "+":
if (values.length == 1) {
answer += values[0];
} else {
for (float value : values) {
answer += value;
}
}
break;
case "-":
if (values.length == 1) {
answer -= values[0];
} else if (values.length != 0) {
answer = values[0];
for (int i = 1; i < values.length; i++) {
answer -= values[i];
}
}
break;
case "*":
if (values.length == 1) {
answer *= values[0];
} else if (values.length != 0) {
answer = values[0];
for (int i = 1; i < values.length; i++) {
answer *= values[i];
}
}
break;
case "/":
if (values.length == 1) {
if (values[0] == 0) {
throw new ArithmeticException("Can not divide " + answer + " with " + values[0]);
}
answer /= values[0];
} else if (values.length != 0) {
answer = values[0];
for (int i = 1; i < values.length; i++) {
if (values[i] == 0) {
throw new ArithmeticException("Can not divide " + answer + " with " + values[i]);
}
answer /= values[i];
}
}
break;
}
return answer;
}
/**
* Current internal state of calculator is printed
* FORMAT:
* "[{+/ -/"/"/*}] value1_value2 [{+/ -/"/"/*}] value1 [{+/ -/"/"/*}] value1 {...}"
*
* #return String of the internal state of the calculator
*/
#Override
public String toString() {
StringBuilder string = new StringBuilder("values: [");
for (float value: values) {
string.append(value)
.append(" ")
.append(operation)
.append(" ");
}
string.append("] answer = ").append(answer);
return string.toString();
}
}
I am stuck trying to call a method. No matter what I do, I get an error that it can't find the symbol. I am trying to use the variables total (from the surfaceArea method) and volume (from the volume method).
The problems are in the toString method, where it cannot see the variables no matter what I do. I am sure it is something incredibly basic I a missing, so I hope someone can figure it out.
Here is the Error Log:
Ellipsoid.java:176: error: cannot find symbol
String vout = df.format(volume);
^
symbol: variable volume
location: class Ellipsoid
Ellipsoid.java:177: error: cannot find symbol
String sout = df.format(total);
^
symbol: variable total
location: class Ellipsoid
2 errors
And here is the code itself. I tried to make it as easy to read as possible:
/**
* This program lets the user enter values of and Ellipsoid.
* #version 02/05/2020
*/
public class Ellipsoid {
// fields
private String label;
private double a, b, c;
//public double total, volume;
// constructor
/**
* This constructor creates a ellipsoid and gets its information.
*
* #param labelIn is the label entered by the user.
* #param aIn is the a valuve entered by the user.
* #param bIn is the b valuve entered by the user.
* #param cIn is the c valuve entered by the user.
*/
public Ellipsoid(String labelIn, double aIn, double bIn, double cIn) {
setLabel(labelIn);
setA(aIn);
setB(bIn);
setC(cIn);
}
// methods
/**
* This method gets the label string.
* #return returns the label of the ellipsoid.
*/
public String getLabel() {
return label;
}
/**
* This method sets the label of the ellipsoid.
* #param labelIn is the label entered by the user.
* #return returns true or false depending on user input.
*/
public boolean setLabel(String labelIn) {
if (labelIn == null) {
return false;
}
else {
label = labelIn.trim();
return true;
}
}
/**
* This method gets the a values of the ellipsoid.
* #return returns a values of the ellipsoid.
*/
public double getA() {
return a;
}
/**
* This method sets the a value of the ellipsoid.
* #param aIn is the a value entered by the user.
* #return returns true or false depending on the user input.
*/
public boolean setA(double aIn)
{
if (aIn > 0)
{
a = aIn;
return true;
}
else
{
return false;
}
}
/**
* This method gets the b value of the ellipsoid.
* #return returns the b value of the ellipsoid.
*/
public double getB()
{
return b;
}
/**
* This method sets the b value of the ellipsoid.
* #param bIn is the b value entered by the user.
* #return returns true or false depending on the user input.
*/
public boolean setB(double bIn)
{
if (bIn > 0)
{
b = bIn;
return true;
}
else
{
return false;
}
}
/**
* This method gets the c value of the ellipsoid.
* #return returns the c value of the ellipsoid.
*/
public double getC()
{
return c;
}
/**
* This method sets the c value of the ellipsoid.
* #param cIn is the c value entered by the user.
* #return returns true or false depending on the user input.
*/
public boolean setC(double cIn)
{
if (cIn > 0)
{
c = cIn;
return true;
}
else
{
return false;
}
}
/**
* This method finds the volume of the ellipsoid.
* #return returns the volume of the ellipsoid.
*/
public double volume()
{
double volume = 4 * Math.PI * a * b * c;
volume = volume / 3;
return volume;
}
/**
* This method finds the surface area of the ellipsoid.
* #return returns the surface area.
*/
public double surfaceArea() {
double ab = (a * b);
ab = Math.pow(ab, 1.6);
double ac = a * c;
ac = Math.pow(ac, 1.6);
double bc = b * c;
bc = Math.pow(bc, 1.6);
double top = ab + ac + bc;
double bottom = top / 3;
double full = bottom * 1 / 1.6;
double total = 4 * Math.PI * full;
return total;
}
/**
* This method prints the information of the ellipsoid.
* #return returns the information of the ellipsoid.
*/
public String toString() {
DecimalFormat df = new DecimalFormat("#,##0.0###");
surfaceArea();
volume();
String aout = df.format(a);
String bout = df.format(b);
String cout = df.format(c);
String vout = df.format(volume);
String sout = df.format(total);
String output = "Ellipsoid \"" + label + "\" with axes a = " + aout
+ ", b = " + bout + ", c = " + cout + " units has:\n\tvolume = "
+ vout + " cubic units\n\tsurface area = "
+ sout + " square units";
return output;
}
}
volume and total are local members to volume() and surfaceArea() methods respectively. It is not visible in toString() method. But a, b and c are visible as they are declared class level. Try assigning returned values from those methods to local variables in toString() as below:
public String toString() {
DecimalFormat df = new DecimalFormat("#,##0.0###");
double total = surfaceArea();
double volume = volume();
....
String vout = df.format(volume);
String sout = df.format(total);
....
}
In the Ellipsoid class, you didn't declare the total and volume variables.
They are commented there, try to uncomment this line:
//public double total, volume;
Should help, but if you want to assign the values to those instance fields while calculating, change the double total and double total in the proper methods to this.total and this.volume.
This will allow you to both keep the data inside object and return it through method.
In the class Room I need to write a method to return a random exit from HashMap exits, or return null if there are no exits in that HashMap.
I have tried using iterators and saving it the HashMap in a Set but nothing works.
public class Room
{
private String description;
private HashMap<Direction, Room> exits; // stores exits of this room.
public Set<Character> chars; // stores the characters that are in this room.
/**
* Create a room described "description". Initially, it has
* no exits. "description" is something like "a kitchen" or
* "an open court yard".
* #param description The room's description.
* Pre-condition: description is not null.
*/
public Room(String description)
{
assert description != null : "Room.Room has null description";
this.description = description;
exits = new HashMap<Direction, Room>();
chars = new HashSet<Character>();
sane();
}
/**
* Define an exit from this room.
* #param direction The direction of the exit.
* #param neighbor The room to which the exit leads.
* Pre-condition: neither direction nor neighbor are null;
* there is no room in given direction yet.
*/
public void setExit(Direction direction, Room neighbor)
{
assert direction != null : "Room.setExit gets null direction";
assert neighbor != null : "Room.setExit gets null neighbor";
assert getExit(direction) == null : "Room.setExit set for direction that has neighbor";
sane();
exits.put(direction, neighbor);
sane();
assert getExit(direction) == neighbor : "Room.setExit has wrong neighbor";
}
/**
* Return the room that is reached if we go from this room in direction
* "direction". If there is no room in that direction, return null.
* #param direction The exit's direction.
* #return The room in the given direction.
* Pre-condition: direction is not null
*/
public Room getExit(Direction direction)
{
assert direction != null : "Room.getExit has null direction";
sane();
return exits.get(direction);
}
Direction:
public enum Direction
{
NORTH("north"), WEST("west"), SOUTH("south"), EAST("east");
private String name;
/**
* Constructor with parameter.
* Pre-condition: name is not null.
*/
private Direction(String name)
{
assert name != null : "Direction.Direction has null name";
this.name = name;
assert toString().equals(name) : "Direction.Direction produces wrong toString";
}
/**
* Return the direction name.
*/
public String toString()
{
return name;
}
}
Any help will be appreciated
Try converting the map to a list something like this (inside Room class) :
public Direction getRandomExit(){
List<Direction> directions = new ArrayList<Direction>(exits.keySet());
if (directions.size()==0){
return null;
}
Random rand = new Random();
int randomIndex = rand.nextInt(directions.size());
return directions.get(randomIndex);
}
I need to extend the class Room such that a room can contain zero or many characters by adding a field and a method in Room class that adds characters to rooms created. I already created an enum class called Character as can be seen below but I don't know how to use that in my Room class to add characters to a Room object.
I already created a HashMap field for storing the characters called charactersroom. The method in my code for adding characters is called addCharacter.
Room Class
public class Room
{
private String description;
private HashMap<Direction, Room> exits; // stores exits of this room.
private HashMap<Character, Room> charactersroom;
/**
* Create a room described "description". Initially, it has
* no exits. "description" is something like "a kitchen" or
* "an open court yard".
* #param description The room's description.
* Pre-condition: description is not null.
*/
public Room(String description)
{
assert description != null : "Room.Room has null description";
this.description = description;
exits = new HashMap<Direction, Room>();
charactersroom = new HashMap<Character, Room>();
sane();
}
public void addCharacter(Character character)
{
}
/**
* Class invariant: getShortDescription() and getLongDescription() don't return null.
*/
public void sane()
{
assert getShortDescription() != null : "Room has no short description" ;
assert getLongDescription() != null : "Room has no long description" ;
}
/**
* Define an exit from this room.
* #param direction The direction of the exit.
* #param neighbor The room to which the exit leads.
* Pre-condition: neither direction nor neighbor are null;
* there is no room in given direction yet.
*/
public void setExit(Direction direction, Room neighbor)
{
assert direction != null : "Room.setExit gets null direction";
assert neighbor != null : "Room.setExit gets null neighbor";
assert getExit(direction) == null : "Room.setExit set for direction that has neighbor";
sane();
exits.put(direction, neighbor);
sane();
assert getExit(direction) == neighbor : "Room.setExit has wrong neighbor";
}
/**
* #return The short description of the room
* (the one that was defined in the constructor).
*/
public String getShortDescription()
{
return description;
}
/**
* Return a description of the room in the form:
* You are in the kitchen.
* Items: map
* Exits: north west
* #return A long description of this room
*/
public String getLongDescription()
{
return "You are " + description + ".\n" + getExitString();
}
/**
* Return a string describing the room's exits, for example
* "Exits: north west".
* #return Details of the room's exits.
*/
private String getExitString()
{
String returnString = "Exits:";
Set<Direction> keys = exits.keySet();
for(Direction exit : keys) {
returnString += " " + exit;
}
return returnString;
}
/**
* Return the room that is reached if we go from this room in direction
* "direction". If there is no room in that direction, return null.
* #param direction The exit's direction.
* #return The room in the given direction.
* Pre-condition: direction is not null
*/
public Room getExit(Direction direction)
{
assert direction != null : "Room.getExit has null direction";
sane();
return exits.get(direction);
}
}
Character enum class
public enum Character
{
LAURA("Laura",Item.SANDWICH),SALLY("Sally", Item.CRISPS),ANDY("Andy", Item.DRINK),ALEX("Alex", null);
private String charDescription;
private Item item;
private Character(String Chardescription, Item item) {
this.charDescription = charDescription;
this.item = item;
}
public String toString()
{
return charDescription+item;
}
/**
* Takes the indicated item from the character
* #return true if successful
*
*/
public boolean take(Item item)
{
if (item == this.item) {
this.item = null;
return true;
}
return false;
}
}
EDIT: This method is in my superclass Game for creating the rooms and their exits:
/**
* Create all the rooms and link their exits together.
*/
private void createRooms()
{
Room trafalgarSquare, chinatown, oxfordStreet, soho, coventGarden,
britishMuseum, stPancras, kingsCross, britishLibrary, leicesterSquare;
// create the rooms
trafalgarSquare = new Room("on Trafalgar Square");
chinatown = new Room("in Chinatown");
oxfordStreet = new Room("on Oxford Street");
soho = new Room("in Soho");
coventGarden = new Room("in Covent Garden");
britishMuseum = new Room("in the British Museum");
stPancras = new Room("in St Pancras");
kingsCross = new Room("in Kings Cross");
britishLibrary = new Room("in the British Library");
leicesterSquare = new Room("on Leicester Square");
// initialise room exits
kingsCross.setExit(Direction.WEST, stPancras);
stPancras.setExit(Direction.EAST, kingsCross);
stPancras.setExit(Direction.WEST, britishLibrary);
britishLibrary.setExit(Direction.EAST, stPancras);
britishLibrary.setExit(Direction.SOUTH, britishMuseum);
britishMuseum.setExit(Direction.NORTH, britishLibrary);
britishMuseum.setExit(Direction.WEST, oxfordStreet);
oxfordStreet.setExit(Direction.EAST, britishMuseum);
britishMuseum.setExit(Direction.SOUTH, coventGarden);
coventGarden.setExit(Direction.NORTH, britishMuseum);
oxfordStreet.setExit(Direction.SOUTH, soho);
soho.setExit(Direction.NORTH, oxfordStreet);
soho.setExit(Direction.SOUTH, chinatown);
chinatown.setExit(Direction.NORTH, soho);
chinatown.setExit(Direction.SOUTH, leicesterSquare);
leicesterSquare.setExit(Direction.NORTH, chinatown);
leicesterSquare.setExit(Direction.EAST, coventGarden);
coventGarden.setExit(Direction.WEST, leicesterSquare);
leicesterSquare.setExit(Direction.SOUTH, trafalgarSquare);
trafalgarSquare.setExit(Direction.NORTH, leicesterSquare);
currentRoom = stPancras; // start game at St Pancras
}