From 1ee8be2cb9f8881ac46a5369f766043accf6d102 Mon Sep 17 00:00:00 2001 From: Jacob Lagares Pozo Date: Thu, 1 Dec 2022 06:22:19 +0100 Subject: [PATCH] Big day! --- LICENSE | 30 ----------- advlib.cabal | 15 ++++-- package.yaml | 46 ++++++++++------- src/Advent.hs | 140 +++++++++++++++++++++++++++++++++++++--------------- src/Advent/Parse.hs | 7 +++ stack.yaml | 2 +- stack.yaml.lock | 8 +-- unlicense | 24 +++++++++ 8 files changed, 176 insertions(+), 96 deletions(-) delete mode 100644 LICENSE rewrite package.yaml (72%) rewrite src/Advent.hs (94%) create mode 100644 src/Advent/Parse.hs create mode 100644 unlicense diff --git a/LICENSE b/LICENSE deleted file mode 100644 index fd3cd33..0000000 --- a/LICENSE +++ /dev/null @@ -1,30 +0,0 @@ -Copyright Jacob Lagares Pozo (c) 2021 - -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - - * Neither the name of Jacob Lagares Pozo nor the names of other - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/advlib.cabal b/advlib.cabal index ec46ebe..730bdaf 100644 --- a/advlib.cabal +++ b/advlib.cabal @@ -9,21 +9,30 @@ version: 0.1.0.0 description: Advent of code boilerplate. author: Jacob Lagares Pozo maintainer: jlagarespo@protonmail.com -copyright: 2021 Jacob Lagares Pozo license: Unlicense -license-file: LICENSE build-type: Simple library exposed-modules: Advent + Advent.Parse other-modules: Paths_advlib autogen-modules: Paths_advlib hs-source-dirs: src - ghc-options: -threaded -rtsopts -with-rtsopts=-N + default-extensions: + OverloadedStrings + ghc-options: -O2 build-depends: base >=4.7 && <5 + , bytestring + , directory + , exceptions + , http-conduit + , http-types + , mtl + , text + , time default-language: Haskell2010 diff --git a/package.yaml b/package.yaml dissimilarity index 72% index 9669f11..89dd0ba 100644 --- a/package.yaml +++ b/package.yaml @@ -1,19 +1,27 @@ -name: advlib -version: 0.1.0.0 -# github: "jlagarespo/advlib" -license: Unlicense -author: "Jacob Lagares Pozo" -maintainer: "jlagarespo@protonmail.com" -copyright: "2021 Jacob Lagares Pozo" - -description: Advent of code boilerplate. - -dependencies: -- base >= 4.7 && < 5 - -library: - source-dirs: src - ghc-options: - - -threaded - - -rtsopts - - -with-rtsopts=-N +name: advlib +version: 0.1.0.0 +license: Unlicense +author: "Jacob Lagares Pozo" +maintainer: "jlagarespo@protonmail.com" + +description: Advent of code boilerplate. + +dependencies: +- base >= 4.7 && < 5 + +library: + source-dirs: src + ghc-options: + - -O2 + dependencies: + - text + - bytestring + - mtl + - exceptions + - time + - directory + - http-conduit + - http-types + +default-extensions: +- OverloadedStrings diff --git a/src/Advent.hs b/src/Advent.hs dissimilarity index 94% index 1572f64..e4531cb 100644 --- a/src/Advent.hs +++ b/src/Advent.hs @@ -1,39 +1,101 @@ -module Advent where - -import Control.Concurrent (threadDelay) -import System.CPUTime (getCPUTime) -import System.Environment (getArgs) -import System.IO - -runDay :: (Show a, Integral a) => a -> a -> IO () -runDay part1 part2 = - putStr "Part 1: " >> print part1 >> - putStr "Part 2: " >> print part2 - -runDayVis :: (Show a, Integral a) => a -> a -> IO () -> IO () -runDayVis part1 part2 vis = do - args <- getArgs - if "--visualization" `elem` args - then vis - else runDay part1 part2 - -withInput :: (String -> IO ()) -> IO () -withInput f = do - hSetBuffering stdin NoBuffering - hSetBuffering stdout NoBuffering - - args <- getArgs - input <- readFile $ head args - - f input - -timeTaken :: IO () -> IO () -timeTaken f = do - start <- getCPUTime - f - end <- getCPUTime - let time = end - start - putStrLn $ " " ++ show (time `div` 1000000) ++ " µs" - -sleep :: Int -> IO () -sleep = threadDelay . (*1000) +{-# LANGUAGE FlexibleContexts #-} +module Advent (runAdvent, getDay, cacheAllDays) where + +import Control.Concurrent (threadDelay) + +import Data.ByteString.Char8 (pack) +import Data.ByteString.Lazy (ByteString) +import qualified Data.Text.Lazy as L +import qualified Data.Text.Lazy.IO as L +import qualified Data.Text.Lazy.Encoding as L + +import Data.Time.Clock +import Data.Time.Calendar +import Data.Time.LocalTime +import Data.Time.Format + +import Control.Monad.Catch +import Control.Monad.Reader + +import System.Directory +import System.Environment + +import Network.HTTP.Conduit +import Network.HTTP.Types +import Data.Time (ZonedTime(ZonedTime)) + +import System.IO (BufferMode(NoBuffering), hSetBuffering, stdout) + +runAdvent :: MonadIO m => ReaderT Manager m b -> m b +runAdvent f = do + liftIO $ hSetBuffering stdout NoBuffering + man <- liftIO $ newManager tlsManagerSettings + runReaderT f man + +download :: (MonadReader Manager m, MonadIO m, MonadThrow m) => String -> m (Response ByteString) +download url = do + man <- ask + req <- parseRequest url + session <- liftIO $ getEnv "AOC_SESSION" + let sessionCookie = Cookie + { cookie_name = "session" + , cookie_value = pack session + , cookie_expiry_time = future + , cookie_domain = "adventofcode.com" + , cookie_path = "/" + , cookie_creation_time = past + , cookie_last_access_time = past + , cookie_persistent = False + , cookie_host_only = False + , cookie_secure_only = False + , cookie_http_only = False + } + httpLbs req {cookieJar = Just $ createCookieJar [sessionCookie]} man + + where + past = UTCTime (ModifiedJulianDay 56200) (secondsToDiffTime 0) + future = UTCTime (ModifiedJulianDay 562000) (secondsToDiffTime 0) + +getDay :: (MonadReader Manager m, MonadIO m, MonadThrow m) => Int -> Int -> m String +getDay year day = do + cached <- liftIO $ (&&) <$> doesFileExist dayCache <*> doesFileExist inputCache + if cached + then liftIO $ readFile dayCache + else do + liftIO $ putStrLn $ "Caching " <> show year <> "/" <> show day + liftIO $ createDirectoryIfMissing True cacheDir + day <- retreiveDay + liftIO $ writeFile dayCache day + pure day + + where + cacheDir = "aocache/" + dayCache = cacheDir <> show year <> "." <> show day + inputCache = dayCache <> ".input" + + retreiveDay = do + day <- download $ "https://adventofcode.com/" <> show year <> "/day/" <> show day <> "/input" + if statusCode (responseStatus day) == 200 + then do + let body = L.unpack . L.decodeUtf8 . responseBody + pure $ body day + else do + -- TODO: Check calendar to know how long to wait for!!! + currentTime <- liftIO getCurrentTime + let estTime = utcToZonedTime (hoursToTimeZone (-5)) currentTime + dayTime = zonedTimeToUTC $ estTime { zonedTimeToLocalTime = (zonedTimeToLocalTime estTime) { localTimeOfDay = midnight } } + dayTime' | currentTime > dayTime = addUTCTime nominalDay dayTime + | otherwise = dayTime + countdown dayTime' + retreiveDay + + countdown dest = do + current <- liftIO getCurrentTime + when (current <= dest) $ do + let remaining = dest `diffUTCTime` current + liftIO $ putStr $ formatTime defaultTimeLocale "%H:%M:%S\r" remaining + liftIO $ threadDelay 1000000 + countdown dest + +cacheAllDays :: (MonadReader Manager m, MonadIO m, MonadThrow m) => m () +cacheAllDays = sequence_ [getDay year day | year <- [2015..2021], day <- [1..25]] diff --git a/src/Advent/Parse.hs b/src/Advent/Parse.hs new file mode 100644 index 0000000..3129b27 --- /dev/null +++ b/src/Advent/Parse.hs @@ -0,0 +1,7 @@ +module Advent.Parse (clumps) where + +clumps :: [String] -> [[String]] +clumps [] = [] +clumps lines = + let (x, xs) = break (=="") lines + in x : clumps (drop 1 xs) diff --git a/stack.yaml b/stack.yaml index 880712e..e4c54f5 100644 --- a/stack.yaml +++ b/stack.yaml @@ -18,7 +18,7 @@ # resolver: ./custom-snapshot.yaml # resolver: https://example.com/snapshots/2018-01-01.yaml resolver: - url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/20/0.yaml + url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/19/33.yaml # User packages to be built. # Various formats can be used as shown in the example below. diff --git a/stack.yaml.lock b/stack.yaml.lock index c818f90..303e47d 100644 --- a/stack.yaml.lock +++ b/stack.yaml.lock @@ -6,8 +6,8 @@ packages: [] snapshots: - completed: - sha256: a2cbcd2f37010a64c4ef74c21fd7e55982a07b49840d2bed306f9bac9981a9c3 - size: 648420 - url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/20/0.yaml + sha256: 6d1532d40621957a25bad5195bfca7938e8a06d923c91bc52aa0f3c41181f2d4 + size: 619204 + url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/19/33.yaml original: - url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/20/0.yaml + url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/19/33.yaml diff --git a/unlicense b/unlicense new file mode 100644 index 0000000..68a49da --- /dev/null +++ b/unlicense @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to -- 2.11.4.GIT