2019: Day 10 Part 1
This commit is contained in:
parent
07eb60e5e1
commit
f6263f7cd9
1 changed files with 116 additions and 0 deletions
116
2019/day10/part1.rb
Normal file
116
2019/day10/part1.rb
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
input = File.read(File.join(__dir__, 'input'))
|
||||
|
||||
class AsteroidBelt
|
||||
def initialize(text)
|
||||
@grid = parse(text)
|
||||
end
|
||||
|
||||
def asteroids
|
||||
return @asteroids unless @asteroids.nil?
|
||||
|
||||
@asteroids = []
|
||||
@grid.each_with_index do |line, y|
|
||||
line.chars.each_with_index do |cell, x|
|
||||
@asteroids << Asteroid.new(x, y) if cell == '#'
|
||||
end
|
||||
end
|
||||
@asteroids
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def parse(text)
|
||||
text.lines
|
||||
end
|
||||
end
|
||||
|
||||
class Asteroid
|
||||
attr_reader :x, :y
|
||||
|
||||
def initialize(x, y)
|
||||
@x = x
|
||||
@y = y
|
||||
end
|
||||
|
||||
def neighbors(asteroids)
|
||||
by_direction = {}
|
||||
asteroids.each do |asteroid|
|
||||
next if asteroid == self
|
||||
|
||||
theta = direction_to(asteroid).normalize
|
||||
# Since we only care about count, we don't care *which* one we can see at
|
||||
# in a given direction. If we do care about it, sort by distance and
|
||||
# take the closer one.
|
||||
by_direction[theta] = asteroid
|
||||
end
|
||||
by_direction
|
||||
end
|
||||
|
||||
def direction_to(other)
|
||||
dx = other.x - x
|
||||
dy = other.y - y
|
||||
Vector.new(dx, dy)
|
||||
end
|
||||
|
||||
def inspect
|
||||
"<Asteroid: #{x},#{y}>"
|
||||
end
|
||||
|
||||
def to_s
|
||||
"(#{x},#{y})"
|
||||
end
|
||||
end
|
||||
|
||||
class Vector
|
||||
attr_reader :x, :y
|
||||
|
||||
def initialize(x, y, normal = false)
|
||||
@x = x
|
||||
@y = y
|
||||
@normal = normal
|
||||
end
|
||||
|
||||
def normalize
|
||||
return self if @normal
|
||||
|
||||
div = gcd(@x.abs, @y.abs)
|
||||
Vector.new(Rational(@x / div), Rational(@y / div), true)
|
||||
end
|
||||
|
||||
def ==(other)
|
||||
s = normalize
|
||||
o = other.normalize
|
||||
|
||||
s.x == o.x && s.y == o.y
|
||||
end
|
||||
|
||||
def eql?(other)
|
||||
self == other
|
||||
end
|
||||
|
||||
def hash
|
||||
n = normalize
|
||||
[n.x, n.y].hash
|
||||
end
|
||||
|
||||
def inspect
|
||||
"<Vector: #{x},#{y}>"
|
||||
end
|
||||
end
|
||||
|
||||
def gcd(n, m)
|
||||
# Invariant: n >= m
|
||||
n, m = m, n if n < m
|
||||
n, m = m, n % m until m.zero?
|
||||
n
|
||||
end
|
||||
|
||||
belt = AsteroidBelt.new input
|
||||
|
||||
best = belt.asteroids.max_by do |asteroid|
|
||||
asteroid.neighbors(belt.asteroids).count
|
||||
end
|
||||
pp best
|
||||
pp best.neighbors(belt.asteroids).count
|
||||
Loading…
Reference in a new issue