На одном из наших вечерних собраний ученики занимались боулинг-ката на Яве. Просмотрев их код, я подумал, что было бы неплохо сделать это самому.
Каждый мастер в Codurance является разработчиком полиглота, и, хотя у нас очень схожие ценности, у всех нас есть свои предпочтения в отношении языков программирования и стилей кодирования. Как вы можете себе представить, мы не всегда можем избежать шутки или двух шуток по поводу всех языков, которые нам не нравятся так сильно, как другие мастера в компании. Так что, просто для удовольствия, многие из нас решили сделать одно и то же ката, используя наш язык. Было здорово видеть, что одна и та же проблема решена на разных языках. Хотя есть еще несколько мастеров и учеников, которые работают над решением ката на разных языках, вот три моих любимых решения на данный момент (без определенного порядка):
Clojure (от Mashooq)
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
(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--------------" ))))) |
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
(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’s GitHub
F # (автор Pedro)
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
|
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 @> |
Смотрите на GitHub Педро
Скала (Сандро)
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
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 ) } } |
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
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 } |
Смотрите на Сандро GitHub
Веселье, страсть и уважение
Веселье на работе, окружение страстными и талантливыми мастерами, уважение, которое мы испытываем друг к другу, и желание учиться и делиться — вот некоторые вещи, которые мне больше всего нравятся в культуре Codurance. То, что начиналось с учеников, практикующих ката, превратилось в отличный способ учиться и делиться знаниями между мастерами и учениками. Некоторые из наших мастеров и учеников также работают над своими решениями в Kotlin, Haskell, Java и C #.
Поскольку между собой мы, вероятно, никогда не договоримся, какой из них мы предпочитаем, мы позволим вам выбрать тот, который вам больше всего нравится. 🙂
Спасибо Машу и Педро за реализацию Clojure и F #.
Ссылка: | Боулинг Ката в Clojure, F # и Scala от нашего партнера JCG Сандро Манкузо в блоге Crafted Software . |