SInce it’s Friday I’ll post my solution to the previous Scala Kata, Identifying Triangle Words.
I started by specifying small functions that could be combined to determine whether or not a word is a triangle word:
import org.specs._
object TriangleWordIdentifierSpec extends Specification{
"letter to number converter" should {
"convert A to 1" in {
convertLetterToNumber('A') must be(1)
}
"convert a to 1" in {
convertLetterToNumber('a') must be(1)
}
"convert C to 3" in {
convertLetterToNumber('C') must be(3)
}
"convert c to 3" in {
convertLetterToNumber('c') must be(3)
}
}
"generate word value" should {
"return sum of each character for 'abc'" in {
wordValue("abc") must be(1 + 2 + 3)
}
"return sum of each character for 'sky'" in {
wordValue("Sky") must be(19 + 11 + 25)
}
"'ddd' should equal 4 + 4 + 4" in {
wordValue("ddd") must be (4 + 4 + 4)
}
}
"identify if word is a triangle word" should {
"sky is a triangle word" in {
isTriangleWord("Sky") must be (true)
}
"ski is not a triangle word" in {
isTriangleWord("Ski") must be (false)
}
}
}
Here’s the implementation. It’s rough, and I have learned a bit more about scala’s for loops since then but decided against refactoring the solution yet.
object convertLetterToNumber extends (Char => Int){
override def apply(s:Char) = s.toUpperCase.toInt - ('A'.toInt-1)
}
object wordValue extends (String => Int){
override def apply(s:String) = {
List.fromString(s).foldRight(0)((a,b) => convertLetterToNumber(a)+b)
}
}
object isTriangleWord extends (String => Boolean){
override def apply(word:String) = {
val wordVal = wordValue(word)
var result = false
for{i <- 1 to wordVal
t = triangleNumberFor(i)
if(t <= wordVal)
}result = t == wordVal
result
}
private def triangleNumberFor(n:Int):Int = (n*(n+1))/2
}
This identifies Triangle Words just fine, but the real test is to read words from a file and count the number of triangle words and verify it is correct on the project euler website. This requires reading in from a scala.io.Source... in the spec I used fromString but the actual I just used fromFile.
import org.specs._
class WordReaderSpec extends Specification{
"only 'bar' and 'sky' are triangle words" should {
val str = """"Fpp","Bar","sKy","Earth"
|""".stripMargin
var triangleWords = List[String]()
doBefore{
triangleWords = WordReader.readWords(scala.io.Source.fromString(str))
}
"identify two elements as triangle words" in {
triangleWords.size must be(2)
}
"return list with 'Bar' and 'sKy' in it" in {
triangleWords must containAll(List("Bar", "sKy"))
}
}
}
The implementation to this isn't very effecient; the provided file from the site was a one line comma delimited file so I just read the whole thing in, stripped the quotes, split on the commas and passed each word to the IsTriangleNumber function. I'm sure this would bomb on a large file.
import scala.io._
object WordReader{
def readWords(source:Source):List[String] = {
var words = List[String]()
source.getLines.map(_.replaceAll("\"","").split(",")).next()
.foreach( arg => if(isTriangleWord(arg))words += arg )
words
}
}
That's it. I liked this kata because this was the first REAL one I did with it and cut my teeth on some of scala's concepts and used file IO with it for the first time. If you got some criticism or feedback please let me know... I'm looking to improve my skill anyway I can!

