Day 5: It's Finally Fast ™
This commit is contained in:
parent
4ffd27205d
commit
9ca0d11cb6
1 changed files with 26 additions and 66 deletions
|
@ -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
|
||||
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 ]
|
||||
|
|
Loading…
Reference in a new issue