Advent of Code 2015 - Day 1 Solution(s) in Ruby

March 02, 2018

Advent of Code?

Advent of Code is an annual event where for the first 25 days of December you can take part in solving a coding challenge. People do it for sport (there are leaderboards), and for fun. I’m in the second camp and I’d like to introduce you to this wonderful event by writing up some thoughts and process notes from the opening challenge of the first ever event.

PLEASE TAKE NOTE - YOU WILL GET MOST OF IT IF YOU SOLVE IT YOURSELF FIRST

 Solution - part 1

Read the challenge to familiarize yourself with it. It is very simple - not much to say. The input string is a single-line string of 7000 characters, each of them either ( or ). Since we are to calculate the final floor, it is as straightforward as setting up a counter and going over the string character by character.

The most obvious solution is to do something like this (written in Ruby):

floor = 0

input_string.each_char do |char|
  if char == '('
    floor += 1
  elsif char == ')'
    floor -= 1
  end
end

puts floor

And that’s it. Doesn’t get simpler than that.

Fun solution - part 1

Simplicity of the task calls for some fun solving it! Since we’re working with just a single string and each bracket represents a value - either 1 or -1, we can do this little thing:

puts eval(input_string.gsub('(', '+1').gsub(')', '-1'))

What happens here is the following:

  1. We’re using gsub to replace every ( with +1, and analogously to this, ) with -1 by running gsub again on the result of the first gsub.

If the input_string was '((()))', we would end up with '+1+1+1-1-1-1'.

  1. Having this string, we can now run the kernel method eval to evaluate this string as ruby code.

And what do you know, we’re getting a neat result of this arithmetic operation. Solved!

Fun solution - improvement

Our solution is nice and slick but we’re running gsub twice on the input string. It will take almost no time on a modern computer, but it’s not elegant. We can do better. Just so happens that gsub can accept a block in which we can use the matched pattern that we’re replacing and inject some logic.

With a regular expression to match a single non-word character (/\W/), we can do a lot of damage like this:

puts eval(input_string.strip.gsub(/\W/) { |char| char == '(' ? '+1' : '-1' })

Please note that I also called strip on the string. Since in the ternary operator I’m only checking for equality of char with (, the newline at the end of the string will match the case of no equality and you’ll end up with a off by one error, hence why stripping whitespace is necessary.

Get creative

Obviously, those aren’t the only options. Try your luck with various array operations. Hint: try reducing the array to a single digit.


Written by Daniel Kaczmarczyk, a software engineer and educator. you can find me on twitter or email me at daniel.kaczmarczyk@hey.com

a pale blue and yellow circle