import Data.List (sortBy)
import Data.Ord (comparing)
import Text.Printf (printf)
import Control.Monad (forM_)
import Data.Ratio (numerator, denominator)

maxWgt :: Rational
maxWgt = 15

data Bounty = Bounty
  { itemName :: String
  , itemVal, itemWgt :: Rational
  }

items :: [Bounty]
items =
  [ Bounty "beef" 36 3.8
  , Bounty "pork" 43 5.4
  , Bounty "ham" 90 3.6
  , Bounty "greaves" 45 2.4
  , Bounty "flitch" 30 4.0
  , Bounty "brawn" 56 2.5
  , Bounty "welt" 67 3.7
  , Bounty "salami" 95 3.0
  , Bounty "sausage" 98 5.9
  ]

solution :: [(Rational, Bounty)]
solution = g maxWgt $ sortBy (flip $ comparing f) items
  where
    g room (b@(Bounty _ _ w):bs) =
      if w < room
        then (w, b): g (room - w) bs
        else [(room, b)]
    f (Bounty _ v w) = v / w

main :: IO ()
main = do
  forM_ solution $ \(w, b) -> printf "%s kg of%s\n" (mixedNum w) (itemName b)
  (printf "Total value:%s\n" . mixedNum . sum) $ f <$> solution
  where
    f (w, Bounty _ v wtot) = v * (w / wtot)
    mixedNum q =
      if b == 0
        then show a
        else printf "%d%d/%d" a (numerator b) (denominator b)
      where
        a = floor q
        b = q - toEnum a