πŸŽ‰ Exercism Research is now launched. Help Exercism, help science and have some fun at research.exercism.io πŸŽ‰
Avatar of SergiiVlasiuk

SergiiVlasiuk's solution

to Wordy in the Scala Track

Published at Aug 28 2019 · 0 comments
Instructions
Test suite
Solution

Parse and evaluate simple math word problems returning the answer as an integer.

Iteration 1 β€” Addition

Add two numbers together.

What is 5 plus 13?

Evaluates to 18.

Handle large numbers and negative numbers.

Iteration 2 β€” Subtraction, Multiplication and Division

Now, perform the other three operations.

What is 7 minus 5?

2

What is 6 multiplied by 4?

24

What is 25 divided by 5?

5

Iteration 3 β€” Multiple Operations

Handle a set of operations, in sequence.

Since these are verbal word problems, evaluate the expression from left-to-right, ignoring the typical order of operations.

What is 5 plus 13 plus 6?

24

What is 3 plus 2 multiplied by 3?

15 (i.e. not 9)

Bonus β€” Exponentials

If you'd like, handle exponentials.

What is 2 raised to the 5th power?

32

The Scala exercises assume an SBT project scheme. The exercise solution source should be placed within the exercise directory/src/main/scala. The exercise unit tests can be found within the exercise directory/src/test/scala.

To run the tests simply run the command sbt test in the exercise directory.

For more detailed info about the Scala track see the help page.

Source

Inspired by one of the generated questions in the Extreme Startup game. https://github.com/rchatley/extreme_startup

Submitting Incomplete Solutions

It's possible to submit an incomplete solution so you can see how others have completed the exercise.

WordyTest.scala

import org.scalatest.{Matchers, FunSuite}

/** @version 1.1.0 */
class WordyTest extends FunSuite with Matchers {

  test("addition") {
    Wordy.answer("What is 1 plus 1?") should be(Some(2))
  }

  test("more addition") {
    pending
    Wordy.answer("What is 53 plus 2?") should be(Some(55))
  }

  test("addition with negative numbers") {
    pending
    Wordy.answer("What is -1 plus -10?") should be(Some(-11))
  }

  test("large addition") {
    pending
    Wordy.answer("What is 123 plus 45678?") should be(Some(45801))
  }

  test("subtraction") {
    pending
    Wordy.answer("What is 4 minus -12?") should be(Some(16))
  }

  test("multiplication") {
    pending
    Wordy.answer("What is -3 multiplied by 25?") should be(Some(-75))
  }

  test("division") {
    pending
    Wordy.answer("What is 33 divided by -3?") should be(Some(-11))
  }

  test("multiple additions") {
    pending
    Wordy.answer("What is 1 plus 1 plus 1?") should be(Some(3))
  }

  test("addition and subtraction") {
    pending
    Wordy.answer("What is 1 plus 5 minus -2?") should be(Some(8))
  }

  test("multiple subtraction") {
    pending
    Wordy.answer("What is 20 minus 4 minus 13?") should be(Some(3))
  }

  test("subtraction then addition") {
    pending
    Wordy.answer("What is 17 minus 6 plus 3?") should be(Some(14))
  }

  test("multiple multiplication") {
    pending
    Wordy.answer("What is 2 multiplied by -2 multiplied by 3?") should be(
      Some(-12))
  }

  test("addition and multiplication") {
    pending
    Wordy.answer("What is -3 plus 7 multiplied by -2?") should be(Some(-8))
  }

  test("multiple division") {
    pending
    Wordy.answer("What is -12 divided by 2 divided by -3?") should be(Some(2))
  }

  test("unknown operation") {
    pending
    Wordy.answer("What is 52 cubed?") should be(None)
  }

  test("Non math question") {
    pending
    Wordy.answer("Who is the President of the United States?") should be(None)
  }
}
import scala.util.parsing.combinator.RegexParsers

object Wordy extends RegexParsers {
  private def constant: Parser[Int] = """\-?\d+""".r ^^ { value => value.toInt }

  private def beginning = """\D*\s+""".r

  private def expr: Parser[Int] = beginning ~> constant ~ rep("plus" ~ constant | "minus" ~ constant | "multiplied by" ~ constant | "divided by" ~ constant) ~ "?" ^^ {
    case number ~ list ~ _ => (number /: list) {
      case (x, "plus" ~ y) => x + y
      case (x, "minus" ~ y) => x - y
      case (x, "multiplied by" ~ y) => x * y
      case (x, "divided by" ~ y) => x / y
    }
  }

  def answer(text: String): Option[Int] = parseAll(expr, text) match {
    case Success(value, _) => Some(value)
    case allElse => None // Error, Failure, NoSuccess
  }
}

Community comments

Find this solution interesting? Ask the author a question to learn more.

What can you learn from this solution?

A huge amount can be learned from reading other people’s code. This is why we wanted to give exercism users the option of making their solutions public.

Here are some questions to help you reflect on this solution and learn the most from it.

  • What compromises have been made?
  • Are there new concepts here that you could read more about to improve your understanding?