code.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  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. continue
  63. }
  64. if current.fences == 0 {
  65. current.fences = countFences(current, matrix, xMax, yMax)
  66. }
  67. region[current.key()] = current
  68. checked[current.key()] = true
  69. newPlots := getPlots(current, matrix, xMax, yMax)
  70. for _, plot := range newPlots {
  71. if !checked[plot.key()] {
  72. plots = append(plots, plot)
  73. }
  74. }
  75. }
  76. return region
  77. }
  78. func calculate(region map[string]Point) int {
  79. var perimeter int
  80. for _, plot := range region {
  81. perimeter += plot.fences
  82. }
  83. return perimeter * len(region)
  84. }
  85. func part1(matrix [][]byte) int {
  86. xMax := len(matrix[0])
  87. yMax := len(matrix)
  88. checked := make(map[string]bool)
  89. var result int
  90. for y := range matrix {
  91. for x := range matrix[y] {
  92. current := Point{x: x, y: y, value: matrix[y][x]}
  93. if !checked[current.key()] {
  94. current.fences = countFences(current, matrix, xMax, yMax)
  95. region := getRegion(current, matrix, xMax, yMax, checked)
  96. result += calculate(region)
  97. }
  98. }
  99. }
  100. return result
  101. }
  102. func main() {
  103. if len(os.Args) < 2 {
  104. log.Fatal("You need to specify a file!")
  105. }
  106. filePath := os.Args[1]
  107. file, err := os.Open(filePath)
  108. if err != nil {
  109. log.Fatalf("Failed to open %s!\n", filePath)
  110. }
  111. matrix := readInput(file)
  112. fmt.Println("Part1:", part1(matrix))
  113. }