In [1]:
inputLines = lines <$> readFile "input/day10.txt"
In [2]:
type Vector = (Int, Int)
In [3]:
asteroidConnection :: Vector -> Vector -> Vector
asteroidConnection (x1, y1) (x2, y2) = (x2 - x1, y2 - y1)
In [4]:
import Control.Monad (guard)
parseMap :: [String] -> [Vector]
parseMap allLines = do
(y, line) <- zip [0..] allLines
(x, point) <- zip [0..] line
guard $ point == '#'
return (x, y)
In [5]:
direction :: Vector -> Vector
direction (dx, dy) = (dx `div` g, dy `div` g)
where
g = gcd dx dy
In [6]:
import qualified Data.Set as Set
numberOfVisibleAsteroids :: Vector -> [Vector] -> Int
numberOfVisibleAsteroids origin = countDistinct . map getDirection . filter (/=origin)
where
countDistinct = Set.size . Set.fromList
getDirection = direction . asteroidConnection origin
In [7]:
bestPosition asteroids = maximum . map resultForOrigin $ asteroids
where
resultForOrigin origin = (numberOfVisibleAsteroids origin asteroids, origin)
In [8]:
bestPosition . parseMap $ [ ".#..#"
, "....."
, "#####"
, "....#"
, "...##" ]
In [9]:
largeMap = parseMap [ ".#..##.###...#######"
, "##.############..##."
, ".#.######.########.#"
, ".###.#######.####.#."
, "#####.##.#.##.###.##"
, "..#####..#.#########"
, "####################"
, "#.####....###.#.#.##"
, "##.#################"
, "#####.##.###..####.."
, "..######..##.#######"
, "####.##.####...##..#"
, ".#####..#.######.###"
, "##...#.##########..."
, "#.##########.#######"
, ".####.#.###.###.#.##"
, "....##.##.###..#####"
, ".#.#.###########.###"
, "#.#.#.#####.####.###"
, "###.##.####.##.#..##" ]
In [10]:
bestPosition largeMap
In [11]:
bestPosition . parseMap <$> inputLines
Find the annihilation order for a given list of asteroids. TODO: cleanup!
In [12]:
import Data.Function (on)
import Data.List (sortOn, sortBy, groupBy)
annihilationOrder :: [Vector] -> [Vector]
annihilationOrder asteroids =
let
(_, bestPos) = bestPosition asteroids
manhattanDistance :: Vector -> Int
manhattanDistance = uncurry ((+) `on` abs) . asteroidConnection bestPos
sortedByDistance = sortOn manhattanDistance $ filter (/=bestPos) asteroids
compareClockwise :: Vector -> Vector -> Ordering
compareClockwise asteroid1 asteroid2 =
let
angle (x, y) = if phi < 0 then phi + 2 * pi else phi
where
phi = (atan2 `on` fromIntegral) x (-y)
compareAngle = compare `on` (angle . asteroidConnection bestPos)
in compareAngle asteroid1 asteroid2
sortedClockwise = sortBy compareClockwise sortedByDistance
sortedByAnnihilation = map snd $ sortOn fst $ concatMap (zip [0..]) $ groupBy ((==) `on` (direction . asteroidConnection bestPos)) sortedClockwise
in sortedByAnnihilation
In [13]:
examples = [1, 2, 3, 10, 20, 50, 100, 199, 200, 201, 299]
f [] [] = []
f (e:es) (x:xs)
| e == fst x = x:f es xs
| e > fst x = f (e:es) xs
f examples $ zip [1..] (annihilationOrder largeMap)
In [14]:
uncurry ((+) . (*100)) . (!! 199) . annihilationOrder . parseMap <$> inputLines