Challenge 21

Challenge 21.1


In [26]:
import numpy as np
import re

SWAP_POS       = re.compile('swap position (\d+) with position (\d+)')
SWAP_LETTER    = re.compile('swap letter ([a-z]) with letter ([a-z])')
ROTATE_LEFT    = re.compile('rotate left (\d+) step')
ROTATE_RIGHT   = re.compile('rotate right (\d+) step')
ROTATE_LETTER  = re.compile('rotate based on position of letter ([a-z])')
REVERSE        = re.compile('reverse positions (\d+) through (\d+)')
MOVE           = re.compile('move position (\d+) to position (\d+)')

class Password(object):
    
    def __init__(self, word):
        self.word = word
    
    def get(self):
        return str(self.word)

    def swap_position(self, x, y):
        a = self.word[x]
        self.word = [self.word[i] if i != x else self.word[y] for i in range(len(self.word))]
        self.word[y] = a
        self.word = ''.join(self.word)
    
    def swap_letter(self, a, b):
        pos_a = [j for j, k in enumerate(list(self.word)) if k == a]
        pos_b = [j for j, k in enumerate(list(self.word)) if k == b]
        self.word = [self.word[i] if i not in pos_a else b for i in range(len(self.word))]
        self.word = ''.join([self.word[i] if i not in pos_b else a for i in range(len(self.word))])
        
    def rotate_right(self, x):
        self.word = ''.join(np.roll(list(self.word), x))
            
    def rotate_left(self, x):
        self.word = ''.join(np.roll(list(self.word), -x))
    
    def rotate_letter(self, a):
        ind = self.word.index(a)
        self.rotate_right((ind + 2)*(ind >= 4) + (ind + 1)*(ind < 4))
    
    def reverse_positions(self, x, y):
        l = list(self.word)
        q = l[x:y+1]
        q.reverse()
        self.word = ''.join(l[:x] + q + l[y+1:])
    
    def move_position(self, x, y):
        l = list(self.word)
        a = l.pop(x)
        q = l[:y] + [a] + l[y:]
        self.word = ''.join(q)
        
    def use(self, instr):
        
        m = SWAP_POS.match(instr)
        if m:
            x, y = m.groups()
            self.swap_position(int(x), int(y))
        
        m = SWAP_LETTER.match(instr)
        if m:
            a, b = m.groups()
            self.swap_letter(a, b)
        
        m = ROTATE_RIGHT.match(instr)
        if m:
            x = m.groups()
            self.rotate_right(int(x[0]))
        
        m = ROTATE_LEFT.match(instr)
        if m:
            x = m.groups()
            self.rotate_left(int(x[0]))
        
        m = ROTATE_LETTER.match(instr)
        if m:
            a = m.groups()
            self.rotate_letter(str(a[0]))
        
        m = REVERSE.match(instr)
        if m:
            x, y = m.groups()
            self.reverse_positions(int(x), int(y))
        
        m = MOVE.match(instr)
        if m:
            x, y = m.groups()
            self.move_position(int(x), int(y))

In [27]:
def scramble(myinput, w):
    password = Password(w)
    with open(myinput, 'rt') as f:
        for line in f:
            password.use(line.rstrip())
    return password.get()

Test


In [28]:
w = Password('abcde')
w.swap_position(4,0)
w.swap_letter('b','d')
w.reverse_positions(0,4)
w.rotate_left(1)
w.move_position(1,4)
w.move_position(3,0)
w.rotate_letter('b')
w.rotate_letter('d')
w.get()


Out[28]:
'decab'

In [29]:
word = 'abcde'
testinput = '/home/fmuinos/projects/adventofcode/2016/ferran/inputs/input21-test.txt'
scramble(testinput, word)


Out[29]:
'decab'

Result


In [30]:
word = 'abcdefgh'
myinput = '/home/fmuinos/projects/adventofcode/2016/ferran/inputs/input21.txt'
scramble(myinput, word)


Out[30]:
'baecdfgh'

Challenge 21.2

(Brute Force Solution)


In [36]:
word = 'fbgdceah'
myinput = '/home/fmuinos/projects/adventofcode/2016/ferran/inputs/input21.txt'

In [37]:
from itertools import permutations

def unscramble(myinput, word):
    for l in permutations(list('abcdefgh')):
        if scramble(myinput, ''.join(l)) == unscrambable:
            return ''.join(l)

In [38]:
unscramble(myinput, word)


Out[38]:
'cegdahbf'