-
• #52
TIL Gitlab supports project-level snippets and profile-level snippets :/
Link updated, might go back and tidy it up later to use enumerate.
-
• #53
I messed about for far too long because I was using len(line) and wasn't aware it was also counting the line break. Ended up doing 'linelength = len(lines[0]) - 1' because I didn't want to read up on importing it properly. At least I'm no longer using Pandas dataframes.
-
• #54
After some classic idiocy around leaving some checks in my input file, I created this:
https://gist.github.com/dmckennell/0c9ad748facfb350944e9cb41915039e...and got:
Part 1 took 0.012765501 seconds Part 2 took 0.002681801 seconds Part 1: 153 Part 2: 2421944712
-
• #55
I did the same! Bloody one-based coordinates.
I also remembered modulo maths, but not how to do it in Python, so I bodged an inelegant coordinate wrapping section.
-
• #56
Ha! I did the exact same with the coordinates but initially thought that was where I was making a mistake so I replaced it with modulo maths.
-
• #57
I chomp off the line feeds when reading in lines as a matter of habit, but I would have been saved if I hadn't by suitable checking:-
sub tree { my ( $x, $y ) = @_; my $rx = $x % $mx; return 0 if( $m[$y][$rx] eq "." ); return 1 if( $m[$y][$rx] eq "#" ); print "ARGH: $x, $y -> $rx, $y [".$m[$y][$rx]."]\n"; exit; }
If it's a . then return 0, if it's a # then return 1, otherwise bail with an error message (ARGH is my general term for "one of my assumptions was wrong"). If I'd failed to remove the line feed that would have found it (on the slope = 1,1 answer for sure, probably on the others too).
Eric has been really evil in the past, he's often designed the example inputs and part 1 in such a way that you get the same answer if you did parse the file correctly as if you didn't parse it correctly and didn't remove the carriage returns. It's these types of puzzles that are maddening as you get the right answer for all of the test cases (which have been cunningly crafted like that) but it fails on your personal input.
-
• #58
Last test of second part tripped me up because I had 'y' incrementing by 1 each step, rather than 'dy'.
Took me bloody ages to figure that out, not as bad as not reading the bloody question yesterday though. -
• #59
yeah similar here, was filtering to get dy lines after moving down 1 rather than moving down dy lines and then counting...
-
• #60
Yeah, I guess because I took the easy way out on the first bit because the y increment was just 1. The final set of steps was the other way round.
I think one of the issues with being relatively green coder is that I doubt a lot of my methods, so end up checking all my indexing etc and stuff like that, when in reality my issue is much more simplistic. -
• #61
Very C-like, I ended up writing
def trees(grid, r, d): return sum(row[(i*r) % len(row)] == "#" for i, row in enumerate(grid[::d]))
for the find-trees function.
-
• #62
were you saying my function was very C-like?
i've actually just re-written it and it's almost bang on the same as yours with enumerate - had seen a few people talking about that so tried to get that working. still not entirely sure what the :: does in grid[::d], apart from take every d'th y.
my function:
def findTrees2(funcdata, dx, dy): numTrees = 0 for i, line in enumerate(funcdata[::dy]): if line[(i*dx) % len(line)] == '#': numTrees += 1 return numTrees
edit: was also confused as to why you can't print an enumerate object until you put it into a list. but guess that's a conversation for data structures... i should really do a bit more formal learning
-
• #63
were you saying my function was very C-like?
Yeah, in the sense of explicit iteration variables
for i in range(...)
.foo[::d]
is shorthand forfoo[slice(None, None, d)]
so it's indexing with a slice object with a stride of d.was also confused as to why you can't print an enumerate object until you put it into a list
Iterations over objects in python3 almost always produce generators, which are objects that you can iterate over but produce their results lazily.
Imagine that the code you had written did something like:
for i, line in enumerate(funcdata[::dy]): if line == "something": break # exit early
With an eager generator, you have to make all the pairs to iterate over only to discard most of them when you exit early. With a lazy generator, you can avoid that (and can even deal with an infinite stream of data as long as you terminate at some point).
-
• #64
Interesting - that probably stems somewhat from 'learning' to code with Java, VBA and then R at university (maths/stats), then trying to pick up Python in recent years. Most of my stuff i've done at work has been VBA in spreadsheets with financial data. I've never really learned properly how to write more advanced programs, all of the main stuff etc just confuses me.
Explanation on enumerate makes sense and thanks for that, very helpful!
-
• #65
still not entirely sure what the :: does in grid[::d], apart from take every d'th y
The slice syntax is
grid[start:stop:stride]
and you can omit any, so start defaults to zero, stop to -1 (which means the end, since negative indices count backwards), and stride defaults to 1.
grid[start]
just gives you the element at indexstart
(ie, the half-open interval[start,start+1)
in maths language),[start:stop]
gives you the sub-sequence/sub-string with default stride 1,[start::stride]
would give you everystride
'th element fromstart
to the end, etc.
-
• #66
Thanks - i had never seen the stride part of the syntax, always just sliced [x:y]
-
• #67
It's one of those nice little things they really paid attention to. For example, you can reverse any sequence by using a negative stride.
-
• #68
This is great, just doing the challenges is already good for my programming skills but info like this and things previously posted by @Greenbank are even better. Helps me move away from hacky solutions to proper solutions.
-
• #69
+1
I find just as much enjoyment looking at others solutions to the tasks after completing it myself.
-
• #70
Today I decided that I would actually setup my environment properly and use junit, log4j2 and git. Learnt a bunch and enjoyed it.
TDD helped me quite a lot today. Had an integer to long overflow issue at one point.
-
• #71
I'm lagging already - had a long day at work yesterday, but catching up now. Day 2, again in ansible: https://gist.github.com/rhowe/1059f9da52850f942e7e120d7b11bf80#file-aoc2020day02part2
-
• #72
Last year I did about 2/3 of them in bash! Including the Intcode interpreter!
I still see my solution to implementing trees in bash as one of my finest achievements.
-
• #73
My solution to day 3 in Haskell. AoC is the first thing I have ever written in Haskell and it shows! I am an aerodynamics engineer who uses MATLAB and Python to basically just deal with matrix operations. It's been tricky to adjust to a functional way of thinking & where everything is not just a matrix of doubles!
main = do input <- fmap lines $ readFile "input_day03.txt" print $ countLetters (tail $ countTrees (every 1 input) [0,3..]) '#' print $ product $ countAllTrees input [1,1,1,1,2] [1,3,5,7,1] countTrees :: [String] -> [Int] -> String countTrees [] _ = [] countTrees (x:xs) (y:ys) = [x !! (y `mod` length x)] ++ countTrees xs ys countLetters :: String -> Char -> Int countLetters str c = length $ filter (== c) str every :: Int -> [String] -> [String] every n (x:xs) = [x] ++ every n (drop (n-1) xs) every _ [] = [] countAllTrees :: [String] -> [Int] -> [Int] -> [Int] countAllTrees input (x:xs) (y:ys) = [countLetters (tail $ countTrees (every x input) [0,y..]) '#'] ++ countAllTrees input xs ys countAllTrees _ [] _ = []
-
• #74
Day 4. The joy of string parsing and regex.
Wasted a few minutes chasing a typo where I was validating the wrong field against the wrong data and letting too many invalid entries slip through.
I also predict that tomorrow (or within the next few days) we may find it saying "They aren't actually passport details, instead they are instructions for a special kind of computer" appearing soon...
-
• #75
Looks good!
Try and train yourself out of the habit of adding a single entry to the start of a list by using
++
and instead cons it on the front with:
.E.g., write
every n (x:xs) = x : every n (drop (n-1) xs) -- Rather than every n (x:xs) [x] ++ every n (drop (n-1) xs)
(:)
is O(1) because you're just adding a node to the head of a linked list, whereas++
is O(n) in the length of the first list because Haskell has to walk to the end of the first list before appending the second one.Although it doesn't really matter here because the first list is only length one, it's an antipattern one tries to avoid. e.g. compare the runtime performance of
rev :: [a] -> [a] rev (x:xs) = rev xs ++ [x] rev [] = [] -- with rev' :: [a] -> [a] rev' xs = revH xs [] where revH (x:xs) ys = revH xs (x:ys) revH [] ys = ys
(Getting ready to teach intro Haskell again...)
I try to be as "good practice" as possible. Modulo the functional-style "incomprehensible Haskell" list comprehensions.