code.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. package main
  2. import (
  3. "bufio"
  4. "fmt"
  5. "log"
  6. "os"
  7. )
  8. type Point struct {
  9. y, x int
  10. value byte
  11. fences int
  12. }
  13. func (p *Point) key() string {
  14. return fmt.Sprintf("%d_%d", p.y, p.x)
  15. }
  16. func readInput(file *os.File) [][]byte {
  17. scanner := bufio.NewScanner(file)
  18. var matrix [][]byte
  19. for scanner.Scan() {
  20. line := scanner.Text()
  21. if line == "" {
  22. break
  23. }
  24. matrix = append(matrix, []byte(line))
  25. }
  26. return matrix
  27. }
  28. var directions [][]int = [][]int{
  29. {0, -1}, {1, 0}, {0, 1}, {-1, 0},
  30. }
  31. func getPlots(current Point, matrix [][]byte, xMax, yMax int) []Point {
  32. var plots []Point
  33. for _, direction := range directions {
  34. plot := Point{x: current.x + direction[0], y: current.y + direction[1]}
  35. if plot.x >= 0 && plot.x < xMax &&
  36. plot.y >= 0 && plot.y < yMax && matrix[plot.y][plot.x] == current.value {
  37. plot.value = matrix[plot.y][plot.x]
  38. plots = append(plots, plot)
  39. }
  40. }
  41. return plots
  42. }
  43. func countFences(current Point, matrix [][]byte, xMax, yMax int) int {
  44. var fences int
  45. for _, direction := range directions {
  46. plot := Point{x: current.x + direction[0], y: current.y + direction[1]}
  47. if plot.x >= 0 && plot.x < xMax &&
  48. plot.y >= 0 && plot.y < yMax && matrix[plot.y][plot.x] == current.value {
  49. continue
  50. }
  51. fences++
  52. }
  53. return fences
  54. }
  55. func getRegion(start Point, matrix [][]byte, xMax, yMax int, checked map[string]bool) map[string]Point {
  56. plots := []Point{start}
  57. region := make(map[string]Point)
  58. for len(plots) > 0 {
  59. current := plots[0]
  60. plots = plots[1:]
  61. if !checked[current.key()] {
  62. if current.fences == 0 {
  63. current.fences = countFences(current, matrix, xMax, yMax)
  64. }
  65. region[current.key()] = current
  66. }
  67. checked[current.key()] = true
  68. newPlots := getPlots(current, matrix, xMax, yMax)
  69. for _, plot := range newPlots {
  70. if !checked[plot.key()] {
  71. plots = append(plots, plot)
  72. }
  73. }
  74. }
  75. return region
  76. }
  77. func calculate(region map[string]Point) int {
  78. var perimeter int
  79. for _, plot := range region {
  80. perimeter += plot.fences
  81. }
  82. return perimeter * len(region)
  83. }
  84. func part1(matrix [][]byte) int {
  85. xMax := len(matrix[0])
  86. yMax := len(matrix)
  87. checked := make(map[string]bool)
  88. var result int
  89. for y := range matrix {
  90. for x := range matrix[y] {
  91. current := Point{x: x, y: y, value: matrix[y][x]}
  92. if !checked[current.key()] {
  93. current.fences = countFences(current, matrix, xMax, yMax)
  94. region := getRegion(current, matrix, xMax, yMax, checked)
  95. result += calculate(region)
  96. }
  97. }
  98. }
  99. return result
  100. }
  101. func main() {
  102. if len(os.Args) < 2 {
  103. log.Fatal("You need to specify a file!")
  104. }
  105. filePath := os.Args[1]
  106. file, err := os.Open(filePath)
  107. if err != nil {
  108. log.Fatalf("Failed to open %s!\n", filePath)
  109. }
  110. matrix := readInput(file)
  111. fmt.Println("Part1:", part1(matrix))
  112. }