# Advent of Code 2016, Day 21: Scrambled Letters and Hash

## Part A

On DAy 21 we need to implement scrambling function that will rearrange characters in our input string according to given instructions. All the instructions are described on the puzzle page.

Because Ruby has all methods necessary to implement this, solution is quite simple:

``````data = File.readlines("21.txt", chomp: true)
input = "abcdefgh"

def scramble(string, instruction)
input = string.dup

if instruction =~ /swap position (\d+) with position (\d+)/
a, b = Regexp.last_match.captures.map(&:to_i)

input[a], input[b] = input[b], input[a]
elsif instruction =~ /swap letter (.+?) with letter (.+?)/
a, b = Regexp.last_match.captures

input.tr!("#{a}#{b}", "#{b}#{a}")
elsif instruction =~ /rotate (.+?) (\d+) step/
direction, steps = Regexp.last_match.captures
direction = direction == "left" ? 1 : -1

input = input.chars.rotate(direction * steps.to_i).join
elsif instruction =~ /rotate based on position of letter (.+?)/
letter = Regexp.last_match.captures.first
index = input.index(letter)
steps = 1 + index
steps += 1 if index >= 4

input = input.chars.rotate(-steps).join
elsif instruction =~ /reverse positions (\d+) through (\d+)/
a, b = Regexp.last_match.captures.map(&:to_i)

input[a..b] = input[a..b].reverse
elsif instruction =~ /move position (.+?) to position (.+?)/
a, b = Regexp.last_match.captures.map(&:to_i)

chars = input.chars
letter = chars.delete_at(a)
chars.insert(b, letter)

input = chars.join
end

input
end

data.each do |instruction|
input = scramble(input, instruction)
end

puts input
``````

## Part B

In the second part we need to implement unscramble method. I was trying to implement the reverse method of `scramble` to do that, so actually for each instruction do the opposite and start from the last instruction, but it didn’t work. I don’t know maybe I did some mistakes or so. In the end I decided to just brute force it:

``````@data = File.readlines("21.txt", chomp: true)
input = "abc"

def scramble(string, instruction)
input = string.dup

if instruction =~ /swap position (\d+) with position (\d+)/
a, b = Regexp.last_match.captures.map(&:to_i)

input[a], input[b] = input[b], input[a]
elsif instruction =~ /swap letter (.+?) with letter (.+?)/
a, b = Regexp.last_match.captures

input.tr!("#{a}#{b}", "#{b}#{a}")
elsif instruction =~ /rotate (.+?) (\d+) step/
direction, steps = Regexp.last_match.captures
direction = direction == "left" ? 1 : -1

input = input.chars.rotate(direction * steps.to_i).join
elsif instruction =~ /rotate based on position of letter (.+?)/
letter = Regexp.last_match.captures.first
index = input.index(letter)
steps = 1 + index
steps += 1 if index >= 4

input = input.chars.rotate(-steps).join
elsif instruction =~ /reverse positions (\d+) through (\d+)/
a, b = Regexp.last_match.captures.map(&:to_i)

input[a..b] = input[a..b].reverse
elsif instruction =~ /move position (.+?) to position (.+?)/
a, b = Regexp.last_match.captures.map(&:to_i)

chars = input.chars
letter = chars.delete_at(a)
chars.insert(b, letter)

input = chars.join
end

input
end

@data.each do |instruction|
end