Skip to content

Instantly share code, notes, and snippets.

@sortega
Created January 19, 2014 08:49
Show Gist options
  • Save sortega/8502156 to your computer and use it in GitHub Desktop.
Save sortega/8502156 to your computer and use it in GitHub Desktop.
Berlin clock kata (http://content.codersdojo.org/code-kata-catalogue/berlin-clock/) implemented in Scala when pairing with Alberto. By just letting the tests guide the design and merciless refactoring after every step we got to this terse code.
package berlin
object BerlinClock {
sealed trait Light
case object Off extends Light
case object Yellow extends Light
case object Red extends Light
type Clock = List[List[Light]]
def format(hours: Int, mins: Int, secs: Int): Clock = for {
(n, lights) <- numberOfLights(hours, mins, secs) zip lightColors
} yield makeLightsRow(n, lights)
private def numberOfLights(hours: Int, mins: Int, secs: Int) = List(
if (secs % 4 < 2) 1 else 0,
hours / 5,
hours % 5,
mins / 5,
mins % 5
)
private def makeLightsRow(turnedOn: Int, onLights: List[Light]) =
onLights.take(turnedOn) ++ List.fill(onLights.size - turnedOn)(Off)
private val lightColors = List(
List(Yellow),
List.fill(4)(Red),
List.fill(4)(Red),
List.tabulate(11)(index => if (index % 3 == 2) Red else Yellow),
List.fill(4)(Yellow)
)
}
package berlin
import org.scalatest.FlatSpec
import org.scalatest.matchers.MustMatchers
import berlin.BerlinClock._
class BerlinClockTest extends FlatSpec with MustMatchers {
"At 00:00:02" must "return completely off" in {
BerlinClock.format(0, 0, 2) must be (List(
List(Off),
List.fill(4)(Off),
List.fill(4)(Off),
List.fill(11)(Off),
List.fill(4)(Off)
))
}
"First row's light" must "switch every two seconds" in {
BerlinClock.format( 0, 10, 0).head must be (List(Yellow))
BerlinClock.format(12, 0, 1).head must be (List(Yellow))
BerlinClock.format(23, 30, 2).head must be (List(Off))
BerlinClock.format(20, 17, 8).head must be (List(Yellow))
}
"Second row's lights" must "have a red light per 5 hours" in {
BerlinClock.format( 0, 10, 10)(1) must be (List.fill(4)(Off))
BerlinClock.format( 6, 15, 5)(1) must be (List(Red, Off, Off, Off))
BerlinClock.format(10, 0, 10)(1) must be (List(Red, Red, Off, Off))
}
"Third row's lights" must "have a red light per hour not represented in the second row" in {
BerlinClock.format( 1, 10, 10)(2) must be (List(Red, Off, Off, Off))
BerlinClock.format(23, 30, 59)(2) must be (List(Red, Red, Red, Off))
}
"Forth row's lights" must "have a light on per 5 minutes" in {
countLightsOn(BerlinClock.format(10, 0, 10)(3)) must be (0)
countLightsOn(BerlinClock.format(15, 6, 5)(3)) must be (1)
countLightsOn(BerlinClock.format( 0, 10, 10)(3)) must be (2)
}
"Forth row's light" must "follow a repeated yellow-yellow-red pattern when turned on" in {
BerlinClock.format(23, 30, 10)(3) must be (List.tabulate(11)(index => {
if (index >= 6) Off
else if (index % 3 == 2) Red
else Yellow
}))
BerlinClock.format(23, 59, 10)(3) must
be (List.tabulate(11)(index => if (index % 3 == 2) Red else Yellow))
}
"Fifth row's lights" must "have a yellow light per minute not represented in the forth row" in {
BerlinClock.format(23, 1, 10)(4) must be (List(Yellow, Off, Off, Off))
BerlinClock.format(23, 59, 10)(4) must be (List.fill(4)(Yellow))
}
private def countLightsOn(row: List[Light]) = row.count(_ != Off)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment