@@ -20,20 +20,33 @@ parens = Token.parens lexer
2020brackets = Token. brackets lexer
2121semi = Token. semi lexer
2222semiSep = Token. semiSep lexer
23+ whiteSpace = Token. whiteSpace lexer
2324
2425type Position = (Int , Int )
25- type DataPoint = (String , String )
26- type HeaderInfo = (Double , Double )
27- data Game = Game Double Double [Position ]
26+ type DataPoint = (String , [String ])
27+ type HeaderInfo = (Double , Double , [Position ])
28+ data Game = Game Double Double [Position ] [Position ]
29+
30+ skipParentheses :: Parser ()
31+ skipParentheses = do
32+ many $ noneOf [' (' , ' )' ]
33+ (char ' )' *> return () )
34+ <|> (char ' (' *> skipParentheses *> skipParentheses)
35+ <|> skipParentheses
2836
2937dataPoint :: Parser DataPoint
3038dataPoint = do
3139 dataType <- identifier
32- argument <- brackets . many $ noneOf [' ]' ]
40+ argument <- many1 . brackets . many $ (try $ char ' \\ ' *> char ' ] ' ) <|> noneOf [' ]' ]
3341 return $ (dataType, argument)
3442
43+ dataPoints :: Parser [DataPoint ]
44+ dataPoints = many $ (try $ (many $ char ' (' *> skipParentheses *> whiteSpace) *> dataPoint)
45+ <|> dataPoint
46+
3547convertMove :: String -> Position
3648convertMove (x : y : _) = (ord x - 97 , ord y - 97 )
49+ convertMove _ = (19 , 19 )
3750
3851validateMove :: Position -> Parser Position
3952validateMove (x, y) = if (x, y) >= (0 , 0 ) && (x, y) <= (19 , 19 )
@@ -42,47 +55,57 @@ validateMove (x, y) = if (x, y) >= (0, 0) && (x, y) <= (19, 19)
4255
4356move :: Parser Position
4457move = do
45- dataPoints <- many dataPoint
46- validateMove $ foldr find (0 , 0 ) dataPoints
47- where find (f, a ) r = if f == " W"
48- then convertMove a
58+ dps <- dataPoints
59+ validateMove $ foldr find (0 , 0 ) dps
60+ where find (f, as ) r = if f == " W"
61+ then case as of (a : _) -> convertMove a
4962 else if f == " B"
50- then convertMove a
63+ then case as of (a : _) -> convertMove a
5164 else r
5265
53- convertScore :: String -> Maybe Double
54- convertScore (c : _ : s) = if c == ' B'
66+ readScore :: String -> Maybe Double
67+ readScore (c : _ : s) = if c == ' B'
5568 then readMaybe s >>= \ x -> Just $ - 1.0 * x
5669 else readMaybe s
5770
71+ readHandicapPositions :: [String ] -> Parser [Position ]
72+ readHandicapPositions as = mapM (validateMove . convertMove) as
73+
5874header :: Parser HeaderInfo
5975header = do
6076 dataPoints <- many dataPoint
61- let r = foldr find (Nothing , Nothing ) dataPoints
77+ let r = foldr find (Nothing , Nothing , Nothing ) dataPoints
6278 case r of
63- (Nothing , _) -> fail " Couldn't read komi"
64- (_, Nothing ) -> fail " No final score"
65- (Just k, Just s) -> return (k, s)
66- where find (f, a) (k, s) = if f == " KM"
67- then (readMaybe a, s)
79+ (Nothing , _, _) -> fail " Couldn't read komi"
80+ (_, Nothing , _) -> fail " Couldn't read final score"
81+ (Just k, Just s, Nothing ) -> return (k, s, [] )
82+ (Just k, Just s, Just as) -> do
83+ hp <- readHandicapPositions as
84+ return (k, s, hp)
85+ where find (f, as) (k, s, hp) = if f == " KM"
86+ then case as of (a : _) -> (readMaybe a, s, hp)
6887 else if f == " RE"
69- then (k, convertScore a)
70- else (k, s)
71-
88+ then case as of (a : _) -> (k, readScore a, hp)
89+ else if f == " AB"
90+ then (k, s, Just as)
91+ else (k, s, hp)
92+
7293game :: Parser Game
7394game = parens $ semi *> do
74- (komi, score) <- header
95+ (komi, score, handicapPositions ) <- header
7596 semi
7697 moves <- semiSep move
77- return $ Game komi score moves
98+ many $ char ' (' *> skipParentheses *> whiteSpace
99+ return $ Game komi score handicapPositions moves
78100
79101parseFile :: FilePath -> IO (Either ParseError Game )
80- parseFile f = parseFromFile ( game <* eof) f
102+ parseFile f = parseFromFile game f
81103
82104instance Show Game where
83- show (Game komi score moves) =
84- let h = show komi ++ " " ++ show score
85- in h ++ foldr runMoves " " moves
105+ show (Game komi score handicaps moves) =
106+ let h = show komi ++ " " ++ show score ++ " " ++ show (length handicaps)
107+ in let h' = h ++ foldr runMoves " " handicaps
108+ in h' ++ foldr runMoves " " moves
86109 where runMoves (x, y) r = " \n " ++ show x ++ " " ++ show y ++ r
87110
88111main = do
0 commit comments