``````data Cell = E
| X
| O
deriving (Eq,Show)

type Row a = [a]
type Board = Row (Row Cell)

iniBoard :: Int -> Board
iniBoard n = let row = replicate n E in replicate n row
``````

``````win :: Cell -> Board -> Bool
win E _   = False
win x brd = any full \$diags brd ++ rows brd ++ cols brd
where
diags brd = mainDiag : [secondDiag]
mainDiag = zipWith (!!) brd [0..]
secondDiag = zipWith (!!) revBrd [0..]
revBrd = do
xs <- brd
return (reverse xs)
rows = id
cols = transpose
full xs = all (==x) xs
``````

``````nxt :: Cell -> Board -> [Board]
nxt x brd = do
if (win x brd || win (switch x) brd)
then
[]
else
undefined
``````

``````picks :: [x] -> [([x], x, [x])]
picks [] = []
picks (x : xs) = ([] , x, xs) : [(x : sy, y, ys) | (sy, y, ys) <- picks xs]
``````

(这是this的调整版),所有可能的下一个板都是

``````import Data.List.Split (chunksOf)

next :: Int -> Cell -> Board -> [Board]
next n who b =
picks (concat b) >>= \(sy, y, ys) ->
case y of E -> [chunksOf n \$sy ++ [who] ++ ys] ;
_ -> []
``````

``````next n who b = [ chunksOf n \$sy ++ [who] ++ ys
| (sy, E, ys) <- picks \$concat b ]
``````

picks函数在连接的行中一个接一个地拾取所有可能的单元格,同时保留前缀和后缀; chunksOf n从一排长的单元格中重建板,连续排列成n个单元格.因此整体效果是所有可能的电路板列表,其中E被替换为谁.

``````next n who b =  do
(sy, E, ys) <- picks \$concat b
return (chunksOf n \$sy ++ [who] ++ ys])
``````

edit2：一个基于Data.List的代码,它通过输入一次性完成,是

``````import Data.List (mapAccumL)

-- mapAccumL :: (acc -> x -> (acc, y)) -> acc -> [x] -> (acc, [y])
next who b = concat . snd \$mapAccumL f (id, drop 1 xs) xs
where
xs = concat b
n = length b
f (k,r) x = ( (k.(x:), drop 1 r) , [chunksOf n \$k (who:r) | x==E] )
``````