如何在集合上使用模式匹配

时间:2015-11-15 17:56:09

标签: f#

我可以在集合上使用模式匹配吗?

我有一个代表一个井字棋盘的网格。

如何使用模式匹配来识别“X”或“O”的条纹?

到目前为止,我构建了一个这样的网格:

// ----------------
//  0 |  1  |  2  |
// ----------------
//  3 |  4  |  5  |
// ----------------
//  6 |  7  |  8  |
// ----------------

type Marker =
| X = 0
| O = 1
| NULL = 3

let cells = [0..8]
let grid = [for cell in cells -> (cell, Marker.NULL)]

let streakExists = 
   match grid with
   | ???
   | ???

所以我想使用模式匹配来识别如下所示的条纹:

//如果网格。[.. 2]都有X

//或grid。[3..5]都有X

//或grid。[6..8]都有X

//返回true

// -----------------

//如果grid。[0; 3; 6;]都有X

//或grid。[1; 4; 5]都有X

//或grid。[2; 5; 8]都有X

//返回true

// ------------------

//如果grid。[0; 4; 8;]都有X

//返回true

注意:

我正在学习F#的基础知识。 如果这个问题显而易见,请原谅我。

3 个答案:

答案 0 :(得分:4)

你可以在集合上使用模式匹配,但是在很多情况下你必须覆盖tic-tac-toe,因此它可能不是最好的选择。

如果我稍微简化你的代码(使用一个有区别的联合而不是enum并只使用一个有区别的联合的值列表),它将如下所示:

type Marker =
  | X
  | O
  | NULL 

let grid = [ for cell in 0 .. 8 -> NULL ]

let streakExists = 
   match grid with
   | [X;X;X;_;_;_;_;_;_] 
   | [_;_;_;X;X;X;_;_;_] 
   | [_;_;_;_;_;_;X;X;X] -> "X wins"
   | _ -> "Not sure"

这样可行,但您可以看到覆盖所有案例的难度。如果我想解决同样的问题,我可能会以不同的方式写出来。您可以创建一个列表,列出网格中所有可能的条纹:

let streaks = 
  [ for row in [0;3;6] do      // Generate one streak for each row
      yield [row;row+1;row+2]
    for col in [0;1;2] do      // Generate one streak for each column
      yield [col;col+3;col+6]
    yield [0;4;8]              // Explicitly add two 
    yield [2;4;6] ]            // diagonal streaks

现在,您可以通过测试是否存在任何条纹(来自grid)来检查streaks是否包含连胜,以便所有指定索引的值均为X或{{1 }}。这应该很容易与OList.forall

一起使用

答案 1 :(得分:2)

正如Tomas所写,将SELECT names FROM Workers WHERE names LIKE (??r -------The name can have 22 characters though. 类型简化为歧视联盟会更容易:

Marker

此外,由于电路板太小,您可以将其保存为八个值的列表:

type Marker = X | O | NULL

我同意Tomas的看法,模式匹配可能不是解决这个问题的最佳方法,但为了完整起见,你可以制作有点明显地传达他们匹配的模式的匹配: / p>

let grid = List.init 8 (fun _ -> NULL)

答案 2 :(得分:1)

如果您直接将模式匹配到网格,我不确定语法是否会非常好,您的选项是:

let streakExists grid =
    match grid with
    |[Marker.X; Marker.X; Marker.X; _; _; _; _; _; _] -> true
    |[_; _; _; Marker.X; Marker.X; Marker.X; _; _; _] -> true
    |[_; _; _; _; _; _; Marker.X; Marker.X; Marker.X] -> true
     ...
    | _ -> false

let streakExists grid =
    match grid with
    |Marker.X :: Marker.X :: Marker.X :: _ -> true
    | _ :: _ :: _ :: Marker.X :: Marker.X :: Marker.X :: _ -> true
    | _ :: _ :: _ :: _ :: _ :: _ :: Marker.X :: Marker.X :: Marker.X :: []  -> true
     ...
    | _ -> false

(这个选项并不理想,因为它可能会在大小不正确的网格上返回true,所以不要使用它,我只想演示语法。)

您可以创建一个函数来模式匹配3个集合中的列表:

let streakExists grid =
    let checkListOf3 list =
        match list with
        |[Marker.X; Marker.X; Marker.X] -> true
        |_ -> false
    if grid.[0..2] |> checkListOf3 then true
    elif grid.[3..5] |> checkListOf3 then true
    elif grid.[6..8] |> checkListOf3 then true
     ...
    else false

修改

你可以将最后一种方法与Tomas使用他的streaks建议的方法结合起来:

let streakExists grid =
    let checkListOf3 list =
        match list with
        |[Marker.X; Marker.X; Marker.X] -> true
        |_ -> false
    streaks |> List.exists (List.map (fun i -> List.item i grid) >> checkListOf3)