Maybe this'll be our repeating problem (like the opcodes last year)... Different starting points, different types of obstacles in the snow, terrain to avoid, ...
First time I've done Advent of Code, but here is my Haskell soloution for Day 3:
trees right down xs = let line_length = length (head xs)
in length $ filter (== '#') $
zipWith (\input move -> input !! (move `mod` line_length))
(downs down xs) [right,right+right..]
where
downs d xs = let ys = drop d xs in if null ys then [] else head ys : downs d ys
main = do xs <- readFile "day3_input" <&> lines
let task1 = trees 3 1 xs
let task2 = [ trees 1 1 xs, trees 3 1 xs, trees 5 1 xs,
trees 7 1 xs, trees 1 2 xs ]
print task1 >> print (product task2)
IDENTIFICATION DIVISION.
PROGRAM-ID. AOC-2020-03-2.
AUTHOR. ANNA KOSIERADZKA.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT INPUTFILE ASSIGN TO "d3.input"
ORGANIZATION IS LINE SEQUENTIAL.
DATA DIVISION.
FILE SECTION.
FD INPUTFILE.
01 INPUTRECORD PIC X(31).
WORKING-STORAGE SECTION.
01 FILE-STATUS PIC 9 VALUE 0.
01 WS-ARR-LEN PIC 9(3) VALUE 323.
01 WS-ARRAY PIC X(31) OCCURS 1 to 500 DEPENDING ON WS-ARR-LEN.
01 WS-TREES-PRODUCT PIC 9(20) VALUE 1.
LOCAL-STORAGE SECTION.
01 TREES UNSIGNED-INT VALUE 0.
01 X UNSIGNED-INT VALUE 1.
01 Y UNSIGNED-INT VALUE 1.
01 DELTA-X UNSIGNED-INT VALUE 1.
01 DELTA-Y UNSIGNED-INT VALUE 1.
01 MAP-WIDTH UNSIGNED-INT VALUE 31.
PROCEDURE DIVISION.
001-MAIN.
OPEN INPUT INPUTFILE.
PERFORM 002-READ UNTIL FILE-STATUS = 1.
CLOSE INPUTFILE.
PERFORM 004-PROCESS-DELTAS.
DISPLAY WS-TREES-PRODUCT.
STOP RUN.
002-READ.
READ INPUTFILE
AT END MOVE 1 TO FILE-STATUS
NOT AT END PERFORM 003-WRITE-TO-ARRAY
END-READ.
003-WRITE-TO-ARRAY.
MOVE INPUTRECORD TO WS-ARRAY(X)
ADD 1 to X.
004-PROCESS-DELTAS.
PERFORM 005-PROCESS-DELTAS-PAIR.
MOVE 3 TO DELTA-Y.
PERFORM 005-PROCESS-DELTAS-PAIR.
MOVE 5 TO DELTA-Y.
PERFORM 005-PROCESS-DELTAS-PAIR.
MOVE 7 TO DELTA-Y.
PERFORM 005-PROCESS-DELTAS-PAIR.
MOVE 2 TO DELTA-X.
MOVE 1 TO DELTA-Y.
PERFORM 005-PROCESS-DELTAS-PAIR.
005-PROCESS-DELTAS-PAIR.
MOVE 1 TO X.
MOVE 1 TO Y.
MOVE 0 TO TREES.
PERFORM 006-LOOP UNTIL X >= WS-ARR-LEN.
COMPUTE WS-TREES-PRODUCT = WS-TREES-PRODUCT * TREES.
006-LOOP.
ADD DELTA-X TO X.
ADD DELTA-Y TO Y.
COMPUTE Y = FUNCTION MOD(Y, MAP-WIDTH).
IF Y = 0 THEN
MOVE MAP-WIDTH TO Y
END-IF.
IF WS-ARRAY(X)(Y:1) = '#' THEN
ADD 1 TO TREES
END-IF.
I'm a Staff Software Engineer at Cisco. I specialize in Python and Go, building functional, practical, and maintainable web systems leveraging Kubernetes and the cloud. Blog opinions are my own.
I typically keep them in the same file in different functions, since work from part 1 is often shared to part 2, (like today), but every so often, he throws a curveball and part 2 ends up being a total rethink, and then it may be nicer to have more separation. It probably doesn’t matter a ton :)
Completed my day 3 with a little help from comments here
import sys
def slope_calc(data, right, down):
tree = 0
open_space = 0
first = True
position = right
line_count = 0
for line in data:
if line != "":
line_read = line.rstrip("\n")
if first:
first = False
else:
if line_count % down == 0:
if line_read[position] == ".":
open_space += 1
else:
if line_read[position] == "#":
tree += 1
position += right
if position > len(line_read)-1:
position = position-len(line_read)
line_count += 1
print("Tree = {}, Open = {}".format(tree, open_space))
return tree
data = []
for line in sys.stdin:
data.append(line.rstrip("\n"))
print(slope_calc(data,1,1) * slope_calc(data,3,1) * slope_calc(data,5,1) * slope_calc(data,7,1) * slope_calc(data,1,2))
I'm a Staff Software Engineer at Cisco. I specialize in Python and Go, building functional, practical, and maintainable web systems leveraging Kubernetes and the cloud. Blog opinions are my own.
OK! Here's my solution. I wasn't sure how managing the 2D grid was going to go in C since I've historically struggled with them in Rust. But it went pretty easy and ran super fast, so I'm very happy with it :)
I had trouble for a minute because my code was skipping slots in my array because of the newline characters in the input. Once I stopped incrementing my index when I saw a newline, it shaped right up!
Day3.h:
/// Day 3: Taboggan Trajectory/// /// Figure out how many trees you'll have to go past given a 2D grid/slope/// covered in them.#ifndef AOC2020_DAY3_H
#define AOC2020_DAY3_H
#include <stdlib.h>
/// All of the possible options for a terrain square in a TreeGrid./// OPEN has no trees in it./// TREE has a tree in it.typedefenum{OPEN,TREE,}TerrainType;/// A 2D grid of terrain./// Knows how wide and tall it is./// Uses a 1D list of cells, and tricky math to index.typedefstruct{TerrainType*cells;size_twidth;size_theight;}TreeGrid;/// 2D indexing into a TreeGrid#define CELL(t, x, y) ((t)->cells[y*(t)->width + x])
/// Parse the input file, which is a 2D grid of '.' (free) and '#' (tree)/// Return a pointer to a TreeGrid.TreeGrid*parse(constchar*filename);/// Frees a TreeGrid.voidfreeTreeGrid(TreeGrid*grid);/// Part 1 calculates how many trees we'll hit with a slope of 3 right/// and 1 down.size_tpart1(TreeGrid*grid);/// Part 2 has us check a few different slopes for trees. The result/// is the product of all tree counts.size_tpart2(TreeGrid*grid);/// Runs both parts and outputs the results.intday3(void);#endif
Day3.c:
#include "Day3.h"
#include "parsing.h"
#include <stdio.h>
TreeGrid*parse(constchar*filename){FILE*fp;fp=fopen(filename,"r");if(fp==NULL){printf("Couldn't open input file.\n");exit(EXIT_FAILURE);}TreeGrid*grid=malloc(sizeof(TreeGrid));GridSizesize=measure_grid(fp);grid->cells=malloc(sizeof(TerrainType)*size.width*size.height);charc;for(size_ti=0;!feof(fp);){switch(c=getc(fp)){case'.':grid->cells[i]=OPEN;i++;break;case'#':grid->cells[i]=TREE;i++;break;case'\n':caseEOF:// Just consume the newlinebreak;default:printf("Unrecognized character on char (x=%zu, y=%zu): %c.\n",i%size.width,i/size.width,c);exit(EXIT_FAILURE);}}fclose(fp);grid->height=size.height;grid->width=size.width;returngrid;}voidfreeTreeGrid(TreeGrid*grid){free(grid->cells);grid->cells=NULL;free(grid);}/// Calculates how many trees you'll see on a linear trip down the hill./// If you go off the right end of the grid, wraps around infinitely wide.staticsize_tcalculateTrees(TreeGrid*grid,size_txShift,size_tyDrop){size_ttrees=0;for(size_tx=0,y=0;y<grid->height;y+=yDrop,x=(x+xShift)%grid->width){switch(CELL(grid,x,y)){caseTREE:trees++;break;caseOPEN:break;}}returntrees;}size_tpart1(TreeGrid*grid){returncalculateTrees(grid,3,1);}size_tpart2(TreeGrid*grid){returncalculateTrees(grid,1,1)*calculateTrees(grid,3,1)*calculateTrees(grid,5,1)*calculateTrees(grid,7,1)*calculateTrees(grid,1,2);}intday3(){TreeGrid*grid=parse("data/day3.txt");printf("====== Day 3 ======\n");printf("Part 1: %zu\n",part1(grid));printf("Part 2: %zu\n",part2(grid));freeTreeGrid(grid);returnEXIT_SUCCESS;}
Additional code to parsing.h:
// .../// The height and width of a 2D grid.typedefstruct{size_twidth;size_theight;}GridSize;/// Takes in a file containing a 2D grid and returns its width/height.GridSizemeasure_grid(FILE*fp);
Aaaand the implementation:
GridSizemeasure_grid(FILE*fp){size_tlines=0;size_tcols=0;while(getc(fp)!='\n')cols++;lines++;while(!feof(fp)){if(getc(fp)=='\n')lines++;}lines++;// Assume no newline after last line.rewind(fp);return(GridSize){.width=cols,.height=lines};}
I'm a Staff Software Engineer at Cisco. I specialize in Python and Go, building functional, practical, and maintainable web systems leveraging Kubernetes and the cloud. Blog opinions are my own.
Hi Rabbi, you have a short string that repeats indefinitely. As you move right you quickly hit the end of the string. It was a very simple way to repeat the pattern otherwise you get an index out of range error when you exceed the original string length.
Its not very efficient as it repeats every line but it works in this instance. If you had to create longer strings you might want to refactor to check if you've hit end of string and only repeat then.
Dan
My solution in Python below for part 1. The hardest part for my was to figure out that the starting point is one further to the right then I expected...
I'm a Staff Software Engineer at Cisco. I specialize in Python and Go, building functional, practical, and maintainable web systems leveraging Kubernetes and the cloud. Blog opinions are my own.
FYI, if you want to get some syntax highlighting in your comments, you can use three backtics followed by the language name to open and three backticks by themselves to close. Here's the Markdown cheat sheet for reference.
Spent ages trying to get this figured using array striding but eventually my head exploded and I resorted to using indices.
importnumpyasnpfromioimportStringIOimportmathdefcount_trees(arr,steps_right,steps_down):n_rows,n_cols=arr.shapen_down_steps=math.floor(n_rows/steps_down)across_positions=[(steps_right*n)%n_colsforninrange(n_down_steps)]flat_array_positions=[(rownum*n_cols*steps_down)+across_positions[rownum]forrownuminrange(n_down_steps)]total_trees=arr.ravel()[flat_array_positions].sum()returntotal_treeswithopen('input.txt','r')asf:data=f.read().replace('.','0').replace('#','1')# using converters parameter to change #/. to 1/0 is a pain if
# we don't know the number of columns. So string-replace them all first
trees_map=np.genfromtxt(StringIO(data),delimiter=1,dtype='uint8')part_2_slopes=((1,1),(3,1),(5,1),(7,1),(1,2))part_1_slope=part_2_slopes[1]print(f"Part 1: {count_trees(trees_map,*part_1_slope)} trees hit")part_2_trees=[count_trees(trees_map,*s)forsinpart_2_slopes]part_2_res=np.prod(part_2_trees)print(f"Part 2: Product of total trees hit is {part_2_res}")
let newArr= arr.split(/\r?\n/);//split by endlines
let xCord = 0;//X coordinates
let counter = 0;//trees hit counter
for(let i = 0 ; i < newArr.length ; i++){
let temp = newArr[i].split('');//split into array of characters
if(temp[xCord]=='#'){//checking for trees
counter++;//if there is a tree increment the counter
}
xCord = xCord +3;//add +3 to the right
if(xCord>=31){//check if there is more coords than elements in array
xCord = xCord-31;//reset coords
}}
console.log(counter);//result
public static class Day3
{
static int r;
static int d;
static string[] input = new string[] { //input };
static Stopwatch timer = new Stopwatch();
static int trees = 0;
public static void Execute()
{
timer.Start();
findNextLocationAndUpdateTreeCount();
}
private static void findNextLocationAndUpdateTreeCount()
{
var line = input[d];
var positionOnLine = line.ToCharArray()[r];
if (positionOnLine == '#')
trees++;
//For part 2 change r and d to the values you have to check
r += 3;
d += 1;
if (input.Length <= d) {
timer.Stop();
Console.WriteLine($"Answer: {trees} trees");
Console.WriteLine($"Executed in: {timer.ElapsedMilliseconds} milliseconds ({timer.ElapsedTicks} Ticks)");
Console.ReadLine();
}
if(line.Length <= r)
{
//By using r - line.Length you don't have to copy the whole input when you reached the end on the right (also possible to use Mod)
r = r - line.Length;
}
findNextLocationAndUpdateTreeCount();
}
}
I'm a Staff Software Engineer at Cisco. I specialize in Python and Go, building functional, practical, and maintainable web systems leveraging Kubernetes and the cloud. Blog opinions are my own.
Rust again
Rustaceans gonna stick together 🦀:
As always, also available on Github.
The
enumimplementation for your input is cool; I wouldn't have thought of that.Rust using lots of iterators and generators. I'm trying to learn the standard library properly now.
Nice! Didn't know about
product(); will have to keep that in a pocket.I like that your solution allows for an arbitrary starting point, rather than always just (0,0).
One thing I've learned about AoC - try not to bake in any assumptions in part 1!
Maybe this'll be our repeating problem (like the opcodes last year)... Different starting points, different types of obstacles in the snow, terrain to avoid, ...
A bit of Go
First time I've done Advent of Code, but here is my Haskell soloution for Day 3:
Still going strong with COBOL
There is my solution, Elixir as always. I'll switch to Golang/PHP when I get stuck.
Day 3, part 1:
Day 3 part 2:
What's your experience guys? Better to keep both parts in one class/module / whatever?
I typically keep them in the same file in different functions, since work from part 1 is often shared to part 2, (like today), but every so often, he throws a curveball and part 2 ends up being a total rethink, and then it may be nicer to have more separation. It probably doesn’t matter a ton :)
Short Python solution
Hi,
In PHP again, for fun, I try to have the minimum of temporary variables.
Full size here : Advent Of Code - Day 3
Here is my Day 3 in Ruby
Mine!
Haskell
Completed my day 3 with a little help from comments here
OK! Here's my solution. I wasn't sure how managing the 2D grid was going to go in C since I've historically struggled with them in Rust. But it went pretty easy and ran super fast, so I'm very happy with it :)
I had trouble for a minute because my code was skipping slots in my array because of the newline characters in the input. Once I stopped incrementing my index when I saw a newline, it shaped right up!
Day3.h:
Day3.c:
Additional code to parsing.h:
Aaaand the implementation:
I put my solution in a gist. It's only for the second part, but I think it's easy enough to adjust it back for the first.
That was quick! I'm just going to put that this one is in JavaScript for my future language-tallying self 😊 Thanks for sharing!
I'm always amazed by the main leader board. Some people seem to have solved the tasks in under five minutes. I can't even read it in that time 😁
Here's my beginner's Haskell solution:
Python effort, short and simple and gives the right answer.
Hi,
Can you explain why "line = line + line" 7 times?
(Maybe i missed something in the question...)
10x :)
Hi Rabbi, you have a short string that repeats indefinitely. As you move right you quickly hit the end of the string. It was a very simple way to repeat the pattern otherwise you get an index out of range error when you exceed the original string length.
Its not very efficient as it repeats every line but it works in this instance. If you had to create longer strings you might want to refactor to check if you've hit end of string and only repeat then.
Dan
Great! That helped me understand my mistake (Thous that end of line leads to the next line) :)
My solution in Python below for part 1. The hardest part for my was to figure out that the starting point is one further to the right then I expected...
My ugly python version
Hi! Thanks for sharing!
FYI, if you want to get some syntax highlighting in your comments, you can use three backtics followed by the language name to open and three backticks by themselves to close. Here's the Markdown cheat sheet for reference.
Python implementation using numpy.
Spent ages trying to get this figured using array striding but eventually my head exploded and I resorted to using indices.
SQL works for me ;)
0 lines of code. No loops, no boolean flag, only SQL.
Get this table naming 'day3':
3.1 Solution
3.2 Solution
Vanilla JS solution in 12 lines of code:
//create arr with input as template literal
let newArr= arr.split(/\r?\n/);//split by endlines
let xCord = 0;//X coordinates
let counter = 0;//trees hit counter
for(let i = 0 ; i < newArr.length ; i++){
let temp = newArr[i].split('');//split into array of characters
if(temp[xCord]=='#'){//checking for trees
counter++;//if there is a tree increment the counter
}
xCord = xCord +3;//add +3 to the right
if(xCord>=31){//check if there is more coords than elements in array
xCord = xCord-31;//reset coords
}}
console.log(counter);//result
My solution in C#:
My JavaScript walkthrough:
My python solution here
I wrote my solution in a notebook in Javascript:
starboard.gg/nb/nLjayUM
Unrelated to the challenges, how did you do the list of post links in your post?
You can add a “series” to front matter on the post. As long as they all match, they’ll get linked up by initial release date.
Thanks!