🏡 index : ~doyle/aoc.git

#!/usr/bin/env nix-shell
#!nix-shell -i runghc -p "haskellPackages.ghcWithPackages (pkgs: with pkgs; [ ])"
import Data.List (find, isInfixOf)
import Data.Maybe (catMaybes)

{- https://adventofcode.com/2023/day/1 -}

main = print =<< run 0

-- recursively read each line from stdin, concatenating first and last digits and folding the result into a sum
run :: Int -> IO Int
run acc = do
  line <- getLine
  if null line
    then return acc
    else do
      let x = concatFirstLastDigitsInString line
      run $ acc + x

-- read first and last digit in a string and concatenate the two together
concatFirstLastDigitsInString :: String -> Int
concatFirstLastDigitsInString s =
  case catMaybes [findDigitFromLeft "" s, findDigitFromRight "" s] of
    [x, y] -> x * 10 + y
    [x] -> x * 11
    _ -> 0

-- find the first digit in the string, searching from the left hand side
findDigitFromLeft :: String -> String -> Maybe Int
findDigitFromLeft acc "" = findDigit acc
findDigitFromLeft acc (x : xs) = case findDigit acc of
  Just v -> Just v
  Nothing -> findDigitFromLeft (acc ++ [x]) xs

-- find the last digit in the string, searching from the right hand side
findDigitFromRight :: String -> String -> Maybe Int
findDigitFromRight acc "" = findDigit acc
findDigitFromRight acc xs = case findDigit acc of
  Just v -> Just v
  Nothing -> findDigitFromRight (last xs : acc) (init xs)

-- finds a digit in either textual or numeric form and returns it as an int
findDigit :: String -> Maybe Int
findDigit s = case find (`isInfixOf` s) digitAsText of
  Just textual -> lookup textual digitMap
  Nothing -> Nothing
  where
    digitMap =
      [ ("eight", 8),
        ("seven", 7),
        ("three", 3),
        ("nine", 9),
        ("four", 4),
        ("five", 5),
        ("two", 2),
        ("one", 1),
        ("six", 6),
        ("1", 1),
        ("2", 2),
        ("3", 3),
        ("4", 4),
        ("5", 5),
        ("6", 6),
        ("7", 7),
        ("8", 8),
        ("9", 9)
      ]
    digitAsText = map fst digitMap