Explain Manillen with types and Elm

Let's try to explain the card game Manillen in Elm.

At Domain Drive Design Europe I met the wonderful @Felienne. In the evening we played the card game bridge (a game the Felienne likes a lot). As a West-Vlaming I love the card game Manillen more, of course, and we joked about it. Felienne has the ambition to create an AI to compete at the world championship of Computer Bridge, and I have joked about some similar ambitions of mine at Socrates Belgium, but this blog post has a much more humble goal. I want to try to explain the rules of Manillen or Manille to you with Elm. If you are to eager and want to find out more about the game (and the rules), see wikipedia.

So lets start.

These are the valid cards:

type Suit = Spade | Club | Diamond | Heart
type Rank = Manille | Ace | King | Queen | Jack | Nine | Eight | Seven

type alias Card = (Suit, Rank)

The Manille is the number 10 in a card deck.

The game is played with 32 cards (4 * 8), thus, this is the full deck:

type alias Deck = List Card

deck : Deck
deck = 
	[ (Spade, Manille), (Club, Manille), (Diamond, Manille), (Heart, Manille)
	, (Spade, Ace),     (Club, Ace),     (Diamond, Ace),     (Heart, Ace)
	, (Spade, King),    (Club, King),    (Diamond, King),    (Heart, King)
	, (Spade, Queen),   (Club, Queen),   (Diamond, Queen),   (Heart, Queen)
	, (Spade, Jack),    (Club, Jack),    (Diamond, Jack),    (Heart, Jack)
	, (Spade, Nine),    (Club, Nine),    (Diamond, Nine),    (Heart, Nine)
	, (Spade, Eight),   (Club, Eight),   (Diamond, Eight),   (Heart, Eight)
	, (Spade, Seven),   (Club, Seven),   (Diamond, Seven),   (Heart, Seven)
	]

or shorter we could write it like this:

suits =
  [ Spade, Club, Diamond, Heart ]


allCardsOfRank rank =
  suits |> List.map (\suit -> ( suit, rank ))


ranks =
  [ Manille, Ace, King, Queen, Jack, Nine, Eight, Seven ]


deck : List Card
deck =
  ranks |> List.concatMap allCardsOfRank

but I find the longer version more readable.

So to start playing we need players:

type Player
  = Front
  | Left
  | Back
  | Right


wulder : ( Player, Player )
wulder =
  ( Front, Back )


zulder : ( Player, Player )
zulder =
  ( Left, Right )

We play in 2 teams, wulder vs zulder (West-Flemish for we and them)

Before we start playing, I’m going to explain how the scoring works and how you can win a game.

points : Rank -> Int
points rank =
  case rank of
    Manille ->
      5

    Ace ->
      4

    King ->
      3

    Queen ->
      2

    Jack ->
      1

    _ ->
      0


score : List Card -> Int
score cards =
  let
    ranks =
      List.map snd cards

    allpoints =
      List.map points ranks
  in
    List.sum allpoints

With elm-test we can see a constraint

[ test "A full deck scores always 60" ((score deck) `assertEqual` 60) ]

And with elm-check (a toolkit for writing property based tests) we see these properties:

Thomas Coopman

Software Consultant