检查玩家是否在井字游戏中获胜

Check if a player wins in a tic tac toe game

作为 Haskell 初学者,我编写了一款井字游戏。在游戏的第一个版本中,我使用 9 元组来表示游戏板。我曾经这样检查获胜条件;

checkWinner :: Board -> Maybe Player
checkWinner (X,X,X,_,_,_,_,_,_) = Just Player1
checkWinner (_,_,_,X,X,X,_,_,_) = Just Player1
... same thing continues

现在我正在尝试更改我的代码以改为使用数组,但我不知道如何检查获胜条件。 haskell 中缺少循环让我很难为此制定算法。

这是我当前的代码;

import Data.Array

data Tile   = EmptyTile | X | O
data Player = Player1 | Player2

showTile :: Tile -> String
showTile EmptyTile = " "
showTile X         = "X"
showTile O         = "O"

type Board = Array (Int,Int) Tile

emptyBoard :: Board
emptyBoard = array ((1,1),(3,3)) [((x,y), EmptyTile) | x <- [1,2,3], y <- [1,2,3]]

put :: Board -> Tile -> Int -> Int -> Maybe Board
put b t x y = case b!(x,y) of
                EmptyTile -> Just (b // [((x,y), t)])
                _         -> Nothing

p1wins, p2wins :: Board -> Bool
p1wins b = tileWins b X
p2wins b = tileWins b O

-- will be called with a board and either x or o
-- and it will tell whether that tile wins
tileWins :: Board -> Tile -> Bool
tileWins b t = 

如何在 haskell 中实现 tileWins 功能?

如果你想对元组做同样的事情,你会做:

if ((b ! 0 ! 0) == t
    && (b ! 0 ! 1) == t
    && (b ! 0 ! 2) == t)
   || ((b ! 1 ! 0) == t
    && (b ! 1 ! 1) == t
    ...

您可以使用获胜指数列表并对其进行处理,从而节省几行代码。

此外,正如@chi 指出的(我的猜测),tileWinsp1winsp2wins 应该 return 和 Bool.

data Tile   = EmptyTile | X | O deriving Eq

tileWins :: Board -> Tile -> Bool
tileWins b t = 
   any (\row -> all (\col -> b!(row,col) == t) [1..3]) [1..3] ||
   any (\col -> all (\row -> b!(row,col) == t) [1..3]) [1..3] ||
   all (\rc -> b!(rc,rc) == t) [1..3] ||
   all (\rc -> b!(rc,4-rc) == t) [1..3]

说明:要t赢得以下其中一项必须申请

  • 必须存在一个 row 使得在所有 column 个位置我们找到 t
  • 必须存在一个 column 使得在所有 row 个位置我们找到 t
  • 在主对角线上我们找到三个 ts
  • 在另一条对角线上我们找到三个 ts