2017-03-17 6 views
0

これはStateTモナドを学習するための練習です。プログラムはゲームMorraを実装します。 2人のプレーヤーはコンピュータと人物です。状態は、コンピュータとプレーヤーのスコアを蓄積します。このプログラムは、関数morraの1回の反復で機能します。しかし、私はそれをループする方法を失っています。私はいくつかのことを試しましたが、何も動かないようです。StateTモナドを使用したループ

module Morra where 

import Control.Monad.Trans.State.Lazy 
import Control.Monad.IO.Class 
import Data.Char (isDigit, digitToInt) 
import System.Random (randomRIO) 
import Control.Monad (when) 

morra :: StateT (Int, Int) IO() 
morra = do 
    p <- liftIO getChar 
    when (isDigit p) $ 
    do 
     let p' = digitToInt p 
     c <- liftIO $ randomRIO (1, 2) 
     liftIO $ putStrLn ['P',':',' ',p] --"P: " ++ p) 
     liftIO $ putStrLn ("C: " ++ show c) 
     (pt, ct) <- get 
     if even (c + p') then 
     do 
      liftIO $ putStrLn "Computer Wins" 
      put (pt, ct + 1) 
     else 
     do 
      liftIO $ putStrLn "Player Wins" 
      put (pt + 1, ct) 

main :: IO() 
main = do 
    putStrLn "-- p is Player" 
    putStrLn "-- c is Computer" 
    putStrLn "-- Player is odds, Computer is evens." 
    fScore <- runStateT morra (0,0) 
    let personS = fst . snd $ fScore 
     compS = snd . snd $ fScore 
    putStrLn ("Person Score: " ++ show personS) 
    putStrLn ("Computer Score: " ++ show compS) 
    if personS > compS then 
    putStrLn "Winner is Person" 
    else 
    putStrLn "Winner is Computer" 

答えて

2

あなたは99%です。最後のputStrLnの直後に新しい行にmainを追加すると、mainが自動的にプログラムを再起動します。

コード内でいくつかのことを簡素化するためにいくつかのトリック:

  • ラウンドのちょうど最終状態を取るためにexecStateT:: StateT s m a -> s -> m sを使用してください。このように、あなたはスコアを抽出するためにletバインディングを使用する必要はありませんし、代わりにインラインでそれを行うことができます。(personS,compS) <- execStateT morra (0,0)
  • ['P',':',' ',p]は、それはスタイルや好みの問題だ("P: " ++ [p])

のように書くことができますが、

if condition 
    then do 
    doSomethingA 
    doSomethingB 
    else someFunction $ do 
    doSomethingElseA 
    doSomethingElseB 

全体的に、素敵な仕事:)

01:あなたの if秒、 else sおよび do Sを再配置することによって、インデントや書式の空白の多くを減らすことができます
+0

ありがとう:これは最終的なコードです。しかし、私は関数morraのループが必要です。ファンクションメインは1回だけ実行されます。関数の最後に 'morra'を置くと(whenの後の' do'に沿って)何も起こりません。 – user1897830

+0

@ user1897830あなたは 'when'(インジケートされた2つのスペースのみ)でインラインにする必要があります。 'whenDigit p'がtrueのときにのみループします。何も起こっていないということはどういう意味ですか?すぐに終了するのですか、それともループに巻き込まれてしまいますか? – Lazersmoke

+0

'isDigit p'が真のときだけループする必要があります。 'isDigit p'が真でなくて終了するまでループします。しかし、私が 'モラ 'を単に中に入れると、それは単に出てループしません。 – user1897830

1

私はp <- liftIO getLinep <- liftIO getCharを置き換え、pは今や文字列ではなく、Char型であるという事実を可能にするために他のいくつかのマイナーな変更を行いました。今それは動作します。それはLinux上でgetCharを使って動作するので、Windowsと何か関係があるようです。そのため

module Morra where 

import Control.Monad.Trans.State.Lazy 
import Control.Monad.IO.Class 
import Data.Char (isDigit, digitToInt) 
import System.Random (randomRIO) 
import Control.Monad (when) 

morra :: StateT (Int, Int) IO() 
morra = do 
    p <- liftIO getLine 
    let p1 = head p 
    when (isDigit p1) $ do 
    let p' = digitToInt p1 
    c <- liftIO $ randomRIO (1, 2) 
    liftIO $ putStrLn ("P: " ++ p) 
    liftIO $ putStrLn ("C: " ++ show c) 
    (pt, ct) <- get 
    if even (c + p') then do 
     liftIO $ putStrLn "Computer Wins" 
     put (pt, ct + 1) 
    else do 
     liftIO $ putStrLn "Player Wins" 
     put (pt + 1, ct) 
    morra 

main :: IO() 
main = do 
    putStrLn "-- p is Player" 
    putStrLn "-- c is Computer" 
    putStrLn "-- Player is odds, Computer is evens." 
    (personS,compS) <- execStateT morra (0,0) 
    putStrLn ("Person Score: " ++ show personS) 
    putStrLn ("Computer Score: " ++ show compS) 
    if personS == compS then 
    putStrLn "No Winner" 
    else if personS > compS then 
    putStrLn "Winner is Person" 
    else 
    putStrLn "Winner is Computer" 
関連する問題