12 votes

Day 3: Toboggan Trajectory

Today's problem description: https://adventofcode.com/2020/day/3


Join the Tildes private leaderboard! You can do that on this page, by entering join code 730956-de85ce0c.

Please post your solutions in your own top-level comment. Here's a template you can copy-paste into your comment to format it nicely, with the code collapsed by default inside an expandable section with syntax highlighting (you can replace python with any of the "short names" listed in this page of supported languages):

<details>
<summary>Part 1</summary>

```python
Your code here.
```

</details>

25 comments

  1. teaearlgraycold
    Link
    Parts 1 and 2 from functools import reduce terrain = [] with open("input", "r") as file: for line in file.readlines(): terrain.append([char == "#" for char in line.strip()]) def count_trees(right,...
    Parts 1 and 2
    from functools import reduce
    
    terrain = []
    
    with open("input", "r") as file:
        for line in file.readlines():
            terrain.append([char == "#" for char in line.strip()])
    
    
    def count_trees(right, down):
        trees_encountered = 0
        position = (0, 0)
    
        while True:
            if terrain[position[1]][position[0]]:
                trees_encountered += 1
            
            position = ((position[0] + right) % len(terrain[0]), position[1] + down)
    
            if position[1] >= len(terrain):
                return trees_encountered
    
    
    print(f"Part 1: {count_trees(3, 1)}")
    
    inputs = [
        (1, 1),
        (3, 1),
        (5, 1),
        (7, 1),
        (1, 2),
    ]
    print(f"Part 2: {reduce(lambda acc, x: acc * x, [count_trees(*input) for input in inputs], 1)}")
    

    I got a little tripped on the the classic problem of reversing my x and y indexes into my 2d array. That cost me at least a few hundred ranks on the global leaderboard.

    6 votes
  2. Crestwave
    Link
    I love the stories behind the puzzles. I actually forgot that POSIX AWK supported modulo, but I didn't have trouble going without it; substr starts its indexes at 1, anyway. While part 1 was very...

    The toboggan can only follow a few specific slopes (you opted for a cheaper model that prefers rational numbers)

    I love the stories behind the puzzles.

    I actually forgot that POSIX AWK supported modulo, but I didn't have trouble going without it; substr starts its indexes at 1, anyway. While part 1 was very short and simple, I did feel some other POSIX limitations restrictive on structuring part 2. But it's nothing that slightly messier code can't fix.

    Part 1
    #!/usr/bin/awk -f
    BEGIN { i = 1 }
    
    {
            if (i > length($0))
                    i -= length($0)
    
            if (substr($0, i, 1) == "#")
                    j += 1
    
            i += 3
    }
    
    END { print j }
    
    Part 2
    #!/usr/bin/awk -f
    BEGIN {
            dirs = split("1, 3, 5, 7, 1", h, ",")
            split("1, 1, 1, 1, 2", v, ",")
            output = 1
    }
    
    { input[lines++] = $0 }
    
    END {
            for (i = 1; i <= dirs; ++i) {
                    count = 0
                    pos = 1
    
                    for (j = 0; j < lines; j += v[i]) {
                            line = input[j]
                            if (pos > length(line))
                                    pos -= length(line)
    
                            if (substr(line, pos, 1) == "#")
                                    count += 1
    
                            pos += h[i]
                    }
    
                    output *= count
            }
    
            print output
    }
    
    5 votes
  3. PapaNachos
    (edited )
    Link
    Code and ramen make a great midnight treat! My food just finished right as the challenge started. This one as pretty fun. I choose to interpret is as if you're colliding into the trees, rather...

    Code and ramen make a great midnight treat! My food just finished right as the challenge started. This one as pretty fun. I choose to interpret is as if you're colliding into the trees, rather than swerving to avoid them, so that definitely amused me while I was writing my code.

    And shout out to % for being the MVP in this one!

    Day 3 Part A - Python For part A I just split up the rows based on the newline character and then used the fact that I can index on a string to get a specific character. The fact that it repeats meant modulus is a great solution for solving how x wraps around. From there it was just a matter of counting how many trees you hit on the way down.

    I had a feeling that part B would have multiple slopes, so I tried to make it so it would be easy to convert

    test_data = '''..##.......
    #...#...#..
    .#....#..#.
    ..#.#...#.#
    .#...##..#.
    ..#.##.....
    .#.#.#....#
    .#........#
    #.##...#...
    #...##....#
    .#..#...#.#'''
    
    area = test_data.split('\n')
    
    width = len(area[0])
    height = len(area)
    
    x_speed = 3
    y_speed = 1
    x_loc = 0
    y_loc = 0
    
    trees_hit = 0
    
    while y_loc < height:
        x_loc = x_loc + x_speed
        y_loc = y_loc + y_speed
        if y_loc >= height:
            print('Made it to the bottom!')
        else:
            current_location = area[y_loc][x_loc % width]
            if current_location == '#':
                trees_hit = trees_hit + 1
    print(f'You only hit {trees_hit} tree(s)!')
    
    Day 3 Part B - Python For Part B I converted the main portion of part A into a method and used the different slopes as arguments. Then I stepped through each of the different slopes and stored their output in an array. Finally I multiplied the contents of that array together. Actually storing the data like I did wasn't really necessary. I could have easily just have run the different versions manually and plugged the results into a calculator, but this felt cleaner and more robust.
    test_data = '''..##.......
    #...#...#..
    .#....#..#.
    ..#.#...#.#
    .#...##..#.
    ..#.##.....
    .#.#.#....#
    .#........#
    #.##...#...
    #...##....#
    .#..#...#.#'''
    
    area = input_data.split('\n')
    
    width = len(area[0])
    height = len(area)
    
    slopes = [(1,1),(3,1),(5,1),(7,1),(1,2)]
    trees = []
    
    def check_slope(x_speed, y_speed):
        x_loc = 0
        y_loc = 0
    
        trees_hit = 0
    
        while y_loc < height:
            x_loc = x_loc + x_speed
            y_loc = y_loc + y_speed
            if y_loc < height:
                current_location = area[y_loc][x_loc % width]
                if current_location == '#':
                    trees_hit = trees_hit + 1
        return trees_hit
        
    for slope in slopes:
        num_trees = check_slope(slope[0],slope[1])
        trees.append(num_trees)
        print(f'For slope {slope} you hit {num_trees} trees')
    product = 1
    for val in trees:
        product = product * val
    print(f'Target number: {product}')
    
    Tips for Beginners
    • If you treat the forest like a grid, you can use a coordinate system to walk through it

    • The % symbol I pointed to in my description means modulus. If you've ever done division by hand, it's the remainder so for example 7 % 3 = 1. Using modulus lets you allow the forest to wrap around infinitely without you needing to worry about it

    • In part B, the easy way is to just manually modify your program for each of the different slopes and record the answers on paper. But you might find it more satisfying to see if you can create a program that can do the whole process without manual intervention

    4 votes
  4. [4]
    tomf
    Link
    With Google Sheets I used a variation of this for everything. The only major difference between the first four and the last one was pulling odd rows. Nothing crazy. Part 1 and 2 =ARRAYFORMULA(...

    With Google Sheets I used a variation of this for everything. The only major difference between the first four and the last one was pulling odd rows. Nothing crazy.

    Part 1 and 2
    =ARRAYFORMULA(
      COUNTIF(
       REGEXEXTRACT(
        A1:A,
        REPT(
         ".",
         MOD(
          TRANSPOSE(
          SEQUENCE(1,COUNTA(A1:A),4,3)-3)-1, 
          LEN($A1:A)))&
         "(.)"),
       "#"))
    
    
    For the 1 - 2 one...
    =ARRAYFORMULA(
      COUNTIF(
       IF(ISEVEN(ROW(A1:A)),,
       REGEXEXTRACT(
        A1:A,
        REPT(
         ".",
         MOD(
          TRANSPOSE(
         SEQUENCE(1,COUNTA(A1:A),0,1))-1, 
          LEN($A1:A)))&
         "(.)")),
       "#"))
    
    Solution

    176 and 5,872,458,240

    4 votes
    1. [3]
      petrichor
      Link Parent
      You're using Google Sheets, that's pretty crazy (crazy impressive, that is). Interesting, I didn't know Advent of Code had multiple problem answers / puzzle inputs. My answers were 242 and 2265549792.

      Nothing crazy.

      You're using Google Sheets, that's pretty crazy (crazy impressive, that is).

      176 and 5,872,458,240

      Interesting, I didn't know Advent of Code had multiple problem answers / puzzle inputs. My answers were 242 and 2265549792.

      5 votes
      1. tomf
        Link Parent
        it's been so much fun so far. I can't believe some of the insane languages some folks are using.

        it's been so much fun so far. I can't believe some of the insane languages some folks are using.

        2 votes
      2. knocklessmonster
        Link Parent
        I was doing 2 pt2, kept having problems with my code, so I saw a lot of different messages: Too high, too low, here's some tips, but one stood out: "You've entered somebody else's answer! ..." I...

        I was doing 2 pt2, kept having problems with my code, so I saw a lot of different messages: Too high, too low, here's some tips, but one stood out: "You've entered somebody else's answer! ..."

        I guess otherwise it would be like Project Euler where you'll find solutions all over.

  5. 3d12
    Link
    I got a little worried when I started reading and saw the diagram, figuring it would be another spacial-relation puzzle (and ho boy, I'm horrible at those!) so I was glad to see it was more...

    I got a little worried when I started reading and saw the diagram, figuring it would be another spacial-relation puzzle (and ho boy, I'm horrible at those!) so I was glad to see it was more mathematical than that. Repo is here

    I totally re-did part 1 after reading the spec for part 2. Should have split that function out to begin with.

    Part 1
    const fs = require('fs');
    const readline = require('readline');
    
    let mapArray = []
    
    async function openFileForReading(file) {
    	const fileStream = fs.createReadStream(file);
    
    	const rl = readline.createInterface({
    		input: fileStream,
    		crlfDelay: Infinity
    	});
    
    	for await (const line of rl) {
    		mapArray.push(line);
    	}
    }
    
    function calculateTreesHit(right, down) {
    	let treesHit = 0;
    	let rowPos = 0;
    	let colPos = 0;
    	while (rowPos < mapArray.length) {
    		// figure out if we've hit a tree at our current position
    		if (mapArray[rowPos].charAt(colPos) == '#') {
    			treesHit++;
    		}
    		// update position (3 right, 1 down)
    		if ((colPos + right) >= mapArray[rowPos].length) {
    			colPos = (colPos + right) % mapArray[rowPos].length;
    		} else {
    			colPos += right;
    		}
    		rowPos += down;
    	}
    	return treesHit;
    }
    
    (async function mainExecution() {
    	await openFileForReading('input.txt');
    	console.log("Trees hit: " + calculateTreesHit(3, 1));
    })();
    
    Part 2
    const fs = require('fs');
    const readline = require('readline');
    
    let mapArray = []
    
    async function openFileForReading(file) {
    	const fileStream = fs.createReadStream(file);
    
    	const rl = readline.createInterface({
    		input: fileStream,
    		crlfDelay: Infinity
    	});
    
    	for await (const line of rl) {
    		mapArray.push(line);
    	}
    }
    
    function calculateTreesHit(right, down) {
    	let treesHit = 0;
    	let rowPos = 0;
    	let colPos = 0;
    	while (rowPos < mapArray.length) {
    		// figure out if we've hit a tree at our current position
    		if (mapArray[rowPos].charAt(colPos) == '#') {
    			treesHit++;
    		}
    		// update position (3 right, 1 down)
    		if ((colPos + right) >= mapArray[rowPos].length) {
    			colPos = (colPos + right) % mapArray[rowPos].length;
    		} else {
    			colPos += right;
    		}
    		rowPos += down;
    	}
    	return treesHit;
    }
    
    (async function mainExecution() {
    	await openFileForReading('input.txt');
    	let result1 = calculateTreesHit(1, 1);
    	console.log("Slope 1,1 hits " + result1 + " trees");
    	let result2 = calculateTreesHit(3, 1);
    	console.log("Slope 3,1 hits " + result2 + " trees");
    	let result3 = calculateTreesHit(5, 1);
    	console.log("Slope 5,1 hits " + result3 + " trees");
    	let result4 = calculateTreesHit(7, 1);
    	console.log("Slope 7,1 hits " + result4 + " trees");
    	let result5 = calculateTreesHit(1, 2);
    	console.log("Slope 1,2 hits " + result5 + " trees");
    	console.log(result1 + " * " + result2 + " * " + result3 + " * " + result4 + " * " + result5 + " = " + (result1 * result2 * result3 * result4 * result5));
    })();
    
    4 votes
  6. [2]
    0d_billie
    Link
    I had no idea how to approach this for a while, but the hints given by @PapaNachos were invaluable, and I managed to solve the problem fairly quickly. I'm not normally one for defining functions...

    I had no idea how to approach this for a while, but the hints given by @PapaNachos were invaluable, and I managed to solve the problem fairly quickly. I'm not normally one for defining functions in my code, so planning ahead and getting the answer for part 2 just by adding a few extra lines was a really nice bonus.

    Part 1 runs in 0.00059 seconds
    #!/usr/bin/env python3
    map = []
    
    with open("input", "r") as input:
        for line in input.readlines():
            map.append(line.strip())
        
    height = len(map)
    width = len(map[0])
        
    def toboggan(x,y):
        trees = 0
        x_loc = 0
        y_loc = 0
        while y_loc < height:
            loc = map[y_loc][x_loc % width]
            if loc == "#":
                trees+=1
            x_loc+=x
            y_loc+=y
        return(trees)
            
    
    toboggan(3,1)
    
    Part 2 runs in 0.00081 seconds
    slopes = [[1,1],[3,1],[5,1],[7,1],[1,2]]
    trees = 1
    for slope in slopes:    
        trees*=toboggan(slope[0],slope[1])
    
    print(trees)
    
    4 votes
    1. PapaNachos
      Link Parent
      I'm glad they helped! Sometimes these problems have a couple obstacles that make them difficult to wrap your head around in the first place.

      I'm glad they helped! Sometimes these problems have a couple obstacles that make them difficult to wrap your head around in the first place.

      4 votes
  7. [2]
    Comment deleted by author
    Link
    1. blitz
      Link Parent
      All of your previous days have been so functional programming oriented, I'm surprised to see an explicit for loop in your second part! You could get the same thing with something like let...

      All of your previous days have been so functional programming oriented, I'm surprised to see an explicit for loop in your second part! You could get the same thing with something like

      let result_two = increments.iter().map(|x| calculate(&data, x)).product()

      2 votes
  8. archevel
    (edited )
    Link
    Did mine earlier today. I generalized the initial solution to a generic one for the second part. I've decided to go heavy into solving it mostly with numpy just to try and keep some of that...

    Did mine earlier today. I generalized the initial solution to a generic one for the second part. I've decided to go heavy into solving it mostly with numpy just to try and keep some of that knowledge fresh (was a while since I worked with it). I struggled first with since I missed the part about the pattern repeating itself, but once I realized this mistake it was fairly straight forward.

    Part 2 (core code solves 1 too)
    import sys
    import numpy as np
    
    v = np.array([list(x[:-1]) for x in sys.stdin.readlines()])
    
    def checkSlope(hStep, vStep):
        repeated = np.hstack([v for i in range(len(v)-len(v[0])+hStep)])
        i = np.arange(len(repeated[::vStep])) * hStep
        path = np.diag(repeated[::vStep, i])
        return sum(path == '#')
    
    res = checkSlope(1,1) * checkSlope(3,1) * checkSlope(5,1) * checkSlope(7,1) * checkSlope(1,2)
    print(res)
    

    Realized I could... (see details below)

    Part 2 (core code solves 1 too) v2 ...ditch the hstack part to make it cleaner by just using modulo on the indexes! One further improvement (?) to the code below would be to use a flat array to represent the input, then just add `np.arange(len(v)) * len(v[0])[::vStep]` to the index `i`. Then use `sum(v.reshape(v.size)[i] == '#')` to get the tree count for a slope...
    import sys
    import numpy as np
    
    v = np.array([list(x[:-1]) for x in sys.stdin.readlines()])
    
    def checkSlope2(hStep, vStep):
        i = (np.arange(len(v[::vStep])) * hStep) % len(v[0])
        path = np.diag(v[::vStep, i])
        return sum(path == '#')
    
    res = checkSlope2(1,1) * checkSlope2(3,1) * checkSlope2(5,1) * checkSlope2(7,1) * checkSlope2(1,2)
    print(res)
    
    3 votes
  9. soks_n_sandals
    (edited )
    Link
    Rewrote my initial Perl solutions with both now working. Part 1 (part 2 nested inside somehow??) use strict; #use warnings; use feature 'say'; open my $input_list, '<', "day3_inp"; chomp(my...

    Rewrote my initial Perl solutions with both now working.

    Part 1 (part 2 nested inside somehow??)
    use strict;
    #use warnings;
    use feature 'say';
    
    
    open my $input_list, '<', "day3_inp";
    chomp(my @landscape = <$input_list>);
    close $input_list;
    
    my $descent = scalar(@landscape); #how many times do we go down?
    my $traverse = length($landscape[0]); #how many times do we go across before repeating?
    
    #say $landscape[0];
    #say "the distance is $descent";
    #say "the traverse is $traverse";
    
    my @position = (0, 0);      #just get an initial position
    
    my $tree_count=0;          #for the sum
    my @route = (3,1);
    
    while ($position[1] <= $descent-1) {
      my @hazards = split //, $landscape[$position[1]]; #split the line of the landscape array into individual characters
    
      if ($position[0] > $traverse-1){
        my $reset = $position[0] - $traverse;
        @position[0]=$reset;
      }
    
      if ($hazards[$position[0]] eq "#"){
        $tree_count=$tree_count + 1;        #increment up by one
      #  say "Hit a tree! That makes $tree_count!";
      } else {
      #  say "We're clear!";
      }
    
      #say "Here we are: position is $position[0],$position[1] and landscape is $hazards[$position[0]]";
      @position[0]=@position[0]+$route[0];
      @position[1]=@position[1]+$route[1];
    }
    
    say "We hit $tree_count trees!";
    
    Part 2
    use strict;
    #use warnings;
    use feature 'say';
    
    
    open my $input_list, '<', "day3_inp";
    chomp(my @landscape = <$input_list>);
    close $input_list;
    
    my $descent = scalar(@landscape); #how many times do we go down?
    my $traverse = length($landscape[0]); #how many times do we go across before repeating?
    
    #say $landscape[0];
    #say "the distance is $descent";
    #say "the traverse is $traverse";
    
    my @tree_log=();            #to hold each result
    my @route_x = (1,3,5,7,1);  #specify the x-routes
    my @route_y = (1,1,1,1,2);  #specify the y-routes - this is a lot easier since the indexing matches
                                #  between the two arrays
    
    foreach (1 ... 5) {
    
      my @route = ($route_x[$_-1] , $route_y[$_-1]);
    
      my $tree_count=0;          #for the sum; initialize as 0 for each loop
      my @position = (0, 0);      #just get an initial position
    
    
      while ($position[1] <= $descent-1) {
        my @hazards = split //, $landscape[$position[1]]; #split the line of the landscape array into individual characters
    
        if ($position[0] > $traverse-1){
          my $reset = $position[0] - $traverse;
          @position[0]=$reset;
        }
    
        if ($hazards[$position[0]] eq "#"){
          $tree_count=$tree_count + 1;        #increment up by one
          #say "Hit a tree! That makes $tree_count!";
        } else {
          #say "We're clear!";
        }
    
        #say "Here we are: position is $position[0],$position[1] and landscape is $hazards[$position[0]]";
        @position[0]=@position[0]+$route[0];
        @position[1]=@position[1]+$route[1];
      }
    @tree_log[$_-1]=$tree_count;
    }
    
    say "We hit @tree_log trees!";
    my $probability = $tree_log[0]*$tree_log[1]*$tree_log[2]*$tree_log[3]*$tree_log[4];
    say $probability;
    
    3 votes
  10. nothis
    Link
    Python. Thanks again to @blitz for the help with the filename. Part 1+2 with open("03/input.txt") as inputFile: terrain = inputFile.read().split("\n") def slopeTrees(right, down, terrain): row =...

    Python. Thanks again to @blitz for the help with the filename.

    Part 1+2
    with open("03/input.txt") as inputFile:
        terrain = inputFile.read().split("\n")
    
    def slopeTrees(right, down, terrain):
        row = right
        width = len(terrain[0])
        treeCount = 0
        for line in range(down, len(terrain), down):
            if terrain[line][row] == "#":
                treeCount += 1
            row = (row + right) % width
        return treeCount
    
    print("Route (3, 1): ", slopeTrees(3, 1, terrain))
    
    allRoutes = slopeTrees(1, 1, terrain) * slopeTrees(3, 1, terrain) * \
        slopeTrees(5, 1, terrain) * slopeTrees(7, 1, terrain) * \
        slopeTrees(1, 2, terrain)
    
    print("All routes: ", allRoutes)
    
    3 votes
  11. clone1
    (edited )
    Link
    Scheme solution Part 1 & 2 I'm using an identity function as my parser because I don't want to mess with my infrastructure. (define (get-lines parse-line) (with-input-from-file "input" (lambda ()...

    Scheme solution

    Part 1 & 2 I'm using an identity function as my parser because I don't want to mess with my infrastructure.
    (define (get-lines parse-line)
      (with-input-from-file "input"
        (lambda ()
          (let loop ((line (read-line))
                     (lines '()))
            (if (eof-object? line)
                (reverse lines)
                (loop (read-line)
                      (cons (parse-line line) lines)))))))
    
    (define (make-slope x y)
      (cons x y))
    (define (get-x slope)
      (car slope))
    (define (get-y slope)
      (cdr slope))
    
    (define (filter-with-index proc l)
      (map cdr
           (filter (lambda (index-and-element)
                     (proc (car index-and-element) (cdr index-and-element)))
                   (map cons (iota (length l)) l))))
    
    (define (tree-count lines slope)
      (let* ((sx (get-x slope))
             (sy (get-y slope))
             (lines (filter-with-index (lambda (i x) (= (remainder i sy) 0))
                                       lines)))
        (count (lambda (i line)
                 (eq? (string-ref line
                                  (remainder (* sx i)
                                             (string-length line)))
                      #\#))
               (iota (length lines))
               lines)))
    
    (define (one lines)
      (tree-count lines (make-slope 3 1)))
    
    (define (product list)
      (fold * 1 list))
    
    (define (two lines)
      (product
       (map (lambda (slope) (tree-count lines slope))
            (list (make-slope 1 1)
                  (make-slope 3 1)
                  (make-slope 5 1)
                  (make-slope 7 1)
                  (make-slope 1 2)))))
    
    (define (run parser)
      (let ((lines (get-lines parser)))
        (display "One: ")
        (display (one lines))
        (newline)
        (display "Two: ")
        (display (two lines))
        (newline)))
    
    ;; Identity function parser because I don't like messing with infrastructure
    (define (parser x) x)
    
    (run parser)
    
    2 votes
  12. andre
    Link
    Nothing too special here, very similar to solution to most people I imagine. 858/576. Part 1 and 2 in JS function countTrees(path, dx, dy) { let y = 0 let x = 0 let trees = 0 while (y <...

    Nothing too special here, very similar to solution to most people I imagine. 858/576.

    Part 1 and 2 in JS
    function countTrees(path, dx, dy) {
      let y = 0
      let x = 0
      let trees = 0
    
      while (y < path.length) {
        if (path[y][x] === '#') {
          trees++
        }
    
        x = (x + dx) % path[y].length
        y += dy
      }
    
      return trees
    }
    
    export function solvePart1(input) {
      input = input.split('\n')
      return countTrees(input, 3, 1)
    }
    
    export function solvePart2(input) {
      input = input.split('\n')
    
      const slopes = [
        [1, 1],
        [3, 1],
        [5, 1],
        [7, 1],
        [1, 2],
      ]
    
      return slopes.map(s => countTrees(input, ...s)).reduce((acc, t) => acc * t, 1)
    }
    
    2 votes
  13. spit-evil-olive-tips
    Link
    Part 1 class Map: def __init__(self, trees): self.trees = trees @property def rows(self): return len(self.trees) @property def columns(self): return len(self.trees[0]) @classmethod def...
    Part 1
    class Map:
        def __init__(self, trees):
            self.trees = trees
    
        @property
        def rows(self):
            return len(self.trees)
    
        @property
        def columns(self):
            return len(self.trees[0])
    
        @classmethod
        def from_file(cls, path):
            rows = []
            with open(path) as input_file:
                for line in input_file:
                    rows.append([char == '#' for char in line])
    
            return cls(rows)
    
    
    def main():
        map = Map.from_file('003.txt')
    
        delta_row, delta_column = 1, 3
        previous_row, previous_column = 0, 0
    
        tree_count = 0
        while True:
            current_row = previous_row + delta_row
            current_column = (previous_column + delta_column) % (map.columns - 1)
    
            if current_row >= map.rows:
                break
    
            has_tree = map.trees[current_row][current_column]
            if has_tree:
                tree_count += 1
    
            previous_row, previous_column = current_row, current_column
    
        print(tree_count)
    
    
    if __name__ == '__main__':
        main()
    

    The biggest thing that tripped me up was % map.columns vs % (map.columns - 1) when calculating wrap-around as you fall off the "right" of the map.

    Part 2
    --- 003a.py     2020-12-02 23:09:09.608291830 -0800
    +++ 003b.py     2020-12-02 23:10:38.330623415 -0800
    @@ -20,19 +20,16 @@
             return cls(rows)
     
     
    -def main():
    -    map = Map.from_file('003.txt')
    -
    -    delta_row, delta_column = 1, 3
    +def evaluate_slope(map, slope):
    +    delta_row, delta_column = slope
         previous_row, previous_column = 0, 0
    -
         tree_count = 0
         while True:
             current_row = previous_row + delta_row
             current_column = (previous_column + delta_column) % (map.columns - 1)
     
             if current_row >= map.rows:
    -            break
    +            return tree_count
     
             has_tree = map.trees[current_row][current_column]
             if has_tree:
    @@ -40,7 +37,25 @@
     
             previous_row, previous_column = current_row, current_column
     
    -    print(tree_count)
    +
    +def main():
    +    map = Map.from_file('003.txt')
    +
    +    candidate_slopes = [
    +        (1, 1),
    +        (1, 3),
    +        (1, 5),
    +        (1, 7),
    +        (2, 1),
    +    ]
    +
    +    result = 1
    +    for slope in candidate_slopes:
    +        tree_count = evaluate_slope(map, slope)
    +        print(f'{slope}: {tree_count}')
    +        result *= tree_count
    +
    +    print(result)
     
     
     if __name__ == '__main__':
    

    For part 2, the main thing I changed was extracting out the evaluate_slope function.

    2 votes
  14. wycy
    (edited )
    Link
    Solution in Rust. Cleaned up a bit. Rust use std::env; use std::io::{self, prelude::*, BufReader}; use std::fs::File; use std::collections::HashSet; #[derive(Debug, Copy, Clone, Eq, PartialEq,...

    Solution in Rust. Cleaned up a bit.

    Rust
    use std::env;
    use std::io::{self, prelude::*, BufReader};
    use std::fs::File;
    use std::collections::HashSet;
    
    #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
    struct MapPoint {
        x: i64,
        y: i64,
    }
    impl MapPoint {
        pub fn new(x: i64, y: i64) -> MapPoint {
            MapPoint {
                x: x,
                y: y,
            }
        }
    }
    
    fn tree_collisions(trees: &HashSet<MapPoint>, width: i64, slope: (i64,i64)) -> usize {
        trees
            .iter()
            .filter(|p| p.y % slope.1 == 0)
            .filter(|p| p.x == (slope.0*p.y / slope.1) % (width+1))
            .count()
    }
    
    fn day03(input: &str) -> io::Result<()> {
        let file = File::open(input).expect("Input file not found.");
        let reader = BufReader::new(file);
    
        // Build map of trees
        let mut width: i64 = 0;
        let mut trees: HashSet<MapPoint> = HashSet::new();
        for (y,line) in reader.lines().enumerate() {
            for (x,c) in line.unwrap().chars().enumerate() {
                let (x,y) = (x as i64, y as i64);
                width = std::cmp::max(width,x);
                if c == '#' { trees.insert(MapPoint::new(x,y)); }
            }
        }
    
        let slopes = vec![(1,1), (3,1), (5,1), (7,1), (1,2)];
    
        // Part 1
        let part1 = tree_collisions(&trees,width,slopes[1]);
        println!("Part 1: {}", part1); // 247
    
        let part2 = slopes
            .iter()
            .map(|s| tree_collisions(&trees,width,*s))
            .fold(1, |mut trees, x| {trees *= x; trees});
        println!("Part 2: {}", part2); // 2983070376
    
        Ok(())
    }
    
    fn main() {
        let args: Vec<String> = env::args().collect();
        let filename = &args[1];
        day03(&filename).unwrap();
    }
    
    2 votes
  15. ali
    Link
    I joined this a bit late (only today). I just finished all of them, now I am in the mood for more Part 1 and 2 in Python input = [line.rstrip() for line in open('input.txt')] input = input...

    I joined this a bit late (only today). I just finished all of them, now I am in the mood for more

    Part 1 and 2 in Python
    input = [line.rstrip() for line in open('input.txt')]
    
    input = input
    input_width = len(input[0])
    
    def slope(right,down):
        position = [0, 0]  # -> and  V
        tree_counter = 0
        while(position[1]+down < len(input)):
    
            position[0] += right
            position[1] += down
    
            tree = 1 if input[position[1]][position[0] % input_width] == '#' else 0
            # print(tree)
            tree_counter += tree
        return tree_counter
    
    paths = [(1,1),(3,1),(5,1),(7,1),(1,2)] # 3,1 is Part 1
    trees = 1
    for path in paths:
        result = slope(path[0],path[1])
        print(result)
        trees = trees* result
    
    
    print(trees)
    
    2 votes
  16. blitz
    (edited )
    Link
    Day 3 (parts combined) use std::io; use std::io::prelude::*; fn count_trees(slope: (usize, usize), lines: &Vec<String>) -> usize { let width = lines[0].len(); let mut encounters = 0; for (i, line)...
    Day 3 (parts combined)
    use std::io;
    use std::io::prelude::*;
    
    fn count_trees(slope: (usize, usize), lines: &Vec<String>) -> usize {
        let width = lines[0].len();
        let mut encounters = 0;
    
        for (i, line) in lines.iter().enumerate() {
            let over = ((slope.0 * i) / slope.1) % width;
            if i % slope.1 == 0 {
                if line.as_bytes()[over] as char == '#' {
                    encounters += 1;
                }
            }
        }
    
        encounters
    }
    
    fn main() {
        let stdin = io::stdin();
    
        let lines: Vec<String> = stdin.lock().lines().collect::<Result<_, _>>().unwrap();
    
        let part2_slopes = vec![(1, 1), (3, 1), (5, 1), (7, 1), (1, 2)];
    
        let part1_ans = count_trees((3,1), &lines);
        let part2_ans: usize = part2_slopes.iter().map(|x| count_trees(*x, &lines)).product();
    
        println!("Part1: {}", part1_ans);
        println!("Part2: {}", part2_ans);
    }
    
    2 votes
  17. Gyrfalcon
    Link
    Language: Julia Repository Personal Challenge: No loops, recursion, map, and vectorization okay Part 2 was trivial once I had part 1 the way I wanted it, so I'll just do one box. Parts 1 and 2...
    • Language: Julia
    • Repository
    • Personal Challenge: No loops, recursion, map, and vectorization okay

    Part 2 was trivial once I had part 1 the way I wanted it, so I'll just do one box.

    Parts 1 and 2
    function main()
    
        # Initialize array and read in input
        lines = []
        open("Day03/input.txt") do fp
            lines = readlines(fp)
        end
    
        # Do a quick conversion to a map of true for trees
        function tree_convert(row)
            return map(x -> x == '#', collect(row))
        end
        slope_map = map(x -> tree_convert(x), lines)
    
        # Define a recursive function that counts up the trees
        function tree_count(step, pos=[1,1])
            if pos[1] > length(slope_map)
                return 0
            # We have to have an extra case because Julia indexes from 1
            elseif mod(pos[2], length(slope_map[1])) == 0
                return (slope_map[pos[1]][length(slope_map[1])] +
                        tree_count(step, pos + step))
            else
                return (slope_map[pos[1]][mod(pos[2], length(slope_map[1]))] +
                        tree_count(step, pos + step))
            end
        end
    
        # Calculate and display results
        println("Part 1 result is ", tree_count([1, 3]))
    
        println("Part 2 result is ", tree_count([1, 1])
                                   * tree_count([1, 3])
                                   * tree_count([1, 5])
                                   * tree_count([1, 7])
                                   * tree_count([2, 1]))
    end
    
    main()
    
    2 votes
  18. heady
    Link
    I keep overwriting part 1 as I work on part 2 rawinput = open("day3input", 'r') slope = [] for line in rawinput: slope.append(line) speeds = [(1, 1), (3, 1), (5, 1), (7, 1), (1, 2)] trees = 1 def...
    I keep overwriting part 1 as I work on part 2
    rawinput = open("day3input", 'r')
    slope = []
    for line in rawinput:
        slope.append(line)
    
    speeds = [(1, 1), (3, 1), (5, 1), (7, 1), (1, 2)]
    trees = 1
    
    def skiifree(slope, speed):
        east_counter = 0
        tree_counter = 0
        south_counter = 0
        for line in range(0, len(slope), speed[1]):
            if slope[line][east_counter % 31] == '#':
                tree_counter += 1
            east_counter += speed[0]
            south_counter += speed[1]
    
        return tree_counter
    
    for speed in speeds:
        tree_counter = skiifree(slope, speed)
        trees *= tree_counter
    
    print(trees)
    
    2 votes
  19. [3]
    vaddi
    Link
    I'm failing to understand how can we find the pattern in the input data.

    I'm failing to understand how can we find the pattern in the input data.

    1 vote
    1. [3]
      Comment deleted by author
      Link Parent
      1. [2]
        vaddi
        Link Parent
        Oh, the complete input? I thought that we had to figure out a row where we would cut the input file, and then paste it to the right, iteratively. Silly me.

        Oh, the complete input? I thought that we had to figure out a row where we would cut the input file, and then paste it to the right, iteratively. Silly me.

        3 votes
        1. [2]
          Comment deleted by author
          Link Parent
          1. vaddi
            Link Parent
            it took me a lot more ahah

            it took me a lot more ahah

            3 votes