require 'minitest/autorun'
class MovableChar
def initialize value
@value = value
is_letter = @value =~ /[[:alpha:]]/
@move_steps = is_letter ? @value.upcase.ord - 64 : 0
end
attr_accessor :move_steps, :value
def mark_moved
@move_steps = 0
end
end
def move(input)
chars = input.chars.map { |c| MovableChar.new(c) }
while index_to_move = chars.find_index { |c| c.move_steps > 0 }
char_to_move = chars.delete_at index_to_move
new_index = (index_to_move + char_to_move.move_steps) % (chars.size + 1)
char_to_move.mark_moved
chars.insert(new_index, char_to_move)
end
chars.map(&:value).join
end
describe MovableChar do
it 'computes moving steps for letters case insensitive' do
assert_equal 1, MovableChar.new('a').move_steps
assert_equal 1, MovableChar.new('A').move_steps
assert_equal 4, MovableChar.new('d').move_steps
assert_equal 4, MovableChar.new('D').move_steps
end
it 'moving steps is zero for non-letters' do
assert_equal 0, MovableChar.new('*').move_steps
assert_equal 0, MovableChar.new('.').move_steps
assert_equal 0, MovableChar.new('-').move_steps
assert_equal 0, MovableChar.new('~').move_steps
end
it 'is not allowed to move more than once' do
c = MovableChar.new('a')
c.mark_moved
assert_equal 0, c.move_steps
end
end
describe :MovingLetters do
def test_case_1
assert_equal 'tca', move('cat')
end
def test_case_2
assert_equal '.F.NU', move('F.U.N')
end
def test_case_3
assert_equal 'goD', move('Dog')
end
def test_case_4
assert_equal '*hibey', move('hi*bye')
end
end
cmVxdWlyZSAnbWluaXRlc3QvYXV0b3J1bicKCmNsYXNzIE1vdmFibGVDaGFyCiAgZGVmIGluaXRpYWxpemUgdmFsdWUKICAgIEB2YWx1ZSA9IHZhbHVlCiAgICBpc19sZXR0ZXIgPSBAdmFsdWUgPX4gL1tbOmFscGhhOl1dLwoKICAgIEBtb3ZlX3N0ZXBzID0gaXNfbGV0dGVyID8gQHZhbHVlLnVwY2FzZS5vcmQgLSA2NCA6IDAKICBlbmQKCiAgYXR0cl9hY2Nlc3NvciA6bW92ZV9zdGVwcywgOnZhbHVlCgogIGRlZiBtYXJrX21vdmVkCiAgICBAbW92ZV9zdGVwcyA9IDAKICBlbmQKZW5kCgpkZWYgbW92ZShpbnB1dCkKICBjaGFycyA9IGlucHV0LmNoYXJzLm1hcCB7IHxjfCBNb3ZhYmxlQ2hhci5uZXcoYykgfQoKICB3aGlsZSBpbmRleF90b19tb3ZlID0gY2hhcnMuZmluZF9pbmRleCB7IHxjfCBjLm1vdmVfc3RlcHMgPiAwIH0KICAgIGNoYXJfdG9fbW92ZSA9IGNoYXJzLmRlbGV0ZV9hdCBpbmRleF90b19tb3ZlCiAgICBuZXdfaW5kZXggPSAoaW5kZXhfdG9fbW92ZSArIGNoYXJfdG9fbW92ZS5tb3ZlX3N0ZXBzKSAlIChjaGFycy5zaXplICsgMSkKICAgIGNoYXJfdG9fbW92ZS5tYXJrX21vdmVkCiAgICBjaGFycy5pbnNlcnQobmV3X2luZGV4LCBjaGFyX3RvX21vdmUpCiAgZW5kCgogIGNoYXJzLm1hcCgmOnZhbHVlKS5qb2luCmVuZAoKZGVzY3JpYmUgTW92YWJsZUNoYXIgZG8KICBpdCAnY29tcHV0ZXMgbW92aW5nIHN0ZXBzIGZvciBsZXR0ZXJzIGNhc2UgaW5zZW5zaXRpdmUnIGRvCiAgICBhc3NlcnRfZXF1YWwgMSwgTW92YWJsZUNoYXIubmV3KCdhJykubW92ZV9zdGVwcwogICAgYXNzZXJ0X2VxdWFsIDEsIE1vdmFibGVDaGFyLm5ldygnQScpLm1vdmVfc3RlcHMKICAgIGFzc2VydF9lcXVhbCA0LCBNb3ZhYmxlQ2hhci5uZXcoJ2QnKS5tb3ZlX3N0ZXBzCiAgICBhc3NlcnRfZXF1YWwgNCwgTW92YWJsZUNoYXIubmV3KCdEJykubW92ZV9zdGVwcwogIGVuZAoKICBpdCAnbW92aW5nIHN0ZXBzIGlzIHplcm8gZm9yIG5vbi1sZXR0ZXJzJyBkbwogICAgYXNzZXJ0X2VxdWFsIDAsIE1vdmFibGVDaGFyLm5ldygnKicpLm1vdmVfc3RlcHMKICAgIGFzc2VydF9lcXVhbCAwLCBNb3ZhYmxlQ2hhci5uZXcoJy4nKS5tb3ZlX3N0ZXBzCiAgICBhc3NlcnRfZXF1YWwgMCwgTW92YWJsZUNoYXIubmV3KCctJykubW92ZV9zdGVwcwogICAgYXNzZXJ0X2VxdWFsIDAsIE1vdmFibGVDaGFyLm5ldygnficpLm1vdmVfc3RlcHMKICBlbmQKCiAgaXQgJ2lzIG5vdCBhbGxvd2VkIHRvIG1vdmUgbW9yZSB0aGFuIG9uY2UnIGRvCiAgICBjID0gTW92YWJsZUNoYXIubmV3KCdhJykKICAgIGMubWFya19tb3ZlZAogICAgYXNzZXJ0X2VxdWFsIDAsIGMubW92ZV9zdGVwcwogIGVuZAplbmQKCmRlc2NyaWJlIDpNb3ZpbmdMZXR0ZXJzIGRvCiAgZGVmIHRlc3RfY2FzZV8xCiAgICBhc3NlcnRfZXF1YWwgJ3RjYScsIG1vdmUoJ2NhdCcpCiAgZW5kCgogIGRlZiB0ZXN0X2Nhc2VfMgogICAgYXNzZXJ0X2VxdWFsICcuRi5OVScsIG1vdmUoJ0YuVS5OJykKICBlbmQKCiAgZGVmIHRlc3RfY2FzZV8zCiAgICBhc3NlcnRfZXF1YWwgJ2dvRCcsIG1vdmUoJ0RvZycpCiAgZW5kCgogIGRlZiB0ZXN0X2Nhc2VfNAogICAgYXNzZXJ0X2VxdWFsICcqaGliZXknLCBtb3ZlKCdoaSpieWUnKQogIGVuZAplbmQK