--- /dev/null
+-- Writeup at https://work.njae.me.uk/2022/12/04/advent-of-code-2022-day-4/
+
+import System.Environment
+import Data.Text (Text)
+import qualified Data.Text.IO as TIO
+import Data.Attoparsec.Text hiding (Result)
+-- import Control.Applicative
+
+data Assignment = Assignment Int Int deriving (Show, Eq)
+type Pair = (Assignment, Assignment)
+
+main :: IO ()
+main =
+ do dataFileName <- getDataFileName
+ text <- TIO.readFile dataFileName
+ let pairs = successfulParse text
+ print $ part1 pairs
+ print $ part2 pairs
+
+getDataFileName :: IO String
+getDataFileName =
+ do args <- getArgs
+ progName <- getProgName
+ let baseDataName = if null args
+ then progName
+ else head args
+ let dataFileName = "data/" ++ baseDataName ++ ".txt"
+ return dataFileName
+
+part1 :: [Pair] -> Int
+part1 = length . (filter hasContainment)
+
+part2 :: [Pair] -> Int
+part2 = length . (filter overlaps)
+
+hasContainment, disjoint, overlaps :: Pair -> Bool
+hasContainment (assignment1, assignment2) =
+ (assignment1 `contains` assignment2) || (assignment2 `contains` assignment1)
+
+disjoint (assignment1, assignment2) =
+ (assignment1 `before` assignment2) || (assignment2 `before` assignment1)
+
+overlaps pair = not $ disjoint pair
+
+contains, before :: Assignment -> Assignment -> Bool
+contains (Assignment lower1 upper1) (Assignment lower2 upper2) =
+ (lower1 <= lower2) && (upper1 >= upper2)
+
+before (Assignment _lower1 upper1) (Assignment lower2 _upper2) = (upper1 < lower2)
+
+-- Parse the input file
+
+pairsP :: Parser [Pair]
+pairP :: Parser Pair
+assignmentP :: Parser Assignment
+
+pairsP = pairP `sepBy` endOfLine
+pairP = (,) <$> assignmentP <* "," <*> assignmentP
+
+assignmentP = Assignment <$> decimal <* "-" <*> decimal
+
+successfulParse :: Text -> [Pair]
+successfulParse input =
+ case parseOnly pairsP input of
+ Left _err -> [] -- TIO.putStr $ T.pack $ parseErrorPretty err
+ Right pairs -> pairs