Skip to content

Instantly share code, notes, and snippets.

@skatenerd
Last active December 3, 2023 18:49
Show Gist options
  • Save skatenerd/df3887c133f74b7296197214d51cf35a to your computer and use it in GitHub Desktop.
Save skatenerd/df3887c133f74b7296197214d51cf35a to your computer and use it in GitHub Desktop.
2023 Day 3 Advent of Code
module DayThree (module DayThree) where
import qualified Data.Text as T
import qualified Text.Read as TR
import qualified Data.Foldable as DF
import qualified Data.Maybe as M
import qualified Data.List.Safe as LS
import qualified Data.Set as S
import qualified Data.List as L
import qualified Data.Text.IO as TI
at world (row, col) = (world !! row) !! col
getNeighbors world row col = filter isLegal allNeighbors
where allNeighbors = do
r <- [row - 1, row, row + 1]
c <- [col - 1, col, col + 1]
[(r,c)]
isLegal (r,c) = (r,c) /= (row, col) && r >= 0 && c >= 0 && c < length (world !! 0) && r < length world
rowNeighbors world row col = filter (\(nr, nc) -> nr == row) (getNeighbors world row col)
partOne textWorld = sum $ M.catMaybes $ map (numFromIndices world) $ S.toList numberBlobs
where numberBlobs = S.fromList $ map (fullNumberIndices world) symbolNeighborIndices
world = (map T.unpack textWorld)
symbolIndices = filter isSymbol (allIndices world)
symbolNeighborIndices = concatMap nbrs symbolIndices
isSymbol (r,c)
| v == '.' = False
| v `elem` ('0' `enumFromTo` '9') = False
| otherwise = True
where v = world `at` (r,c)
nbrs (r,c) = getNeighbors world r c
partTwo textWorld = sum $ map scoreGear gearIndices
where gearIndices = filter (isGear world) (allIndices world)
scoreGear (r,c) = DF.product (gearNumbers world (r,c))
world = map T.unpack textWorld
testWorld = ["467..114..",
"...*......",
"..35..633.",
"......#...",
"617*......",
".....+.58.",
"..592.....",
"......755.",
"...$.*....",
".664.598.."]
numFromIndices :: [String] -> S.Set (Int, Int) -> Maybe Int
numFromIndices world bunch = TR.readMaybe $ map (world `at`) (L.sort (S.toList bunch))
fullNumberIndices :: [String] -> (Int, Int) -> S.Set (Int, Int)
fullNumberIndices world (row,col) = S.fromList $ go [] (row,col)
where go visitedSoFar (row,col)
| (world `at` (row, col) `elem` (enumFromTo '0' '9')) = (row,col):(concatMap (go ((row,col):visitedSoFar)) ((rowNeighbors world row col) L.\\ visitedSoFar))
| otherwise = []
isGear world (row,col) = hasStar && length (gearNumbers world (row, col)) == 2
where hasStar = (world `at` (row, col)) == '*'
gearNumbers world (row,col) = S.fromList $ M.catMaybes $ map (numFromIndices world) bunches
where bunches = map (fullNumberIndices world) $ getNeighbors world row col
allIndices world = do
r <- 0 `enumFromTo` ((length world) - 1)
c <- 0 `enumFromTo` ((length (world !! 0)) - 1)
[(r,c)]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment