如何修复我的 haskell 代码来计算剪刀石头布的第一人称得分?
How can I fix my haskell code to count the first person points in rock paper scissors?
我想计算第一位玩家赢得游戏的次数。有人可以帮我解决吗?
data RPS = Rock | Paper | Scissors deriving (Eq)
beats :: RPS -> RPS
beats rps = case rps of
Rock -> Scissors
Paper -> Rock
Scissors -> Paper
firstBeats :: [RPS] -> [RPS] -> Int
firstBeats (a:ax) (b:bx)
| a==Rock && b==Scissors = 1 + (firstBeats ax) : (firstBeats bx)
| a==Scissors && b==Paper = 1 + (firstBeats ax) : (firstBeats bx)
| a==Paper && b==Rock = 1+ (firstBeats ax) : (firstBeats bx)
| otherwise = (a: firstBeats ax) + (b : firstBeats bx)
Examples:
firstBeats [Rock] [Paper] == 0
firstBeats [Rock] [Scissors] == 1
firstBeats [Paper, Scissors] [Rock, Paper] == 2
firstBeats [Paper, Scissors, Paper] [Rock, Paper, Scissors] == 2
firstBeats (replicate 20 Paper) (replicate 20 Rock) == 20
主要问题是firstBeats
有两个参数,所以你应该传递两个列表的尾部。此外,您应该涵盖两个列表之一或两个列表都为空的情况,因此:
firstBeats :: [RPS] -> [RPS] -> Int
firstBeats (a:ax) (b:bx)
| a == Rock && b == Scissors = 1 + firstBeats ax bx
| a == Scissors && b == Paper = 1 + firstBeats ax bx
| a == Paper && b == Rock = 1 + firstBeats ax bx
| otherwise = firstBeats ax bx
firstBeats _ _ = 0
但这并不优雅,需要大量重复。您可以定义一个函数来检查第一项是否击败了第二项:
hasBeaten :: RPS -> RPS -> Bool
hasBeaten Rock Scissors = True
hasBeaten Scissors Paper = True
hasBeaten Paper Rock = True
hasBeaten _ _ = False
那么你可以将其实现为:
firstBeats :: [RPS] -> [RPS] -> Int
firstBeats (a:as) (b:bs)
| hasBeaten a b = 1 + firstBeats ax bx
| otherwise = firstBeats ax bx
firstBeats _ _ = 0
不过造型也不是很好看。人们会期望使用 RPS
的二元组列表,这样就不可能传递两个包含不同数量项目的列表。那么就是:
firstBeats :: [(RPS, RPS)] -> Int
firstBeats = length . filter (uncurry hasBeaten)
我想计算第一位玩家赢得游戏的次数。有人可以帮我解决吗?
data RPS = Rock | Paper | Scissors deriving (Eq)
beats :: RPS -> RPS
beats rps = case rps of
Rock -> Scissors
Paper -> Rock
Scissors -> Paper
firstBeats :: [RPS] -> [RPS] -> Int
firstBeats (a:ax) (b:bx)
| a==Rock && b==Scissors = 1 + (firstBeats ax) : (firstBeats bx)
| a==Scissors && b==Paper = 1 + (firstBeats ax) : (firstBeats bx)
| a==Paper && b==Rock = 1+ (firstBeats ax) : (firstBeats bx)
| otherwise = (a: firstBeats ax) + (b : firstBeats bx)
Examples:
firstBeats [Rock] [Paper] == 0
firstBeats [Rock] [Scissors] == 1
firstBeats [Paper, Scissors] [Rock, Paper] == 2
firstBeats [Paper, Scissors, Paper] [Rock, Paper, Scissors] == 2
firstBeats (replicate 20 Paper) (replicate 20 Rock) == 20
主要问题是firstBeats
有两个参数,所以你应该传递两个列表的尾部。此外,您应该涵盖两个列表之一或两个列表都为空的情况,因此:
firstBeats :: [RPS] -> [RPS] -> Int
firstBeats (a:ax) (b:bx)
| a == Rock && b == Scissors = 1 + firstBeats ax bx
| a == Scissors && b == Paper = 1 + firstBeats ax bx
| a == Paper && b == Rock = 1 + firstBeats ax bx
| otherwise = firstBeats ax bx
firstBeats _ _ = 0
但这并不优雅,需要大量重复。您可以定义一个函数来检查第一项是否击败了第二项:
hasBeaten :: RPS -> RPS -> Bool
hasBeaten Rock Scissors = True
hasBeaten Scissors Paper = True
hasBeaten Paper Rock = True
hasBeaten _ _ = False
那么你可以将其实现为:
firstBeats :: [RPS] -> [RPS] -> Int
firstBeats (a:as) (b:bs)
| hasBeaten a b = 1 + firstBeats ax bx
| otherwise = firstBeats ax bx
firstBeats _ _ = 0
不过造型也不是很好看。人们会期望使用 RPS
的二元组列表,这样就不可能传递两个包含不同数量项目的列表。那么就是:
firstBeats :: [(RPS, RPS)] -> Int
firstBeats = length . filter (uncurry hasBeaten)