diff --git a/2021/5/go.mod b/2021/5/go.mod new file mode 100644 index 0000000..e282ece --- /dev/null +++ b/2021/5/go.mod @@ -0,0 +1,9 @@ +module AoC/2021/5 + +require AoC/2021/common v0.0.0 + +require github.com/joho/godotenv v1.4.0 // indirect + +replace AoC/2021/common v0.0.0 => ../common + +go 1.17 diff --git a/2021/5/go.sum b/2021/5/go.sum new file mode 100644 index 0000000..8c9f290 --- /dev/null +++ b/2021/5/go.sum @@ -0,0 +1,2 @@ +github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg= +github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= diff --git a/2021/5/improved.go b/2021/5/improved.go new file mode 100644 index 0000000..ee63d26 --- /dev/null +++ b/2021/5/improved.go @@ -0,0 +1,101 @@ +package main + +import ( + aoc "AoC/2021/common" + "bufio" + "regexp" + "strconv" +) + +func min(a, b int) int { + if a < b { + return a + } + return b +} + +func max(a, b int) int { + if a > b { + return a + } + return b +} + +func findIntersection(diagonal bool) func (*bufio.Scanner) int { + return func (input *bufio.Scanner) int { + size := 1000 + diagram := make([][]int, size) + for y := 0; y < size; y++ { + diagram[y] = make([]int, size) + } + + re := regexp.MustCompile("[0-9]+") + for input.Scan() { + text := input.Text() + numbers := re.FindAllString(text, -1) + + if len(numbers) != 4 { + panic("Did not find 4 numbers") + } + + x1, _ := strconv.Atoi(numbers[0]) + y1, _ := strconv.Atoi(numbers[1]) + x2, _ := strconv.Atoi(numbers[2]) + y2, _ := strconv.Atoi(numbers[3]) + + // Optionally skip lines that are not horizontal or vertical + if !diagonal && !(x1 == x2 || y1 == y2) { + continue + } + + dx := 1 + dy := 1 + length := max(max(x1, x2) - min(x1, x2) + 1, max(y1, y2) - min(y1, y2) + 1) + + if x1 == x2 { + dx = 0 + } else if x1 > x2 { + dx = -dx + } + + if y1 == y2 { + dy = 0 + } else if y1 > y2 { + dy = -dy + } + + for i := 0; i < length; i++ { + diagram[y1 + i*dy][x1 + i*dx]++ + } + } + + points := 0 + for y := 0; y < size; y++ { + for x := 0; x < size; x++ { + if diagram[y][x] > 1 { + points++ + } + } + } + + return points + } +} + +func main() { + aoc := aoc.New(2021, 5) + + aoc.Test(`0,9 -> 5,9 +8,0 -> 0,8 +9,4 -> 3,4 +2,2 -> 2,1 +7,0 -> 7,4 +6,4 -> 2,0 +0,9 -> 2,9 +3,4 -> 1,4 +0,0 -> 8,8 +5,5 -> 8,2`, []int{5, 12}) + + aoc.Solution(1, findIntersection(false)) + aoc.Solution(2, findIntersection(true)) +} diff --git a/2021/5/main.go b/2021/5/main.go new file mode 100644 index 0000000..a85b58a --- /dev/null +++ b/2021/5/main.go @@ -0,0 +1,129 @@ +package main + +import ( + aoc "AoC/2021/common" + "bufio" + "regexp" + "strconv" +) + +type line struct { + x1, y1, x2, y2 int +} + +func min(a, b int) int { + if a < b { + return a + } + return b +} + +func max(a, b int) int { + if a > b { + return a + } + return b +} + +func findIntersection(diagonal bool) func (*bufio.Scanner) int { + return func (input *bufio.Scanner) int { + var lines []line + var xmax, ymax int + + re := regexp.MustCompile("[0-9]+") + for input.Scan() { + text := input.Text() + numbers := re.FindAllString(text, -1) + + if len(numbers) != 4 { + panic("Did not find 4 numbers") + } + + var coords [4]int + for i, n := range numbers { + c, err := strconv.Atoi(n) + if err != nil { + panic(err) + } + coords[i] = c + } + + xmax = max(xmax, max(coords[0], coords[2])) + ymax = max(ymax, max(coords[1], coords[3])) + + // Only consider horizontal and vertical line if diagonal is false + if diagonal || coords[0] == coords[2] || coords[1] == coords[3] { + lines = append(lines, line{coords[0], coords[1], coords[2], coords[3]}) + } + } + + diagram := make([][]int, ymax+1) + for y := 0; y <= ymax; y++ { + diagram[y] = make([]int, xmax+1) + } + + for _, a := range lines { + // Vertical line + if a.x1 == a.x2 { + for y := min(a.y1, a.y2); y <= max(a.y1, a.y2); y++ { + diagram[y][a.x1]++ + } + continue + } + + // Horizontal line + if a.y1 == a.y2 { + for x := min(a.x1, a.x2); x <= max(a.x1, a.x2); x++ { + diagram[a.y1][x]++ + } + continue + } + + // Otherwise we have a diagonal line + length := max(a.x1, a.x2) - min(a.x1, a.x2) + 1 + for i := 0; i < length; i++ { + x := a.x1 + i + if (a.x1 > a.x2) { + x = a.x1 - i + } + + y := a.y1 + i + if (a.y1 > a.y2) { + y = a.y1 - i + } + + diagram[y][x]++ + } + } + + + points := 0 + for y := 0; y <= ymax; y++ { + for x := 0; x <= xmax; x++ { + if diagram[y][x] > 1 { + points++ + } + } + } + + return points + } +} + +func main() { + aoc := aoc.New(2021, 5) + + aoc.Test(`0,9 -> 5,9 +8,0 -> 0,8 +9,4 -> 3,4 +2,2 -> 2,1 +7,0 -> 7,4 +6,4 -> 2,0 +0,9 -> 2,9 +3,4 -> 1,4 +0,0 -> 8,8 +5,5 -> 8,2`, []int{5, 12}) + + aoc.Solution(1, findIntersection(false)) + aoc.Solution(2, findIntersection(true)) +}