函数程序设计实验七:石头、剪刀和布

{-
设计一个交互程序,实现计算机(我)和用户(您)玩猜拳「石头、剪刀和布」。
例如,运行程序实现下来交互游戏:
*Main> play

请您出手 (R)石头, (S)剪刀, (P)布:p, 您出了布, 我出了石头

您赢了这手

我的得分: 0

您的得分: 1

请您出手 (R)石头, (S)剪刀, (P)布:s, 您出了剪刀, 我出了布

您赢了这手

我的得分: 0

您的得分: 2

请您出手 (R)石头, (S)剪刀, (P)布:r, 您出了石头, 我出了剪刀

您赢了这手

我的得分: 0

您的得分: 3

算您赢了这轮。


*Main> play

请您出手 (R)石头, (S)剪刀, (P)布:s, 您出了剪刀, 我出了布

您赢了这手

我的得分: 0

您的得分: 1

请您出手 (R)石头, (S)剪刀, (P)布:r, 您出了石头, 我出了石头

这一手平手

我的得分: 0

您的得分: 1

请您出手 (R)石头, (S)剪刀, (P)布:p, 您出了布, 我出了剪刀

我的得分: 1

您的得分: 1

请您出手 (R)石头, (S)剪刀, (P)布:p, 您出了布, 我出了剪刀

我的得分: 2

您的得分: 1

请您出手 (R)石头, (S)剪刀, (P)布:r, 您出了石头, 我出了剪刀

您赢了这手

我的得分: 2

您的得分: 2

请您出手 (R)石头, (S)剪刀, (P)布:s, 您出了剪刀, 我出了石头

我的得分: 3

您的得分: 2

哈哈,我赢了!


作业要求:
1. 模块命名为Game, 程序命名为play:: IO ();
2. 程序要仿照以上例子,输出交互过程和相关详细信息;
3. 使用下面的手势类型及instance定义,需要 import System.Random:
data Hand = Rock | Scissor | Paper deriving (Enum)
instance Random Hand where



    random g = case randomR (0,2) g of



                     (r, g') -> (toEnum r, g')



    randomR (a,b) g = case randomR (fromEnum a, fromEnum b) g of



            (r, g') -> (toEnum r, g')

你也可以自己将Hand定义为Random的实例,以便能够使用随机手势,如 randomIO :: IO Hand
4. 用户(您)的输入用字母表示:r, s和p(不分大小写)分别表示用户选择的石头、剪刀和布
5. 建议适当定义一些辅助函数,不要把所有的命令都写在函数play中
6. 一点提示:猜数和猜单词中定义了函数:
guess :: Int (或者String) -> IO ()
其中输入参数是要猜的数或单词,在一系列猜测过程中需要这个信息,以便决定是停止还是继续猜(递归)。那么,猜拳时可能也需要类似的信息。
提交要求:
1. 提交模块Game;
2. 仿照以上例子,至少给出计算机(我)和用户(您)各赢一次的运行截图。
-}
module Game where
import System.Random
import Text.Printf

data Hand = Rock | Scissor | Paper deriving (Enum,Eq)
instance Random Hand where
    random g = case randomR (0,2) g of
                     (r, g') -> (toEnum r, g')
    randomR (a,b) g = case randomR (fromEnum a, fromEnum b) g of
            (r, g') -> (toEnum r, g')

getHand::IO Hand
getHand=
    do
        s<-getLine
        if (s=="r")||(s=="R")
            then return Rock
            else if (s=="s")||(s=="S")
                then return Scissor
                else return Paper

isWin::Hand->Hand->Bool
isWin p c=(p==Rock&&c==Scissor)||(p==Scissor&&c==Paper)||(p==Paper&&c==Rock)

toStr::Hand->String
toStr Rock="石头"
toStr Scissor="剪刀"
toStr Paper="布"

play::IO()
play=game 0 0

game::Int->Int->IO()
game a b=
    do
        putStrLn "请您出手 (R)石头, (S)剪刀, (P)布:"
        ta<-getHand
        tb<-randomIO::IO Hand
        putStrLn(printf "您出了%s, 我出了%s" (toStr ta) (toStr tb))
        if isWin ta tb
            then do
                putStrLn(printf "您赢了这手\n我的得分: %d\n您的得分: %d" b (a+1))
                if a>1
                    then putStrLn "算您赢了这轮。"
                    else game (a+1) b
            else if isWin tb ta
                then do
                    putStrLn(printf "我赢了这手\n我的得分: %d\n您的得分: %d" (b+1) a)
                    if b>1
                        then putStrLn "哈哈,我赢了!"
                        else game a (b+1)
                else do
                    putStrLn(printf "这一手平手\n我的得分: %d\n您的得分: %d" b a)
                    game a b

--main::IO()
--main=play