package main import ( "bufio" "fmt" "os" "strings" ) func main() { partOne() partTwo() } type slope struct { rise int run int trees int position int } type terrain struct { row []string } func (t terrain) isTree(poss int) bool { return t.row[poss%len(t.row)] == "#" } // You start on the open square (.) in the top-left corner and need to reach the bottom (below the bottom-most row on your map). // The toboggan can only follow a few specific slopes (you opted for a cheaper model that prefers rational numbers); // start by counting all the trees you would encounter for the slope right 3, down 1: // From your starting position at the top-left, check the position that is right 3 and down 1. // Then, check the position that is right 3 and down 1 from there, and so on until you go past the bottom of the map. // The locations you'd check in the above example are marked here with O where there was an open square and X where there was a tree: // ..##.........##.........##.........##.........##.........##....... ---> // #..O#...#..#...#...#..#...#...#..#...#...#..#...#...#..#...#...#.. // .#....X..#..#....#..#..#....#..#..#....#..#..#....#..#..#....#..#. // ..#.#...#O#..#.#...#.#..#.#...#.#..#.#...#.#..#.#...#.#..#.#...#.# // .#...##..#..X...##..#..#...##..#..#...##..#..#...##..#..#...##..#. // ..#.##.......#.X#.......#.##.......#.##.......#.##.......#.##..... ---> // .#.#.#....#.#.#.#.O..#.#.#.#....#.#.#.#....#.#.#.#....#.#.#.#....# // .#........#.#........X.#........#.#........#.#........#.#........# // #.##...#...#.##...#...#.X#...#...#.##...#...#.##...#...#.##...#... // #...##....##...##....##...#X....##...##....##...##....##...##....# // .#..#...#.#.#..#...#.#.#..#...X.#.#..#...#.#.#..#...#.#.#..#...#.# ---> // In this example, traversing the map using this slope would cause you to encounter 7 trees. // Starting at the top-left corner of your map and following a slope of right 3 and down 1, how many trees would you encounter? func partOne() { f, _ := os.Open("input") reader := bufio.NewReader(f) scanner := bufio.NewScanner(reader) depth := 0 s := slope{ rise: 1, run: 3, trees: 0, position: 0, } for scanner.Scan() { e := terrain{ row: strings.Split(scanner.Text(), ""), } if depth%s.rise == 0 && e.isTree(s.position) { s.trees = s.trees + 1 } s.position = s.position + s.run depth = depth + s.rise } fmt.Println(s.trees) } // Determine the number of trees you would encounter if, for each of the following slopes, you start at the top-left corner and traverse the map all the way to the bottom: // Right 1, down 1. // Right 3, down 1. (This is the slope you already checked.) // Right 5, down 1. // Right 7, down 1. // Right 1, down 2. // In the above example, these slopes would find 2, 7, 3, 4, and 2 tree(s) respectively; multiplied together, these produce the answer 336. func partTwo() { f, _ := os.Open("input") reader := bufio.NewReader(f) scanner := bufio.NewScanner(reader) slopes := []*slope{ { rise: 1, run: 1, trees: 0, position: 0, }, { rise: 1, run: 3, trees: 0, position: 0, }, { rise: 1, run: 5, trees: 0, position: 0, }, { rise: 1, run: 7, trees: 0, position: 0, }, { rise: 2, run: 1, trees: 0, position: 0, }, } depth := 0 for scanner.Scan() { e := terrain{ row: strings.Split(scanner.Text(), ""), } for _, s := range slopes { if depth%s.rise == 0 { // check tree if e.isTree(s.position) { s.trees = s.trees + 1 } // only increment position if we're "on" for this row; handles the rise > run case s.position = s.position + s.run } // always move on a row depth = depth + 1 } } // can't be bothered to write out the loop fmt.Println(slopes[0].trees * slopes[1].trees * slopes[2].trees * slopes[3].trees * slopes[4].trees) }