code.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. package main
  2. import (
  3. "bufio"
  4. "fmt"
  5. "log"
  6. "os"
  7. "sort"
  8. )
  9. type Point struct {
  10. X, Y int
  11. }
  12. type PointList []Point
  13. func (p PointList) Len() int {
  14. return len(p)
  15. }
  16. func (p PointList) Swap(i, j int) {
  17. p[i], p[j] = p[j], p[i]
  18. }
  19. func Area2(a, b, c Point) int {
  20. return (b.X-a.X)*(c.Y-a.Y) - (c.X-a.X)*(b.Y-a.Y)
  21. }
  22. func abs(a int) int {
  23. if a < 0 {
  24. return -a
  25. }
  26. return a
  27. }
  28. func (p PointList) Less(i, j int) bool {
  29. area := Area2(p[0], p[i], p[j])
  30. if area == 0 {
  31. x := abs(p[i].X-p[0].X) - abs(p[j].X-p[0].X)
  32. y := abs(p[i].Y-p[0].Y) - abs(p[j].Y-p[0].Y)
  33. if x < 0 || y < 0 {
  34. return true
  35. } else if x > 0 || y > 0 {
  36. return false
  37. } else {
  38. return false
  39. }
  40. }
  41. return area > 0
  42. }
  43. func (p PointList) FindLowestPoint() {
  44. m := 0
  45. for i := 1; i < len(p); i++ {
  46. //If lowest points are on the same line, take the rightmost point
  47. if (p[i].Y < p[m].Y) || ((p[i].Y == p[m].Y) && p[i].X > p[m].X) {
  48. m = i
  49. }
  50. }
  51. p[0], p[m] = p[m], p[0]
  52. }
  53. func isLeft(p0, p1, p2 Point) bool {
  54. return Area2(p0, p1, p2) > 0
  55. }
  56. func (points PointList) Compute() (PointList, bool) {
  57. if len(points) < 3 {
  58. return nil, false
  59. }
  60. stack := new(Stack)
  61. points.FindLowestPoint()
  62. sort.Sort(&points)
  63. stack.Push(points[0])
  64. stack.Push(points[1])
  65. i := 2
  66. for i < len(points) {
  67. pi := points[i]
  68. p1 := stack.top.next.value.(Point)
  69. p2 := stack.top.value.(Point)
  70. if isLeft(p1, p2, pi) {
  71. stack.Push(pi)
  72. i++
  73. } else {
  74. stack.Pop()
  75. }
  76. }
  77. //Copy the hull
  78. ret := make(PointList, stack.Len())
  79. top := stack.top
  80. count := 0
  81. for top != nil {
  82. ret[count] = top.value.(Point)
  83. top = top.next
  84. count++
  85. }
  86. return ret, true
  87. }
  88. func readInput(file *os.File) []Point {
  89. scanner := bufio.NewScanner(file)
  90. var tiles []Point
  91. for scanner.Scan() {
  92. line := scanner.Text()
  93. if line == "" {
  94. continue
  95. }
  96. var x, y int
  97. n, err := fmt.Sscanf(line, "%d,%d", &x, &y)
  98. if n != 2 || err != nil {
  99. log.Fatalf("Bad input: %s", line)
  100. }
  101. tiles = append(tiles, Point{X: x, Y: y})
  102. }
  103. return tiles
  104. }
  105. func part1(tiles []Point) int {
  106. end := len(tiles)
  107. var maxArea int
  108. for i := range tiles {
  109. for j := i + 1; j < end; j++ {
  110. area := (abs(tiles[j].X-tiles[i].X) + 1) * (abs(tiles[j].Y-tiles[i].Y) + 1)
  111. if area > maxArea {
  112. maxArea = area
  113. }
  114. }
  115. }
  116. return maxArea
  117. }
  118. func main() {
  119. if len(os.Args) < 2 {
  120. log.Fatal("You need to specify a file!")
  121. }
  122. filePath := os.Args[1]
  123. file, err := os.Open(filePath)
  124. if err != nil {
  125. log.Fatalf("Failed to open %s!\n", filePath)
  126. }
  127. tiles := readInput(file)
  128. fmt.Println("Part1:", part1(tiles))
  129. }