From 7ce30d3ab60f066c05d0f387fc213ef43083d741 Mon Sep 17 00:00:00 2001 From: Jordan Doyle Date: Wed, 6 Dec 2023 16:18:49 +0000 Subject: [PATCH] Add day 3 --- 3.hs | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100755 3.hs diff --git a/3.hs b/3.hs new file mode 100755 index 0000000..b3a1d06 --- /dev/null +++ b/3.hs @@ -0,0 +1,87 @@ +#!/usr/bin/env nix-shell +#!nix-shell -i runghc -p "haskellPackages.ghcWithPackages (pkgs: with pkgs; [ ])" +import Data.Char (isNumber) +import Data.List (findIndices) + +{- https://adventofcode.com/2023/day/3 -} + +main = do + input <- getContents + let (schematics, symbols) = takeSymbols input + print $ sum $ part1FindNumbersAdjacentToSchematic schematics symbols + print $ sum $ map product $ part2FindGearPartNumbers schematics symbols + +-- find all the part numbers (schematics that are adjacent to a symbol) +part1FindNumbersAdjacentToSchematic :: [Schematic] -> [Symbol] -> [Int] +part1FindNumbersAdjacentToSchematic schematics symbols = map partNumber $ filter (isSchematicAdjacentToAnySymbol symbols) schematics + +-- find all part numbers for gears (schematics that are adjacent to exactly two symbols) +part2FindGearPartNumbers :: [Schematic] -> [Symbol] -> [[Int]] +part2FindGearPartNumbers schematics symbols = map (map partNumber) $ filter (\inner -> length inner == 2) $ map (findSchematicsAdjacentToSymbol schematics) symbols + +-- returns all schematics that are adjacent to the given symbol +findSchematicsAdjacentToSymbol :: [Schematic] -> Symbol -> [Schematic] +findSchematicsAdjacentToSymbol schematics symbol = filter (`isSchematicAdjacent` symbol) schematics + +-- returns true, if the given schematic is adjacent to any of the given symbols +isSchematicAdjacentToAnySymbol :: [Symbol] -> Schematic -> Bool +isSchematicAdjacentToAnySymbol symbol schematic = any (isSchematicAdjacent schematic) symbol + +-- returns true, if the given schematic is directly adjacent to the given symbol +isSchematicAdjacent :: Schematic -> Symbol -> Bool +isSchematicAdjacent sc sy = isAdjacent (symbolCoords sy) (schematicCoords sc) + +-- returns true, grid position (px, py) is adjacent to single height multi column grid position (rx, ry, width) +isAdjacent :: (Int, Int) -> (Int, Int, Int) -> Bool +isAdjacent (px, py) (rx, ry, width) = + let leftX = rx + rightX = rx + width - 1 + upperY = ry + 1 + lowerY = ry - 1 + in (px >= leftX - 1 && px <= rightX + 1 && py == ry) -- adjacent horizontally + || (py == upperY || py == lowerY) && (px >= leftX && px <= rightX) -- adjacent vertically + || (px == leftX - 1 || px == rightX + 1) && (py == upperY || py == lowerY) -- adjacent diagonally + +data Schematic = Schematic + { partNumber :: Int, + schematicCoords :: (Int, Int, Int) + } + deriving (Show) + +data Symbol = Symbol + { symbolCoords :: (Int, Int), + symbolType :: Char + } + deriving (Show) + +-- parse the entire input +takeSymbols :: String -> ([Schematic], [Symbol]) +takeSymbols input = takeSymbol input Nothing (0, 0) [] [] + +-- recursively parses the input character by character +takeSymbol :: String -> Maybe Schematic -> (Int, Int) -> [Schematic] -> [Symbol] -> ([Schematic], [Symbol]) +takeSymbol "" Nothing _ schematicAcc symbolAcc = (schematicAcc, symbolAcc) +takeSymbol "" (Just inProgressSchematic) _ schematicAcc symbolAcc = (schematicAcc ++ [inProgressSchematic], symbolAcc) +takeSymbol (x : xs) inProgressSchematic (posX, posY) schematicAcc symbolAcc = + case x of + _ | isNumber x -> takeSymbol xs (Just $ appendToSchematic inProgressSchematic (posX, posY) (read [x])) (posX + 1, posY) schematicAcc symbolAcc + '.' -> takeSymbol xs Nothing (posX + 1, posY) (maybeAppend schematicAcc inProgressSchematic) symbolAcc + '\n' -> takeSymbol xs Nothing (0, posY + 1) (maybeAppend schematicAcc inProgressSchematic) symbolAcc + _ -> takeSymbol xs Nothing (posX + 1, posY) (maybeAppend schematicAcc inProgressSchematic) (symbolAcc ++ [buildSymbol posX posY x]) + +-- appends a character to the schematic, creating a new schematic if one isn't already instantiated +appendToSchematic :: Maybe Schematic -> (Int, Int) -> Int -> Schematic +appendToSchematic (Just schematic) _ c = + let (x, y, n) = schematicCoords schematic + currPartNumber = partNumber schematic + in schematic {partNumber = currPartNumber * 10 + c, schematicCoords = (x, y, n + 1)} +appendToSchematic Nothing (x, y) c = Schematic {partNumber = c, schematicCoords = (x, y, 1)} + +-- append a Maybe Schematic to [Schematic] +maybeAppend :: [Schematic] -> Maybe Schematic -> [Schematic] +maybeAppend out (Just new) = out ++ [new] +maybeAppend out Nothing = out + +-- easy constructor for a Symbol +buildSymbol :: Int -> Int -> Char -> Symbol +buildSymbol x y symbolType = Symbol {symbolCoords = (x, y), symbolType} -- libgit2 1.7.2