package main import ( "flag" "fmt" "strings" "github.com/alexchao26/advent-of-code-go/mathy" "github.com/alexchao26/advent-of-code-go/util" ) func main() { var part int flag.IntVar(&part, "part", 1, "part 1 or 2") flag.Parse() fmt.Println("Running part", part) ans := part1(util.ReadFile("./input.txt"), part) fmt.Println("Output:", ans) } // 1240/668 func part1(input string, part int) int { instructions := strings.Split(input, "\n") tileIsBlack := map[[6]int]bool{} for _, inst := range instructions { // tally the steps taken in each of the hex directions var tallyDirections [6]int // iterate thorugh the NONDELIMITED instructions for i := 0; i < len(inst); { // set the direction to the next two characters if possible dir := string(inst[i]) if i+2 <= len(inst) { dir = inst[i : i+2] } // if the two character direction is se, sw, nw or ne, both characters // must be used, because using one is invalid ("n" or "s") switch dir { case "se", "sw", "nw", "ne": tallyDirections[dirIndices[dir]]++ i += 2 default: tallyDirections[dirIndices[dir[0:1]]]++ i++ } // collapse and directions that cancel out, such as sw/nw -> w tallyDirections = zeroOutHexDirections(tallyDirections) } // flip that tile tileIsBlack[tallyDirections] = !tileIsBlack[tallyDirections] } // for part 2, play game of life 100 times if part == 2 { for i := 0; i < 100; i++ { // flip based on neighbors nextState := map[[6]int]bool{} // collect all coordinates to check toCheck := map[[6]int]bool{} for i := 0; i < 6; i++ { for k := range tileIsBlack { k[i]++ toCheck[zeroOutHexDirections(k)] = true } } for coord := range toCheck { // count neighbors var neighbors int for i := 0; i < 6; i++ { clone := coord // don't want to modify the original coord clone[i]++ // generates the six directions around coord clone = zeroOutHexDirections(clone) if tileIsBlack[clone] { neighbors++ } } // flipping logic: // back with zero or more than 2 neighbors becomes white if tileIsBlack[coord] && (neighbors == 0 || neighbors > 2) { nextState[coord] = false } else if !tileIsBlack[coord] && neighbors == 2 { // white with exactly 2 neighbors becomes black nextState[coord] = true } else { // stays the same nextState[coord] = tileIsBlack[coord] } } tileIsBlack = nextState } } var count int for _, b := range tileIsBlack { if b { count++ } } return count } var dirIndices = map[string]int{ "e": 0, "se": 1, "sw": 2, "w": 3, "nw": 4, "ne": 5, } // borrowed from my 2017 day 11 code which calculated hex coordinate manhattan distances func zeroOutHexDirections(tally [6]int) [6]int { // zero out opposite indices for i := range tally { if tally[i] != 0 { oppositeIndex := (i + 3) % 6 smaller := mathy.MinInt(tally[oppositeIndex], tally[i]) tally[oppositeIndex] -= smaller tally[i] -= smaller } } // handle neighbors which collapse into the current direction // e.g. sw,se == s for i := range tally { toLeft := (i + 5) % 6 toRight := (i + 1) % 6 if tally[toLeft] > 0 && tally[toRight] > 0 { smaller := mathy.MinInt(tally[toLeft], tally[toRight]) tally[toLeft] -= smaller tally[toRight] -= smaller tally[i] += smaller } } return tally }