isUsedNum :: Char->String->Int
isUsedNum _ [] = 0
isUsedNum a (x:xs)
| a == x = 1 + isUsedNum a xs
| otherwise = isUsedNum a xs
isSuitableNum :: String->Bool
isSuitableNum [] = True
isSuitableNum (x:xs) = isUsedNum x xs == 0 && isSuitableNum xs
normNum :: String->String
normNum xs
| (l < 4) = normNum $ "0" ++ xs
| otherwise = xs
where l = length xs
targetNum :: [Int]->String
targetNum (x:xs)
| (isSuitableNum strX) = strX
| otherwise = targetNum xs
where strX = normNum $ show x
main = do
r <- getStdRandom $ randomR (0, 99)
let t = targetNum $ randomRs (0,9999) (mkStdGen r)
- 乱数で4ケタの数字を求める。この時、数字はいくつも生成してリストにしておく
- リストの頭から数字を1つ取り出し、数当てゲームで使える数字だったら採用。違ったら、リストの頭の数字を捨てて、リストの頭から数字を取りだすところからやり直し。→ targetNum
- 採用した数字が3ケタだったら、頭に0をつける。→ normNum
- 数当てゲームで使えるかどうかは isSuitableNum。一桁ずつ取り出して、既に使っているかどうかを順番にチェック→isUsedNum
では、数当て問題 - Hit & Blow -: ツムジのひとりごとのコードを拝見。
-- xs からランダムに重複しない n 個の要素を取り出す
randomPicUp :: Eq a => Int -> [a] -> IO [a]
randomPicUp n xs = loop n (length xs - 1) xs []
where
loop 0 _ _ prd = return prd
loop c m xs prd = do
g <- newStdGen
let (i, _) = randomR (0, m) g
let x = xs !! i
loop (c - 1) (m - 1) (delete x xs) (x : prd)
main :: IO ()
main = do
target <- randomPicUp 4 ['0'..'9']
大きな違いは、
- 0~9から数字を1個選ぶ。これを4回行って、4けたの数字とする
- cはループカウンタかな?xsは選び出す数字の候補で、最初は0~9だけど、選ばれた数字を除外していく。mは選び出す数字の候補の数のようだから、xsの長さから求めればいいよね。
- prdは選んだ数字のリスト。これを数えるようにすれば、cはいらなくなるかな?