2013年10月25日金曜日

開発環境

『初めてのプログラミング 第2版』(Chris Pine 著、長尾 高弘 訳、オライリー・ジャパン、2010年、ISBN978-4-87311-469-9)の13章(新しいクラスの作成と既存クラスの変更), 13.2(クラスの作り方)、13.3(インスタンス変数)、13.4(newとinitialize)、13.5(ベビードラゴンゲーム)、13.6(練習問題の続き)、対話的ベビードラゴンをHaskellで解いてみる。

その他参考書籍

Haskellだと組み込みクラスとかオブジェクトとかRubyと考え方が違うので、前問と同様にとりあえずモジュールを作ったり、自作の新しい型を作ったりしてみる。

対話的ベビードラゴン

コード(BBEdit)

Sample.hs

{-# OPTIONS -Wall -Werror #-}

import Dragon

main :: IO ()
main = do
    putStrLn "ベビードラゴンの名前を入力してください。"
    line <- getLine
    let s = if line == ""
               then "匿名"
               else line
        pet = born s
    putStrLn $ s ++ "が生まれました。"
    command pet

command :: Dragon -> IO ()
command d = do
    putStrLn "コマンドを(feed/walk/bed/toss/rock)を入力: "
    line <- getLine
    let (e, xs) = case line of
                       "feed" -> feed d
                       "walk" ->  walk d
                       "bed" -> putToBed d
                       "toss" -> toss d
                       "rock" -> rock d
                       _ -> (d, ["入力を確認してください"])
    mapM_ putStrLn xs
    command e

コード(BBEdit)

Dragon.hs

--{-# OPTIONS -Wall -Werror #-}

module Dragon
( Dragon,
  born,
  feed,
  walk,
  putToBed,
  toss,
  rock
) where  

data Dragon = Dragon { name :: String,
                       asleep :: Bool,
                       stuffInBelly :: Int,
                       stuffInIntestine :: Int}

born :: String -> Dragon
born [] = Dragon "匿名" False 10 0
born s = Dragon s False 10 0

feed :: Dragon -> (Dragon, [String])
feed (Dragon a b _ c) = (fst $ passageOfTime $ Dragon a b 10 c, 
                         [a ++ "にご飯をあげます。"])

walk :: Dragon -> (Dragon, [String])
walk (Dragon a b c _) = (fst $ passageOfTime $ Dragon a b c 0,
                         [a ++ "をトイレに連れていきます。"])


putToBed :: Dragon -> (Dragon, [String])
putToBed (Dragon a _ b c) = 
    let (Dragon d e f g, xs) = loop 3 (Dragon a True b c) []
        s = a ++ "を寝かしつけます。"
    in if e
       then (Dragon d False f g, s:(xs ++ [a ++ "はゆっくり目覚めます。"]))
       else (Dragon d e f g, s:xs)

loop :: Int -> Dragon -> [String] -> (Dragon, [String])
loop 0 a xs = (a, xs)
loop n (Dragon a False b c) xs = loop (n - 1) (Dragon a False b c) xs                                 
loop n (Dragon a True b c) xs =
    let (Dragon d e f g, ys) = passageOfTime $ Dragon a True b c
    in if e
       then loop (n - 1)
                 (Dragon d e f g)
                 (xs ++ ys ++ [a ++ "がいびきをかいて、部屋が煙だらけです。"])
       else loop (n - 1) (Dragon d e f g) $ xs ++ ys

toss :: Dragon -> (Dragon, [String])
toss a = let b = passageOfTime a
             c = name a
         in (fst b, (c ++ "に高い高いをします。"):
                    (c ++ "が笑ってあなたの眉毛が焦げます。"):(snd b))

rock :: Dragon -> (Dragon, [String])
rock (Dragon a _ b c) =
    let (Dragon d e f g, xs) = passageOfTime $ Dragon a True b c
        ys = (a ++ "をやさしくあやします。"):(a ++ "は少し居眠りをします。"):xs
    in if e
    then (Dragon d False f g, ys ++ ["しかし、やめると起きてしまいます"])
    else (Dragon d e f g, ys)

passageOfTime :: Dragon -> (Dragon, [String])
passageOfTime (Dragon a True 0 _) = error $ ('\n':a) ++
                                            "が突然目を覚まします!\n" ++
                                            a ++ "がお腹をすかせています。\n" ++
                                            "我慢できなくてあなたを食べました。"
passageOfTime (Dragon a False 0 _) = error $ ('\n':a) ++ 
                                            "がお腹をすかせています。\n" ++
                                            "我慢できなくてあなたを食べました。"

passageOfTime (Dragon a b c d) =
    let (e, xs) = intestine $ Dragon a b (c - 1) (d - 1)
        (f, ys) = hungry e
        (g , zs) = poopy f
    in (g, xs ++ ys ++ zs)

intestine :: Dragon -> (Dragon, [String])
intestine (Dragon a b c d) | d >= 10 = (Dragon a b c 0,
                       ["うわっ、" ++ a ++ "がお漏らしを…"])
                           | otherwise = (Dragon a b c d, [])

hungry :: Dragon -> (Dragon, [String])
hungry (Dragon a b c d)
    | c <= 2 = let e = a ++ "のお腹が鳴っています。"
                   xs = if b
                        then (a ++ "が突然目を覚まします!"):[e]
                        else [e]
               in (Dragon a False c d, xs)
    | otherwise = (Dragon a b c d, [])

poopy :: Dragon -> (Dragon, [String])
poopy (Dragon a b c d)
    | d >= 8 = let e = a ++ "がうんちのためにしゃがみ込みます。"
                   xs = if b == True
                        then (a ++ "が突然目を覚まします!"):[e]
                        else [e]
               in (Dragon a False c d, xs)
    | otherwise = (Dragon a b c d, [])

入出力結果(Terminal, runghc)

$ runghc Sample.hs
ベビードラゴンの名前を入力してください。
ノーバート
ノーバートが生まれました。
コマンドを(feed/walk/bed/toss/rock)を入力: 
feed
ノーバートにご飯をあげます。
コマンドを(feed/walk/bed/toss/rock)を入力: 
toss
ノーバートに高い高いをします。
ノーバートが笑ってあなたの眉毛が焦げます。
コマンドを(feed/walk/bed/toss/rock)を入力: 
walk
ノーバートをトイレに連れていきます。
コマンドを(feed/walk/bed/toss/rock)を入力: 
bed
ノーバートを寝かしつけます。
ノーバートがいびきをかいて、部屋が煙だらけです。
ノーバートがいびきをかいて、部屋が煙だらけです。
ノーバートがいびきをかいて、部屋が煙だらけです。
ノーバートはゆっくり目覚めます。
コマンドを(feed/walk/bed/toss/rock)を入力: 
rock
ノーバートをやさしくあやします。
ノーバートは少し居眠りをします。
しかし、やめると起きてしまいます
コマンドを(feed/walk/bed/toss/rock)を入力: 
bed
ノーバートを寝かしつけます。
ノーバートが突然目を覚まします!
ノーバートのお腹が鳴っています。
コマンドを(feed/walk/bed/toss/rock)を入力: 
bed
ノーバートを寝かしつけます。
ノーバートが突然目を覚まします!
ノーバートのお腹が鳴っています。
コマンドを(feed/walk/bed/toss/rock)を入力: 
bed
ノーバートを寝かしつけます。
ノーバートが突然目を覚まします!
ノーバートのお腹が鳴っています。
コマンドを(feed/walk/bed/toss/rock)を入力: 
bed
Sample.hs: 
ノーバートが突然目を覚まします!
ノーバートがお腹をすかせています。
我慢できなくてあなたを食べました。
$

0 コメント:

コメントを投稿