alt 05
This commit is contained in:
parent
8b5adfcd3b
commit
3b4c9c0962
90
code/src/05/Main2.hs
Normal file
90
code/src/05/Main2.hs
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
-- why is this slower than the other one? i dont get it
|
||||||
|
|
||||||
|
module Main where
|
||||||
|
|
||||||
|
import Data.Tuple
|
||||||
|
import Data.List
|
||||||
|
import qualified Text.Parsec as P
|
||||||
|
import qualified Data.Map as M
|
||||||
|
import Data.Map.Strict (insertWith)
|
||||||
|
|
||||||
|
type Point = (Int,Int)
|
||||||
|
type Segment = (Point,Point)
|
||||||
|
type Op = Db -> Db
|
||||||
|
type Db = M.Map Point Int
|
||||||
|
data Line =
|
||||||
|
Straight Segment
|
||||||
|
| Diag Segment
|
||||||
|
|
||||||
|
main :: IO ()
|
||||||
|
main = do
|
||||||
|
raw <- getContents
|
||||||
|
let input = parseInput raw
|
||||||
|
(straight, diag) = splitLines input
|
||||||
|
partAdb = toOps straight $ M.empty
|
||||||
|
partBdb = toOps diag $ partAdb
|
||||||
|
putStrLn $ "day5a: " ++ show (solve $ partAdb)
|
||||||
|
putStrLn $ "day5b: " ++ show (solve $ partBdb)
|
||||||
|
|
||||||
|
solve :: Db -> Int
|
||||||
|
solve db = M.size $ M.filter (>= 2) db
|
||||||
|
|
||||||
|
toOps :: [Line] -> Op
|
||||||
|
toOps ls = foldl (.) id $ map toOp ls
|
||||||
|
|
||||||
|
toOp :: Line -> Op
|
||||||
|
toOp l = foldl (.) id $ map f (createSpots l)
|
||||||
|
where
|
||||||
|
f p = insertWith (+) p 1
|
||||||
|
|
||||||
|
splitLines :: [Line] -> ([Line], [Line])
|
||||||
|
splitLines = go ([],[])
|
||||||
|
where
|
||||||
|
go acc [] = acc
|
||||||
|
go (al,ar) (l@(Straight s):ls) = go ((l:al),ar) ls
|
||||||
|
go (al,ar) (l@(Diag s):ls) = go (al,(l:ar)) ls
|
||||||
|
|
||||||
|
parseInput :: String -> [Line]
|
||||||
|
parseInput raw = [ toLine l | Right l <- segs ]
|
||||||
|
where
|
||||||
|
segs = map (P.parse lineP []) $ lines raw
|
||||||
|
|
||||||
|
toLine :: Segment -> Line
|
||||||
|
toLine s@((x1,y1),(x2,y2))
|
||||||
|
| x1 == x2 || y1 == y2 = Straight s
|
||||||
|
| otherwise = Diag s
|
||||||
|
|
||||||
|
lineP :: P.Parsec String () Segment
|
||||||
|
lineP = do
|
||||||
|
x1 <- P.many1 P.digit
|
||||||
|
_ <- P.char ','
|
||||||
|
y1 <- P.many1 P.digit
|
||||||
|
_ <- P.string " -> "
|
||||||
|
x2 <- P.many1 P.digit
|
||||||
|
_ <- P.char ','
|
||||||
|
y2 <- P.many1 P.digit
|
||||||
|
return ((read x1, read y1), (read x2, read y2))
|
||||||
|
|
||||||
|
range :: Int -> Int -> [Int]
|
||||||
|
range x y = [ i .. j ]
|
||||||
|
where
|
||||||
|
(i,j) = if x > y then (y,x) else (x,y)
|
||||||
|
|
||||||
|
createSpots :: Line -> [Point]
|
||||||
|
createSpots (Straight ps) = runStraight ps
|
||||||
|
createSpots (Diag ps) = runDiag ps
|
||||||
|
|
||||||
|
runStraight :: Segment -> [Point]
|
||||||
|
runStraight ((x1,y1),(x2,y2))
|
||||||
|
| x1 == x2 = [ (x1,j) | j <- range y1 y2 ]
|
||||||
|
| otherwise = [ (i,y1) | i <- range x1 x2 ]
|
||||||
|
|
||||||
|
runDiag :: Segment -> [Point]
|
||||||
|
runDiag ((x1,y1),(x2,y2)) = take n $ iterate f start
|
||||||
|
where
|
||||||
|
dl (x,y) = (x+1,y+1)
|
||||||
|
dr (x,y) = (x-1,y+1)
|
||||||
|
n = (abs (x1-x2)) + 1
|
||||||
|
f = if (fst start) < (fst end) then dl else dr
|
||||||
|
(start,end) = (if y1 < y2 then id else swap) ((x1,y1),(x2,y2))
|
||||||
|
|
Loading…
Reference in a new issue