j.doe
j.doe

Reputation: 29

How to calculate value of math expression and check user answer?

Any help or advice would be greatly appreciated. I'm dooing a simple game which generates ten different, random questions. The questions can be composed from 2, 3 or 4 integers.Something like this: 552 − 4 − 101, 102 / 3 / 3, 589 − 281, 123 + 56 + 2.

The question will be displayed in a textview and then the user can take a guess, entering values into an edittext and then upon clicking a key on a custom keypad, it will check the answer, and then display the next question until it reaches 10 questions. I have a problem with imputing the answer from the code i have. No matter what i do here i cant input the answer to the randomly generated expression.

public enum Operator {

PLUS("+"), MINUS("-"), MULTIPLIER("*"), DIVIDER("/");
private String displayValue;

private Operator(String displayValue) {
    this.displayValue = displayValue;
}
public String getDisplayValue() {
    return displayValue;
}}




public class Question{

 private List<QuestionElement> questionElements;

public Question(int sizeOfQuestionElemets) {
    questionElements = new ArrayList<QuestionElement>(sizeOfQuestionElemets);
}


public void addElement(QuestionElement questionElement) {
    questionElements.add(questionElement);
}

public List<QuestionElement> getElements() {
    return questionElements;
}

public int size() {
    return questionElements.size();
}

@Override
public String toString() {
    StringBuilder sb = new StringBuilder();
    for (QuestionElement questionElement : questionElements) {
        sb.append(questionElement);
    }
    return sb.toString().trim();
}
 }

public class QuestionElement {

private int value;
private Operator operator;

public int getValue() {
    return value;
}

public void setValue(int value) {
    this.value = value;
}

public Operator getOperator() {
    return operator;
}

public void setOperator(Operator operator) {
    this.operator = operator;
}

@Override
public String toString() {
    return value + (operator == null ? "" : " " + operator.getDisplayValue()) + " ";
}
 }

public class RandomQuestions {


static QuestionElement q =  new QuestionElement();
private static final int NUMBER_OF_QUESTIONS = 10;
private static final int MIN_QUESTION_ELEMENTS = 2;
private static final int MAX_QUESTION_ELEMENTS = 2;
private static final int MIN_QUESTION_ELEMENT_VALUE = 1;
private static final int MAX_QUESTION_ELEMENT_VALUE = 20;
private final Random randomGenerator = new Random();




public List<Question> getGeneratedRandomQuestions() {
    List<Question> randomQuestions = new ArrayList<>(NUMBER_OF_QUESTIONS);
    int randomQuestionElementsCapacity = getRandomQuestionElementsCapacity();
    Question question = new Question(randomQuestionElementsCapacity);
    for (int j = 0; j < randomQuestionElementsCapacity; j++) {
        boolean isLastIteration = j + 1 == randomQuestionElementsCapacity;

        QuestionElement questionElement = new QuestionElement();
        questionElement.setValue(getRandomQuestionElementValue());
        questionElement.setOperator(isLastIteration ? null
                : Operator.values()[randomGenerator.nextInt(Operator.values().length)]);

        question.addElement(questionElement);
    }
    randomQuestions.add(question);

    return randomQuestions;
}

private int getRandomQuestionElementsCapacity() {
    return getRandomIntegerFromRange(MIN_QUESTION_ELEMENTS, MAX_QUESTION_ELEMENTS);
}

private int getRandomQuestionElementValue() {
    return getRandomIntegerFromRange(MIN_QUESTION_ELEMENT_VALUE, MAX_QUESTION_ELEMENT_VALUE);
}

private int getRandomIntegerFromRange(int min, int max) {
    return randomGenerator.nextInt(max - min + 1) + min;
}





public static void main(String[] args) {
    Scanner input = new Scanner(System.in);
    RandomQuestions questionGenerator = new RandomQuestions();
    List<Question> randomQuestions = questionGenerator.getGeneratedRandomQuestions();
    for (Question question : randomQuestions) {
        System.out.println(""+ question+"=?");
        int answer = input.nextInt();

        if (answer == q.getValue()) {
            System.out.println("CORRECT");
        }else{
            System.err.println("STILL NOT WORKING");
        }

    }
}
}

Upvotes: 1

Views: 128

Answers (1)

Anonymous
Anonymous

Reputation: 86333

In your main() you are printing question, reading an answer from the user and then comparing the answer to q.getValue(). q is a question element that is not related to question and always has value 0. So the trick is to answer 0 no matter what the question is, then the program will print CORRECT. :-)

I haven’t found anywhere in your code where you are calculating the correct value of the math expression. This would probably be a good first step towards checking whether the user has indeed entered the correct result.

Calculating the correct result is not really trivial if we insist on taking operator precedence into account. 4 + 3 * 2 should be 10 (not 14). I believe that reading about the Shunting-yard algorithm should get you some of the way. It’s an algorithm for parsing a math expression, which is only the first step towards calculating its value, but still a first step.

I suggest that the object-oriented approach will be that the Question object knows how to check an answer. Here is an implementation of the algorithm, simplified to the four operators, but extended to actually do the calculation:

public boolean checkAnswer(int answer) {
    // calculate correct answer
    // use shunting yard algorithm
    Deque<Integer> outputQueue = new ArrayDeque<>();
    Deque<Operator> operatorStack = new ArrayDeque<>();
    for (QuestionElement element : questionElements) {
        outputQueue.push(element.getValue());
        Operator op = element.getOperator();
        if (op != null) {
            while (!operatorStack.isEmpty() && op.getPrecedence() <= operatorStack.peek().getPrecedence()) {
                int operand2 = outputQueue.pop();
                int operand1 = outputQueue.pop();
                outputQueue.push(operatorStack.pop().apply(operand1, operand2));
            }
            operatorStack.push(op);
        }
    }
    while (!operatorStack.isEmpty()) {
        int operand2 = outputQueue.pop();
        int operand1 = outputQueue.pop();
        outputQueue.push(operatorStack.pop().apply(operand1, operand2));
    }
    int result = outputQueue.pop();
    assert outputQueue.isEmpty();

    return answer == result;
}

You notice that I have put some new demands on your Operator enum too. It has a precedence. And the + operator must know how to do addition (through its apply method), and similarly for the other operators:

PLUS("+", 1) {
    @Override
    public int apply(int operand1, int operand2) {
        return operand1 + operand2;
    }
}, 
// etc.

public abstract int apply(int operand1, int operand2);

and so on. 1 is the precedence; * and / have higher precedence, for example 2.

Now in main() you just need to write:

        if (question.checkAnswer(answer)) {

If you decide to explain to the user that strict left-to-right evaluation is applied, it’s getting somewhat simpler:

public boolean checkAnswer(int answer) {
    // calculate correct answer
    // do left to right calculation
    int result = questionElements.get(0).getValue();
    for (int elementIndex = 1; elementIndex < questionElements.size(); elementIndex++) {
        Operator op = questionElements.get(elementIndex - 1).getOperator();
        result = op.apply(result, questionElements.get(elementIndex).getValue());
    }

    return answer == result;
}

The operators still need to have the apply method, but they no longer need the precedence.

Upvotes: 2

Related Questions