import Data.List (intercalate)
import Text.Printf (printf)
import Data.List.Split (chunksOf)

isEban :: Int -> Bool
isEban n = all (`elem` [0, 2, 4, 6]) z
 where
  (b, r1) = n  `quotRem` (10 ^ 9)
  (m, r2) = r1 `quotRem` (10 ^ 6)
  (t, r3) = r2 `quotRem` (10 ^ 3)
  z       = b: map (\x -> if x >= 30 && x <= 66 then x `mod` 10 else x) [m, t, r3]

ebans = map f
 where
  f x = (thousands x, thousands $ length $ filter isEban [1..x])

thousands:: Int -> String
thousands = reverse . intercalate "," . chunksOf 3 . reverse . show

main :: IO ()
main = do
  uncurry (printf "eban numbers up to and including 1000:%2s\n%s\n\n") $ r [1..1000]
  uncurry (printf "eban numbers between 1000 and 4000:%2s\n%s\n\n") $ r [1000..4000]
  mapM_ (uncurry (printf "eban numbers up and including%13s:%5s\n")) ebanCounts
 where 
  ebanCounts = ebans [        10_000
                     ,       100_000
                     ,     1_000_000
                     ,    10_000_000
                     ,   100_000_000
                     , 1_000_000_000 ]
  r = ((,) <$> thousands . length <*> show) . filter isEban