逆FizzBuzz問題というのがあるらしいです。
逆FizzBuzz問題 (Inverse FizzBuzz) - 猫とC#について書くmatarilloの雑記
簡単に言うとFizzBuzzの逆関数を求める問題ですね。
Haskellで解いてみました。
-- FizzBuzzInv.hs
import Data.Maybe (catMaybes)
import Data.Function (on)
import Data.List (isPrefixOf, sortBy)
data FizzBuzz = Fizz | Buzz | FizzBuzz deriving (Eq, Show)
fizzBuzz :: Int -> Maybe FizzBuzz
fizzBuzz n
| n `mod` 15 == 0 = Just FizzBuzz
| n `mod` 3 == 0 = Just Fizz
| n `mod` 5 == 0 = Just Buzz
| otherwise = Nothing
fizzBuzzFrom :: Int -> [(Int, FizzBuzz)]
fizzBuzzFrom n = catMaybes $ fbs n
where
fbs n = fmap (cons n) (fizzBuzz n) : fbs (n + 1)
cons a b = (a, b)
findFizzBuzzSeq :: [FizzBuzz] -> [[(Int, FizzBuzz)]]
findFizzBuzzSeq fbs = do
let len = length fbs
i <- [3, 5, 6, 9, 10, 12, 15]
let fbs' = fizzBuzzFrom i
if fbs `isPrefixOf` (map snd fbs')
then return $ take len $ fbs'
else []
invFizzBuzz :: [FizzBuzz] -> Maybe (Int, Int)
invFizzBuzz fbs = case findFizzBuzzSeq fbs of
[] -> Nothing
xs -> let lengths = map (\fbs -> (fst $ head fbs, fst $ last fbs)) xs
in Just $ head $ sortBy (compare `on` (\(x, y) -> y - x)) lengths
test :: [FizzBuzz] -> IO ()
test fbs = do
putStr $ show fbs
putStr " -> "
case invFizzBuzz fbs of
Just (from, to) -> print [from..to]
Nothing -> putStrLn "X"
main :: IO ()
main = do
test [Fizz]
test [Buzz]
test [Fizz, Fizz]
test [Fizz, Buzz]
test [Buzz, Fizz]
test [Buzz, Buzz]
test [Fizz, Buzz, Fizz]
test [Fizz, Fizz, Buzz]
test [Buzz, Fizz, Buzz]
test [Buzz, Fizz, Fizz]
実行結果:
$ stack exec runghc FizzBuzzInv.hs
[Fizz] -> [3]
[Buzz] -> [5]
[Fizz,Fizz] -> [6,7,8,9]
[Fizz,Buzz] -> [9,10]
[Buzz,Fizz] -> [5,6]
[Buzz,Buzz] -> X
[Fizz,Buzz,Fizz] -> [3,4,5,6]
[Fizz,Fizz,Buzz] -> [6,7,8,9,10]
[Buzz,Fizz,Buzz] -> X
[Buzz,Fizz,Fizz] -> [5,6,7,8,9]
FizzBuzzほどシンプルな問題ではないので一瞬考えますが、15を周期としてFizzBuzzの列のパターンが繰り返されることにさえ気づけば簡単に書けます。