2019-12-10 14:01:09 +01:00
import Data.List as List
2019-12-10 22:07:34 +01:00
import Debug.Trace as Trace
2019-12-10 14:01:09 +01:00
main = do
content <- getContents
let layers = lines content
let indexlayers = map ( \ x -> mapInd ( \ x y -> ( y , x ) ) x ) layers
let points = concat ( mapInd ( \ x y -> map ( \ x -> ( ( fst x , y ) , snd x ) ) x ) $ indexlayers )
2019-12-10 17:12:15 +01:00
let asteroids = ( map fst ( filter ( \ ( x , y ) -> y == '#' ) points ) )
2019-12-10 22:07:34 +01:00
let maximum = List . maximum ( map ( \ x -> length ( getViews ( changeCoordinate ( asteroids ) x ) ) ) ( asteroids ) )
let station = head $ map ( \ x -> fst x ) $ filter ( \ x -> snd x == maximum ) ( map ( \ x -> ( x , ( length ( getViews ( changeCoordinate asteroids x ) ) ) ) ) ( asteroids ) )
let changedAsteroids = changeCoordinate asteroids station
let sortedAsteroids = sortBy sortDistance changedAsteroids
let views = getViews sortedAsteroids
let sortedViews = sortBy sortDegree views
let destroyed = getDestroyOrder sortedAsteroids []
let destroyNormal = map ( \ ( a , b ) -> ( ( ( fst station ) + a ) , ( ( snd station ) + b ) ) ) destroyed
putStrLn ( show maximum )
putStrLn ( show station )
putStrLn ( show views )
putStrLn ( show sortedViews )
putStrLn ( show $ map degree destroyed )
putStrLn ( show $ destroyNormal !! 19 )
2019-12-10 14:01:09 +01:00
mapInd :: ( a -> Int -> b ) -> [ a ] -> [ b ]
mapInd f l = zipWith f l [ 0 .. ]
2019-12-10 22:07:34 +01:00
getDestroyOrder :: [ ( Int , Int ) ] -> [ ( Int , Int ) ] -> [ ( Int , Int ) ]
getDestroyOrder ast out
| length ast > 0 = do
let views = getViews ast
let sortedViews = sortBy sortDegree views
let newout = out ++ sortedViews
let newast = ast \\ sortedViews
getDestroyOrder newast newout
| otherwise = out
sortDistance ( ( a , b ) ) ( ( a2 , b2 ) )
| abs ( a ) + abs ( b ) > abs ( a2 ) + abs ( b2 ) = GT
| abs ( a ) + abs ( b ) < abs ( a2 ) + abs ( b2 ) = LT
| abs ( a ) + abs ( b ) == abs ( a2 ) + abs ( b2 ) = EQ
2019-12-10 14:01:09 +01:00
2019-12-10 22:07:34 +01:00
sortDegree a b
| degree a > degree b = GT
| degree a < degree b = LT
| degree a == degree b = EQ
getViews :: [ ( Int , Int ) ] -> [ ( Int , Int ) ]
getViews xs = foldl getView [] xs
2019-12-10 14:01:09 +01:00
2019-12-10 17:00:06 +01:00
changeCoordinate :: [ ( Int , Int ) ] -> ( Int , Int ) -> [ ( Int , Int ) ]
changeCoordinate xs ( a , b ) = ( delete ( 0 , 0 ) ( ( map ( \ ( x , y ) -> ( ( x - a ) , ( y - b ) ) ) xs ) ) )
2019-12-10 14:01:09 +01:00
getView :: [ ( Int , Int ) ] -> ( Int , Int ) -> [ ( Int , Int ) ]
getView xs y
| notElem ( reduce y ) ( map reduce xs ) = xs ++ [ y ]
| otherwise = xs
reduce :: ( Int , Int ) -> ( Int , Int )
reduce ( a , b ) = ( ( div a ( gcd a b ) ) , ( div b ( gcd a b ) ) )
2019-12-10 16:44:25 +01:00
2019-12-10 22:07:34 +01:00
degree :: ( Int , Int ) -> Double
degree ( a , b ) = do
let x = fromIntegral a
let y = fromIntegral b
y / x