我正在编写一个函数,它可以用FEN表示法(从国际象棋中得知)获取一个字符串。一个空的3x 3棋盘将是:
,,/,,/,,
字符串
在每个单元格上,可以有多个块相互堆叠,可以是白色(w)或黑色(b)。例如,有效位置为:
bwb,,b/,,/w,w,w
型
我使用以下数据类型:
data Player = Red | Blue deriving Show
data Cell = Stack [Player] | Empty deriving Show
type Board = [[Cell]]
型
我需要将一个FEN_String转换成一个board. I想首先将原始字符串拆分成'/'上的单独列表,但后来我陷入了如何以最好的方式处理结果列表的困境。
还有什么比大小写匹配更好的吗?我不想涵盖每一种可能的情况,我已经为一个不同的游戏做过一次了:
buildBoard :: String -> Board
buildBoard [] = [[]]
buildBoard xs = (chunksOf 9 ([Empty] ++ buildboardHelper xs))
buildboardHelper :: String -> [Cell]
buildboardHelper (a:b:c:d:rest)
| (a == ',' && b == 'w') = buildboardHelper (b:c:d:rest)
| (a == ',' && b == 'b') = buildboardHelper (b:c:d:rest)
| (a == '/' && b == ',') = [Empty] ++ buildboardHelper (b:c:d:rest)
| (a == '/' && b == 'w') = buildboardHelper (b:c:d:rest)
| (a == '/' && b == 'b') = buildboardHelper (b:c:d:rest)
| (a == ',' && b == '/') = [Empty] ++ buildboardHelper (b:c:d:rest)
| (a == ',' && b == ',' && c == ',' && d ==',') = [Empty] ++ [Empty] ++ buildboardHelper (c:d:rest)
| (a == ',' && b == ',') = [Empty] ++ buildboardHelper (b:c:d:rest)
| (a == 'w' && isDigit b && isDigit c && isDigit d) = let number = (read ([b,c,d]) :: Int) in [Piece White number] ++ buildboardHelper (rest)
| (a == 'w' && isDigit b && isDigit c) = let number = (read ([b,c]) :: Int) in [Piece White number] ++ buildboardHelper (d:rest)
| (a == 'w' && isDigit b) = let number = (read ([b]) :: Int) in [Piece White number] ++ buildboardHelper (c:d:rest)
| (a == 'b' && isDigit b && isDigit c && isDigit d) = let number = (read ([b,c,d]) :: Int) in [Piece Black number] ++ buildboardHelper (rest)
| (a == 'b' && isDigit b && isDigit c) = let number = (read ([b,c]) :: Int) in [Piece Black number] ++ buildboardHelper (d:rest)
| (a == 'b' && isDigit b) = let number = (read ([b]) :: Int) in [Piece Black number] ++ buildboardHelper (c:d:rest)
| otherwise = [Empty]
buildboardHelper [',',','] = [Empty] ++ [Empty]
buildboardHelper [','] = [Empty]
型
1条答案
按热度按时间ykejflvf1#
还有什么比大小写匹配更好的吗?我不想涵盖每一种可能的情况,我已经为一个不同的游戏做过一次了:
我强烈建议使用解析器库,而不是手动解析。这只会让情况变得更糟。手动解析通常很复杂:有很多情况需要覆盖,大多数手动解析器不允许在另一个解析器中轻松重用逻辑。
例如,我们可以使用
parsec
。这个库允许将非常简单的解析器合并组合成更复杂的解析器。例如,我们可以首先为单个
Player
项创建一个解析器:字符串
现在我们可以使用
Cell
的player
解析器:型
最后,我们为
Board
创建一个解析器:型
现在我们定义了解析器,我们可以运行
board
解析器:型
因此,它返回一个
Right …
,这意味着解析是成功的,乍一看,它看起来正确地解析了流。最好的事情可能是,我们不仅得到了
Board
的解析器,而且还得到了Cell
和Player
的解析器,我们可以独立使用和合并。