F# 建模扑克牌

F# modeling playing cards

我正在尝试代表 standard playing cards in F#. My goal is to implement a clone of Microsoft Solitaire(Windows 附带的游戏),这是一款卡牌花色、牌面和颜色很重要的游戏。本练习的主要目的是作为学习 F# 的一种方式。

我考虑过使用歧视工会:

type Suit =
    | Diamonds
    | Hearts
    | Clubs
    | Spades

type Color =
    | Red
    | Black

type Face =
    Two | Three | Four | Five | Six | Seven |
    Eight | Nine | Ten | Jack | Queen | King | Ace

卡的记录类型:

type Card = {
    suit: Suit;
    face: Face;
    color: Color;
}

但是,一张牌的颜色可以从它的花色推断出来——所有的方块和红心都是红色的,所有的梅花和黑桃都是黑色的。西装不能仅从颜色来确定。也许这样的事情是合适的:

type Suit =
    | Diamonds of Color //should always be red
    | Hearts of Color //should always be red
    | Clubs of Color //should always be black
    | Spades of Color //should always be black

type Face =
    Two | Three | Four | Five | Six | Seven |
    Eight | Nine | Ten | Jack | Queen | King | Ace

type Card = {
    suit: Suit;
    face: Face;
}

但这似乎不对,因为这允许不正确的组合,例如黑心红桃。

我的问题是:

  1. 考虑到 Color 依赖于 Suit,处理 Suit 和 Color 最惯用的方法是什么?
  2. 是否应该明确表示颜色的概念?理论上可以将所有出现的颜色替换为与方块或红心(红色)和梅花或黑桃(黑色)匹配的图案。

由于 Color 总是可以从 Suit 中推断出来,因此没有理由对其进行显式建模;你会想要 illegal states unrepresentable.

您仍然可以从您的模型中获得很好的编程体验,并且可以使用 Active Pattern:

来很好地建模颜色
type Suit =
    | Diamonds
    | Hearts
    | Clubs
    | Spades

let (|Red|Black|) suit =
    match suit with
    | Diamonds | Hearts -> Red
    | Clubs | Spades -> Black

这将使您能够在 Suit 上进行模式匹配,就像这个空洞的例子:

let printColor card =
    match card.Suit with
    | Red -> "Red"
    | Black -> "Black"

来自 FSI 的用法示例:

> printColor { Suit = Spades; Face = Ace };;
val it : string = "Black"
> printColor { Suit = Diamonds; Face = King };;
val it : string = "Red"

您可以添加录音方式:

type Card = 
    {suit: Suit;face: Face}
    member this.Color = 
        match this.suit with
            | Diamonds | Hearts -> Red
            | Clubs | Spades -> Black

示例:

let v = {suit = Diamonds;face = Two}
printfn "%A" v.Color

let v1 = {suit = Clubs;face = Two}
printfn "%A" v1.Color

红色 黑色的 按任意键继续。 . .