From 9ca0d11cb692f6ce3e7d4a23d199ccd5da83fb8a Mon Sep 17 00:00:00 2001 From: Riley Apeldoorn Date: Fri, 10 Dec 2021 22:18:58 +0100 Subject: [PATCH] =?UTF-8?q?Day=205:=20It's=20Finally=20Fast=20=E2=84=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 5/solution.hs | 92 +++++++++++++++------------------------------------ 1 file changed, 26 insertions(+), 66 deletions(-) diff --git a/5/solution.hs b/5/solution.hs index ac4d18a..df404d9 100644 --- a/5/solution.hs +++ b/5/solution.hs @@ -1,78 +1,38 @@ import Data.List import Data.List.Split -import Control.Monad (join) -import Control.Concurrent +import Data.Char (isDigit) main :: IO () -main = do - input <- readFile "5/example.txt" - let x = parse $ lines input +main = do + input <- readFile "5/riley.txt" + let x = parse <$> lines input print $ f x print $ g x where - f = length . nub . solve . filter (not . diagonal) - g = length . nub . solve + f = solve . filter (not . diagonal) + g = solve -parse :: [String] -> [(Point,Point)] -parse = map (parseLine . words) +-- | Extract all the numbers from the given string +parse :: String -> [Int] +parse = map read . wordsBy (not . isDigit) -parseLine :: [String] -> (Point,Point) -parseLine [ s, "->", e ] = (a, b) - where a = parseCoord s - b = parseCoord e +-- | Determine if the given line is diagonal. +diagonal :: [Int] -> Bool +diagonal [ x1, y1, x2, y2 ] = x1 /= x2 && y1 /= y2 -toRange :: (Point,Point) -> [Point] -toRange (a @ (xa,ya), b @ (xb,yb)) - | diagonal (a,b) = makeDiagonal a b - | otherwise = [ (x,y) | x <- [ x1 .. x2 ], y <- [ y1 .. y2 ] ] - where - x1 = min xa xb - x2 = max xa xb - y1 = min ya yb - y2 = max ya yb +solve :: [[Int]] -> Int +solve = length . filter ((>= 2) . length) . group . sort . (>>= range) -parseCoord :: String -> (Int,Int) -parseCoord l = (head n, last n) - where - n = map read . wordsBy (== ',') $ l - -solve :: [(Point, Point)] -> [Point] -solve [_] = [] -solve (p:ps) = overlapping' p ps ++ solve ps - -overlapping' :: (Point, Point) -> [(Point, Point)] -> [Point] -overlapping' _ [] = [] -overlapping' p1 (p2:ps) = overlap p1 p2 ++ overlapping' p1 ps - -diagonal :: (Point,Point) -> Bool -diagonal (a,b) = xof a /= xof b && yof a /= yof b - -type Point = (Int,Int) - -xof :: Point -> Int -xof = fst - -yof :: Point -> Int -yof = snd - -overlap :: (Point,Point) -> (Point,Point) -> [Point] -overlap a @ (sa,ea) b @ (sb,eb) - | x && y = toRange a `intersect` toRange b - | otherwise = [] - where - x = xof sa >= xof sb || xof sa <= xof sb - y = yof sa >= yof sb || yof sa <= yof sb - -makeDiagonal :: (Int, Int) -> (Int, Int) -> [(Int, Int)] -makeDiagonal (a, b) (c, d) - | (a > c && b > d) || (a < c && b < d) = - let x1 = min a c - x2 = max a c - y1 = min b d - in [(x1 + i, y1 + i) | i <- [0..(x2 - x1)]] - | otherwise = - let x1 = min a c - x2 = max a c - y1 = max b d - in [(x1 + i, y1 - i) | i <- [0..(x2 - x1)]] +-- | Transform a line to a list of points on that line. +range :: [Int] -> [(Int,Int)] +range [ x1, y1, x2, y2 ] + | x1 == x2 = [ (x1,y) | y <- ys ] + | y1 == y2 = [ (x,y1) | x <- xs ] + | otherwise = zip xs ys + where xs = gen x1 x2 + ys = gen y1 y2 +-- | Generate a list of numbers from `a` to `b`. +gen :: Int -> Int -> [Int] +gen a b | a > b = [ b .. a ] + | otherwise = reverse [ a .. b ]