187 lines
3.4 KiB
Go
187 lines
3.4 KiB
Go
package main
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"os"
|
|
"time"
|
|
)
|
|
|
|
func main() {
|
|
start := time.Now()
|
|
partOne()
|
|
duration := time.Since(start)
|
|
partTwo()
|
|
duration2 := time.Since(start)
|
|
fmt.Printf("p1: %s, p2: %s\n", duration, duration2-duration)
|
|
}
|
|
|
|
// Our grid is a hex, so let's represent that as follows:
|
|
// x runs east-west, y runs north-south. Yes, these coordinates here are backward.
|
|
// 2,-2 2,0 2,2 2,4
|
|
// 1,-2 1,-1 1,1 1,2
|
|
// 0,-2 0,0 0,2 0,4
|
|
// -1,-2 -1,-1 -1,1 -1,2
|
|
// -2,-2 -2,0 -2,2 -2,4
|
|
// 0,0 -> e -> 0, 2
|
|
// -> w -> 0,-2
|
|
// -> se -> -1, 1
|
|
// -> sw -> -1,-1
|
|
// -> ne -> 1, 1
|
|
// -> nw -> 1,-1
|
|
|
|
// 0 == white, 1 == black
|
|
type tiles map[coord]int
|
|
|
|
type coord struct {
|
|
x int
|
|
y int
|
|
}
|
|
|
|
func walkGrid(directions []string) (int, int) {
|
|
var y, x int
|
|
for _, d := range directions {
|
|
switch d {
|
|
case "e":
|
|
x = x + 2
|
|
case "se":
|
|
y = y - 1
|
|
x = x + 1
|
|
case "sw":
|
|
y = y - 1
|
|
x = x - 1
|
|
case "w":
|
|
x = x - 2
|
|
case "ne":
|
|
y = y + 1
|
|
x = x + 1
|
|
case "nw":
|
|
y = y + 1
|
|
x = x - 1
|
|
}
|
|
}
|
|
return y, x
|
|
}
|
|
|
|
func parseLine(s string) []string {
|
|
directions := []string{}
|
|
for i := 0; i < len(s); {
|
|
switch s[i] {
|
|
case 'e':
|
|
directions = append(directions, "e")
|
|
i = i + 1
|
|
case 's':
|
|
if s[i+1] == 'e' {
|
|
directions = append(directions, "se")
|
|
i = i + 2
|
|
} else if s[i+1] == 'w' {
|
|
directions = append(directions, "sw")
|
|
i = i + 2
|
|
}
|
|
case 'w':
|
|
directions = append(directions, "w")
|
|
i = i + 1
|
|
case 'n':
|
|
if s[i+1] == 'e' {
|
|
directions = append(directions, "ne")
|
|
i = i + 2
|
|
} else if s[i+1] == 'w' {
|
|
directions = append(directions, "nw")
|
|
i = i + 2
|
|
}
|
|
}
|
|
}
|
|
return directions
|
|
}
|
|
|
|
func generation(t tiles) tiles {
|
|
newTiles := tiles{}
|
|
seenWhiteTiles := tiles{}
|
|
for coord, tile := range t {
|
|
// walk black tile list
|
|
if tile == 1 {
|
|
neighbors := getNeighbors(coord)
|
|
bn := 0
|
|
for _, n := range neighbors {
|
|
if t[n] == 0 {
|
|
seenWhiteTiles[n] = seenWhiteTiles[n] + 1
|
|
} else {
|
|
bn = bn + 1
|
|
}
|
|
}
|
|
// black tiles only survive if they have one or two black neighbors
|
|
if bn == 1 || bn == 2 {
|
|
newTiles[coord] = 1
|
|
}
|
|
}
|
|
}
|
|
// white tiles turn black if they have two black neighbors
|
|
for c, n := range seenWhiteTiles {
|
|
if n == 2 {
|
|
newTiles[c] = 1
|
|
}
|
|
}
|
|
return newTiles
|
|
}
|
|
|
|
func getNeighbors(c coord) []coord {
|
|
return []coord{
|
|
{x: c.x + 2, y: c.y}, // e
|
|
{x: c.x - 2, y: c.y}, // w
|
|
{x: c.x + 1, y: c.y + 1}, // ne
|
|
{x: c.x + 1, y: c.y - 1}, // nw
|
|
{x: c.x - 1, y: c.y + 1}, // se
|
|
{x: c.x - 1, y: c.y - 1}, // sw
|
|
}
|
|
}
|
|
|
|
func countBlackTiles(t tiles) int {
|
|
sum := 0
|
|
for _, tile := range t {
|
|
sum = sum + tile
|
|
}
|
|
return sum
|
|
}
|
|
|
|
func partOne() {
|
|
f, _ := os.Open("testinput")
|
|
reader := bufio.NewReader(f)
|
|
scanner := bufio.NewScanner(reader)
|
|
|
|
t := tiles{}
|
|
|
|
for scanner.Scan() {
|
|
line := scanner.Text()
|
|
x, y := walkGrid(parseLine(line))
|
|
if t[coord{x: x, y: y}] == 0 {
|
|
t[coord{x: x, y: y}] = 1
|
|
} else {
|
|
t[coord{x: x, y: y}] = 0
|
|
}
|
|
}
|
|
fmt.Println(countBlackTiles(t))
|
|
}
|
|
|
|
func partTwo() {
|
|
f, _ := os.Open("input")
|
|
reader := bufio.NewReader(f)
|
|
scanner := bufio.NewScanner(reader)
|
|
|
|
t := tiles{}
|
|
|
|
for scanner.Scan() {
|
|
line := scanner.Text()
|
|
y, x := walkGrid(parseLine(line))
|
|
if t[coord{x: x, y: y}] == 0 {
|
|
t[coord{x: x, y: y}] = 1
|
|
} else {
|
|
t[coord{x: x, y: y}] = 0
|
|
}
|
|
}
|
|
for day := 1; day <= 100; day = day + 1 {
|
|
t = generation(t)
|
|
}
|
|
fmt.Println(countBlackTiles(t))
|
|
|
|
}
|