{-# LANGUAGE MultiParamTypeClasses, RankNTypes, FlexibleInstances #-} {-# LANGUAGE ViewPatterns, FunctionalDependencies, TupleSections #-} module Main (main) where import System.IO import Control.Applicative import Control.Monad import Data.Array import Data.Function import Data.Functor import Data.Functor.Identity import Data.List import Data.Monoid import Debug.Trace import qualified Data.Foldable as F import qualified Data.Set as S type Node = (Int, Int) type NodeArray = Array Node (Int, [Node], [Node]) main :: IO () main = do hSetBuffering stdout NoBuffering -- DO NOT REMOVE (width, height) <- (,) <$> readLn <*> readLn let readCell d = (case d of { '.' -> (-1); _ -> read [d] }, [], []) gridLines <- replicateM height getLine let nodes' = listArray ((0,0),(width-1,height-1)) . concatMap (map readCell) $ transpose gridLines -- traceM $ unlines $ [show width, show height] ++ gridLines let firstCell f is = take 1 [ i | i <- map f is, (nodes'!i)^._1 >= 0 ] let nodes = nodes' // [ ((x1,y1),(x,ns++ns,[])) | ((x1,y1),(x,_,_)) <- zip (indices nodes') (elems nodes') , x >= 0 , let ns = firstCell (,y1) [x1+1..width-1] ++ firstCell (x1,) [y1+1..height-1] ] forM_ (head $ loop nodes (indices nodes) []) $ \((x1,y1),(x2,y2)) -> putStrLn . unwords $ map show [x1,y1,x2,y2,1] loop :: NodeArray -> [Node] -> [(Node,Node)] -> [[(Node, Node)]] loop nodes [] links = [] <$ guard (connected nodes) loop nodes (n1:ns) links = if (nodes!n1)^._1 < 1 then loop nodes ns links else do n2 <- nub $ (nodes!n1)^._2 guard $ (nodes!n2)^._1 >= 1 guard . not $ any (crosses (n1,n2)) links let nodes' = accum (\(x,ns,ls) n -> (x-1,delete n ns,n:ls)) nodes [(n1,n2), (n2,n1)] ls <- loop nodes' (n1:ns) ((n1,n2):links) return $ (n1,n2):ls crosses :: (Node,Node) -> (Node,Node) -> Bool crosses ((ax1,ay1),(bx1,by1)) ((ax2,ay2),(bx2,by2)) = (ax1 == bx1 && ay2 == by2 && (ax1 > ax2 && ax1 < bx2) && (ay2 > ay1 && ay2 < by1)) || (ax2 == bx2 && ay1 == by1 && (ax2 > ax1 && ax2 < bx1) && (ay1 > ay2 && ay1 < by2)) connected :: NodeArray -> Bool connected nodes = go (S.singleton (head allNodes)) S.empty where allNodes = filter (\i -> (nodes!i)^._1 >= 0) $ indices nodes go ns vs = case S.minView ns of Nothing -> S.size vs == length allNodes Just (n, _) -> let ns' = ns `S.union` S.fromList ((nodes!n)^._3) vs' = S.insert n vs in go (S.difference ns' vs') vs' -- -- Primitive lenses for easy access to the parts of a tuple -- type Lens s t a b = Functor f => (a -> f b) -> s -> f t type Getting r s a = (a -> Const r a) -> s -> Const r s type Setting s t a b = (a -> Identity b) -> s -> Identity t class Field1 s t a b | s -> a, t -> b, s b -> t, t a -> s where _1 :: Lens s t a b class Field2 s t a b | s -> a, t -> b, s b -> t, t a -> s where _2 :: Lens s t a b class Field3 s t a b | s -> a, t -> b, s b -> t, t a -> s where _3 :: Lens s t a b class Field4 s t a b | s -> a, t -> b, s b -> t, t a -> s where _4 :: Lens s t a b instance Field1 (a,b) (a',b) a a' where _1 f (a,b) = (,b) <$> f a instance Field2 (a,b) (a,b') b b' where _2 f (a,b) = (a,) <$> f b instance Field1 (a,b,c) (a',b,c) a a' where _1 f (a,b,c) = (,b,c) <$> f a instance Field2 (a,b,c) (a,b',c) b b' where _2 f (a,b,c) = (a,,c) <$> f b instance Field3 (a,b,c) (a,b,c') c c' where _3 f (a,b,c) = (a,b,) <$> f c instance Field1 (a,b,c,d) (a',b,c,d) a a' where _1 f (a,b,c,d) = (,b,c,d) <$> f a instance Field2 (a,b,c,d) (a,b',c,d) b b' where _2 f (a,b,c,d) = (a,,c,d) <$> f b instance Field3 (a,b,c,d) (a,b,c',d) c c' where _3 f (a,b,c,d) = (a,b,,d) <$> f c instance Field4 (a,b,c,d) (a,b,c,d') d d' where _4 f (a,b,c,d) = (a,b,c,) <$> f d view :: Getting a s a -> s -> a view l = getConst . l Const (^.) :: s -> Getting a s a -> a (^.) = flip view infixl 8 ^. over :: Setting s t a b -> (a -> b) -> s -> t over l f = runIdentity . l (Identity . f) set :: Setting s t a b -> b -> s -> t set l = over l . const