Advent of Code 2016, Day 4: Security Through Obscurity

#ruby #advent of code 2016

Part A

On Day 4 we are dealing with checksums. We are given strings describing rooms. Each string containts multiple parts: name, sector id and checksum. Our task is to verify which strings are valid by calculating checksum and comparing it with the checksum in the string.

Our input looks like this:


To calculate checksum we need to count occurences of characters and then sort them in the descending order. In case of ties we need to sort alphabetically. For first example string we have 5 times ‘a’, 3 times ‘b’, 1 time ‘x’, 1 time ‘y’ and 1 time ‘z’. The checksum should be abxyz and it is so the string is valid.

Here is my solution:

data = File.readlines("4.txt").map(&:strip)
sum = 0

data.each do |room|
  name, sector, checksum = room.match(/([a-z\-]+)-(\d+)\[(.+)\]/).captures
  name.gsub!("-", "")

  chars = { |hash, key| hash[key] = 0 }
  name.chars.each { |char| chars[char] += 1 }

  sorted = chars.to_a.sort do |a, b|
    res = b[1] <=> a[1]

    if res == 0
      a[0] <=> b[0]

  calculated = sorted[0..4].map { |elem| elem[0] }.join

  if calculated == checksum
    sum += sector.to_i

puts sum

In the sort block we are first trying to compare both items by their occurence count. We use Ruby spaceship <=> operator and it case of equal values it will return 0. So if we get a 0 we need to them compare them alphabetically.

Part B

In second part we need to decrypt the names of rooms, so we are interested in the first part of the string and the sector id. Strings are encrypted with kind of Caesar cipher with sector id being an offset. We just need to iterate over each char and shift it given amount of times. Here is my solution:

data = File.readlines("4.txt", chomp: true)

data.each do |room|
  name, sector, checksum = room.match(/([a-z\-]+)-(\d+)\[(.+)\]/).captures

  decrypted = do |char|
    if char == "-"
      " "
      value = char.ord - 'a'.ord
      value = ((value + sector.to_i) % 26) + 'a'.ord


  if decrypted =~ /north/
    puts sector

This part value = char.ord - 'a'.ord converts any char into alphabet index starting from 0. ‘a’ is 0, ‘b’ is 1, ‘c’ is 2 and so on. It is easier to shift integers as we can just add to it. Them we can convert it back into character by adding 'a'.ord and calling value.chr.