|
|
@@ -5,12 +5,103 @@ import (
|
|
|
"fmt"
|
|
|
"log"
|
|
|
"os"
|
|
|
+ "sort"
|
|
|
)
|
|
|
|
|
|
type Point struct {
|
|
|
X, Y int
|
|
|
}
|
|
|
|
|
|
+type PointList []Point
|
|
|
+
|
|
|
+func (p PointList) Len() int {
|
|
|
+ return len(p)
|
|
|
+}
|
|
|
+
|
|
|
+func (p PointList) Swap(i, j int) {
|
|
|
+ p[i], p[j] = p[j], p[i]
|
|
|
+}
|
|
|
+
|
|
|
+func Area2(a, b, c Point) int {
|
|
|
+ return (b.X-a.X)*(c.Y-a.Y) - (c.X-a.X)*(b.Y-a.Y)
|
|
|
+}
|
|
|
+
|
|
|
+func abs(a int) int {
|
|
|
+ if a < 0 {
|
|
|
+ return -a
|
|
|
+ }
|
|
|
+
|
|
|
+ return a
|
|
|
+}
|
|
|
+
|
|
|
+func (p PointList) Less(i, j int) bool {
|
|
|
+ area := Area2(p[0], p[i], p[j])
|
|
|
+ if area == 0 {
|
|
|
+ x := abs(p[i].X-p[0].X) - abs(p[j].X-p[0].X)
|
|
|
+ y := abs(p[i].Y-p[0].Y) - abs(p[j].Y-p[0].Y)
|
|
|
+ if x < 0 || y < 0 {
|
|
|
+ return true
|
|
|
+ } else if x > 0 || y > 0 {
|
|
|
+ return false
|
|
|
+ } else {
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return area > 0
|
|
|
+}
|
|
|
+
|
|
|
+func (p PointList) FindLowestPoint() {
|
|
|
+ m := 0
|
|
|
+ for i := 1; i < len(p); i++ {
|
|
|
+ //If lowest points are on the same line, take the rightmost point
|
|
|
+ if (p[i].Y < p[m].Y) || ((p[i].Y == p[m].Y) && p[i].X > p[m].X) {
|
|
|
+ m = i
|
|
|
+ }
|
|
|
+ }
|
|
|
+ p[0], p[m] = p[m], p[0]
|
|
|
+}
|
|
|
+
|
|
|
+func isLeft(p0, p1, p2 Point) bool {
|
|
|
+ return Area2(p0, p1, p2) > 0
|
|
|
+}
|
|
|
+
|
|
|
+func (points PointList) Compute() (PointList, bool) {
|
|
|
+ if len(points) < 3 {
|
|
|
+ return nil, false
|
|
|
+ }
|
|
|
+
|
|
|
+ stack := new(Stack)
|
|
|
+ points.FindLowestPoint()
|
|
|
+ sort.Sort(&points)
|
|
|
+
|
|
|
+ stack.Push(points[0])
|
|
|
+ stack.Push(points[1])
|
|
|
+
|
|
|
+ i := 2
|
|
|
+ for i < len(points) {
|
|
|
+ pi := points[i]
|
|
|
+ p1 := stack.top.next.value.(Point)
|
|
|
+ p2 := stack.top.value.(Point)
|
|
|
+ if isLeft(p1, p2, pi) {
|
|
|
+ stack.Push(pi)
|
|
|
+ i++
|
|
|
+ } else {
|
|
|
+ stack.Pop()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //Copy the hull
|
|
|
+ ret := make(PointList, stack.Len())
|
|
|
+ top := stack.top
|
|
|
+ count := 0
|
|
|
+ for top != nil {
|
|
|
+ ret[count] = top.value.(Point)
|
|
|
+ top = top.next
|
|
|
+ count++
|
|
|
+ }
|
|
|
+ return ret, true
|
|
|
+}
|
|
|
+
|
|
|
func readInput(file *os.File) []Point {
|
|
|
scanner := bufio.NewScanner(file)
|
|
|
var tiles []Point
|
|
|
@@ -33,14 +124,6 @@ func readInput(file *os.File) []Point {
|
|
|
return tiles
|
|
|
}
|
|
|
|
|
|
-func abs(a int) int {
|
|
|
- if a < 0 {
|
|
|
- return -a
|
|
|
- }
|
|
|
-
|
|
|
- return a
|
|
|
-}
|
|
|
-
|
|
|
func part1(tiles []Point) int {
|
|
|
end := len(tiles)
|
|
|
var maxArea int
|