|
@@ -0,0 +1,156 @@
|
|
|
|
|
+package main
|
|
|
|
|
+
|
|
|
|
|
+import (
|
|
|
|
|
+ "bufio"
|
|
|
|
|
+ "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
|
|
|
|
|
+
|
|
|
|
|
+ for scanner.Scan() {
|
|
|
|
|
+ line := scanner.Text()
|
|
|
|
|
+ if line == "" {
|
|
|
|
|
+ continue
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ var x, y int
|
|
|
|
|
+ n, err := fmt.Sscanf(line, "%d,%d", &x, &y)
|
|
|
|
|
+ if n != 2 || err != nil {
|
|
|
|
|
+ log.Fatalf("Bad input: %s", line)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ tiles = append(tiles, Point{X: x, Y: y})
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return tiles
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func part1(tiles []Point) int {
|
|
|
|
|
+ end := len(tiles)
|
|
|
|
|
+ var maxArea int
|
|
|
|
|
+
|
|
|
|
|
+ for i := range tiles {
|
|
|
|
|
+ for j := i + 1; j < end; j++ {
|
|
|
|
|
+ area := (abs(tiles[j].X-tiles[i].X) + 1) * (abs(tiles[j].Y-tiles[i].Y) + 1)
|
|
|
|
|
+ if area > maxArea {
|
|
|
|
|
+ maxArea = area
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return maxArea
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func main() {
|
|
|
|
|
+ if len(os.Args) < 2 {
|
|
|
|
|
+ log.Fatal("You need to specify a file!")
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ filePath := os.Args[1]
|
|
|
|
|
+ file, err := os.Open(filePath)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ log.Fatalf("Failed to open %s!\n", filePath)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ tiles := readInput(file)
|
|
|
|
|
+ fmt.Println("Part1:", part1(tiles))
|
|
|
|
|
+}
|