Day 7.hs 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. import Data.List
  2. import Data.Foldable
  3. data Bundle = Bundle {
  4. count :: Int,
  5. col :: Int
  6. } deriving (Show)
  7. toLeft :: Bundle -> Bundle
  8. toLeft (Bundle c i) = Bundle c (i - 1)
  9. toRight :: Bundle -> Bundle
  10. toRight (Bundle c i) = Bundle c (i + 1)
  11. overlap :: Bundle -> Bundle -> Bundle
  12. overlap (Bundle c1 i) (Bundle c2 _) = Bundle (c1 + c2) i
  13. instance Eq Bundle where
  14. (==) b1 b2 = col b1 == col b2
  15. instance Ord Bundle where
  16. b1 `compare` b2 = col b1 `compare` col b2
  17. mergeBundles :: Bundle -> Bundle -> (Bundle, Maybe Bundle)
  18. mergeBundles b1 b2
  19. | b1 < b2 = (b1, Just b2)
  20. | b1 > b2 = (b2, Just b1)
  21. | b1 == b2 = (overlap b1 b2, Nothing)
  22. mergeBundleLists :: [Bundle] -> [Bundle] -> [Bundle]
  23. mergeBundleLists b1s [] = b1s
  24. mergeBundleLists [] bs2 = bs2
  25. mergeBundleLists (b1:b1s) (b2:b2s) = minB:mergeBundleLists b1s' b2s
  26. where
  27. (minB, maxB) = mergeBundles b1 b2
  28. b1s' = maybe b1s (prependBundle b1s) maxB
  29. prependBundle :: [Bundle] -> Bundle -> [Bundle]
  30. prependBundle [] b = [b]
  31. prependBundle (fb:beams) b = min_b:(toList max_b ++ beams)
  32. where
  33. (min_b, max_b) = mergeBundles b fb
  34. mergeSplit :: Bundle -> ([Bundle], Int) -> ([Bundle], Int)
  35. mergeSplit b (beams, splitCount) = (toLeft b : prependBundle beams (toRight b), splitCount + 1)
  36. mergeMiss :: Bundle -> ([Bundle], Int) -> ([Bundle], Int)
  37. mergeMiss b (beams, splitCount) = (prependBundle beams b, splitCount)
  38. passBundles :: [Int] -> [Bundle] -> ([Bundle], Int)
  39. passBundles [] beams = (beams, 0)
  40. passBundles _ [] = ([], 0)
  41. passBundles (s:splitters) (b@(Bundle size i):bundleList)
  42. | s < i = passBundles splitters (b:bundleList)
  43. | s > i = mergeMiss b (passBundles (s:splitters) bundleList)
  44. | s == i = mergeSplit b (passBundles splitters bundleList)
  45. sources :: String -> [Bundle]
  46. sources = map (Bundle 1) . elemIndices 'S'
  47. splitters :: String -> [Int]
  48. splitters = elemIndices '^'
  49. passLine :: [([Bundle], Int)] -> String -> [([Bundle], Int)]
  50. passLine (beams:beamss) line = (res, splitCount + snd beams):beams:beamss
  51. where
  52. spls = splitters line
  53. bms = mergeBundleLists (fst beams) (sources line)
  54. (res, splitCount) = passBundles spls bms
  55. countBundles :: [Bundle] -> Int
  56. countBundles bs = sum (map count bs)
  57. passLines :: String -> [([Bundle], Int)]
  58. passLines inputStr = foldl passLine [([], 0)] (lines inputStr)
  59. main :: IO()
  60. main = do
  61. inputStr <- getContents
  62. print ((\(bs, c) -> (c, countBundles bs)) $ head $ passLines inputStr)