From e0e54dc95e91a28d2e895908b5bd10395107681f Mon Sep 17 00:00:00 2001 From: alexchao26 Date: Thu, 17 Dec 2020 18:28:42 -0500 Subject: [PATCH] 2020-day17 initial solution, it ain't pretty --- 2020/day17/main.go | 227 +++++++++++++++++++++++++++++++++++++--- 2020/day17/main_test.go | 12 ++- 2 files changed, 225 insertions(+), 14 deletions(-) diff --git a/2020/day17/main.go b/2020/day17/main.go index bde80ba..1440140 100644 --- a/2020/day17/main.go +++ b/2020/day17/main.go @@ -5,10 +5,10 @@ import ( "fmt" "strings" - "github.com/alexchao26/advent-of-code-go/mathutil" "github.com/alexchao26/advent-of-code-go/util" ) +// finished 933/~700 - jeez... func main() { var part int flag.IntVar(&part, "part", 1, "part 1 or 2") @@ -17,7 +17,6 @@ func main() { if part == 1 { ans := part1(util.ReadFile("./input.txt")) - util.CopyToClipboard(fmt.Sprintf("%v", ans)) fmt.Println("Output:", ans) } else { ans := part2(util.ReadFile("./input.txt")) @@ -27,20 +26,224 @@ func main() { } func part1(input string) int { - parsed := parseInput(input) - _ = parsed + nodes := parseInput3D(input) - return 0 + for cycles := 0; cycles < 6; cycles++ { + toCheck := map[[3]int]bool{} + for _, node := range nodes { + for _, dir := range directions { + x, y, z := node.x+dir[0], node.y+dir[1], node.z+dir[2] + toCheck[[3]int{x, y, z}] = true + } + } + + nextState := map[[3]int]*node3D{} + for coord := range toCheck { + // check all neighbors around this coord + var countNeighbors int + for _, d := range directions { + x, y, z := coord[0]+d[0], coord[1]+d[1], coord[2]+d[2] + neighCoord := [3]int{x, y, z} + if neigh, ok := nodes[neighCoord]; ok { + if neigh.active { + countNeighbors++ + } + } + } + + stateInNext := node3D{ + x: coord[0], + y: coord[1], + z: coord[2], + active: false, + } + if n, ok := nodes[coord]; ok && n.active { + if countNeighbors == 2 || countNeighbors == 3 { + stateInNext.active = true + } + } else { + // inactive originally + if countNeighbors == 3 { + stateInNext.active = true + } + } + nextState[coord] = &stateInNext + } + nodes = nextState + + } + + var count int + for _, node := range nodes { + if node.active { + count++ + } + } + // cubes after 6 cycles + return count +} + +func generate3DDirections() [][3]int { + directions := [][3]int{} + for i := -1; i < 2; i++ { + for j := -1; j < 2; j++ { + for k := -1; k < 2; k++ { + if !(i == 0 && j == 0 && k == 0) { + directions = append(directions, [3]int{i, j, k}) + } + } + } + } + return directions +} + +var directions = generate3DDirections() + +type node3D struct { + x, y, z int + active bool +} + +func parseInput3D(input string) map[[3]int]*node3D { + nodes := map[[3]int]*node3D{} + lines := strings.Split(input, "\n") + for i, l := range lines { + for j, cell := range strings.Split(l, "") { + n := &node3D{ + x: i, y: j, z: 0, active: false, + } + if cell == "#" { + n.active = true + } + nodes[[3]int{i, j, 0}] = n + } + } + return nodes } func part2(input string) int { - return 0 + nodes := parseInput4D(input) + + for cycles := 0; cycles < 6; cycles++ { + toCheck := map[[4]int]bool{} + for _, node := range nodes { + for _, dir := range directions4D { + x, y, z, w := node.x+dir[0], node.y+dir[1], node.z+dir[2], node.w+dir[3] + toCheck[[4]int{x, y, z, w}] = true + } + } + + nextState := map[[4]int]*node4D{} + for coord := range toCheck { + // check all neighbors around this coord + var countNeighbors int + for _, d := range directions4D { + x, y, z, w := coord[0]+d[0], coord[1]+d[1], coord[2]+d[2], coord[3]+d[3] + neighCoord := [4]int{x, y, z, w} + if neigh, ok := nodes[neighCoord]; ok { + if neigh.active { + countNeighbors++ + } + } + } + + stateInNext := node4D{ + x: coord[0], + y: coord[1], + z: coord[2], + w: coord[3], + active: false, + } + if n, ok := nodes[coord]; ok && n.active { + if countNeighbors == 2 || countNeighbors == 3 { + stateInNext.active = true + } + } else { + // inactive originally + if countNeighbors == 3 { + stateInNext.active = true + } + } + nextState[coord] = &stateInNext + + } + nodes = nextState + + } + + var count int + for _, node := range nodes { + if node.active { + count++ + } + } + // cubes after 6 cycles + return count } -func parseInput(input string) (ans []int) { - lines := strings.Split(input, "\n") - for _, l := range lines { - ans = append(ans, mathutil.StrToInt(l)) - } - return ans +type node4D struct { + x, y, z, w int + active bool +} + +func parseInput4D(input string) map[[4]int]*node4D { + nodes := map[[4]int]*node4D{} + lines := strings.Split(input, "\n") + for i, l := range lines { + for j, cell := range strings.Split(l, "") { + n := &node4D{ + x: i, y: j, z: 0, w: 0, active: false, + } + if cell == "#" { + n.active = true + } + nodes[[4]int{i, j, 0, 0}] = n + } + } + return nodes +} + +func generate4DDirections() [][4]int { + directions := [][4]int{} + for i := -1; i < 2; i++ { + for j := -1; j < 2; j++ { + for k := -1; k < 2; k++ { + for w := -1; w < 2; w++ { + if !(i == 0 && j == 0 && k == 0 && w == 0) { + directions = append(directions, [4]int{i, j, k, w}) + } + } + } + } + } + return directions +} + +var directions4D = generate4DDirections() + +func makeDirections(length int) [][]int { + perms := [][]int{ + make([]int, length), + } + + for i := 0; i < length; i++ { + for _, p := range perms { + copy1, copy2 := make([]int, length), make([]int, length) + copy(copy1, p) + copy(copy2, p) + copy1[i] = -1 + copy2[i] = 1 + perms = append(perms, copy1, copy2) + } + } + + return perms[1:] +} + +func getStringKey(slice []int) string { + var key string + for _, v := range slice { + key += fmt.Sprintf("%d-", v) + } + return key } diff --git a/2020/day17/main_test.go b/2020/day17/main_test.go index 22a4487..462730e 100644 --- a/2020/day17/main_test.go +++ b/2020/day17/main_test.go @@ -2,15 +2,22 @@ package main import ( "testing" + + "github.com/alexchao26/advent-of-code-go/util" ) +var example = `.#. +..# +###` + func Test_part1(t *testing.T) { tests := []struct { name string input string want int }{ - // {"actual", util.ReadFile("input.txt"), ACTUAL_ANSWER}, + {"example", example, 112}, + {"actual", util.ReadFile("input.txt"), 388}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -27,7 +34,8 @@ func Test_part2(t *testing.T) { input string want int }{ - // {"actual", util.ReadFile("input.txt"), ACTUAL_ANSWER}, + {"example", example, 848}, + {"actual", util.ReadFile("input.txt"), 2280}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) {