package main import ( "os" "fmt" "strconv" "strings" ) // --------------------------------------- type Stone int64 func (s Stone) blink() [2]Stone { stones := [...]Stone{-1, -1} num_str := strconv.Itoa(int(s)) switch { // rule 1 case s == 0: stones[0] = 1 // rule 2 case len(num_str) % 2 == 0: num1, err := strconv.Atoi(num_str[:len(num_str) / 2]) check(err) num2, err := strconv.Atoi(num_str[len(num_str) / 2:]) check(err) stones[0] = Stone(num1) stones[1] = Stone(num2) // rule 3 default: stones[0] = s * 2024 } return stones } // --------------------------------------- type Pair struct { s Stone n_steps uint32 } var population_number_cache map[Pair]uint64 func population_number(s Stone, n_steps uint32) uint64 { cache := population_number_cache[Pair{s, n_steps}] if cache != 0 { return cache } new_stones := s.blink() if n_steps == 0 { return 1 } p := population_number(new_stones[0], n_steps - 1) if new_stones[1] > -1 { p += population_number(new_stones[1], n_steps - 1) } population_number_cache[Pair{s, n_steps}] = p return p } func check(e error) { if e != nil { panic(e) } } func main() { // read in file dat, err := os.ReadFile("data.txt") check(err) dat_str := strings.TrimSpace(string(dat)) line_arr := strings.Split(dat_str, " ") // convert to list of numbers stones := make([]Stone, 0, len(line_arr)) for _, e := range line_arr { num, err := strconv.Atoi(e) check(err) stones = append(stones, Stone(num)) } // init cache population_number_cache = make(map[Pair]uint64) // main calc len_acc := uint64(0) for _, stone := range stones { len_acc += population_number(stone, 75) } fmt.Println(len_acc) }