diff --git a/2016/ruby/day_04.rb b/2016/ruby/day_04.rb
new file mode 100644
index 0000000..f11a02b
--- /dev/null
+++ b/2016/ruby/day_04.rb
@@ -0,0 +1,48 @@
+class Room
+ attr_reader :encrypted_name, :sector_id
+
+ def initialize(encrypted_name, sector_id)
+ @encrypted_name, @sector_id = encrypted_name, sector_id
+ end
+
+ def checksum
+ encrypted_name
+ .scan(/[a-z]/)
+ .group_by {|x| x }
+ .map {|k,v| [k, v.size] }
+ .sort {|a,b|
+ (a.last == b.last) ? a.first <=> b.first : b.last <=> a.last
+ }
+ .take(5)
+ .map(&:first)
+ .join
+ end
+end
+
+if __FILE__ == $0
+ DATA.read.lines.map {|line|
+ /(?<name>.+)-(?<sector_id>\d+)\[(?<checksum>[a-z]+)\]/ =~ line
+ room = Room.new(name, sector_id.to_i)
+ [room, checksum]
+ }.select {|room, checksum|
+ room.checksum == checksum
+ }.inject(0) {|n, (room, _)|
+ n += room.sector_id
+ }.tap {|count|
+ puts count
+ }
+end
+
+require 'minitest'
+# require 'minitest/autorun'
+
+class TestDay04 < Minitest::Test
+ def test_day_04
+ assert_equal 'abxyz', Room.new('aaaaa-bbb-z-y-x', 123).checksum
+ assert_equal 'abcde', Room.new('a-b-c-d-e-f-g-h', 987).checksum
+ assert_equal 'oarel', Room.new('not-a-real-room', 404).checksum
+ refute_equal 'decoy', Room.new('totally-real-room', 200).checksum
+ end
+end
+
+__END__