61 lines
1.7 KiB
Ruby
61 lines
1.7 KiB
Ruby
class StraddlingCheckerboard
|
|
EncodableChars = "A-Z0-9."
|
|
SortedChars = " ./" + [*"A".."Z"].join
|
|
|
|
def initialize(board = nil)
|
|
if board.nil?
|
|
# create a new random board
|
|
rest = "BCDFGHJKLMPQUVWXYZ/.".chars.shuffle
|
|
@board = [" ESTONIAR".chars.shuffle, rest[0..9], rest[10..19]]
|
|
elsif board.chars.sort.join == SortedChars
|
|
@board = board.chars.each_slice(10).to_a
|
|
else
|
|
raise ArgumentError, "invalid #{self.class}: #{board}"
|
|
end
|
|
# find the indices of the first row blanks
|
|
@row_labels = @board[0].each_with_index.select {|v, i| v == " "}.map {|v,i| i}
|
|
|
|
@mapping = {}
|
|
@board[0].each_with_index {|char, idx| @mapping[char] = idx.to_s unless char == " "}
|
|
@board[1..2].each_with_index do |row, row_idx|
|
|
row.each_with_index do |char, idx|
|
|
@mapping[char] = "%d%d" % [@row_labels[row_idx], idx]
|
|
end
|
|
end
|
|
end
|
|
|
|
def encode(message)
|
|
msg = message.upcase.delete("^#{EncodableChars}")
|
|
msg.chars.inject("") do |crypt, char|
|
|
crypt << (char =~ /[0-9]/ ? @mapping["/"] + char : @mapping[char])
|
|
end
|
|
end
|
|
|
|
def decode(code)
|
|
msg = ""
|
|
tokens = code.chars
|
|
until tokens.empty?
|
|
token = tokens.shift
|
|
itoken = token.to_i
|
|
unless @row_labels.include?(itoken)
|
|
msg << @board[0][itoken]
|
|
else
|
|
token2 = tokens.shift
|
|
if @mapping["/"] == token + token2
|
|
msg << tokens.shift
|
|
else
|
|
msg << @board[1+@row_labels.index(itoken)][token2.to_i]
|
|
end
|
|
end
|
|
end
|
|
msg
|
|
end
|
|
|
|
def to_s
|
|
@board.inject("") {|res, row| res << row.join}
|
|
end
|
|
|
|
def inspect
|
|
"#<%s board=%p, row_labels=%p, mapping=%p>" % [self.class, to_s, @row_labels, @mapping]
|
|
end
|
|
end
|