Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
December 4, 2019 11:20 pm GMT

Advent of Code Day 4: Code Golf and Irresponsible Password Practices

After yesterday, I was hoping for a puzzle that involved a little bit less breaking my brain, and Advent of Code, Day 4 did not disappoint.

Here's part one:

You arrive at the Venus fuel depot only to discover it's protected by a password. The Elves had written the password on a sticky note, but someone threw it out.

However, they do remember a few key facts about the password:

It is a six-digit number.
The value is within the range given in your puzzle input.
Two adjacent digits are the same (like 22 in 122345).
Going from left to right, the digits never decrease; they only ever increase or stay the same (like 111123 or 135679).
Other than the range rule, the following are true:

How many different passwords within the range given in your puzzle input meet these criteria?

First, I wrote two methods: one that checks that all digits in a number are ascending, and another that checks whether there are any adjacent digits in a number.

Originally, these methods involved some pretty ugly for loops (I don't think I've ever used a for loop in production-level Ruby code, but I digress...), so I did some digging into methods I could use to make them more elegant, and I stumbled on something I had never seen before: Array#each_cons. Here's what it looks like:

# Returns true if every digit in num# is less than or equal to the digit after it.def ascending_digits?(num)  num_str = num.to_s  digits = num_str.split('').map(&:to_i)  digits.each_cons(2).all? do |dig1, dig2|    dig1 <= dig2  endend# Returns true if any two adjacent# digits in the string are the samedef adjacent_digits?(num)  num_str = num.to_s  digits = num_str.split('')  digits.each_cons(2).any? do |dig1, dig2|    dig1 == dig2  endend

To break it down -- #each_cons is an Enumerable method that allows you to pull elements from the array in groups, rather than one at a time. In this case, I've used it with the Enumerable methods any? and all? to check whether any/all of the groups of array elements match the specified criteria. Isn't that cool?

Using these two methods, I iterated through all the numbers in my input range to find which ones were viable passwords:

input = '206938-679128'low, high = input.split('-').map(&:to_ipart_one_result = (low..high)  .to_a  .select do |num|    adjacent_digits?(num) && ascending_digits?(num)  end.lengthputs "The solution to part one is: #{part_one_result}"

Unsurprisingly, this actually takes a couple seconds to run, and I wonder if there's a faster way to cut down on the solution space before doing expensive string manipulations. However, this does return the correct answer, so I decided not to worry too much about it.

Here's part two:

An Elf just remembered one more important detail: the two adjacent matching digits are not part of a larger group of matching digits.

How many different passwords within the range given in your puzzle input meet all of the criteria?

This problem was definitely tricker, because I had to check not just that digits were being repeated, but how many times they were being repeated. I continued to use #each_cons, but I kept some other variables with information about which number was currently being repeated, and how many times it had been repeated. Here's what it looks like:

def two_adjacent_digits?(num)  num_str = num.to_s  digits = num_str.split('')  num_matching = 1  num_to_match = digits.first  digits.each_cons(2).each do |dig1, dig2|    if dig1 == dig2      num_matching += 1    else      return true if num_matching == 2      num_matching = 1      num_to_match = dig1    end  end  num_matching == 2end

This is still a bit bulky, and if anybody came up with a shorter solution, I'd love to see it!

Finally, I used this new method to find a solution for part two:

part_two_result = (low..high)  .to_a  .select do |num|    two_adjacent_digits?(num) && ascending_digits?(num)  end.lengthputs "The solution to part two is: #{part_two_result}

I suspect that we will soon get to a point where the input is too large for a brute-force solution like this to be viable, and I'm excited to start thinking a little more about data structures and algorithms. It was cool to learn about a new Ruby method that I had never used before, and I'm glad that I took the time to go back and clean up all the ugly for-loops in my code.

That being said, if we've learned anything today, it's to use a password manager and not be like these elves. See you tomorrow!

As always, you can view my complete Ruby solution on my GitHub repo:

Advent of Code 2019

Here are my solutions to the Advent of Code 2019 puzzles! Enjoy.

Advent of Code 2019, Day 3 - - Advent of Code 2019, Day 5


Original Link: https://dev.to/egiurleo/advent-of-code-day-4-irresponsible-password-practices-2mne

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To