יום 6 - Chronal Coordinates

קישור לחידה המקורית:
https://adventofcode.com/2018/day/6

פיתרון בשפת רובי:

class Item
  attr_accessor :owner, :x, :y

  def distance(ax, ay)
    (x - ax).abs + (y - ay).abs
  end

  def initialize(x, y, owner)
    self.x, self.y, self.owner = x, y, owner
  end

  def to_s
    "#{x}, #{y} [#{owner}]"
  end
end

class Matrix
  attr_accessor :top, :left, :bottom, :right, :data
  def initialize
    @bottom = -1
    @right = -1
    @left = Float::INFINITY
    @top = Float::INFINITY
    @phase = 0
  end

  def xy_in_game
    Enumerator.new do |yielder|
      (@right - @left).times do |x|
        (@bottom - @top).times do |y|
          yielder.yield x + @left, y + @top
        end
      end

    end
  end
end

$id = 'A'
matrix = Matrix.new

base = []

ARGF.each_line do |line|
  x, y = line.scan(/\d+/).map(&:to_i)
  base << Item.new(x, y, $id.dup)
  matrix.bottom = y if y > matrix.bottom
  matrix.right = x if x > matrix.right
  matrix.left = x if x < matrix.left
  matrix.top = y if y < matrix.top

  $id.next!
end

part1 = {}
part1.default = 0
matrix.xy_in_game.each do |x, y|
  closest_to = base.min_by(2) {|b| b.distance(x, y)}
  if closest_to[0].distance(x, y) != closest_to[1].distance(x, y)
    part1[closest_to[0].owner] += 1
  end
end
print "Part 1: ", part1.values.max, "\n"

part2 = 0
matrix.xy_in_game.each do |x, y|
  total_distance = base.map {|b| b.distance(x, y)}.sum
  if total_distance < 10_000
    part2 += 1
  end
end

print "Part 2: ", part2, "\n"

הפעם הקוד יצא ארוך, וזה גם התרגיל הראשון השנה שנתקעתי עליו. הבעיה כמובן היתה אני ולא התרגיל - וניסיונות שלי להיות חכם מדי בחלק הראשון במקום לחפש את הדרך הקלה. למרות שבסופו של דבר יצא ארוך יותר מהקודמים אני מרוצה מהפיתרון. אשמח לשמוע מה אתם עשיתם.

פיתרון שלי לחלק 2 בשפת Go (חלק 1 די דומה, אבל מכיוון שהקוד ארוך הסתפקתי בחלק השני)

// point on the grid with x, y coordinates
type point struct {
    x int
    y int
}

// distance between point p to point other by applying Manhattan distance calc
func (p point) distance(other point) int {
    return int(math.Abs(float64(p.x-other.x)) + math.Abs(float64(p.y-other.y)))
}

// grid has width and height (rows\cols) and collection of coordinates on the grid
type grid struct {
    width       int
    height      int
    coordinates map[point]int
}

// insert new point to grid
func (g *grid) insert(p point) {
   if p.x > g.width {
        g.width = p.x
    }
    if p.y > g.height {
        g.height = p.y
    }
     g.coordinates[p] = 0
}

// distanceToCoords return total distance from a point p to all coordiantes on the grid
func (g *grid) distanceToCoords(p point) int {
    var distance int
    for coordinate := range g.coordinates {
        distance += coordinate.distance(p)
     }
     return distance
}

// findRegion finds the size of the region in which all locations distance from grid coordinates < minDistance
func (g *grid) findRegion(minDistance int) int {
    var region int
    for row := 0; row <= g.width; row++ {
        for col := 0; col <= g.height; col++ {
           d := g.distanceToCoords(point{x: row, y: col})
            if d < minDistance {
                 region++
            }
        }
    }
    return region
}