На одном из наших вечерних собраний ученики занимались боулинг-ката на Яве. Просмотрев их код, я подумал, что было бы неплохо сделать это самому.
Каждый мастер в 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_scoringimport com.codurance.UnitSpecimport com.codurance.bowlingkata.full_scoring.BowlingFullScoreCalculator.scoreForclass 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_scoringobject 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 . |