Guessing Number using Haskell
今天利用一點時間寫出來的簡單版(困難版我也不會 XD),明天有空再補心得 XD。如果有什麼可以加強或改寫的的地方還請指教,我會很開心的,謝謝 :)。
import System.Random
checkNum :: [Integer] -> [Integer] -> (Integer, Integer)
checkNum input ans = (posNum input ans, correctNum input ans)
where posNum input ans = sum $ zipWith (boolValue (x==y)) input ans
correctNum input ans = foldr (\x y -> y + boolValue (any (== x) ans)) 0 input
boolValue a = if a == True then 1 else 0
game :: [Integer] -> IO ()
game ans = do
input <- fmap (fmap (\x -> read [x])) getLine
let (rpn, rn) = checkNum input ans
if rpn == 4 then
do putStrLn "Win"
return ()
else
do putStrLn $ show rpn ++ "A" ++ show rn ++ "B"
game ans
main = do
gen <- getStdGen
let ans = take 4 (randomRs (1,9) gen)
game ans
---
繼續前進。
T55555的回應給了許多寶貴的意見,真的很謝謝他每次都給予很好的建議(至於我這麼晚回的原因是因為仍在當兵中...Orz),我也做出了回應,現在把整個修完的 code 再貼一次如下。
import System.Random
-- Wrong game logic
-- checkNum :: [Int] -> [Int] -> (Int, Int)
-- checkNum input ans = (posNum input ans, correctNum input ans)
-- where posNum input ans = foldr (\x y -> y + fromEnum x) 0 $ zipWith (==) input ans
-- correctNum input ans = foldr (\x y -> y + (fromEnum (any (==x) ans))) 0 input
checkNum' :: [Int] -> [Int] -> (Int, Int)
checkNum' input ans = foldr (check ans) (0, 0) $ zip input ans
where check ans (x,y) (p,c) =
if x == y then (p+1,c)
else
if (any (==x) ans) then (p,c+1)
else (p,c)
game :: [Int] -> IO ()
game ans = do
input <- fmap (fmap (\x -> read [x])) getLine
let (rpn, rn) = checkNum' input ans
if rpn == 4 then
do putStrLn "Win"
return ()
else
do putStrLn $ show rpn ++ "A" ++ show rn ++ "B"
game ans
main = do
gen <- getStdGen
let ans = take 4 (randomRs (1,9) gen)
putStrLn $ show ans
game ans
2 則留言:
You code seems miss something and cannot compile.
It seems to me two lines are missing code during post, my guess they are:
posNum input ans = sum $ zipWith (\x y -> boolValue (x==y)) input ans
correctNum input ans = foldr (\x y -> y + boolValue (any (== x) ans)) 0
If they are like above, then there is logic error:
checkNum [1,2,3,5] [6,7,8,5] will return (1,1)
BTW. Don't need boolValue, you can just use fromEnum.
fromEnum False ==> 0
fromEnum True ==> 1
This is because Bool is instance of Enum.
I tried to implememnt checkNum, here is my version:
checkNum :: (Eq a) => [a] -> [a] -> (Int, Int)
checkNum xs ys = foldl check (0, 0) $ productSet (zip xs [1..]) (zip ys [1..])
where
productSet xs ys = concatMap (zip xs . repeat) ys
check ab@(a,b) ((v1, i1), (v2, i2))
| v1 /= v2 = ab
| i1 == i2 = (a+1, b)
| otherwise = (a, b+1)
Thanks for your comments.
You are right. The piece of code is missing. Now I have corrected it in the original post.
The logic error about the function "checkNum" is my fault because I don't know the checking policy is like what you wrote.
If I write the code without 'boolValue' function, I can write as the follows (It is still using the wrong logic. XD)
checkNum :: [Int] -> [Int] -> (Int, Int)
checkNum input ans = (posNum input ans, correctNum input ans)
where posNum input ans = foldr (\x y -> y + fromEnum x) 0 $ zipWith (==) input ans
correctNum input ans = foldr (\x y -> y + (fromEnum (any (==x) ans))) 0 input
Follow your logic, I try to write the checkNum function again.
checkNum' :: [Int] -> [Int] -> (Int, Int)
checkNum' input ans = foldr (check ans) (0, 0) $ zip input ans
where check ans (x,y) (p,c) =
if x == y then (p+1,c)
else
if (any (==x) ans) then (p,c+1)
else (p,c)
I learned some good ideas from your comments. Thank you.
張貼留言