Skip to content

Instantly share code, notes, and snippets.

@skatenerd
Created December 1, 2023 18:30
Show Gist options
  • Save skatenerd/825014f7ca0cedf1d35c0ab06937d4e5 to your computer and use it in GitHub Desktop.
Save skatenerd/825014f7ca0cedf1d35c0ab06937d4e5 to your computer and use it in GitHub Desktop.
AOC 2023 Day 1
module DayOne
( partOne, decodeLine, substringIndices, Digit (..), operateOnString, toLower, allDigits, firstDigit, lastDigit, scoreDigit, scoreLine, partTwo
) where
import qualified Data.Text as T
import qualified Data.Text.IO as TI
import qualified Data.Maybe as M
import qualified Data.List as L
import qualified Data.List.Safe as LS
-- ############# Data Structures ##############
data Digit = Zero | One | Two | Three | Four | Five | Six | Seven | Eight | Nine deriving (Show, Enum, Eq)
allDigits = enumFrom Zero
scoreDigit d = M.fromJust $ L.elemIndex d allDigits
-- #############################################
toLower = operateOnString T.toLower
operateOnString f = T.unpack . f . T.pack
substringIndices target world = go world 0
where go "" _ = []
go remainingWorld currentIndex =
if L.isPrefixOf target remainingWorld
then currentIndex : go (tail remainingWorld) (currentIndex + 1)
else go (tail remainingWorld) (currentIndex + 1)
hitIndices :: Digit -> String -> [Int]
hitIndices target world = fullNameIndices ++ numeralIndices
where fullNameIndices = substringIndices (toLower (show target)) world
numeralIndices = substringIndices (toLower (show (scoreDigit target))) world
firstDigit :: String -> Maybe Digit
firstDigit s = LS.minimumBy score allDigits
where score a b = myCompare (hitIndices a s) (hitIndices b s)
myCompare [] [] = EQ
myCompare [] _ = GT
myCompare _ [] = LT
myCompare a b = compare (L.minimum a) (L.minimum b)
lastDigit :: String -> Maybe Digit
lastDigit s = LS.maximumBy score allDigits
where score a b = compare maxLeftHit maxRightHit
where maxLeftHit :: Maybe Int = (LS.maximum (hitIndices a s))
maxRightHit :: Maybe Int = (LS.maximum (hitIndices b s))
scoreLine :: String -> Int
scoreLine line = read $ map (head . show. scoreDigit) $ M.catMaybes [firstDigit line, lastDigit line]
partTwo :: IO ()
partTwo = do
fileBody <- TI.readFile "/users/wailee.feman/Downloads/input.txt"
let allLines = T.lines fileBody
ints = map (scoreLine . T.unpack) allLines
answer = sum ints
print answer
-- part 1
partOne :: IO ()
partOne = do
fileBody <- TI.readFile "/users/wailee.feman/Downloads/input.txt"
let allLines = T.lines fileBody
ints = map (decodeLine . T.unpack) allLines
answer = sum ints
print answer
decodeLine :: String -> Int
decodeLine s = read [firstDigit, lastDigit]
where firstDigit = head digits
lastDigit = last digits
digits :: String
digits = filter isDigit s
isDigit :: Char -> Bool
isDigit c = elem c allDigitsString
allDigitsString :: String
allDigitsString = enumFromTo '0' '9'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment