AoC 2015 - 11일차 - 조금 더 RegEx

산타는 암호를 선택하는 이상한(그리고 위험한!) 방법을 가지고 있습니다. 퍼즐에 설명된 방법은 다음과 같습니다.



이 모든 것은 긴 이야기입니다.
  • 산타의 다음 암호를 찾으려면 8자로 구성된 기존 암호를 증가시켜야 합니다.
  • 세 가지 규칙이 충족될 때까지 암호를 증가시킵니다.

  • 증분 문자



    표면적으로는 짜증날 정도로 단순해 보이지만 실제로 알아내는 데 시간이 좀 걸렸습니다.

    기존 암호가 abc 인 경우 abd 로 증가시킵니다. 모두 훌륭하지만 abz에 도달하면 어떻게 됩니까? 숫자를 증가시키는 것과 같은 방식으로 증가하고 다음 열에서 시작하므로 aca 가 됩니다.

    나는 zzzzzzzz 이후의 다음 암호가 aaaaaaaa 라고 가정했지만 고맙게도 실제 퍼즐에서는 이러한 상황에 도달하지 않습니다. 암호를 코딩에 도움이 되는 것이 아니라 Base 26 숫자로 생각하게 되었습니다.

    재귀와 관련된 산타의 암호를 증가시키는 방법은 다음과 같습니다!

    def incr_string(s):
        if len(s):
            l, r = s[:-1], s[-1]
            if r == 'z':
                return incr_string(l) + 'a'
            else:
                return l + chr(ord(r) + 1)
        else:
            return ''
    


    여기서 우리가 하고 있는 것은 문자열을 두 부분으로 나누는 것입니다: (i) 마지막 문자까지의 모든 것, (ii) 마지막 문자. za 로 굴릴 필요가 없을 만큼 운이 좋다면 Ascii 숫자로 변환하고 1을 더한 다음 다시 문자로 변환합니다.

    마지막 문자가 a z 인 경우 함수로 다시 이동하여 마지막 문자 없이 문자열을 증가시킨 다음 끝에 'a'가 있는 결과를 반환합니다. 그리고 물론 기존 암호가 abcdzzzz이면 재귀에 상당히 깊이 들어가게 됩니다!

    규칙



    암호를 높인 후에는 모든 규칙을 통과하는지 확인할 차례입니다.

    1) 비밀번호는 abc, bcd, cde 등과 같이 최대 xyz까지 3자 이상 증가하는 직선을 포함해야 합니다. 그들은 글자를 건너뛸 수 없습니다. abd는 포함되지 않습니다.

    아래의 두 번째 규칙 덕분에 실제로 허용되는 짧은 세 쌍둥이 목록이 생겼습니다.

    if sum(map(s.count, ['abc', 'bcd', 'cde', 
                         'def', 'efg', 'fgh', 
                         'pqr', 'qrs', 'rst', 
                         'stu', 'tuv', 'uvw', 
                         'vwx', 'wxy', 'xyz'])):
    


    그러나 megathread을 포함하여 looping through the word and checking consecutive letters에서 증가하는 직선을 찾는 더 좋은 방법이 많이 있습니다.

    has_straight = False
    for i in range(len(password) - 2):
        if ord(password[i]) == ord(password[i+1])-1 and 
           ord(password[i]) == ord(password[i+2])-2:
            has_straight = True
            break
    


    놀랍게도 세 개의 연속 문자를 찾기 위해 RegEx 접근 방식을 사용하는 사람을 찾지 못했습니다.

    2) 암호에는 i, o 또는 l 문자가 포함될 수 없습니다. 이러한 문자는 다른 문자로 오인되어 혼동을 일으킬 수 있습니다.

    이것은 지금까지 모음을 세는 것과 같이 훨씬 더 간단했습니다.

    if sum(map(s.count, 'iol')) == 0:
    


    3) 암호에는 aa, bb 또는 zz와 같이 겹치지 않는 서로 다른 문자 쌍이 2개 이상 포함되어야 합니다.

    여기에 RegEx가 필요했고 '다르다'라는 단어를 완전히 놓친 채 퍼즐을 더 잘 읽어야 했습니다. 내가 인정하는 것보다 오랫동안 abcxxdxx 와 같은 암호를 허용했습니다. 쌍이 달라야 한다는 것을 알지 못했습니다.

    우선, 작동하는 RegEx가 필요합니다. 문자열에서 겹치지 않는 동일한 문자 쌍을 찾는 패턴은 (.)\1이며 확인할 수 있습니다 here . 나는 findall()를 사용하여 일치하는 모든 쌍을 검색한 다음 하나 이상의 다른 쌍이 있는지 확인하기 위해 세트로 밀어 넣었습니다.

    if len(set(re.findall(r'(.)\1', s))) > 1:
    


    기본적으로 그게 전부입니다. 기존 암호(퍼즐 입력)를 가져와서 규칙을 충족할 때까지 증가시킵니다.

    코드의 강림에서는 이례적으로 파트 2가 단순히 두 번째 암호를 찾는 것이었기 때문에 더 이상 코드를 작성할 필요가 없었습니다. 앞으로!

    좋은 웹페이지 즐겨찾기