package main import ( "bufio" "fmt" "os" ) func printWorld(world []rune, stride int) { for z := 0; z < stride; z++ { i := z * (stride * stride) fmt.Printf("Z: %d\n", z) for y := 0; y < stride; y++ { j := i + (y * stride) for x := 0; x < stride; x++ { k := j + x r := world[k] if r == 0 { fmt.Printf("%c", '+') } else { fmt.Printf("%c", r) } } fmt.Println() } fmt.Println() } } func printWorld4D(world []rune, stride int) { for w := 0; w < stride; w++ { t := w * (stride * stride * stride) fmt.Printf("W: %d\n", w) for z := 0; z < stride; z++ { i := t + (z * (stride * stride)) fmt.Printf("Z: %d\n", z) for y := 0; y < stride; y++ { j := i + (y * stride) for x := 0; x < stride; x++ { k := j + x r := world[k] if r == 0 { fmt.Printf("%c", '+') } else { fmt.Printf("%c", r) } } fmt.Println() } fmt.Println() } fmt.Println() } } func getNumNeighbors(world []rune, stride int, x, y, z int) int { var result int for zz := z - 1; zz < z+2; zz++ { if zz < 0 || zz >= stride { continue } i := zz * (stride * stride) for yy := y - 1; yy < y+2; yy++ { if yy < 0 || yy >= stride { continue } j := i + (yy * stride) for xx := x - 1; xx < x+2; xx++ { if xx == x && yy == y && zz == z { continue } if xx < 0 || xx >= stride { continue } k := j + xx if world[k] == '#' { result++ } } } } return result } func getNumNeighbors4D(world []rune, stride int, x, y, z, w int) int { var result int for ww := w - 1; ww < w+2; ww++ { if ww < 0 || ww >= stride { continue } t := ww * (stride * stride * stride) for zz := z - 1; zz < z+2; zz++ { if zz < 0 || zz >= stride { continue } i := t + (zz * (stride * stride)) for yy := y - 1; yy < y+2; yy++ { if yy < 0 || yy >= stride { continue } j := i + (yy * stride) for xx := x - 1; xx < x+2; xx++ { if xx == x && yy == y && zz == z && ww == w { continue } if xx < 0 || xx >= stride { continue } k := j + xx if world[k] == '#' { result++ } } } } } return result } // Task1 ... func Task1(input []rune, stride int) int { offset := 1 worldStride := stride + (offset * 2) size := worldStride * worldStride * worldStride world := make([]rune, size) for i := range world { world[i] = '.' } for y := 0; y < stride; y++ { for x := 0; x < stride; x++ { zz := offset * (worldStride * worldStride) yy := (y + offset) * worldStride xx := x + offset world[zz+yy+xx] = input[(y*stride)+x] } } printWorld(world, worldStride) prevWorld := make([]rune, size) for step := 0; step < 6; step++ { //fmt.Printf("Step %d\n==========\n", step+1) copy(prevWorld, world) var grow bool for z := 0; z < worldStride; z++ { i := z * (worldStride * worldStride) for y := 0; y < worldStride; y++ { j := i + (y * worldStride) for x := 0; x < worldStride; x++ { k := j + x num := getNumNeighbors(prevWorld, worldStride, x, y, z) if prevWorld[k] == '#' { if num != 2 && num != 3 { world[k] = '.' } } else if prevWorld[i] == '.' { if num == 3 { world[k] = '#' if x == 0 || x == stride-1 || y == 0 || y == stride-1 || z == 0 || z == stride-1 { grow = true } } } } } } if grow { offset++ oldStride := worldStride worldStride = stride + (offset * 2) size = worldStride * worldStride * worldStride prevWorld = make([]rune, size) for i := range prevWorld { prevWorld[i] = '.' } for z := 0; z < oldStride; z++ { for y := 0; y < oldStride; y++ { for x := 0; x < oldStride; x++ { zz := (z + 1) * (worldStride * worldStride) yy := (y + 1) * worldStride xx := x + 1 prevWorld[zz+yy+xx] = world[(z*(oldStride*oldStride))+(y*oldStride)+x] } } } world = make([]rune, size) copy(world, prevWorld) } //printWorld(world, worldStride) } var result int for i := range world { if world[i] == '#' { result++ } } return result } // Task2 ... func Task2(input []rune, stride int) int { offset := 1 worldStride := stride + (offset * 2) size := worldStride * worldStride * worldStride * worldStride world := make([]rune, size) for i := range world { world[i] = '.' } for y := 0; y < stride; y++ { for x := 0; x < stride; x++ { ww := offset * (worldStride * worldStride * worldStride) zz := offset * (worldStride * worldStride) yy := (y + offset) * worldStride xx := x + offset world[ww+zz+yy+xx] = input[(y*stride)+x] } } //printWorld4D(world, worldStride) prevWorld := make([]rune, size) for step := 0; step < 6; step++ { //fmt.Printf("Step %d\n==========\n", step+1) copy(prevWorld, world) var grow bool for w := 0; w < worldStride; w++ { t := w * (worldStride * worldStride * worldStride) for z := 0; z < worldStride; z++ { i := t + (z * (worldStride * worldStride)) for y := 0; y < worldStride; y++ { j := i + (y * worldStride) for x := 0; x < worldStride; x++ { k := j + x num := getNumNeighbors4D(prevWorld, worldStride, x, y, z, w) if prevWorld[k] == '#' { if num != 2 && num != 3 { world[k] = '.' } } else if prevWorld[i] == '.' { if num == 3 { world[k] = '#' if x == 0 || x == stride-1 || y == 0 || y == stride-1 || z == 0 || z == stride-1 || w == 0 || w == stride-1 { grow = true } } } } } } } if grow { offset++ oldStride := worldStride worldStride = stride + (offset * 2) size = worldStride * worldStride * worldStride * worldStride prevWorld = make([]rune, size) for i := range prevWorld { prevWorld[i] = '.' } for w := 0; w < oldStride; w++ { for z := 0; z < oldStride; z++ { for y := 0; y < oldStride; y++ { for x := 0; x < oldStride; x++ { ww := (w + 1) * (worldStride * worldStride * worldStride) zz := (z + 1) * (worldStride * worldStride) yy := (y + 1) * worldStride xx := x + 1 prevWorld[ww+zz+yy+xx] = world[(w*(oldStride*oldStride*oldStride))+(z*(oldStride*oldStride))+(y*oldStride)+x] } } } } world = make([]rune, size) copy(world, prevWorld) } //printWorld4D(world, worldStride) } var result int for i := range world { if world[i] == '#' { result++ } } return result } func main() { file, _ := os.Open("input.txt") scanner := bufio.NewScanner(file) var stride int input := make([]rune, 0, 100) for scanner.Scan() { line := scanner.Text() if stride == 0 { stride = len(line) } for _, r := range line { input = append(input, rune(r)) } } file.Close() result := Task1(input, stride) fmt.Printf("Task 1: %d\n", result) result = Task2(input, stride) fmt.Printf("Task 2: %d\n", result) }