Keith,
That's a pretty cool program. Your representation is pretty concise. I've posted a different version below that is tail recursive (could be construed as pointless, as it is capped at 10 frames by the second match case below).
I only did some cursory testing, but the logic seems sound.
1 2 3 4 5 6 7 8 9 10 11
let score_bowls bowls = let rec sb frame l score = match l with | [] -> score | _ when frame = 10 -> score | [f] -> sb (frame+1) [] (score + f) | 10 :: s :: n :: tail -> sb (frame+1) (s::n::tail) (score+10+s+n) | f :: s :: n :: tail when (f + s) = 10 -> sb (frame+1) (n::tail) (score+10+n) | f :: s :: tail -> sb (frame+1) tail (score+f+s) sb 0 bowls 0
In this code, I am using frame
to represent how many frames have been processed so far. score
is the accumulator, while l
represents the remaining frames to process. The main difference, other than the accumulator, is that I have removed the match case [f; s]
, which is handled by the last case above.
The equivalent non-tail recursive function is:
1 2 3 4 5 6 7 8 9 10
let score_bowls2 bowls = let rec sb frame l = match l with | [] -> 0 | _ when frame = 10 -> 0 | [f] -> f | 10 :: s :: n :: tail -> 10 + s + n + sb (frame+1) (s::n::tail) | f :: s :: n :: tail when (f + s) = 10 -> 10 + n + sb (frame+1) (n::tail) | f :: s :: tail -> f + s + sb (frame+1) tail sb 0 bowls
Regards,
z.
Continuing to try and improve my initial code and remove some of the duplication (and fix a bug)
<!--
{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;}??\fs28 #light\par ??\par ??\cf3 open\cf0 System\par ??\cf3 open\cf0 NUnit.Framework\par ??\par ??\cf3 let\cf0 \cf3 rec\cf0 score_bowls bowls =\par ?? \cf3 let\cf0 \cf3 rec\cf0 score_bowls' frame l = \par ?? \cf3 let\cf0 sum b = (List.fold_right (\cf3 fun\cf0 x y \cf3 ->\cf0 x + y) b 0)\par ?? \cf3 let\cf0 nextframe = score_bowls' (frame+1)\par ?? \cf3 match\cf0 l \cf3 with\cf0 \par ?? | _ \cf3 when\cf0 frame = 10 \cf3 ->\cf0 sum l \par ?? | [10;s] \cf3 ->\cf0 10 + s + s\par ?? | 10 :: s :: n :: tail \cf3 ->\cf0 10 + s + n + nextframe (s :: n :: tail ) \par ?? | f :: s :: n :: tail \cf3 ->\cf0 f + s + (\cf3 if\cf0 ((f+s)=10) \cf3 then\cf0 n \cf3 else\cf0 0) + nextframe (n :: tail)\par ?? | _ \cf3 ->\cf0 sum l \par ?? score_bowls' 1 bowls\par ?? \par ??[<TestFixture>]\par ??\cf3 type\cf0 BowlingTestCases = \cf3 class\par ??\cf0 \cf3 new\cf0 () = \{\} \par ?? [<Test>]\par ?? \cf3 member\cf0 x.SimpleScoring() = Assert.AreEqual(6, score_bowls [1;2;3] )\par ?? [<Test>]\par ?? \cf3 member\cf0 x.ScoreSpare() = Assert.AreEqual(12, score_bowls [2;8;1] )\par ?? [<Test>]\par ?? \cf3 member\cf0 x.ScoreStrike() = Assert.AreEqual(16, score_bowls [10;1;2] )\par ?? [<Test>] \par ?? \cf3 member\cf0 x.ScorePerfectGame() = Assert.AreEqual( 300, score_bowls [\cf3 for\cf0 i \cf3 in\cf0 1..12 \cf3 ->\cf0 10] )\par ?? [<Test>] \par ?? \cf3 member\cf0 x.SpareLastFrame() = Assert.AreEqual( 11, score_bowls ([\cf3 for\cf0 i \cf3 in\cf0 1..18 \cf3 ->\cf0 0] @ [2;8;1]) )\par ?? [<Test>] \par ?? \cf3 member\cf0 x.StrikeLastFrame() = Assert.AreEqual( 21, score_bowls ([\cf3 for\cf0 i \cf3 in\cf0 1..18 \cf3 ->\cf0 0] @ [10;10;1]) )\par ?? [<Test>] \par ?? \cf3 member\cf0 x.DoubleStrike() = Assert.AreEqual(33, score_bowls [10;10;1] )\par ??\cf3 end\par ??\par ??}
-->
#light
open System
open NUnit.Framework
let rec score_bowls bowls =
let rec score_bowls' frame l =
let sum b = (List.fold_right (fun x y -> x + y) b 0)
let nextframe = score_bowls' (frame+1)
match l with
| _ when frame = 10 -> sum l
| [10;s] -> 10 + s + s
| 10 :: s :: n :: tail -> 10 + s + n + nextframe (s :: n :: tail )
| f :: s :: n :: tail -> f + s + (if((f+s)=10) then n else 0) + nextframe (n :: tail)
| _ -> sum l
score_bowls' 1 bowls
[<TestFixture>]
type BowlingTestCases = class
new() = {}
[<Test>]
member x.SimpleScoring() = Assert.AreEqual(6, score_bowls [1;2;3] )
[<Test>]
member x.ScoreSpare() = Assert.AreEqual(12, score_bowls [2;8;1] )
[<Test>]
member x.ScoreStrike() = Assert.AreEqual(16, score_bowls [10;1;2] )
[<Test>]
member x.ScorePerfectGame() = Assert.AreEqual( 300, score_bowls [for i in 1..12 -> 10] )
[<Test>]
member x.SpareLastFrame() = Assert.AreEqual( 11, score_bowls ([for i in 1..18 -> 0] @ [2;8;1]) )
[<Test>]
member x.StrikeLastFrame() = Assert.AreEqual( 21, score_bowls ([for i in 1..18 -> 0] @ [10;10;1]) )
[<Test>]
member x.DoubleStrike() = Assert.AreEqual(33, score_bowls [10;10;1] )
end
another shot... cleaning things up a bit<!--
{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;}??\fs28 #light\par ??\par ??\cf3 open\cf0 System\par ??\cf3 open\cf0 NUnit.Framework\par ??\par ??\cf3 let\cf0 score_bowls bowls =\par ?? \cf3 let\cf0 \cf3 rec\cf0 score_bowls' frame l = \par ?? \cf3 let\cf0 nextframe = score_bowls' (frame+1)\par ?? \cf3 match\cf0 l \cf3 with\cf0 \par ?? | _ \cf3 when\cf0 frame = 11 \cf3 ->\cf0 0 \par ?? | [10;s] \cf3 ->\cf0 10 + s + s\par ?? | 10 :: s :: n :: tail \cf3 ->\cf0 10 + s + n + nextframe (s :: n :: tail ) \par ?? | f :: s :: n :: tail \cf3 ->\cf0 f + s + (\cf3 if\cf0 ((f+s)=10) \cf3 then\cf0 n \cf3 else\cf0 0) + nextframe (n :: tail)\par ?? | _ \cf3 ->\cf0 List.fold_right (\cf3 fun\cf0 x y \cf3 ->\cf0 x + y) l 0\par ?? score_bowls' 1 bowls\par ?? \par ??[<TestFixture>]\par ??\cf3 type\cf0 BowlingTestCases = \cf3 class\par ??\cf0 \cf3 new\cf0 () = \{\} \par ?? [<Test>]\par ?? \cf3 member\cf0 x.SimpleScoring() = Assert.AreEqual(6, score_bowls [1;2;3] )\par ?? [<Test>]\par ?? \cf3 member\cf0 x.ScoreSpare() = Assert.AreEqual(12, score_bowls [2;8;1] )\par ?? [<Test>]\par ?? \cf3 member\cf0 x.ScoreStrike() = Assert.AreEqual(16, score_bowls [10;1;2] )\par ?? [<Test>] \par ?? \cf3 member\cf0 x.ScorePerfectGame() = Assert.AreEqual( 300, score_bowls [\cf3 for\cf0 i \cf3 in\cf0 1..12 \cf3 ->\cf0 10] )\par ?? [<Test>] \par ?? \cf3 member\cf0 x.SpareLastFrame() = Assert.AreEqual( 11, score_bowls ([\cf3 for\cf0 i \cf3 in\cf0 1..18 \cf3 ->\cf0 0] @ [2;8;1]) )\par ?? [<Test>] \par ?? \cf3 member\cf0 x.StrikeLastFrame() = Assert.AreEqual( 21, score_bowls ([\cf3 for\cf0 i \cf3 in\cf0 1..18 \cf3 ->\cf0 0] @ [10;10;1]) )\par ?? [<Test>] \par ?? \cf3 member\cf0 x.DoubleStrike() = Assert.AreEqual(33, score_bowls [10;10;1] )\par ??\cf3 end\par ??\par ??}
-->
#light
open System
open NUnit.Framework
let score_bowls bowls =
let rec score_bowls' frame l =
let nextframe = score_bowls' (frame+1)
match l with
| _ when frame = 11 -> 0
| [10;s] -> 10 + s + s
| 10 :: s :: n :: tail -> 10 + s + n + nextframe (s :: n :: tail )
| f :: s :: n :: tail -> f + s + (if((f+s)=10) then n else 0) + nextframe (n :: tail)
| _ -> List.fold_right (fun x y -> x + y) l 0
score_bowls' 1 bowls
[<TestFixture>]
type BowlingTestCases = class
new() = {}
[<Test>]
member x.SimpleScoring() = Assert.AreEqual(6, score_bowls [1;2;3] )
[<Test>]
member x.ScoreSpare() = Assert.AreEqual(12, score_bowls [2;8;1] )
[<Test>]
member x.ScoreStrike() = Assert.AreEqual(16, score_bowls [10;1;2] )
[<Test>]
member x.ScorePerfectGame() = Assert.AreEqual( 300, score_bowls [for i in 1..12 -> 10] )
[<Test>]
member x.SpareLastFrame() = Assert.AreEqual( 11, score_bowls ([for i in 1..18 -> 0] @ [2;8;1]) )
[<Test>]
member x.StrikeLastFrame() = Assert.AreEqual( 21, score_bowls ([for i in 1..18 -> 0] @ [10;10;1]) )
[<Test>]
member x.DoubleStrike() = Assert.AreEqual(33, score_bowls [10;10;1] )
end
Just if anyones interested...
a friend tipped me off to another thing... (fun x y -> x + y) is the + operator..... obviously enough in retrospect.
Still not happy with the embedded if statement though.... I don't think its too clear.
my match basically is
if we are at the end of the game, dont score anymore frames
if we have an incomplete strike, score what we can
if strike, score strike and carry on
if normal frame, score it, if we got a spare then add on the extra and then carry on
otherwise, just add up whats there.
Thing is, without comments I can't see a way of introducing the language too easily. In C# / C++ you'd introudce an explaining variable / methods. Here I kind need a new kind of refactoring called "Introduce explaining pattern match" but I don't think I can do that. I'm not sure if it would help understanding if I could. It's still way more concise than any C# / Java / C++ I've seen for the same thing.
so...the code<!--
{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;}??\fs28 #light\par ??\par ??\cf3 open\cf0 System\par ??\cf3 open\cf0 NUnit.Framework\par ??\par ??\cf3 let\cf0 score_bowls bowls =\par ?? \cf3 let\cf0 \cf3 rec\cf0 score_bowls' frame l = \par ?? \cf3 let\cf0 nextframe = score_bowls' (frame+1)\par ?? \cf3 match\cf0 l \cf3 with\cf0 \par ?? | _ \cf3 when\cf0 frame = 11 \cf3 ->\cf0 0 \par ?? | [10;s] \cf3 ->\cf0 10 + s + s\par ?? | 10 :: s :: n :: tail \cf3 ->\cf0 10 + s + n + nextframe (s :: n :: tail ) \par ?? | f :: s :: n :: tail \cf3 ->\cf0 f + s + (\cf3 if\cf0 ((f+s)=10) \cf3 then\cf0 n \cf3 else\cf0 0) + nextframe (n :: tail)\par ?? | _ \cf3 ->\cf0 List.fold_right (+) l 0\par ?? score_bowls' 1 bowls\par ?? \par ??[<TestFixture>]\par ??\cf3 type\cf0 BowlingTestCases = \cf3 class\par ??\cf0 \cf3 new\cf0 () = \{\} \par ?? [<Test>]\par ?? \cf3 member\cf0 x.SimpleScoring() = Assert.AreEqual(6, score_bowls [1;2;3] )\par ?? [<Test>]\par ?? \cf3 member\cf0 x.ScoreSpare() = Assert.AreEqual(12, score_bowls [2;8;1] )\par ?? [<Test>]\par ?? \cf3 member\cf0 x.ScoreStrike() = Assert.AreEqual(16, score_bowls [10;1;2] )\par ?? [<Test>] \par ?? \cf3 member\cf0 x.ScorePerfectGame() = Assert.AreEqual( 300, score_bowls [\cf3 for\cf0 i \cf3 in\cf0 1..12 \cf3 ->\cf0 10] )\par ?? [<Test>] \par ?? \cf3 member\cf0 x.SpareLastFrame() = Assert.AreEqual( 11, score_bowls ([\cf3 for\cf0 i \cf3 in\cf0 1..18 \cf3 ->\cf0 0] @ [2;8;1]) )\par ?? [<Test>] \par ?? \cf3 member\cf0 x.StrikeLastFrame() = Assert.AreEqual( 21, score_bowls ([\cf3 for\cf0 i \cf3 in\cf0 1..18 \cf3 ->\cf0 0] @ [10;10;1]) )\par ?? [<Test>] \par ?? \cf3 member\cf0 x.DoubleStrike() = Assert.AreEqual(33, score_bowls [10;10;1] )\par ?? [<Test>] \par ?? \cf3 member\cf0 x.ExampleGame() = Assert.AreEqual(133, score_bowls [1;4;4;5;6;4;5;5;10;0;1;7;3;6;4;10;2;8;6] )\par ??\cf3 end\par ??\par ??}
-->
#light
open System
open NUnit.Framework
let score_bowls bowls =
let rec score_bowls' frame l =
let nextframe = score_bowls' (frame+1)
match l with
| _ when frame = 11 -> 0
| [10;s] -> 10 + s + s
| 10 :: s :: n :: tail -> 10 + s + n + nextframe (s :: n :: tail )
| f :: s :: n :: tail -> f + s + (if((f+s)=10) then n else 0) + nextframe (n :: tail)
| _ -> List.fold_right (+) l 0
score_bowls' 1 bowls
[<TestFixture>]
type BowlingTestCases = class
new() = {}
[<Test>]
member x.SimpleScoring() = Assert.AreEqual(6, score_bowls [1;2;3] )
[<Test>]
member x.ScoreSpare() = Assert.AreEqual(12, score_bowls [2;8;1] )
[<Test>]
member x.ScoreStrike() = Assert.AreEqual(16, score_bowls [10;1;2] )
[<Test>]
member x.ScorePerfectGame() = Assert.AreEqual( 300, score_bowls [for i in 1..12 -> 10] )
[<Test>]
member x.SpareLastFrame() = Assert.AreEqual( 11, score_bowls ([for i in 1..18 -> 0] @ [2;8;1]) )
[<Test>]
member x.StrikeLastFrame() = Assert.AreEqual( 21, score_bowls ([for i in 1..18 -> 0] @ [10;10;1]) )
[<Test>]
member x.DoubleStrike() = Assert.AreEqual(33, score_bowls [10;10;1] )
[<Test>]
member x.ExampleGame() = Assert.AreEqual(133, score_bowls [1;4;4;5;6;4;5;5;10;0;1;7;3;6;4;10;2;8;6] )
end
Thanks a bunch for the examples! I do a lot of test-driven development and I have a project called FsUnit that I could use some input on.
My project has been up on Google Code for a while now: [link:code.google.com]
Please check it out if you're interested and let me know what I can add or change. Right now it's just a syntactic wrapper for NUnit but I would like to take this project much further.
Using FsUnit, you can write assertions like this:
1 2 3 4 5 6 7 8
score_bowls [1;2;3] |> should (equal 6) [|"item1"|] |> should (contain "item1") true |> should (be True)
If you want to better express the intent of the code then I would probably go with something like I've done below, however, it's just under twice as long as your version so it really comes down to a trade of. Whats more important code size or readability? In this case I'd probably go with code size and just add some comments since the function itself isn't doing anything overly complicated.
#light
let (|EndOfGame|IncompleteStrike|Strike|Normal|Other|) (l, frame) =
match l with
_ when frame = 11 -> EndOfGame(0)
| [10;s] -> IncompleteStrike(10 + s + s)
| 10 :: s :: n :: tail -> Strike(10 + s + n, s :: n :: tail)
| f :: s :: n :: tail when f + s = 10 -> Normal(f + s + n, n :: tail)
| f :: s :: n :: tail -> Normal(f + s , n :: tail)
| ls -> Other(List.fold_left (+) 0 ls)
let score_bowls bowls =
let rec score_bowls' frame l current_score =
let nextframe = score_bowls' (frame+1)
match (l, frame) with
EndOfGame(score) -> current_score + score
| IncompleteStrike(score) -> current_score + score
| Strike(score, l) -> nextframe l (current_score + score)
| Normal(score, l) -> nextframe l (current_score + score)
| Other(score) -> current_score + score
score_bowls' 1 bowls
Topic tags
- f# × 3705
- websharper × 1897
- compiler × 286
- functional × 201
- ui next × 139
- c# × 121
- classes × 97
- web × 97
- .net × 84
- book × 84
- async × 76
- ui.next × 67
- bug × 54
- core × 49
- website × 49
- server × 45
- parallel × 43
- ui × 43
- enhancement × 41
- parsing × 41
- testing × 41
- trywebsharper × 41
- typescript × 37
- html × 35
- javascript × 35
- owin × 35
- asynchronous × 30
- monad × 28
- ocaml × 28
- tutorial × 27
- warp × 27
- haskell × 26
- sitelet × 25
- linq × 22
- workflows × 22
- wpf × 20
- fpish × 19
- introduction × 19
- silverlight × 19
- sitelets × 19
- monodevelop × 17
- rpc × 17
- suave × 17
- piglets × 16
- collections × 15
- feature request × 15
- jquery × 15
- templates × 15
- getting started × 14
- pipeline × 14
- kendoui × 13
- reactive × 12
- 4.1.0.171 × 11
- monads × 11
- opinion × 10
- 4.0.190.100-rc × 9
- deployment × 9
- fixed × 9
- formlets × 9
- in × 9
- json × 9
- plugin × 9
- proposal × 9
- scheme × 9
- solid × 9
- basics × 8
- concurrent × 8
- highcharts × 8
- how-to × 8
- python × 8
- 4.1.1.175 × 7
- complexity × 7
- documentation × 7
- visual studio × 7
- 4.1.2.178 × 6
- lisp × 6
- real-world × 6
- released in 4.0.192.103-rc × 6
- remoting × 6
- resources × 6
- scala × 6
- websharper ui.next × 6
- workshop × 6
- xaml × 6
- 4.0.193.110 × 5
- 4.2.3.236 × 5
- aspnetmvc × 5
- authentication × 5
- azure × 5
- bootstrap × 5
- conference × 5
- dsl × 5
- formlet × 5
- java × 5
- list × 5
- metaprogramming × 5
- ml × 5
- released in Zafir.4.0.188.91-beta10 × 5
- sql × 5
- visualstudio × 5
- websharper.forms × 5
- zafir × 5
- 4.0.192.106 × 4
- 4.0.195.127 × 4
- 4.1.0.38 × 4
- 4.2.1.86 × 4
- 4.2.6.118 × 4
- css × 4
- example × 4
- extensions × 4
- fsi × 4
- fsx × 4
- html5 × 4
- jqueryui × 4
- lift × 4
- reflection × 4
- remote × 4
- rest × 4
- spa × 4
- teaching × 4
- template × 4
- websocket × 4
- wontfix × 4
- 4.0.196.147 × 3
- 4.1.0.34 × 3
- 4.1.6.207 × 3
- 4.2.1.223-beta × 3
- 4.2.11.258 × 3
- 4.2.4.114 × 3
- 4.2.4.247 × 3
- 4.2.5.115 × 3
- 4.2.6.253 × 3
- 4.2.9.256 × 3
- ajax × 3
- alt.net × 3
- aml × 3
- asp.net mvc × 3
- canvas × 3
- cloudsharper × 3
- compilation × 3
- database × 3
- erlang × 3
- events × 3
- extension × 3
- file upload × 3
- forums × 3
- inline × 3
- issue × 3
- kendo × 3
- macro × 3
- mono × 3
- msbuild × 3
- mvc × 3
- pattern × 3
- piglet × 3
- released in Zafir.4.0.187.90-beta10 × 3
- svg × 3
- type provider × 3
- view × 3
- 4.1.1.64 × 2
- 4.1.5.203 × 2
- 4.1.7.232 × 2
- 4.2.10.257 × 2
- 4.2.3.111 × 2
- 4.2.5.249 × 2
- android × 2
- asp.net × 2
- beginner × 2
- blog × 2
- chart × 2
- client × 2
- client server app × 2
- clojure × 2
- computation expressions × 2
- constructor × 2
- corporate × 2
- courses × 2
- cufp × 2
- d3 × 2
- debugging × 2
- direct × 2
- discriminated union × 2
- docs × 2
- elm × 2
- endpoint × 2
- endpoints × 2
- enterprise × 2
- entity framework × 2
- event × 2
- f# interactive × 2
- fable × 2
- flowlet × 2
- formdata × 2
- forms × 2
- fsc × 2
- google maps × 2
- hosting × 2
- http × 2
- https × 2
- iis 8.0 × 2
- install × 2
- interactive × 2
- interface × 2
- iphone × 2
- iteratee × 2
- jobs × 2
- jquery mobile × 2
- keynote × 2
- lens × 2
- lenses × 2
- linux × 2
- listmodel × 2
- mac × 2
- numeric × 2
- oauth × 2
- obfuscation × 2
- offline × 2
- oop × 2
- osx × 2
- packaging × 2
- pattern matching × 2
- performance × 2
- pipelines × 2
- q&a × 2
- quotation × 2
- reference × 2
- released in Zafir.4.0.185.88-beta10 × 2
- rx × 2
- script × 2
- security × 2
- self host × 2
- seq × 2
- sockets × 2
- stm × 2
- tcp × 2
- trie × 2
- tutorials × 2
- type × 2
- url × 2
- var × 2
- websharper.charting × 2
- websharper4 × 2
- websockets × 2
- wig × 2
- xna × 2
- zh × 2
- .net interop × 1
- 2012 × 1
- 4.0.194.126 × 1
- 4.1.3.184 × 1
- 4.1.4.189 × 1
- 4.2.0.214-beta × 1
- 4.2.12.259 × 1
- 4.2.2.231-beta × 1
- 4.2.8.255 × 1
- Canvas Sample Example × 1
- DynamicStyle Animated Style × 1
- Fixed in 4.0.190.100-rc × 1
- Released in Zafir.UI.Next.4.0.169.79-beta10 × 1
- SvgDynamicAttribute × 1
- WebComponent × 1
- abstract class × 1
- accumulator × 1
- active pattern × 1
- actor × 1
- addin × 1
- agents × 1
- aggregation × 1
- agile × 1
- alter session × 1
- animation × 1
- anonymous object × 1
- apache × 1
- api × 1
- appcelerator × 1
- architecture × 1
- array × 1
- arrays × 1
- asp.net 4.5 × 1
- asp.net core × 1
- asp.net integration × 1
- asp.net mvc 4 × 1
- asp.net web api × 1
- aspnet × 1
- ast × 1
- attributes × 1
- authorization × 1
- b-tree × 1
- back button × 1
- badimageformatexception × 1
- bash script × 1
- batching × 1
- binding-vars × 1
- bistro × 1
- body × 1
- bundle × 1
- camtasia studio × 1
- cas protocol × 1
- charts × 1
- clarity × 1
- class × 1
- cli × 1
- clipboard × 1
- clojurescript × 1
- closures × 1
- cloud × 1
- cms × 1
- coding diacritics × 1
- color highlighting × 1
- color zones × 1
- combinator × 1
- combinators × 1
- compile × 1
- compile code on server × 1
- config × 1
- confirm × 1
- content × 1
- context × 1
- context.usersession × 1
- continuation-passing style × 1
- coords × 1
- cordova × 1
- cors × 1
- coursera × 1
- cross-domain × 1
- csla × 1
- current_schema × 1
- custom content × 1
- data × 1
- data grid × 1
- datetime × 1
- debug × 1
- declarative × 1
- delete × 1
- devexpress × 1
- dhtmlx × 1
- dictionary × 1
- directattribute × 1
- disqus × 1
- distance × 1
- do binding × 1
- doc elt ui.next upgrade × 1
- docker × 1
- dojo × 1
- dol × 1
- dom × 1
- domain × 1
- du × 1
- duf-101 × 1
- dynamic × 1
- eastern language × 1
- eclipse × 1
- edsl × 1
- em algorithm × 1
- emacs × 1
- emotion × 1
- enums × 1
- error × 1
- etw × 1
- euclidean × 1
- eventhandlerlist × 1
- examples × 1
- ext js × 1
- extension methods × 1
- extra × 1
- facet pattern × 1
- failed to translate × 1
- fake × 1
- fantomas × 1
- fear × 1
- float × 1
- form × 1
- form-data × 1
- forum × 1
- fp × 1
- frank × 1
- fsdoc × 1
- fsharp × 1
- fsharp.core × 1
- fsharp.powerpack × 1
- fsharpx × 1
- fsunit × 1
- function × 1
- functional style × 1
- game × 1
- games × 1
- gc × 1
- generic × 1
- geometry × 1
- getlastwin32error × 1
- getting-started × 1
- google × 1
- google.maps × 1
- grid × 1
- group × 1
- guide × 1
- hash × 1
- headers × 1
- hello world example × 1
- heroku × 1
- highchart × 1
- history × 1
- how to × 1
- html-templating × 1
- http405 × 1
- httpcontext × 1
- hubfs × 1
- i18n × 1
- ie 8 × 1
- if-doc × 1
- iis × 1
- image × 1
- images × 1
- inheritance × 1
- initialize × 1
- input × 1
- install "visual studio" × 1
- installer × 1
- int64 × 1
- interfaces × 1
- internet explorer × 1
- interop × 1
- interpreter × 1
- io × 1
- iobservable × 1
- ios × 1
- iot × 1
- ipad × 1
- isomorphic × 1
- javascript optimization × 1
- javascript semanticui resources × 1
- jquery-plugin × 1
- jquery-ui × 1
- jquery-ui-datepicker × 1
- js × 1
- kendo datasource × 1
- kendochart × 1
- kendoui compiler × 1
- knockout × 1
- l10n × 1
- learning × 1
- library × 1
- libs × 1
- license × 1
- licensing × 1
- lineserieszonescfg × 1
- local setting × 1
- localization × 1
- logging × 1
- loop × 1
- macros × 1
- mailboxprocessor × 1
- mapping × 1
- maps × 1
- markerclusterer × 1
- markup × 1
- marshal × 1
- math × 1
- mathjax × 1
- message × 1
- message passing × 1
- message-passing × 1
- meta × 1
- metro style × 1
- micro orm × 1
- minimum-requirements × 1
- mix × 1
- mobile installation × 1
- mod_mono × 1
- modal × 1
- module × 1
- mouseevent × 1
- mouseposition × 1
- multidimensional × 1
- multiline × 1
- multithreading × 1
- mysql × 1
- mysqlclient × 1
- nancy × 1
- native × 1
- nested × 1
- nested loops × 1
- node × 1
- nunit × 1
- object relation mapper × 1
- object-oriented × 1
- om × 1
- onboarding × 1
- onclick × 1
- optimization × 1
- option × 1
- orm × 1
- os x × 1
- output-path × 1
- override × 1
- paper × 1
- parameter × 1
- persistence × 1
- persistent data structure × 1
- phonegap × 1
- pola × 1
- post × 1
- powerpack × 1
- prefix tree × 1
- principle of least authority × 1
- privacy × 1
- private × 1
- profile × 1
- programming × 1
- project × 1
- project euler × 1
- projekt_feladat × 1
- protected × 1
- provider × 1
- proxy × 1
- ptvs × 1
- public × 1
- pure f# × 1
- purescript × 1
- qna × 1
- quant × 1
- query sitelet × 1
- question × 1
- quotations × 1
- range × 1
- raphael × 1
- razor × 1
- rc × 1
- reactjs × 1
- real-time × 1
- ref × 1
- region × 1
- released in 4.0.190.100-rc × 1
- reporting × 1
- responsive design × 1
- rest api × 1
- rest sitelet × 1
- restful × 1
- round table × 1
- router × 1
- routing × 1
- rpc reverseproxy × 1
- runtime × 1
- sales × 1
- sample × 1
- sampleapp × 1
- scriptcs × 1
- scripting × 1
- search × 1
- self hosted × 1
- semanticui × 1
- sequence × 1
- serialisation × 1
- service × 1
- session-state × 1
- sharepoint × 1
- signals × 1
- sitelet website × 1
- sitelet.protect × 1
- sitlets × 1
- slickgrid × 1
- source code × 1
- sqlentityconnection × 1
- ssl × 1
- standards × 1
- static content × 1
- stickynotes × 1
- streamreader × 1
- stress × 1
- strong name × 1
- structures × 1
- submitbutton × 1
- subscribe × 1
- svg example html5 websharper.ui.next × 1
- sweetalert × 1
- system.datetime × 1
- system.reflection.targetinvocationexception × 1
- table storage × 1
- targets × 1
- tdd × 1
- templates ui.next × 1
- templating × 1
- text parsing × 1
- three.js × 1
- time travel × 1
- tls × 1
- tooltip × 1
- tracing × 1
- tsunamiide × 1
- turkish × 1
- twitter-bootstrap × 1
- type erasure × 1
- type inference × 1
- type providers × 1
- type-providers × 1
- typeprovider × 1
- ui next forms × 1
- ui-next × 1
- ui.next jqueryui × 1
- ui.next charting × 1
- ui.next formlets × 1
- ui.next forms × 1
- ui.next suave visualstudio × 1
- ui.next templating × 1
- unicode × 1
- unittest client × 1
- upload × 1
- usersession × 1
- validation × 1
- vb × 1
- vb.net × 1
- vector × 1
- view.map × 1
- visal studio × 1
- visual f# × 1
- visual studio 11 × 1
- visual studio 2012 × 1
- visual studio shell × 1
- vs2017 compiler zafir × 1
- vsix × 1
- web api × 1
- web-scraping × 1
- webapi × 1
- webcomponents × 1
- webforms × 1
- webgl × 1
- webrtc × 1
- webshaper × 1
- websharper async × 1
- websharper codemirror × 1
- websharper f# google × 1
- websharper forms × 1
- websharper reactive × 1
- websharper rpc × 1
- websharper sitelets routing × 1
- websharper warp × 1
- websharper-interface-generator × 1
- websharper.chartsjs × 1
- websharper.com × 1
- websharper.exe × 1
- websharper.owin × 1
- websharper.ui.next × 1
- websharper.ui.next jquery × 1
- websockets iis × 1
- why-websharper × 1
- windows 7 × 1
- windows 8 × 1
- windows-phone × 1
- winrt × 1
- www.grabbitmedia.com × 1
- xamarin × 1
- xml × 1
- yeoman × 1
- yield × 1
- zafir beta × 1
- zafir websharper4 × 1
- zarovizsga × 1
![]() |
Copyright (c) 2011-2012 IntelliFactory. All rights reserved. Home | Products | Consulting | Trainings | Blogs | Jobs | Contact Us | Terms of Use | Privacy Policy | Cookie Policy |
Built with WebSharper |
Hi all... I had a crack at the classic TDD "Bowling Game" example in F#. The code is pretty short compared to doing it in C# / C++ . However I'd appareiciate any feedback on the actual code. Especially if I can simplify it.
The original article on the bowling game is [link:www.objectmentor.com]
Regards,
Keith<!--
{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;}??\fs28 #light\par ??\par ??\cf3 open\cf0 System\par ??\cf3 open\cf0 NUnit.Framework\par ??\par ??\cf3 let\cf0 \cf3 rec\cf0 score_bowls bowls =\par ?? \cf3 let\cf0 \cf3 rec\cf0 score_bowls' frame l = \par ?? \cf3 match\cf0 l \cf3 with\cf0 \par ?? | _ \cf3 when\cf0 frame = 10 \cf3 ->\cf0 (List.fold_right (\cf3 fun\cf0 x y \cf3 ->\cf0 x + y) l 0)\par ?? | [] \cf3 ->\cf0 0\par ?? | [f] \cf3 ->\cf0 f\par ?? | [f;s] \cf3 ->\cf0 f + s\par ?? | f :: s :: n :: tail \cf3 when\cf0 f = 10 \cf3 ->\cf0 10 + s + n + score_bowls' (frame+1) ( s :: n :: tail )\par ?? | f :: s :: n :: tail \cf3 when\cf0 (f + s) = 10 \cf3 ->\cf0 10 + n + score_bowls' (frame+1) (n :: tail)\par ?? | f :: s :: n :: tail \cf3 ->\cf0 f + s + score_bowls' (frame+1) (n :: tail)\par ?? score_bowls' 1 bowls\par ?? \par ??[<TestFixture>]\par ??\cf3 type\cf0 BowlingTestCases = \cf3 class\par ??\cf0 \cf3 new\cf0 () = \{\} \par ?? [<Test>]\par ?? \cf3 member\cf0 x.SimpleScoring() = Assert.AreEqual(6, score_bowls [1;2;3] )\par ?? [<Test>]\par ?? \cf3 member\cf0 x.ScoreSpare() = Assert.AreEqual(12, score_bowls [2;8;1] )\par ?? [<Test>]\par ?? \cf3 member\cf0 x.ScoreStrike() = Assert.AreEqual(16, score_bowls [10;1;2] )\par ?? [<Test>] \par ?? \cf3 member\cf0 x.ScorePerfectGame() = Assert.AreEqual( 300, score_bowls [\cf3 for\cf0 i \cf3 in\cf0 1..12 \cf3 ->\cf0 10] )\par ?? [<Test>] \par ?? \cf3 member\cf0 x.SpareLastFrame() = Assert.AreEqual( 11, score_bowls ([\cf3 for\cf0 i \cf3 in\cf0 1..18 \cf3 ->\cf0 0] @ [2;8;1]) )\par ?? [<Test>] \par ?? \cf3 member\cf0 x.StrikeLastFrame() = Assert.AreEqual( 21, score_bowls ([\cf3 for\cf0 i \cf3 in\cf0 1..18 \cf3 ->\cf0 0] @ [10;10;1]) )\par ??\cf3 end\par ??\par ??}
-->
#light
open System
open NUnit.Framework
let rec score_bowls bowls =
let rec score_bowls' frame l =
match l with
| _ when frame = 10 -> (List.fold_right (fun x y -> x + y) l 0)
| [] -> 0
| [f] -> f
| [f;s] -> f + s
| f :: s :: n :: tail when f = 10 -> 10 + s + n + score_bowls' (frame+1) ( s :: n :: tail )
| f :: s :: n :: tail when (f + s) = 10 -> 10 + n + score_bowls' (frame+1) (n :: tail)
| f :: s :: n :: tail -> f + s + score_bowls' (frame+1) (n :: tail)
score_bowls' 1 bowls
[<TestFixture>]
type BowlingTestCases = class
new() = {}
[<Test>]
member x.SimpleScoring() = Assert.AreEqual(6, score_bowls [1;2;3] )
[<Test>]
member x.ScoreSpare() = Assert.AreEqual(12, score_bowls [2;8;1] )
[<Test>]
member x.ScoreStrike() = Assert.AreEqual(16, score_bowls [10;1;2] )
[<Test>]
member x.ScorePerfectGame() = Assert.AreEqual( 300, score_bowls [for i in 1..12 -> 10] )
[<Test>]
member x.SpareLastFrame() = Assert.AreEqual( 11, score_bowls ([for i in 1..18 -> 0] @ [2;8;1]) )
[<Test>]
member x.StrikeLastFrame() = Assert.AreEqual( 21, score_bowls ([for i in 1..18 -> 0] @ [10;10;1]) )
end