{-# Language ImportQualifiedPost, OverloadedStrings #-}
{-|
Module      : Advent.Input
Description : Input file helpers
Copyright   : (c) Eric Mertens, 2021
License     : ISC
Maintainer  : emertens@gmail.com

This module provides input files in some of the most commonly
needed formats. It either automatically loads from an @inputs@
directory, or takes the input file as a command-line argument.

-}
module Advent.Input where

import Advent.Coord (Coord(..), coordLines)
import Data.Array.Unboxed qualified as A
import Data.Map (Map)
import Data.Map.Strict qualified as SMap
import System.Environment (getArgs)
import System.IO (hPutStrLn, stderr)
import Text.Printf (printf)

-- | Get the input for the given day.
--
-- If a filename is provided in the command line that will be used as the
-- input file.
--
-- If the filename is @-@ the stdin will be used as the input file.
--
-- Otherwise the input text file corresponding to the day number will be used.
getRawInput :: Int {- ^ year -} -> Int {- ^ day number -} -> IO String
getRawInput :: Int -> Int -> IO FilePath
getRawInput Int
y Int
d =
  do args <- IO [FilePath]
getArgs
     case args of
       []    -> FilePath -> IO FilePath
readFile (FilePath -> Int -> Int -> FilePath
forall r. PrintfType r => FilePath -> r
printf FilePath
"inputs/%d/%02d.txt" Int
y Int
d)
       FilePath
"-":[FilePath]
_ -> Handle -> FilePath -> IO ()
hPutStrLn Handle
stderr FilePath
"Ready!" IO () -> IO FilePath -> IO FilePath
forall a b. IO a -> IO b -> IO b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> IO FilePath
getContents
       FilePath
"+":FilePath
input:[FilePath]
_ -> FilePath -> IO FilePath
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure FilePath
input
       FilePath
fn:[FilePath]
_  -> FilePath -> IO FilePath
readFile FilePath
fn

-- | Default input filename given a day number
inputFileName :: Int {- ^ day -} -> FilePath
inputFileName :: Int -> FilePath
inputFileName = FilePath -> Int -> FilePath
forall r. PrintfType r => FilePath -> r
printf FilePath
"inputs/%02d.txt"

-- | Load input file as a list of lines.
getInputLines :: Int {- ^ year -} -> Int {- ^ day -} -> IO [String]
getInputLines :: Int -> Int -> IO [FilePath]
getInputLines Int
y Int
d = FilePath -> [FilePath]
lines (FilePath -> [FilePath]) -> IO FilePath -> IO [FilePath]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Int -> Int -> IO FilePath
getRawInput Int
y Int
d

-- | Load input file as a rectangular array of characters.
getInputArray :: Int {- ^ year -} -> Int {- ^ day -} -> IO (A.UArray Coord Char)
getInputArray :: Int -> Int -> IO (UArray Coord Char)
getInputArray Int
y Int
d =
  do xs <- Int -> Int -> IO [FilePath]
getInputLines Int
y Int
d
     pure $! A.listArray (C 0 0, C (length xs - 1) (length (head xs) - 1)) (concat xs)

-- | Load input file as a 2-dimensional map of characters.
getInputMap :: Int {- ^ year -} -> Int {- ^ day -} -> IO (Map Coord Char)
getInputMap :: Int -> Int -> IO (Map Coord Char)
getInputMap Int
y Int
d =
  do xs <- Int -> Int -> IO [FilePath]
getInputLines Int
y Int
d
     pure $! SMap.fromList (coordLines xs)