Parsec の使い方を学ぶために昔の宿題をやり直しているのですが、Exit (および含まれているデータ型) のパーサーを構築するのに苦労しています。まず、部屋のリストを含むファイルを取得します。各部屋には、部屋の名前 (以下 -- 部屋 --)、いくつかの説明またはストーリー、そして の形式の出口のリストが含まれています(direction, destination)
。最終的に人が方向を選択し、部屋の名前を調べてプレーヤーを次の部屋に連れて行きます。
-- Room --
Center
You are in a square room. There are doors to the
north, south, east, and west.
-- Exits --
North: North Hall
South: South Room
East: East Room
West: West Room
-- Room --
North Hall
You are in a hallway. There are doors to the north and south.
ご覧のとおり、一部の部屋には出口がありません(私が保管している方法はありません)。したがって、Maybe Exits が存在する可能性があります。
exits 部分まで到達し、そのステップの前にすべてのパーサーが機能しているようです。問題は、出口がないか、複数の出口がある可能性があるという事実を処理することです。また、Exit の処理方法は、Exit タイプの処理方法に影響すると思います (別名タイプ Exit は、たぶん [ Exit ] になる可能性があります)。
とにかくここに私のコードがあります:
--module Loader
-- Game parser will go here
--
import Text.ParserCombinators.Parsec
import Data.List.Split
astory = unlines [" -- Room --",
"Cell",
"You have been locked in a dungeon cell. The prisoner next",
"to you whipsers, there's a tunnel behind the bed on the",
"south wall. Good Luck!",
"-- Exits --",
"South: Tunnel"]
type Rooms = [Room]
type Story = String
type Destination = String
data Exit = Exit { direction :: Direction, destination :: Destination } deriving (Ord, Show, Eq)
type Exits = [ Exit ]
data Room = Room { name :: String
, story :: String
, exits :: Exits
} deriving (Ord, Show, Eq)
data Direction = Nothing | North | South | East | West | Quit deriving (Ord, Show, Eq)
an_exit = "North: Tunnel \n"
a_full_exit = "-- Exits --\nSouth: Tunnel"
directionParser :: Parser Direction
directionParser = (string "South:" >> return South)
<|> (string "North:" >> return North)
<|> (string "East:" >> return East)
<|> (string "West:" >> return West)
parseExit :: Parser Exit
parseExit = do
direction <- directionParser
spaces
destination <- many (noneOf "\n")
return $ Exit direction destination
parseExits :: Parse Exits
parseExits = do
string "-- Exits --\n"
--oneRoom :: Parser Room
--oneRoom = do
-- string "--Room--\n"
-- name <- many (noneOf "\n")
-- newline
-- story <- manyTill anyChar (string "-- Exits --")
-- optionMaybe (string "-- Exits --")
-- exits <- optionMaybe $ many1 anyExits
-- return $ Room name story exits
--main = do
-- file <- readFile "cave.adventure"
-- let stories = splitOn "\n\n" file
-- mapM putStrLn stories
私は現在、小さなパーサーをテストしていたので、部屋をコメントアウトしました。
私のアプローチ:
- 解析する parseExits -- Exits -- と「多数の parseExit」を作成します。
- --Exit-- が見つからない場合、パーサーは失敗します (その場合は Nothing を返すと思います)
- oneRoom パーサーで、0 個または多数の parseExits または eof を探します (\n\n で事前に分割しているため)
質問:
- parsec docs optionMaybe または optional に従って none または many をどのように行うのですか? 出口または1つの部屋で?簡単にアクセスできるドキュメント
- ミニパーサーを扱う私のアプローチは、この問題を haskell と parsec で扱う正しい方法ですか?
- 最後に、oneRoom は現在 \n\n で分割されたファイル文字列を受け取りますが、それを oneRoom パーサーの正しい最後の行としてパーサーに含めることができると思いますか?
- 私の oneRoom パーサーでは、現在 Story を終了する要素として解析しています -- Exit -- しかし、ストーリーが次の -- Exits -- または eof を消費しないとは確信していませんか? Story パーサーを最初の -- 終了 -- 検出または eof (またはファイル全体を解析する場合は \n\n) で終了させるにはどうすればよいですか?
私の質問とコードが十分に明確であることを願っています。そうでない場合は、明確にする方法を教えてください。前もって感謝します。