diff --git a/2018/day18/day18.go b/2018/day18/day18.go new file mode 100644 index 0000000..9c19f17 --- /dev/null +++ b/2018/day18/day18.go @@ -0,0 +1,202 @@ +package main + +import ( + "bufio" + "fmt" + "os" + "time" +) + +const ( + DIR_N = -1i + DIR_NE = 1 - 1i + DIR_E = 1 + DIR_SE = 1 + 1i + DIR_S = 1i + DIR_SW = -1 + 1i + DIR_W = -1 + DIR_NW = -1 - 1i + + CLEAR_SCREEN = "\033[H\033[2J" +) + +var scan []byte +var next []byte +var prevScans [][]byte +var width, height int + +func main() { + stdinToByteSlice() + part1() + part2() +} + +func part1() { + printScan() + for i := 0; i < 10; i++ { + fmt.Print(CLEAR_SCREEN) + scan = tickToNext() + printScan() + time.Sleep(time.Millisecond * 250) + } + var ttlOpen, ttlTrees, ttlLmbr int + for i := range scan { + switch getByte(getPosFromInt(i)) { + case '.': + ttlOpen++ + case '|': + ttlTrees++ + case '#': + ttlLmbr++ + } + } + _ = ttlOpen + fmt.Println("= Part 1 =") + fmt.Println(ttlTrees * ttlLmbr) +} + +// 191080? +func part2() { + var isDupe bool + var i int + target := 1000000000 + for i = 0; i < target; i++ { + //fmt.Print(CLEAR_SCREEN, target) + next := tickToNext() + if isDupe, prevScans = checkDuplicateState(next, prevScans); isDupe { + i++ + scan = next + break + } + prevScans = append(prevScans, next) + scan = next + } + // We need to find the state after `target` increments + scan = prevScans[(target-i)%len(prevScans)] + var ttlOpen, ttlTrees, ttlLmbr int + for i := range scan { + switch getByte(getPosFromInt(i)) { + case '.': + ttlOpen++ + case '|': + ttlTrees++ + case '#': + ttlLmbr++ + } + } + _ = ttlOpen + fmt.Println("= Part 2 =") + fmt.Println(ttlTrees * ttlLmbr) +} + +// checkDuplicateState returns the slice of prev that has all remaining available states +func checkDuplicateState(s []byte, prev [][]byte) (bool, [][]byte) { + for i, v := range prev { + if areasAreEqual(s, v) { + return true, prev[i:] + } + } + return false, prev +} + +func areasAreEqual(a1, a2 []byte) bool { + for i := range a1 { + if a1[i] != a2[i] { + return false + } + } + return true +} + +func tickToNext() []byte { + var ret []byte + for i := 0; i < len(scan); i++ { + c := getPosFromInt(i) + _, sTree, sLmbr := getSurroundingCounts(c) + b := getByte(c) + switch b { + case '.': + if sTree >= 3 { + ret = append(ret, '|') + } else { + ret = append(ret, '.') + } + case '|': + if sLmbr >= 3 { + ret = append(ret, '#') + } else { + ret = append(ret, '|') + } + case '#': + if sLmbr > 0 && sTree > 0 { + ret = append(ret, '#') + } else { + ret = append(ret, '.') + } + } + } + return ret +} + +// getSurroundingCounts takes a pos and returns: +// Number of open areas +// Number of trees +// Number of lumberyards +// Surrounding that spot +func getSurroundingCounts(c complex64) (int, int, int) { + var sOpen, sTree, sLmbr int + for _, v := range []complex64{DIR_NW, DIR_N, DIR_NE, DIR_W, DIR_E, DIR_SW, DIR_S, DIR_SE} { + switch getByte(c + v) { + case '.': + sOpen++ + case '|': + sTree++ + case '#': + sLmbr++ + } + } + return sOpen, sTree, sLmbr +} + +func printScan() { + for i := 0; i < len(scan)/width; i++ { + fmt.Println(string(scan[i*width : (i+1)*width])) + } +} + +// getByte pulls a byte from the given position in the scan +func getByte(pos complex64) byte { + //idx := int(real(pos)) + int(imag(pos))*width + if int(real(pos)) < 0 || int(imag(pos)) < 0 || int(real(pos)) >= width || int(imag(pos)) >= height { + return 0 + } + return scan[int(real(pos))+int(imag(pos))*width] +} + +func getPosComplex(x, y int) complex64 { + return complex(float32(x), float32(y)) +} + +func getPosFromInt(i int) complex64 { + return complex(float32(i%width), float32(i/width)) +} + +func getIdxFromPos(pos complex64) int { + return int(real(pos)) + int(imag(pos))*width +} + +func getCoordString(p complex64) string { + return fmt.Sprintf("(%d,%d [%d])", int(real(p)), int(imag(p)), getIdxFromPos(p)) +} + +func stdinToByteSlice() { + scanner := bufio.NewScanner(os.Stdin) + for scanner.Scan() { + s := scanner.Bytes() + if width == 0 { + width = len(s) + } + scan = append(scan, s...) + height++ + } +} diff --git a/2018/day18/input b/2018/day18/input new file mode 100644 index 0000000..98cad1f --- /dev/null +++ b/2018/day18/input @@ -0,0 +1,50 @@ +.#|#.##....#|....|.#.#.|||.#.|....||....|...|..#.. +..|#||.|#..|...|#|..#...|#...#..#..|.....||..#.|#. +#|||#..||.....||.#................|..#.##|.#...#.| +|#..#.|...##...#..#|#|#..|#.#...|....#..#...##.... +.###.........|.||#...#|.|#.||||#..|...||....#..#.. +###.|..|#|...|..||..##.....|..#.|.#.............|. +..|.|.||.#....|...|....#|.........##||..#||..|.##. +#||#|...#|..|.|.||#...#|...|#.......|...#.....|... +....||.....|.|.....#...|.......|...|..|...|......| +#......#..#|#|..|....#.|.|.#...#.#.|..#.|.....#.#. +.|#...|...........#|.#....#.#...#.|..|...|....|.|. +..||.#.|...||#|....#.#..||#..#...#|..#..|..#|..... +|..|.|..#...|.....#.|..|#.||..#|.|.||#|#..|#...##| +..|..|#......||##..|........#.|...#.|.|#.#...||..# +#.|...#.||#..|.|..|..|.#....|.||....|.|....#....#. +#||.|.#..#..|...#....##|#..#...#.#...|.#...#.....# +#.|.##.|##..#.##|##........#.|...#...|..#|.#|#|... +.|#|....|.#...#..|||.#.||..#||.||.|..#.|....|..##. +|.#.||#|.##.|.||.....#...#.#..###|.#......||#|.... +.|.#..|#||......|##..##.#|..#|.|#.|.|#......|#.|#. +#..|........|||..|###..|#..|||#.|.|.....#|..|...|# +..####||#......|#||..###.|...|....#..|.#|.||....|| +|##.......|||..........|..||.#.|#.......##...|...| +|.......#......####|#|....#....|......#.|#.###...# +#|.#.|||...|..|.....#....|...|......|#|#|......||. +...#.|......#..||||.#|.....|.|.|||.|.|.|#|.#...#.# +#.#.##.|.#|.|...|...|...#|...#.|#..|..##.|....#..| +|...#.......#....#....#.#....#.#|.|#||.|.|.|#...#. +#..|.||..|.#..|.#.....#|##.|.|....|....||.......|. +..||.#..|#|.###....#.#|..#|.#..........#...|...#|. +|#||.|.#..|....|....#.#||#.|......#..|#.#.|||||#|. +.|#.|#.##.....#.|.#.....|....|.#..#.#..|#.#.....|. +#.||.#.......|..|......|#||.|..#....#...|...|...|. +|.....#.|.....#||.....##...#.#...||.|..#........|. +||#..|.##.#...........#..|..|.|..#....|...#..||.#. +..||.##.##.|.||......#...|.#.#.#..#.#...##.#.|.#.. +.|.#......#|#||.|.#|......||.#.|.|..|....#...||... +....|.##.....|#|####.#..#..#|.....|.#.#|......|... +...#..|......#....|#.#...|...|.#.#.......#.#.##..# +.|||#.||||...|..|#||.|.#|#||..|..#..|..|..#||..... +.....|..#..|#|.||.#||.||......|||..|..#|.|##...... +.#...#|..#..|||..||.|..|.#.#.......||..|...|.|.... +.##.||..|..||.|.......#.|||.|.|..|.#.#..|.||.|#||| +.|..##|..#.#|#|....|.#.#.#|#.#|.##|........###...# +..#..|#|...#.........#.#.####..#.#..#..#||#|...#|# +#.|...|.......|.#.#..#.|#..#|#|..#..|.....|..|...| +.##.|..#.....|...#..|#..|.|.#..##.#.|..#.|..|.##.. +....|..|.|..||....|...|.....#..|.|.....|.#|......# +...##.|#..#..|.#|.##....|.#...||#|.....#...##.#|.. +.|....##.....||...#.#.....#|#...#...#|.|..#.#.#.## diff --git a/2018/day18/problem b/2018/day18/problem new file mode 100644 index 0000000..26c93fe --- /dev/null +++ b/2018/day18/problem @@ -0,0 +1,203 @@ +Advent of Code + +--- Day 18: Settlers of The North Pole --- + + On the outskirts of the North Pole base construction project, many Elves are collecting lumber. + + The lumber collection area is 50 acres by 50 acres; each acre can be either open ground (.), trees (|), or a + lumberyard (#). You take a scan of the area (your puzzle input). + + Strange magic is at work here: each minute, the landscape looks entirely different. In exactly one minute, an + open acre can fill with trees, a wooded acre can be converted to a lumberyard, or a lumberyard can be cleared + to open ground (the lumber having been sent to other projects). + + The change to each acre is based entirely on the contents of that acre as well as the number of open, wooded, + or lumberyard acres adjacent to it at the start of each minute. Here, "adjacent" means any of the eight acres + surrounding that acre. (Acres on the edges of the lumber collection area might have fewer than eight adjacent + acres; the missing acres aren't counted.) + + In particular: + + • An open acre will become filled with trees if three or more adjacent acres contained trees. Otherwise, + nothing happens. + • An acre filled with trees will become a lumberyard if three or more adjacent acres were lumberyards. + Otherwise, nothing happens. + • An acre containing a lumberyard will remain a lumberyard if it was adjacent to at least one other + lumberyard and at least one acre containing trees. Otherwise, it becomes open. + + These changes happen across all acres simultaneously, each of them using the state of all acres at the + beginning of the minute and changing to their new form by the end of that same minute. Changes that happen + during the minute don't affect each other. + + For example, suppose the lumber collection area is instead only 10 by 10 acres with this initial + configuration: + + Initial state: + .#.#...|#. + .....#|##| + .|..|...#. + ..|#.....# + #.#|||#|#| + ...#.||... + .|....|... + ||...#|.#| + |.||||..|. + ...#.|..|. + + After 1 minute: + .......##. + ......|### + .|..|...#. + ..|#||...# + ..##||.|#| + ...#||||.. + ||...|||.. + |||||.||.| + |||||||||| + ....||..|. + + After 2 minutes: + .......#.. + ......|#.. + .|.|||.... + ..##|||..# + ..###|||#| + ...#|||||. + |||||||||. + |||||||||| + |||||||||| + .||||||||| + + After 3 minutes: + .......#.. + ....|||#.. + .|.||||... + ..###|||.# + ...##|||#| + .||##||||| + |||||||||| + |||||||||| + |||||||||| + |||||||||| + + After 4 minutes: + .....|.#.. + ...||||#.. + .|.#||||.. + ..###||||# + ...###||#| + |||##||||| + |||||||||| + |||||||||| + |||||||||| + |||||||||| + + After 5 minutes: + ....|||#.. + ...||||#.. + .|.##||||. + ..####|||# + .|.###||#| + |||###|||| + |||||||||| + |||||||||| + |||||||||| + |||||||||| + + After 6 minutes: + ...||||#.. + ...||||#.. + .|.###|||. + ..#.##|||# + |||#.##|#| + |||###|||| + ||||#||||| + |||||||||| + |||||||||| + |||||||||| + + After 7 minutes: + ...||||#.. + ..||#|##.. + .|.####||. + ||#..##||# + ||##.##|#| + |||####||| + |||###|||| + |||||||||| + |||||||||| + |||||||||| + + After 8 minutes: + ..||||##.. + ..|#####.. + |||#####|. + ||#...##|# + ||##..###| + ||##.###|| + |||####||| + ||||#||||| + |||||||||| + |||||||||| + + After 9 minutes: + ..||###... + .||#####.. + ||##...##. + ||#....### + |##....##| + ||##..###| + ||######|| + |||###|||| + |||||||||| + |||||||||| + + After 10 minutes: + .||##..... + ||###..... + ||##...... + |##.....## + |##.....## + |##....##| + ||##.####| + ||#####||| + ||||#||||| + |||||||||| + + After 10 minutes, there are 37 wooded acres and 31 lumberyards. Multiplying the number of wooded acres by the + number of lumberyards gives the total resource value after ten minutes: 37 * 31 = 1147. + + What will the total resource value of the lumber collection area be after 10 minutes? + + Your puzzle answer was 644640. + +--- Part Two --- + + This important natural resource will need to last for at least thousands of years. Are the Elves collecting + this lumber sustainably? + + What will the total resource value of the lumber collection area be after 1000000000 minutes? + + Your puzzle answer was 191080. + + 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/18/input diff --git a/2018/day18/testinput b/2018/day18/testinput new file mode 100644 index 0000000..13d299d --- /dev/null +++ b/2018/day18/testinput @@ -0,0 +1,10 @@ +.#.#...|#. +.....#|##| +.|..|...#. +..|#.....# +#.#|||#|#| +...#.||... +.|....|... +||...#|.#| +|.||||..|. +...#.|..|.