package coords import ( "strconv" "strings" ) type Point struct { X int Y int RectArea int } func ParsePoints(data []string) []*Point { points := []*Point{} for _, pointInfo := range data { components := strings.Split(pointInfo, ", ") x, _ := strconv.Atoi(components[0]) y, _ := strconv.Atoi(components[1]) points = append(points, &Point{ X: x, Y: y, }) } return points } // Mutates the passed-in data in-place, computing the rectilinear // area for all points within the space bounded by (0,0) and the points themselves. // Sets the area of the 4 corner-most points (which definitionally must have // unbounded areas) to -1 func ComputeRectilinearAreas(data []*Point) { // first we find the bounds maxX := 0 maxY := 0 for _, point := range data { if point.X > maxX { maxX = point.X } if point.Y > maxY { maxY = point.Y } } // now for each integer point in our range, we compute the distance to each // point. We save the closest point and its distance, then: // 1. If there are two or more identically closest points, we do nothing. // 2. Otherwise, we increment RectArea for the closest point. for x := -maxX; x <= maxX*2; x++ { for y := -maxY; y <= maxY*2; y++ { closest := FindClosest(data, &Point{X: x, Y: y}) if closest == nil { continue } closest.RectArea++ } } // now we find any unbounded points and set their areas to the sentinel // value DetectUnboundedPoints(data) } func FindClosest(data []*Point, point *Point) *Point { closest := data[0] distance := computeDistance(data[0], point) for i := 1; i < len(data); i++ { candidate := data[i] newDistance := computeDistance(candidate, point) if newDistance < distance { closest = candidate distance = newDistance } else if newDistance == distance { closest = nil } } return closest } func DetectUnboundedPoints(data []*Point) { for _, candidate := range data { // look in each direction up := FindClosest(data, &Point{X: candidate.X, Y: candidate.Y + 1000000}) down := FindClosest(data, &Point{X: candidate.X, Y: candidate.Y - 1000000}) left := FindClosest(data, &Point{X: candidate.X + 1000000, Y: candidate.Y}) right := FindClosest(data, &Point{X: candidate.X - 1000000, Y: candidate.Y}) // if any of those points are closest to our point, we're unbounded if up == candidate || down == candidate || left == candidate || right == candidate { candidate.RectArea = -1 } } } func computeDistance(p1 *Point, p2 *Point) int { return abs(p2.Y-p1.Y) + abs(p2.X-p1.X) } func abs(x int) int { if x < 0 { return -x } return x }