1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
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
def name
name = encrypted_name.chars
sector_id.times do
name = name.map {|char|
case char
when /[a-y]/
char.succ
when ?z
?a
when ?-, ' '
' '
else
raise "unexpected char: '#{char.inspect}'"
end
}
end
name.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 && room.name =~ /north/
}.tap {|rooms|
p rooms
}
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
assert_equal 'very encrypted name', Room.new('qzmt-zixmtkozy-ivhz', 343).name
end
end
__END__