DEV Community

Discussion on: AoC Day 12: Subterranean Sustainability

Collapse
 
bjarnemagnussen profile image
Bjarne Magnussen

Here is the Golang code. I don't think this is the best way of doing it in Golang, but it does the job!

package main

import (
    "bufio"
    "fmt"
    "os"
    "reflect"
    "regexp"
)

type entry struct {
    e     int
    shift int
}

// readLines reads a whole file into memory
// and returns a slice of its lines.
func readLines(path string) ([]string, error) {
    file, err := os.Open(path)
    if err != nil {
        return nil, err
    }
    defer file.Close()

    var lines []string
    scanner := bufio.NewScanner(file)
    for scanner.Scan() {
        lines = append(lines, scanner.Text())
    }
    return lines, scanner.Err()
}

// function to evolve generations.
func evolve(generations int) ([]rune, int) {
    seen := make(map[string]entry)
    shift := -4
    plantsCopy := make([]rune, len(plants))
    plantsOld := make([]rune, len(plants))
    copy(plantsOld, plants)
    for e := 1; e <= generations; e++ {
        plantsCopy = make([]rune, len(plantsOld))
        copy(plantsCopy, plantsOld)
        for idx := range plantsOld {
            if idx < 2 || idx > len(plantsOld)-3 {
                continue
            }
            plantsCopy[idx] = rules[string(plantsOld[idx-2:idx+3])]
        }
        if plantsCopy[3] == '#' {
            plantsCopy = append(plantsCopy, 0)
            copy(plantsCopy[1:], plantsCopy[0:])
            plantsCopy[0] = '.'
            shift--
        } else if reflect.DeepEqual(plantsCopy[:5], []rune{'.', '.', '.', '.', '.'}) {
            plantsCopy = plantsCopy[1:]
            shift++
        }
        if plantsCopy[len(plantsCopy)-3] == '#' {
            plantsCopy = append(plantsCopy, '.')
        } else if reflect.DeepEqual(plantsCopy[len(plantsCopy)-5:], []rune{'.', '.', '.', '.', '.'}) {
            plantsCopy = plantsCopy[:len(plantsCopy)-1]
        }
        if val, ok := seen[string(plantsCopy)]; ok {
            circleLength := e - val.e
            circles := (generations - e) / circleLength
            e = e + circles*circleLength
            shiftLength := shift - val.shift
            shift = shift + circles*shiftLength
        }
        seen[string(plantsCopy)] = entry{e: e, shift: shift}
        plantsOld = make([]rune, len(plantsCopy))
        copy(plantsOld, plantsCopy)
    }
    return plantsCopy, shift
}

var plants []rune
var rules map[string]rune

func main() {
    data, err := readLines("input")
    if err != nil {
        panic(err)
    }
    plantsInitial := "...." + data[0][15:] + "...."
    plants = []rune(plantsInitial)

    rules = make(map[string]rune)
    r, _ := regexp.Compile("([#|\\.]+) => ([#|\\.])")
    for _, d := range data[2:] {
        rule := r.FindStringSubmatch(d)[1]
        res := r.FindStringSubmatch(d)[2]
        rules[rule] = []rune(res)[0]
    }

    // Part 1:
    plants, shift := evolve(20)
    fmt.Println("Part 1:")
    var sum int
    sum = 0
    for i, p := range plants {
        if p == '#' {
            sum += i + shift
        }
    }
    fmt.Println(sum)

    // Part 2:
    plants, shift = evolve(50000000000)
    fmt.Println("Part 2:")
    sum = 0
    for i, p := range plants {
        if p == '#' {
            sum += i + shift
        }
    }
    fmt.Println(sum)
}