feat: solve day6 part 2
Read the numbers from a given column and multiply each partial sum with 10, to go from (0, [1, 2, 3]) -> (1, [2, 3]) -> (10 + 2, [3]) -> (120 + 3, []) -> 120.
This commit is contained in:
parent
02927269a8
commit
a64400efd8
1 changed files with 93 additions and 14 deletions
107
app/Day6.hs
107
app/Day6.hs
|
|
@ -1,5 +1,6 @@
|
||||||
module Main where
|
module Main where
|
||||||
|
|
||||||
|
import Data.Char (digitToInt)
|
||||||
import Data.Either (lefts, rights)
|
import Data.Either (lefts, rights)
|
||||||
import Data.IntMap (IntMap)
|
import Data.IntMap (IntMap)
|
||||||
import qualified Data.IntMap as M
|
import qualified Data.IntMap as M
|
||||||
|
|
@ -14,16 +15,13 @@ main = do
|
||||||
|
|
||||||
part1 :: String -> Int
|
part1 :: String -> Int
|
||||||
part1 = M.foldl' (+) 0 . parse
|
part1 = M.foldl' (+) 0 . parse
|
||||||
|
|
||||||
data Oper = Mult | Add
|
|
||||||
deriving (Show)
|
|
||||||
|
|
||||||
-- Parse each space-delimited value as either a number or an
|
|
||||||
-- operator. Then combine the operator and the operands into a
|
|
||||||
-- calculation.
|
|
||||||
parse :: String -> IntMap Int
|
|
||||||
parse = M.map complete . foldl' insertPartial mempty . concat . map parseLine . lines
|
|
||||||
where
|
where
|
||||||
|
-- Parse each space-delimited value as either a number or an
|
||||||
|
-- operator. Then combine the operator and the operands into a
|
||||||
|
-- calculation.
|
||||||
|
parse :: String -> IntMap Int
|
||||||
|
parse = M.map complete . foldl' insertPartial mempty . concat . map parseLine . lines
|
||||||
|
|
||||||
parseLine :: String -> [(Int, Either Oper Int)]
|
parseLine :: String -> [(Int, Either Oper Int)]
|
||||||
parseLine = zip [0 ..] . map parseWord . words
|
parseLine = zip [0 ..] . map parseWord . words
|
||||||
|
|
||||||
|
|
@ -40,14 +38,95 @@ parse = M.map complete . foldl' insertPartial mempty . concat . map parseLine .
|
||||||
(nums, Mult) -> product nums
|
(nums, Mult) -> product nums
|
||||||
(nums, Add) -> sum nums
|
(nums, Add) -> sum nums
|
||||||
|
|
||||||
|
data Oper = Mult | Add
|
||||||
|
deriving (Show)
|
||||||
|
|
||||||
part2 :: String -> Int
|
part2 :: String -> Int
|
||||||
part2 = error "Not implemented"
|
part2 = (\g -> foldl' (+) 0 $ map (calculateGroup g) [0 .. M.size (columns g) - 1]) . newGrid
|
||||||
|
|
||||||
|
-- Extract the character in the grid on row, group and column.
|
||||||
|
--
|
||||||
|
-- Return Nothing if the char is ' '.
|
||||||
|
idx :: Grid -> Int -> Int -> Int -> Maybe Char
|
||||||
|
idx (Grid cols rows cs) row col n
|
||||||
|
| col >= M.size cols = error $ "idx: requested a too large number group index (" ++ show col ++ " >= " ++ show cols ++ ")"
|
||||||
|
| row >= rows = error $ "idx: requested a too large row index (" ++ show row ++ " >= " ++ show rows ++ ")"
|
||||||
|
| n >= size (cols M.! col) = error $ "idx: requested a too large column index (" ++ show n ++ " >= " ++ show (size (cols M.! col)) ++ ")"
|
||||||
|
| otherwise = case cs !! row !! i of
|
||||||
|
' ' -> Nothing
|
||||||
|
c -> Just c
|
||||||
|
where
|
||||||
|
i = n + (sum . map ((+ 1) . (size . (cols M.!))) $ [0 .. col - 1])
|
||||||
|
|
||||||
|
digit :: Grid -> Int -> Int -> Int -> Maybe Int
|
||||||
|
digit g r c = fmap digitToInt . idx g r c
|
||||||
|
|
||||||
|
operator :: Grid -> Int -> Oper
|
||||||
|
operator g col = case idx g (rows g - 1) col 0 of
|
||||||
|
Just '+' -> Add
|
||||||
|
Just '*' -> Mult
|
||||||
|
Just ch -> error $ "operator: Expected '+' or '*', got " <> show ch
|
||||||
|
Nothing -> error $ "operator: Expected '+' or '*', got nothing"
|
||||||
|
|
||||||
|
-- Calculate a column by traversing all rows at that column inside that group.
|
||||||
|
--
|
||||||
|
-- Calculation is performed by first multiplying the accumulated value
|
||||||
|
-- by 10 and then adding the new digit. If no value exists in that
|
||||||
|
-- slot we don't modify the accumulated value.
|
||||||
|
calculateColumn :: Grid -> Int -> Int -> Int
|
||||||
|
calculateColumn g c n = foldl' (\acc r -> maybe acc ((+) (acc * 10)) $ digit g r c n) 0 [0 .. rows g - 2]
|
||||||
|
|
||||||
|
-- Calculates each column and folds them using the operator at the last line.
|
||||||
|
calculateGroup :: Grid -> Int -> Int
|
||||||
|
calculateGroup g c = foldl' (op $ oper column) (identity column) $ map (calculateColumn g c) [0 .. (size column) - 1]
|
||||||
|
where
|
||||||
|
column = columns g M.! c
|
||||||
|
|
||||||
|
op :: Oper -> (Int -> Int -> Int)
|
||||||
|
op Mult = (*)
|
||||||
|
op Add = (+)
|
||||||
|
|
||||||
|
data Grid = Grid
|
||||||
|
{ columns :: IntMap Column,
|
||||||
|
rows :: Int,
|
||||||
|
cells :: [[Char]]
|
||||||
|
}
|
||||||
|
deriving (Show)
|
||||||
|
|
||||||
|
data Column = Column
|
||||||
|
{ size :: Int,
|
||||||
|
oper :: Oper,
|
||||||
|
identity :: Int
|
||||||
|
}
|
||||||
|
deriving (Show)
|
||||||
|
|
||||||
|
-- | Construct a grid based on the last line.
|
||||||
|
--
|
||||||
|
-- Using the last line we can get the number of digits in each column.
|
||||||
|
newGrid :: String -> Grid
|
||||||
|
newGrid = go . lines
|
||||||
|
where
|
||||||
|
go :: [String] -> Grid
|
||||||
|
go ls =
|
||||||
|
let columns = M.fromList $ foldl' go' [] (last ls)
|
||||||
|
in Grid columns (length ls) ls
|
||||||
|
|
||||||
|
go' :: [(Int, Column)] -> Char -> [(Int, Column)]
|
||||||
|
go' [] ch = pure . (0,) . (\(oper, idty) -> Column 1 oper idty) $ parseOper ch
|
||||||
|
go' ((n, c) : lengths) ch
|
||||||
|
| ch == ' ' = (n, c {size = size c + 1}) : lengths
|
||||||
|
| otherwise = (n + 1, (\(oper, idty) -> Column 1 oper idty) (parseOper ch)) : (n, c {size = size c - 1}) : lengths
|
||||||
|
|
||||||
|
parseOper :: Char -> (Oper, Int)
|
||||||
|
parseOper '*' = (Mult, 1)
|
||||||
|
parseOper '+' = (Add, 0)
|
||||||
|
parseOper c = error $ "parseOper: expects a '+' or '*', got " <> show c
|
||||||
|
|
||||||
testInput :: String
|
testInput :: String
|
||||||
testInput =
|
testInput =
|
||||||
unlines
|
unlines
|
||||||
[ "123 328 51 64",
|
[ "123 328 51 64 1",
|
||||||
" 45 64 387 23",
|
" 45 64 387 23 2",
|
||||||
" 6 98 215 314",
|
" 6 98 215 314 3",
|
||||||
"* + * + "
|
"* + * + +"
|
||||||
]
|
]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue