Solved using Golang (1.10 / 1.11, if versions come up)
Part 1 changed substantially after I had to start working on part 2. Part 2 was a pain
Part 1 is easy enough, but the challenge is that the array is sort of backwards -- probably my own fault with the indexes Part 2 is still pretty easy, but it nearly had me rewrite this. One solution I didn't really try much was something along these lines
In python...
movement = {
1: {'U': 1, 'R': 2, 'D': 4, 'L': 1},
# ...
5: {'U': 2, 'R': 6, 'D': 8, 'L': 4},
}
position = 5
for c in directions:
position = movement[position][direction]
Doing this solution would have made this pretty trivial, but might be hard to maintain as the grid grew from 3x3 to, say, 5x5
Go regex isn't as straight forward as I'd like
I also like how the core logic didn't change -- just the parsing logic changed, which helped my code.
A pretty interesting problem, but sort of hard to do. FOr the 2nd half, I really just wanted to use sql:
select letter from table order by count desc, letter asc
So, Go's md5 implmenetation returns back a [16]byte
, but Go's hex takes []byte
, which is super annoying
But, there's an easy way to do this conversaion: use rtn[:]
to turn it into a byte slick pretty easily
This one is a bit weird, and focuses on scanning and keeping track of where you are. This ended up not being as hard as I figured it would be. The big challenge for me here was making sure that I was keep track of which character I was in, while factoring what the next loop iteration was going to do. Also, I need a way to keep that regex global, or relatively global so that I don't need to redefine it on every call.
I hate the while syntax here. Seems pretty terrible, really. I suppose that's why most other languages opt for a while style and a for style?
Also, I'm pretty tired of using := range
for for
loops. I don't really get why they opted to use :=
instead of in
, or alternatively why range
is required. I nearly always write it without the range, then I need to go back and add it.
This was a pain. I'm not super happy with my code, so I may make some revisions later on.
The basic flow is this:
- Figure out eah of the relationships for each bot/output and their station positions
- Encode that logic somewhere (A struct here, with one reciever method -- a class would probably work better here)
- Find any bot that has 2 elements -- thankfully there's only one
- Execute the logic (recursively) until everything ends up in an output.
The big problem I faced here was actually with references. I wanted some shorthand variable to use over and over
without using *
and &
(kind of a pain to type on this keyboard), but I ended up making copies without realizing it
Soo, no luck there. I ended up going back and replacing all of the values with references, and then my code worked perfectly
As a result though, there's a fair bit of debug code here that needs to be cleaned out.
No clue what to do here.
I coded this up correctly on the first pass, but it seemed like it didn't work, since it was pretty slow
I ended up doing two things to make this work faster:
- Cheat the number identification. I originally used a regular expression (not even a compiled one), but figured it would be faster to simply check to see that the first character looked like it could be a number, and not worry about if it was error prone. I didn't test, but this had a large impact on performance. it could probably be further optimized here as well
- Pre-pare out the steps. Initially I split the inputs on each pass, which ended up being needless.
A 3rd improvement would be to memoize the relative results from a (or maybe each) cell, up until a jump. This one is more complicated, but could maybe save a number of iterations through the loop, and focus only on the parts that matter (namely, jumps)
I think there's a faster way to do this, possibly having to use the LCM of the discs. The idea of the quicker way is this:
- You've figured out how to drop it through n holes. You can repeat this by only choosing LCMs of the n discs, with each multiple being the number of positions in contains (in my example, the first 3 discs:
17 * 19 * 7
). - When you use multiples of the LCM, you are guarenteed to pass through the same n discs.
- Each LCM is going to advance the next disc some number of values. You need to figure out what that next number is. Once you have that, you can advance the guess count until you find a match
- once you find that match, you should now be able to drop the capsule n+1 steps (the first n pass, because we always increment by lcms, the next, because the modulous finally works)
This one was actually pretty straight forward -- I appreciate the puzzlesa in which they give explicit rules on how to transform the data. However, part 2 is kind of weird. Normally part 2 requires some kind of code change. Technically, this did require a code change -- a 40 to 400000 but this isn't very significant. But, I guess what they were going for was maybe having some people run into problems with memory consumption? As a psuedo code solutino for that (actually just python), you can instead not build out the grid, and instead look at only two rows. the logic looks something like this:
def calc_safe_squares(start_row, num_rows):
def calc_safe_in_row(row):
return sum([1 for c in s if c =='.'])
last_row = start_row
row_sum = 0
for i in range(num_rows-1):
row_sum += calc_safe_in_row(last_row)
last_row = build_row(last_row) # same logic as before -- look at the previous row based off of the established rules
return row_sum
I actually saw a youtube video on this: https://www.youtube.com/watch?v=uCsD3ZGzMgE
Short version: we can wrtie the number as 2^n + l
(the biggest power of 2 less than the number, plus the remainder)
If we do this, then the "winning" seat will be 2l + 1
Funny note: this video was published on Oct 28 2016, for the 2016 puzzle, so maybe a puzzle creator took inspiration from this?
Part 2 was a bit more difficult. I ended up having to implement a brute force solution, but that was going to take far too long to execute.
I ended up looking at the numbers again and noticed the following pattern:
for every n that can be evenly represted as 3^n, the winning seat is the last seat (i.e. W(n) = n
)
From there, solutions progress at slope = 1 for some period of time, before switching to slope=2. These switches occur
on the "middle" multiple of 3, or expressed differently, at the midpoint between 3^n
and 3^(n-1)
. My math capabitiles have
apparently deteriated to the point that I couldn't merge these into a single equation, nor am I sure that a single equation exists.
So, in my solution, I instead just did a quick check based on where the midpoint is, relative to the encapsulating powers of 3, and checked
which side was closer, and determined the result from there.