clojure和scala
在我们晚上的一次学徒会议上,一对正在用Java做Bowling Kata 。 复习他们的代码后,我认为最好自己动手做。
Codurance的每个工匠都是多语言的开发人员,尽管我们的价值观非常相似,但在编程语言和编码风格方面我们都有自己的偏好。 可以想像,我们不能总是避免对我们不太喜欢的所有语言开一两个玩笑,但公司中的其他工匠却喜欢。 因此,只是为了娱乐,我们中的许多人决定使用我们选择的语言来制作相同的kata。 很高兴看到使用不同语言解决的同一问题。 尽管仍然有一些工匠和学徒用不同的语言来解决kata问题,但到目前为止,这里是我最喜欢的3种解决方案(无特定顺序):
Clojure(作者Mashooq)
(ns bowling.core-test
(:require [clojure.test :refer :all]
[bowling.core :refer :all]))
(deftest bowling
(testing "strikes for all rolls"
(is (= 300 (score "XXXXXXXXXXXX"))))
(testing "normal scores"
(is (= 99 (score "91919393929291219191"))))
(testing "normal scores or misses"
(is (= 90 (score "9-9-9-9-9-9-9-9-9-9-")))
(is (= 93 (score "919-9-9-9-9-929-9-9-"))))
(testing "mixture of stikes and normals"
(is (= 98 (score "9-X8-9-9-9-9-9-9-9-")))
(is (= 104 (score "9-X8-9-9-9-9-9-9-X23")))
(is (= 28 (score "--X81--------------")))
(is (= 27 (score "--X8-1-------------"))))
(testing "spares for all rolls"
(is (= 150 (score "5/5/5/5/5/5/5/5/5/5/5"))))
(testing "mixture of spares and normals"
(is (= 82 (score "9-8/--9-9-9-9-9-9-9-")))
(is (= 84 (score "9-8/--9-9-9-9-9-9-9/1")))
(is (= 12 (score "--8/1---------------")))
(is (= 11 (score "--8/-1--------------")))))
(ns bowling.core)
(defn- spare?[s] (= \/ s))
(defn- strike? [s] (= \X s))
(defn- spare-or-strike? [s] (or (spare? s) (strike? s)))
(defn- miss? [s] (or (= nil s) (= \- s)))
(defn- score-for [s]
(cond
(spare-or-strike? s) 10
(miss? s) 0
:else (read-string (str s))))
(defn- score-roll [this-roll rem-rolls]
(cond
(strike? this-roll) (+ 10 (score-for (first rem-rolls)) (score-for (first (rest rem-rolls))))
(spare? this-roll) (+ 10 (score-for (first rem-rolls)))
(spare? (first rem-rolls)) 0
:else (score-for this-roll)))
(defn- score-rolls [acc rolls]
(if (seq rolls)
(let [running-score (+ acc (score-roll (first rolls) (rest rolls)))]
(score-rolls running-score (rest rolls)))
acc))
(defn- expand-strikes [rolls]
(seq (reduce str (map #(if (strike? %) "X-" (str %)) (seq rolls)))))
(defn- deduct-extra-rolls [score rolls]
(- score (score-rolls 0 (drop 20 (expand-strikes rolls)))))
(defn score [rolls]
(deduct-extra-rolls (score-rolls 0 (seq rolls)) rolls))
在Mash的GitHub上查看
F#(Pedro撰写)
namespace BowlingV2.FSharpKatas
module Bowling =
open System
type private Rolls = Strike | Spare | Roll
type private Pins = Pins of int
type private Roll = Rolls * Pins
let private maxRolls = 20
let private maxPins = 10
let private noPins = 0
let private pinCountForRoll roll =
let (Pins pins) = snd roll
pins
let private pinsFromRawRoll rawRoll =
Pins (Int32.Parse(rawRoll.ToString()))
let private sparePinsFromRawRoll rawRoll =
Pins (maxPins - Int32.Parse(rawRoll.ToString()))
let private parse roll index rolls =
let previousRoll = fun () -> Seq.item (index - 1) rolls
match roll with
| '-' -> Roll, Pins noPins
| '/' -> Spare, sparePinsFromRawRoll(previousRoll())
| 'X' -> Strike, Pins maxPins
| r -> Roll, pinsFromRawRoll r
let private scoreRoll index rolls =
let bonusRoll = fun(lookAhead) ->
if index + lookAhead < Seq.length rolls
then pinCountForRoll (Seq.item (index + lookAhead) rolls)
else noPins
let exceedsMaxRolls = fun() ->
rolls
|> Seq.take index
|> Seq.map (fun r -> match r with | (Strike, _) -> 2 | _ -> 1)
|> Seq.sum >= maxRolls
match Seq.item index rolls with
| (_, _) when exceedsMaxRolls() -> noPins
| (Spare, Pins pins) -> pins + bonusRoll 1
| (Strike, Pins pins) -> pins + bonusRoll 1 + bonusRoll 2
| (Roll, Pins pins) -> pins
let scoreGame rolls =
let parsedRolls = rolls |> Seq.mapi (fun index roll ->
parse roll index rolls)
parsedRolls
|> Seq.mapi (fun index _ -> scoreRoll index parsedRolls)
|> Seq.sum
module BowlingTests =
open NUnit.Framework
open Swensen.Unquote
open Bowling
[<Test>]
let ``calculate scores with no strikes or spares``() =
test <@ scoreGame "--" = 0 @>
test <@ scoreGame "1" = 1 @>
test <@ scoreGame "13" = 4 @>
test <@ scoreGame "13521" = 12 @>
[<Test>]
let ``calculate scores containing a miss``() =
test <@ scoreGame "1-5-" = 6 @>
test <@ scoreGame "9-9-9-9-9-9-9-9-9-9-" = 90 @>
[<Test>]
let ``calculate scores containing spares``() =
test <@ scoreGame "1/" = 10 @>
test <@ scoreGame "1/--" = 10 @>
test <@ scoreGame "1/-5" = 15 @>
test <@ scoreGame "1/35-" = 21 @>
test <@ scoreGame "1/3/23" = 30 @>
test <@ scoreGame "5/5/5/5/5/5/5/5/5/5/5" = 150 @>
[<Test>]
let ``calculate scores containing strikes``() =
test <@ scoreGame "X" = 10 @>
test <@ scoreGame "X--" = 10 @>
test <@ scoreGame "X--51" = 16 @>
test <@ scoreGame "X51" = 22 @>
test <@ scoreGame "XXXXXXXXXXXX" = 300 @>
test <@ scoreGame "XXXXXXXXXX12" = 274 @>
test <@ scoreGame "1/35XXX45" = 103 @>
test <@ scoreGame "1/35XXX458/X35" = 149 @>
test <@ scoreGame "1/35XXX458/X3/" = 153 @>
test <@ scoreGame "1/35XXX458/X3/23" = 160 @>
test <@ scoreGame "1/35XXX458/X3/X" = 173 @>
test <@ scoreGame "1/35XXX458/X3/XX6" = 189 @>
斯卡拉(Sandro)
package com.codurance.bowlingkata.full_scoring
import com.codurance.UnitSpec
import com.codurance.bowlingkata.full_scoring.BowlingFullScoreCalculator.scoreFor
class BowlingFullScoreCalculatorShould extends UnitSpec {
"calculate scores with no strikes or spares" in {
scoreFor("11111111112222222222") should be (30)
}
"calculate scores containing a miss" in {
scoreFor("--------------------") should be (0)
scoreFor("1-1----------------1") should be (3)
scoreFor("9-9-9-9-9-9-9-9-9-9-") should be (90)
}
"calculate scores containing spares" in {
scoreFor("5/11------------3/11") should be (26)
scoreFor("5/5/5/5/5/5/5/5/5/5/5") should be (150)
}
"calculate scores containing strikes" in {
scoreFor("XXXXXXXXXXXX") should be(300)
scoreFor("XXXXXXXXXX12") should be(274)
scoreFor("1/35XXX458/X3/23") should be(160)
scoreFor("1/35XXX458/X3/XX6") should be(189)
}
}
package com.codurance.bowlingkata.full_scoring
object BowlingFullScoreCalculator {
def scoreFor(rolls: String): Int = totalScore(rolls.split("").toList)
private def totalScore(rolls: List[String], index: Int = 0, score: Int = 0): Int = {
lazy val MISS = "-"
lazy val SPARE = ("/", () => 10 - rollScoreAt(index - 1) + if_(index < 19, rollScoreAt(index + 1)))
lazy val STRIKE = ("X", () => 10 + if_(index + numberOfPreviousStrikes() < 18,
rollScoreAt(index + 1) + rollScoreAt(index + 2)))
def numberOfPreviousStrikes() = rolls.mkString.take(index).count(_ == 'X')
def rollScoreAt(index: Int): Int =
rolls(index) match {
case STRIKE._1 => 10
case SPARE._1 => 10 - rolls(index - 1).toInt
case MISS => 0
case pins => pins.toInt
}
rolls.drop(index) match {
case STRIKE._1 :: _ => totalScore(rolls, index + 1, score + STRIKE._2())
case SPARE._1 :: _ => totalScore(rolls, index + 1, score + SPARE._2())
case MISS :: _ => totalScore(rolls, index + 1, score)
case n :: _ => totalScore(rolls, index + 1, score + n.toInt)
case List() => score
}
}
private def if_(condition: Boolean, ifTrue: => Int): Int = if (condition) ifTrue else 0
}
乐趣,热情和尊重
在工作中获得乐趣,被充满激情和才华的工匠所包围,我们彼此之间的尊重以及学习和分享的意愿,是我对Codurance文化最钟爱的一些东西。 最初是用kata练习的学徒,后来变成了在工匠和学徒之间学习和共享知识的好方法。 我们的一些工匠和学徒也在Kotlin,Haskell,Java和C#中致力于他们的解决方案。
在我们当中,我们可能永远不会同意我们更喜欢哪一种,我们会让您选择最喜欢的一种。 :)
翻译自: https://www.javacodegeeks.com/2016/05/bowling-kata-clojure-f-scala.html
clojure和scala