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:
aaaaa-bbb-z-y-x-123[abxyz]
a-b-c-d-e-f-g-h-987[abcde]
not-a-real-room-404[oarel]
totally-real-room-200[decoy]
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.new { |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]
else
res
end
end
calculated = sorted[0..4].map { |elem| elem[0] }.join
if calculated == checksum
sum += sector.to_i
end
end
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.
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 = name.chars.map do |char|
if char == "-"
" "
else
value = char.ord - 'a'.ord
value = ((value + sector.to_i) % 26) + 'a'.ord
value.chr
end
end.join
if decrypted =~ /north/
puts sector
end
end
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
.