summaryrefslogtreecommitdiffstats
path: root/day06/app
diff options
context:
space:
mode:
authorShivesh Mandalia <mail@shivesh.org>2023-02-05 01:32:03 +0000
committerShivesh Mandalia <mail@shivesh.org>2023-02-05 01:32:03 +0000
commit4cb3fa6de434d287bb46ca94c3026880164cb774 (patch)
tree38be4bcf69883777d7243b1d732c4ee8f184df30 /day06/app
parent21c330dcd6f9b873a37e04487a24ac21606c3aee (diff)
downloadAOC_2022_haskell-4cb3fa6de434d287bb46ca94c3026880164cb774.tar.gz
AOC_2022_haskell-4cb3fa6de434d287bb46ca94c3026880164cb774.zip
complete day 6 and 7
Diffstat (limited to 'day06/app')
-rw-r--r--day06/app/Main.hs154
1 files changed, 154 insertions, 0 deletions
diff --git a/day06/app/Main.hs b/day06/app/Main.hs
new file mode 100644
index 0000000..68f1492
--- /dev/null
+++ b/day06/app/Main.hs
@@ -0,0 +1,154 @@
+{-
+--- Day 6: Tuning Trouble ---
+
+The preparations are finally complete; you and the Elves leave camp on foot and begin to make
+your way toward the star fruit grove.
+
+As you move through the dense undergrowth, one of the Elves gives you a handheld device. He
+says that it has many fancy features, but the most important one to set up right now is the
+communication system.
+
+However, because he's heard you have significant experience dealing with signal-based systems,
+he convinced the other Elves that it would be okay to give you their one malfunctioning device
+- surely you'll have no problem fixing it.
+
+As if inspired by comedic timing, the device emits a few colorful sparks.
+
+To be able to communicate with the Elves, the device needs to lock on to their signal. The
+signal is a series of seemingly-random characters that the device receives one at a time.
+
+To fix the communication system, you need to add a subroutine to the device that detects a
+start-of-packet marker in the datastream. In the protocol being used by the Elves, the start
+of a packet is indicated by a sequence of four characters that are all different.
+
+The device will send your subroutine a datastream buffer (your puzzle input); your subroutine
+needs to identify the first position where the four most recently received characters were all
+different. Specifically, it needs to report the number of characters from the beginning of the
+buffer to the end of the first such four-character marker.
+
+For example, suppose you receive the following datastream buffer:
+
+```
+mjqjpqmgbljsphdztnvjfqwrcgsmlb
+```
+
+After the first three characters (mjq) have been received, there haven't been enough characters
+received yet to find the marker. The first time a marker could occur is after the fourth
+character is received, making the most recent four characters mjqj. Because j is repeated, this
+isn't a marker.
+
+The first time a marker appears is after the seventh character arrives. Once it does, the last
+four characters received are jpqm, which are all different. In this case, your subroutine
+should report the value 7, because the first start-of-packet marker is complete after 7
+characters have been processed.
+
+Here are a few more examples:
+
+ bvwbjplbgvbhsrlpgdmjqwftvncz: first marker after character 5
+ nppdvjthqldpwncqszvftbrmjlhg: first marker after character 6
+ nznrnfrfntjfmvfwmzdfjlvtqnbhcprsg: first marker after character 10
+ zcfzfwzzqfrljwzlrfnpqdbhtmscgvjw: first marker after character 11
+
+How many characters need to be processed before the first start-of-packet marker is detected?
+
+--- Part Two ---
+
+Your device's communication system is correctly detecting packets, but still isn't working. It
+looks like it also needs to look for messages.
+
+A start-of-message marker is just like a start-of-packet marker, except it consists of 14
+distinct characters rather than 4.
+
+Here are the first positions of start-of-message markers for all of the above examples:
+
+ mjqjpqmgbljsphdztnvjfqwrcgsmlb: first marker after character 19
+ bvwbjplbgvbhsrlpgdmjqwftvncz: first marker after character 23
+ nppdvjthqldpwncqszvftbrmjlhg: first marker after character 23
+ nznrnfrfntjfmvfwmzdfjlvtqnbhcprsg: first marker after character 29
+ zcfzfwzzqfrljwzlrfnpqdbhtmscgvjw: first marker after character 26
+
+How many characters need to be processed before the first start-of-message marker is detected?
+-}
+{-# LANGUAGE DerivingStrategies #-}
+{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}
+{-# HLINT ignore "Use ordNub" #-}
+{-# OPTIONS_GHC -Wno-unsafe #-}
+
+module Main (main) where
+
+import Data.ByteString.Lazy (ByteString)
+import Data.Discrimination (Grouping, nub)
+import Data.List (findIndex, length)
+import Options.Applicative (Parser, ParserInfo, argument, execParser, fullDesc, help, helper, info, metavar, str)
+import Relude hiding (ByteString, elem, empty, filter, fromList, length, null, optional, readFile, splitAt)
+import Text.Parsec (ParseError, parse, (<?>))
+import Text.Parsec.ByteString.Lazy (GenParser)
+import Text.Parsec.Char (anyChar, string)
+import Text.Parsec.Combinator (eof, many1)
+import Text.Parsec.Prim (parsecMap, try)
+
+type Opts :: Type
+newtype Opts = Opts {_filename :: Text} deriving stock (Show)
+
+parseInput :: FilePath -> ByteString -> Either ParseError String
+parseInput = parse $ many1 anyChar <* (eol <|> eof)
+ where
+ eol :: GenParser t st ()
+ eol =
+ parsecMap
+ (const ())
+ ( try (string "\n\r")
+ <|> try (string "\r\n")
+ <|> string "\n"
+ <|> string "\r"
+ <?> "end of line"
+ )
+
+window :: Int -> [a] -> [[a]]
+window n xs =
+ if n > length xs
+ then []
+ else take n xs : window n (drop 1 xs)
+
+allunique :: Grouping a => [a] -> Bool
+allunique xs = nub xs == xs
+
+run :: Int -> String -> Maybe Int
+run nchars = findIndex allunique . window nchars
+
+runPart1 :: String -> Int
+runPart1 xs = case run nchars xs of
+ Nothing -> error "Failure"
+ Just res -> nchars + res
+ where
+ nchars :: Int
+ nchars = 4
+
+runPart2 :: String -> Int
+runPart2 xs = case run nchars xs of
+ Nothing -> error "Failure"
+ Just res -> nchars + res
+ where
+ nchars :: Int
+ nchars = 14
+
+main :: IO ()
+main = do
+ fileName <- toString . _filename <$> execParser opts
+ rawInput <- readFileLBS fileName
+ case parseInput fileName rawInput of
+ Left e -> do
+ putTextLn "Error parsing input:"
+ print e
+ Right r -> do
+ print $ runPart1 r
+ print $ runPart2 r
+ where
+ opts :: ParserInfo Opts
+ opts = info (helper <*> options) fullDesc
+
+ options :: Parser Opts
+ options = Opts <$> filename
+
+ filename :: Parser Text
+ filename = argument str $ metavar "filename" <> help "Input file"