From 18d07e81db33bb0a4262a46e6807d432540b8b7e Mon Sep 17 00:00:00 2001 From: Brian Buller Date: Wed, 12 Dec 2018 16:55:33 -0600 Subject: [PATCH] 2018 day 12 done --- 2018/day12/day12.go | 273 +++++++++++++++++++++++++++++--------------- 2018/day12/problem | 123 ++++++++++++++++++++ 2 files changed, 304 insertions(+), 92 deletions(-) create mode 100644 2018/day12/problem diff --git a/2018/day12/day12.go b/2018/day12/day12.go index f0317c6..c327873 100644 --- a/2018/day12/day12.go +++ b/2018/day12/day12.go @@ -7,136 +7,177 @@ import ( "strings" ) -var row map[int]bool -var transitions []*Transition +const ( + MaxInt = int(^uint(0) >> 1) + MinInt = -MaxInt - 1 +) + +var lastState string +var garden *Garden func main() { inp := StdinToStringSlice() - BuildRow(inp[0]) + garden = NewGarden(strings.Trim(inp[0], "intalsae: "), 0) for _, v := range inp[2:] { - transitions = append(transitions, NewTransition(v)) + garden.transitions = append(garden.transitions, NewTransition(v)) } - fmt.Print("St: ") - PrintState() - for i := 0; i < 20; i++ { - Tick() - fmt.Printf("%2d: ", i) - PrintState() + generations := 50000000000 + var i int + for i = 0; i < generations; i++ { + lastState = garden.string() + garden = garden.tick() + if garden.string() == lastState { + i++ + break + } } - fmt.Println("Total:", GetSum()) + garden.shiftPots(generations - i) + fmt.Println(garden.sum()) } -func Tick() { - m := make(map[int]bool) - lowest, highest := 0, 0 - for i := range row { - if i < lowest { - lowest = i - } - if i > highest { - highest = i +/** + * 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) } - for i := lowest - 2; i <= highest+2; i++ { - m[i] = GetNextValue(i) - } - lowest, highest = 0, 0 - for k := range m { - if k < lowest && m[k] { - lowest = k - } - if k > highest && m[k] { - highest = k - } - } - row = make(map[int]bool) - for i := lowest; i <= highest; i++ { - row[i] = m[i] + return g +} + +func (g *Garden) shiftPots(val int) { + for i := range g.pots { + g.pots[i].id = g.pots[i].id + val } } -func GetSum() int { - var ret int - lowest, highest := 0, 0 - for i := range row { - if i < lowest { - lowest = i - } - if i > highest { - highest = i - } - } - for i := lowest; i <= highest; i++ { - if row[i] { - ret += i +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 BuildRow(inp string) { - inp = strings.Split(inp, ": ")[1] - row = make(map[int]bool) - for i, v := range inp { - row[i] = rb(v) +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 GetIdxValue(idx int) byte { +func (g *Garden) getNextStateForPot(id int) bool { var ret byte - for i := idx + 2; i >= idx-2; i-- { + for i := id - 2; i <= id+2; i++ { ret = ret << 1 - if row[i] { + if g.getPot(i).value { ret = ret | 1 } } - return ret -} - -func GetNextValue(idx int) bool { - idxVal := GetIdxValue(idx) - for _, v := range transitions { - if v.GetValue() == idxVal { + for _, v := range g.transitions { + if v.GetValue() == ret { return v.next } } - return false + return false //g.getPot(id).value } -func GetValueString(b byte) string { +func (g *Garden) substring(st, ed int) string { var ret string - for i := 0; i < 5; i++ { - if (b & 1) == 1 { - ret = ret + "#" - } else { - ret = ret + "." - } - b = b >> 1 + for i := st; i <= ed; i++ { + ret += g.getPot(i).string() } return ret } -func PrintState() { - lowest, highest := -2, 30 - for i := range row { - if i < lowest { - lowest = i - } - if i > highest { - highest = i - } +func (g *Garden) string() string { + var ret string + for i := g.getStartIndex(); i <= g.getEndIndex(); i++ { + ret += g.getPot(i).string() } - fmt.Print("(", lowest, ") ") - for i := lowest; i <= highest; i++ { - if row[i] { - fmt.Print("#") - } else { - fmt.Print(".") - } - } - fmt.Println(" (", highest, ") ") + 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 @@ -146,9 +187,12 @@ func NewTransition(inp string) *Transition { var state []bool var next bool pts := strings.Split(inp, " => ") - for i := len(pts[0]) - 1; i >= 0; i-- { + 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, @@ -157,6 +201,14 @@ func NewTransition(inp string) *Transition { 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 { @@ -168,6 +220,43 @@ func (t *Transition) GetValue() byte { 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)) } diff --git a/2018/day12/problem b/2018/day12/problem new file mode 100644 index 0000000..c4c361b --- /dev/null +++ b/2018/day12/problem @@ -0,0 +1,123 @@ +Advent of Code + +--- Day 12: Subterranean Sustainability --- + + The year 518 is significantly more underground than your history books implied. Either that, or you've arrived in a vast + cavern network under the North Pole. + + After exploring a little, you discover a long tunnel that contains a row of small pots as far as you can see to your left + and right. A few of them contain plants - someone is trying to grow things in these geothermally-heated caves. + + The pots are numbered, with 0 in front of you. To the left, the pots are numbered -1, -2, -3, and so on; to the right, 1, 2, + 3.... Your puzzle input contains a list of pots from 0 to the right and whether they do (#) or do not (.) currently contain + a plant, the initial state. (No other pots currently contain plants.) For example, an initial state of #..##.... indicates + that pots 0, 3, and 4 currently contain plants. + + Your puzzle input also contains some notes you find on a nearby table: someone has been trying to figure out how these + plants spread to nearby pots. Based on the notes, for each generation of plants, a given pot has or does not have a plant + based on whether that pot (and the two pots on either side of it) had a plant in the last generation. These are written as + LLCRR => N, where L are pots to the left, C is the current pot being considered, R are the pots to the right, and N is + whether the current pot will have a plant in the next generation. For example: + + • A note like ..#.. => . means that a pot that contains a plant but with no plants within two pots of it will not have a + plant in it during the next generation. + • A note like ##.## => . means that an empty pot with two plants on each side of it will remain empty in the next + generation. + • A note like .##.# => # means that a pot has a plant in a given generation if, in the previous generation, there were + plants in that pot, the one immediately to the left, and the one two pots to the right, but not in the ones immediately + to the right and two to the left. + + It's not clear what these plants are for, but you're sure it's important, so you'd like to make sure the current + configuration of plants is sustainable by determining what will happen after 20 generations. + + For example, given the following input: + + initial state: #..#.#..##......###...### + + ...## => # + ..#.. => # + .#... => # + .#.#. => # + .#.## => # + .##.. => # + .#### => # + #.#.# => # + #.### => # + ##.#. => # + ##.## => # + ###.. => # + ###.# => # + ####. => # + + For brevity, in this example, only the combinations which do produce a plant are listed. (Your input includes all possible + combinations.) Then, the next 20 generations will look like this: + + 1 2 3 + 0 0 0 0 + 0: ...#..#.#..##......###...###........... + 1: ...#...#....#.....#..#..#..#........... + 2: ...##..##...##....#..#..#..##.......... + 3: ..#.#...#..#.#....#..#..#...#.......... + 4: ...#.#..#...#.#...#..#..##..##......... + 5: ....#...##...#.#..#..#...#...#......... + 6: ....##.#.#....#...#..##..##..##........ + 7: ...#..###.#...##..#...#...#...#........ + 8: ...#....##.#.#.#..##..##..##..##....... + 9: ...##..#..#####....#...#...#...#....... + 10: ..#.#..#...#.##....##..##..##..##...... + 11: ...#...##...#.#...#.#...#...#...#...... + 12: ...##.#.#....#.#...#.#..##..##..##..... + 13: ..#..###.#....#.#...#....#...#...#..... + 14: ..#....##.#....#.#..##...##..##..##.... + 15: ..##..#..#.#....#....#..#.#...#...#.... + 16: .#.#..#...#.#...##...#...#.#..##..##... + 17: ..#...##...#.#.#.#...##...#....#...#... + 18: ..##.#.#....#####.#.#.#...##...##..##.. + 19: .#..###.#..#.#.#######.#.#.#..#.#...#.. + 20: .#....##....#####...#######....#.#..##. + + The generation is shown along the left, where 0 is the initial state. The pot numbers are shown along the top, where 0 + labels the center pot, negative-numbered pots extend to the left, and positive pots extend toward the right. Remember, the + initial state begins at pot 0, which is not the leftmost pot used in this example. + + After one generation, only seven plants remain. The one in pot 0 matched the rule looking for ..#.., the one in pot 4 + matched the rule looking for .#.#., pot 9 matched .##.., and so on. + + In this example, after 20 generations, the pots shown as # contain plants, the furthest left of which is pot -2, and the + furthest right of which is pot 34. Adding up all the numbers of plant-containing pots after the 20th generation produces + 325. + + After 20 generations, what is the sum of the numbers of all pots which contain a plant? + + Your puzzle answer was 2281. + +--- Part Two --- + + You realize that 20 generations aren't enough. After all, these plants will need to last another 1500 years to even reach + your timeline, not to mention your future. + + After fifty billion (50000000000) generations, what is the sum of the numbers of all pots which contain a plant? + + Your puzzle answer was 2250000000120. + + Both parts of this puzzle are complete! They provide two gold stars: ** + +References + + Visible links + . https://adventofcode.com/ + . https://adventofcode.com/2018/about + . https://adventofcode.com/2018/events + . https://adventofcode.com/2018/settings + . https://adventofcode.com/2018/auth/logout + . Advent of Code Supporter + https://adventofcode.com/2018/support + . https://adventofcode.com/2018 + . https://adventofcode.com/2018 + . https://adventofcode.com/2018/support + . https://adventofcode.com/2018/sponsors + . https://adventofcode.com/2018/leaderboard + . https://adventofcode.com/2018/stats + . https://adventofcode.com/2018/sponsors + . https://adventofcode.com/2018 + . https://adventofcode.com/2018/day/12/input