# Tally Calculator for Baloot in F#

This is a tally calculator for the Saudi card game Baloot. As in, they're a set of functions so that the user would provide their winnings at the end of a round (card captured, projects declared, etc) and the functions would give them the score for themselves and their opponent.

Domain Model

(I listed most of these types in one line for vertical brevity).

// Types
type Team = Us | Them
type Suit = Hearts | Diamonds | Clubs | Spades
type Rank = Ace | King | Queen | Jack | Ten | Nine | Eight | Seven
type Card =
{ Rank : Rank
Suit : Suit }
type Mode = Sun | Trump of Suit
type Project = Sira | Fifty | Hundred | FourHundred | Baloot
type Hand =
{ Mode : Mode
Captured : Card list
Projects : Project list
Ground : bool
Bettor : Team
Owner : Team }

Point Tally functions
// Trick Total Point Calculations
let sunTrickPts card =
match card.Rank with
| Ace -> 11
| Ten -> 10
| King -> 4
| Queen -> 3
| Jack -> 2
| _ -> 0

let trumpTrickPts card trump =
match (card.Rank, card.Suit) with
| (Jack, s) when s = trump -> 20
| (Nine, s) when s = trump -> 14
| _ -> sunTrickPts card

let capturedTrickPts hand =
match hand.Mode with
| Sun ->
hand.Captured
|> List.fold (fun acc card -> acc + (sunTrickPts card)) 0
| Trump(suit) ->
hand.Captured
|> List.fold (fun acc card -> acc + (trumpTrickPts card suit)) 0
+ if hand.Ground then 10
else 0

// Captured Cards Point Calculations
let sunHandPts pts =
match pts % 10 with
| 5 -> pts
| n when n < 5 -> pts - n
| n -> pts - n + 10
/ 5

let trumpHandPts pts =
match pts % 10 with
| n when n <= 5 -> pts - n
| n -> pts - n + 10
/ 10

let capturedHandPts hand =
let pts = capturedTrickPts hand
match hand.Mode with
| Sun -> sunHandPts pts
| Trump(_) ->
match pts % 10, hand.Bettor with
| 6, t when t = hand.Owner -> (trumpHandPts pts) - 1
| _ -> trumpHandPts pts

// Project Points Calculations
let sunProjectPts =
function
| Sira -> 4
| Fifty -> 10
| Hundred -> 20
| FourHundred -> 40
| _ -> 0

let trumpProjectPts =
function
| Sira | Baloot -> 2
| Fifty -> 5
| Hundred | FourHundred -> 10

let projectHandPts hand =
let projectPts =
match hand.Mode with
| Sun -> sunProjectPts
| Trump(_) -> trumpProjectPts
hand.Projects |> List.fold (fun acc pro -> acc + (projectPts pro)) 0

// Total Point for Hand
// TARGET FUNCTION
let handPts hand = (capturedHandPts hand) + (projectHandPts hand)

Functions to test the logic.
// Type Creations
let newCard (rank, suit) =
{ Card.Rank = rank
Card.Suit = suit }

let newHand (mode, captured, projects, ground, bettor, owner) =
{ Hand.Mode = mode
Hand.Captured = captured
Hand.Projects = projects
Hand.Ground = ground
Hand.Bettor = bettor
Hand.Owner = owner }

// The Other Team
let opp =
function
| Us -> Them
| Them -> Us

open Microsoft.FSharp.Reflection

// Deck Creation and Shuffling
let fullDeck =
let suits = FSharpType.GetUnionCases typeof<Suit>
let ranks = FSharpType.GetUnionCases typeof<Rank>
[ for s in suits do
let suit = FSharpValue.MakeUnion(s, [||]) :?> Suit
for r in ranks do
let rank = FSharpValue.MakeUnion(r, [||]) :?> Rank
yield newCard (rank, suit) ]

let shuffleDeck deck =
let r = new System.Random()
deck |> List.sortBy (fun _ -> r.Next())

let cutDeck deck =
let rand = new System.Random()
let rInt = rand.Next(0, 7) * 4
deck |> List.splitAt rInt

// Randomized Hand Creation for testing
let createTestHands (mode) =
let rInt = System.Random().Next(100)
let rBool = rInt % 2 = 0

let rBettor, rOwner =
match rInt % 4 with
| 0 -> Us, Us
| 1 -> Us, Them
| 2 -> Them, Them
| _ -> Them, Us

let capped1, capped2 =
fullDeck
|> shuffleDeck
|> cutDeck

let hand1 = newHand (mode, capped1, [], rBool, rBettor, rOwner)
let hand2 = newHand (mode, capped2, [], not rBool, opp rBettor, opp rOwner)
hand1, hand2


I used that last function to test the handPts function on random shuffled sets of hands.

PS. Is there a simpler method to generate the fullDeck? Reflection seems to be a bit of an overkill.

• I really love the F# type system. It reads like a formal language grammar. – RubberDuck Jul 6 '16 at 20:40

In my opinion, the code is pretty good. The only thing:

In function trumpTrickPts all versions share the same "guarding rules".

So, you can write:

let trumpTrickPts card trump =
match (card.Rank, card.Suit = trump) with
| (Jack, true) -> 20
| (Nine, true) -> 14
| _ -> sunTrickPts card


Instead of reflection, you can enumerate all the options in the list:

let fullDeck =
let suits =
let ranks =
[Ace ; King ; Queen ; Jack ; Ten ; Nine ; Eight ; Seven]

[for s in suits do
for r in ranks ->
newCard (r, s) ]


In the function shuffleDeck you creating a new Random inside the function. By default, Random "starts" with the current system clock. So, if you quickly run two stirring new deck, you'll get same results:

Example

Since you are using Random in several function, then better to "take away" it.

Instead of rand.Next(0, 7) * 4 you can use rand.Next(7) * 4

let rand = System.Random()

let shuffleDeck deck =
deck |> List.sortBy (fun _ -> rand.Next())

let cutDeck deck =
let rInt = rand.Next(7) * 4
deck |> splitAt rInt

// Randomized Hand Creation for testing
let createTestHands (mode) =
let rInt = rand.Next(100)
...