1
0
Fork 0
main
Bill Ewanick 2023-12-01 15:14:28 -05:00
parent 6ca4b02c67
commit 2005e169f4
2 changed files with 136 additions and 0 deletions

View File

@ -1,6 +1,9 @@
{
"cSpell.words": [
"Bifunctor",
"bimap",
"Collatz",
"Combinators",
"concat",
"coprime",
"elems",

View File

@ -0,0 +1,133 @@
-- https://adventofcode.com/2023/day/1
import Data.Bifunctor (bimap)
import Data.Maybe (fromMaybe)
import Text.ParserCombinators.ReadP (ReadP, choice, many, readP_to_S,
string, (<++))
main :: IO ()
main = do
entries <- lines <$> readFile "src/advent_of_code/2023/input1"
print "Advent of Code 2022 - Day 4"
-- print entries
print ("Part 1: " <> show (solveP1 entries))
print ("Part 2: " <> show (solveP2 entries))
--
-- Part 1
--
solveP1 :: [String] -> Int
solveP1 = sum . map solveP1Line
solveP1Line :: String -> Int
solveP1Line = sumPairS . bimap head last . doubleString . filter isNumP1 . tokenized tokensP1
tokensP1 :: ReadP String
tokensP1 = parseNumberChars <++ parseChars
--
-- Part 2
--
solveP2 :: [String] -> Int
solveP2 = sum . map solveP2Line
solveP2Line :: String -> Int
solveP2Line = sumPairS . bimap a b . doubleString
where
a = head . condense . fromLeft
b = last . condense . fromRight
-- Need to parse from both sides
-- "oneight" should return 18, not 11
condense = map stringToNum . filter isNumP2
fromLeft = tokenized tokensP2
fromRight = map reverse . reverse . tokenized tokensP2' . reverse
tokensP2 :: ReadP String
tokensP2 = parseNumberWords <++ parseNumberChars <++ parseChars
tokensP2' :: ReadP String
tokensP2' = parseNumberWords' <++ parseNumberChars <++ parseChars
solveP2LineBad :: String -> Int
solveP2LineBad = sumPairS . bimap head last . doubleString . map stringToNum . filter isNumP2 . tokenized tokensP2
--
-- Utility functions
--
-- Doing this because I want to use a bifunctor
doubleString :: str -> (str, str)
doubleString str = (str, str)
sumPairS :: (String, String) -> Int
sumPairS (x,y) = read (x ++ y)
stringToNum :: String -> String
stringToNum str = fromMaybe str (lookup str $ zip numberWords numberChars)
--
-- Boilerplate equality checks
-- Now condensed
--
isNumP1 :: String -> Bool
isNumP1 = flip elem numberChars
isNumP2 :: String -> Bool
isNumP2 = flip elem (numberChars ++ numberWords)
--
-- Parsing for question
--
numberWords :: [String]
numberWords = ["zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"]
numberChars :: [String]
numberChars = map show [0..9]
letterChars :: String
letterChars = ['a'..'z']
parseNumberWords :: ReadP String
parseNumberWords = choice $ map string numberWords
parseNumberWords' :: ReadP String
parseNumberWords' = choice $ map (string . reverse) numberWords
parseNumberChars :: ReadP String
parseNumberChars = choice $ map string numberChars
parseChars :: ReadP String
parseChars = choice $ map (\c -> string [c]) letterChars
tokenized :: ReadP a -> String -> [a]
tokenized tokenSet = fst . last . readP_to_S (many tokenSet)
--
-- Examples
--
example1 :: [String]
example1 =
[ "1abc2"
, "pqr3stu8vwx"
, "a1b2c3d4e5f"
, "treb7uchet"
]
example2 :: [String]
example2 =
[ "two1nine"
, "eightwothree"
, "abcone2threexyz"
, "xtwone3four"
, "4nineeightseven2"
, "zoneight234"
, "7pqrstsixteen"
]