 # burns239's solution

## to Say in the Scala Track

Published at Jun 03 2019 · 0 comments
Instructions
Test suite
Solution

Given a number from 0 to 999,999,999,999, spell out that number in English.

## Step 1

Handle the basic case of 0 through 99.

If the input to the program is `22`, then the output should be `'twenty-two'`.

Your program should complain loudly if given a number outside the blessed range.

Some good test cases for this program are:

• 0
• 14
• 50
• 98
• -1
• 100

### Extension

If you're on a Mac, shell out to Mac OS X's `say` program to talk out loud.

## Step 2

Implement breaking a number up into chunks of thousands.

So `1234567890` should yield a list like 1, 234, 567, and 890, while the far simpler `1000` should yield just 1 and 0.

The program must also report any values that are out of range.

## Step 3

Now handle inserting the appropriate scale word between those chunks.

So `1234567890` should yield `'1 billion 234 million 567 thousand 890'`

The program must also report any values that are out of range. It's fine to stop at "trillion".

## Step 4

Put it all together to get nothing but plain English.

`12345` should give `twelve thousand three hundred forty-five`.

The program must also report any values that are out of range.

### Extensions

Use and (correctly) when spelling out the number in English:

• 14 becomes "fourteen".
• 100 becomes "one hundred".
• 120 becomes "one hundred and twenty".
• 1002 becomes "one thousand and two".
• 1323 becomes "one thousand three hundred and twenty-three".

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

A variation on JavaRanch CattleDrive, exercise 4a http://www.javaranch.com/say.jsp

## Submitting Incomplete Solutions

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

### SayTest.scala

``````import org.scalatest.{Matchers, FunSuite}

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

test("zero") {
Say.inEnglish(0) should be(Some("zero"))
}

test("one") {
pending
Say.inEnglish(1) should be(Some("one"))
}

test("fourteen") {
pending
Say.inEnglish(14) should be(Some("fourteen"))
}

test("twenty") {
pending
Say.inEnglish(20) should be(Some("twenty"))
}

test("twenty-two") {
pending
Say.inEnglish(22) should be(Some("twenty-two"))
}

test("one hundred") {
pending
Say.inEnglish(100) should be(Some("one hundred"))
}

test("one hundred twenty-three") {
pending
Say.inEnglish(123) should be(Some("one hundred twenty-three"))
}

test("one thousand") {
pending
Say.inEnglish(1000) should be(Some("one thousand"))
}

test("one thousand two hundred thirty-four") {
pending
Say.inEnglish(1234) should be(Some("one thousand two hundred thirty-four"))
}

test("one million") {
pending
Say.inEnglish(1000000) should be(Some("one million"))
}

test("one million two thousand three hundred forty-five") {
pending
Say.inEnglish(1002345) should be(Some("one million two thousand three hundred forty-five"))
}

test("one billion") {
pending
Say.inEnglish(1000000000) should be(Some("one billion"))
}

test("a big number") {
pending
Say.inEnglish(987654321123l) should be(Some("nine hundred eighty-seven billion six hundred fifty-four million three hundred twenty-one thousand one hundred twenty-three"))
}

test("numbers below zero are out of range") {
pending
Say.inEnglish(-1) should be(None)
}

test("numbers above 999,999,999,999 are out of range") {
pending
Say.inEnglish(1000000000000l) should be(None)
}
}``````
``````package Func

object Say {

def inEnglish(int: Long): Option[String] = {
def zeroThroughNinetyNine(int: Long): Option[String] = {
int match {
case 0 => Some("")
case n if n % 10 == 0 => tens(n)
case n if n < 10 => singleDigit(n)
case n if n < 20 => teens(n)
case n if n < 100 => for {
ten <- tens(n - (n % 10))
dig <- singleDigit(n % 10)
} yield	s"\${ten}-\${dig}"
case _ => None
}
}

def singleDigit(int: Long): Option[String] = {
int match {
case 1 => Some("one")
case 2 => Some("two")
case 3 => Some("three")
case 4 => Some("four")
case 5 => Some("five")
case 6 => Some("six")
case 7 => Some("seven")
case 8 => Some("eight")
case 9 => Some("nine")
case _ => None
}
}

def teens(int: Long): Option[String] = {
int match {
case 11 => Some("eleven")
case 12 => Some("twelve")
case 13 => Some("thirteen")
case 14 => Some("fourteen")
case 15 => Some("fifteen")
case 16 => Some("sixteen")
case 17 => Some("seventeen")
case 18 => Some("eighteen")
case 19 => Some("nineteen")
case _ => None
}
}

def tens(int: Long): Option[String] = {
int match {
case 10 => Some("ten")
case 20 => Some("twenty")
case 30 => Some("thirty")
case 40 => Some("forty")
case 50 => Some("fifty")
case 60 => Some("sixty")
case 70 => Some("seventy")
case 80 => Some("eighty")
case 90 => Some("ninety")
case _ => None
}
}

val BILLION = 1000000000
val MILLION = 1000000
val THOUSAND = 1000
val HUNDRED = 100
val MAX = 999999999999l

def englishise(int: Long): Option[String] = {
int match {
case n if n < 0 || n > MAX => None
case n if n > 999999999 => scaling(n, BILLION, "billion")
case n if n > 999999 => scaling(n, MILLION, "million")
case n if n > 999 => scaling(n, THOUSAND, "thousand")
case n if n > 99 => scaling(n, HUNDRED, "hundred")
case n if n < 100 => zeroThroughNinetyNine(n)
}

}

def scaling(int: Long, scale: Long, text: String): Option[String] = {
for {
atScale <- englishise((int - int % scale)/scale)
underScale <- englishise(int % scale)
} yield s"\${atScale} \${text} \${underScale}".trim
}

if (int == 0) {
Some("zero")
} else {
englishise(int)
}

}

}``````