package main import ( "bufio" "fmt" "os" "strings" ) const ( MaxInt = int(^uint(0) >> 1) MinInt = -MaxInt - 1 ) var lastState string var garden *Garden func main() { inp := StdinToStringSlice() garden = NewGarden(strings.Trim(inp[0], "intalsae: "), 0) for _, v := range inp[2:] { garden.transitions = append(garden.transitions, NewTransition(v)) } generations := 50000000000 var i int for i = 0; i < generations; i++ { lastState = garden.string() garden = garden.tick() if garden.string() == lastState { i++ break } } garden.shiftPots(generations - i) fmt.Println(garden.sum()) } /** * A Garden */ type Garden struct { pots []*Pot transitions []*Transition } func NewGarden(inp string, start int) *Garden { g := &Garden{} for k, v := range inp { p := &Pot{ id: k + start, value: rb(v), } g.pots = append(g.pots, p) } return g } func (g *Garden) shiftPots(val int) { for i := range g.pots { g.pots[i].id = g.pots[i].id + val } } func (g *Garden) sum() int64 { var ret int64 st, ed := g.getStartIndex(), g.getEndIndex() for i := st; i <= ed; i++ { if g.getPot(i).value { ret += int64(i) } } return ret } func (g *Garden) tick() *Garden { earliest, latest := g.getStartIndex(), g.getEndIndex() st := earliest - 2 ed := latest + 2 ret := &Garden{ transitions: g.transitions, } for i := st; i <= ed; i++ { next := g.getNextStateForPot(i) if next { ret.pots = append(ret.pots, &Pot{ id: i, value: next, }) } } return ret } func (g *Garden) getNextStateForPot(id int) bool { var ret byte for i := id - 2; i <= id+2; i++ { ret = ret << 1 if g.getPot(i).value { ret = ret | 1 } } for _, v := range g.transitions { if v.GetValue() == ret { return v.next } } return false //g.getPot(id).value } func (g *Garden) substring(st, ed int) string { var ret string for i := st; i <= ed; i++ { ret += g.getPot(i).string() } return ret } func (g *Garden) string() string { var ret string for i := g.getStartIndex(); i <= g.getEndIndex(); i++ { ret += g.getPot(i).string() } return ret } func (g *Garden) transitionStrings() string { var ret string for _, v := range g.transitions { ret = ret + v.string() + "\n" } return ret } func (g *Garden) getStartIndex() int { min := MaxInt for _, v := range g.pots { if v.id < min { min = v.id } } return min } func (g *Garden) getEndIndex() int { max := MinInt for _, v := range g.pots { if v.id > max { max = v.id } } return max } func (g *Garden) getPot(idx int) *Pot { for _, v := range g.pots { if v.id == idx { return v } } return &Pot{ id: idx, value: false, } } /** * A Pot */ type Pot struct { id int value bool } func (p *Pot) string() string { return bs(p.value) } /** * Transitions */ type Transition struct { state []bool next bool } func NewTransition(inp string) *Transition { var state []bool var next bool pts := strings.Split(inp, " => ") for i := range pts[0] { state = append(state, bb(pts[0][i])) } //for i := len(pts[0]) - 1; i >= 0; i-- { // state = append(state, bb(pts[0][i])) //} next = bb(pts[1][0]) t := &Transition{ state: state, next: next, } return t } func (t *Transition) string() string { var ret string for _, v := range t.state { ret += bs(v) } return ret + " => " + bs(t.next) } func (t *Transition) GetValue() byte { var ret byte for _, v := range t.state { ret = ret << 1 if v { ret = ret | 1 } } return ret } /** * Helper Functions */ // Take a byte and return a string representation of the bits func byteToString(b byte) string { var ret string for i := 0; i < 8; i++ { if b&1 == 1 { ret += "#" } else { ret += "." } b = b >> 1 } return ret } // Take a string representation of a bits and return the byte func stringToByte(n string) byte { var b byte for i := range n { if n[i] == '#' { b = b | 1 } b = b << 1 } return b } func bs(b bool) string { if b { return "#" } return "." } func rb(r rune) bool { return bb(byte(r)) } func bb(b byte) bool { return b == '#' } func StdinToStringSlice() []string { var input []string scanner := bufio.NewScanner(os.Stdin) for scanner.Scan() { input = append(input, scanner.Text()) } return input }