|
@@ -1,32 +1,35 @@
|
1
|
1
|
module Day6 (
|
2
|
2
|
findEnd,
|
3
|
3
|
findStart,
|
4
|
|
- isUnique,
|
5
|
4
|
day6
|
6
|
5
|
) where
|
7
|
6
|
|
8
|
|
-findMarker :: Int -> String -> Maybe Int
|
9
|
|
-findMarker windowSize = findMarker' 0 ""
|
10
|
|
- where
|
11
|
|
- findMarker' :: Int -> String -> String -> Maybe Int
|
12
|
|
- findMarker' offset window []
|
13
|
|
- | isUnique window && length window == windowSize = Just offset
|
14
|
|
- | otherwise = Nothing
|
15
|
|
- findMarker' offset window (c:cs)
|
16
|
|
- | length window < windowSize = findMarker' (offset + 1) (c:window) cs
|
17
|
|
- | not (isUnique window) = findMarker' (offset + 1) (c:init window) cs
|
18
|
|
- | isUnique window = Just offset
|
19
|
|
- | otherwise = Nothing
|
|
7
|
+import qualified Data.Sequence as S
|
|
8
|
+import Data.Sequence (Seq (..), (|>))
|
20
|
9
|
|
21
|
10
|
findStart :: String -> Maybe Int
|
22
|
|
-findStart = findMarker 14
|
|
11
|
+findStart = findUniqueSubstring 14
|
23
|
12
|
|
24
|
13
|
findEnd :: String -> Maybe Int
|
25
|
|
-findEnd = findMarker 4
|
|
14
|
+findEnd = findUniqueSubstring 4
|
26
|
15
|
|
27
|
|
-isUnique :: (Eq a) => [a] -> Bool
|
28
|
|
-isUnique [] = True
|
29
|
|
-isUnique (c:cs) = c `notElem` cs && isUnique cs
|
|
16
|
+findUniqueSubstring :: Int -> String -> Maybe Int
|
|
17
|
+findUniqueSubstring size input
|
|
18
|
+ | length input < size = Nothing -- imposible to find a substring because input is too small
|
|
19
|
+ | otherwise = find 0 S.empty $ S.fromList input
|
|
20
|
+ where
|
|
21
|
+ find :: Int -> Seq Char -> Seq Char -> Maybe Int
|
|
22
|
+ find _ _ Empty = Nothing
|
|
23
|
+ find off window (r :<| rs)
|
|
24
|
+ = case S.elemIndexL r window of -- is new element in window?
|
|
25
|
+ Nothing -> if S.length window == size -1 -- Element not found, but is our window large nough?
|
|
26
|
+ then Just nextOff -- Large enough, we got a winner!
|
|
27
|
+ else find nextOff enlargedWindow rs -- Not large enough, push new element to the end of the window
|
|
28
|
+ Just i -> find nextOff (removeConflict (i + 1)) rs -- continue after clearing window
|
|
29
|
+ where
|
|
30
|
+ nextOff = off + 1
|
|
31
|
+ enlargedWindow = window |> r
|
|
32
|
+ removeConflict i = S.drop i enlargedWindow
|
30
|
33
|
|
31
|
34
|
day6 :: IO ()
|
32
|
35
|
day6 = do
|