about summary refs log tree commit diff
path: root/aoc2019/Day10.cs
blob: 6151e54ffdc335a264eadccef24e8b5fd2cd28d5 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
using System;
using System.Collections.Generic;
using System.Linq;
using aoc2019.lib;

namespace aoc2019
{
    public sealed class Day10 : Day
    {
        private readonly HashSet<(int x, int y)> asteroids;
        private (int x, int y) best = (x: -1, y: -1);
        private int bestCanSee;

        public Day10() : base(10, "Monitoring Station")
        {
            asteroids = Input
                .Select((r, y) => r.Select((c, x) => (x, y, isAsteroid: c == '#')).ToArray())
                .SelectMany(r => r)
                .Where(a => a.isAsteroid)
                .Select(a => (a.x, a.y))
                .ToHashSet();
        }

        public override string Part1()
        {
            foreach (var asteroid in asteroids)
            {
                var canSee = asteroids
                    .Except(new[] {asteroid})
                    .Select(a => (x: a.x - asteroid.x, y: a.y - asteroid.y))
                    .GroupBy(a => Math.Atan2(a.y, a.x))
                    .Count();

                if (canSee > bestCanSee)
                {
                    best = asteroid;
                    bestCanSee = canSee;
                }
            }

            return $"{bestCanSee}";
        }

        public override string Part2()
        {
            static IEnumerable<(int x, int y, double angle, double dist)> GetValue(
                Queue<(int x, int y, double angle, double dist)> q)
            {
                if (q.Count > 0) yield return q.Dequeue();
            }

            return asteroids
                .Where(a => a != best)
                .Select(a =>
                {
                    var xDist = a.x - best.x;
                    var yDist = a.y - best.y;
                    var angle = Math.Atan2(xDist, yDist);
                    return (a.x, a.y, angle, dist: Math.Sqrt(xDist * xDist + yDist * yDist));
                })
                .ToLookup(a => a.angle)
                .OrderByDescending(a => a.Key)
                .Select(a => new Queue<(int x, int y, double angle, double dist)>(a.OrderBy(b => b.dist)))
                .Repeat()
                .SelectMany(GetValue)
                .Skip(199)
                .Take(1)
                .Select(a => a.x * 100 + a.y)
                .Single()
                .ToString();
        }
    }
}