import Data.List (unfoldr, genericIndex)
import Control.Monad (replicateM, foldM, mzero)


isEsthetic b = all ((== 1) . abs) . differences . toBase b
  where
    differences lst = zipWith (-) lst (tail lst)


esthetics_m b =
  do differences <- (\n -> replicateM n [-1, 1]) <$> [0..]
     firstDigit <- [1..b-1]
     differences >>= fromBase b <$> scanl (+) firstDigit



esthetics b = tail $ fst <$> iterate step (undefined, q)
  where
    q = [(d, d) | d <- [1..b-1]]
    step (_, queue) =
      let (num, lsd) = head queue
          new_lsds = [d | d <- [lsd-1, lsd+1], d < b, d >= 0]
      in (num, tail queue ++ [(num*b + d, d) | d <- new_lsds])


fromBase b = foldM f 0
  where f r d | d < 0 || d >= b = mzero
              | otherwise = pure (r*b + d)

toBase b = reverse . unfoldr f
  where
    f 0 = Nothing
    f n = let (q, r) = divMod n b in Just (r, q)

showInBase b = foldMap (pure . digit) . toBase b
  where digit = genericIndex (['0'..'9'] <> ['a'..'z'])